]> rtime.felk.cvut.cz Git - linux-imx.git/blob - drivers/video/omap2/displays-new/connector-analog-tv.c
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[linux-imx.git] / drivers / video / omap2 / displays-new / connector-analog-tv.c
1 /*
2  * Analog TV Connector 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/slab.h>
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15
16 #include <video/omapdss.h>
17 #include <video/omap-panel-data.h>
18
19 struct panel_drv_data {
20         struct omap_dss_device dssdev;
21         struct omap_dss_device *in;
22
23         struct device *dev;
24
25         struct omap_video_timings timings;
26
27         enum omap_dss_venc_type connector_type;
28         bool invert_polarity;
29 };
30
31 static const struct omap_video_timings tvc_pal_timings = {
32         .x_res          = 720,
33         .y_res          = 574,
34         .pixel_clock    = 13500,
35         .hsw            = 64,
36         .hfp            = 12,
37         .hbp            = 68,
38         .vsw            = 5,
39         .vfp            = 5,
40         .vbp            = 41,
41
42         .interlace      = true,
43 };
44
45 #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
46
47 static int tvc_connect(struct omap_dss_device *dssdev)
48 {
49         struct panel_drv_data *ddata = to_panel_data(dssdev);
50         struct omap_dss_device *in = ddata->in;
51         int r;
52
53         dev_dbg(ddata->dev, "connect\n");
54
55         if (omapdss_device_is_connected(dssdev))
56                 return 0;
57
58         r = in->ops.atv->connect(in, dssdev);
59         if (r)
60                 return r;
61
62         return 0;
63 }
64
65 static void tvc_disconnect(struct omap_dss_device *dssdev)
66 {
67         struct panel_drv_data *ddata = to_panel_data(dssdev);
68         struct omap_dss_device *in = ddata->in;
69
70         dev_dbg(ddata->dev, "disconnect\n");
71
72         if (!omapdss_device_is_connected(dssdev))
73                 return;
74
75         in->ops.atv->disconnect(in, dssdev);
76 }
77
78 static int tvc_enable(struct omap_dss_device *dssdev)
79 {
80         struct panel_drv_data *ddata = to_panel_data(dssdev);
81         struct omap_dss_device *in = ddata->in;
82         int r;
83
84         dev_dbg(ddata->dev, "enable\n");
85
86         if (!omapdss_device_is_connected(dssdev))
87                 return -ENODEV;
88
89         if (omapdss_device_is_enabled(dssdev))
90                 return 0;
91
92         in->ops.atv->set_timings(in, &ddata->timings);
93
94         in->ops.atv->set_type(in, ddata->connector_type);
95         in->ops.atv->invert_vid_out_polarity(in, ddata->invert_polarity);
96
97         r = in->ops.atv->enable(in);
98         if (r)
99                 return r;
100
101         dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
102
103         return r;
104 }
105
106 static void tvc_disable(struct omap_dss_device *dssdev)
107 {
108         struct panel_drv_data *ddata = to_panel_data(dssdev);
109         struct omap_dss_device *in = ddata->in;
110
111         dev_dbg(ddata->dev, "disable\n");
112
113         if (!omapdss_device_is_enabled(dssdev))
114                 return;
115
116         in->ops.atv->disable(in);
117
118         dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
119 }
120
121 static void tvc_set_timings(struct omap_dss_device *dssdev,
122                 struct omap_video_timings *timings)
123 {
124         struct panel_drv_data *ddata = to_panel_data(dssdev);
125         struct omap_dss_device *in = ddata->in;
126
127         ddata->timings = *timings;
128         dssdev->panel.timings = *timings;
129
130         in->ops.atv->set_timings(in, timings);
131 }
132
133 static void tvc_get_timings(struct omap_dss_device *dssdev,
134                 struct omap_video_timings *timings)
135 {
136         struct panel_drv_data *ddata = to_panel_data(dssdev);
137
138         *timings = ddata->timings;
139 }
140
141 static int tvc_check_timings(struct omap_dss_device *dssdev,
142                 struct omap_video_timings *timings)
143 {
144         struct panel_drv_data *ddata = to_panel_data(dssdev);
145         struct omap_dss_device *in = ddata->in;
146
147         return in->ops.atv->check_timings(in, timings);
148 }
149
150 static u32 tvc_get_wss(struct omap_dss_device *dssdev)
151 {
152         struct panel_drv_data *ddata = to_panel_data(dssdev);
153         struct omap_dss_device *in = ddata->in;
154
155         return in->ops.atv->get_wss(in);
156 }
157
158 static int tvc_set_wss(struct omap_dss_device *dssdev, u32 wss)
159 {
160         struct panel_drv_data *ddata = to_panel_data(dssdev);
161         struct omap_dss_device *in = ddata->in;
162
163         return in->ops.atv->set_wss(in, wss);
164 }
165
166 static struct omap_dss_driver tvc_driver = {
167         .connect                = tvc_connect,
168         .disconnect             = tvc_disconnect,
169
170         .enable                 = tvc_enable,
171         .disable                = tvc_disable,
172
173         .set_timings            = tvc_set_timings,
174         .get_timings            = tvc_get_timings,
175         .check_timings          = tvc_check_timings,
176
177         .get_resolution         = omapdss_default_get_resolution,
178
179         .get_wss                = tvc_get_wss,
180         .set_wss                = tvc_set_wss,
181 };
182
183 static int tvc_probe_pdata(struct platform_device *pdev)
184 {
185         struct panel_drv_data *ddata = platform_get_drvdata(pdev);
186         struct connector_atv_platform_data *pdata;
187         struct omap_dss_device *in, *dssdev;
188
189         pdata = dev_get_platdata(&pdev->dev);
190
191         in = omap_dss_find_output(pdata->source);
192         if (in == NULL) {
193                 dev_err(&pdev->dev, "Failed to find video source\n");
194                 return -ENODEV;
195         }
196
197         ddata->in = in;
198
199         ddata->connector_type = pdata->connector_type;
200         ddata->invert_polarity = ddata->invert_polarity;
201
202         dssdev = &ddata->dssdev;
203         dssdev->name = pdata->name;
204
205         return 0;
206 }
207
208 static int tvc_probe(struct platform_device *pdev)
209 {
210         struct panel_drv_data *ddata;
211         struct omap_dss_device *dssdev;
212         int r;
213
214         ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
215         if (!ddata)
216                 return -ENOMEM;
217
218         platform_set_drvdata(pdev, ddata);
219         ddata->dev = &pdev->dev;
220
221         if (dev_get_platdata(&pdev->dev)) {
222                 r = tvc_probe_pdata(pdev);
223                 if (r)
224                         return r;
225         } else {
226                 return -ENODEV;
227         }
228
229         ddata->timings = tvc_pal_timings;
230
231         dssdev = &ddata->dssdev;
232         dssdev->driver = &tvc_driver;
233         dssdev->dev = &pdev->dev;
234         dssdev->type = OMAP_DISPLAY_TYPE_VENC;
235         dssdev->owner = THIS_MODULE;
236         dssdev->panel.timings = tvc_pal_timings;
237
238         r = omapdss_register_display(dssdev);
239         if (r) {
240                 dev_err(&pdev->dev, "Failed to register panel\n");
241                 goto err_reg;
242         }
243
244         return 0;
245 err_reg:
246         omap_dss_put_device(ddata->in);
247         return r;
248 }
249
250 static int __exit tvc_remove(struct platform_device *pdev)
251 {
252         struct panel_drv_data *ddata = platform_get_drvdata(pdev);
253         struct omap_dss_device *dssdev = &ddata->dssdev;
254         struct omap_dss_device *in = ddata->in;
255
256         omapdss_unregister_display(&ddata->dssdev);
257
258         tvc_disable(dssdev);
259         tvc_disconnect(dssdev);
260
261         omap_dss_put_device(in);
262
263         return 0;
264 }
265
266 static struct platform_driver tvc_connector_driver = {
267         .probe  = tvc_probe,
268         .remove = __exit_p(tvc_remove),
269         .driver = {
270                 .name   = "connector-analog-tv",
271                 .owner  = THIS_MODULE,
272         },
273 };
274
275 module_platform_driver(tvc_connector_driver);
276
277 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
278 MODULE_DESCRIPTION("Analog TV Connector driver");
279 MODULE_LICENSE("GPL");