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 void hdmi_set_mode(struct hdmi
*hdmi
, bool power_on
)
25 ctrl
|= HDMI_CTRL_ENABLE
;
26 if (!hdmi
->hdmi_mode
) {
27 ctrl
|= HDMI_CTRL_HDMI
;
28 hdmi_write(hdmi
, REG_HDMI_CTRL
, ctrl
);
29 ctrl
&= ~HDMI_CTRL_HDMI
;
31 ctrl
|= HDMI_CTRL_HDMI
;
34 ctrl
= HDMI_CTRL_HDMI
;
37 hdmi_write(hdmi
, REG_HDMI_CTRL
, ctrl
);
38 DBG("HDMI Core: %s, HDMI_CTRL=0x%08x",
39 power_on
? "Enable" : "Disable", ctrl
);
42 irqreturn_t
hdmi_irq(int irq
, void *dev_id
)
44 struct hdmi
*hdmi
= dev_id
;
47 hdmi_connector_irq(hdmi
->connector
);
50 hdmi_i2c_irq(hdmi
->i2c
);
57 void hdmi_destroy(struct kref
*kref
)
59 struct hdmi
*hdmi
= container_of(kref
, struct hdmi
, refcount
);
60 struct hdmi_phy
*phy
= hdmi
->phy
;
63 phy
->funcs
->destroy(phy
);
66 hdmi_i2c_destroy(hdmi
->i2c
);
68 platform_set_drvdata(hdmi
->pdev
, NULL
);
71 /* initialize connector */
72 struct hdmi
*hdmi_init(struct drm_device
*dev
, struct drm_encoder
*encoder
)
74 struct hdmi
*hdmi
= NULL
;
75 struct msm_drm_private
*priv
= dev
->dev_private
;
76 struct platform_device
*pdev
= priv
->hdmi_pdev
;
77 struct hdmi_platform_config
*config
;
81 dev_err(dev
->dev
, "no hdmi device\n");
86 config
= pdev
->dev
.platform_data
;
88 hdmi
= kzalloc(sizeof(*hdmi
), GFP_KERNEL
);
94 kref_init(&hdmi
->refcount
);
98 hdmi
->config
= config
;
99 hdmi
->encoder
= encoder
;
101 hdmi_audio_infoframe_init(&hdmi
->audio
.infoframe
);
103 /* not sure about which phy maps to which msm.. probably I miss some */
104 if (config
->phy_init
)
105 hdmi
->phy
= config
->phy_init(hdmi
);
107 hdmi
->phy
= ERR_PTR(-ENXIO
);
109 if (IS_ERR(hdmi
->phy
)) {
110 ret
= PTR_ERR(hdmi
->phy
);
111 dev_err(dev
->dev
, "failed to load phy: %d\n", ret
);
116 hdmi
->mmio
= msm_ioremap(pdev
, config
->mmio_name
, "HDMI");
117 if (IS_ERR(hdmi
->mmio
)) {
118 ret
= PTR_ERR(hdmi
->mmio
);
122 BUG_ON(config
->hpd_reg_cnt
> ARRAY_SIZE(hdmi
->hpd_regs
));
123 for (i
= 0; i
< config
->hpd_reg_cnt
; i
++) {
124 struct regulator
*reg
;
126 reg
= devm_regulator_get(&pdev
->dev
, config
->hpd_reg_names
[i
]);
129 dev_err(dev
->dev
, "failed to get hpd regulator: %s (%d)\n",
130 config
->hpd_reg_names
[i
], ret
);
134 hdmi
->hpd_regs
[i
] = reg
;
137 BUG_ON(config
->pwr_reg_cnt
> ARRAY_SIZE(hdmi
->pwr_regs
));
138 for (i
= 0; i
< config
->pwr_reg_cnt
; i
++) {
139 struct regulator
*reg
;
141 reg
= devm_regulator_get(&pdev
->dev
, config
->pwr_reg_names
[i
]);
144 dev_err(dev
->dev
, "failed to get pwr regulator: %s (%d)\n",
145 config
->pwr_reg_names
[i
], ret
);
149 hdmi
->pwr_regs
[i
] = reg
;
152 BUG_ON(config
->hpd_clk_cnt
> ARRAY_SIZE(hdmi
->hpd_clks
));
153 for (i
= 0; i
< config
->hpd_clk_cnt
; i
++) {
156 clk
= devm_clk_get(&pdev
->dev
, config
->hpd_clk_names
[i
]);
159 dev_err(dev
->dev
, "failed to get hpd clk: %s (%d)\n",
160 config
->hpd_clk_names
[i
], ret
);
164 hdmi
->hpd_clks
[i
] = clk
;
167 BUG_ON(config
->pwr_clk_cnt
> ARRAY_SIZE(hdmi
->pwr_clks
));
168 for (i
= 0; i
< config
->pwr_clk_cnt
; i
++) {
171 clk
= devm_clk_get(&pdev
->dev
, config
->pwr_clk_names
[i
]);
174 dev_err(dev
->dev
, "failed to get pwr clk: %s (%d)\n",
175 config
->pwr_clk_names
[i
], ret
);
179 hdmi
->pwr_clks
[i
] = clk
;
182 hdmi
->i2c
= hdmi_i2c_init(hdmi
);
183 if (IS_ERR(hdmi
->i2c
)) {
184 ret
= PTR_ERR(hdmi
->i2c
);
185 dev_err(dev
->dev
, "failed to get i2c: %d\n", ret
);
190 hdmi
->bridge
= hdmi_bridge_init(hdmi
);
191 if (IS_ERR(hdmi
->bridge
)) {
192 ret
= PTR_ERR(hdmi
->bridge
);
193 dev_err(dev
->dev
, "failed to create HDMI bridge: %d\n", ret
);
198 hdmi
->connector
= hdmi_connector_init(hdmi
);
199 if (IS_ERR(hdmi
->connector
)) {
200 ret
= PTR_ERR(hdmi
->connector
);
201 dev_err(dev
->dev
, "failed to create HDMI connector: %d\n", ret
);
202 hdmi
->connector
= NULL
;
206 if (!config
->shared_irq
) {
207 hdmi
->irq
= platform_get_irq(pdev
, 0);
210 dev_err(dev
->dev
, "failed to get irq: %d\n", ret
);
214 ret
= devm_request_threaded_irq(&pdev
->dev
, hdmi
->irq
,
215 NULL
, hdmi_irq
, IRQF_TRIGGER_HIGH
| IRQF_ONESHOT
,
218 dev_err(dev
->dev
, "failed to request IRQ%u: %d\n",
224 encoder
->bridge
= hdmi
->bridge
;
226 priv
->bridges
[priv
->num_bridges
++] = hdmi
->bridge
;
227 priv
->connectors
[priv
->num_connectors
++] = hdmi
->connector
;
229 platform_set_drvdata(pdev
, hdmi
);
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 void set_hdmi_pdev(struct drm_device
*dev
,
253 struct platform_device
*pdev
)
255 struct msm_drm_private
*priv
= dev
->dev_private
;
256 priv
->hdmi_pdev
= pdev
;
259 static int hdmi_bind(struct device
*dev
, struct device
*master
, void *data
)
261 static struct hdmi_platform_config config
= {};
263 struct device_node
*of_node
= dev
->of_node
;
265 int get_gpio(const char *name
)
267 int gpio
= of_get_named_gpio(of_node
, name
, 0);
269 dev_err(dev
, "failed to get gpio: %s (%d)\n",
276 /* TODO actually use DT.. */
277 static const char *hpd_reg_names
[] = {"hpd-gdsc", "hpd-5v"};
278 static const char *pwr_reg_names
[] = {"core-vdda", "core-vcc"};
279 static const char *hpd_clk_names
[] = {"iface_clk", "core_clk", "mdp_core_clk"};
280 static unsigned long hpd_clk_freq
[] = {0, 19200000, 0};
281 static const char *pwr_clk_names
[] = {"extp_clk", "alt_iface_clk"};
283 config
.phy_init
= hdmi_phy_8x74_init
;
284 config
.mmio_name
= "core_physical";
285 config
.hpd_reg_names
= hpd_reg_names
;
286 config
.hpd_reg_cnt
= ARRAY_SIZE(hpd_reg_names
);
287 config
.pwr_reg_names
= pwr_reg_names
;
288 config
.pwr_reg_cnt
= ARRAY_SIZE(pwr_reg_names
);
289 config
.hpd_clk_names
= hpd_clk_names
;
290 config
.hpd_freq
= hpd_clk_freq
;
291 config
.hpd_clk_cnt
= ARRAY_SIZE(hpd_clk_names
);
292 config
.pwr_clk_names
= pwr_clk_names
;
293 config
.pwr_clk_cnt
= ARRAY_SIZE(pwr_clk_names
);
294 config
.ddc_clk_gpio
= get_gpio("qcom,hdmi-tx-ddc-clk");
295 config
.ddc_data_gpio
= get_gpio("qcom,hdmi-tx-ddc-data");
296 config
.hpd_gpio
= get_gpio("qcom,hdmi-tx-hpd");
297 config
.mux_en_gpio
= get_gpio("qcom,hdmi-tx-mux-en");
298 config
.mux_sel_gpio
= get_gpio("qcom,hdmi-tx-mux-sel");
299 config
.shared_irq
= true;
302 static const char *hpd_clk_names
[] = {
303 "core_clk", "master_iface_clk", "slave_iface_clk",
305 if (cpu_is_apq8064()) {
306 static const char *hpd_reg_names
[] = {"8921_hdmi_mvs"};
307 config
.phy_init
= hdmi_phy_8960_init
;
308 config
.mmio_name
= "hdmi_msm_hdmi_addr";
309 config
.hpd_reg_names
= hpd_reg_names
;
310 config
.hpd_reg_cnt
= ARRAY_SIZE(hpd_reg_names
);
311 config
.hpd_clk_names
= hpd_clk_names
;
312 config
.hpd_clk_cnt
= ARRAY_SIZE(hpd_clk_names
);
313 config
.ddc_clk_gpio
= 70;
314 config
.ddc_data_gpio
= 71;
315 config
.hpd_gpio
= 72;
316 config
.mux_en_gpio
= -1;
317 config
.mux_sel_gpio
= -1;
318 } else if (cpu_is_msm8960() || cpu_is_msm8960ab()) {
319 static const char *hpd_reg_names
[] = {"8921_hdmi_mvs"};
320 config
.phy_init
= hdmi_phy_8960_init
;
321 config
.mmio_name
= "hdmi_msm_hdmi_addr";
322 config
.hpd_reg_names
= hpd_reg_names
;
323 config
.hpd_reg_cnt
= ARRAY_SIZE(hpd_reg_names
);
324 config
.hpd_clk_names
= hpd_clk_names
;
325 config
.hpd_clk_cnt
= ARRAY_SIZE(hpd_clk_names
);
326 config
.ddc_clk_gpio
= 100;
327 config
.ddc_data_gpio
= 101;
328 config
.hpd_gpio
= 102;
329 config
.mux_en_gpio
= -1;
330 config
.mux_sel_gpio
= -1;
331 } else if (cpu_is_msm8x60()) {
332 static const char *hpd_reg_names
[] = {
333 "8901_hdmi_mvs", "8901_mpp0"
335 config
.phy_init
= hdmi_phy_8x60_init
;
336 config
.mmio_name
= "hdmi_msm_hdmi_addr";
337 config
.hpd_reg_names
= hpd_reg_names
;
338 config
.hpd_reg_cnt
= ARRAY_SIZE(hpd_reg_names
);
339 config
.hpd_clk_names
= hpd_clk_names
;
340 config
.hpd_clk_cnt
= ARRAY_SIZE(hpd_clk_names
);
341 config
.ddc_clk_gpio
= 170;
342 config
.ddc_data_gpio
= 171;
343 config
.hpd_gpio
= 172;
344 config
.mux_en_gpio
= -1;
345 config
.mux_sel_gpio
= -1;
348 dev
->platform_data
= &config
;
349 set_hdmi_pdev(dev_get_drvdata(master
), to_platform_device(dev
));
353 static void hdmi_unbind(struct device
*dev
, struct device
*master
,
356 set_hdmi_pdev(dev_get_drvdata(master
), NULL
);
359 static const struct component_ops hdmi_ops
= {
361 .unbind
= hdmi_unbind
,
364 static int hdmi_dev_probe(struct platform_device
*pdev
)
366 return component_add(&pdev
->dev
, &hdmi_ops
);
369 static int hdmi_dev_remove(struct platform_device
*pdev
)
371 component_del(&pdev
->dev
, &hdmi_ops
);
375 static const struct of_device_id dt_match
[] = {
376 { .compatible
= "qcom,hdmi-tx" },
380 static struct platform_driver hdmi_driver
= {
381 .probe
= hdmi_dev_probe
,
382 .remove
= hdmi_dev_remove
,
385 .of_match_table
= dt_match
,
389 void __init
hdmi_register(void)
391 platform_driver_register(&hdmi_driver
);
394 void __exit
hdmi_unregister(void)
396 platform_driver_unregister(&hdmi_driver
);