aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/omap2/dss/hdmi_panel.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/omap2/dss/hdmi_panel.c')
-rw-r--r--drivers/video/omap2/dss/hdmi_panel.c236
1 files changed, 213 insertions, 23 deletions
diff --git a/drivers/video/omap2/dss/hdmi_panel.c b/drivers/video/omap2/dss/hdmi_panel.c
index 533d5dc634d2..1179e3c4b1c7 100644
--- a/drivers/video/omap2/dss/hdmi_panel.c
+++ b/drivers/video/omap2/dss/hdmi_panel.c
@@ -30,7 +30,12 @@
30#include "dss.h" 30#include "dss.h"
31 31
32static struct { 32static struct {
33 struct mutex hdmi_lock; 33 /* This protects the panel ops, mainly when accessing the HDMI IP. */
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
34} hdmi; 39} hdmi;
35 40
36 41
@@ -54,12 +59,168 @@ static void hdmi_panel_remove(struct omap_dss_device *dssdev)
54 59
55} 60}
56 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
57static int hdmi_panel_enable(struct omap_dss_device *dssdev) 218static int hdmi_panel_enable(struct omap_dss_device *dssdev)
58{ 219{
59 int r = 0; 220 int r = 0;
60 DSSDBG("ENTER hdmi_panel_enable\n"); 221 DSSDBG("ENTER hdmi_panel_enable\n");
61 222
62 mutex_lock(&hdmi.hdmi_lock); 223 mutex_lock(&hdmi.lock);
63 224
64 if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { 225 if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
65 r = -EINVAL; 226 r = -EINVAL;
@@ -75,40 +236,52 @@ static int hdmi_panel_enable(struct omap_dss_device *dssdev)
75 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; 236 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
76 237
77err: 238err:
78 mutex_unlock(&hdmi.hdmi_lock); 239 mutex_unlock(&hdmi.lock);
79 240
80 return r; 241 return r;
81} 242}
82 243
83static void hdmi_panel_disable(struct omap_dss_device *dssdev) 244static void hdmi_panel_disable(struct omap_dss_device *dssdev)
84{ 245{
85 mutex_lock(&hdmi.hdmi_lock); 246 mutex_lock(&hdmi.lock);
86 247
87 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);
88 omapdss_hdmi_display_disable(dssdev); 255 omapdss_hdmi_display_disable(dssdev);
256 }
89 257
90 dssdev->state = OMAP_DSS_DISPLAY_DISABLED; 258 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
91 259
92 mutex_unlock(&hdmi.hdmi_lock); 260 mutex_unlock(&hdmi.lock);
93} 261}
94 262
95static int hdmi_panel_suspend(struct omap_dss_device *dssdev) 263static int hdmi_panel_suspend(struct omap_dss_device *dssdev)
96{ 264{
97 int r = 0; 265 int r = 0;
98 266
99 mutex_lock(&hdmi.hdmi_lock); 267 mutex_lock(&hdmi.lock);
100 268
101 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { 269 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
102 r = -EINVAL; 270 r = -EINVAL;
103 goto err; 271 goto err;
104 } 272 }
105 273
106 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);
107 279
280 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
108 omapdss_hdmi_display_disable(dssdev); 281 omapdss_hdmi_display_disable(dssdev);
109 282
110err: 283err:
111 mutex_unlock(&hdmi.hdmi_lock); 284 mutex_unlock(&hdmi.lock);
112 285
113 return r; 286 return r;
114} 287}
@@ -117,7 +290,7 @@ static int hdmi_panel_resume(struct omap_dss_device *dssdev)
117{ 290{
118 int r = 0; 291 int r = 0;
119 292
120 mutex_lock(&hdmi.hdmi_lock); 293 mutex_lock(&hdmi.lock);
121 294
122 if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) { 295 if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
123 r = -EINVAL; 296 r = -EINVAL;
@@ -129,11 +302,12 @@ static int hdmi_panel_resume(struct omap_dss_device *dssdev)
129 DSSERR("failed to power on\n"); 302 DSSERR("failed to power on\n");
130 goto err; 303 goto err;
131 } 304 }
305 /* TODO: notify audio users that the panel resumed. */
132 306
133 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; 307 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
134 308
135err: 309err:
136 mutex_unlock(&hdmi.hdmi_lock); 310 mutex_unlock(&hdmi.lock);
137 311
138 return r; 312 return r;
139} 313}
@@ -141,11 +315,11 @@ err:
141static void hdmi_get_timings(struct omap_dss_device *dssdev, 315static void hdmi_get_timings(struct omap_dss_device *dssdev,
142 struct omap_video_timings *timings) 316 struct omap_video_timings *timings)
143{ 317{
144 mutex_lock(&hdmi.hdmi_lock); 318 mutex_lock(&hdmi.lock);
145 319
146 *timings = dssdev->panel.timings; 320 *timings = dssdev->panel.timings;
147 321
148 mutex_unlock(&hdmi.hdmi_lock); 322 mutex_unlock(&hdmi.lock);
149} 323}
150 324
151static void hdmi_set_timings(struct omap_dss_device *dssdev, 325static void hdmi_set_timings(struct omap_dss_device *dssdev,
@@ -153,12 +327,18 @@ static void hdmi_set_timings(struct omap_dss_device *dssdev,
153{ 327{
154 DSSDBG("hdmi_set_timings\n"); 328 DSSDBG("hdmi_set_timings\n");
155 329
156 mutex_lock(&hdmi.hdmi_lock); 330 mutex_lock(&hdmi.lock);
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);
157 337
158 dssdev->panel.timings = *timings; 338 dssdev->panel.timings = *timings;
159 omapdss_hdmi_display_set_timing(dssdev); 339 omapdss_hdmi_display_set_timing(dssdev);
160 340
161 mutex_unlock(&hdmi.hdmi_lock); 341 mutex_unlock(&hdmi.lock);
162} 342}
163 343
164static int hdmi_check_timings(struct omap_dss_device *dssdev, 344static int hdmi_check_timings(struct omap_dss_device *dssdev,
@@ -168,11 +348,11 @@ static int hdmi_check_timings(struct omap_dss_device *dssdev,
168 348
169 DSSDBG("hdmi_check_timings\n"); 349 DSSDBG("hdmi_check_timings\n");
170 350
171 mutex_lock(&hdmi.hdmi_lock); 351 mutex_lock(&hdmi.lock);
172 352
173 r = omapdss_hdmi_display_check_timing(dssdev, timings); 353 r = omapdss_hdmi_display_check_timing(dssdev, timings);
174 354
175 mutex_unlock(&hdmi.hdmi_lock); 355 mutex_unlock(&hdmi.lock);
176 return r; 356 return r;
177} 357}
178 358
@@ -180,7 +360,7 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len)
180{ 360{
181 int r; 361 int r;
182 362
183 mutex_lock(&hdmi.hdmi_lock); 363 mutex_lock(&hdmi.lock);
184 364
185 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { 365 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
186 r = omapdss_hdmi_display_enable(dssdev); 366 r = omapdss_hdmi_display_enable(dssdev);
@@ -194,7 +374,7 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len)
194 dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) 374 dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
195 omapdss_hdmi_display_disable(dssdev); 375 omapdss_hdmi_display_disable(dssdev);
196err: 376err:
197 mutex_unlock(&hdmi.hdmi_lock); 377 mutex_unlock(&hdmi.lock);
198 378
199 return r; 379 return r;
200} 380}
@@ -203,7 +383,7 @@ static bool hdmi_detect(struct omap_dss_device *dssdev)
203{ 383{
204 int r; 384 int r;
205 385
206 mutex_lock(&hdmi.hdmi_lock); 386 mutex_lock(&hdmi.lock);
207 387
208 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { 388 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
209 r = omapdss_hdmi_display_enable(dssdev); 389 r = omapdss_hdmi_display_enable(dssdev);
@@ -217,7 +397,7 @@ static bool hdmi_detect(struct omap_dss_device *dssdev)
217 dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) 397 dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
218 omapdss_hdmi_display_disable(dssdev); 398 omapdss_hdmi_display_disable(dssdev);
219err: 399err:
220 mutex_unlock(&hdmi.hdmi_lock); 400 mutex_unlock(&hdmi.lock);
221 401
222 return r; 402 return r;
223} 403}
@@ -234,6 +414,12 @@ static struct omap_dss_driver hdmi_driver = {
234 .check_timings = hdmi_check_timings, 414 .check_timings = hdmi_check_timings,
235 .read_edid = hdmi_read_edid, 415 .read_edid = hdmi_read_edid,
236 .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,
237 .driver = { 423 .driver = {
238 .name = "hdmi_panel", 424 .name = "hdmi_panel",
239 .owner = THIS_MODULE, 425 .owner = THIS_MODULE,
@@ -242,7 +428,11 @@ static struct omap_dss_driver hdmi_driver = {
242 428
243int hdmi_panel_init(void) 429int hdmi_panel_init(void)
244{ 430{
245 mutex_init(&hdmi.hdmi_lock); 431 mutex_init(&hdmi.lock);
432
433#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
434 spin_lock_init(&hdmi.audio_lock);
435#endif
246 436
247 omap_dss_register_driver(&hdmi_driver); 437 omap_dss_register_driver(&hdmi_driver);
248 438