aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ti.com>2015-12-09 13:26:00 -0500
committerTomi Valkeinen <tomi.valkeinen@ti.com>2015-12-29 04:07:48 -0500
commit9960aa7cb58caadef8edf3a2582e30664a6b68dd (patch)
treeff7cfe2855cca84c59beccba9f2ca7cea36541c2 /drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c
parent5ca28914b8b4371cfa56b6ee2dec68debb99718f (diff)
drm/omap: move omapdss & displays under omapdrm
Now that omapfb has its own copy of omapdss and display drivers, we can move omapdss and display drivers which omapdrm uses to omapdrm's directory. We also need to change the main drm Makefile so that omapdrm directory is always entered, because omapdss has a file that can't be built as a module. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com> Acked-by: Dave Airlie <airlied@gmail.com> Acked-by: Rob Clark <robdclark@gmail.com>
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");