2 * Copyright (C) 2013 Red Hat
3 * Author: Rob Clark <robdclark@gmail.com>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
20 static struct platform_device
*hdmi_pdev
;
22 void hdmi_set_mode(struct hdmi
*hdmi
, bool power_on
)
27 ctrl
|= HDMI_CTRL_ENABLE
;
28 if (!hdmi
->hdmi_mode
) {
29 ctrl
|= HDMI_CTRL_HDMI
;
30 hdmi_write(hdmi
, REG_HDMI_CTRL
, ctrl
);
31 ctrl
&= ~HDMI_CTRL_HDMI
;
33 ctrl
|= HDMI_CTRL_HDMI
;
36 ctrl
= HDMI_CTRL_HDMI
;
39 hdmi_write(hdmi
, REG_HDMI_CTRL
, ctrl
);
40 DBG("HDMI Core: %s, HDMI_CTRL=0x%08x",
41 power_on
? "Enable" : "Disable", ctrl
);
44 irqreturn_t
hdmi_irq(int irq
, void *dev_id
)
46 struct hdmi
*hdmi
= dev_id
;
49 hdmi_connector_irq(hdmi
->connector
);
52 hdmi_i2c_irq(hdmi
->i2c
);
59 void hdmi_destroy(struct kref
*kref
)
61 struct hdmi
*hdmi
= container_of(kref
, struct hdmi
, refcount
);
62 struct hdmi_phy
*phy
= hdmi
->phy
;
65 phy
->funcs
->destroy(phy
);
68 hdmi_i2c_destroy(hdmi
->i2c
);
70 put_device(&hdmi
->pdev
->dev
);
73 /* initialize connector */
74 struct hdmi
*hdmi_init(struct drm_device
*dev
, struct drm_encoder
*encoder
)
76 struct hdmi
*hdmi
= NULL
;
77 struct msm_drm_private
*priv
= dev
->dev_private
;
78 struct platform_device
*pdev
= hdmi_pdev
;
79 struct hdmi_platform_config
*config
;
83 dev_err(dev
->dev
, "no hdmi device\n");
88 config
= pdev
->dev
.platform_data
;
90 hdmi
= kzalloc(sizeof(*hdmi
), GFP_KERNEL
);
96 kref_init(&hdmi
->refcount
);
98 get_device(&pdev
->dev
);
102 hdmi
->config
= config
;
103 hdmi
->encoder
= encoder
;
105 /* not sure about which phy maps to which msm.. probably I miss some */
106 if (config
->phy_init
)
107 hdmi
->phy
= config
->phy_init(hdmi
);
109 hdmi
->phy
= ERR_PTR(-ENXIO
);
111 if (IS_ERR(hdmi
->phy
)) {
112 ret
= PTR_ERR(hdmi
->phy
);
113 dev_err(dev
->dev
, "failed to load phy: %d\n", ret
);
118 hdmi
->mmio
= msm_ioremap(pdev
, config
->mmio_name
, "HDMI");
119 if (IS_ERR(hdmi
->mmio
)) {
120 ret
= PTR_ERR(hdmi
->mmio
);
124 BUG_ON(config
->hpd_reg_cnt
> ARRAY_SIZE(hdmi
->hpd_regs
));
125 for (i
= 0; i
< config
->hpd_reg_cnt
; i
++) {
126 struct regulator
*reg
;
128 reg
= devm_regulator_get(&pdev
->dev
, config
->hpd_reg_names
[i
]);
131 dev_err(dev
->dev
, "failed to get hpd regulator: %s (%d)\n",
132 config
->hpd_reg_names
[i
], ret
);
136 hdmi
->hpd_regs
[i
] = reg
;
139 BUG_ON(config
->pwr_reg_cnt
> ARRAY_SIZE(hdmi
->pwr_regs
));
140 for (i
= 0; i
< config
->pwr_reg_cnt
; i
++) {
141 struct regulator
*reg
;
143 reg
= devm_regulator_get(&pdev
->dev
, config
->pwr_reg_names
[i
]);
146 dev_err(dev
->dev
, "failed to get pwr regulator: %s (%d)\n",
147 config
->pwr_reg_names
[i
], ret
);
151 hdmi
->pwr_regs
[i
] = reg
;
154 BUG_ON(config
->hpd_clk_cnt
> ARRAY_SIZE(hdmi
->hpd_clks
));
155 for (i
= 0; i
< config
->hpd_clk_cnt
; i
++) {
158 clk
= devm_clk_get(&pdev
->dev
, config
->hpd_clk_names
[i
]);
161 dev_err(dev
->dev
, "failed to get hpd clk: %s (%d)\n",
162 config
->hpd_clk_names
[i
], ret
);
166 hdmi
->hpd_clks
[i
] = clk
;
169 BUG_ON(config
->pwr_clk_cnt
> ARRAY_SIZE(hdmi
->pwr_clks
));
170 for (i
= 0; i
< config
->pwr_clk_cnt
; i
++) {
173 clk
= devm_clk_get(&pdev
->dev
, config
->pwr_clk_names
[i
]);
176 dev_err(dev
->dev
, "failed to get pwr clk: %s (%d)\n",
177 config
->pwr_clk_names
[i
], ret
);
181 hdmi
->pwr_clks
[i
] = clk
;
184 hdmi
->i2c
= hdmi_i2c_init(hdmi
);
185 if (IS_ERR(hdmi
->i2c
)) {
186 ret
= PTR_ERR(hdmi
->i2c
);
187 dev_err(dev
->dev
, "failed to get i2c: %d\n", ret
);
192 hdmi
->bridge
= hdmi_bridge_init(hdmi
);
193 if (IS_ERR(hdmi
->bridge
)) {
194 ret
= PTR_ERR(hdmi
->bridge
);
195 dev_err(dev
->dev
, "failed to create HDMI bridge: %d\n", ret
);
200 hdmi
->connector
= hdmi_connector_init(hdmi
);
201 if (IS_ERR(hdmi
->connector
)) {
202 ret
= PTR_ERR(hdmi
->connector
);
203 dev_err(dev
->dev
, "failed to create HDMI connector: %d\n", ret
);
204 hdmi
->connector
= NULL
;
208 if (!config
->shared_irq
) {
209 hdmi
->irq
= platform_get_irq(pdev
, 0);
212 dev_err(dev
->dev
, "failed to get irq: %d\n", ret
);
216 ret
= devm_request_threaded_irq(&pdev
->dev
, hdmi
->irq
,
217 NULL
, hdmi_irq
, IRQF_TRIGGER_HIGH
| IRQF_ONESHOT
,
220 dev_err(dev
->dev
, "failed to request IRQ%u: %d\n",
226 encoder
->bridge
= hdmi
->bridge
;
228 priv
->bridges
[priv
->num_bridges
++] = hdmi
->bridge
;
229 priv
->connectors
[priv
->num_connectors
++] = hdmi
->connector
;
235 /* bridge/connector are normally destroyed by drm: */
237 hdmi
->bridge
->funcs
->destroy(hdmi
->bridge
);
239 hdmi
->connector
->funcs
->destroy(hdmi
->connector
);
240 hdmi_destroy(&hdmi
->refcount
);
250 #include <linux/of_gpio.h>
252 static int hdmi_dev_probe(struct platform_device
*pdev
)
254 static struct hdmi_platform_config config
= {};
256 struct device_node
*of_node
= pdev
->dev
.of_node
;
258 int get_gpio(const char *name
)
260 int gpio
= of_get_named_gpio(of_node
, name
, 0);
262 dev_err(&pdev
->dev
, "failed to get gpio: %s (%d)\n",
269 /* TODO actually use DT.. */
270 static const char *hpd_reg_names
[] = {"hpd-gdsc", "hpd-5v"};
271 static const char *pwr_reg_names
[] = {"core-vdda", "core-vcc"};
272 static const char *hpd_clk_names
[] = {"iface_clk", "core_clk", "mdp_core_clk"};
273 static const char *pwr_clk_names
[] = {"extp_clk", "alt_iface_clk"};
275 config
.phy_init
= hdmi_phy_8x74_init
;
276 config
.mmio_name
= "core_physical";
277 config
.hpd_reg_names
= hpd_reg_names
;
278 config
.hpd_reg_cnt
= ARRAY_SIZE(hpd_reg_names
);
279 config
.pwr_reg_names
= pwr_reg_names
;
280 config
.pwr_reg_cnt
= ARRAY_SIZE(pwr_reg_names
);
281 config
.hpd_clk_names
= hpd_clk_names
;
282 config
.hpd_clk_cnt
= ARRAY_SIZE(hpd_clk_names
);
283 config
.pwr_clk_names
= pwr_clk_names
;
284 config
.pwr_clk_cnt
= ARRAY_SIZE(pwr_clk_names
);
285 config
.ddc_clk_gpio
= get_gpio("qcom,hdmi-tx-ddc-clk");
286 config
.ddc_data_gpio
= get_gpio("qcom,hdmi-tx-ddc-data");
287 config
.hpd_gpio
= get_gpio("qcom,hdmi-tx-hpd");
288 config
.mux_en_gpio
= get_gpio("qcom,hdmi-tx-mux-en");
289 config
.mux_sel_gpio
= get_gpio("qcom,hdmi-tx-mux-sel");
290 config
.shared_irq
= true;
293 static const char *hpd_clk_names
[] = {
294 "core_clk", "master_iface_clk", "slave_iface_clk",
296 if (cpu_is_apq8064()) {
297 static const char *hpd_reg_names
[] = {"8921_hdmi_mvs"};
298 config
.phy_init
= hdmi_phy_8960_init
;
299 config
.mmio_name
= "hdmi_msm_hdmi_addr";
300 config
.hpd_reg_names
= hpd_reg_names
;
301 config
.hpd_reg_cnt
= ARRAY_SIZE(hpd_reg_names
);
302 config
.hpd_clk_names
= hpd_clk_names
;
303 config
.hpd_clk_cnt
= ARRAY_SIZE(hpd_clk_names
);
304 config
.ddc_clk_gpio
= 70;
305 config
.ddc_data_gpio
= 71;
306 config
.hpd_gpio
= 72;
307 config
.mux_en_gpio
= -1;
308 config
.mux_sel_gpio
= 13 + NR_GPIO_IRQS
;
309 } else if (cpu_is_msm8960() || cpu_is_msm8960ab()) {
310 static const char *hpd_reg_names
[] = {"8921_hdmi_mvs"};
311 config
.phy_init
= hdmi_phy_8960_init
;
312 config
.mmio_name
= "hdmi_msm_hdmi_addr";
313 config
.hpd_reg_names
= hpd_reg_names
;
314 config
.hpd_reg_cnt
= ARRAY_SIZE(hpd_reg_names
);
315 config
.hpd_clk_names
= hpd_clk_names
;
316 config
.hpd_clk_cnt
= ARRAY_SIZE(hpd_clk_names
);
317 config
.ddc_clk_gpio
= 100;
318 config
.ddc_data_gpio
= 101;
319 config
.hpd_gpio
= 102;
320 config
.mux_en_gpio
= -1;
321 config
.mux_sel_gpio
= -1;
322 } else if (cpu_is_msm8x60()) {
323 static const char *hpd_reg_names
[] = {
324 "8901_hdmi_mvs", "8901_mpp0"
326 config
.phy_init
= hdmi_phy_8x60_init
;
327 config
.mmio_name
= "hdmi_msm_hdmi_addr";
328 config
.hpd_reg_names
= hpd_reg_names
;
329 config
.hpd_reg_cnt
= ARRAY_SIZE(hpd_reg_names
);
330 config
.hpd_clk_names
= hpd_clk_names
;
331 config
.hpd_clk_cnt
= ARRAY_SIZE(hpd_clk_names
);
332 config
.ddc_clk_gpio
= 170;
333 config
.ddc_data_gpio
= 171;
334 config
.hpd_gpio
= 172;
335 config
.mux_en_gpio
= -1;
336 config
.mux_sel_gpio
= -1;
339 pdev
->dev
.platform_data
= &config
;
344 static int hdmi_dev_remove(struct platform_device
*pdev
)
350 static const struct of_device_id dt_match
[] = {
351 { .compatible
= "qcom,hdmi-tx" },
354 MODULE_DEVICE_TABLE(of
, dt_match
);
356 static struct platform_driver hdmi_driver
= {
357 .probe
= hdmi_dev_probe
,
358 .remove
= hdmi_dev_remove
,
361 .of_match_table
= dt_match
,
365 void __init
hdmi_register(void)
367 platform_driver_register(&hdmi_driver
);
370 void __exit
hdmi_unregister(void)
372 platform_driver_unregister(&hdmi_driver
);