]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/video/omap2/displays-new/connector-hdmi.c
Merge branches 'fixes', 'misc', 'mmci', 'unstable/dma-for-next' and 'sa11x0' into...
[karo-tx-linux.git] / drivers / video / omap2 / displays-new / connector-hdmi.c
1 /*
2  * HDMI 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 <drm/drm_edid.h>
17
18 #include <video/omapdss.h>
19 #include <video/omap-panel-data.h>
20
21 static const struct omap_video_timings hdmic_default_timings = {
22         .x_res          = 640,
23         .y_res          = 480,
24         .pixel_clock    = 25175,
25         .hsw            = 96,
26         .hfp            = 16,
27         .hbp            = 48,
28         .vsw            = 2,
29         .vfp            = 11,
30         .vbp            = 31,
31
32         .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
33         .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
34
35         .interlace      = false,
36 };
37
38 struct panel_drv_data {
39         struct omap_dss_device dssdev;
40         struct omap_dss_device *in;
41
42         struct device *dev;
43
44         struct omap_video_timings timings;
45 };
46
47 #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
48
49 static int hdmic_connect(struct omap_dss_device *dssdev)
50 {
51         struct panel_drv_data *ddata = to_panel_data(dssdev);
52         struct omap_dss_device *in = ddata->in;
53         int r;
54
55         dev_dbg(ddata->dev, "connect\n");
56
57         if (omapdss_device_is_connected(dssdev))
58                 return 0;
59
60         r = in->ops.hdmi->connect(in, dssdev);
61         if (r)
62                 return r;
63
64         return 0;
65 }
66
67 static void hdmic_disconnect(struct omap_dss_device *dssdev)
68 {
69         struct panel_drv_data *ddata = to_panel_data(dssdev);
70         struct omap_dss_device *in = ddata->in;
71
72         dev_dbg(ddata->dev, "disconnect\n");
73
74         if (!omapdss_device_is_connected(dssdev))
75                 return;
76
77         in->ops.hdmi->disconnect(in, dssdev);
78 }
79
80 static int hdmic_enable(struct omap_dss_device *dssdev)
81 {
82         struct panel_drv_data *ddata = to_panel_data(dssdev);
83         struct omap_dss_device *in = ddata->in;
84         int r;
85
86         dev_dbg(ddata->dev, "enable\n");
87
88         if (!omapdss_device_is_connected(dssdev))
89                 return -ENODEV;
90
91         if (omapdss_device_is_enabled(dssdev))
92                 return 0;
93
94         in->ops.hdmi->set_timings(in, &ddata->timings);
95
96         r = in->ops.hdmi->enable(in);
97         if (r)
98                 return r;
99
100         dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
101
102         return r;
103 }
104
105 static void hdmic_disable(struct omap_dss_device *dssdev)
106 {
107         struct panel_drv_data *ddata = to_panel_data(dssdev);
108         struct omap_dss_device *in = ddata->in;
109
110         dev_dbg(ddata->dev, "disable\n");
111
112         if (!omapdss_device_is_enabled(dssdev))
113                 return;
114
115         in->ops.hdmi->disable(in);
116
117         dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
118 }
119
120 static void hdmic_set_timings(struct omap_dss_device *dssdev,
121                 struct omap_video_timings *timings)
122 {
123         struct panel_drv_data *ddata = to_panel_data(dssdev);
124         struct omap_dss_device *in = ddata->in;
125
126         ddata->timings = *timings;
127         dssdev->panel.timings = *timings;
128
129         in->ops.hdmi->set_timings(in, timings);
130 }
131
132 static void hdmic_get_timings(struct omap_dss_device *dssdev,
133                 struct omap_video_timings *timings)
134 {
135         struct panel_drv_data *ddata = to_panel_data(dssdev);
136
137         *timings = ddata->timings;
138 }
139
140 static int hdmic_check_timings(struct omap_dss_device *dssdev,
141                 struct omap_video_timings *timings)
142 {
143         struct panel_drv_data *ddata = to_panel_data(dssdev);
144         struct omap_dss_device *in = ddata->in;
145
146         return in->ops.hdmi->check_timings(in, timings);
147 }
148
149 static int hdmic_read_edid(struct omap_dss_device *dssdev,
150                 u8 *edid, int len)
151 {
152         struct panel_drv_data *ddata = to_panel_data(dssdev);
153         struct omap_dss_device *in = ddata->in;
154
155         return in->ops.hdmi->read_edid(in, edid, len);
156 }
157
158 static bool hdmic_detect(struct omap_dss_device *dssdev)
159 {
160         struct panel_drv_data *ddata = to_panel_data(dssdev);
161         struct omap_dss_device *in = ddata->in;
162
163         return in->ops.hdmi->detect(in);
164 }
165
166 static int hdmic_audio_enable(struct omap_dss_device *dssdev)
167 {
168         struct panel_drv_data *ddata = to_panel_data(dssdev);
169         struct omap_dss_device *in = ddata->in;
170         int r;
171
172         /* enable audio only if the display is active */
173         if (!omapdss_device_is_enabled(dssdev))
174                 return -EPERM;
175
176         r = in->ops.hdmi->audio_enable(in);
177         if (r)
178                 return r;
179
180         dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED;
181
182         return 0;
183 }
184
185 static void hdmic_audio_disable(struct omap_dss_device *dssdev)
186 {
187         struct panel_drv_data *ddata = to_panel_data(dssdev);
188         struct omap_dss_device *in = ddata->in;
189
190         in->ops.hdmi->audio_disable(in);
191
192         dssdev->audio_state = OMAP_DSS_AUDIO_DISABLED;
193 }
194
195 static int hdmic_audio_start(struct omap_dss_device *dssdev)
196 {
197         struct panel_drv_data *ddata = to_panel_data(dssdev);
198         struct omap_dss_device *in = ddata->in;
199         int r;
200
201         /*
202          * No need to check the panel state. It was checked when trasitioning
203          * to AUDIO_ENABLED.
204          */
205         if (dssdev->audio_state != OMAP_DSS_AUDIO_ENABLED)
206                 return -EPERM;
207
208         r = in->ops.hdmi->audio_start(in);
209         if (r)
210                 return r;
211
212         dssdev->audio_state = OMAP_DSS_AUDIO_PLAYING;
213
214         return 0;
215 }
216
217 static void hdmic_audio_stop(struct omap_dss_device *dssdev)
218 {
219         struct panel_drv_data *ddata = to_panel_data(dssdev);
220         struct omap_dss_device *in = ddata->in;
221
222         in->ops.hdmi->audio_stop(in);
223
224         dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED;
225 }
226
227 static bool hdmic_audio_supported(struct omap_dss_device *dssdev)
228 {
229         struct panel_drv_data *ddata = to_panel_data(dssdev);
230         struct omap_dss_device *in = ddata->in;
231
232         if (!omapdss_device_is_enabled(dssdev))
233                 return false;
234
235         return in->ops.hdmi->audio_supported(in);
236 }
237
238 static int hdmic_audio_config(struct omap_dss_device *dssdev,
239                 struct omap_dss_audio *audio)
240 {
241         struct panel_drv_data *ddata = to_panel_data(dssdev);
242         struct omap_dss_device *in = ddata->in;
243         int r;
244
245         /* config audio only if the display is active */
246         if (!omapdss_device_is_enabled(dssdev))
247                 return -EPERM;
248
249         r = in->ops.hdmi->audio_config(in, audio);
250         if (r)
251                 return r;
252
253         dssdev->audio_state = OMAP_DSS_AUDIO_CONFIGURED;
254
255         return 0;
256 }
257
258 static struct omap_dss_driver hdmic_driver = {
259         .connect                = hdmic_connect,
260         .disconnect             = hdmic_disconnect,
261
262         .enable                 = hdmic_enable,
263         .disable                = hdmic_disable,
264
265         .set_timings            = hdmic_set_timings,
266         .get_timings            = hdmic_get_timings,
267         .check_timings          = hdmic_check_timings,
268
269         .get_resolution         = omapdss_default_get_resolution,
270
271         .read_edid              = hdmic_read_edid,
272         .detect                 = hdmic_detect,
273
274         .audio_enable           = hdmic_audio_enable,
275         .audio_disable          = hdmic_audio_disable,
276         .audio_start            = hdmic_audio_start,
277         .audio_stop             = hdmic_audio_stop,
278         .audio_supported        = hdmic_audio_supported,
279         .audio_config           = hdmic_audio_config,
280 };
281
282 static int hdmic_probe_pdata(struct platform_device *pdev)
283 {
284         struct panel_drv_data *ddata = platform_get_drvdata(pdev);
285         struct connector_hdmi_platform_data *pdata;
286         struct omap_dss_device *in, *dssdev;
287
288         pdata = dev_get_platdata(&pdev->dev);
289
290         in = omap_dss_find_output(pdata->source);
291         if (in == NULL) {
292                 dev_err(&pdev->dev, "Failed to find video source\n");
293                 return -EPROBE_DEFER;
294         }
295
296         ddata->in = in;
297
298         dssdev = &ddata->dssdev;
299         dssdev->name = pdata->name;
300
301         return 0;
302 }
303
304 static int hdmic_probe(struct platform_device *pdev)
305 {
306         struct panel_drv_data *ddata;
307         struct omap_dss_device *dssdev;
308         int r;
309
310         ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
311         if (!ddata)
312                 return -ENOMEM;
313
314         platform_set_drvdata(pdev, ddata);
315         ddata->dev = &pdev->dev;
316
317         if (dev_get_platdata(&pdev->dev)) {
318                 r = hdmic_probe_pdata(pdev);
319                 if (r)
320                         return r;
321         } else {
322                 return -ENODEV;
323         }
324
325         ddata->timings = hdmic_default_timings;
326
327         dssdev = &ddata->dssdev;
328         dssdev->driver = &hdmic_driver;
329         dssdev->dev = &pdev->dev;
330         dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
331         dssdev->owner = THIS_MODULE;
332         dssdev->panel.timings = hdmic_default_timings;
333
334         r = omapdss_register_display(dssdev);
335         if (r) {
336                 dev_err(&pdev->dev, "Failed to register panel\n");
337                 goto err_reg;
338         }
339
340         return 0;
341 err_reg:
342         omap_dss_put_device(ddata->in);
343         return r;
344 }
345
346 static int __exit hdmic_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         struct omap_dss_device *in = ddata->in;
351
352         omapdss_unregister_display(&ddata->dssdev);
353
354         hdmic_disable(dssdev);
355         hdmic_disconnect(dssdev);
356
357         omap_dss_put_device(in);
358
359         return 0;
360 }
361
362 static struct platform_driver hdmi_connector_driver = {
363         .probe  = hdmic_probe,
364         .remove = __exit_p(hdmic_remove),
365         .driver = {
366                 .name   = "connector-hdmi",
367                 .owner  = THIS_MODULE,
368         },
369 };
370
371 module_platform_driver(hdmi_connector_driver);
372
373 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
374 MODULE_DESCRIPTION("HDMI Connector driver");
375 MODULE_LICENSE("GPL");