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