Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003 *
0004 * Copyright Adrian McMenamin 2005, 2006, 2007
0005 * <adrian@mcmen.demon.co.uk>
0006 * Requires firmware (BSD licenced) available from:
0007 * http://linuxdc.cvs.sourceforge.net/linuxdc/linux-sh-dc/sound/oss/aica/firmware/
0008 * or the maintainer
0009 */
0010 
0011 #include <linux/init.h>
0012 #include <linux/jiffies.h>
0013 #include <linux/slab.h>
0014 #include <linux/time.h>
0015 #include <linux/wait.h>
0016 #include <linux/module.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/firmware.h>
0019 #include <linux/timer.h>
0020 #include <linux/delay.h>
0021 #include <linux/workqueue.h>
0022 #include <linux/io.h>
0023 #include <sound/core.h>
0024 #include <sound/control.h>
0025 #include <sound/pcm.h>
0026 #include <sound/initval.h>
0027 #include <sound/info.h>
0028 #include <asm/dma.h>
0029 #include <mach/sysasic.h>
0030 #include "aica.h"
0031 
0032 MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>");
0033 MODULE_DESCRIPTION("Dreamcast AICA sound (pcm) driver");
0034 MODULE_LICENSE("GPL");
0035 MODULE_FIRMWARE("aica_firmware.bin");
0036 
0037 /* module parameters */
0038 #define CARD_NAME "AICA"
0039 static int index = -1;
0040 static char *id;
0041 static bool enable = 1;
0042 module_param(index, int, 0444);
0043 MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
0044 module_param(id, charp, 0444);
0045 MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
0046 module_param(enable, bool, 0644);
0047 MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
0048 
0049 /* Simple platform device */
0050 static struct platform_device *pd;
0051 static struct resource aica_memory_space[2] = {
0052     {
0053      .name = "AICA ARM CONTROL",
0054      .start = ARM_RESET_REGISTER,
0055      .flags = IORESOURCE_MEM,
0056      .end = ARM_RESET_REGISTER + 3,
0057      },
0058     {
0059      .name = "AICA Sound RAM",
0060      .start = SPU_MEMORY_BASE,
0061      .flags = IORESOURCE_MEM,
0062      .end = SPU_MEMORY_BASE + 0x200000 - 1,
0063      },
0064 };
0065 
0066 /* SPU specific functions */
0067 /* spu_write_wait - wait for G2-SH FIFO to clear */
0068 static void spu_write_wait(void)
0069 {
0070     int time_count;
0071     time_count = 0;
0072     while (1) {
0073         if (!(readl(G2_FIFO) & 0x11))
0074             break;
0075         /* To ensure hardware failure doesn't wedge kernel */
0076         time_count++;
0077         if (time_count > 0x10000) {
0078             snd_printk
0079                 ("WARNING: G2 FIFO appears to be blocked.\n");
0080             break;
0081         }
0082     }
0083 }
0084 
0085 /* spu_memset - write to memory in SPU address space */
0086 static void spu_memset(u32 toi, u32 what, int length)
0087 {
0088     int i;
0089     unsigned long flags;
0090     if (snd_BUG_ON(length % 4))
0091         return;
0092     for (i = 0; i < length; i++) {
0093         if (!(i % 8))
0094             spu_write_wait();
0095         local_irq_save(flags);
0096         writel(what, toi + SPU_MEMORY_BASE);
0097         local_irq_restore(flags);
0098         toi++;
0099     }
0100 }
0101 
0102 /* spu_memload - write to SPU address space */
0103 static void spu_memload(u32 toi, const void *from, int length)
0104 {
0105     unsigned long flags;
0106     const u32 *froml = from;
0107     u32 __iomem *to = (u32 __iomem *) (SPU_MEMORY_BASE + toi);
0108     int i;
0109     u32 val;
0110     length = DIV_ROUND_UP(length, 4);
0111     spu_write_wait();
0112     for (i = 0; i < length; i++) {
0113         if (!(i % 8))
0114             spu_write_wait();
0115         val = *froml;
0116         local_irq_save(flags);
0117         writel(val, to);
0118         local_irq_restore(flags);
0119         froml++;
0120         to++;
0121     }
0122 }
0123 
0124 /* spu_disable - set spu registers to stop sound output */
0125 static void spu_disable(void)
0126 {
0127     int i;
0128     unsigned long flags;
0129     u32 regval;
0130     spu_write_wait();
0131     regval = readl(ARM_RESET_REGISTER);
0132     regval |= 1;
0133     spu_write_wait();
0134     local_irq_save(flags);
0135     writel(regval, ARM_RESET_REGISTER);
0136     local_irq_restore(flags);
0137     for (i = 0; i < 64; i++) {
0138         spu_write_wait();
0139         regval = readl(SPU_REGISTER_BASE + (i * 0x80));
0140         regval = (regval & ~0x4000) | 0x8000;
0141         spu_write_wait();
0142         local_irq_save(flags);
0143         writel(regval, SPU_REGISTER_BASE + (i * 0x80));
0144         local_irq_restore(flags);
0145     }
0146 }
0147 
0148 /* spu_enable - set spu registers to enable sound output */
0149 static void spu_enable(void)
0150 {
0151     unsigned long flags;
0152     u32 regval = readl(ARM_RESET_REGISTER);
0153     regval &= ~1;
0154     spu_write_wait();
0155     local_irq_save(flags);
0156     writel(regval, ARM_RESET_REGISTER);
0157     local_irq_restore(flags);
0158 }
0159 
0160 /* 
0161  * Halt the sound processor, clear the memory,
0162  * load some default ARM7 code, and then restart ARM7
0163 */
0164 static void spu_reset(void)
0165 {
0166     unsigned long flags;
0167     spu_disable();
0168     spu_memset(0, 0, 0x200000 / 4);
0169     /* Put ARM7 in endless loop */
0170     local_irq_save(flags);
0171     __raw_writel(0xea000002, SPU_MEMORY_BASE);
0172     local_irq_restore(flags);
0173     spu_enable();
0174 }
0175 
0176 /* aica_chn_start - write to spu to start playback */
0177 static void aica_chn_start(void)
0178 {
0179     unsigned long flags;
0180     spu_write_wait();
0181     local_irq_save(flags);
0182     writel(AICA_CMD_KICK | AICA_CMD_START, (u32 *) AICA_CONTROL_POINT);
0183     local_irq_restore(flags);
0184 }
0185 
0186 /* aica_chn_halt - write to spu to halt playback */
0187 static void aica_chn_halt(void)
0188 {
0189     unsigned long flags;
0190     spu_write_wait();
0191     local_irq_save(flags);
0192     writel(AICA_CMD_KICK | AICA_CMD_STOP, (u32 *) AICA_CONTROL_POINT);
0193     local_irq_restore(flags);
0194 }
0195 
0196 /* ALSA code below */
0197 static const struct snd_pcm_hardware snd_pcm_aica_playback_hw = {
0198     .info = (SNDRV_PCM_INFO_NONINTERLEAVED),
0199     .formats =
0200         (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |
0201          SNDRV_PCM_FMTBIT_IMA_ADPCM),
0202     .rates = SNDRV_PCM_RATE_8000_48000,
0203     .rate_min = 8000,
0204     .rate_max = 48000,
0205     .channels_min = 1,
0206     .channels_max = 2,
0207     .buffer_bytes_max = AICA_BUFFER_SIZE,
0208     .period_bytes_min = AICA_PERIOD_SIZE,
0209     .period_bytes_max = AICA_PERIOD_SIZE,
0210     .periods_min = AICA_PERIOD_NUMBER,
0211     .periods_max = AICA_PERIOD_NUMBER,
0212 };
0213 
0214 static int aica_dma_transfer(int channels, int buffer_size,
0215                  struct snd_pcm_substream *substream)
0216 {
0217     int q, err, period_offset;
0218     struct snd_card_aica *dreamcastcard;
0219     struct snd_pcm_runtime *runtime;
0220     unsigned long flags;
0221     err = 0;
0222     dreamcastcard = substream->pcm->private_data;
0223     period_offset = dreamcastcard->clicks;
0224     period_offset %= (AICA_PERIOD_NUMBER / channels);
0225     runtime = substream->runtime;
0226     for (q = 0; q < channels; q++) {
0227         local_irq_save(flags);
0228         err = dma_xfer(AICA_DMA_CHANNEL,
0229                    (unsigned long) (runtime->dma_area +
0230                         (AICA_BUFFER_SIZE * q) /
0231                         channels +
0232                         AICA_PERIOD_SIZE *
0233                         period_offset),
0234                    AICA_CHANNEL0_OFFSET + q * CHANNEL_OFFSET +
0235                    AICA_PERIOD_SIZE * period_offset,
0236                    buffer_size / channels, AICA_DMA_MODE);
0237         if (unlikely(err < 0)) {
0238             local_irq_restore(flags);
0239             break;
0240         }
0241         dma_wait_for_completion(AICA_DMA_CHANNEL);
0242         local_irq_restore(flags);
0243     }
0244     return err;
0245 }
0246 
0247 static void startup_aica(struct snd_card_aica *dreamcastcard)
0248 {
0249     spu_memload(AICA_CHANNEL0_CONTROL_OFFSET,
0250             dreamcastcard->channel, sizeof(struct aica_channel));
0251     aica_chn_start();
0252 }
0253 
0254 static void run_spu_dma(struct work_struct *work)
0255 {
0256     int buffer_size;
0257     struct snd_pcm_runtime *runtime;
0258     struct snd_card_aica *dreamcastcard;
0259     dreamcastcard =
0260         container_of(work, struct snd_card_aica, spu_dma_work);
0261     runtime = dreamcastcard->substream->runtime;
0262     if (unlikely(dreamcastcard->dma_check == 0)) {
0263         buffer_size =
0264             frames_to_bytes(runtime, runtime->buffer_size);
0265         if (runtime->channels > 1)
0266             dreamcastcard->channel->flags |= 0x01;
0267         aica_dma_transfer(runtime->channels, buffer_size,
0268                   dreamcastcard->substream);
0269         startup_aica(dreamcastcard);
0270         dreamcastcard->clicks =
0271             buffer_size / (AICA_PERIOD_SIZE * runtime->channels);
0272         return;
0273     } else {
0274         aica_dma_transfer(runtime->channels,
0275                   AICA_PERIOD_SIZE * runtime->channels,
0276                   dreamcastcard->substream);
0277         snd_pcm_period_elapsed(dreamcastcard->substream);
0278         dreamcastcard->clicks++;
0279         if (unlikely(dreamcastcard->clicks >= AICA_PERIOD_NUMBER))
0280             dreamcastcard->clicks %= AICA_PERIOD_NUMBER;
0281         mod_timer(&dreamcastcard->timer, jiffies + 1);
0282     }
0283 }
0284 
0285 static void aica_period_elapsed(struct timer_list *t)
0286 {
0287     struct snd_card_aica *dreamcastcard = from_timer(dreamcastcard,
0288                                   t, timer);
0289     struct snd_pcm_substream *substream = dreamcastcard->substream;
0290     /*timer function - so cannot sleep */
0291     int play_period;
0292     struct snd_pcm_runtime *runtime;
0293     runtime = substream->runtime;
0294     dreamcastcard = substream->pcm->private_data;
0295     /* Have we played out an additional period? */
0296     play_period =
0297         frames_to_bytes(runtime,
0298                 readl
0299                 (AICA_CONTROL_CHANNEL_SAMPLE_NUMBER)) /
0300         AICA_PERIOD_SIZE;
0301     if (play_period == dreamcastcard->current_period) {
0302         /* reschedule the timer */
0303         mod_timer(&(dreamcastcard->timer), jiffies + 1);
0304         return;
0305     }
0306     if (runtime->channels > 1)
0307         dreamcastcard->current_period = play_period;
0308     if (unlikely(dreamcastcard->dma_check == 0))
0309         dreamcastcard->dma_check = 1;
0310     schedule_work(&(dreamcastcard->spu_dma_work));
0311 }
0312 
0313 static void spu_begin_dma(struct snd_pcm_substream *substream)
0314 {
0315     struct snd_card_aica *dreamcastcard;
0316     struct snd_pcm_runtime *runtime;
0317     runtime = substream->runtime;
0318     dreamcastcard = substream->pcm->private_data;
0319     /*get the queue to do the work */
0320     schedule_work(&(dreamcastcard->spu_dma_work));
0321     mod_timer(&dreamcastcard->timer, jiffies + 4);
0322 }
0323 
0324 static int snd_aicapcm_pcm_open(struct snd_pcm_substream
0325                 *substream)
0326 {
0327     struct snd_pcm_runtime *runtime;
0328     struct aica_channel *channel;
0329     struct snd_card_aica *dreamcastcard;
0330     if (!enable)
0331         return -ENOENT;
0332     dreamcastcard = substream->pcm->private_data;
0333     channel = kmalloc(sizeof(struct aica_channel), GFP_KERNEL);
0334     if (!channel)
0335         return -ENOMEM;
0336     /* set defaults for channel */
0337     channel->sfmt = SM_8BIT;
0338     channel->cmd = AICA_CMD_START;
0339     channel->vol = dreamcastcard->master_volume;
0340     channel->pan = 0x80;
0341     channel->pos = 0;
0342     channel->flags = 0; /* default to mono */
0343     dreamcastcard->channel = channel;
0344     runtime = substream->runtime;
0345     runtime->hw = snd_pcm_aica_playback_hw;
0346     spu_enable();
0347     dreamcastcard->clicks = 0;
0348     dreamcastcard->current_period = 0;
0349     dreamcastcard->dma_check = 0;
0350     return 0;
0351 }
0352 
0353 static int snd_aicapcm_pcm_close(struct snd_pcm_substream
0354                  *substream)
0355 {
0356     struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
0357     flush_work(&(dreamcastcard->spu_dma_work));
0358     del_timer(&dreamcastcard->timer);
0359     dreamcastcard->substream = NULL;
0360     kfree(dreamcastcard->channel);
0361     spu_disable();
0362     return 0;
0363 }
0364 
0365 static int snd_aicapcm_pcm_prepare(struct snd_pcm_substream
0366                    *substream)
0367 {
0368     struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
0369     if ((substream->runtime)->format == SNDRV_PCM_FORMAT_S16_LE)
0370         dreamcastcard->channel->sfmt = SM_16BIT;
0371     dreamcastcard->channel->freq = substream->runtime->rate;
0372     dreamcastcard->substream = substream;
0373     return 0;
0374 }
0375 
0376 static int snd_aicapcm_pcm_trigger(struct snd_pcm_substream
0377                    *substream, int cmd)
0378 {
0379     switch (cmd) {
0380     case SNDRV_PCM_TRIGGER_START:
0381         spu_begin_dma(substream);
0382         break;
0383     case SNDRV_PCM_TRIGGER_STOP:
0384         aica_chn_halt();
0385         break;
0386     default:
0387         return -EINVAL;
0388     }
0389     return 0;
0390 }
0391 
0392 static unsigned long snd_aicapcm_pcm_pointer(struct snd_pcm_substream
0393                          *substream)
0394 {
0395     return readl(AICA_CONTROL_CHANNEL_SAMPLE_NUMBER);
0396 }
0397 
0398 static const struct snd_pcm_ops snd_aicapcm_playback_ops = {
0399     .open = snd_aicapcm_pcm_open,
0400     .close = snd_aicapcm_pcm_close,
0401     .prepare = snd_aicapcm_pcm_prepare,
0402     .trigger = snd_aicapcm_pcm_trigger,
0403     .pointer = snd_aicapcm_pcm_pointer,
0404 };
0405 
0406 /* TO DO: set up to handle more than one pcm instance */
0407 static int __init snd_aicapcmchip(struct snd_card_aica
0408                   *dreamcastcard, int pcm_index)
0409 {
0410     struct snd_pcm *pcm;
0411     int err;
0412     /* AICA has no capture ability */
0413     err =
0414         snd_pcm_new(dreamcastcard->card, "AICA PCM", pcm_index, 1, 0,
0415             &pcm);
0416     if (unlikely(err < 0))
0417         return err;
0418     pcm->private_data = dreamcastcard;
0419     strcpy(pcm->name, "AICA PCM");
0420     snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
0421             &snd_aicapcm_playback_ops);
0422     /* Allocate the DMA buffers */
0423     snd_pcm_set_managed_buffer_all(pcm,
0424                        SNDRV_DMA_TYPE_CONTINUOUS,
0425                        NULL,
0426                        AICA_BUFFER_SIZE,
0427                        AICA_BUFFER_SIZE);
0428     return 0;
0429 }
0430 
0431 /* Mixer controls */
0432 #define aica_pcmswitch_info     snd_ctl_boolean_mono_info
0433 
0434 static int aica_pcmswitch_get(struct snd_kcontrol *kcontrol,
0435                   struct snd_ctl_elem_value *ucontrol)
0436 {
0437     ucontrol->value.integer.value[0] = 1;   /* TO DO: Fix me */
0438     return 0;
0439 }
0440 
0441 static int aica_pcmswitch_put(struct snd_kcontrol *kcontrol,
0442                   struct snd_ctl_elem_value *ucontrol)
0443 {
0444     if (ucontrol->value.integer.value[0] == 1)
0445         return 0;   /* TO DO: Fix me */
0446     else
0447         aica_chn_halt();
0448     return 0;
0449 }
0450 
0451 static int aica_pcmvolume_info(struct snd_kcontrol *kcontrol,
0452                    struct snd_ctl_elem_info *uinfo)
0453 {
0454     uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
0455     uinfo->count = 1;
0456     uinfo->value.integer.min = 0;
0457     uinfo->value.integer.max = 0xFF;
0458     return 0;
0459 }
0460 
0461 static int aica_pcmvolume_get(struct snd_kcontrol *kcontrol,
0462                   struct snd_ctl_elem_value *ucontrol)
0463 {
0464     struct snd_card_aica *dreamcastcard;
0465     dreamcastcard = kcontrol->private_data;
0466     if (unlikely(!dreamcastcard->channel))
0467         return -ETXTBSY;    /* we've not yet been set up */
0468     ucontrol->value.integer.value[0] = dreamcastcard->channel->vol;
0469     return 0;
0470 }
0471 
0472 static int aica_pcmvolume_put(struct snd_kcontrol *kcontrol,
0473                   struct snd_ctl_elem_value *ucontrol)
0474 {
0475     struct snd_card_aica *dreamcastcard;
0476     unsigned int vol;
0477     dreamcastcard = kcontrol->private_data;
0478     if (unlikely(!dreamcastcard->channel))
0479         return -ETXTBSY;
0480     vol = ucontrol->value.integer.value[0];
0481     if (vol > 0xff)
0482         return -EINVAL;
0483     if (unlikely(dreamcastcard->channel->vol == vol))
0484         return 0;
0485     dreamcastcard->channel->vol = ucontrol->value.integer.value[0];
0486     dreamcastcard->master_volume = ucontrol->value.integer.value[0];
0487     spu_memload(AICA_CHANNEL0_CONTROL_OFFSET,
0488             dreamcastcard->channel, sizeof(struct aica_channel));
0489     return 1;
0490 }
0491 
0492 static const struct snd_kcontrol_new snd_aica_pcmswitch_control = {
0493     .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0494     .name = "PCM Playback Switch",
0495     .index = 0,
0496     .info = aica_pcmswitch_info,
0497     .get = aica_pcmswitch_get,
0498     .put = aica_pcmswitch_put
0499 };
0500 
0501 static const struct snd_kcontrol_new snd_aica_pcmvolume_control = {
0502     .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0503     .name = "PCM Playback Volume",
0504     .index = 0,
0505     .info = aica_pcmvolume_info,
0506     .get = aica_pcmvolume_get,
0507     .put = aica_pcmvolume_put
0508 };
0509 
0510 static int load_aica_firmware(void)
0511 {
0512     int err;
0513     const struct firmware *fw_entry;
0514     spu_reset();
0515     err = request_firmware(&fw_entry, "aica_firmware.bin", &pd->dev);
0516     if (unlikely(err))
0517         return err;
0518     /* write firmware into memory */
0519     spu_disable();
0520     spu_memload(0, fw_entry->data, fw_entry->size);
0521     spu_enable();
0522     release_firmware(fw_entry);
0523     return err;
0524 }
0525 
0526 static int add_aicamixer_controls(struct snd_card_aica *dreamcastcard)
0527 {
0528     int err;
0529     err = snd_ctl_add
0530         (dreamcastcard->card,
0531          snd_ctl_new1(&snd_aica_pcmvolume_control, dreamcastcard));
0532     if (unlikely(err < 0))
0533         return err;
0534     err = snd_ctl_add
0535         (dreamcastcard->card,
0536          snd_ctl_new1(&snd_aica_pcmswitch_control, dreamcastcard));
0537     if (unlikely(err < 0))
0538         return err;
0539     return 0;
0540 }
0541 
0542 static int snd_aica_remove(struct platform_device *devptr)
0543 {
0544     struct snd_card_aica *dreamcastcard;
0545     dreamcastcard = platform_get_drvdata(devptr);
0546     if (unlikely(!dreamcastcard))
0547         return -ENODEV;
0548     snd_card_free(dreamcastcard->card);
0549     kfree(dreamcastcard);
0550     return 0;
0551 }
0552 
0553 static int snd_aica_probe(struct platform_device *devptr)
0554 {
0555     int err;
0556     struct snd_card_aica *dreamcastcard;
0557     dreamcastcard = kzalloc(sizeof(struct snd_card_aica), GFP_KERNEL);
0558     if (unlikely(!dreamcastcard))
0559         return -ENOMEM;
0560     err = snd_card_new(&devptr->dev, index, SND_AICA_DRIVER,
0561                THIS_MODULE, 0, &dreamcastcard->card);
0562     if (unlikely(err < 0)) {
0563         kfree(dreamcastcard);
0564         return err;
0565     }
0566     strcpy(dreamcastcard->card->driver, "snd_aica");
0567     strcpy(dreamcastcard->card->shortname, SND_AICA_DRIVER);
0568     strcpy(dreamcastcard->card->longname,
0569            "Yamaha AICA Super Intelligent Sound Processor for SEGA Dreamcast");
0570     /* Prepare to use the queue */
0571     INIT_WORK(&(dreamcastcard->spu_dma_work), run_spu_dma);
0572     timer_setup(&dreamcastcard->timer, aica_period_elapsed, 0);
0573     /* Load the PCM 'chip' */
0574     err = snd_aicapcmchip(dreamcastcard, 0);
0575     if (unlikely(err < 0))
0576         goto freedreamcast;
0577     /* Add basic controls */
0578     err = add_aicamixer_controls(dreamcastcard);
0579     if (unlikely(err < 0))
0580         goto freedreamcast;
0581     /* Register the card with ALSA subsystem */
0582     err = snd_card_register(dreamcastcard->card);
0583     if (unlikely(err < 0))
0584         goto freedreamcast;
0585     platform_set_drvdata(devptr, dreamcastcard);
0586     snd_printk
0587         ("ALSA Driver for Yamaha AICA Super Intelligent Sound Processor\n");
0588     return 0;
0589       freedreamcast:
0590     snd_card_free(dreamcastcard->card);
0591     kfree(dreamcastcard);
0592     return err;
0593 }
0594 
0595 static struct platform_driver snd_aica_driver = {
0596     .probe = snd_aica_probe,
0597     .remove = snd_aica_remove,
0598     .driver = {
0599         .name = SND_AICA_DRIVER,
0600     },
0601 };
0602 
0603 static int __init aica_init(void)
0604 {
0605     int err;
0606     err = platform_driver_register(&snd_aica_driver);
0607     if (unlikely(err < 0))
0608         return err;
0609     pd = platform_device_register_simple(SND_AICA_DRIVER, -1,
0610                          aica_memory_space, 2);
0611     if (IS_ERR(pd)) {
0612         platform_driver_unregister(&snd_aica_driver);
0613         return PTR_ERR(pd);
0614     }
0615     /* Load the firmware */
0616     return load_aica_firmware();
0617 }
0618 
0619 static void __exit aica_exit(void)
0620 {
0621     platform_device_unregister(pd);
0622     platform_driver_unregister(&snd_aica_driver);
0623     /* Kill any sound still playing and reset ARM7 to safe state */
0624     spu_reset();
0625 }
0626 
0627 module_init(aica_init);
0628 module_exit(aica_exit);