2 * TPD12S015 HDMI ESD protection & level shifter chip 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/completion.h>
13 #include <linux/delay.h>
14 #include <linux/module.h>
15 #include <linux/slab.h>
16 #include <linux/platform_device.h>
17 #include <linux/gpio/consumer.h>
18 #include <linux/mutex.h>
20 #include "../dss/omapdss.h"
22 struct panel_drv_data
{
23 struct omap_dss_device dssdev
;
24 void (*hpd_cb
)(void *cb_data
, enum drm_connector_status status
);
26 struct mutex hpd_lock
;
28 struct gpio_desc
*ct_cp_hpd_gpio
;
29 struct gpio_desc
*ls_oe_gpio
;
30 struct gpio_desc
*hpd_gpio
;
33 #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
35 static int tpd_connect(struct omap_dss_device
*src
,
36 struct omap_dss_device
*dst
)
38 struct panel_drv_data
*ddata
= to_panel_data(dst
);
41 r
= omapdss_device_connect(dst
->dss
, dst
, dst
->next
);
45 gpiod_set_value_cansleep(ddata
->ct_cp_hpd_gpio
, 1);
46 gpiod_set_value_cansleep(ddata
->ls_oe_gpio
, 1);
48 /* DC-DC converter needs at max 300us to get to 90% of 5V */
54 static void tpd_disconnect(struct omap_dss_device
*src
,
55 struct omap_dss_device
*dst
)
57 struct panel_drv_data
*ddata
= to_panel_data(dst
);
59 gpiod_set_value_cansleep(ddata
->ct_cp_hpd_gpio
, 0);
60 gpiod_set_value_cansleep(ddata
->ls_oe_gpio
, 0);
62 omapdss_device_disconnect(dst
, dst
->next
);
65 static int tpd_enable(struct omap_dss_device
*dssdev
)
67 struct omap_dss_device
*src
= dssdev
->src
;
70 if (dssdev
->state
== OMAP_DSS_DISPLAY_ACTIVE
)
73 r
= src
->ops
->enable(src
);
77 dssdev
->state
= OMAP_DSS_DISPLAY_ACTIVE
;
82 static void tpd_disable(struct omap_dss_device
*dssdev
)
84 struct omap_dss_device
*src
= dssdev
->src
;
86 if (dssdev
->state
!= OMAP_DSS_DISPLAY_ACTIVE
)
89 src
->ops
->disable(src
);
91 dssdev
->state
= OMAP_DSS_DISPLAY_DISABLED
;
94 static bool tpd_detect(struct omap_dss_device
*dssdev
)
96 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
98 return gpiod_get_value_cansleep(ddata
->hpd_gpio
);
101 static void tpd_register_hpd_cb(struct omap_dss_device
*dssdev
,
102 void (*cb
)(void *cb_data
,
103 enum drm_connector_status status
),
106 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
108 mutex_lock(&ddata
->hpd_lock
);
110 ddata
->hpd_cb_data
= cb_data
;
111 mutex_unlock(&ddata
->hpd_lock
);
114 static void tpd_unregister_hpd_cb(struct omap_dss_device
*dssdev
)
116 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
118 mutex_lock(&ddata
->hpd_lock
);
119 ddata
->hpd_cb
= NULL
;
120 ddata
->hpd_cb_data
= NULL
;
121 mutex_unlock(&ddata
->hpd_lock
);
124 static const struct omap_dss_device_ops tpd_ops
= {
125 .connect
= tpd_connect
,
126 .disconnect
= tpd_disconnect
,
127 .enable
= tpd_enable
,
128 .disable
= tpd_disable
,
129 .detect
= tpd_detect
,
130 .register_hpd_cb
= tpd_register_hpd_cb
,
131 .unregister_hpd_cb
= tpd_unregister_hpd_cb
,
134 static irqreturn_t
tpd_hpd_isr(int irq
, void *data
)
136 struct panel_drv_data
*ddata
= data
;
138 mutex_lock(&ddata
->hpd_lock
);
140 enum drm_connector_status status
;
142 if (tpd_detect(&ddata
->dssdev
))
143 status
= connector_status_connected
;
145 status
= connector_status_disconnected
;
147 ddata
->hpd_cb(ddata
->hpd_cb_data
, status
);
149 mutex_unlock(&ddata
->hpd_lock
);
154 static int tpd_probe(struct platform_device
*pdev
)
156 struct omap_dss_device
*dssdev
;
157 struct panel_drv_data
*ddata
;
159 struct gpio_desc
*gpio
;
161 ddata
= devm_kzalloc(&pdev
->dev
, sizeof(*ddata
), GFP_KERNEL
);
165 platform_set_drvdata(pdev
, ddata
);
167 gpio
= devm_gpiod_get_index_optional(&pdev
->dev
, NULL
, 0,
170 return PTR_ERR(gpio
);
172 ddata
->ct_cp_hpd_gpio
= gpio
;
174 gpio
= devm_gpiod_get_index_optional(&pdev
->dev
, NULL
, 1,
177 return PTR_ERR(gpio
);
179 ddata
->ls_oe_gpio
= gpio
;
181 gpio
= devm_gpiod_get_index(&pdev
->dev
, NULL
, 2,
184 return PTR_ERR(gpio
);
186 ddata
->hpd_gpio
= gpio
;
188 mutex_init(&ddata
->hpd_lock
);
190 r
= devm_request_threaded_irq(&pdev
->dev
, gpiod_to_irq(ddata
->hpd_gpio
),
192 IRQF_TRIGGER_RISING
| IRQF_TRIGGER_FALLING
| IRQF_ONESHOT
,
193 "tpd12s015 hpd", ddata
);
197 dssdev
= &ddata
->dssdev
;
198 dssdev
->ops
= &tpd_ops
;
199 dssdev
->dev
= &pdev
->dev
;
200 dssdev
->type
= OMAP_DISPLAY_TYPE_HDMI
;
201 dssdev
->output_type
= OMAP_DISPLAY_TYPE_HDMI
;
202 dssdev
->owner
= THIS_MODULE
;
203 dssdev
->of_ports
= BIT(1) | BIT(0);
204 dssdev
->ops_flags
= OMAP_DSS_DEVICE_OP_DETECT
205 | OMAP_DSS_DEVICE_OP_HPD
;
207 dssdev
->next
= omapdss_of_find_connected_device(pdev
->dev
.of_node
, 1);
208 if (IS_ERR(dssdev
->next
)) {
209 if (PTR_ERR(dssdev
->next
) != -EPROBE_DEFER
)
210 dev_err(&pdev
->dev
, "failed to find video sink\n");
211 return PTR_ERR(dssdev
->next
);
214 omapdss_device_register(dssdev
);
219 static int __exit
tpd_remove(struct platform_device
*pdev
)
221 struct panel_drv_data
*ddata
= platform_get_drvdata(pdev
);
222 struct omap_dss_device
*dssdev
= &ddata
->dssdev
;
225 omapdss_device_put(dssdev
->next
);
226 omapdss_device_unregister(&ddata
->dssdev
);
228 WARN_ON(omapdss_device_is_enabled(dssdev
));
229 if (omapdss_device_is_enabled(dssdev
))
232 WARN_ON(omapdss_device_is_connected(dssdev
));
233 if (omapdss_device_is_connected(dssdev
))
234 omapdss_device_disconnect(NULL
, dssdev
);
239 static const struct of_device_id tpd_of_match
[] = {
240 { .compatible
= "omapdss,ti,tpd12s015", },
244 MODULE_DEVICE_TABLE(of
, tpd_of_match
);
246 static struct platform_driver tpd_driver
= {
248 .remove
= __exit_p(tpd_remove
),
251 .of_match_table
= tpd_of_match
,
252 .suppress_bind_attrs
= true,
256 module_platform_driver(tpd_driver
);
258 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
259 MODULE_DESCRIPTION("TPD12S015 driver");
260 MODULE_LICENSE("GPL");