xref: /openbmc/linux/drivers/gpu/drm/msm/hdmi/hdmi.c (revision 447fa529)
1c8afe684SRob Clark /*
2c8afe684SRob Clark  * Copyright (C) 2013 Red Hat
3c8afe684SRob Clark  * Author: Rob Clark <robdclark@gmail.com>
4c8afe684SRob Clark  *
5c8afe684SRob Clark  * This program is free software; you can redistribute it and/or modify it
6c8afe684SRob Clark  * under the terms of the GNU General Public License version 2 as published by
7c8afe684SRob Clark  * the Free Software Foundation.
8c8afe684SRob Clark  *
9c8afe684SRob Clark  * This program is distributed in the hope that it will be useful, but WITHOUT
10c8afe684SRob Clark  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11c8afe684SRob Clark  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12c8afe684SRob Clark  * more details.
13c8afe684SRob Clark  *
14c8afe684SRob Clark  * You should have received a copy of the GNU General Public License along with
15c8afe684SRob Clark  * this program.  If not, see <http://www.gnu.org/licenses/>.
16c8afe684SRob Clark  */
17c8afe684SRob Clark 
18f6a8eacaSRob Clark #include <linux/of_irq.h>
19c8afe684SRob Clark #include "hdmi.h"
20c8afe684SRob Clark 
21c8afe684SRob Clark void hdmi_set_mode(struct hdmi *hdmi, bool power_on)
22c8afe684SRob Clark {
23c8afe684SRob Clark 	uint32_t ctrl = 0;
24c8afe684SRob Clark 
25c8afe684SRob Clark 	if (power_on) {
26c8afe684SRob Clark 		ctrl |= HDMI_CTRL_ENABLE;
27c8afe684SRob Clark 		if (!hdmi->hdmi_mode) {
28c8afe684SRob Clark 			ctrl |= HDMI_CTRL_HDMI;
29c8afe684SRob Clark 			hdmi_write(hdmi, REG_HDMI_CTRL, ctrl);
30c8afe684SRob Clark 			ctrl &= ~HDMI_CTRL_HDMI;
31c8afe684SRob Clark 		} else {
32c8afe684SRob Clark 			ctrl |= HDMI_CTRL_HDMI;
33c8afe684SRob Clark 		}
34c8afe684SRob Clark 	} else {
35c8afe684SRob Clark 		ctrl = HDMI_CTRL_HDMI;
36c8afe684SRob Clark 	}
37c8afe684SRob Clark 
38c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_CTRL, ctrl);
39c8afe684SRob Clark 	DBG("HDMI Core: %s, HDMI_CTRL=0x%08x",
40c8afe684SRob Clark 			power_on ? "Enable" : "Disable", ctrl);
41c8afe684SRob Clark }
42c8afe684SRob Clark 
43f6a8eacaSRob Clark static irqreturn_t hdmi_irq(int irq, void *dev_id)
44c8afe684SRob Clark {
45c8afe684SRob Clark 	struct hdmi *hdmi = dev_id;
46c8afe684SRob Clark 
47c8afe684SRob Clark 	/* Process HPD: */
48c8afe684SRob Clark 	hdmi_connector_irq(hdmi->connector);
49c8afe684SRob Clark 
50c8afe684SRob Clark 	/* Process DDC: */
51c8afe684SRob Clark 	hdmi_i2c_irq(hdmi->i2c);
52c8afe684SRob Clark 
53c8afe684SRob Clark 	/* TODO audio.. */
54c8afe684SRob Clark 
55c8afe684SRob Clark 	return IRQ_HANDLED;
56c8afe684SRob Clark }
57c8afe684SRob Clark 
58d1a717bdSRob Clark static void hdmi_destroy(struct hdmi *hdmi)
59c8afe684SRob Clark {
60c8afe684SRob Clark 	struct hdmi_phy *phy = hdmi->phy;
61c8afe684SRob Clark 
62c8afe684SRob Clark 	if (phy)
63c8afe684SRob Clark 		phy->funcs->destroy(phy);
64c8afe684SRob Clark 
65c8afe684SRob Clark 	if (hdmi->i2c)
66c8afe684SRob Clark 		hdmi_i2c_destroy(hdmi->i2c);
67c8afe684SRob Clark 
68c0c0d9eeSRob Clark 	platform_set_drvdata(hdmi->pdev, NULL);
69c8afe684SRob Clark }
70c8afe684SRob Clark 
71067fef37SRob Clark /* construct hdmi at bind/probe time, grab all the resources.  If
72067fef37SRob Clark  * we are to EPROBE_DEFER we want to do it here, rather than later
73067fef37SRob Clark  * at modeset_init() time
74067fef37SRob Clark  */
75067fef37SRob Clark static struct hdmi *hdmi_init(struct platform_device *pdev)
76c8afe684SRob Clark {
77067fef37SRob Clark 	struct hdmi_platform_config *config = pdev->dev.platform_data;
78a3376e3eSRob Clark 	struct hdmi *hdmi = NULL;
79dada25bdSRob Clark 	int i, ret;
80c8afe684SRob Clark 
81067fef37SRob Clark 	hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
82a3376e3eSRob Clark 	if (!hdmi) {
83a3376e3eSRob Clark 		ret = -ENOMEM;
84a3376e3eSRob Clark 		goto fail;
85a3376e3eSRob Clark 	}
86a3376e3eSRob Clark 
87c8afe684SRob Clark 	hdmi->pdev = pdev;
88dada25bdSRob Clark 	hdmi->config = config;
89c0c0d9eeSRob Clark 
90c8afe684SRob Clark 	/* not sure about which phy maps to which msm.. probably I miss some */
91c8afe684SRob Clark 	if (config->phy_init)
92c8afe684SRob Clark 		hdmi->phy = config->phy_init(hdmi);
93c8afe684SRob Clark 	else
94c8afe684SRob Clark 		hdmi->phy = ERR_PTR(-ENXIO);
95c8afe684SRob Clark 
96c8afe684SRob Clark 	if (IS_ERR(hdmi->phy)) {
97c8afe684SRob Clark 		ret = PTR_ERR(hdmi->phy);
98067fef37SRob Clark 		dev_err(&pdev->dev, "failed to load phy: %d\n", ret);
99c8afe684SRob Clark 		hdmi->phy = NULL;
100c8afe684SRob Clark 		goto fail;
101c8afe684SRob Clark 	}
102c8afe684SRob Clark 
103dada25bdSRob Clark 	hdmi->mmio = msm_ioremap(pdev, config->mmio_name, "HDMI");
104c8afe684SRob Clark 	if (IS_ERR(hdmi->mmio)) {
105c8afe684SRob Clark 		ret = PTR_ERR(hdmi->mmio);
106c8afe684SRob Clark 		goto fail;
107c8afe684SRob Clark 	}
108c8afe684SRob Clark 
109447fa529SStephane Viau 	hdmi->hpd_regs = devm_kzalloc(&pdev->dev, sizeof(hdmi->hpd_regs[0]) *
110447fa529SStephane Viau 			config->hpd_reg_cnt, GFP_KERNEL);
111447fa529SStephane Viau 	if (!hdmi->hpd_regs) {
112447fa529SStephane Viau 		ret = -ENOMEM;
113447fa529SStephane Viau 		goto fail;
114447fa529SStephane Viau 	}
115dada25bdSRob Clark 	for (i = 0; i < config->hpd_reg_cnt; i++) {
116dada25bdSRob Clark 		struct regulator *reg;
117dada25bdSRob Clark 
1183e87599bSRob Clark 		reg = devm_regulator_get(&pdev->dev,
11941e69778SRob Clark 				config->hpd_reg_names[i]);
120dada25bdSRob Clark 		if (IS_ERR(reg)) {
121dada25bdSRob Clark 			ret = PTR_ERR(reg);
122067fef37SRob Clark 			dev_err(&pdev->dev, "failed to get hpd regulator: %s (%d)\n",
123dada25bdSRob Clark 					config->hpd_reg_names[i], ret);
124c8afe684SRob Clark 			goto fail;
125c8afe684SRob Clark 		}
126c8afe684SRob Clark 
127dada25bdSRob Clark 		hdmi->hpd_regs[i] = reg;
128dada25bdSRob Clark 	}
129c8afe684SRob Clark 
130447fa529SStephane Viau 	hdmi->pwr_regs = devm_kzalloc(&pdev->dev, sizeof(hdmi->pwr_regs[0]) *
131447fa529SStephane Viau 			config->pwr_reg_cnt, GFP_KERNEL);
132447fa529SStephane Viau 	if (!hdmi->pwr_regs) {
133447fa529SStephane Viau 		ret = -ENOMEM;
134447fa529SStephane Viau 		goto fail;
135447fa529SStephane Viau 	}
136dada25bdSRob Clark 	for (i = 0; i < config->pwr_reg_cnt; i++) {
137dada25bdSRob Clark 		struct regulator *reg;
138dada25bdSRob Clark 
1393e87599bSRob Clark 		reg = devm_regulator_get(&pdev->dev,
14041e69778SRob Clark 				config->pwr_reg_names[i]);
141dada25bdSRob Clark 		if (IS_ERR(reg)) {
142dada25bdSRob Clark 			ret = PTR_ERR(reg);
143067fef37SRob Clark 			dev_err(&pdev->dev, "failed to get pwr regulator: %s (%d)\n",
144dada25bdSRob Clark 					config->pwr_reg_names[i], ret);
145c8afe684SRob Clark 			goto fail;
146c8afe684SRob Clark 		}
147c8afe684SRob Clark 
148dada25bdSRob Clark 		hdmi->pwr_regs[i] = reg;
149dada25bdSRob Clark 	}
150dada25bdSRob Clark 
151447fa529SStephane Viau 	hdmi->hpd_clks = devm_kzalloc(&pdev->dev, sizeof(hdmi->hpd_clks[0]) *
152447fa529SStephane Viau 			config->hpd_clk_cnt, GFP_KERNEL);
153447fa529SStephane Viau 	if (!hdmi->hpd_clks) {
154447fa529SStephane Viau 		ret = -ENOMEM;
155447fa529SStephane Viau 		goto fail;
156447fa529SStephane Viau 	}
157dada25bdSRob Clark 	for (i = 0; i < config->hpd_clk_cnt; i++) {
158dada25bdSRob Clark 		struct clk *clk;
159dada25bdSRob Clark 
160dada25bdSRob Clark 		clk = devm_clk_get(&pdev->dev, config->hpd_clk_names[i]);
161dada25bdSRob Clark 		if (IS_ERR(clk)) {
162dada25bdSRob Clark 			ret = PTR_ERR(clk);
163067fef37SRob Clark 			dev_err(&pdev->dev, "failed to get hpd clk: %s (%d)\n",
164dada25bdSRob Clark 					config->hpd_clk_names[i], ret);
165c8afe684SRob Clark 			goto fail;
166c8afe684SRob Clark 		}
167c8afe684SRob Clark 
168dada25bdSRob Clark 		hdmi->hpd_clks[i] = clk;
169dada25bdSRob Clark 	}
170dada25bdSRob Clark 
171447fa529SStephane Viau 	hdmi->pwr_clks = devm_kzalloc(&pdev->dev, sizeof(hdmi->pwr_clks[0]) *
172447fa529SStephane Viau 			config->pwr_clk_cnt, GFP_KERNEL);
173447fa529SStephane Viau 	if (!hdmi->pwr_clks) {
174447fa529SStephane Viau 		ret = -ENOMEM;
175447fa529SStephane Viau 		goto fail;
176447fa529SStephane Viau 	}
177dada25bdSRob Clark 	for (i = 0; i < config->pwr_clk_cnt; i++) {
178dada25bdSRob Clark 		struct clk *clk;
179dada25bdSRob Clark 
180dada25bdSRob Clark 		clk = devm_clk_get(&pdev->dev, config->pwr_clk_names[i]);
181dada25bdSRob Clark 		if (IS_ERR(clk)) {
182dada25bdSRob Clark 			ret = PTR_ERR(clk);
183067fef37SRob Clark 			dev_err(&pdev->dev, "failed to get pwr clk: %s (%d)\n",
184dada25bdSRob Clark 					config->pwr_clk_names[i], ret);
185c8afe684SRob Clark 			goto fail;
186c8afe684SRob Clark 		}
187c8afe684SRob Clark 
188dada25bdSRob Clark 		hdmi->pwr_clks[i] = clk;
189dada25bdSRob Clark 	}
190dada25bdSRob Clark 
191c8afe684SRob Clark 	hdmi->i2c = hdmi_i2c_init(hdmi);
192c8afe684SRob Clark 	if (IS_ERR(hdmi->i2c)) {
193c8afe684SRob Clark 		ret = PTR_ERR(hdmi->i2c);
194067fef37SRob Clark 		dev_err(&pdev->dev, "failed to get i2c: %d\n", ret);
195c8afe684SRob Clark 		hdmi->i2c = NULL;
196c8afe684SRob Clark 		goto fail;
197c8afe684SRob Clark 	}
198c8afe684SRob Clark 
199067fef37SRob Clark 	return hdmi;
200067fef37SRob Clark 
201067fef37SRob Clark fail:
202067fef37SRob Clark 	if (hdmi)
203d1a717bdSRob Clark 		hdmi_destroy(hdmi);
204067fef37SRob Clark 
205067fef37SRob Clark 	return ERR_PTR(ret);
206067fef37SRob Clark }
207067fef37SRob Clark 
208067fef37SRob Clark /* Second part of initialization, the drm/kms level modeset_init,
209067fef37SRob Clark  * constructs/initializes mode objects, etc, is called from master
210067fef37SRob Clark  * driver (not hdmi sub-device's probe/bind!)
211067fef37SRob Clark  *
212067fef37SRob Clark  * Any resource (regulator/clk/etc) which could be missing at boot
213067fef37SRob Clark  * should be handled in hdmi_init() so that failure happens from
214067fef37SRob Clark  * hdmi sub-device's probe.
215067fef37SRob Clark  */
216067fef37SRob Clark int hdmi_modeset_init(struct hdmi *hdmi,
217067fef37SRob Clark 		struct drm_device *dev, struct drm_encoder *encoder)
218067fef37SRob Clark {
219067fef37SRob Clark 	struct msm_drm_private *priv = dev->dev_private;
220067fef37SRob Clark 	struct platform_device *pdev = hdmi->pdev;
221067fef37SRob Clark 	int ret;
222067fef37SRob Clark 
223067fef37SRob Clark 	hdmi->dev = dev;
224067fef37SRob Clark 	hdmi->encoder = encoder;
225067fef37SRob Clark 
226067fef37SRob Clark 	hdmi_audio_infoframe_init(&hdmi->audio.infoframe);
227067fef37SRob Clark 
228a3376e3eSRob Clark 	hdmi->bridge = hdmi_bridge_init(hdmi);
229a3376e3eSRob Clark 	if (IS_ERR(hdmi->bridge)) {
230a3376e3eSRob Clark 		ret = PTR_ERR(hdmi->bridge);
231a3376e3eSRob Clark 		dev_err(dev->dev, "failed to create HDMI bridge: %d\n", ret);
232a3376e3eSRob Clark 		hdmi->bridge = NULL;
233a3376e3eSRob Clark 		goto fail;
234a3376e3eSRob Clark 	}
235a3376e3eSRob Clark 
236a3376e3eSRob Clark 	hdmi->connector = hdmi_connector_init(hdmi);
237a3376e3eSRob Clark 	if (IS_ERR(hdmi->connector)) {
238a3376e3eSRob Clark 		ret = PTR_ERR(hdmi->connector);
239a3376e3eSRob Clark 		dev_err(dev->dev, "failed to create HDMI connector: %d\n", ret);
240a3376e3eSRob Clark 		hdmi->connector = NULL;
241a3376e3eSRob Clark 		goto fail;
242a3376e3eSRob Clark 	}
243a3376e3eSRob Clark 
244f6a8eacaSRob Clark 	hdmi->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
245c8afe684SRob Clark 	if (hdmi->irq < 0) {
246c8afe684SRob Clark 		ret = hdmi->irq;
247c8afe684SRob Clark 		dev_err(dev->dev, "failed to get irq: %d\n", ret);
248c8afe684SRob Clark 		goto fail;
249c8afe684SRob Clark 	}
250c8afe684SRob Clark 
251f6a8eacaSRob Clark 	ret = devm_request_irq(&pdev->dev, hdmi->irq,
252f6a8eacaSRob Clark 			hdmi_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
253c8afe684SRob Clark 			"hdmi_isr", hdmi);
254c8afe684SRob Clark 	if (ret < 0) {
255c8afe684SRob Clark 		dev_err(dev->dev, "failed to request IRQ%u: %d\n",
256c8afe684SRob Clark 				hdmi->irq, ret);
257c8afe684SRob Clark 		goto fail;
258c8afe684SRob Clark 	}
259c8afe684SRob Clark 
260a3376e3eSRob Clark 	encoder->bridge = hdmi->bridge;
261a3376e3eSRob Clark 
262a3376e3eSRob Clark 	priv->bridges[priv->num_bridges++]       = hdmi->bridge;
263a3376e3eSRob Clark 	priv->connectors[priv->num_connectors++] = hdmi->connector;
264a3376e3eSRob Clark 
265c0c0d9eeSRob Clark 	platform_set_drvdata(pdev, hdmi);
266c0c0d9eeSRob Clark 
267067fef37SRob Clark 	return 0;
268c8afe684SRob Clark 
269c8afe684SRob Clark fail:
2703d3f8b1fSAjay Kumar 	/* bridge is normally destroyed by drm: */
271067fef37SRob Clark 	if (hdmi->bridge) {
2723d3f8b1fSAjay Kumar 		hdmi_bridge_destroy(hdmi->bridge);
273067fef37SRob Clark 		hdmi->bridge = NULL;
274067fef37SRob Clark 	}
275067fef37SRob Clark 	if (hdmi->connector) {
276a3376e3eSRob Clark 		hdmi->connector->funcs->destroy(hdmi->connector);
277067fef37SRob Clark 		hdmi->connector = NULL;
278a3376e3eSRob Clark 	}
279c8afe684SRob Clark 
280067fef37SRob Clark 	return ret;
281c8afe684SRob Clark }
282c8afe684SRob Clark 
283c8afe684SRob Clark /*
284c8afe684SRob Clark  * The hdmi device:
285c8afe684SRob Clark  */
286c8afe684SRob Clark 
287dada25bdSRob Clark #include <linux/of_gpio.h>
288dada25bdSRob Clark 
289c8afe684SRob Clark #ifdef CONFIG_OF
290fc886107SMark Charlebois static int get_gpio(struct device *dev, struct device_node *of_node, const char *name)
291dada25bdSRob Clark {
292dada25bdSRob Clark 	int gpio = of_get_named_gpio(of_node, name, 0);
293dada25bdSRob Clark 	if (gpio < 0) {
29441e69778SRob Clark 		char name2[32];
29541e69778SRob Clark 		snprintf(name2, sizeof(name2), "%s-gpio", name);
29641e69778SRob Clark 		gpio = of_get_named_gpio(of_node, name2, 0);
29741e69778SRob Clark 		if (gpio < 0) {
298060530f1SRob Clark 			dev_err(dev, "failed to get gpio: %s (%d)\n",
299dada25bdSRob Clark 					name, gpio);
300dada25bdSRob Clark 			gpio = -1;
301dada25bdSRob Clark 		}
30241e69778SRob Clark 	}
303dada25bdSRob Clark 	return gpio;
304dada25bdSRob Clark }
305fc886107SMark Charlebois #endif
306fc886107SMark Charlebois 
307fc886107SMark Charlebois static int hdmi_bind(struct device *dev, struct device *master, void *data)
308fc886107SMark Charlebois {
309d1a717bdSRob Clark 	struct drm_device *drm = dev_get_drvdata(master);
310d1a717bdSRob Clark 	struct msm_drm_private *priv = drm->dev_private;
311fc886107SMark Charlebois 	static struct hdmi_platform_config config = {};
312067fef37SRob Clark 	struct hdmi *hdmi;
313fc886107SMark Charlebois #ifdef CONFIG_OF
314fc886107SMark Charlebois 	struct device_node *of_node = dev->of_node;
315dada25bdSRob Clark 
31641e69778SRob Clark 	if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8074")) {
317dada25bdSRob Clark 		static const char *hpd_reg_names[] = {"hpd-gdsc", "hpd-5v"};
318dada25bdSRob Clark 		static const char *pwr_reg_names[] = {"core-vdda", "core-vcc"};
319dada25bdSRob Clark 		static const char *hpd_clk_names[] = {"iface_clk", "core_clk", "mdp_core_clk"};
320b77f47e7SStephane Viau 		static unsigned long hpd_clk_freq[] = {0, 19200000, 0};
321dada25bdSRob Clark 		static const char *pwr_clk_names[] = {"extp_clk", "alt_iface_clk"};
322dada25bdSRob Clark 		config.phy_init      = hdmi_phy_8x74_init;
323dada25bdSRob Clark 		config.hpd_reg_names = hpd_reg_names;
324dada25bdSRob Clark 		config.hpd_reg_cnt   = ARRAY_SIZE(hpd_reg_names);
325dada25bdSRob Clark 		config.pwr_reg_names = pwr_reg_names;
326dada25bdSRob Clark 		config.pwr_reg_cnt   = ARRAY_SIZE(pwr_reg_names);
327dada25bdSRob Clark 		config.hpd_clk_names = hpd_clk_names;
328b77f47e7SStephane Viau 		config.hpd_freq      = hpd_clk_freq;
329dada25bdSRob Clark 		config.hpd_clk_cnt   = ARRAY_SIZE(hpd_clk_names);
330dada25bdSRob Clark 		config.pwr_clk_names = pwr_clk_names;
331dada25bdSRob Clark 		config.pwr_clk_cnt   = ARRAY_SIZE(pwr_clk_names);
33241e69778SRob Clark 	} else if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8960")) {
33341e69778SRob Clark 		static const char *hpd_clk_names[] = {"core_clk", "master_iface_clk", "slave_iface_clk"};
33441e69778SRob Clark 		static const char *hpd_reg_names[] = {"core-vdda", "hdmi-mux"};
33541e69778SRob Clark 		config.phy_init      = hdmi_phy_8960_init;
33641e69778SRob Clark 		config.hpd_reg_names = hpd_reg_names;
33741e69778SRob Clark 		config.hpd_reg_cnt   = ARRAY_SIZE(hpd_reg_names);
33841e69778SRob Clark 		config.hpd_clk_names = hpd_clk_names;
33941e69778SRob Clark 		config.hpd_clk_cnt   = ARRAY_SIZE(hpd_clk_names);
34041e69778SRob Clark 	} else if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8660")) {
34141e69778SRob Clark 		config.phy_init      = hdmi_phy_8x60_init;
34241e69778SRob Clark 	} else {
34341e69778SRob Clark 		dev_err(dev, "unknown phy: %s\n", of_node->name);
34441e69778SRob Clark 	}
34541e69778SRob Clark 
34641e69778SRob Clark 	config.mmio_name     = "core_physical";
347fc886107SMark Charlebois 	config.ddc_clk_gpio  = get_gpio(dev, of_node, "qcom,hdmi-tx-ddc-clk");
348fc886107SMark Charlebois 	config.ddc_data_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-ddc-data");
349fc886107SMark Charlebois 	config.hpd_gpio      = get_gpio(dev, of_node, "qcom,hdmi-tx-hpd");
350fc886107SMark Charlebois 	config.mux_en_gpio   = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-en");
351fc886107SMark Charlebois 	config.mux_sel_gpio  = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-sel");
352fc886107SMark Charlebois 	config.mux_lpm_gpio  = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-lpm");
353dada25bdSRob Clark 
354c8afe684SRob Clark #else
355dada25bdSRob Clark 	static const char *hpd_clk_names[] = {
356dada25bdSRob Clark 			"core_clk", "master_iface_clk", "slave_iface_clk",
357dada25bdSRob Clark 	};
358c8afe684SRob Clark 	if (cpu_is_apq8064()) {
359dada25bdSRob Clark 		static const char *hpd_reg_names[] = {"8921_hdmi_mvs"};
360c8afe684SRob Clark 		config.phy_init      = hdmi_phy_8960_init;
361dada25bdSRob Clark 		config.mmio_name     = "hdmi_msm_hdmi_addr";
362dada25bdSRob Clark 		config.hpd_reg_names = hpd_reg_names;
363dada25bdSRob Clark 		config.hpd_reg_cnt   = ARRAY_SIZE(hpd_reg_names);
364dada25bdSRob Clark 		config.hpd_clk_names = hpd_clk_names;
365dada25bdSRob Clark 		config.hpd_clk_cnt   = ARRAY_SIZE(hpd_clk_names);
366c8afe684SRob Clark 		config.ddc_clk_gpio  = 70;
367c8afe684SRob Clark 		config.ddc_data_gpio = 71;
368c8afe684SRob Clark 		config.hpd_gpio      = 72;
369dada25bdSRob Clark 		config.mux_en_gpio   = -1;
370c0c0d9eeSRob Clark 		config.mux_sel_gpio  = -1;
371e529c7e6SRob Clark 	} else if (cpu_is_msm8960() || cpu_is_msm8960ab()) {
372dada25bdSRob Clark 		static const char *hpd_reg_names[] = {"8921_hdmi_mvs"};
373c8afe684SRob Clark 		config.phy_init      = hdmi_phy_8960_init;
374dada25bdSRob Clark 		config.mmio_name     = "hdmi_msm_hdmi_addr";
375dada25bdSRob Clark 		config.hpd_reg_names = hpd_reg_names;
376dada25bdSRob Clark 		config.hpd_reg_cnt   = ARRAY_SIZE(hpd_reg_names);
377dada25bdSRob Clark 		config.hpd_clk_names = hpd_clk_names;
378dada25bdSRob Clark 		config.hpd_clk_cnt   = ARRAY_SIZE(hpd_clk_names);
379c8afe684SRob Clark 		config.ddc_clk_gpio  = 100;
380c8afe684SRob Clark 		config.ddc_data_gpio = 101;
381c8afe684SRob Clark 		config.hpd_gpio      = 102;
382dada25bdSRob Clark 		config.mux_en_gpio   = -1;
383dada25bdSRob Clark 		config.mux_sel_gpio  = -1;
384c8afe684SRob Clark 	} else if (cpu_is_msm8x60()) {
385dada25bdSRob Clark 		static const char *hpd_reg_names[] = {
386dada25bdSRob Clark 				"8901_hdmi_mvs", "8901_mpp0"
387dada25bdSRob Clark 		};
388c8afe684SRob Clark 		config.phy_init      = hdmi_phy_8x60_init;
389dada25bdSRob Clark 		config.mmio_name     = "hdmi_msm_hdmi_addr";
390dada25bdSRob Clark 		config.hpd_reg_names = hpd_reg_names;
391dada25bdSRob Clark 		config.hpd_reg_cnt   = ARRAY_SIZE(hpd_reg_names);
392dada25bdSRob Clark 		config.hpd_clk_names = hpd_clk_names;
393dada25bdSRob Clark 		config.hpd_clk_cnt   = ARRAY_SIZE(hpd_clk_names);
394c8afe684SRob Clark 		config.ddc_clk_gpio  = 170;
395c8afe684SRob Clark 		config.ddc_data_gpio = 171;
396c8afe684SRob Clark 		config.hpd_gpio      = 172;
397dada25bdSRob Clark 		config.mux_en_gpio   = -1;
398dada25bdSRob Clark 		config.mux_sel_gpio  = -1;
399c8afe684SRob Clark 	}
400c8afe684SRob Clark #endif
401060530f1SRob Clark 	dev->platform_data = &config;
402067fef37SRob Clark 	hdmi = hdmi_init(to_platform_device(dev));
403067fef37SRob Clark 	if (IS_ERR(hdmi))
404067fef37SRob Clark 		return PTR_ERR(hdmi);
405d1a717bdSRob Clark 	priv->hdmi = hdmi;
406c8afe684SRob Clark 	return 0;
407c8afe684SRob Clark }
408c8afe684SRob Clark 
409060530f1SRob Clark static void hdmi_unbind(struct device *dev, struct device *master,
410060530f1SRob Clark 		void *data)
411060530f1SRob Clark {
412d1a717bdSRob Clark 	struct drm_device *drm = dev_get_drvdata(master);
413d1a717bdSRob Clark 	struct msm_drm_private *priv = drm->dev_private;
414d1a717bdSRob Clark 	if (priv->hdmi) {
415d1a717bdSRob Clark 		hdmi_destroy(priv->hdmi);
416d1a717bdSRob Clark 		priv->hdmi = NULL;
417d1a717bdSRob Clark 	}
418060530f1SRob Clark }
419060530f1SRob Clark 
420060530f1SRob Clark static const struct component_ops hdmi_ops = {
421060530f1SRob Clark 		.bind   = hdmi_bind,
422060530f1SRob Clark 		.unbind = hdmi_unbind,
423060530f1SRob Clark };
424060530f1SRob Clark 
425060530f1SRob Clark static int hdmi_dev_probe(struct platform_device *pdev)
426060530f1SRob Clark {
427060530f1SRob Clark 	return component_add(&pdev->dev, &hdmi_ops);
428060530f1SRob Clark }
429060530f1SRob Clark 
430c8afe684SRob Clark static int hdmi_dev_remove(struct platform_device *pdev)
431c8afe684SRob Clark {
432060530f1SRob Clark 	component_del(&pdev->dev, &hdmi_ops);
433c8afe684SRob Clark 	return 0;
434c8afe684SRob Clark }
435c8afe684SRob Clark 
436dada25bdSRob Clark static const struct of_device_id dt_match[] = {
43741e69778SRob Clark 	{ .compatible = "qcom,hdmi-tx-8074" },
43841e69778SRob Clark 	{ .compatible = "qcom,hdmi-tx-8960" },
43941e69778SRob Clark 	{ .compatible = "qcom,hdmi-tx-8660" },
440dada25bdSRob Clark 	{}
441dada25bdSRob Clark };
442dada25bdSRob Clark 
443c8afe684SRob Clark static struct platform_driver hdmi_driver = {
444c8afe684SRob Clark 	.probe = hdmi_dev_probe,
445c8afe684SRob Clark 	.remove = hdmi_dev_remove,
446dada25bdSRob Clark 	.driver = {
447dada25bdSRob Clark 		.name = "hdmi_msm",
448dada25bdSRob Clark 		.of_match_table = dt_match,
449dada25bdSRob Clark 	},
450c8afe684SRob Clark };
451c8afe684SRob Clark 
452c8afe684SRob Clark void __init hdmi_register(void)
453c8afe684SRob Clark {
454c8afe684SRob Clark 	platform_driver_register(&hdmi_driver);
455c8afe684SRob Clark }
456c8afe684SRob Clark 
457c8afe684SRob Clark void __exit hdmi_unregister(void)
458c8afe684SRob Clark {
459c8afe684SRob Clark 	platform_driver_unregister(&hdmi_driver);
460c8afe684SRob Clark }
461