2 * HDMI Connector driver
4 * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
5 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
12 #include <linux/gpio/consumer.h>
13 #include <linux/module.h>
14 #include <linux/mutex.h>
15 #include <linux/platform_device.h>
16 #include <linux/slab.h>
18 #include "../dss/omapdss.h"
20 struct panel_drv_data
{
21 struct omap_dss_device dssdev
;
22 void (*hpd_cb
)(void *cb_data
, enum drm_connector_status status
);
24 struct mutex hpd_lock
;
28 struct gpio_desc
*hpd_gpio
;
31 #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
33 static int hdmic_connect(struct omap_dss_device
*src
,
34 struct omap_dss_device
*dst
)
39 static void hdmic_disconnect(struct omap_dss_device
*src
,
40 struct omap_dss_device
*dst
)
44 static int hdmic_enable(struct omap_dss_device
*dssdev
)
46 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
47 struct omap_dss_device
*src
= dssdev
->src
;
50 dev_dbg(ddata
->dev
, "enable\n");
52 if (!omapdss_device_is_connected(dssdev
))
55 if (omapdss_device_is_enabled(dssdev
))
58 r
= src
->ops
->enable(src
);
62 dssdev
->state
= OMAP_DSS_DISPLAY_ACTIVE
;
67 static void hdmic_disable(struct omap_dss_device
*dssdev
)
69 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
70 struct omap_dss_device
*src
= dssdev
->src
;
72 dev_dbg(ddata
->dev
, "disable\n");
74 if (!omapdss_device_is_enabled(dssdev
))
77 src
->ops
->disable(src
);
79 dssdev
->state
= OMAP_DSS_DISPLAY_DISABLED
;
82 static bool hdmic_detect(struct omap_dss_device
*dssdev
)
84 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
86 return gpiod_get_value_cansleep(ddata
->hpd_gpio
);
89 static void hdmic_register_hpd_cb(struct omap_dss_device
*dssdev
,
90 void (*cb
)(void *cb_data
,
91 enum drm_connector_status status
),
94 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
96 mutex_lock(&ddata
->hpd_lock
);
98 ddata
->hpd_cb_data
= cb_data
;
99 mutex_unlock(&ddata
->hpd_lock
);
102 static void hdmic_unregister_hpd_cb(struct omap_dss_device
*dssdev
)
104 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
106 mutex_lock(&ddata
->hpd_lock
);
107 ddata
->hpd_cb
= NULL
;
108 ddata
->hpd_cb_data
= NULL
;
109 mutex_unlock(&ddata
->hpd_lock
);
112 static const struct omap_dss_device_ops hdmic_ops
= {
113 .connect
= hdmic_connect
,
114 .disconnect
= hdmic_disconnect
,
116 .enable
= hdmic_enable
,
117 .disable
= hdmic_disable
,
119 .detect
= hdmic_detect
,
120 .register_hpd_cb
= hdmic_register_hpd_cb
,
121 .unregister_hpd_cb
= hdmic_unregister_hpd_cb
,
124 static irqreturn_t
hdmic_hpd_isr(int irq
, void *data
)
126 struct panel_drv_data
*ddata
= data
;
128 mutex_lock(&ddata
->hpd_lock
);
130 enum drm_connector_status status
;
132 if (hdmic_detect(&ddata
->dssdev
))
133 status
= connector_status_connected
;
135 status
= connector_status_disconnected
;
137 ddata
->hpd_cb(ddata
->hpd_cb_data
, status
);
139 mutex_unlock(&ddata
->hpd_lock
);
144 static int hdmic_probe(struct platform_device
*pdev
)
146 struct panel_drv_data
*ddata
;
147 struct omap_dss_device
*dssdev
;
148 struct gpio_desc
*gpio
;
151 ddata
= devm_kzalloc(&pdev
->dev
, sizeof(*ddata
), GFP_KERNEL
);
155 platform_set_drvdata(pdev
, ddata
);
156 ddata
->dev
= &pdev
->dev
;
158 mutex_init(&ddata
->hpd_lock
);
161 gpio
= devm_gpiod_get_optional(&pdev
->dev
, "hpd", GPIOD_IN
);
163 dev_err(&pdev
->dev
, "failed to parse HPD gpio\n");
164 return PTR_ERR(gpio
);
167 ddata
->hpd_gpio
= gpio
;
169 if (ddata
->hpd_gpio
) {
170 r
= devm_request_threaded_irq(&pdev
->dev
,
171 gpiod_to_irq(ddata
->hpd_gpio
),
173 IRQF_TRIGGER_RISING
| IRQF_TRIGGER_FALLING
|
180 dssdev
= &ddata
->dssdev
;
181 dssdev
->ops
= &hdmic_ops
;
182 dssdev
->dev
= &pdev
->dev
;
183 dssdev
->type
= OMAP_DISPLAY_TYPE_HDMI
;
184 dssdev
->owner
= THIS_MODULE
;
185 dssdev
->of_ports
= BIT(0);
186 dssdev
->ops_flags
= ddata
->hpd_gpio
187 ? OMAP_DSS_DEVICE_OP_DETECT
| OMAP_DSS_DEVICE_OP_HPD
190 omapdss_display_init(dssdev
);
191 omapdss_device_register(dssdev
);
196 static int __exit
hdmic_remove(struct platform_device
*pdev
)
198 struct panel_drv_data
*ddata
= platform_get_drvdata(pdev
);
199 struct omap_dss_device
*dssdev
= &ddata
->dssdev
;
201 omapdss_device_unregister(&ddata
->dssdev
);
203 hdmic_disable(dssdev
);
208 static const struct of_device_id hdmic_of_match
[] = {
209 { .compatible
= "omapdss,hdmi-connector", },
213 MODULE_DEVICE_TABLE(of
, hdmic_of_match
);
215 static struct platform_driver hdmi_connector_driver
= {
216 .probe
= hdmic_probe
,
217 .remove
= __exit_p(hdmic_remove
),
219 .name
= "connector-hdmi",
220 .of_match_table
= hdmic_of_match
,
221 .suppress_bind_attrs
= true,
225 module_platform_driver(hdmi_connector_driver
);
227 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
228 MODULE_DESCRIPTION("HDMI Connector driver");
229 MODULE_LICENSE("GPL");