]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/arm/plat-omap/dsp/dsp_core.c
ARM:OMAP: Integrated blk request queues for mbox fwk
[linux-2.6-omap-h63xx.git] / arch / arm / plat-omap / dsp / 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 <asm/arch/mailbox.h>
33 #include <asm/arch/dsp_common.h>
34 #include "dsp_mbcmd.h"
35 #include "dsp.h"
36 #include "ipbuf.h"
37 #include "dsp_common.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 void 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 static int dsp_kfunc_probe_devices(struct omap_dsp *dsp)
136 {
137         struct dsp_kfunc_device *p;
138         int ret, fail = 0;
139
140         mutex_lock(&dsp->lock);
141         list_for_each_entry(p, dsp->kdev_list, entry) {
142                 if (p->probe == NULL)
143                         continue;
144                 ret = p->probe(p);
145                 if (ret) {
146                         printk(KERN_ERR
147                                "probing %s failed\n", p->name);
148                         fail++;
149                 }
150         }
151         mutex_unlock(&dsp->lock);
152
153         pr_debug("%s() fail:%d\n", __FUNCTION__, fail);
154
155         return fail;
156 }
157
158 static int dsp_kfunc_remove_devices(struct omap_dsp *dsp)
159 {
160         struct dsp_kfunc_device *p;
161         int ret, fail = 0;
162
163         mutex_lock(&dsp->lock);
164         list_for_each_entry_reverse(p, dsp->kdev_list, entry) {
165                 if (p->remove == NULL)
166                         continue;
167                 ret = p->remove(p);
168                 if (ret) {
169                         printk(KERN_ERR
170                                "removing %s failed\n", p->name);
171                         fail++;
172                 }
173         }
174         mutex_unlock(&dsp->lock);
175
176         pr_debug("%s() fail:%d\n", __FUNCTION__, fail);
177
178         return fail;
179 }
180
181 static int dsp_kfunc_enable_devices(struct omap_dsp *dsp, int type, int stage)
182 {
183         struct dsp_kfunc_device *p;
184         int ret, fail = 0;
185
186         mutex_lock(&dsp->lock);
187         list_for_each_entry(p, dsp->kdev_list, entry) {
188                 if ((p->type != type) || (p->enable == NULL))
189                         continue;
190                 ret = p->enable(p, stage);
191                 if (ret) {
192                         printk(KERN_ERR
193                                "enabling %s failed\n", p->name);
194                         fail++;
195                 }
196         }
197         mutex_unlock(&dsp->lock);
198
199         pr_debug("%s(%d) fail:%d\n", __FUNCTION__, type, fail);
200
201         return fail;
202 }
203
204 static int dsp_kfunc_disable_devices(struct omap_dsp *dsp, int type, int stage)
205 {
206         struct dsp_kfunc_device *p;
207         int ret, fail = 0;
208
209         mutex_lock(&dsp->lock);
210         list_for_each_entry_reverse(p, omap_dsp->kdev_list, entry) {
211                 if ((p->type != type) || (p->disable == NULL))
212                         continue;
213                 ret = p->disable(p, stage);
214                 if (ret) {
215                         printk(KERN_ERR
216                                "disabling %s failed\n", p->name);
217                         fail++;
218                 }
219         }
220         mutex_unlock(&dsp->lock);
221
222         pr_debug("%s(%d) fail:%d\n", __FUNCTION__, type, fail);
223
224         return fail;
225 }
226
227 int sync_with_dsp(u16 *adr, u16 val, int try_cnt)
228 {
229         int try;
230
231         if (*(volatile u16 *)adr == val)
232                 return 0;
233
234         for (try = 0; try < try_cnt; try++) {
235                 udelay(1);
236                 if (*(volatile u16 *)adr == val) {
237                         /* success! */
238                         pr_info("omapdsp: sync_with_dsp(): try = %d\n", try);
239                         return 0;
240                 }
241         }
242
243         /* fail! */
244         return -1;
245 }
246
247 static int mbcmd_sender_prepare(void *data)
248 {
249         struct mb_exarg *arg = data;
250         int i, ret = 0;
251         /*
252          * even if ipbuf_sys_ad is in DSP internal memory,
253          * dsp_mem_enable() never cause to call PM mailbox command
254          * because in that case DSP memory should be always enabled.
255          * (see ipbuf_sys_hold_mem_active in ipbuf.c)
256          *
257          * Therefore, we can call this function here safely.
258          */
259         if (sync_with_dsp(&ipbuf_sys_ad->s, TID_FREE, 10) < 0) {
260                 printk(KERN_ERR "omapdsp: ipbuf_sys_ad is busy.\n");
261                 ret = -EBUSY;
262                 goto out;
263         }
264
265         for (i = 0; i < arg->argc; i++) {
266                 ipbuf_sys_ad->d[i] = arg->argv[i];
267         }
268         ipbuf_sys_ad->s = arg->tid;
269  out:
270         return ret;
271 }
272
273 /*
274  * __dsp_mbcmd_send_exarg(): mailbox dispatcher
275  */
276 int __dsp_mbcmd_send_exarg(struct mbcmd *mb, struct mb_exarg *arg,
277                            int recovery_flag)
278 {
279         int ret = 0;
280
281         if (unlikely(omap_dsp->enabled == 0)) {
282                 ret = dsp_kfunc_enable_devices(omap_dsp,
283                                                DSP_KFUNC_DEV_TYPE_COMMON, 0);
284                 if (ret == 0)
285                         omap_dsp->enabled = 1;
286         }
287
288         /*
289          * while MMU fault is set,
290          * only recovery command can be executed
291          */
292         if (dsp_err_isset(ERRCODE_MMU) && !recovery_flag) {
293                 printk(KERN_ERR
294                        "mbox: mmu interrupt is set. %s is aborting.\n",
295                        cmd_name(*mb));
296                 goto out;
297         }
298
299         if (arg)
300                 dsp_mem_enable(ipbuf_sys_ad);
301
302         ret = omap_mbox_msg_send(omap_dsp->mbox,
303                                  *(mbox_msg_t *)mb, (void*)arg);
304         if (ret)
305                 goto out;
306
307         if (mbseq)
308                 mbseq->ad_arm++;
309
310         mblog_add(mb, DIR_A2D);
311  out:
312         if (arg)
313                 dsp_mem_disable(ipbuf_sys_ad);
314
315         return ret;
316 }
317
318 int dsp_mbcmd_send_and_wait_exarg(struct mbcmd *mb, struct mb_exarg *arg,
319                                   wait_queue_head_t *q)
320 {
321         long current_state;
322         DECLARE_WAITQUEUE(wait, current);
323
324         add_wait_queue(q, &wait);
325         current_state = current->state;
326         set_current_state(TASK_INTERRUPTIBLE);
327         if (dsp_mbcmd_send_exarg(mb, arg) < 0) {
328                 set_current_state(current_state);
329                 remove_wait_queue(q, &wait);
330                 return -1;
331         }
332         schedule_timeout(DSP_TIMEOUT);
333         set_current_state(current_state);
334         remove_wait_queue(q, &wait);
335
336         return 0;
337 }
338
339 /*
340  * mbcmd receiver
341  */
342 static void mbcmd_receiver(mbox_msg_t msg)
343 {
344         struct mbcmd *mb = (struct mbcmd *)&msg;
345
346         if (cmdinfo[mb->cmd_h] == NULL) {
347                 printk(KERN_ERR
348                        "invalid message (%08x) for mbcmd_receiver().\n", msg);
349                 return;
350         }
351
352         (*mbseq_expect)++;
353
354         mblog_add(mb, DIR_D2A);
355
356         /* call handler for the command */
357         if (cmdinfo[mb->cmd_h]->handler)
358                 cmdinfo[mb->cmd_h]->handler(mb);
359         else
360                 printk(KERN_ERR "mbox: %s is not allowed from DSP.\n",
361                        cmd_name(*mb));
362 }
363
364 static int mbsync_hold_mem_active;
365
366 void dsp_mbox_start(void)
367 {
368         omap_mbox_init_seq(omap_dsp->mbox);
369         mbseq_expect_tmp = 0;
370 }
371
372 void dsp_mbox_stop(void)
373 {
374         mbseq = NULL;
375         mbseq_expect = &mbseq_expect_tmp;
376 }
377
378 int dsp_mbox_config(void *p)
379 {
380         unsigned long flags;
381
382         if (dsp_address_validate(p, sizeof(struct sync_seq), "mbseq") < 0)
383                 return -1;
384         if (dsp_mem_type(p, sizeof(struct sync_seq)) != MEM_TYPE_EXTERN) {
385                 printk(KERN_WARNING
386                        "omapdsp: mbseq is placed in DSP internal memory.\n"
387                        "         It will prevent DSP from idling.\n");
388                 mbsync_hold_mem_active = 1;
389                 /*
390                  * dsp_mem_enable() never fails because
391                  * it has been already enabled in dspcfg process and
392                  * this will just increment the usecount.
393                  */
394                 dsp_mem_enable((void *)daram_base);
395         }
396
397         local_irq_save(flags);
398         mbseq = p;
399         mbseq->da_arm = mbseq_expect_tmp;
400         mbseq_expect = &mbseq->da_arm;
401         local_irq_restore(flags);
402
403         return 0;
404 }
405
406 static int __init dsp_mbox_init(void)
407 {
408         omap_dsp->mbox = omap_mbox_get("dsp");
409         if (omap_dsp->mbox == NULL) {
410                 printk(KERN_ERR "failed to get mailbox handler for DSP.\n");
411                 return -ENODEV;
412         }
413
414         omap_dsp->mbox->msg_receive_cb = mbcmd_receiver;
415         omap_dsp->mbox->msg_sender_cb = mbcmd_sender_prepare;
416
417         return 0;
418 }
419
420 static void dsp_mbox_exit(void)
421 {
422         omap_dsp->mbox->msg_sender_cb = NULL;
423         omap_dsp->mbox->msg_receive_cb = NULL;
424
425         if (mbsync_hold_mem_active) {
426                 dsp_mem_disable((void *)daram_base);
427                 mbsync_hold_mem_active = 0;
428         }
429 }
430
431 /*
432  * kernel function dispatcher
433  */
434 extern void mbox_fbctl_upd(void);
435 extern void mbox_fbctl_disable(struct mbcmd *mb);
436
437 static void mbox_kfunc_fbctl(struct mbcmd *mb)
438 {
439         switch (mb->data) {
440         case FBCTL_UPD:
441                 mbox_fbctl_upd();
442                 break;
443         case FBCTL_DISABLE:
444                 mbox_fbctl_disable(mb);
445                 break;
446         default:
447                 printk(KERN_ERR
448                        "mbox: Unknown FBCTL from DSP: 0x%04x\n", mb->data);
449         }
450 }
451
452 /*
453  * dspgw: KFUNC message handler
454  */
455 static void mbox_kfunc_power(unsigned short data)
456 {
457         int ret = -1;
458
459         switch (data) {
460         case DVFS_START: /* ACK from DSP */
461                 /* TBD */
462                 break;
463         case AUDIO_PWR_UP:
464                 ret = dsp_kfunc_enable_devices(omap_dsp,
465                                                DSP_KFUNC_DEV_TYPE_AUDIO, 0);
466                 if (ret == 0)
467                         ret++;
468                 break;
469         case AUDIO_PWR_DOWN: /* == AUDIO_PWR_DOWN1 */
470                 ret = dsp_kfunc_disable_devices(omap_dsp,
471                                                 DSP_KFUNC_DEV_TYPE_AUDIO, 1);
472                 break;
473         case AUDIO_PWR_DOWN2:
474                 ret = dsp_kfunc_disable_devices(omap_dsp,
475                                                 DSP_KFUNC_DEV_TYPE_AUDIO, 2);
476                 break;
477         case DSP_PWR_DOWN:
478                 ret = dsp_kfunc_disable_devices(omap_dsp,
479                                                 DSP_KFUNC_DEV_TYPE_COMMON, 0);
480                 if (ret == 0)
481                         omap_dsp->enabled = 0;
482                 break;
483         default:
484                 printk(KERN_ERR
485                        "mailbox: Unknown PWR from DSP: 0x%04x\n", data);
486                 break;
487         }
488
489         if (unlikely(ret < 0)) {
490                 printk(KERN_ERR "mailbox: PWR(0x%04x) failed\n", data);
491                 return;
492         }
493
494         if (likely(ret == 0))
495                 return;
496
497         mbcompose_send(KFUNC, KFUNC_POWER, data);
498 }
499
500 static void mbox_kfunc(struct mbcmd *mb)
501 {
502         switch (mb->cmd_l) {
503         case KFUNC_FBCTL:
504                 mbox_kfunc_fbctl(mb);
505                 break;
506         case KFUNC_POWER:
507                 mbox_kfunc_power(mb->data);
508                 break;
509         default:
510                 printk(KERN_ERR
511                        "mbox: Unknown KFUNC from DSP: 0x%02x\n", mb->cmd_l);
512         }
513 }
514
515 int dsp_late_init(void)
516 {
517         int ret;
518
519         /*dsp_clk_autoidle();*/
520         dsp_clk_enable();
521
522         dsp_mem_late_init();
523         ret = dsp_mbox_init();
524         if (ret)
525                 goto fail_mbox;
526
527 #ifdef CONFIG_ARCH_OMAP1
528         dsp_set_idle_boot_base(IDLEPG_BASE, IDLEPG_SIZE);
529 #endif
530         ret = dsp_kfunc_enable_devices(omap_dsp,
531                                        DSP_KFUNC_DEV_TYPE_COMMON, 0);
532         if (ret == 0)
533                 goto fail_kfunc;
534
535         omap_dsp->enabled = 1;
536
537         return 0;
538
539 fail_kfunc:
540         dsp_mbox_exit();
541 fail_mbox:
542         dsp_clk_disable();
543         return ret;
544 }
545
546 extern int  dsp_ctl_core_init(void);
547 extern void dsp_ctl_core_exit(void);
548 extern void dsp_ctl_init(void);
549 extern void dsp_ctl_exit(void);
550 extern int  dsp_mem_init(void);
551 extern void dsp_mem_exit(void);
552 extern void mblog_init(void);
553 extern void mblog_exit(void);
554 extern int  dsp_taskmod_init(void);
555 extern void dsp_taskmod_exit(void);
556
557 /*
558  * driver functions
559  */
560 static int __init dsp_drv_probe(struct platform_device *pdev)
561 {
562         int ret;
563         struct omap_dsp *info;
564         struct dsp_platform_data *pdata = pdev->dev.platform_data;
565
566         dev_info(&pdev->dev, "OMAP DSP driver initialization\n");
567
568         info = kzalloc(sizeof(struct omap_dsp), GFP_KERNEL);
569         if (unlikely(info == NULL)) {
570                 dev_dbg(&pdev->dev, "no memory for info\n");
571                 return -ENOMEM;
572         }
573         platform_set_drvdata(pdev, info);
574         omap_dsp = info;
575
576         mutex_init(&info->lock);
577         info->dev = &pdev->dev;
578         info->kdev_list = &pdata->kdev_list;
579
580         ret = dsp_kfunc_probe_devices(info);
581         if (ret) {
582                 ret = -ENXIO;
583                 goto fail0;
584         }
585
586         info->mmu_irq = platform_get_irq_byname(pdev, "dsp_mmu");
587         if (unlikely(info->mmu_irq) < 0) {
588                 ret = -ENXIO;
589                 goto fail1;
590         }
591
592         if ((ret = dsp_ctl_core_init()) < 0)
593                 goto fail2;
594         if ((ret = dsp_mem_init()) < 0)
595                 goto fail3;
596         dsp_ctl_init();
597         mblog_init();
598         if ((ret = dsp_taskmod_init()) < 0)
599                 goto fail4;
600
601         return 0;
602
603  fail4:
604         mblog_exit();
605         dsp_ctl_exit();
606         dsp_mem_exit();
607  fail3:
608         dsp_ctl_core_exit();
609  fail2:
610  fail1:
611         dsp_kfunc_remove_devices(info);
612  fail0:
613         kfree(info);
614
615         return ret;
616 }
617
618 static int dsp_drv_remove(struct platform_device *pdev)
619 {
620         struct omap_dsp *info = platform_get_drvdata(pdev);
621
622         dsp_cpustat_request(CPUSTAT_RESET);
623
624         dsp_cfgstat_request(CFGSTAT_CLEAN);
625         dsp_mbox_exit();
626         dsp_taskmod_exit();
627         mblog_exit();
628         dsp_ctl_exit();
629         dsp_mem_exit();
630
631         dsp_ctl_core_exit();
632
633 #ifdef CONFIG_ARCH_OMAP2
634         __dsp_per_disable();
635         clk_disable(dsp_ick_handle);
636         clk_disable(dsp_fck_handle);
637 #endif
638         dsp_kfunc_remove_devices(info);
639         kfree(info);
640
641         return 0;
642 }
643
644 #ifdef CONFIG_PM
645 static int dsp_drv_suspend(struct platform_device *pdev, pm_message_t state)
646 {
647         dsp_cfgstat_request(CFGSTAT_SUSPEND);
648
649         return 0;
650 }
651
652 static int dsp_drv_resume(struct platform_device *pdev)
653 {
654         dsp_cfgstat_request(CFGSTAT_RESUME);
655
656         return 0;
657 }
658 #else
659 #define dsp_drv_suspend         NULL
660 #define dsp_drv_resume          NULL
661 #endif /* CONFIG_PM */
662
663 static struct platform_driver dsp_driver = {
664         .probe          = dsp_drv_probe,
665         .remove         = dsp_drv_remove,
666         .suspend        = dsp_drv_suspend,
667         .resume         = dsp_drv_resume,
668         .driver         = {
669                 .name   = "dsp",
670         },
671 };
672
673 static int __init omap_dsp_mod_init(void)
674 {
675         return platform_driver_register(&dsp_driver);
676 }
677
678 static void __exit omap_dsp_mod_exit(void)
679 {
680         platform_driver_unregister(&dsp_driver);
681 }
682
683 /* module dependency: need mailbox module that have mbox_dsp_info */
684 extern struct omap_mbox mbox_dsp_info;
685 struct omap_mbox *mbox_dep = &mbox_dsp_info;
686
687 module_init(omap_dsp_mod_init);
688 module_exit(omap_dsp_mod_exit);