diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-11 00:55:17 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-11 00:55:17 -0500 |
commit | aa2cf420593b67cc93de7a3f675b2a88eba0505f (patch) | |
tree | dfb3c73a8a3987c3b3ba08083f379ebc90942e03 /drivers/video/omap2/dss/display.c | |
parent | d71cb81af3817193bc605de061da0499934263a6 (diff) | |
parent | 178ff4c9175db447f93b7343954b1d44707c881b (diff) |
Merge branch 'for-linus' of git://gitorious.org/linux-omap-dss2/linux
* 'for-linus' of git://gitorious.org/linux-omap-dss2/linux:
MAINTAINERS: Add OMAP2/3 DSS and OMAPFB maintainer
OMAP: SDP: Enable DSS2 for OMAP3 SDP board
OMAP: DSS2: Taal DSI command mode panel driver
OMAP: DSS2: Add generic and Sharp panel drivers
OMAP: DSS2: omapfb driver
OMAP: DSS2: DSI driver
OMAP: DSS2: SDI driver
OMAP: DSS2: RFBI driver
OMAP: DSS2: Video encoder driver
OMAP: DSS2: DPI driver
OMAP: DSS2: DISPC
OMAP: DSS2: Add more core files
OMAP: DSS2: Display Subsystem Driver core
OMAP: DSS2: Documentation for DSS2
OMAP: Add support for VRFB rotation engine
OMAP: Add VRAM manager
OMAP: OMAPFB: add omapdss device
OMAP: OMAPFB: split omapfb.h
OMAP2: Add funcs for writing SMS_ROT_* registers
Diffstat (limited to 'drivers/video/omap2/dss/display.c')
-rw-r--r-- | drivers/video/omap2/dss/display.c | 671 |
1 files changed, 671 insertions, 0 deletions
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c new file mode 100644 index 000000000000..3b92b84b9560 --- /dev/null +++ b/drivers/video/omap2/dss/display.c | |||
@@ -0,0 +1,671 @@ | |||
1 | /* | ||
2 | * linux/drivers/video/omap2/dss/display.c | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> | ||
6 | * | ||
7 | * Some code and ideas taken from drivers/video/omap/ driver | ||
8 | * by Imre Deak. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License version 2 as published by | ||
12 | * the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
17 | * more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along with | ||
20 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
21 | */ | ||
22 | |||
23 | #define DSS_SUBSYS_NAME "DISPLAY" | ||
24 | |||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/jiffies.h> | ||
28 | #include <linux/list.h> | ||
29 | #include <linux/platform_device.h> | ||
30 | |||
31 | #include <plat/display.h> | ||
32 | #include "dss.h" | ||
33 | |||
34 | static LIST_HEAD(display_list); | ||
35 | |||
36 | static ssize_t display_enabled_show(struct device *dev, | ||
37 | struct device_attribute *attr, char *buf) | ||
38 | { | ||
39 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
40 | bool enabled = dssdev->state != OMAP_DSS_DISPLAY_DISABLED; | ||
41 | |||
42 | return snprintf(buf, PAGE_SIZE, "%d\n", enabled); | ||
43 | } | ||
44 | |||
45 | static ssize_t display_enabled_store(struct device *dev, | ||
46 | struct device_attribute *attr, | ||
47 | const char *buf, size_t size) | ||
48 | { | ||
49 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
50 | bool enabled, r; | ||
51 | |||
52 | enabled = simple_strtoul(buf, NULL, 10); | ||
53 | |||
54 | if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) { | ||
55 | if (enabled) { | ||
56 | r = dssdev->enable(dssdev); | ||
57 | if (r) | ||
58 | return r; | ||
59 | } else { | ||
60 | dssdev->disable(dssdev); | ||
61 | } | ||
62 | } | ||
63 | |||
64 | return size; | ||
65 | } | ||
66 | |||
67 | static ssize_t display_upd_mode_show(struct device *dev, | ||
68 | struct device_attribute *attr, char *buf) | ||
69 | { | ||
70 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
71 | enum omap_dss_update_mode mode = OMAP_DSS_UPDATE_AUTO; | ||
72 | if (dssdev->get_update_mode) | ||
73 | mode = dssdev->get_update_mode(dssdev); | ||
74 | return snprintf(buf, PAGE_SIZE, "%d\n", mode); | ||
75 | } | ||
76 | |||
77 | static ssize_t display_upd_mode_store(struct device *dev, | ||
78 | struct device_attribute *attr, | ||
79 | const char *buf, size_t size) | ||
80 | { | ||
81 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
82 | int val, r; | ||
83 | enum omap_dss_update_mode mode; | ||
84 | |||
85 | val = simple_strtoul(buf, NULL, 10); | ||
86 | |||
87 | switch (val) { | ||
88 | case OMAP_DSS_UPDATE_DISABLED: | ||
89 | case OMAP_DSS_UPDATE_AUTO: | ||
90 | case OMAP_DSS_UPDATE_MANUAL: | ||
91 | mode = (enum omap_dss_update_mode)val; | ||
92 | break; | ||
93 | default: | ||
94 | return -EINVAL; | ||
95 | } | ||
96 | |||
97 | r = dssdev->set_update_mode(dssdev, mode); | ||
98 | if (r) | ||
99 | return r; | ||
100 | |||
101 | return size; | ||
102 | } | ||
103 | |||
104 | static ssize_t display_tear_show(struct device *dev, | ||
105 | struct device_attribute *attr, char *buf) | ||
106 | { | ||
107 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
108 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
109 | dssdev->get_te ? dssdev->get_te(dssdev) : 0); | ||
110 | } | ||
111 | |||
112 | static ssize_t display_tear_store(struct device *dev, | ||
113 | struct device_attribute *attr, const char *buf, size_t size) | ||
114 | { | ||
115 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
116 | unsigned long te; | ||
117 | int r; | ||
118 | |||
119 | if (!dssdev->enable_te || !dssdev->get_te) | ||
120 | return -ENOENT; | ||
121 | |||
122 | te = simple_strtoul(buf, NULL, 0); | ||
123 | |||
124 | r = dssdev->enable_te(dssdev, te); | ||
125 | if (r) | ||
126 | return r; | ||
127 | |||
128 | return size; | ||
129 | } | ||
130 | |||
131 | static ssize_t display_timings_show(struct device *dev, | ||
132 | struct device_attribute *attr, char *buf) | ||
133 | { | ||
134 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
135 | struct omap_video_timings t; | ||
136 | |||
137 | if (!dssdev->get_timings) | ||
138 | return -ENOENT; | ||
139 | |||
140 | dssdev->get_timings(dssdev, &t); | ||
141 | |||
142 | return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n", | ||
143 | t.pixel_clock, | ||
144 | t.x_res, t.hfp, t.hbp, t.hsw, | ||
145 | t.y_res, t.vfp, t.vbp, t.vsw); | ||
146 | } | ||
147 | |||
148 | static ssize_t display_timings_store(struct device *dev, | ||
149 | struct device_attribute *attr, const char *buf, size_t size) | ||
150 | { | ||
151 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
152 | struct omap_video_timings t; | ||
153 | int r, found; | ||
154 | |||
155 | if (!dssdev->set_timings || !dssdev->check_timings) | ||
156 | return -ENOENT; | ||
157 | |||
158 | found = 0; | ||
159 | #ifdef CONFIG_OMAP2_DSS_VENC | ||
160 | if (strncmp("pal", buf, 3) == 0) { | ||
161 | t = omap_dss_pal_timings; | ||
162 | found = 1; | ||
163 | } else if (strncmp("ntsc", buf, 4) == 0) { | ||
164 | t = omap_dss_ntsc_timings; | ||
165 | found = 1; | ||
166 | } | ||
167 | #endif | ||
168 | if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu", | ||
169 | &t.pixel_clock, | ||
170 | &t.x_res, &t.hfp, &t.hbp, &t.hsw, | ||
171 | &t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9) | ||
172 | return -EINVAL; | ||
173 | |||
174 | r = dssdev->check_timings(dssdev, &t); | ||
175 | if (r) | ||
176 | return r; | ||
177 | |||
178 | dssdev->set_timings(dssdev, &t); | ||
179 | |||
180 | return size; | ||
181 | } | ||
182 | |||
183 | static ssize_t display_rotate_show(struct device *dev, | ||
184 | struct device_attribute *attr, char *buf) | ||
185 | { | ||
186 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
187 | int rotate; | ||
188 | if (!dssdev->get_rotate) | ||
189 | return -ENOENT; | ||
190 | rotate = dssdev->get_rotate(dssdev); | ||
191 | return snprintf(buf, PAGE_SIZE, "%u\n", rotate); | ||
192 | } | ||
193 | |||
194 | static ssize_t display_rotate_store(struct device *dev, | ||
195 | struct device_attribute *attr, const char *buf, size_t size) | ||
196 | { | ||
197 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
198 | unsigned long rot; | ||
199 | int r; | ||
200 | |||
201 | if (!dssdev->set_rotate || !dssdev->get_rotate) | ||
202 | return -ENOENT; | ||
203 | |||
204 | rot = simple_strtoul(buf, NULL, 0); | ||
205 | |||
206 | r = dssdev->set_rotate(dssdev, rot); | ||
207 | if (r) | ||
208 | return r; | ||
209 | |||
210 | return size; | ||
211 | } | ||
212 | |||
213 | static ssize_t display_mirror_show(struct device *dev, | ||
214 | struct device_attribute *attr, char *buf) | ||
215 | { | ||
216 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
217 | int mirror; | ||
218 | if (!dssdev->get_mirror) | ||
219 | return -ENOENT; | ||
220 | mirror = dssdev->get_mirror(dssdev); | ||
221 | return snprintf(buf, PAGE_SIZE, "%u\n", mirror); | ||
222 | } | ||
223 | |||
224 | static ssize_t display_mirror_store(struct device *dev, | ||
225 | struct device_attribute *attr, const char *buf, size_t size) | ||
226 | { | ||
227 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
228 | unsigned long mirror; | ||
229 | int r; | ||
230 | |||
231 | if (!dssdev->set_mirror || !dssdev->get_mirror) | ||
232 | return -ENOENT; | ||
233 | |||
234 | mirror = simple_strtoul(buf, NULL, 0); | ||
235 | |||
236 | r = dssdev->set_mirror(dssdev, mirror); | ||
237 | if (r) | ||
238 | return r; | ||
239 | |||
240 | return size; | ||
241 | } | ||
242 | |||
243 | static ssize_t display_wss_show(struct device *dev, | ||
244 | struct device_attribute *attr, char *buf) | ||
245 | { | ||
246 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
247 | unsigned int wss; | ||
248 | |||
249 | if (!dssdev->get_wss) | ||
250 | return -ENOENT; | ||
251 | |||
252 | wss = dssdev->get_wss(dssdev); | ||
253 | |||
254 | return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss); | ||
255 | } | ||
256 | |||
257 | static ssize_t display_wss_store(struct device *dev, | ||
258 | struct device_attribute *attr, const char *buf, size_t size) | ||
259 | { | ||
260 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
261 | unsigned long wss; | ||
262 | int r; | ||
263 | |||
264 | if (!dssdev->get_wss || !dssdev->set_wss) | ||
265 | return -ENOENT; | ||
266 | |||
267 | if (strict_strtoul(buf, 0, &wss)) | ||
268 | return -EINVAL; | ||
269 | |||
270 | if (wss > 0xfffff) | ||
271 | return -EINVAL; | ||
272 | |||
273 | r = dssdev->set_wss(dssdev, wss); | ||
274 | if (r) | ||
275 | return r; | ||
276 | |||
277 | return size; | ||
278 | } | ||
279 | |||
280 | static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR, | ||
281 | display_enabled_show, display_enabled_store); | ||
282 | static DEVICE_ATTR(update_mode, S_IRUGO|S_IWUSR, | ||
283 | display_upd_mode_show, display_upd_mode_store); | ||
284 | static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR, | ||
285 | display_tear_show, display_tear_store); | ||
286 | static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR, | ||
287 | display_timings_show, display_timings_store); | ||
288 | static DEVICE_ATTR(rotate, S_IRUGO|S_IWUSR, | ||
289 | display_rotate_show, display_rotate_store); | ||
290 | static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR, | ||
291 | display_mirror_show, display_mirror_store); | ||
292 | static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR, | ||
293 | display_wss_show, display_wss_store); | ||
294 | |||
295 | static struct device_attribute *display_sysfs_attrs[] = { | ||
296 | &dev_attr_enabled, | ||
297 | &dev_attr_update_mode, | ||
298 | &dev_attr_tear_elim, | ||
299 | &dev_attr_timings, | ||
300 | &dev_attr_rotate, | ||
301 | &dev_attr_mirror, | ||
302 | &dev_attr_wss, | ||
303 | NULL | ||
304 | }; | ||
305 | |||
306 | static void default_get_resolution(struct omap_dss_device *dssdev, | ||
307 | u16 *xres, u16 *yres) | ||
308 | { | ||
309 | *xres = dssdev->panel.timings.x_res; | ||
310 | *yres = dssdev->panel.timings.y_res; | ||
311 | } | ||
312 | |||
313 | void default_get_overlay_fifo_thresholds(enum omap_plane plane, | ||
314 | u32 fifo_size, enum omap_burst_size *burst_size, | ||
315 | u32 *fifo_low, u32 *fifo_high) | ||
316 | { | ||
317 | unsigned burst_size_bytes; | ||
318 | |||
319 | *burst_size = OMAP_DSS_BURST_16x32; | ||
320 | burst_size_bytes = 16 * 32 / 8; | ||
321 | |||
322 | *fifo_high = fifo_size - 1; | ||
323 | *fifo_low = fifo_size - burst_size_bytes; | ||
324 | } | ||
325 | |||
326 | static int default_wait_vsync(struct omap_dss_device *dssdev) | ||
327 | { | ||
328 | unsigned long timeout = msecs_to_jiffies(500); | ||
329 | u32 irq; | ||
330 | |||
331 | if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) | ||
332 | irq = DISPC_IRQ_EVSYNC_ODD; | ||
333 | else | ||
334 | irq = DISPC_IRQ_VSYNC; | ||
335 | |||
336 | return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | ||
337 | } | ||
338 | |||
339 | static int default_get_recommended_bpp(struct omap_dss_device *dssdev) | ||
340 | { | ||
341 | if (dssdev->panel.recommended_bpp) | ||
342 | return dssdev->panel.recommended_bpp; | ||
343 | |||
344 | switch (dssdev->type) { | ||
345 | case OMAP_DISPLAY_TYPE_DPI: | ||
346 | if (dssdev->phy.dpi.data_lines == 24) | ||
347 | return 24; | ||
348 | else | ||
349 | return 16; | ||
350 | |||
351 | case OMAP_DISPLAY_TYPE_DBI: | ||
352 | case OMAP_DISPLAY_TYPE_DSI: | ||
353 | if (dssdev->ctrl.pixel_size == 24) | ||
354 | return 24; | ||
355 | else | ||
356 | return 16; | ||
357 | case OMAP_DISPLAY_TYPE_VENC: | ||
358 | case OMAP_DISPLAY_TYPE_SDI: | ||
359 | return 24; | ||
360 | return 24; | ||
361 | default: | ||
362 | BUG(); | ||
363 | } | ||
364 | } | ||
365 | |||
366 | /* Checks if replication logic should be used. Only use for active matrix, | ||
367 | * when overlay is in RGB12U or RGB16 mode, and LCD interface is | ||
368 | * 18bpp or 24bpp */ | ||
369 | bool dss_use_replication(struct omap_dss_device *dssdev, | ||
370 | enum omap_color_mode mode) | ||
371 | { | ||
372 | int bpp; | ||
373 | |||
374 | if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16) | ||
375 | return false; | ||
376 | |||
377 | if (dssdev->type == OMAP_DISPLAY_TYPE_DPI && | ||
378 | (dssdev->panel.config & OMAP_DSS_LCD_TFT) == 0) | ||
379 | return false; | ||
380 | |||
381 | switch (dssdev->type) { | ||
382 | case OMAP_DISPLAY_TYPE_DPI: | ||
383 | bpp = dssdev->phy.dpi.data_lines; | ||
384 | break; | ||
385 | case OMAP_DISPLAY_TYPE_VENC: | ||
386 | case OMAP_DISPLAY_TYPE_SDI: | ||
387 | bpp = 24; | ||
388 | break; | ||
389 | case OMAP_DISPLAY_TYPE_DBI: | ||
390 | case OMAP_DISPLAY_TYPE_DSI: | ||
391 | bpp = dssdev->ctrl.pixel_size; | ||
392 | break; | ||
393 | default: | ||
394 | BUG(); | ||
395 | } | ||
396 | |||
397 | return bpp > 16; | ||
398 | } | ||
399 | |||
400 | void dss_init_device(struct platform_device *pdev, | ||
401 | struct omap_dss_device *dssdev) | ||
402 | { | ||
403 | struct device_attribute *attr; | ||
404 | int i; | ||
405 | int r; | ||
406 | |||
407 | switch (dssdev->type) { | ||
408 | case OMAP_DISPLAY_TYPE_DPI: | ||
409 | #ifdef CONFIG_OMAP2_DSS_RFBI | ||
410 | case OMAP_DISPLAY_TYPE_DBI: | ||
411 | #endif | ||
412 | #ifdef CONFIG_OMAP2_DSS_SDI | ||
413 | case OMAP_DISPLAY_TYPE_SDI: | ||
414 | #endif | ||
415 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
416 | case OMAP_DISPLAY_TYPE_DSI: | ||
417 | #endif | ||
418 | #ifdef CONFIG_OMAP2_DSS_VENC | ||
419 | case OMAP_DISPLAY_TYPE_VENC: | ||
420 | #endif | ||
421 | break; | ||
422 | default: | ||
423 | DSSERR("Support for display '%s' not compiled in.\n", | ||
424 | dssdev->name); | ||
425 | return; | ||
426 | } | ||
427 | |||
428 | dssdev->get_resolution = default_get_resolution; | ||
429 | dssdev->get_recommended_bpp = default_get_recommended_bpp; | ||
430 | dssdev->wait_vsync = default_wait_vsync; | ||
431 | |||
432 | switch (dssdev->type) { | ||
433 | case OMAP_DISPLAY_TYPE_DPI: | ||
434 | r = dpi_init_display(dssdev); | ||
435 | break; | ||
436 | #ifdef CONFIG_OMAP2_DSS_RFBI | ||
437 | case OMAP_DISPLAY_TYPE_DBI: | ||
438 | r = rfbi_init_display(dssdev); | ||
439 | break; | ||
440 | #endif | ||
441 | #ifdef CONFIG_OMAP2_DSS_VENC | ||
442 | case OMAP_DISPLAY_TYPE_VENC: | ||
443 | r = venc_init_display(dssdev); | ||
444 | break; | ||
445 | #endif | ||
446 | #ifdef CONFIG_OMAP2_DSS_SDI | ||
447 | case OMAP_DISPLAY_TYPE_SDI: | ||
448 | r = sdi_init_display(dssdev); | ||
449 | break; | ||
450 | #endif | ||
451 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
452 | case OMAP_DISPLAY_TYPE_DSI: | ||
453 | r = dsi_init_display(dssdev); | ||
454 | break; | ||
455 | #endif | ||
456 | default: | ||
457 | BUG(); | ||
458 | } | ||
459 | |||
460 | if (r) { | ||
461 | DSSERR("failed to init display %s\n", dssdev->name); | ||
462 | return; | ||
463 | } | ||
464 | |||
465 | /* create device sysfs files */ | ||
466 | i = 0; | ||
467 | while ((attr = display_sysfs_attrs[i++]) != NULL) { | ||
468 | r = device_create_file(&dssdev->dev, attr); | ||
469 | if (r) | ||
470 | DSSERR("failed to create sysfs file\n"); | ||
471 | } | ||
472 | |||
473 | /* create display? sysfs links */ | ||
474 | r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj, | ||
475 | dev_name(&dssdev->dev)); | ||
476 | if (r) | ||
477 | DSSERR("failed to create sysfs display link\n"); | ||
478 | } | ||
479 | |||
480 | void dss_uninit_device(struct platform_device *pdev, | ||
481 | struct omap_dss_device *dssdev) | ||
482 | { | ||
483 | struct device_attribute *attr; | ||
484 | int i = 0; | ||
485 | |||
486 | sysfs_remove_link(&pdev->dev.kobj, dev_name(&dssdev->dev)); | ||
487 | |||
488 | while ((attr = display_sysfs_attrs[i++]) != NULL) | ||
489 | device_remove_file(&dssdev->dev, attr); | ||
490 | |||
491 | if (dssdev->manager) | ||
492 | dssdev->manager->unset_device(dssdev->manager); | ||
493 | } | ||
494 | |||
495 | static int dss_suspend_device(struct device *dev, void *data) | ||
496 | { | ||
497 | int r; | ||
498 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
499 | |||
500 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { | ||
501 | dssdev->activate_after_resume = false; | ||
502 | return 0; | ||
503 | } | ||
504 | |||
505 | if (!dssdev->suspend) { | ||
506 | DSSERR("display '%s' doesn't implement suspend\n", | ||
507 | dssdev->name); | ||
508 | return -ENOSYS; | ||
509 | } | ||
510 | |||
511 | r = dssdev->suspend(dssdev); | ||
512 | if (r) | ||
513 | return r; | ||
514 | |||
515 | dssdev->activate_after_resume = true; | ||
516 | |||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | int dss_suspend_all_devices(void) | ||
521 | { | ||
522 | int r; | ||
523 | struct bus_type *bus = dss_get_bus(); | ||
524 | |||
525 | r = bus_for_each_dev(bus, NULL, NULL, dss_suspend_device); | ||
526 | if (r) { | ||
527 | /* resume all displays that were suspended */ | ||
528 | dss_resume_all_devices(); | ||
529 | return r; | ||
530 | } | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | static int dss_resume_device(struct device *dev, void *data) | ||
536 | { | ||
537 | int r; | ||
538 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
539 | |||
540 | if (dssdev->activate_after_resume && dssdev->resume) { | ||
541 | r = dssdev->resume(dssdev); | ||
542 | if (r) | ||
543 | return r; | ||
544 | } | ||
545 | |||
546 | dssdev->activate_after_resume = false; | ||
547 | |||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | int dss_resume_all_devices(void) | ||
552 | { | ||
553 | struct bus_type *bus = dss_get_bus(); | ||
554 | |||
555 | return bus_for_each_dev(bus, NULL, NULL, dss_resume_device); | ||
556 | } | ||
557 | |||
558 | static int dss_disable_device(struct device *dev, void *data) | ||
559 | { | ||
560 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
561 | dssdev->disable(dssdev); | ||
562 | return 0; | ||
563 | } | ||
564 | |||
565 | void dss_disable_all_devices(void) | ||
566 | { | ||
567 | struct bus_type *bus = dss_get_bus(); | ||
568 | bus_for_each_dev(bus, NULL, NULL, dss_disable_device); | ||
569 | } | ||
570 | |||
571 | |||
572 | void omap_dss_get_device(struct omap_dss_device *dssdev) | ||
573 | { | ||
574 | get_device(&dssdev->dev); | ||
575 | } | ||
576 | EXPORT_SYMBOL(omap_dss_get_device); | ||
577 | |||
578 | void omap_dss_put_device(struct omap_dss_device *dssdev) | ||
579 | { | ||
580 | put_device(&dssdev->dev); | ||
581 | } | ||
582 | EXPORT_SYMBOL(omap_dss_put_device); | ||
583 | |||
584 | /* ref count of the found device is incremented. ref count | ||
585 | * of from-device is decremented. */ | ||
586 | struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from) | ||
587 | { | ||
588 | struct device *dev; | ||
589 | struct device *dev_start = NULL; | ||
590 | struct omap_dss_device *dssdev = NULL; | ||
591 | |||
592 | int match(struct device *dev, void *data) | ||
593 | { | ||
594 | /* skip panels connected to controllers */ | ||
595 | if (to_dss_device(dev)->panel.ctrl) | ||
596 | return 0; | ||
597 | |||
598 | return 1; | ||
599 | } | ||
600 | |||
601 | if (from) | ||
602 | dev_start = &from->dev; | ||
603 | dev = bus_find_device(dss_get_bus(), dev_start, NULL, match); | ||
604 | if (dev) | ||
605 | dssdev = to_dss_device(dev); | ||
606 | if (from) | ||
607 | put_device(&from->dev); | ||
608 | |||
609 | return dssdev; | ||
610 | } | ||
611 | EXPORT_SYMBOL(omap_dss_get_next_device); | ||
612 | |||
613 | struct omap_dss_device *omap_dss_find_device(void *data, | ||
614 | int (*match)(struct omap_dss_device *dssdev, void *data)) | ||
615 | { | ||
616 | struct omap_dss_device *dssdev = NULL; | ||
617 | |||
618 | while ((dssdev = omap_dss_get_next_device(dssdev)) != NULL) { | ||
619 | if (match(dssdev, data)) | ||
620 | return dssdev; | ||
621 | } | ||
622 | |||
623 | return NULL; | ||
624 | } | ||
625 | EXPORT_SYMBOL(omap_dss_find_device); | ||
626 | |||
627 | int omap_dss_start_device(struct omap_dss_device *dssdev) | ||
628 | { | ||
629 | int r; | ||
630 | |||
631 | if (!dssdev->driver) { | ||
632 | DSSDBG("no driver\n"); | ||
633 | r = -ENODEV; | ||
634 | goto err0; | ||
635 | } | ||
636 | |||
637 | if (dssdev->ctrl.panel && !dssdev->ctrl.panel->driver) { | ||
638 | DSSDBG("no panel driver\n"); | ||
639 | r = -ENODEV; | ||
640 | goto err0; | ||
641 | } | ||
642 | |||
643 | if (!try_module_get(dssdev->dev.driver->owner)) { | ||
644 | r = -ENODEV; | ||
645 | goto err0; | ||
646 | } | ||
647 | |||
648 | if (dssdev->ctrl.panel) { | ||
649 | if (!try_module_get(dssdev->ctrl.panel->dev.driver->owner)) { | ||
650 | r = -ENODEV; | ||
651 | goto err1; | ||
652 | } | ||
653 | } | ||
654 | |||
655 | return 0; | ||
656 | err1: | ||
657 | module_put(dssdev->dev.driver->owner); | ||
658 | err0: | ||
659 | return r; | ||
660 | } | ||
661 | EXPORT_SYMBOL(omap_dss_start_device); | ||
662 | |||
663 | void omap_dss_stop_device(struct omap_dss_device *dssdev) | ||
664 | { | ||
665 | if (dssdev->ctrl.panel) | ||
666 | module_put(dssdev->ctrl.panel->dev.driver->owner); | ||
667 | |||
668 | module_put(dssdev->dev.driver->owner); | ||
669 | } | ||
670 | EXPORT_SYMBOL(omap_dss_stop_device); | ||
671 | |||