]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/dsp/dspgateway/dsp_core.c
f2368fb32d8bc3f60d5999cb861c40818a2ed73b
[linux-2.6-omap-h63xx.git] / drivers / dsp / dspgateway / dsp_core.c
1 /*
2  * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
3  *
4  * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
5  *
6  * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * version 2 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20  * 02110-1301 USA
21  *
22  */
23
24 #include <linux/init.h>
25 #include <linux/module.h>
26 #include <linux/platform_device.h>
27 #include <linux/sched.h>
28 #include <linux/mutex.h>
29 #include <linux/err.h>
30 #include <linux/clk.h>
31 #include <asm/delay.h>
32 #include <mach/mailbox.h>
33 #include <mach/dsp.h>
34 #include <mach/dsp_common.h>
35 #include "dsp_mbcmd.h"
36 #include "dsp.h"
37 #include "ipbuf.h"
38
39 MODULE_AUTHOR("Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>");
40 MODULE_DESCRIPTION("OMAP DSP driver module");
41 MODULE_LICENSE("GPL");
42
43 static struct sync_seq *mbseq;
44 static u16 mbseq_expect_tmp;
45 static u16 *mbseq_expect = &mbseq_expect_tmp;
46
47 extern int dsp_mem_late_init(void);
48
49 /*
50  * mailbox commands
51  */
52 extern void mbox_wdsnd(struct mbcmd *mb);
53 extern void mbox_wdreq(struct mbcmd *mb);
54 extern void mbox_bksnd(struct mbcmd *mb);
55 extern void mbox_bkreq(struct mbcmd *mb);
56 extern void mbox_bkyld(struct mbcmd *mb);
57 extern void mbox_bksndp(struct mbcmd *mb);
58 extern void mbox_bkreqp(struct mbcmd *mb);
59 extern void mbox_tctl(struct mbcmd *mb);
60 extern void mbox_poll(struct mbcmd *mb);
61 #ifdef OLD_BINARY_SUPPORT
62 /* v3.3 obsolete */
63 extern void mbox_wdt(struct mbcmd *mb);
64 #endif
65 extern void mbox_suspend(struct mbcmd *mb);
66 static void mbox_kfunc(struct mbcmd *mb);
67 extern void mbox_tcfg(struct mbcmd *mb);
68 extern void mbox_tadd(struct mbcmd *mb);
69 extern void mbox_tdel(struct mbcmd *mb);
70 extern void mbox_dspcfg(struct mbcmd *mb);
71 extern void mbox_regrw(struct mbcmd *mb);
72 extern void mbox_getvar(struct mbcmd *mb);
73 extern void mbox_err(struct mbcmd *mb);
74 extern void mbox_dbg(struct mbcmd *mb);
75
76 static const struct cmdinfo
77         cif_wdsnd    = { "WDSND",    CMD_L_TYPE_TID,    mbox_wdsnd   },
78         cif_wdreq    = { "WDREQ",    CMD_L_TYPE_TID,    mbox_wdreq   },
79         cif_bksnd    = { "BKSND",    CMD_L_TYPE_TID,    mbox_bksnd   },
80         cif_bkreq    = { "BKREQ",    CMD_L_TYPE_TID,    mbox_bkreq   },
81         cif_bkyld    = { "BKYLD",    CMD_L_TYPE_NULL,   mbox_bkyld   },
82         cif_bksndp   = { "BKSNDP",   CMD_L_TYPE_TID,    mbox_bksndp  },
83         cif_bkreqp   = { "BKREQP",   CMD_L_TYPE_TID,    mbox_bkreqp  },
84         cif_tctl     = { "TCTL",     CMD_L_TYPE_TID,    mbox_tctl    },
85         cif_poll     = { "POLL",     CMD_L_TYPE_NULL,   mbox_poll    },
86 #ifdef OLD_BINARY_SUPPORT
87         /* v3.3 obsolete */
88         cif_wdt      = { "WDT",      CMD_L_TYPE_NULL,   mbox_wdt     },
89 #endif
90         cif_runlevel = { "RUNLEVEL", CMD_L_TYPE_SUBCMD, NULL        },
91         cif_pm       = { "PM",       CMD_L_TYPE_SUBCMD, NULL        },
92         cif_suspend  = { "SUSPEND",  CMD_L_TYPE_NULL,   mbox_suspend },
93         cif_kfunc    = { "KFUNC",    CMD_L_TYPE_SUBCMD, mbox_kfunc   },
94         cif_tcfg     = { "TCFG",     CMD_L_TYPE_TID,    mbox_tcfg    },
95         cif_tadd     = { "TADD",     CMD_L_TYPE_TID,    mbox_tadd    },
96         cif_tdel     = { "TDEL",     CMD_L_TYPE_TID,    mbox_tdel    },
97         cif_tstop    = { "TSTOP",    CMD_L_TYPE_TID,    NULL        },
98         cif_dspcfg   = { "DSPCFG",   CMD_L_TYPE_SUBCMD, mbox_dspcfg  },
99         cif_regrw    = { "REGRW",    CMD_L_TYPE_SUBCMD, mbox_regrw   },
100         cif_getvar   = { "GETVAR",   CMD_L_TYPE_SUBCMD, mbox_getvar  },
101         cif_setvar   = { "SETVAR",   CMD_L_TYPE_SUBCMD, NULL        },
102         cif_err      = { "ERR",      CMD_L_TYPE_SUBCMD, mbox_err     },
103         cif_dbg      = { "DBG",      CMD_L_TYPE_NULL,   mbox_dbg     };
104
105 #define MBOX_CMD_MAX    0x80
106 const struct cmdinfo *cmdinfo[MBOX_CMD_MAX] = {
107         [MBOX_CMD_DSP_WDSND]    = &cif_wdsnd,
108         [MBOX_CMD_DSP_WDREQ]    = &cif_wdreq,
109         [MBOX_CMD_DSP_BKSND]    = &cif_bksnd,
110         [MBOX_CMD_DSP_BKREQ]    = &cif_bkreq,
111         [MBOX_CMD_DSP_BKYLD]    = &cif_bkyld,
112         [MBOX_CMD_DSP_BKSNDP]   = &cif_bksndp,
113         [MBOX_CMD_DSP_BKREQP]   = &cif_bkreqp,
114         [MBOX_CMD_DSP_TCTL]     = &cif_tctl,
115         [MBOX_CMD_DSP_POLL]     = &cif_poll,
116 #ifdef OLD_BINARY_SUPPORT
117         [MBOX_CMD_DSP_WDT]      = &cif_wdt, /* v3.3 obsolete */
118 #endif
119         [MBOX_CMD_DSP_RUNLEVEL] = &cif_runlevel,
120         [MBOX_CMD_DSP_PM]       = &cif_pm,
121         [MBOX_CMD_DSP_SUSPEND]  = &cif_suspend,
122         [MBOX_CMD_DSP_KFUNC]    = &cif_kfunc,
123         [MBOX_CMD_DSP_TCFG]     = &cif_tcfg,
124         [MBOX_CMD_DSP_TADD]     = &cif_tadd,
125         [MBOX_CMD_DSP_TDEL]     = &cif_tdel,
126         [MBOX_CMD_DSP_TSTOP]    = &cif_tstop,
127         [MBOX_CMD_DSP_DSPCFG]   = &cif_dspcfg,
128         [MBOX_CMD_DSP_REGRW]    = &cif_regrw,
129         [MBOX_CMD_DSP_GETVAR]   = &cif_getvar,
130         [MBOX_CMD_DSP_SETVAR]   = &cif_setvar,
131         [MBOX_CMD_DSP_ERR]      = &cif_err,
132         [MBOX_CMD_DSP_DBG]      = &cif_dbg,
133 };
134
135 #define list_for_each_entry_safe_natural(p,n,h,m) \
136                         list_for_each_entry_safe(p,n,h,m)
137 #define __BUILD_KFUNC(fn, dir)                                                  \
138 static int __dsp_kfunc_##fn##_devices(struct omap_dsp *dsp, int type, int stage)\
139 {                                                                               \
140         struct dsp_kfunc_device *p, *tmp;                                       \
141         int ret, fail = 0;                                                      \
142                                                                                 \
143         list_for_each_entry_safe_##dir(p, tmp, dsp->kdev_list, entry) {         \
144                 if (type && (p->type != type))                                  \
145                         continue;                                               \
146                 if (p->fn == NULL)                                              \
147                         continue;                                               \
148                 ret = p->fn(p, stage);                                          \
149                 if (ret) {                                                      \
150                         printk(KERN_ERR "%s %s failed\n", #fn, p->name);        \
151                         fail++;                                                 \
152                 }                                                               \
153         }                                                                       \
154         return fail;                                                            \
155 }
156 #define BUILD_KFUNC(fn, dir)                                            \
157 __BUILD_KFUNC(fn, dir)                                                  \
158 static inline int dsp_kfunc_##fn##_devices(struct omap_dsp *dsp)        \
159 {                                                                       \
160         return __dsp_kfunc_##fn##_devices(dsp, 0, 0);                   \
161 }
162 #define BUILD_KFUNC_CTL(fn, dir)                                                        \
163 __BUILD_KFUNC(fn, dir)                                                                  \
164 static inline int dsp_kfunc_##fn##_devices(struct omap_dsp *dsp, int type, int stage)   \
165 {                                                                                       \
166         return __dsp_kfunc_##fn##_devices(dsp, type, stage);                            \
167 }
168
169 BUILD_KFUNC(probe, natural)
170 BUILD_KFUNC(remove, reverse)
171 BUILD_KFUNC_CTL(enable, natural)
172 BUILD_KFUNC_CTL(disable, reverse)
173
174 int sync_with_dsp(u16 *adr, u16 val, int try_cnt)
175 {
176         int try;
177
178         if (*(volatile u16 *)adr == val)
179                 return 0;
180
181         for (try = 0; try < try_cnt; try++) {
182                 udelay(1);
183                 if (*(volatile u16 *)adr == val) {
184                         /* success! */
185                         pr_info("omapdsp: sync_with_dsp(): try = %d\n", try);
186                         return 0;
187                 }
188         }
189
190         /* fail! */
191         return -1;
192 }
193
194 static int mbcmd_sender_prepare(void *data)
195 {
196         struct mb_exarg *arg = data;
197         int i, ret = 0;
198         /*
199          * even if ipbuf_sys_ad is in DSP internal memory,
200          * dsp_mem_enable() never cause to call PM mailbox command
201          * because in that case DSP memory should be always enabled.
202          * (see ipbuf_sys_hold_mem_active in ipbuf.c)
203          *
204          * Therefore, we can call this function here safely.
205          */
206         dsp_mem_enable(ipbuf_sys_ad);
207         if (sync_with_dsp(&ipbuf_sys_ad->s, TID_FREE, 10) < 0) {
208                 printk(KERN_ERR "omapdsp: ipbuf_sys_ad is busy.\n");
209                 ret = -EBUSY;
210                 goto out;
211         }
212
213         for (i = 0; i < arg->argc; i++) {
214                 ipbuf_sys_ad->d[i] = arg->argv[i];
215         }
216         ipbuf_sys_ad->s = arg->tid;
217  out:
218         dsp_mem_disable(ipbuf_sys_ad);
219         return ret;
220 }
221
222 /*
223  * __dsp_mbcmd_send_exarg(): mailbox dispatcher
224  */
225 int __dsp_mbcmd_send_exarg(struct mbcmd *mb, struct mb_exarg *arg,
226                            int recovery_flag)
227 {
228         int ret = 0;
229
230         if (unlikely(omap_dsp->enabled == 0)) {
231                 ret = dsp_kfunc_enable_devices(omap_dsp,
232                                                DSP_KFUNC_DEV_TYPE_COMMON, 0);
233                 if (ret == 0)
234                         omap_dsp->enabled = 1;
235         }
236
237         /*
238          * while MMU fault is set,
239          * only recovery command can be executed
240          */
241         if (dsp_err_isset(ERRCODE_MMU) && !recovery_flag) {
242                 printk(KERN_ERR
243                        "mbox: mmu interrupt is set. %s is aborting.\n",
244                        cmd_name(*mb));
245                 goto out;
246         }
247
248         ret = omap_mbox_msg_send(omap_dsp->mbox,
249                                  *(mbox_msg_t *)mb, (void*)arg);
250         if (ret)
251                 goto out;
252
253         if (mbseq)
254                 mbseq->ad_arm++;
255
256         mblog_add(mb, DIR_A2D);
257  out:
258         return ret;
259 }
260
261 int dsp_mbcmd_send_and_wait_exarg(struct mbcmd *mb, struct mb_exarg *arg,
262                                   wait_queue_head_t *q)
263 {
264         int ret;
265
266         DEFINE_WAIT(wait);
267         prepare_to_wait(q, &wait, TASK_INTERRUPTIBLE);
268         ret = dsp_mbcmd_send_exarg(mb, arg);
269         if (ret < 0)
270                 goto out;
271         schedule_timeout(DSP_TIMEOUT);
272  out:
273         finish_wait(q, &wait);
274         return ret;
275 }
276
277 /*
278  * mbcmd receiver
279  */
280 static int mbcmd_receiver(void* msg)
281 {
282         struct mbcmd *mb = (struct mbcmd *)&msg;
283
284         if (cmdinfo[mb->cmd_h] == NULL) {
285                 printk(KERN_ERR
286                        "invalid message (%08x) for mbcmd_receiver().\n",
287                        (mbox_msg_t)msg);
288                 return -1;
289         }
290
291         (*mbseq_expect)++;
292
293         mblog_add(mb, DIR_D2A);
294
295         /* call handler for the command */
296         if (cmdinfo[mb->cmd_h]->handler)
297                 cmdinfo[mb->cmd_h]->handler(mb);
298         else
299                 printk(KERN_ERR "mbox: %s is not allowed from DSP.\n",
300                        cmd_name(*mb));
301         return 0;
302 }
303
304 static int mbsync_hold_mem_active;
305
306 void dsp_mbox_start(void)
307 {
308         omap_mbox_init_seq(omap_dsp->mbox);
309         mbseq_expect_tmp = 0;
310 }
311
312 void dsp_mbox_stop(void)
313 {
314         mbseq = NULL;
315         mbseq_expect = &mbseq_expect_tmp;
316 }
317
318 int dsp_mbox_config(void *p)
319 {
320         unsigned long flags;
321
322         if (dsp_address_validate(p, sizeof(struct sync_seq), "mbseq") < 0)
323                 return -1;
324         if (dsp_mem_type(p, sizeof(struct sync_seq)) != MEM_TYPE_EXTERN) {
325                 printk(KERN_WARNING
326                        "omapdsp: mbseq is placed in DSP internal memory.\n"
327                        "         It will prevent DSP from idling.\n");
328                 mbsync_hold_mem_active = 1;
329                 /*
330                  * dsp_mem_enable() never fails because
331                  * it has been already enabled in dspcfg process and
332                  * this will just increment the usecount.
333                  */
334                 dsp_mem_enable((void *)daram_base);
335         }
336
337         local_irq_save(flags);
338         mbseq = p;
339         mbseq->da_arm = mbseq_expect_tmp;
340         mbseq_expect = &mbseq->da_arm;
341         local_irq_restore(flags);
342
343         return 0;
344 }
345
346 static int __init dsp_mbox_init(void)
347 {
348         omap_dsp->mbox = omap_mbox_get("dsp");
349         if (IS_ERR(omap_dsp->mbox)) {
350                 printk(KERN_ERR "failed to get mailbox handler for DSP.\n");
351                 return -ENODEV;
352         }
353
354         omap_dsp->mbox->rxq->callback = mbcmd_receiver;
355         omap_dsp->mbox->txq->callback = mbcmd_sender_prepare;
356
357         return 0;
358 }
359
360 static void dsp_mbox_exit(void)
361 {
362         omap_dsp->mbox->txq->callback = NULL;
363         omap_dsp->mbox->rxq->callback = NULL;
364
365         omap_mbox_put(omap_dsp->mbox);
366
367         if (mbsync_hold_mem_active) {
368                 dsp_mem_disable((void *)daram_base);
369                 mbsync_hold_mem_active = 0;
370         }
371 }
372
373 /*
374  * kernel function dispatcher
375  */
376 extern void mbox_fbctl_upd(void);
377 extern void mbox_fbctl_disable(struct mbcmd *mb);
378
379 static void mbox_kfunc_fbctl(struct mbcmd *mb)
380 {
381         switch (mb->data) {
382         case FBCTL_UPD:
383                 mbox_fbctl_upd();
384                 break;
385         case FBCTL_DISABLE:
386                 mbox_fbctl_disable(mb);
387                 break;
388         default:
389                 printk(KERN_ERR
390                        "mbox: Unknown FBCTL from DSP: 0x%04x\n", mb->data);
391         }
392 }
393
394 /*
395  * dspgw: KFUNC message handler
396  */
397 static void mbox_kfunc_power(unsigned short data)
398 {
399         int ret = -1;
400
401         switch (data) {
402         case DVFS_START: /* ACK from DSP */
403                 /* TBD */
404                 break;
405         case AUDIO_PWR_UP:
406                 ret = dsp_kfunc_enable_devices(omap_dsp,
407                                                DSP_KFUNC_DEV_TYPE_AUDIO, 0);
408                 if (ret == 0)
409                         ret++;
410                 break;
411         case AUDIO_PWR_DOWN: /* == AUDIO_PWR_DOWN1 */
412                 ret = dsp_kfunc_disable_devices(omap_dsp,
413                                                 DSP_KFUNC_DEV_TYPE_AUDIO, 1);
414                 break;
415         case AUDIO_PWR_DOWN2:
416                 ret = dsp_kfunc_disable_devices(omap_dsp,
417                                                 DSP_KFUNC_DEV_TYPE_AUDIO, 2);
418                 break;
419         case DSP_PWR_DOWN:
420                 ret = dsp_kfunc_disable_devices(omap_dsp,
421                                                 DSP_KFUNC_DEV_TYPE_COMMON, 0);
422                 if (ret == 0)
423                         omap_dsp->enabled = 0;
424                 break;
425         default:
426                 printk(KERN_ERR
427                        "mailbox: Unknown PWR from DSP: 0x%04x\n", data);
428                 break;
429         }
430
431         if (unlikely(ret < 0)) {
432                 printk(KERN_ERR "mailbox: PWR(0x%04x) failed\n", data);
433                 return;
434         }
435
436         if (likely(ret == 0))
437                 return;
438
439         mbcompose_send(KFUNC, KFUNC_POWER, data);
440 }
441
442 static void mbox_kfunc(struct mbcmd *mb)
443 {
444         switch (mb->cmd_l) {
445         case KFUNC_FBCTL:
446                 mbox_kfunc_fbctl(mb);
447                 break;
448         case KFUNC_POWER:
449                 mbox_kfunc_power(mb->data);
450                 break;
451         default:
452                 printk(KERN_ERR
453                        "mbox: Unknown KFUNC from DSP: 0x%02x\n", mb->cmd_l);
454         }
455 }
456
457 #if defined(CONFIG_ARCH_OMAP1)
458 static inline void dsp_clk_enable(void) {}
459 static inline void dsp_clk_disable(void) {}
460 #elif defined(CONFIG_ARCH_OMAP2)
461 static inline void dsp_clk_enable(void)
462 {
463         clk_enable(dsp_fck_handle);
464         clk_enable(dsp_ick_handle);
465         __dsp_per_enable();
466 }
467 static inline void dsp_clk_disable(void)
468 {
469         __dsp_per_disable();
470         clk_disable(dsp_ick_handle);
471         clk_disable(dsp_fck_handle);
472 }
473 #endif
474
475 int dsp_late_init(void)
476 {
477         int ret;
478
479         dsp_clk_enable();
480         ret = dsp_mem_late_init();
481         if (ret)
482                 return ret;
483         ret = dsp_mbox_init();
484         if (ret)
485                 goto fail_mbox;
486 #ifdef CONFIG_ARCH_OMAP1
487         dsp_set_idle_boot_base(IDLEPG_BASE, IDLEPG_SIZE);
488 #endif
489         ret = dsp_kfunc_enable_devices(omap_dsp,
490                                        DSP_KFUNC_DEV_TYPE_COMMON, 0);
491         if (ret)
492                 goto fail_kfunc;
493         omap_dsp->enabled = 1;
494
495         return 0;
496
497  fail_kfunc:
498         dsp_mbox_exit();
499  fail_mbox:
500         dsp_clk_disable();
501
502         return ret;
503 }
504
505 extern int  dsp_ctl_core_init(void);
506 extern void dsp_ctl_core_exit(void);
507 extern int dsp_ctl_init(void);
508 extern void dsp_ctl_exit(void);
509 extern int  dsp_mem_init(void);
510 extern void dsp_mem_exit(void);
511 extern void mblog_init(void);
512 extern void mblog_exit(void);
513 extern int  dsp_taskmod_init(void);
514 extern void dsp_taskmod_exit(void);
515
516 /*
517  * driver functions
518  */
519 static int __init dsp_drv_probe(struct platform_device *pdev)
520 {
521         int ret;
522         struct omap_dsp *info;
523         struct dsp_platform_data *pdata = pdev->dev.platform_data;
524
525         dev_info(&pdev->dev, "OMAP DSP driver initialization\n");
526
527         info = kzalloc(sizeof(struct omap_dsp), GFP_KERNEL);
528         if (unlikely(info == NULL)) {
529                 dev_dbg(&pdev->dev, "no memory for info\n");
530                 return -ENOMEM;
531         }
532         platform_set_drvdata(pdev, info);
533         omap_dsp = info;
534
535         mutex_init(&info->lock);
536         info->dev = &pdev->dev;
537         info->kdev_list = &pdata->kdev_list;
538
539         ret = dsp_kfunc_probe_devices(info);
540         if (ret) {
541                 ret = -ENXIO;
542                 goto fail_kfunc;
543         }
544
545         ret = dsp_ctl_core_init();
546         if (ret)
547                 goto fail_ctl_core;
548         ret = dsp_mem_init();
549         if (ret)
550                 goto fail_mem;
551         ret = dsp_ctl_init();
552         if (unlikely(ret))
553                 goto fail_ctl_init;
554         mblog_init();
555         ret = dsp_taskmod_init();
556         if (ret)
557                 goto fail_taskmod;
558
559         return 0;
560
561  fail_taskmod:
562         mblog_exit();
563         dsp_ctl_exit();
564  fail_ctl_init:
565         dsp_mem_exit();
566  fail_mem:
567         dsp_ctl_core_exit();
568  fail_ctl_core:
569         dsp_kfunc_remove_devices(info);
570  fail_kfunc:
571         kfree(info);
572
573         return ret;
574 }
575
576 static int dsp_drv_remove(struct platform_device *pdev)
577 {
578         struct omap_dsp *info = platform_get_drvdata(pdev);
579
580         dsp_cpustat_request(CPUSTAT_RESET);
581
582         dsp_cfgstat_request(CFGSTAT_CLEAN);
583         dsp_mbox_exit();
584         dsp_taskmod_exit();
585         mblog_exit();
586         dsp_ctl_exit();
587         dsp_mem_exit();
588
589         dsp_ctl_core_exit();
590
591 #ifdef CONFIG_ARCH_OMAP2
592         __dsp_per_disable();
593         clk_disable(dsp_ick_handle);
594         clk_disable(dsp_fck_handle);
595 #endif
596         dsp_kfunc_remove_devices(info);
597         kfree(info);
598
599         return 0;
600 }
601
602 #if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP1)
603 static int dsp_drv_suspend(struct platform_device *pdev, pm_message_t state)
604 {
605         dsp_cfgstat_request(CFGSTAT_SUSPEND);
606
607         return 0;
608 }
609
610 static int dsp_drv_resume(struct platform_device *pdev)
611 {
612         dsp_cfgstat_request(CFGSTAT_RESUME);
613
614         return 0;
615 }
616 #else
617 #define dsp_drv_suspend         NULL
618 #define dsp_drv_resume          NULL
619 #endif /* CONFIG_PM */
620
621 static struct platform_driver dsp_driver = {
622         .probe          = dsp_drv_probe,
623         .remove         = dsp_drv_remove,
624         .suspend        = dsp_drv_suspend,
625         .resume         = dsp_drv_resume,
626         .driver         = {
627                 .name   = "dsp",
628         },
629 };
630
631 static int __init omap_dsp_mod_init(void)
632 {
633         return platform_driver_register(&dsp_driver);
634 }
635
636 static void __exit omap_dsp_mod_exit(void)
637 {
638         platform_driver_unregister(&dsp_driver);
639 }
640
641 /* module dependency: need mailbox module that have mbox_dsp_info */
642 extern struct omap_mbox mbox_dsp_info;
643 struct omap_mbox *mbox_dep = &mbox_dsp_info;
644
645 module_init(omap_dsp_mod_init);
646 module_exit(omap_dsp_mod_exit);