]> Pileus Git - ~andy/linux/blob - drivers/video/omap2/dss/core.c
OMAP: DSS2: Display Subsystem Driver core
[~andy/linux] / drivers / video / omap2 / dss / core.c
1 /*
2  * linux/drivers/video/omap2/dss/core.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 "CORE"
24
25 #include <linux/kernel.h>
26 #include <linux/module.h>
27 #include <linux/clk.h>
28 #include <linux/err.h>
29 #include <linux/platform_device.h>
30 #include <linux/seq_file.h>
31 #include <linux/debugfs.h>
32 #include <linux/io.h>
33 #include <linux/device.h>
34
35 #include <plat/display.h>
36 #include <plat/clock.h>
37
38 #include "dss.h"
39
40 static struct {
41         struct platform_device *pdev;
42         int             ctx_id;
43
44         struct clk      *dss_ick;
45         struct clk      *dss1_fck;
46         struct clk      *dss2_fck;
47         struct clk      *dss_54m_fck;
48         struct clk      *dss_96m_fck;
49         unsigned        num_clks_enabled;
50 } core;
51
52 static void dss_clk_enable_all_no_ctx(void);
53 static void dss_clk_disable_all_no_ctx(void);
54 static void dss_clk_enable_no_ctx(enum dss_clock clks);
55 static void dss_clk_disable_no_ctx(enum dss_clock clks);
56
57 static char *def_disp_name;
58 module_param_named(def_disp, def_disp_name, charp, 0);
59 MODULE_PARM_DESC(def_disp_name, "default display name");
60
61 #ifdef DEBUG
62 unsigned int dss_debug;
63 module_param_named(debug, dss_debug, bool, 0644);
64 #endif
65
66 /* CONTEXT */
67 static int dss_get_ctx_id(void)
68 {
69         struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
70         int r;
71
72         if (!pdata->get_last_off_on_transaction_id)
73                 return 0;
74         r = pdata->get_last_off_on_transaction_id(&core.pdev->dev);
75         if (r < 0) {
76                 dev_err(&core.pdev->dev, "getting transaction ID failed, "
77                                 "will force context restore\n");
78                 r = -1;
79         }
80         return r;
81 }
82
83 int dss_need_ctx_restore(void)
84 {
85         int id = dss_get_ctx_id();
86
87         if (id < 0 || id != core.ctx_id) {
88                 DSSDBG("ctx id %d -> id %d\n",
89                                 core.ctx_id, id);
90                 core.ctx_id = id;
91                 return 1;
92         } else {
93                 return 0;
94         }
95 }
96
97 static void save_all_ctx(void)
98 {
99         DSSDBG("save context\n");
100
101         dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
102
103         dss_save_context();
104         dispc_save_context();
105 #ifdef CONFIG_OMAP2_DSS_DSI
106         dsi_save_context();
107 #endif
108
109         dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
110 }
111
112 static void restore_all_ctx(void)
113 {
114         DSSDBG("restore context\n");
115
116         dss_clk_enable_all_no_ctx();
117
118         dss_restore_context();
119         dispc_restore_context();
120 #ifdef CONFIG_OMAP2_DSS_DSI
121         dsi_restore_context();
122 #endif
123
124         dss_clk_disable_all_no_ctx();
125 }
126
127 /* CLOCKS */
128 static void core_dump_clocks(struct seq_file *s)
129 {
130         int i;
131         struct clk *clocks[5] = {
132                 core.dss_ick,
133                 core.dss1_fck,
134                 core.dss2_fck,
135                 core.dss_54m_fck,
136                 core.dss_96m_fck
137         };
138
139         seq_printf(s, "- CORE -\n");
140
141         seq_printf(s, "internal clk count\t\t%u\n", core.num_clks_enabled);
142
143         for (i = 0; i < 5; i++) {
144                 if (!clocks[i])
145                         continue;
146                 seq_printf(s, "%-15s\t%lu\t%d\n",
147                                 clocks[i]->name,
148                                 clk_get_rate(clocks[i]),
149                                 clocks[i]->usecount);
150         }
151 }
152
153 static int dss_get_clock(struct clk **clock, const char *clk_name)
154 {
155         struct clk *clk;
156
157         clk = clk_get(&core.pdev->dev, clk_name);
158
159         if (IS_ERR(clk)) {
160                 DSSERR("can't get clock %s", clk_name);
161                 return PTR_ERR(clk);
162         }
163
164         *clock = clk;
165
166         DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk));
167
168         return 0;
169 }
170
171 static int dss_get_clocks(void)
172 {
173         int r;
174
175         core.dss_ick = NULL;
176         core.dss1_fck = NULL;
177         core.dss2_fck = NULL;
178         core.dss_54m_fck = NULL;
179         core.dss_96m_fck = NULL;
180
181         r = dss_get_clock(&core.dss_ick, "ick");
182         if (r)
183                 goto err;
184
185         r = dss_get_clock(&core.dss1_fck, "dss1_fck");
186         if (r)
187                 goto err;
188
189         r = dss_get_clock(&core.dss2_fck, "dss2_fck");
190         if (r)
191                 goto err;
192
193         r = dss_get_clock(&core.dss_54m_fck, "tv_fck");
194         if (r)
195                 goto err;
196
197         r = dss_get_clock(&core.dss_96m_fck, "video_fck");
198         if (r)
199                 goto err;
200
201         return 0;
202
203 err:
204         if (core.dss_ick)
205                 clk_put(core.dss_ick);
206         if (core.dss1_fck)
207                 clk_put(core.dss1_fck);
208         if (core.dss2_fck)
209                 clk_put(core.dss2_fck);
210         if (core.dss_54m_fck)
211                 clk_put(core.dss_54m_fck);
212         if (core.dss_96m_fck)
213                 clk_put(core.dss_96m_fck);
214
215         return r;
216 }
217
218 static void dss_put_clocks(void)
219 {
220         if (core.dss_96m_fck)
221                 clk_put(core.dss_96m_fck);
222         clk_put(core.dss_54m_fck);
223         clk_put(core.dss1_fck);
224         clk_put(core.dss2_fck);
225         clk_put(core.dss_ick);
226 }
227
228 unsigned long dss_clk_get_rate(enum dss_clock clk)
229 {
230         switch (clk) {
231         case DSS_CLK_ICK:
232                 return clk_get_rate(core.dss_ick);
233         case DSS_CLK_FCK1:
234                 return clk_get_rate(core.dss1_fck);
235         case DSS_CLK_FCK2:
236                 return clk_get_rate(core.dss2_fck);
237         case DSS_CLK_54M:
238                 return clk_get_rate(core.dss_54m_fck);
239         case DSS_CLK_96M:
240                 return clk_get_rate(core.dss_96m_fck);
241         }
242
243         BUG();
244         return 0;
245 }
246
247 static unsigned count_clk_bits(enum dss_clock clks)
248 {
249         unsigned num_clks = 0;
250
251         if (clks & DSS_CLK_ICK)
252                 ++num_clks;
253         if (clks & DSS_CLK_FCK1)
254                 ++num_clks;
255         if (clks & DSS_CLK_FCK2)
256                 ++num_clks;
257         if (clks & DSS_CLK_54M)
258                 ++num_clks;
259         if (clks & DSS_CLK_96M)
260                 ++num_clks;
261
262         return num_clks;
263 }
264
265 static void dss_clk_enable_no_ctx(enum dss_clock clks)
266 {
267         unsigned num_clks = count_clk_bits(clks);
268
269         if (clks & DSS_CLK_ICK)
270                 clk_enable(core.dss_ick);
271         if (clks & DSS_CLK_FCK1)
272                 clk_enable(core.dss1_fck);
273         if (clks & DSS_CLK_FCK2)
274                 clk_enable(core.dss2_fck);
275         if (clks & DSS_CLK_54M)
276                 clk_enable(core.dss_54m_fck);
277         if (clks & DSS_CLK_96M)
278                 clk_enable(core.dss_96m_fck);
279
280         core.num_clks_enabled += num_clks;
281 }
282
283 void dss_clk_enable(enum dss_clock clks)
284 {
285         dss_clk_enable_no_ctx(clks);
286
287         if (cpu_is_omap34xx() && dss_need_ctx_restore())
288                 restore_all_ctx();
289 }
290
291 static void dss_clk_disable_no_ctx(enum dss_clock clks)
292 {
293         unsigned num_clks = count_clk_bits(clks);
294
295         if (clks & DSS_CLK_ICK)
296                 clk_disable(core.dss_ick);
297         if (clks & DSS_CLK_FCK1)
298                 clk_disable(core.dss1_fck);
299         if (clks & DSS_CLK_FCK2)
300                 clk_disable(core.dss2_fck);
301         if (clks & DSS_CLK_54M)
302                 clk_disable(core.dss_54m_fck);
303         if (clks & DSS_CLK_96M)
304                 clk_disable(core.dss_96m_fck);
305
306         core.num_clks_enabled -= num_clks;
307 }
308
309 void dss_clk_disable(enum dss_clock clks)
310 {
311         if (cpu_is_omap34xx()) {
312                 unsigned num_clks = count_clk_bits(clks);
313
314                 BUG_ON(core.num_clks_enabled < num_clks);
315
316                 if (core.num_clks_enabled == num_clks)
317                         save_all_ctx();
318         }
319
320         dss_clk_disable_no_ctx(clks);
321 }
322
323 static void dss_clk_enable_all_no_ctx(void)
324 {
325         enum dss_clock clks;
326
327         clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
328         if (cpu_is_omap34xx())
329                 clks |= DSS_CLK_96M;
330         dss_clk_enable_no_ctx(clks);
331 }
332
333 static void dss_clk_disable_all_no_ctx(void)
334 {
335         enum dss_clock clks;
336
337         clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
338         if (cpu_is_omap34xx())
339                 clks |= DSS_CLK_96M;
340         dss_clk_disable_no_ctx(clks);
341 }
342
343 static void dss_clk_disable_all(void)
344 {
345         enum dss_clock clks;
346
347         clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
348         if (cpu_is_omap34xx())
349                 clks |= DSS_CLK_96M;
350         dss_clk_disable(clks);
351 }
352
353 /* DEBUGFS */
354 #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
355 static void dss_debug_dump_clocks(struct seq_file *s)
356 {
357         core_dump_clocks(s);
358         dss_dump_clocks(s);
359         dispc_dump_clocks(s);
360 #ifdef CONFIG_OMAP2_DSS_DSI
361         dsi_dump_clocks(s);
362 #endif
363 }
364
365 static int dss_debug_show(struct seq_file *s, void *unused)
366 {
367         void (*func)(struct seq_file *) = s->private;
368         func(s);
369         return 0;
370 }
371
372 static int dss_debug_open(struct inode *inode, struct file *file)
373 {
374         return single_open(file, dss_debug_show, inode->i_private);
375 }
376
377 static const struct file_operations dss_debug_fops = {
378         .open           = dss_debug_open,
379         .read           = seq_read,
380         .llseek         = seq_lseek,
381         .release        = single_release,
382 };
383
384 static struct dentry *dss_debugfs_dir;
385
386 static int dss_initialize_debugfs(void)
387 {
388         dss_debugfs_dir = debugfs_create_dir("omapdss", NULL);
389         if (IS_ERR(dss_debugfs_dir)) {
390                 int err = PTR_ERR(dss_debugfs_dir);
391                 dss_debugfs_dir = NULL;
392                 return err;
393         }
394
395         debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir,
396                         &dss_debug_dump_clocks, &dss_debug_fops);
397
398         debugfs_create_file("dss", S_IRUGO, dss_debugfs_dir,
399                         &dss_dump_regs, &dss_debug_fops);
400         debugfs_create_file("dispc", S_IRUGO, dss_debugfs_dir,
401                         &dispc_dump_regs, &dss_debug_fops);
402 #ifdef CONFIG_OMAP2_DSS_RFBI
403         debugfs_create_file("rfbi", S_IRUGO, dss_debugfs_dir,
404                         &rfbi_dump_regs, &dss_debug_fops);
405 #endif
406 #ifdef CONFIG_OMAP2_DSS_DSI
407         debugfs_create_file("dsi", S_IRUGO, dss_debugfs_dir,
408                         &dsi_dump_regs, &dss_debug_fops);
409 #endif
410 #ifdef CONFIG_OMAP2_DSS_VENC
411         debugfs_create_file("venc", S_IRUGO, dss_debugfs_dir,
412                         &venc_dump_regs, &dss_debug_fops);
413 #endif
414         return 0;
415 }
416
417 static void dss_uninitialize_debugfs(void)
418 {
419         if (dss_debugfs_dir)
420                 debugfs_remove_recursive(dss_debugfs_dir);
421 }
422 #endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */
423
424 /* PLATFORM DEVICE */
425 static int omap_dss_probe(struct platform_device *pdev)
426 {
427         struct omap_dss_board_info *pdata = pdev->dev.platform_data;
428         int skip_init = 0;
429         int r;
430         int i;
431
432         core.pdev = pdev;
433
434         dss_init_overlay_managers(pdev);
435         dss_init_overlays(pdev);
436
437         r = dss_get_clocks();
438         if (r)
439                 goto fail0;
440
441         dss_clk_enable_all_no_ctx();
442
443         core.ctx_id = dss_get_ctx_id();
444         DSSDBG("initial ctx id %u\n", core.ctx_id);
445
446 #ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
447         /* DISPC_CONTROL */
448         if (omap_readl(0x48050440) & 1) /* LCD enabled? */
449                 skip_init = 1;
450 #endif
451
452         r = dss_init(skip_init);
453         if (r) {
454                 DSSERR("Failed to initialize DSS\n");
455                 goto fail0;
456         }
457
458 #ifdef CONFIG_OMAP2_DSS_RFBI
459         r = rfbi_init();
460         if (r) {
461                 DSSERR("Failed to initialize rfbi\n");
462                 goto fail0;
463         }
464 #endif
465
466         r = dpi_init();
467         if (r) {
468                 DSSERR("Failed to initialize dpi\n");
469                 goto fail0;
470         }
471
472         r = dispc_init();
473         if (r) {
474                 DSSERR("Failed to initialize dispc\n");
475                 goto fail0;
476         }
477 #ifdef CONFIG_OMAP2_DSS_VENC
478         r = venc_init(pdev);
479         if (r) {
480                 DSSERR("Failed to initialize venc\n");
481                 goto fail0;
482         }
483 #endif
484         if (cpu_is_omap34xx()) {
485 #ifdef CONFIG_OMAP2_DSS_SDI
486                 r = sdi_init(skip_init);
487                 if (r) {
488                         DSSERR("Failed to initialize SDI\n");
489                         goto fail0;
490                 }
491 #endif
492 #ifdef CONFIG_OMAP2_DSS_DSI
493                 r = dsi_init(pdev);
494                 if (r) {
495                         DSSERR("Failed to initialize DSI\n");
496                         goto fail0;
497                 }
498 #endif
499         }
500
501 #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
502         r = dss_initialize_debugfs();
503         if (r)
504                 goto fail0;
505 #endif
506
507         for (i = 0; i < pdata->num_devices; ++i) {
508                 struct omap_dss_device *dssdev = pdata->devices[i];
509
510                 r = omap_dss_register_device(dssdev);
511                 if (r)
512                         DSSERR("device reg failed %d\n", i);
513
514                 if (def_disp_name && strcmp(def_disp_name, dssdev->name) == 0)
515                         pdata->default_device = dssdev;
516         }
517
518         dss_clk_disable_all();
519
520         return 0;
521
522         /* XXX fail correctly */
523 fail0:
524         return r;
525 }
526
527 static int omap_dss_remove(struct platform_device *pdev)
528 {
529         struct omap_dss_board_info *pdata = pdev->dev.platform_data;
530         int i;
531         int c;
532
533 #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
534         dss_uninitialize_debugfs();
535 #endif
536
537 #ifdef CONFIG_OMAP2_DSS_VENC
538         venc_exit();
539 #endif
540         dispc_exit();
541         dpi_exit();
542 #ifdef CONFIG_OMAP2_DSS_RFBI
543         rfbi_exit();
544 #endif
545         if (cpu_is_omap34xx()) {
546 #ifdef CONFIG_OMAP2_DSS_DSI
547                 dsi_exit();
548 #endif
549 #ifdef CONFIG_OMAP2_DSS_SDI
550                 sdi_exit();
551 #endif
552         }
553
554         dss_exit();
555
556         /* these should be removed at some point */
557         c = core.dss_ick->usecount;
558         if (c > 0) {
559                 DSSERR("warning: dss_ick usecount %d, disabling\n", c);
560                 while (c-- > 0)
561                         clk_disable(core.dss_ick);
562         }
563
564         c = core.dss1_fck->usecount;
565         if (c > 0) {
566                 DSSERR("warning: dss1_fck usecount %d, disabling\n", c);
567                 while (c-- > 0)
568                         clk_disable(core.dss1_fck);
569         }
570
571         c = core.dss2_fck->usecount;
572         if (c > 0) {
573                 DSSERR("warning: dss2_fck usecount %d, disabling\n", c);
574                 while (c-- > 0)
575                         clk_disable(core.dss2_fck);
576         }
577
578         c = core.dss_54m_fck->usecount;
579         if (c > 0) {
580                 DSSERR("warning: dss_54m_fck usecount %d, disabling\n", c);
581                 while (c-- > 0)
582                         clk_disable(core.dss_54m_fck);
583         }
584
585         if (core.dss_96m_fck) {
586                 c = core.dss_96m_fck->usecount;
587                 if (c > 0) {
588                         DSSERR("warning: dss_96m_fck usecount %d, disabling\n",
589                                         c);
590                         while (c-- > 0)
591                                 clk_disable(core.dss_96m_fck);
592                 }
593         }
594
595         dss_put_clocks();
596
597         dss_uninit_overlays(pdev);
598         dss_uninit_overlay_managers(pdev);
599
600         for (i = 0; i < pdata->num_devices; ++i)
601                 omap_dss_unregister_device(pdata->devices[i]);
602
603         return 0;
604 }
605
606 static void omap_dss_shutdown(struct platform_device *pdev)
607 {
608         DSSDBG("shutdown\n");
609         dss_disable_all_devices();
610 }
611
612 static int omap_dss_suspend(struct platform_device *pdev, pm_message_t state)
613 {
614         DSSDBG("suspend %d\n", state.event);
615
616         return dss_suspend_all_devices();
617 }
618
619 static int omap_dss_resume(struct platform_device *pdev)
620 {
621         DSSDBG("resume\n");
622
623         return dss_resume_all_devices();
624 }
625
626 static struct platform_driver omap_dss_driver = {
627         .probe          = omap_dss_probe,
628         .remove         = omap_dss_remove,
629         .shutdown       = omap_dss_shutdown,
630         .suspend        = omap_dss_suspend,
631         .resume         = omap_dss_resume,
632         .driver         = {
633                 .name   = "omapdss",
634                 .owner  = THIS_MODULE,
635         },
636 };
637
638 /* BUS */
639 static int dss_bus_match(struct device *dev, struct device_driver *driver)
640 {
641         struct omap_dss_device *dssdev = to_dss_device(dev);
642
643         DSSDBG("bus_match. dev %s/%s, drv %s\n",
644                         dev_name(dev), dssdev->driver_name, driver->name);
645
646         return strcmp(dssdev->driver_name, driver->name) == 0;
647 }
648
649 static ssize_t device_name_show(struct device *dev,
650                 struct device_attribute *attr, char *buf)
651 {
652         struct omap_dss_device *dssdev = to_dss_device(dev);
653         return snprintf(buf, PAGE_SIZE, "%s\n",
654                         dssdev->name ?
655                         dssdev->name : "");
656 }
657
658 static struct device_attribute default_dev_attrs[] = {
659         __ATTR(name, S_IRUGO, device_name_show, NULL),
660         __ATTR_NULL,
661 };
662
663 static ssize_t driver_name_show(struct device_driver *drv, char *buf)
664 {
665         struct omap_dss_driver *dssdrv = to_dss_driver(drv);
666         return snprintf(buf, PAGE_SIZE, "%s\n",
667                         dssdrv->driver.name ?
668                         dssdrv->driver.name : "");
669 }
670 static struct driver_attribute default_drv_attrs[] = {
671         __ATTR(name, S_IRUGO, driver_name_show, NULL),
672         __ATTR_NULL,
673 };
674
675 static struct bus_type dss_bus_type = {
676         .name = "omapdss",
677         .match = dss_bus_match,
678         .dev_attrs = default_dev_attrs,
679         .drv_attrs = default_drv_attrs,
680 };
681
682 static void dss_bus_release(struct device *dev)
683 {
684         DSSDBG("bus_release\n");
685 }
686
687 static struct device dss_bus = {
688         .release = dss_bus_release,
689 };
690
691 struct bus_type *dss_get_bus(void)
692 {
693         return &dss_bus_type;
694 }
695
696 /* DRIVER */
697 static int dss_driver_probe(struct device *dev)
698 {
699         int r;
700         struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver);
701         struct omap_dss_device *dssdev = to_dss_device(dev);
702         struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
703         bool force;
704
705         DSSDBG("driver_probe: dev %s/%s, drv %s\n",
706                                 dev_name(dev), dssdev->driver_name,
707                                 dssdrv->driver.name);
708
709         dss_init_device(core.pdev, dssdev);
710
711         /* skip this if the device is behind a ctrl */
712         if (!dssdev->panel.ctrl) {
713                 force = pdata->default_device == dssdev;
714                 dss_recheck_connections(dssdev, force);
715         }
716
717         r = dssdrv->probe(dssdev);
718
719         if (r) {
720                 DSSERR("driver probe failed: %d\n", r);
721                 return r;
722         }
723
724         DSSDBG("probe done for device %s\n", dev_name(dev));
725
726         dssdev->driver = dssdrv;
727
728         return 0;
729 }
730
731 static int dss_driver_remove(struct device *dev)
732 {
733         struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver);
734         struct omap_dss_device *dssdev = to_dss_device(dev);
735
736         DSSDBG("driver_remove: dev %s/%s\n", dev_name(dev),
737                         dssdev->driver_name);
738
739         dssdrv->remove(dssdev);
740
741         dss_uninit_device(core.pdev, dssdev);
742
743         dssdev->driver = NULL;
744
745         return 0;
746 }
747
748 int omap_dss_register_driver(struct omap_dss_driver *dssdriver)
749 {
750         dssdriver->driver.bus = &dss_bus_type;
751         dssdriver->driver.probe = dss_driver_probe;
752         dssdriver->driver.remove = dss_driver_remove;
753         return driver_register(&dssdriver->driver);
754 }
755 EXPORT_SYMBOL(omap_dss_register_driver);
756
757 void omap_dss_unregister_driver(struct omap_dss_driver *dssdriver)
758 {
759         driver_unregister(&dssdriver->driver);
760 }
761 EXPORT_SYMBOL(omap_dss_unregister_driver);
762
763 /* DEVICE */
764 static void reset_device(struct device *dev, int check)
765 {
766         u8 *dev_p = (u8 *)dev;
767         u8 *dev_end = dev_p + sizeof(*dev);
768         void *saved_pdata;
769
770         saved_pdata = dev->platform_data;
771         if (check) {
772                 /*
773                  * Check if there is any other setting than platform_data
774                  * in struct device; warn that these will be reset by our
775                  * init.
776                  */
777                 dev->platform_data = NULL;
778                 while (dev_p < dev_end) {
779                         if (*dev_p) {
780                                 WARN("%s: struct device fields will be "
781                                                 "discarded\n",
782                                      __func__);
783                                 break;
784                         }
785                         dev_p++;
786                 }
787         }
788         memset(dev, 0, sizeof(*dev));
789         dev->platform_data = saved_pdata;
790 }
791
792
793 static void omap_dss_dev_release(struct device *dev)
794 {
795         reset_device(dev, 0);
796 }
797
798 int omap_dss_register_device(struct omap_dss_device *dssdev)
799 {
800         static int dev_num;
801         static int panel_num;
802         int r;
803
804         WARN_ON(!dssdev->driver_name);
805
806         reset_device(&dssdev->dev, 1);
807         dssdev->dev.bus = &dss_bus_type;
808         dssdev->dev.parent = &dss_bus;
809         dssdev->dev.release = omap_dss_dev_release;
810         dev_set_name(&dssdev->dev, "display%d", dev_num++);
811         r = device_register(&dssdev->dev);
812         if (r)
813                 return r;
814
815         if (dssdev->ctrl.panel) {
816                 struct omap_dss_device *panel = dssdev->ctrl.panel;
817
818                 panel->panel.ctrl = dssdev;
819
820                 reset_device(&panel->dev, 1);
821                 panel->dev.bus = &dss_bus_type;
822                 panel->dev.parent = &dssdev->dev;
823                 panel->dev.release = omap_dss_dev_release;
824                 dev_set_name(&panel->dev, "panel%d", panel_num++);
825                 r = device_register(&panel->dev);
826                 if (r)
827                         return r;
828         }
829
830         return 0;
831 }
832
833 void omap_dss_unregister_device(struct omap_dss_device *dssdev)
834 {
835         device_unregister(&dssdev->dev);
836
837         if (dssdev->ctrl.panel) {
838                 struct omap_dss_device *panel = dssdev->ctrl.panel;
839                 device_unregister(&panel->dev);
840         }
841 }
842
843 /* BUS */
844 static int omap_dss_bus_register(void)
845 {
846         int r;
847
848         r = bus_register(&dss_bus_type);
849         if (r) {
850                 DSSERR("bus register failed\n");
851                 return r;
852         }
853
854         dev_set_name(&dss_bus, "omapdss");
855         r = device_register(&dss_bus);
856         if (r) {
857                 DSSERR("bus driver register failed\n");
858                 bus_unregister(&dss_bus_type);
859                 return r;
860         }
861
862         return 0;
863 }
864
865 /* INIT */
866
867 #ifdef CONFIG_OMAP2_DSS_MODULE
868 static void omap_dss_bus_unregister(void)
869 {
870         device_unregister(&dss_bus);
871
872         bus_unregister(&dss_bus_type);
873 }
874
875 static int __init omap_dss_init(void)
876 {
877         int r;
878
879         r = omap_dss_bus_register();
880         if (r)
881                 return r;
882
883         r = platform_driver_register(&omap_dss_driver);
884         if (r) {
885                 omap_dss_bus_unregister();
886                 return r;
887         }
888
889         return 0;
890 }
891
892 static void __exit omap_dss_exit(void)
893 {
894         platform_driver_unregister(&omap_dss_driver);
895
896         omap_dss_bus_unregister();
897 }
898
899 module_init(omap_dss_init);
900 module_exit(omap_dss_exit);
901 #else
902 static int __init omap_dss_init(void)
903 {
904         return omap_dss_bus_register();
905 }
906
907 static int __init omap_dss_init2(void)
908 {
909         return platform_driver_register(&omap_dss_driver);
910 }
911
912 core_initcall(omap_dss_init);
913 device_initcall(omap_dss_init2);
914 #endif
915
916 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
917 MODULE_DESCRIPTION("OMAP2/3 Display Subsystem");
918 MODULE_LICENSE("GPL v2");
919