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