aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-01-18 14:58:31 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2016-01-18 14:58:31 -0500
commitd43fb9f3c5dff281dd72bea5cd2e91386fdc33a8 (patch)
tree4f3f2b00629b2df1ce4f02684689ccaa4b434854 /drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c
parent5807fcaa9bf7dd87241df739161c119cf78a6bc4 (diff)
parent6f6abd360603aff043352db90c28748c8c46560e (diff)
Merge tag 'fbdev-4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux
Pull fbdev updates from Tomi Valkeinen: "Summary: - pxafb: device-tree support - An unsafe kernel parameter 'lockless_register_fb' for debugging problems happening while inside the console lock - Small miscellaneous fixes & cleanups - omapdss: add writeback support functions - Separation of omapfb and omapdrm (see below) About the separation of omapfb and omapdrm, see http://permalink.gmane.org/gmane.comp.video.dri.devel/143151 for longer story. The short version: omapfb and omapdrm have shared low level drivers (omapdss and panel drivers), making further development of omapdrm difficult. After these patches omapfb and omapdrm have their own versions of the drivers, which are more or less direct copies for now but will diverge soon. This also means that omapfb (everything under drivers/video/fbdev/omap2/) is now in maintenance mode, and all new development will be done for omapdrm (drivers/gpu/drm/omapdrm/)" * tag 'fbdev-4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux: (49 commits) video: fbdev: pxafb: fix out of memory error path drm/omap: make omapdrm select OMAP2_DSS drm/omap: move omapdss & displays under omapdrm omapfb: move vrfb into omapfb omapfb: take omapfb's private omapdss into use omapfb/displays: change CONFIG_DISPLAY_* to CONFIG_FB_OMAP2_* omapfb/dss: change CONFIG_OMAP* to CONFIG_FB_OMAP* omapdss: remove CONFIG_OMAP2_DSS_VENC from omapdss.h omapfb: copy omapdss & displays for omapfb omapfb: allow compilation only if DRM_OMAP is disabled fbdev: omap2: panel-dpi: simplify gpio setting fbdev: omap2: panel-dpi: in .disable first disable backlight then display OMAPDSS: DSS: fix a warning message video: omapdss: delete unneeded of_node_put OMAPDSS: DISPC: Remove boolean comparisons OMAPDSS: DSI: cleanup DSI_IRQ_ERROR_MASK define OMAPDSS: remove extra out == NULL checks OMAPDSS: change internal dispc functions to static OMAPDSS: make a two dss feat funcs internal to omapdss OMAPDSS: remove extra EXPORT_SYMBOLs ...
Diffstat (limited to 'drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c')
-rw-r--r--drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c320
1 files changed, 320 insertions, 0 deletions
diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c b/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c
new file mode 100644
index 000000000000..d9048b3df495
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c
@@ -0,0 +1,320 @@
1/*
2 * TFP410 DPI-to-DVI encoder driver
3 *
4 * Copyright (C) 2013 Texas Instruments
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/gpio.h>
13#include <linux/module.h>
14#include <linux/platform_device.h>
15#include <linux/slab.h>
16#include <linux/of_gpio.h>
17
18#include <video/omapdss.h>
19#include <video/omap-panel-data.h>
20
21struct panel_drv_data {
22 struct omap_dss_device dssdev;
23 struct omap_dss_device *in;
24
25 int pd_gpio;
26 int data_lines;
27
28 struct omap_video_timings timings;
29};
30
31#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
32
33static int tfp410_connect(struct omap_dss_device *dssdev,
34 struct omap_dss_device *dst)
35{
36 struct panel_drv_data *ddata = to_panel_data(dssdev);
37 struct omap_dss_device *in = ddata->in;
38 int r;
39
40 if (omapdss_device_is_connected(dssdev))
41 return -EBUSY;
42
43 r = in->ops.dpi->connect(in, dssdev);
44 if (r)
45 return r;
46
47 dst->src = dssdev;
48 dssdev->dst = dst;
49
50 return 0;
51}
52
53static void tfp410_disconnect(struct omap_dss_device *dssdev,
54 struct omap_dss_device *dst)
55{
56 struct panel_drv_data *ddata = to_panel_data(dssdev);
57 struct omap_dss_device *in = ddata->in;
58
59 WARN_ON(!omapdss_device_is_connected(dssdev));
60 if (!omapdss_device_is_connected(dssdev))
61 return;
62
63 WARN_ON(dst != dssdev->dst);
64 if (dst != dssdev->dst)
65 return;
66
67 dst->src = NULL;
68 dssdev->dst = NULL;
69
70 in->ops.dpi->disconnect(in, &ddata->dssdev);
71}
72
73static int tfp410_enable(struct omap_dss_device *dssdev)
74{
75 struct panel_drv_data *ddata = to_panel_data(dssdev);
76 struct omap_dss_device *in = ddata->in;
77 int r;
78
79 if (!omapdss_device_is_connected(dssdev))
80 return -ENODEV;
81
82 if (omapdss_device_is_enabled(dssdev))
83 return 0;
84
85 in->ops.dpi->set_timings(in, &ddata->timings);
86 if (ddata->data_lines)
87 in->ops.dpi->set_data_lines(in, ddata->data_lines);
88
89 r = in->ops.dpi->enable(in);
90 if (r)
91 return r;
92
93 if (gpio_is_valid(ddata->pd_gpio))
94 gpio_set_value_cansleep(ddata->pd_gpio, 1);
95
96 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
97
98 return 0;
99}
100
101static void tfp410_disable(struct omap_dss_device *dssdev)
102{
103 struct panel_drv_data *ddata = to_panel_data(dssdev);
104 struct omap_dss_device *in = ddata->in;
105
106 if (!omapdss_device_is_enabled(dssdev))
107 return;
108
109 if (gpio_is_valid(ddata->pd_gpio))
110 gpio_set_value_cansleep(ddata->pd_gpio, 0);
111
112 in->ops.dpi->disable(in);
113
114 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
115}
116
117static void tfp410_fix_timings(struct omap_video_timings *timings)
118{
119 timings->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
120 timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
121 timings->de_level = OMAPDSS_SIG_ACTIVE_HIGH;
122}
123
124static void tfp410_set_timings(struct omap_dss_device *dssdev,
125 struct omap_video_timings *timings)
126{
127 struct panel_drv_data *ddata = to_panel_data(dssdev);
128 struct omap_dss_device *in = ddata->in;
129
130 tfp410_fix_timings(timings);
131
132 ddata->timings = *timings;
133 dssdev->panel.timings = *timings;
134
135 in->ops.dpi->set_timings(in, timings);
136}
137
138static void tfp410_get_timings(struct omap_dss_device *dssdev,
139 struct omap_video_timings *timings)
140{
141 struct panel_drv_data *ddata = to_panel_data(dssdev);
142
143 *timings = ddata->timings;
144}
145
146static int tfp410_check_timings(struct omap_dss_device *dssdev,
147 struct omap_video_timings *timings)
148{
149 struct panel_drv_data *ddata = to_panel_data(dssdev);
150 struct omap_dss_device *in = ddata->in;
151
152 tfp410_fix_timings(timings);
153
154 return in->ops.dpi->check_timings(in, timings);
155}
156
157static const struct omapdss_dvi_ops tfp410_dvi_ops = {
158 .connect = tfp410_connect,
159 .disconnect = tfp410_disconnect,
160
161 .enable = tfp410_enable,
162 .disable = tfp410_disable,
163
164 .check_timings = tfp410_check_timings,
165 .set_timings = tfp410_set_timings,
166 .get_timings = tfp410_get_timings,
167};
168
169static int tfp410_probe_pdata(struct platform_device *pdev)
170{
171 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
172 struct encoder_tfp410_platform_data *pdata;
173 struct omap_dss_device *dssdev, *in;
174
175 pdata = dev_get_platdata(&pdev->dev);
176
177 ddata->pd_gpio = pdata->power_down_gpio;
178
179 ddata->data_lines = pdata->data_lines;
180
181 in = omap_dss_find_output(pdata->source);
182 if (in == NULL) {
183 dev_err(&pdev->dev, "Failed to find video source\n");
184 return -ENODEV;
185 }
186
187 ddata->in = in;
188
189 dssdev = &ddata->dssdev;
190 dssdev->name = pdata->name;
191
192 return 0;
193}
194
195static int tfp410_probe_of(struct platform_device *pdev)
196{
197 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
198 struct device_node *node = pdev->dev.of_node;
199 struct omap_dss_device *in;
200 int gpio;
201
202 gpio = of_get_named_gpio(node, "powerdown-gpios", 0);
203
204 if (gpio_is_valid(gpio) || gpio == -ENOENT) {
205 ddata->pd_gpio = gpio;
206 } else {
207 dev_err(&pdev->dev, "failed to parse PD gpio\n");
208 return gpio;
209 }
210
211 in = omapdss_of_find_source_for_first_ep(node);
212 if (IS_ERR(in)) {
213 dev_err(&pdev->dev, "failed to find video source\n");
214 return PTR_ERR(in);
215 }
216
217 ddata->in = in;
218
219 return 0;
220}
221
222static int tfp410_probe(struct platform_device *pdev)
223{
224 struct panel_drv_data *ddata;
225 struct omap_dss_device *dssdev;
226 int r;
227
228 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
229 if (!ddata)
230 return -ENOMEM;
231
232 platform_set_drvdata(pdev, ddata);
233
234 if (dev_get_platdata(&pdev->dev)) {
235 r = tfp410_probe_pdata(pdev);
236 if (r)
237 return r;
238 } else if (pdev->dev.of_node) {
239 r = tfp410_probe_of(pdev);
240 if (r)
241 return r;
242 } else {
243 return -ENODEV;
244 }
245
246 if (gpio_is_valid(ddata->pd_gpio)) {
247 r = devm_gpio_request_one(&pdev->dev, ddata->pd_gpio,
248 GPIOF_OUT_INIT_LOW, "tfp410 PD");
249 if (r) {
250 dev_err(&pdev->dev, "Failed to request PD GPIO %d\n",
251 ddata->pd_gpio);
252 goto err_gpio;
253 }
254 }
255
256 dssdev = &ddata->dssdev;
257 dssdev->ops.dvi = &tfp410_dvi_ops;
258 dssdev->dev = &pdev->dev;
259 dssdev->type = OMAP_DISPLAY_TYPE_DPI;
260 dssdev->output_type = OMAP_DISPLAY_TYPE_DVI;
261 dssdev->owner = THIS_MODULE;
262 dssdev->phy.dpi.data_lines = ddata->data_lines;
263 dssdev->port_num = 1;
264
265 r = omapdss_register_output(dssdev);
266 if (r) {
267 dev_err(&pdev->dev, "Failed to register output\n");
268 goto err_reg;
269 }
270
271 return 0;
272err_reg:
273err_gpio:
274 omap_dss_put_device(ddata->in);
275 return r;
276}
277
278static int __exit tfp410_remove(struct platform_device *pdev)
279{
280 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
281 struct omap_dss_device *dssdev = &ddata->dssdev;
282 struct omap_dss_device *in = ddata->in;
283
284 omapdss_unregister_output(&ddata->dssdev);
285
286 WARN_ON(omapdss_device_is_enabled(dssdev));
287 if (omapdss_device_is_enabled(dssdev))
288 tfp410_disable(dssdev);
289
290 WARN_ON(omapdss_device_is_connected(dssdev));
291 if (omapdss_device_is_connected(dssdev))
292 tfp410_disconnect(dssdev, dssdev->dst);
293
294 omap_dss_put_device(in);
295
296 return 0;
297}
298
299static const struct of_device_id tfp410_of_match[] = {
300 { .compatible = "omapdss,ti,tfp410", },
301 {},
302};
303
304MODULE_DEVICE_TABLE(of, tfp410_of_match);
305
306static struct platform_driver tfp410_driver = {
307 .probe = tfp410_probe,
308 .remove = __exit_p(tfp410_remove),
309 .driver = {
310 .name = "tfp410",
311 .of_match_table = tfp410_of_match,
312 .suppress_bind_attrs = true,
313 },
314};
315
316module_platform_driver(tfp410_driver);
317
318MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
319MODULE_DESCRIPTION("TFP410 DPI to DVI encoder driver");
320MODULE_LICENSE("GPL");