1 // SPDX-License-Identifier: GPL-2.0
3 * TPD12S015 HDMI ESD protection & level shifter chip driver
5 * Copyright (C) 2019 Texas Instruments Incorporated
7 * Based on the omapdrm-specific encoder-opa362 driver
9 * Copyright (C) 2013 Texas Instruments Incorporated
10 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
13 #include <linux/delay.h>
14 #include <linux/gpio/consumer.h>
15 #include <linux/interrupt.h>
16 #include <linux/module.h>
17 #include <linux/mutex.h>
19 #include <linux/of_graph.h>
20 #include <linux/platform_device.h>
22 #include <drm/drm_bridge.h>
24 struct tpd12s015_device
{
25 struct drm_bridge bridge
;
27 struct gpio_desc
*ct_cp_hpd_gpio
;
28 struct gpio_desc
*ls_oe_gpio
;
29 struct gpio_desc
*hpd_gpio
;
32 struct drm_bridge
*next_bridge
;
35 static inline struct tpd12s015_device
*to_tpd12s015(struct drm_bridge
*bridge
)
37 return container_of(bridge
, struct tpd12s015_device
, bridge
);
40 static int tpd12s015_attach(struct drm_bridge
*bridge
,
41 enum drm_bridge_attach_flags flags
)
43 struct tpd12s015_device
*tpd
= to_tpd12s015(bridge
);
46 if (!(flags
& DRM_BRIDGE_ATTACH_NO_CONNECTOR
))
49 ret
= drm_bridge_attach(bridge
->encoder
, tpd
->next_bridge
,
54 gpiod_set_value_cansleep(tpd
->ls_oe_gpio
, 1);
56 /* DC-DC converter needs at max 300us to get to 90% of 5V. */
57 usleep_range(300, 1000);
62 static void tpd12s015_detach(struct drm_bridge
*bridge
)
64 struct tpd12s015_device
*tpd
= to_tpd12s015(bridge
);
66 gpiod_set_value_cansleep(tpd
->ls_oe_gpio
, 0);
69 static enum drm_connector_status
tpd12s015_detect(struct drm_bridge
*bridge
)
71 struct tpd12s015_device
*tpd
= to_tpd12s015(bridge
);
73 if (gpiod_get_value_cansleep(tpd
->hpd_gpio
))
74 return connector_status_connected
;
76 return connector_status_disconnected
;
79 static void tpd12s015_hpd_enable(struct drm_bridge
*bridge
)
81 struct tpd12s015_device
*tpd
= to_tpd12s015(bridge
);
83 gpiod_set_value_cansleep(tpd
->ct_cp_hpd_gpio
, 1);
86 static void tpd12s015_hpd_disable(struct drm_bridge
*bridge
)
88 struct tpd12s015_device
*tpd
= to_tpd12s015(bridge
);
90 gpiod_set_value_cansleep(tpd
->ct_cp_hpd_gpio
, 0);
93 static const struct drm_bridge_funcs tpd12s015_bridge_funcs
= {
94 .attach
= tpd12s015_attach
,
95 .detach
= tpd12s015_detach
,
96 .detect
= tpd12s015_detect
,
97 .hpd_enable
= tpd12s015_hpd_enable
,
98 .hpd_disable
= tpd12s015_hpd_disable
,
101 static irqreturn_t
tpd12s015_hpd_isr(int irq
, void *data
)
103 struct tpd12s015_device
*tpd
= data
;
104 struct drm_bridge
*bridge
= &tpd
->bridge
;
106 drm_bridge_hpd_notify(bridge
, tpd12s015_detect(bridge
));
111 static int tpd12s015_probe(struct platform_device
*pdev
)
113 struct tpd12s015_device
*tpd
;
114 struct device_node
*node
;
115 struct gpio_desc
*gpio
;
118 tpd
= devm_kzalloc(&pdev
->dev
, sizeof(*tpd
), GFP_KERNEL
);
122 platform_set_drvdata(pdev
, tpd
);
124 tpd
->bridge
.funcs
= &tpd12s015_bridge_funcs
;
125 tpd
->bridge
.of_node
= pdev
->dev
.of_node
;
126 tpd
->bridge
.type
= DRM_MODE_CONNECTOR_HDMIA
;
127 tpd
->bridge
.ops
= DRM_BRIDGE_OP_DETECT
;
129 /* Get the next bridge, connected to port@1. */
130 node
= of_graph_get_remote_node(pdev
->dev
.of_node
, 1, -1);
134 tpd
->next_bridge
= of_drm_find_bridge(node
);
137 if (!tpd
->next_bridge
)
138 return -EPROBE_DEFER
;
140 /* Get the control and HPD GPIOs. */
141 gpio
= devm_gpiod_get_index_optional(&pdev
->dev
, NULL
, 0,
144 return PTR_ERR(gpio
);
146 tpd
->ct_cp_hpd_gpio
= gpio
;
148 gpio
= devm_gpiod_get_index_optional(&pdev
->dev
, NULL
, 1,
151 return PTR_ERR(gpio
);
153 tpd
->ls_oe_gpio
= gpio
;
155 gpio
= devm_gpiod_get_index(&pdev
->dev
, NULL
, 2, GPIOD_IN
);
157 return PTR_ERR(gpio
);
159 tpd
->hpd_gpio
= gpio
;
161 /* Register the IRQ if the HPD GPIO is IRQ-capable. */
162 tpd
->hpd_irq
= gpiod_to_irq(tpd
->hpd_gpio
);
163 if (tpd
->hpd_irq
>= 0) {
164 ret
= devm_request_threaded_irq(&pdev
->dev
, tpd
->hpd_irq
, NULL
,
166 IRQF_TRIGGER_RISING
|
167 IRQF_TRIGGER_FALLING
|
169 "tpd12s015 hpd", tpd
);
173 tpd
->bridge
.ops
|= DRM_BRIDGE_OP_HPD
;
176 /* Register the DRM bridge. */
177 drm_bridge_add(&tpd
->bridge
);
182 static int __exit
tpd12s015_remove(struct platform_device
*pdev
)
184 struct tpd12s015_device
*tpd
= platform_get_drvdata(pdev
);
186 drm_bridge_remove(&tpd
->bridge
);
191 static const struct of_device_id tpd12s015_of_match
[] = {
192 { .compatible
= "ti,tpd12s015", },
196 MODULE_DEVICE_TABLE(of
, tpd12s015_of_match
);
198 static struct platform_driver tpd12s015_driver
= {
199 .probe
= tpd12s015_probe
,
200 .remove
= __exit_p(tpd12s015_remove
),
203 .of_match_table
= tpd12s015_of_match
,
207 module_platform_driver(tpd12s015_driver
);
209 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
210 MODULE_DESCRIPTION("TPD12S015 HDMI level shifter and ESD protection driver");
211 MODULE_LICENSE("GPL");