4 * HDMI library support functions for TI OMAP4 processors.
6 * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
7 * Authors: Mythri P k <mythripk@ti.com>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License version 2 as published by
11 * the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * You should have received a copy of the GNU General Public License along with
19 * this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <linux/kernel.h>
23 #include <linux/err.h>
25 #include <linux/mutex.h>
26 #include <linux/module.h>
27 #include <video/omapdss.h>
28 #include <linux/slab.h>
33 /* This protects the panel ops, mainly when accessing the HDMI IP. */
35 #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
36 /* This protects the audio ops, specifically. */
37 spinlock_t audio_lock;
42 static int hdmi_panel_probe(struct omap_dss_device *dssdev)
44 DSSDBG("ENTER hdmi_panel_probe\n");
46 dssdev->panel.timings = (struct omap_video_timings)
47 { 640, 480, 25175, 96, 16, 48, 2, 11, 31,
48 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
52 DSSDBG("hdmi_panel_probe x_res= %d y_res = %d\n",
53 dssdev->panel.timings.x_res,
54 dssdev->panel.timings.y_res);
58 static void hdmi_panel_remove(struct omap_dss_device *dssdev)
63 #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
64 static int hdmi_panel_audio_enable(struct omap_dss_device *dssdev)
69 mutex_lock(&hdmi.lock);
70 spin_lock_irqsave(&hdmi.audio_lock, flags);
72 /* enable audio only if the display is active and supports audio */
73 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE ||
74 !hdmi_mode_has_audio()) {
75 DSSERR("audio not supported or display is off\n");
80 r = hdmi_audio_enable();
83 dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED;
86 spin_unlock_irqrestore(&hdmi.audio_lock, flags);
87 mutex_unlock(&hdmi.lock);
91 static void hdmi_panel_audio_disable(struct omap_dss_device *dssdev)
95 spin_lock_irqsave(&hdmi.audio_lock, flags);
99 dssdev->audio_state = OMAP_DSS_AUDIO_DISABLED;
101 spin_unlock_irqrestore(&hdmi.audio_lock, flags);
104 static int hdmi_panel_audio_start(struct omap_dss_device *dssdev)
109 spin_lock_irqsave(&hdmi.audio_lock, flags);
111 * No need to check the panel state. It was checked when trasitioning
114 if (dssdev->audio_state != OMAP_DSS_AUDIO_ENABLED) {
115 DSSERR("audio start from invalid state\n");
120 r = hdmi_audio_start();
123 dssdev->audio_state = OMAP_DSS_AUDIO_PLAYING;
126 spin_unlock_irqrestore(&hdmi.audio_lock, flags);
130 static void hdmi_panel_audio_stop(struct omap_dss_device *dssdev)
134 spin_lock_irqsave(&hdmi.audio_lock, flags);
137 dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED;
139 spin_unlock_irqrestore(&hdmi.audio_lock, flags);
142 static bool hdmi_panel_audio_supported(struct omap_dss_device *dssdev)
146 mutex_lock(&hdmi.lock);
148 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
151 if (!hdmi_mode_has_audio())
156 mutex_unlock(&hdmi.lock);
160 static int hdmi_panel_audio_config(struct omap_dss_device *dssdev,
161 struct omap_dss_audio *audio)
166 mutex_lock(&hdmi.lock);
167 spin_lock_irqsave(&hdmi.audio_lock, flags);
169 /* config audio only if the display is active and supports audio */
170 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE ||
171 !hdmi_mode_has_audio()) {
172 DSSERR("audio not supported or display is off\n");
177 r = hdmi_audio_config(audio);
180 dssdev->audio_state = OMAP_DSS_AUDIO_CONFIGURED;
183 spin_unlock_irqrestore(&hdmi.audio_lock, flags);
184 mutex_unlock(&hdmi.lock);
189 static int hdmi_panel_audio_enable(struct omap_dss_device *dssdev)
194 static void hdmi_panel_audio_disable(struct omap_dss_device *dssdev)
198 static int hdmi_panel_audio_start(struct omap_dss_device *dssdev)
203 static void hdmi_panel_audio_stop(struct omap_dss_device *dssdev)
207 static bool hdmi_panel_audio_supported(struct omap_dss_device *dssdev)
212 static int hdmi_panel_audio_config(struct omap_dss_device *dssdev,
213 struct omap_dss_audio *audio)
219 static int hdmi_panel_enable(struct omap_dss_device *dssdev)
222 DSSDBG("ENTER hdmi_panel_enable\n");
224 mutex_lock(&hdmi.lock);
226 if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
231 r = omapdss_hdmi_display_enable(dssdev);
233 DSSERR("failed to power on\n");
237 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
240 mutex_unlock(&hdmi.lock);
245 static void hdmi_panel_disable(struct omap_dss_device *dssdev)
247 mutex_lock(&hdmi.lock);
249 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
251 * TODO: notify audio users that the display was disabled. For
252 * now, disable audio locally to not break our audio state
255 hdmi_panel_audio_disable(dssdev);
256 omapdss_hdmi_display_disable(dssdev);
259 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
261 mutex_unlock(&hdmi.lock);
264 static int hdmi_panel_suspend(struct omap_dss_device *dssdev)
268 mutex_lock(&hdmi.lock);
270 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
276 * TODO: notify audio users that the display was suspended. For now,
277 * disable audio locally to not break our audio state machine.
279 hdmi_panel_audio_disable(dssdev);
281 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
282 omapdss_hdmi_display_disable(dssdev);
285 mutex_unlock(&hdmi.lock);
290 static int hdmi_panel_resume(struct omap_dss_device *dssdev)
294 mutex_lock(&hdmi.lock);
296 if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
301 r = omapdss_hdmi_display_enable(dssdev);
303 DSSERR("failed to power on\n");
306 /* TODO: notify audio users that the panel resumed. */
308 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
311 mutex_unlock(&hdmi.lock);
316 static void hdmi_get_timings(struct omap_dss_device *dssdev,
317 struct omap_video_timings *timings)
319 mutex_lock(&hdmi.lock);
321 *timings = dssdev->panel.timings;
323 mutex_unlock(&hdmi.lock);
326 static void hdmi_set_timings(struct omap_dss_device *dssdev,
327 struct omap_video_timings *timings)
329 DSSDBG("hdmi_set_timings\n");
331 mutex_lock(&hdmi.lock);
334 * TODO: notify audio users that there was a timings change. For
335 * now, disable audio locally to not break our audio state machine.
337 hdmi_panel_audio_disable(dssdev);
339 dssdev->panel.timings = *timings;
340 omapdss_hdmi_display_set_timing(dssdev);
342 mutex_unlock(&hdmi.lock);
345 static int hdmi_check_timings(struct omap_dss_device *dssdev,
346 struct omap_video_timings *timings)
350 DSSDBG("hdmi_check_timings\n");
352 mutex_lock(&hdmi.lock);
354 r = omapdss_hdmi_display_check_timing(dssdev, timings);
356 mutex_unlock(&hdmi.lock);
360 static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len)
364 mutex_lock(&hdmi.lock);
366 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
367 r = omapdss_hdmi_display_enable(dssdev);
372 r = omapdss_hdmi_read_edid(buf, len);
374 if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED ||
375 dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
376 omapdss_hdmi_display_disable(dssdev);
378 mutex_unlock(&hdmi.lock);
383 static bool hdmi_detect(struct omap_dss_device *dssdev)
387 mutex_lock(&hdmi.lock);
389 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
390 r = omapdss_hdmi_display_enable(dssdev);
395 r = omapdss_hdmi_detect();
397 if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED ||
398 dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
399 omapdss_hdmi_display_disable(dssdev);
401 mutex_unlock(&hdmi.lock);
406 static struct omap_dss_driver hdmi_driver = {
407 .probe = hdmi_panel_probe,
408 .remove = hdmi_panel_remove,
409 .enable = hdmi_panel_enable,
410 .disable = hdmi_panel_disable,
411 .suspend = hdmi_panel_suspend,
412 .resume = hdmi_panel_resume,
413 .get_timings = hdmi_get_timings,
414 .set_timings = hdmi_set_timings,
415 .check_timings = hdmi_check_timings,
416 .read_edid = hdmi_read_edid,
417 .detect = hdmi_detect,
418 .audio_enable = hdmi_panel_audio_enable,
419 .audio_disable = hdmi_panel_audio_disable,
420 .audio_start = hdmi_panel_audio_start,
421 .audio_stop = hdmi_panel_audio_stop,
422 .audio_supported = hdmi_panel_audio_supported,
423 .audio_config = hdmi_panel_audio_config,
425 .name = "hdmi_panel",
426 .owner = THIS_MODULE,
430 int hdmi_panel_init(void)
432 mutex_init(&hdmi.lock);
434 #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
435 spin_lock_init(&hdmi.audio_lock);
438 omap_dss_register_driver(&hdmi_driver);
443 void hdmi_panel_exit(void)
445 omap_dss_unregister_driver(&hdmi_driver);