2 * linux/drivers/video/omap2/dss/dss.c
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
7 * Some code and ideas taken from drivers/video/omap/ driver
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.
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
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/>.
23 #define DSS_SUBSYS_NAME "DSS"
25 #include <linux/kernel.h>
27 #include <linux/export.h>
28 #include <linux/err.h>
29 #include <linux/delay.h>
30 #include <linux/seq_file.h>
31 #include <linux/clk.h>
32 #include <linux/platform_device.h>
33 #include <linux/pm_runtime.h>
35 #include <video/omapdss.h>
36 #include <plat/clock.h>
38 #include "dss_features.h"
40 #define DSS_SZ_REGS SZ_512
46 #define DSS_REG(idx) ((const struct dss_reg) { idx })
48 #define DSS_REVISION DSS_REG(0x0000)
49 #define DSS_SYSCONFIG DSS_REG(0x0010)
50 #define DSS_SYSSTATUS DSS_REG(0x0014)
51 #define DSS_CONTROL DSS_REG(0x0040)
52 #define DSS_SDI_CONTROL DSS_REG(0x0044)
53 #define DSS_PLL_CONTROL DSS_REG(0x0048)
54 #define DSS_SDI_STATUS DSS_REG(0x005C)
56 #define REG_GET(idx, start, end) \
57 FLD_GET(dss_read_reg(idx), start, end)
59 #define REG_FLD_MOD(idx, val, start, end) \
60 dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
63 struct platform_device
*pdev
;
66 struct clk
*dpll4_m4_ck
;
69 unsigned long cache_req_pck
;
70 unsigned long cache_prate
;
71 struct dss_clock_info cache_dss_cinfo
;
72 struct dispc_clock_info cache_dispc_cinfo
;
74 enum omap_dss_clk_source dsi_clk_source
[MAX_NUM_DSI
];
75 enum omap_dss_clk_source dispc_clk_source
;
76 enum omap_dss_clk_source lcd_clk_source
[MAX_DSS_LCD_MANAGERS
];
79 u32 ctx
[DSS_SZ_REGS
/ sizeof(u32
)];
82 static const char * const dss_generic_clk_source_names
[] = {
83 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC
] = "DSI_PLL_HSDIV_DISPC",
84 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI
] = "DSI_PLL_HSDIV_DSI",
85 [OMAP_DSS_CLK_SRC_FCK
] = "DSS_FCK",
88 static inline void dss_write_reg(const struct dss_reg idx
, u32 val
)
90 __raw_writel(val
, dss
.base
+ idx
.idx
);
93 static inline u32
dss_read_reg(const struct dss_reg idx
)
95 return __raw_readl(dss
.base
+ idx
.idx
);
99 dss.ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(DSS_##reg)
101 dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)])
103 static void dss_save_context(void)
105 DSSDBG("dss_save_context\n");
109 if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD
) &
110 OMAP_DISPLAY_TYPE_SDI
) {
115 dss
.ctx_valid
= true;
117 DSSDBG("context saved\n");
120 static void dss_restore_context(void)
122 DSSDBG("dss_restore_context\n");
129 if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD
) &
130 OMAP_DISPLAY_TYPE_SDI
) {
135 DSSDBG("context restored\n");
141 void dss_sdi_init(u8 datapairs
)
145 BUG_ON(datapairs
> 3 || datapairs
< 1);
147 l
= dss_read_reg(DSS_SDI_CONTROL
);
148 l
= FLD_MOD(l
, 0xf, 19, 15); /* SDI_PDIV */
149 l
= FLD_MOD(l
, datapairs
-1, 3, 2); /* SDI_PRSEL */
150 l
= FLD_MOD(l
, 2, 1, 0); /* SDI_BWSEL */
151 dss_write_reg(DSS_SDI_CONTROL
, l
);
153 l
= dss_read_reg(DSS_PLL_CONTROL
);
154 l
= FLD_MOD(l
, 0x7, 25, 22); /* SDI_PLL_FREQSEL */
155 l
= FLD_MOD(l
, 0xb, 16, 11); /* SDI_PLL_REGN */
156 l
= FLD_MOD(l
, 0xb4, 10, 1); /* SDI_PLL_REGM */
157 dss_write_reg(DSS_PLL_CONTROL
, l
);
160 int dss_sdi_enable(void)
162 unsigned long timeout
;
164 dispc_pck_free_enable(1);
167 REG_FLD_MOD(DSS_PLL_CONTROL
, 1, 18, 18); /* SDI_PLL_SYSRESET */
168 udelay(1); /* wait 2x PCLK */
171 REG_FLD_MOD(DSS_PLL_CONTROL
, 1, 28, 28); /* SDI_PLL_GOBIT */
173 /* Waiting for PLL lock request to complete */
174 timeout
= jiffies
+ msecs_to_jiffies(500);
175 while (dss_read_reg(DSS_SDI_STATUS
) & (1 << 6)) {
176 if (time_after_eq(jiffies
, timeout
)) {
177 DSSERR("PLL lock request timed out\n");
182 /* Clearing PLL_GO bit */
183 REG_FLD_MOD(DSS_PLL_CONTROL
, 0, 28, 28);
185 /* Waiting for PLL to lock */
186 timeout
= jiffies
+ msecs_to_jiffies(500);
187 while (!(dss_read_reg(DSS_SDI_STATUS
) & (1 << 5))) {
188 if (time_after_eq(jiffies
, timeout
)) {
189 DSSERR("PLL lock timed out\n");
194 dispc_lcd_enable_signal(1);
196 /* Waiting for SDI reset to complete */
197 timeout
= jiffies
+ msecs_to_jiffies(500);
198 while (!(dss_read_reg(DSS_SDI_STATUS
) & (1 << 2))) {
199 if (time_after_eq(jiffies
, timeout
)) {
200 DSSERR("SDI reset timed out\n");
208 dispc_lcd_enable_signal(0);
211 REG_FLD_MOD(DSS_PLL_CONTROL
, 0, 18, 18); /* SDI_PLL_SYSRESET */
213 dispc_pck_free_enable(0);
218 void dss_sdi_disable(void)
220 dispc_lcd_enable_signal(0);
222 dispc_pck_free_enable(0);
225 REG_FLD_MOD(DSS_PLL_CONTROL
, 0, 18, 18); /* SDI_PLL_SYSRESET */
228 const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src
)
230 return dss_generic_clk_source_names
[clk_src
];
234 void dss_dump_clocks(struct seq_file
*s
)
236 unsigned long dpll4_ck_rate
;
237 unsigned long dpll4_m4_ck_rate
;
238 const char *fclk_name
, *fclk_real_name
;
239 unsigned long fclk_rate
;
241 if (dss_runtime_get())
244 seq_printf(s
, "- DSS -\n");
246 fclk_name
= dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK
);
247 fclk_real_name
= dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_FCK
);
248 fclk_rate
= clk_get_rate(dss
.dss_clk
);
250 if (dss
.dpll4_m4_ck
) {
251 dpll4_ck_rate
= clk_get_rate(clk_get_parent(dss
.dpll4_m4_ck
));
252 dpll4_m4_ck_rate
= clk_get_rate(dss
.dpll4_m4_ck
);
254 seq_printf(s
, "dpll4_ck %lu\n", dpll4_ck_rate
);
256 if (cpu_is_omap3630() || cpu_is_omap44xx())
257 seq_printf(s
, "%s (%s) = %lu / %lu = %lu\n",
258 fclk_name
, fclk_real_name
,
260 dpll4_ck_rate
/ dpll4_m4_ck_rate
,
263 seq_printf(s
, "%s (%s) = %lu / %lu * 2 = %lu\n",
264 fclk_name
, fclk_real_name
,
266 dpll4_ck_rate
/ dpll4_m4_ck_rate
,
269 seq_printf(s
, "%s (%s) = %lu\n",
270 fclk_name
, fclk_real_name
,
277 void dss_dump_regs(struct seq_file
*s
)
279 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
281 if (dss_runtime_get())
284 DUMPREG(DSS_REVISION
);
285 DUMPREG(DSS_SYSCONFIG
);
286 DUMPREG(DSS_SYSSTATUS
);
287 DUMPREG(DSS_CONTROL
);
289 if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD
) &
290 OMAP_DISPLAY_TYPE_SDI
) {
291 DUMPREG(DSS_SDI_CONTROL
);
292 DUMPREG(DSS_PLL_CONTROL
);
293 DUMPREG(DSS_SDI_STATUS
);
300 void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src
)
302 struct platform_device
*dsidev
;
307 case OMAP_DSS_CLK_SRC_FCK
:
310 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC
:
312 dsidev
= dsi_get_dsidev_from_id(0);
313 dsi_wait_pll_hsdiv_dispc_active(dsidev
);
315 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC
:
317 dsidev
= dsi_get_dsidev_from_id(1);
318 dsi_wait_pll_hsdiv_dispc_active(dsidev
);
324 dss_feat_get_reg_field(FEAT_REG_DISPC_CLK_SWITCH
, &start
, &end
);
326 REG_FLD_MOD(DSS_CONTROL
, b
, start
, end
); /* DISPC_CLK_SWITCH */
328 dss
.dispc_clk_source
= clk_src
;
331 void dss_select_dsi_clk_source(int dsi_module
,
332 enum omap_dss_clk_source clk_src
)
334 struct platform_device
*dsidev
;
338 case OMAP_DSS_CLK_SRC_FCK
:
341 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI
:
342 BUG_ON(dsi_module
!= 0);
344 dsidev
= dsi_get_dsidev_from_id(0);
345 dsi_wait_pll_hsdiv_dsi_active(dsidev
);
347 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI
:
348 BUG_ON(dsi_module
!= 1);
350 dsidev
= dsi_get_dsidev_from_id(1);
351 dsi_wait_pll_hsdiv_dsi_active(dsidev
);
357 REG_FLD_MOD(DSS_CONTROL
, b
, 1, 1); /* DSI_CLK_SWITCH */
359 dss
.dsi_clk_source
[dsi_module
] = clk_src
;
362 void dss_select_lcd_clk_source(enum omap_channel channel
,
363 enum omap_dss_clk_source clk_src
)
365 struct platform_device
*dsidev
;
368 if (!dss_has_feature(FEAT_LCD_CLK_SRC
))
372 case OMAP_DSS_CLK_SRC_FCK
:
375 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC
:
376 BUG_ON(channel
!= OMAP_DSS_CHANNEL_LCD
);
378 dsidev
= dsi_get_dsidev_from_id(0);
379 dsi_wait_pll_hsdiv_dispc_active(dsidev
);
381 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC
:
382 BUG_ON(channel
!= OMAP_DSS_CHANNEL_LCD2
);
384 dsidev
= dsi_get_dsidev_from_id(1);
385 dsi_wait_pll_hsdiv_dispc_active(dsidev
);
391 pos
= channel
== OMAP_DSS_CHANNEL_LCD
? 0 : 12;
392 REG_FLD_MOD(DSS_CONTROL
, b
, pos
, pos
); /* LCDx_CLK_SWITCH */
394 ix
= channel
== OMAP_DSS_CHANNEL_LCD
? 0 : 1;
395 dss
.lcd_clk_source
[ix
] = clk_src
;
398 enum omap_dss_clk_source
dss_get_dispc_clk_source(void)
400 return dss
.dispc_clk_source
;
403 enum omap_dss_clk_source
dss_get_dsi_clk_source(int dsi_module
)
405 return dss
.dsi_clk_source
[dsi_module
];
408 enum omap_dss_clk_source
dss_get_lcd_clk_source(enum omap_channel channel
)
410 if (dss_has_feature(FEAT_LCD_CLK_SRC
)) {
411 int ix
= channel
== OMAP_DSS_CHANNEL_LCD
? 0 : 1;
412 return dss
.lcd_clk_source
[ix
];
414 /* LCD_CLK source is the same as DISPC_FCLK source for
416 return dss
.dispc_clk_source
;
420 /* calculate clock rates using dividers in cinfo */
421 int dss_calc_clock_rates(struct dss_clock_info
*cinfo
)
423 if (dss
.dpll4_m4_ck
) {
425 u16 fck_div_max
= 16;
427 if (cpu_is_omap3630() || cpu_is_omap44xx())
430 if (cinfo
->fck_div
> fck_div_max
|| cinfo
->fck_div
== 0)
433 prate
= clk_get_rate(clk_get_parent(dss
.dpll4_m4_ck
));
435 cinfo
->fck
= prate
/ cinfo
->fck_div
;
437 if (cinfo
->fck_div
!= 0)
439 cinfo
->fck
= clk_get_rate(dss
.dss_clk
);
445 int dss_set_clock_div(struct dss_clock_info
*cinfo
)
447 if (dss
.dpll4_m4_ck
) {
451 prate
= clk_get_rate(clk_get_parent(dss
.dpll4_m4_ck
));
452 DSSDBG("dpll4_m4 = %ld\n", prate
);
454 r
= clk_set_rate(dss
.dpll4_m4_ck
, prate
/ cinfo
->fck_div
);
458 if (cinfo
->fck_div
!= 0)
462 DSSDBG("fck = %ld (%d)\n", cinfo
->fck
, cinfo
->fck_div
);
467 int dss_get_clock_div(struct dss_clock_info
*cinfo
)
469 cinfo
->fck
= clk_get_rate(dss
.dss_clk
);
471 if (dss
.dpll4_m4_ck
) {
474 prate
= clk_get_rate(clk_get_parent(dss
.dpll4_m4_ck
));
476 if (cpu_is_omap3630() || cpu_is_omap44xx())
477 cinfo
->fck_div
= prate
/ (cinfo
->fck
);
479 cinfo
->fck_div
= prate
/ (cinfo
->fck
/ 2);
487 unsigned long dss_get_dpll4_rate(void)
490 return clk_get_rate(clk_get_parent(dss
.dpll4_m4_ck
));
495 int dss_calc_clock_div(bool is_tft
, unsigned long req_pck
,
496 struct dss_clock_info
*dss_cinfo
,
497 struct dispc_clock_info
*dispc_cinfo
)
500 struct dss_clock_info best_dss
;
501 struct dispc_clock_info best_dispc
;
503 unsigned long fck
, max_dss_fck
;
505 u16 fck_div
, fck_div_max
= 16;
510 prate
= dss_get_dpll4_rate();
512 max_dss_fck
= dss_feat_get_param_max(FEAT_PARAM_DSS_FCK
);
514 fck
= clk_get_rate(dss
.dss_clk
);
515 if (req_pck
== dss
.cache_req_pck
&&
516 ((cpu_is_omap34xx() && prate
== dss
.cache_prate
) ||
517 dss
.cache_dss_cinfo
.fck
== fck
)) {
518 DSSDBG("dispc clock info found from cache.\n");
519 *dss_cinfo
= dss
.cache_dss_cinfo
;
520 *dispc_cinfo
= dss
.cache_dispc_cinfo
;
524 min_fck_per_pck
= CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK
;
526 if (min_fck_per_pck
&&
527 req_pck
* min_fck_per_pck
> max_dss_fck
) {
528 DSSERR("Requested pixel clock not possible with the current "
529 "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
530 "the constraint off.\n");
535 memset(&best_dss
, 0, sizeof(best_dss
));
536 memset(&best_dispc
, 0, sizeof(best_dispc
));
538 if (dss
.dpll4_m4_ck
== NULL
) {
539 struct dispc_clock_info cur_dispc
;
540 /* XXX can we change the clock on omap2? */
541 fck
= clk_get_rate(dss
.dss_clk
);
544 dispc_find_clk_divs(is_tft
, req_pck
, fck
, &cur_dispc
);
548 best_dss
.fck_div
= fck_div
;
550 best_dispc
= cur_dispc
;
554 if (cpu_is_omap3630() || cpu_is_omap44xx())
557 for (fck_div
= fck_div_max
; fck_div
> 0; --fck_div
) {
558 struct dispc_clock_info cur_dispc
;
560 if (fck_div_max
== 32)
561 fck
= prate
/ fck_div
;
563 fck
= prate
/ fck_div
* 2;
565 if (fck
> max_dss_fck
)
568 if (min_fck_per_pck
&&
569 fck
< req_pck
* min_fck_per_pck
)
574 dispc_find_clk_divs(is_tft
, req_pck
, fck
, &cur_dispc
);
576 if (abs(cur_dispc
.pck
- req_pck
) <
577 abs(best_dispc
.pck
- req_pck
)) {
580 best_dss
.fck_div
= fck_div
;
582 best_dispc
= cur_dispc
;
584 if (cur_dispc
.pck
== req_pck
)
592 if (min_fck_per_pck
) {
593 DSSERR("Could not find suitable clock settings.\n"
594 "Turning FCK/PCK constraint off and"
600 DSSERR("Could not find suitable clock settings.\n");
606 *dss_cinfo
= best_dss
;
608 *dispc_cinfo
= best_dispc
;
610 dss
.cache_req_pck
= req_pck
;
611 dss
.cache_prate
= prate
;
612 dss
.cache_dss_cinfo
= best_dss
;
613 dss
.cache_dispc_cinfo
= best_dispc
;
618 void dss_set_venc_output(enum omap_dss_venc_type type
)
622 if (type
== OMAP_DSS_VENC_TYPE_COMPOSITE
)
624 else if (type
== OMAP_DSS_VENC_TYPE_SVIDEO
)
629 /* venc out selection. 0 = comp, 1 = svideo */
630 REG_FLD_MOD(DSS_CONTROL
, l
, 6, 6);
633 void dss_set_dac_pwrdn_bgz(bool enable
)
635 REG_FLD_MOD(DSS_CONTROL
, enable
, 5, 5); /* DAC Power-Down Control */
638 void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi
)
640 REG_FLD_MOD(DSS_CONTROL
, hdmi
, 15, 15); /* VENC_HDMI_SWITCH */
643 enum dss_hdmi_venc_clk_source_select
dss_get_hdmi_venc_clk_source(void)
645 enum omap_display_type displays
;
647 displays
= dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT
);
648 if ((displays
& OMAP_DISPLAY_TYPE_HDMI
) == 0)
649 return DSS_VENC_TV_CLK
;
651 return REG_GET(DSS_CONTROL
, 15, 15);
654 static int dss_get_clocks(void)
659 clk
= clk_get(&dss
.pdev
->dev
, "fck");
661 DSSERR("can't get clock fck\n");
668 if (cpu_is_omap34xx()) {
669 clk
= clk_get(NULL
, "dpll4_m4_ck");
671 DSSERR("Failed to get dpll4_m4_ck\n");
675 } else if (cpu_is_omap44xx()) {
676 clk
= clk_get(NULL
, "dpll_per_m5x2_ck");
678 DSSERR("Failed to get dpll_per_m5x2_ck\n");
682 } else { /* omap24xx */
686 dss
.dpll4_m4_ck
= clk
;
692 clk_put(dss
.dss_clk
);
694 clk_put(dss
.dpll4_m4_ck
);
699 static void dss_put_clocks(void)
702 clk_put(dss
.dpll4_m4_ck
);
703 clk_put(dss
.dss_clk
);
706 int dss_runtime_get(void)
710 DSSDBG("dss_runtime_get\n");
712 r
= pm_runtime_get_sync(&dss
.pdev
->dev
);
714 return r
< 0 ? r
: 0;
717 void dss_runtime_put(void)
721 DSSDBG("dss_runtime_put\n");
723 r
= pm_runtime_put_sync(&dss
.pdev
->dev
);
728 #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
729 void dss_debug_dump_clocks(struct seq_file
*s
)
732 dispc_dump_clocks(s
);
733 #ifdef CONFIG_OMAP2_DSS_DSI
739 /* DSS HW IP initialisation */
740 static int omap_dsshw_probe(struct platform_device
*pdev
)
742 struct resource
*dss_mem
;
748 dss_mem
= platform_get_resource(dss
.pdev
, IORESOURCE_MEM
, 0);
750 DSSERR("can't get IORESOURCE_MEM DSS\n");
754 dss
.base
= ioremap(dss_mem
->start
, resource_size(dss_mem
));
756 DSSERR("can't ioremap DSS\n");
761 r
= dss_get_clocks();
765 pm_runtime_enable(&pdev
->dev
);
767 r
= dss_runtime_get();
769 goto err_runtime_get
;
772 REG_FLD_MOD(DSS_CONTROL
, 0, 0, 0);
774 #ifdef CONFIG_OMAP2_DSS_VENC
775 REG_FLD_MOD(DSS_CONTROL
, 1, 4, 4); /* venc dac demen */
776 REG_FLD_MOD(DSS_CONTROL
, 1, 3, 3); /* venc clock 4x enable */
777 REG_FLD_MOD(DSS_CONTROL
, 0, 2, 2); /* venc clock mode = normal */
779 dss
.dsi_clk_source
[0] = OMAP_DSS_CLK_SRC_FCK
;
780 dss
.dsi_clk_source
[1] = OMAP_DSS_CLK_SRC_FCK
;
781 dss
.dispc_clk_source
= OMAP_DSS_CLK_SRC_FCK
;
782 dss
.lcd_clk_source
[0] = OMAP_DSS_CLK_SRC_FCK
;
783 dss
.lcd_clk_source
[1] = OMAP_DSS_CLK_SRC_FCK
;
787 DSSERR("Failed to initialize DPI\n");
793 DSSERR("Failed to initialize SDI\n");
797 rev
= dss_read_reg(DSS_REVISION
);
798 printk(KERN_INFO
"OMAP DSS rev %d.%d\n",
799 FLD_GET(rev
, 7, 4), FLD_GET(rev
, 3, 0));
809 pm_runtime_disable(&pdev
->dev
);
817 static int omap_dsshw_remove(struct platform_device
*pdev
)
824 pm_runtime_disable(&pdev
->dev
);
831 static int dss_runtime_suspend(struct device
*dev
)
837 static int dss_runtime_resume(struct device
*dev
)
839 dss_restore_context();
843 static const struct dev_pm_ops dss_pm_ops
= {
844 .runtime_suspend
= dss_runtime_suspend
,
845 .runtime_resume
= dss_runtime_resume
,
848 static struct platform_driver omap_dsshw_driver
= {
849 .probe
= omap_dsshw_probe
,
850 .remove
= omap_dsshw_remove
,
852 .name
= "omapdss_dss",
853 .owner
= THIS_MODULE
,
858 int dss_init_platform_driver(void)
860 return platform_driver_register(&omap_dsshw_driver
);
863 void dss_uninit_platform_driver(void)
865 return platform_driver_unregister(&omap_dsshw_driver
);