aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/video/omap2/dss/dss.h8
-rw-r--r--drivers/video/omap2/dss/hdmi.c42
-rw-r--r--drivers/video/omap2/dss/hdmi_panel.c193
3 files changed, 241 insertions, 2 deletions
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index d5cb19fe7e8b..4aa9529a4768 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -464,6 +464,14 @@ int omapdss_hdmi_read_edid(u8 *buf, int len);
464bool omapdss_hdmi_detect(void); 464bool omapdss_hdmi_detect(void);
465int hdmi_panel_init(void); 465int hdmi_panel_init(void);
466void hdmi_panel_exit(void); 466void hdmi_panel_exit(void);
467#ifdef CONFIG_OMAP4_DSS_HDMI_AUDIO
468int hdmi_audio_enable(void);
469void hdmi_audio_disable(void);
470int hdmi_audio_start(void);
471void hdmi_audio_stop(void);
472bool hdmi_mode_has_audio(void);
473int hdmi_audio_config(struct omap_dss_audio *audio);
474#endif
467 475
468/* RFBI */ 476/* RFBI */
469int rfbi_init_platform_driver(void) __init; 477int rfbi_init_platform_driver(void) __init;
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index 09fdbf8714ea..8195c7166d20 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -654,6 +654,48 @@ int hdmi_compute_acr(u32 sample_freq, u32 *n, u32 *cts)
654 654
655 return 0; 655 return 0;
656} 656}
657
658int hdmi_audio_enable(void)
659{
660 DSSDBG("audio_enable\n");
661
662 return hdmi.ip_data.ops->audio_enable(&hdmi.ip_data);
663}
664
665void hdmi_audio_disable(void)
666{
667 DSSDBG("audio_disable\n");
668
669 hdmi.ip_data.ops->audio_disable(&hdmi.ip_data);
670}
671
672int hdmi_audio_start(void)
673{
674 DSSDBG("audio_start\n");
675
676 return hdmi.ip_data.ops->audio_start(&hdmi.ip_data);
677}
678
679void hdmi_audio_stop(void)
680{
681 DSSDBG("audio_stop\n");
682
683 hdmi.ip_data.ops->audio_stop(&hdmi.ip_data);
684}
685
686bool hdmi_mode_has_audio(void)
687{
688 if (hdmi.ip_data.cfg.cm.mode == HDMI_HDMI)
689 return true;
690 else
691 return false;
692}
693
694int hdmi_audio_config(struct omap_dss_audio *audio)
695{
696 return hdmi.ip_data.ops->audio_config(&hdmi.ip_data, audio);
697}
698
657#endif 699#endif
658 700
659static void __init hdmi_probe_pdata(struct platform_device *pdev) 701static void __init hdmi_probe_pdata(struct platform_device *pdev)
diff --git a/drivers/video/omap2/dss/hdmi_panel.c b/drivers/video/omap2/dss/hdmi_panel.c
index 5e215d6e8d0a..1179e3c4b1c7 100644
--- a/drivers/video/omap2/dss/hdmi_panel.c
+++ b/drivers/video/omap2/dss/hdmi_panel.c
@@ -32,6 +32,10 @@
32static struct { 32static struct {
33 /* This protects the panel ops, mainly when accessing the HDMI IP. */ 33 /* This protects the panel ops, mainly when accessing the HDMI IP. */
34 struct mutex lock; 34 struct mutex lock;
35#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
36 /* This protects the audio ops, specifically. */
37 spinlock_t audio_lock;
38#endif
35} hdmi; 39} hdmi;
36 40
37 41
@@ -55,6 +59,162 @@ static void hdmi_panel_remove(struct omap_dss_device *dssdev)
55 59
56} 60}
57 61
62#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
63static int hdmi_panel_audio_enable(struct omap_dss_device *dssdev)
64{
65 unsigned long flags;
66 int r;
67
68 mutex_lock(&hdmi.lock);
69 spin_lock_irqsave(&hdmi.audio_lock, flags);
70
71 /* enable audio only if the display is active and supports audio */
72 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE ||
73 !hdmi_mode_has_audio()) {
74 DSSERR("audio not supported or display is off\n");
75 r = -EPERM;
76 goto err;
77 }
78
79 r = hdmi_audio_enable();
80
81 if (!r)
82 dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED;
83
84err:
85 spin_unlock_irqrestore(&hdmi.audio_lock, flags);
86 mutex_unlock(&hdmi.lock);
87 return r;
88}
89
90static void hdmi_panel_audio_disable(struct omap_dss_device *dssdev)
91{
92 unsigned long flags;
93
94 spin_lock_irqsave(&hdmi.audio_lock, flags);
95
96 hdmi_audio_disable();
97
98 dssdev->audio_state = OMAP_DSS_AUDIO_DISABLED;
99
100 spin_unlock_irqrestore(&hdmi.audio_lock, flags);
101}
102
103static int hdmi_panel_audio_start(struct omap_dss_device *dssdev)
104{
105 unsigned long flags;
106 int r;
107
108 spin_lock_irqsave(&hdmi.audio_lock, flags);
109 /*
110 * No need to check the panel state. It was checked when trasitioning
111 * to AUDIO_ENABLED.
112 */
113 if (dssdev->audio_state != OMAP_DSS_AUDIO_ENABLED) {
114 DSSERR("audio start from invalid state\n");
115 r = -EPERM;
116 goto err;
117 }
118
119 r = hdmi_audio_start();
120
121 if (!r)
122 dssdev->audio_state = OMAP_DSS_AUDIO_PLAYING;
123
124err:
125 spin_unlock_irqrestore(&hdmi.audio_lock, flags);
126 return r;
127}
128
129static void hdmi_panel_audio_stop(struct omap_dss_device *dssdev)
130{
131 unsigned long flags;
132
133 spin_lock_irqsave(&hdmi.audio_lock, flags);
134
135 hdmi_audio_stop();
136 dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED;
137
138 spin_unlock_irqrestore(&hdmi.audio_lock, flags);
139}
140
141static bool hdmi_panel_audio_supported(struct omap_dss_device *dssdev)
142{
143 bool r = false;
144
145 mutex_lock(&hdmi.lock);
146
147 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
148 goto err;
149
150 if (!hdmi_mode_has_audio())
151 goto err;
152
153 r = true;
154err:
155 mutex_unlock(&hdmi.lock);
156 return r;
157}
158
159static int hdmi_panel_audio_config(struct omap_dss_device *dssdev,
160 struct omap_dss_audio *audio)
161{
162 unsigned long flags;
163 int r;
164
165 mutex_lock(&hdmi.lock);
166 spin_lock_irqsave(&hdmi.audio_lock, flags);
167
168 /* config audio only if the display is active and supports audio */
169 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE ||
170 !hdmi_mode_has_audio()) {
171 DSSERR("audio not supported or display is off\n");
172 r = -EPERM;
173 goto err;
174 }
175
176 r = hdmi_audio_config(audio);
177
178 if (!r)
179 dssdev->audio_state = OMAP_DSS_AUDIO_CONFIGURED;
180
181err:
182 spin_unlock_irqrestore(&hdmi.audio_lock, flags);
183 mutex_unlock(&hdmi.lock);
184 return r;
185}
186
187#else
188static int hdmi_panel_audio_enable(struct omap_dss_device *dssdev)
189{
190 return -EPERM;
191}
192
193static void hdmi_panel_audio_disable(struct omap_dss_device *dssdev)
194{
195}
196
197static int hdmi_panel_audio_start(struct omap_dss_device *dssdev)
198{
199 return -EPERM;
200}
201
202static void hdmi_panel_audio_stop(struct omap_dss_device *dssdev)
203{
204}
205
206static bool hdmi_panel_audio_supported(struct omap_dss_device *dssdev)
207{
208 return false;
209}
210
211static int hdmi_panel_audio_config(struct omap_dss_device *dssdev,
212 struct omap_dss_audio *audio)
213{
214 return -EPERM;
215}
216#endif
217
58static int hdmi_panel_enable(struct omap_dss_device *dssdev) 218static int hdmi_panel_enable(struct omap_dss_device *dssdev)
59{ 219{
60 int r = 0; 220 int r = 0;
@@ -85,8 +245,15 @@ static void hdmi_panel_disable(struct omap_dss_device *dssdev)
85{ 245{
86 mutex_lock(&hdmi.lock); 246 mutex_lock(&hdmi.lock);
87 247
88 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) 248 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
249 /*
250 * TODO: notify audio users that the display was disabled. For
251 * now, disable audio locally to not break our audio state
252 * machine.
253 */
254 hdmi_panel_audio_disable(dssdev);
89 omapdss_hdmi_display_disable(dssdev); 255 omapdss_hdmi_display_disable(dssdev);
256 }
90 257
91 dssdev->state = OMAP_DSS_DISPLAY_DISABLED; 258 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
92 259
@@ -104,8 +271,13 @@ static int hdmi_panel_suspend(struct omap_dss_device *dssdev)
104 goto err; 271 goto err;
105 } 272 }
106 273
107 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; 274 /*
275 * TODO: notify audio users that the display was suspended. For now,
276 * disable audio locally to not break our audio state machine.
277 */
278 hdmi_panel_audio_disable(dssdev);
108 279
280 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
109 omapdss_hdmi_display_disable(dssdev); 281 omapdss_hdmi_display_disable(dssdev);
110 282
111err: 283err:
@@ -130,6 +302,7 @@ static int hdmi_panel_resume(struct omap_dss_device *dssdev)
130 DSSERR("failed to power on\n"); 302 DSSERR("failed to power on\n");
131 goto err; 303 goto err;
132 } 304 }
305 /* TODO: notify audio users that the panel resumed. */
133 306
134 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; 307 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
135 308
@@ -156,6 +329,12 @@ static void hdmi_set_timings(struct omap_dss_device *dssdev,
156 329
157 mutex_lock(&hdmi.lock); 330 mutex_lock(&hdmi.lock);
158 331
332 /*
333 * TODO: notify audio users that there was a timings change. For
334 * now, disable audio locally to not break our audio state machine.
335 */
336 hdmi_panel_audio_disable(dssdev);
337
159 dssdev->panel.timings = *timings; 338 dssdev->panel.timings = *timings;
160 omapdss_hdmi_display_set_timing(dssdev); 339 omapdss_hdmi_display_set_timing(dssdev);
161 340
@@ -235,6 +414,12 @@ static struct omap_dss_driver hdmi_driver = {
235 .check_timings = hdmi_check_timings, 414 .check_timings = hdmi_check_timings,
236 .read_edid = hdmi_read_edid, 415 .read_edid = hdmi_read_edid,
237 .detect = hdmi_detect, 416 .detect = hdmi_detect,
417 .audio_enable = hdmi_panel_audio_enable,
418 .audio_disable = hdmi_panel_audio_disable,
419 .audio_start = hdmi_panel_audio_start,
420 .audio_stop = hdmi_panel_audio_stop,
421 .audio_supported = hdmi_panel_audio_supported,
422 .audio_config = hdmi_panel_audio_config,
238 .driver = { 423 .driver = {
239 .name = "hdmi_panel", 424 .name = "hdmi_panel",
240 .owner = THIS_MODULE, 425 .owner = THIS_MODULE,
@@ -245,6 +430,10 @@ int hdmi_panel_init(void)
245{ 430{
246 mutex_init(&hdmi.lock); 431 mutex_init(&hdmi.lock);
247 432
433#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
434 spin_lock_init(&hdmi.audio_lock);
435#endif
436
248 omap_dss_register_driver(&hdmi_driver); 437 omap_dss_register_driver(&hdmi_driver);
249 438
250 return 0; 439 return 0;