GNU Linux-libre 4.19.264-gnu1
[releases.git] / drivers / gpu / drm / omapdrm / displays / encoder-tpd12s015.c
1 /*
2  * TPD12S015 HDMI ESD protection & level shifter chip driver
3  *
4  * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
5  * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
6  *
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.
10  */
11
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>
19
20 #include "../dss/omapdss.h"
21
22 struct panel_drv_data {
23         struct omap_dss_device dssdev;
24         struct omap_dss_device *in;
25         void (*hpd_cb)(void *cb_data, enum drm_connector_status status);
26         void *hpd_cb_data;
27         bool hpd_enabled;
28         struct mutex hpd_lock;
29
30         struct gpio_desc *ct_cp_hpd_gpio;
31         struct gpio_desc *ls_oe_gpio;
32         struct gpio_desc *hpd_gpio;
33
34         struct videomode vm;
35 };
36
37 #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
38
39 static int tpd_connect(struct omap_dss_device *dssdev,
40                 struct omap_dss_device *dst)
41 {
42         struct panel_drv_data *ddata = to_panel_data(dssdev);
43         struct omap_dss_device *in;
44         int r;
45
46         in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
47         if (IS_ERR(in)) {
48                 dev_err(dssdev->dev, "failed to find video source\n");
49                 return PTR_ERR(in);
50         }
51
52         r = in->ops.hdmi->connect(in, dssdev);
53         if (r) {
54                 omap_dss_put_device(in);
55                 return r;
56         }
57
58         dst->src = dssdev;
59         dssdev->dst = dst;
60
61         gpiod_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1);
62         gpiod_set_value_cansleep(ddata->ls_oe_gpio, 1);
63
64         /* DC-DC converter needs at max 300us to get to 90% of 5V */
65         udelay(300);
66
67         ddata->in = in;
68         return 0;
69 }
70
71 static void tpd_disconnect(struct omap_dss_device *dssdev,
72                 struct omap_dss_device *dst)
73 {
74         struct panel_drv_data *ddata = to_panel_data(dssdev);
75         struct omap_dss_device *in = ddata->in;
76
77         WARN_ON(dst != dssdev->dst);
78
79         if (dst != dssdev->dst)
80                 return;
81
82         gpiod_set_value_cansleep(ddata->ct_cp_hpd_gpio, 0);
83         gpiod_set_value_cansleep(ddata->ls_oe_gpio, 0);
84
85         dst->src = NULL;
86         dssdev->dst = NULL;
87
88         in->ops.hdmi->disconnect(in, &ddata->dssdev);
89
90         omap_dss_put_device(in);
91         ddata->in = NULL;
92 }
93
94 static int tpd_enable(struct omap_dss_device *dssdev)
95 {
96         struct panel_drv_data *ddata = to_panel_data(dssdev);
97         struct omap_dss_device *in = ddata->in;
98         int r;
99
100         if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
101                 return 0;
102
103         in->ops.hdmi->set_timings(in, &ddata->vm);
104
105         r = in->ops.hdmi->enable(in);
106         if (r)
107                 return r;
108
109         dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
110
111         return r;
112 }
113
114 static void tpd_disable(struct omap_dss_device *dssdev)
115 {
116         struct panel_drv_data *ddata = to_panel_data(dssdev);
117         struct omap_dss_device *in = ddata->in;
118
119         if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
120                 return;
121
122         in->ops.hdmi->disable(in);
123
124         dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
125 }
126
127 static void tpd_set_timings(struct omap_dss_device *dssdev,
128                             struct videomode *vm)
129 {
130         struct panel_drv_data *ddata = to_panel_data(dssdev);
131         struct omap_dss_device *in = ddata->in;
132
133         ddata->vm = *vm;
134         dssdev->panel.vm = *vm;
135
136         in->ops.hdmi->set_timings(in, vm);
137 }
138
139 static void tpd_get_timings(struct omap_dss_device *dssdev,
140                             struct videomode *vm)
141 {
142         struct panel_drv_data *ddata = to_panel_data(dssdev);
143
144         *vm = ddata->vm;
145 }
146
147 static int tpd_check_timings(struct omap_dss_device *dssdev,
148                              struct videomode *vm)
149 {
150         struct panel_drv_data *ddata = to_panel_data(dssdev);
151         struct omap_dss_device *in = ddata->in;
152         int r;
153
154         r = in->ops.hdmi->check_timings(in, vm);
155
156         return r;
157 }
158
159 static int tpd_read_edid(struct omap_dss_device *dssdev,
160                 u8 *edid, int len)
161 {
162         struct panel_drv_data *ddata = to_panel_data(dssdev);
163         struct omap_dss_device *in = ddata->in;
164
165         if (!gpiod_get_value_cansleep(ddata->hpd_gpio))
166                 return -ENODEV;
167
168         return in->ops.hdmi->read_edid(in, edid, len);
169 }
170
171 static bool tpd_detect(struct omap_dss_device *dssdev)
172 {
173         struct panel_drv_data *ddata = to_panel_data(dssdev);
174         struct omap_dss_device *in = ddata->in;
175         bool connected = gpiod_get_value_cansleep(ddata->hpd_gpio);
176
177         if (!connected && in->ops.hdmi->lost_hotplug)
178                 in->ops.hdmi->lost_hotplug(in);
179         return connected;
180 }
181
182 static int tpd_register_hpd_cb(struct omap_dss_device *dssdev,
183                                void (*cb)(void *cb_data,
184                                           enum drm_connector_status status),
185                                void *cb_data)
186 {
187         struct panel_drv_data *ddata = to_panel_data(dssdev);
188
189         mutex_lock(&ddata->hpd_lock);
190         ddata->hpd_cb = cb;
191         ddata->hpd_cb_data = cb_data;
192         mutex_unlock(&ddata->hpd_lock);
193
194         return 0;
195 }
196
197 static void tpd_unregister_hpd_cb(struct omap_dss_device *dssdev)
198 {
199         struct panel_drv_data *ddata = to_panel_data(dssdev);
200
201         mutex_lock(&ddata->hpd_lock);
202         ddata->hpd_cb = NULL;
203         ddata->hpd_cb_data = NULL;
204         mutex_unlock(&ddata->hpd_lock);
205 }
206
207 static void tpd_enable_hpd(struct omap_dss_device *dssdev)
208 {
209         struct panel_drv_data *ddata = to_panel_data(dssdev);
210
211         mutex_lock(&ddata->hpd_lock);
212         ddata->hpd_enabled = true;
213         mutex_unlock(&ddata->hpd_lock);
214 }
215
216 static void tpd_disable_hpd(struct omap_dss_device *dssdev)
217 {
218         struct panel_drv_data *ddata = to_panel_data(dssdev);
219
220         mutex_lock(&ddata->hpd_lock);
221         ddata->hpd_enabled = false;
222         mutex_unlock(&ddata->hpd_lock);
223 }
224
225 static int tpd_set_infoframe(struct omap_dss_device *dssdev,
226                 const struct hdmi_avi_infoframe *avi)
227 {
228         struct panel_drv_data *ddata = to_panel_data(dssdev);
229         struct omap_dss_device *in = ddata->in;
230
231         return in->ops.hdmi->set_infoframe(in, avi);
232 }
233
234 static int tpd_set_hdmi_mode(struct omap_dss_device *dssdev,
235                 bool hdmi_mode)
236 {
237         struct panel_drv_data *ddata = to_panel_data(dssdev);
238         struct omap_dss_device *in = ddata->in;
239
240         return in->ops.hdmi->set_hdmi_mode(in, hdmi_mode);
241 }
242
243 static const struct omapdss_hdmi_ops tpd_hdmi_ops = {
244         .connect                = tpd_connect,
245         .disconnect             = tpd_disconnect,
246
247         .enable                 = tpd_enable,
248         .disable                = tpd_disable,
249
250         .check_timings          = tpd_check_timings,
251         .set_timings            = tpd_set_timings,
252         .get_timings            = tpd_get_timings,
253
254         .read_edid              = tpd_read_edid,
255         .detect                 = tpd_detect,
256         .register_hpd_cb        = tpd_register_hpd_cb,
257         .unregister_hpd_cb      = tpd_unregister_hpd_cb,
258         .enable_hpd             = tpd_enable_hpd,
259         .disable_hpd            = tpd_disable_hpd,
260         .set_infoframe          = tpd_set_infoframe,
261         .set_hdmi_mode          = tpd_set_hdmi_mode,
262 };
263
264 static irqreturn_t tpd_hpd_isr(int irq, void *data)
265 {
266         struct panel_drv_data *ddata = data;
267
268         mutex_lock(&ddata->hpd_lock);
269         if (ddata->hpd_enabled && ddata->hpd_cb) {
270                 enum drm_connector_status status;
271
272                 if (tpd_detect(&ddata->dssdev))
273                         status = connector_status_connected;
274                 else
275                         status = connector_status_disconnected;
276
277                 ddata->hpd_cb(ddata->hpd_cb_data, status);
278         }
279         mutex_unlock(&ddata->hpd_lock);
280
281         return IRQ_HANDLED;
282 }
283
284 static int tpd_probe(struct platform_device *pdev)
285 {
286         struct omap_dss_device *in, *dssdev;
287         struct panel_drv_data *ddata;
288         int r;
289         struct gpio_desc *gpio;
290
291         ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
292         if (!ddata)
293                 return -ENOMEM;
294
295         platform_set_drvdata(pdev, ddata);
296
297         gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 0,
298                  GPIOD_OUT_LOW);
299         if (IS_ERR(gpio))
300                 return PTR_ERR(gpio);
301
302         ddata->ct_cp_hpd_gpio = gpio;
303
304         gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 1,
305                  GPIOD_OUT_LOW);
306         if (IS_ERR(gpio))
307                 return PTR_ERR(gpio);
308
309         ddata->ls_oe_gpio = gpio;
310
311         gpio = devm_gpiod_get_index(&pdev->dev, NULL, 2,
312                 GPIOD_IN);
313         if (IS_ERR(gpio))
314                 return PTR_ERR(gpio);
315
316         ddata->hpd_gpio = gpio;
317
318         mutex_init(&ddata->hpd_lock);
319
320         r = devm_request_threaded_irq(&pdev->dev, gpiod_to_irq(ddata->hpd_gpio),
321                 NULL, tpd_hpd_isr,
322                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
323                 "tpd12s015 hpd", ddata);
324         if (r)
325                 return r;
326
327         dssdev = &ddata->dssdev;
328         dssdev->ops.hdmi = &tpd_hdmi_ops;
329         dssdev->dev = &pdev->dev;
330         dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
331         dssdev->output_type = OMAP_DISPLAY_TYPE_HDMI;
332         dssdev->owner = THIS_MODULE;
333         dssdev->port_num = 1;
334
335         in = ddata->in;
336
337         r = omapdss_register_output(dssdev);
338         if (r) {
339                 dev_err(&pdev->dev, "Failed to register output\n");
340                 return r;
341         }
342
343         return 0;
344 }
345
346 static int __exit tpd_remove(struct platform_device *pdev)
347 {
348         struct panel_drv_data *ddata = platform_get_drvdata(pdev);
349         struct omap_dss_device *dssdev = &ddata->dssdev;
350
351         omapdss_unregister_output(&ddata->dssdev);
352
353         WARN_ON(omapdss_device_is_enabled(dssdev));
354         if (omapdss_device_is_enabled(dssdev))
355                 tpd_disable(dssdev);
356
357         WARN_ON(omapdss_device_is_connected(dssdev));
358         if (omapdss_device_is_connected(dssdev))
359                 tpd_disconnect(dssdev, dssdev->dst);
360
361         return 0;
362 }
363
364 static const struct of_device_id tpd_of_match[] = {
365         { .compatible = "omapdss,ti,tpd12s015", },
366         {},
367 };
368
369 MODULE_DEVICE_TABLE(of, tpd_of_match);
370
371 static struct platform_driver tpd_driver = {
372         .probe  = tpd_probe,
373         .remove = __exit_p(tpd_remove),
374         .driver = {
375                 .name   = "tpd12s015",
376                 .of_match_table = tpd_of_match,
377                 .suppress_bind_attrs = true,
378         },
379 };
380
381 module_platform_driver(tpd_driver);
382
383 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
384 MODULE_DESCRIPTION("TPD12S015 driver");
385 MODULE_LICENSE("GPL");