linux/sound/sh/aica.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3*
   4* Copyright Adrian McMenamin 2005, 2006, 2007
   5* <adrian@mcmen.demon.co.uk>
   6* Requires firmware (BSD licenced) available from:
   7* http://linuxdc.cvs.sourceforge.net/linuxdc/linux-sh-dc/sound/oss/aica/firmware/
   8* or the maintainer
   9*/
  10
  11#include <linux/init.h>
  12#include <linux/jiffies.h>
  13#include <linux/slab.h>
  14#include <linux/time.h>
  15#include <linux/wait.h>
  16#include <linux/module.h>
  17#include <linux/platform_device.h>
  18#include <linux/firmware.h>
  19#include <linux/timer.h>
  20#include <linux/delay.h>
  21#include <linux/workqueue.h>
  22#include <linux/io.h>
  23#include <sound/core.h>
  24#include <sound/control.h>
  25#include <sound/pcm.h>
  26#include <sound/initval.h>
  27#include <sound/info.h>
  28#include <asm/dma.h>
  29#include <mach/sysasic.h>
  30#include "aica.h"
  31
  32MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>");
  33MODULE_DESCRIPTION("Dreamcast AICA sound (pcm) driver");
  34MODULE_LICENSE("GPL");
  35MODULE_SUPPORTED_DEVICE("{{Yamaha/SEGA, AICA}}");
  36MODULE_FIRMWARE("aica_firmware.bin");
  37
  38/* module parameters */
  39#define CARD_NAME "AICA"
  40static int index = -1;
  41static char *id;
  42static bool enable = 1;
  43module_param(index, int, 0444);
  44MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
  45module_param(id, charp, 0444);
  46MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
  47module_param(enable, bool, 0644);
  48MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
  49
  50/* Simple platform device */
  51static struct platform_device *pd;
  52static struct resource aica_memory_space[2] = {
  53        {
  54         .name = "AICA ARM CONTROL",
  55         .start = ARM_RESET_REGISTER,
  56         .flags = IORESOURCE_MEM,
  57         .end = ARM_RESET_REGISTER + 3,
  58         },
  59        {
  60         .name = "AICA Sound RAM",
  61         .start = SPU_MEMORY_BASE,
  62         .flags = IORESOURCE_MEM,
  63         .end = SPU_MEMORY_BASE + 0x200000 - 1,
  64         },
  65};
  66
  67/* SPU specific functions */
  68/* spu_write_wait - wait for G2-SH FIFO to clear */
  69static void spu_write_wait(void)
  70{
  71        int time_count;
  72        time_count = 0;
  73        while (1) {
  74                if (!(readl(G2_FIFO) & 0x11))
  75                        break;
  76                /* To ensure hardware failure doesn't wedge kernel */
  77                time_count++;
  78                if (time_count > 0x10000) {
  79                        snd_printk
  80                            ("WARNING: G2 FIFO appears to be blocked.\n");
  81                        break;
  82                }
  83        }
  84}
  85
  86/* spu_memset - write to memory in SPU address space */
  87static void spu_memset(u32 toi, u32 what, int length)
  88{
  89        int i;
  90        unsigned long flags;
  91        if (snd_BUG_ON(length % 4))
  92                return;
  93        for (i = 0; i < length; i++) {
  94                if (!(i % 8))
  95                        spu_write_wait();
  96                local_irq_save(flags);
  97                writel(what, toi + SPU_MEMORY_BASE);
  98                local_irq_restore(flags);
  99                toi++;
 100        }
 101}
 102
 103/* spu_memload - write to SPU address space */
 104static void spu_memload(u32 toi, void *from, int length)
 105{
 106        unsigned long flags;
 107        u32 *froml = from;
 108        u32 __iomem *to = (u32 __iomem *) (SPU_MEMORY_BASE + toi);
 109        int i;
 110        u32 val;
 111        length = DIV_ROUND_UP(length, 4);
 112        spu_write_wait();
 113        for (i = 0; i < length; i++) {
 114                if (!(i % 8))
 115                        spu_write_wait();
 116                val = *froml;
 117                local_irq_save(flags);
 118                writel(val, to);
 119                local_irq_restore(flags);
 120                froml++;
 121                to++;
 122        }
 123}
 124
 125/* spu_disable - set spu registers to stop sound output */
 126static void spu_disable(void)
 127{
 128        int i;
 129        unsigned long flags;
 130        u32 regval;
 131        spu_write_wait();
 132        regval = readl(ARM_RESET_REGISTER);
 133        regval |= 1;
 134        spu_write_wait();
 135        local_irq_save(flags);
 136        writel(regval, ARM_RESET_REGISTER);
 137        local_irq_restore(flags);
 138        for (i = 0; i < 64; i++) {
 139                spu_write_wait();
 140                regval = readl(SPU_REGISTER_BASE + (i * 0x80));
 141                regval = (regval & ~0x4000) | 0x8000;
 142                spu_write_wait();
 143                local_irq_save(flags);
 144                writel(regval, SPU_REGISTER_BASE + (i * 0x80));
 145                local_irq_restore(flags);
 146        }
 147}
 148
 149/* spu_enable - set spu registers to enable sound output */
 150static void spu_enable(void)
 151{
 152        unsigned long flags;
 153        u32 regval = readl(ARM_RESET_REGISTER);
 154        regval &= ~1;
 155        spu_write_wait();
 156        local_irq_save(flags);
 157        writel(regval, ARM_RESET_REGISTER);
 158        local_irq_restore(flags);
 159}
 160
 161/* 
 162 * Halt the sound processor, clear the memory,
 163 * load some default ARM7 code, and then restart ARM7
 164*/
 165static void spu_reset(void)
 166{
 167        unsigned long flags;
 168        spu_disable();
 169        spu_memset(0, 0, 0x200000 / 4);
 170        /* Put ARM7 in endless loop */
 171        local_irq_save(flags);
 172        __raw_writel(0xea000002, SPU_MEMORY_BASE);
 173        local_irq_restore(flags);
 174        spu_enable();
 175}
 176
 177/* aica_chn_start - write to spu to start playback */
 178static void aica_chn_start(void)
 179{
 180        unsigned long flags;
 181        spu_write_wait();
 182        local_irq_save(flags);
 183        writel(AICA_CMD_KICK | AICA_CMD_START, (u32 *) AICA_CONTROL_POINT);
 184        local_irq_restore(flags);
 185}
 186
 187/* aica_chn_halt - write to spu to halt playback */
 188static void aica_chn_halt(void)
 189{
 190        unsigned long flags;
 191        spu_write_wait();
 192        local_irq_save(flags);
 193        writel(AICA_CMD_KICK | AICA_CMD_STOP, (u32 *) AICA_CONTROL_POINT);
 194        local_irq_restore(flags);
 195}
 196
 197/* ALSA code below */
 198static const struct snd_pcm_hardware snd_pcm_aica_playback_hw = {
 199        .info = (SNDRV_PCM_INFO_NONINTERLEAVED),
 200        .formats =
 201            (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |
 202             SNDRV_PCM_FMTBIT_IMA_ADPCM),
 203        .rates = SNDRV_PCM_RATE_8000_48000,
 204        .rate_min = 8000,
 205        .rate_max = 48000,
 206        .channels_min = 1,
 207        .channels_max = 2,
 208        .buffer_bytes_max = AICA_BUFFER_SIZE,
 209        .period_bytes_min = AICA_PERIOD_SIZE,
 210        .period_bytes_max = AICA_PERIOD_SIZE,
 211        .periods_min = AICA_PERIOD_NUMBER,
 212        .periods_max = AICA_PERIOD_NUMBER,
 213};
 214
 215static int aica_dma_transfer(int channels, int buffer_size,
 216                             struct snd_pcm_substream *substream)
 217{
 218        int q, err, period_offset;
 219        struct snd_card_aica *dreamcastcard;
 220        struct snd_pcm_runtime *runtime;
 221        unsigned long flags;
 222        err = 0;
 223        dreamcastcard = substream->pcm->private_data;
 224        period_offset = dreamcastcard->clicks;
 225        period_offset %= (AICA_PERIOD_NUMBER / channels);
 226        runtime = substream->runtime;
 227        for (q = 0; q < channels; q++) {
 228                local_irq_save(flags);
 229                err = dma_xfer(AICA_DMA_CHANNEL,
 230                               (unsigned long) (runtime->dma_area +
 231                                                (AICA_BUFFER_SIZE * q) /
 232                                                channels +
 233                                                AICA_PERIOD_SIZE *
 234                                                period_offset),
 235                               AICA_CHANNEL0_OFFSET + q * CHANNEL_OFFSET +
 236                               AICA_PERIOD_SIZE * period_offset,
 237                               buffer_size / channels, AICA_DMA_MODE);
 238                if (unlikely(err < 0)) {
 239                        local_irq_restore(flags);
 240                        break;
 241                }
 242                dma_wait_for_completion(AICA_DMA_CHANNEL);
 243                local_irq_restore(flags);
 244        }
 245        return err;
 246}
 247
 248static void startup_aica(struct snd_card_aica *dreamcastcard)
 249{
 250        spu_memload(AICA_CHANNEL0_CONTROL_OFFSET,
 251                    dreamcastcard->channel, sizeof(struct aica_channel));
 252        aica_chn_start();
 253}
 254
 255static void run_spu_dma(struct work_struct *work)
 256{
 257        int buffer_size;
 258        struct snd_pcm_runtime *runtime;
 259        struct snd_card_aica *dreamcastcard;
 260        dreamcastcard =
 261            container_of(work, struct snd_card_aica, spu_dma_work);
 262        runtime = dreamcastcard->substream->runtime;
 263        if (unlikely(dreamcastcard->dma_check == 0)) {
 264                buffer_size =
 265                    frames_to_bytes(runtime, runtime->buffer_size);
 266                if (runtime->channels > 1)
 267                        dreamcastcard->channel->flags |= 0x01;
 268                aica_dma_transfer(runtime->channels, buffer_size,
 269                                  dreamcastcard->substream);
 270                startup_aica(dreamcastcard);
 271                dreamcastcard->clicks =
 272                    buffer_size / (AICA_PERIOD_SIZE * runtime->channels);
 273                return;
 274        } else {
 275                aica_dma_transfer(runtime->channels,
 276                                  AICA_PERIOD_SIZE * runtime->channels,
 277                                  dreamcastcard->substream);
 278                snd_pcm_period_elapsed(dreamcastcard->substream);
 279                dreamcastcard->clicks++;
 280                if (unlikely(dreamcastcard->clicks >= AICA_PERIOD_NUMBER))
 281                        dreamcastcard->clicks %= AICA_PERIOD_NUMBER;
 282                mod_timer(&dreamcastcard->timer, jiffies + 1);
 283        }
 284}
 285
 286static void aica_period_elapsed(struct timer_list *t)
 287{
 288        struct snd_card_aica *dreamcastcard = from_timer(dreamcastcard,
 289                                                              t, timer);
 290        struct snd_pcm_substream *substream = dreamcastcard->substream;
 291        /*timer function - so cannot sleep */
 292        int play_period;
 293        struct snd_pcm_runtime *runtime;
 294        runtime = substream->runtime;
 295        dreamcastcard = substream->pcm->private_data;
 296        /* Have we played out an additional period? */
 297        play_period =
 298            frames_to_bytes(runtime,
 299                            readl
 300                            (AICA_CONTROL_CHANNEL_SAMPLE_NUMBER)) /
 301            AICA_PERIOD_SIZE;
 302        if (play_period == dreamcastcard->current_period) {
 303                /* reschedule the timer */
 304                mod_timer(&(dreamcastcard->timer), jiffies + 1);
 305                return;
 306        }
 307        if (runtime->channels > 1)
 308                dreamcastcard->current_period = play_period;
 309        if (unlikely(dreamcastcard->dma_check == 0))
 310                dreamcastcard->dma_check = 1;
 311        schedule_work(&(dreamcastcard->spu_dma_work));
 312}
 313
 314static void spu_begin_dma(struct snd_pcm_substream *substream)
 315{
 316        struct snd_card_aica *dreamcastcard;
 317        struct snd_pcm_runtime *runtime;
 318        runtime = substream->runtime;
 319        dreamcastcard = substream->pcm->private_data;
 320        /*get the queue to do the work */
 321        schedule_work(&(dreamcastcard->spu_dma_work));
 322        mod_timer(&dreamcastcard->timer, jiffies + 4);
 323}
 324
 325static int snd_aicapcm_pcm_open(struct snd_pcm_substream
 326                                *substream)
 327{
 328        struct snd_pcm_runtime *runtime;
 329        struct aica_channel *channel;
 330        struct snd_card_aica *dreamcastcard;
 331        if (!enable)
 332                return -ENOENT;
 333        dreamcastcard = substream->pcm->private_data;
 334        channel = kmalloc(sizeof(struct aica_channel), GFP_KERNEL);
 335        if (!channel)
 336                return -ENOMEM;
 337        /* set defaults for channel */
 338        channel->sfmt = SM_8BIT;
 339        channel->cmd = AICA_CMD_START;
 340        channel->vol = dreamcastcard->master_volume;
 341        channel->pan = 0x80;
 342        channel->pos = 0;
 343        channel->flags = 0;     /* default to mono */
 344        dreamcastcard->channel = channel;
 345        runtime = substream->runtime;
 346        runtime->hw = snd_pcm_aica_playback_hw;
 347        spu_enable();
 348        dreamcastcard->clicks = 0;
 349        dreamcastcard->current_period = 0;
 350        dreamcastcard->dma_check = 0;
 351        return 0;
 352}
 353
 354static int snd_aicapcm_pcm_close(struct snd_pcm_substream
 355                                 *substream)
 356{
 357        struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
 358        flush_work(&(dreamcastcard->spu_dma_work));
 359        del_timer(&dreamcastcard->timer);
 360        dreamcastcard->substream = NULL;
 361        kfree(dreamcastcard->channel);
 362        spu_disable();
 363        return 0;
 364}
 365
 366static int snd_aicapcm_pcm_hw_free(struct snd_pcm_substream
 367                                   *substream)
 368{
 369        /* Free the DMA buffer */
 370        return snd_pcm_lib_free_pages(substream);
 371}
 372
 373static int snd_aicapcm_pcm_hw_params(struct snd_pcm_substream
 374                                     *substream, struct snd_pcm_hw_params
 375                                     *hw_params)
 376{
 377        /* Allocate a DMA buffer using ALSA built-ins */
 378        return
 379            snd_pcm_lib_malloc_pages(substream,
 380                                     params_buffer_bytes(hw_params));
 381}
 382
 383static int snd_aicapcm_pcm_prepare(struct snd_pcm_substream
 384                                   *substream)
 385{
 386        struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
 387        if ((substream->runtime)->format == SNDRV_PCM_FORMAT_S16_LE)
 388                dreamcastcard->channel->sfmt = SM_16BIT;
 389        dreamcastcard->channel->freq = substream->runtime->rate;
 390        dreamcastcard->substream = substream;
 391        return 0;
 392}
 393
 394static int snd_aicapcm_pcm_trigger(struct snd_pcm_substream
 395                                   *substream, int cmd)
 396{
 397        switch (cmd) {
 398        case SNDRV_PCM_TRIGGER_START:
 399                spu_begin_dma(substream);
 400                break;
 401        case SNDRV_PCM_TRIGGER_STOP:
 402                aica_chn_halt();
 403                break;
 404        default:
 405                return -EINVAL;
 406        }
 407        return 0;
 408}
 409
 410static unsigned long snd_aicapcm_pcm_pointer(struct snd_pcm_substream
 411                                             *substream)
 412{
 413        return readl(AICA_CONTROL_CHANNEL_SAMPLE_NUMBER);
 414}
 415
 416static const struct snd_pcm_ops snd_aicapcm_playback_ops = {
 417        .open = snd_aicapcm_pcm_open,
 418        .close = snd_aicapcm_pcm_close,
 419        .ioctl = snd_pcm_lib_ioctl,
 420        .hw_params = snd_aicapcm_pcm_hw_params,
 421        .hw_free = snd_aicapcm_pcm_hw_free,
 422        .prepare = snd_aicapcm_pcm_prepare,
 423        .trigger = snd_aicapcm_pcm_trigger,
 424        .pointer = snd_aicapcm_pcm_pointer,
 425};
 426
 427/* TO DO: set up to handle more than one pcm instance */
 428static int __init snd_aicapcmchip(struct snd_card_aica
 429                                  *dreamcastcard, int pcm_index)
 430{
 431        struct snd_pcm *pcm;
 432        int err;
 433        /* AICA has no capture ability */
 434        err =
 435            snd_pcm_new(dreamcastcard->card, "AICA PCM", pcm_index, 1, 0,
 436                        &pcm);
 437        if (unlikely(err < 0))
 438                return err;
 439        pcm->private_data = dreamcastcard;
 440        strcpy(pcm->name, "AICA PCM");
 441        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
 442                        &snd_aicapcm_playback_ops);
 443        /* Allocate the DMA buffers */
 444        snd_pcm_lib_preallocate_pages_for_all(pcm,
 445                                              SNDRV_DMA_TYPE_CONTINUOUS,
 446                                              snd_dma_continuous_data(GFP_KERNEL),
 447                                              AICA_BUFFER_SIZE,
 448                                              AICA_BUFFER_SIZE);
 449        return 0;
 450}
 451
 452/* Mixer controls */
 453#define aica_pcmswitch_info             snd_ctl_boolean_mono_info
 454
 455static int aica_pcmswitch_get(struct snd_kcontrol *kcontrol,
 456                              struct snd_ctl_elem_value *ucontrol)
 457{
 458        ucontrol->value.integer.value[0] = 1;   /* TO DO: Fix me */
 459        return 0;
 460}
 461
 462static int aica_pcmswitch_put(struct snd_kcontrol *kcontrol,
 463                              struct snd_ctl_elem_value *ucontrol)
 464{
 465        if (ucontrol->value.integer.value[0] == 1)
 466                return 0;       /* TO DO: Fix me */
 467        else
 468                aica_chn_halt();
 469        return 0;
 470}
 471
 472static int aica_pcmvolume_info(struct snd_kcontrol *kcontrol,
 473                               struct snd_ctl_elem_info *uinfo)
 474{
 475        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 476        uinfo->count = 1;
 477        uinfo->value.integer.min = 0;
 478        uinfo->value.integer.max = 0xFF;
 479        return 0;
 480}
 481
 482static int aica_pcmvolume_get(struct snd_kcontrol *kcontrol,
 483                              struct snd_ctl_elem_value *ucontrol)
 484{
 485        struct snd_card_aica *dreamcastcard;
 486        dreamcastcard = kcontrol->private_data;
 487        if (unlikely(!dreamcastcard->channel))
 488                return -ETXTBSY;        /* we've not yet been set up */
 489        ucontrol->value.integer.value[0] = dreamcastcard->channel->vol;
 490        return 0;
 491}
 492
 493static int aica_pcmvolume_put(struct snd_kcontrol *kcontrol,
 494                              struct snd_ctl_elem_value *ucontrol)
 495{
 496        struct snd_card_aica *dreamcastcard;
 497        unsigned int vol;
 498        dreamcastcard = kcontrol->private_data;
 499        if (unlikely(!dreamcastcard->channel))
 500                return -ETXTBSY;
 501        vol = ucontrol->value.integer.value[0];
 502        if (vol > 0xff)
 503                return -EINVAL;
 504        if (unlikely(dreamcastcard->channel->vol == vol))
 505                return 0;
 506        dreamcastcard->channel->vol = ucontrol->value.integer.value[0];
 507        dreamcastcard->master_volume = ucontrol->value.integer.value[0];
 508        spu_memload(AICA_CHANNEL0_CONTROL_OFFSET,
 509                    dreamcastcard->channel, sizeof(struct aica_channel));
 510        return 1;
 511}
 512
 513static const struct snd_kcontrol_new snd_aica_pcmswitch_control = {
 514        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 515        .name = "PCM Playback Switch",
 516        .index = 0,
 517        .info = aica_pcmswitch_info,
 518        .get = aica_pcmswitch_get,
 519        .put = aica_pcmswitch_put
 520};
 521
 522static const struct snd_kcontrol_new snd_aica_pcmvolume_control = {
 523        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 524        .name = "PCM Playback Volume",
 525        .index = 0,
 526        .info = aica_pcmvolume_info,
 527        .get = aica_pcmvolume_get,
 528        .put = aica_pcmvolume_put
 529};
 530
 531static int load_aica_firmware(void)
 532{
 533        int err;
 534        const struct firmware *fw_entry;
 535        spu_reset();
 536        err = request_firmware(&fw_entry, "aica_firmware.bin", &pd->dev);
 537        if (unlikely(err))
 538                return err;
 539        /* write firmware into memory */
 540        spu_disable();
 541        spu_memload(0, fw_entry->data, fw_entry->size);
 542        spu_enable();
 543        release_firmware(fw_entry);
 544        return err;
 545}
 546
 547static int add_aicamixer_controls(struct snd_card_aica *dreamcastcard)
 548{
 549        int err;
 550        err = snd_ctl_add
 551            (dreamcastcard->card,
 552             snd_ctl_new1(&snd_aica_pcmvolume_control, dreamcastcard));
 553        if (unlikely(err < 0))
 554                return err;
 555        err = snd_ctl_add
 556            (dreamcastcard->card,
 557             snd_ctl_new1(&snd_aica_pcmswitch_control, dreamcastcard));
 558        if (unlikely(err < 0))
 559                return err;
 560        return 0;
 561}
 562
 563static int snd_aica_remove(struct platform_device *devptr)
 564{
 565        struct snd_card_aica *dreamcastcard;
 566        dreamcastcard = platform_get_drvdata(devptr);
 567        if (unlikely(!dreamcastcard))
 568                return -ENODEV;
 569        snd_card_free(dreamcastcard->card);
 570        kfree(dreamcastcard);
 571        return 0;
 572}
 573
 574static int snd_aica_probe(struct platform_device *devptr)
 575{
 576        int err;
 577        struct snd_card_aica *dreamcastcard;
 578        dreamcastcard = kzalloc(sizeof(struct snd_card_aica), GFP_KERNEL);
 579        if (unlikely(!dreamcastcard))
 580                return -ENOMEM;
 581        err = snd_card_new(&devptr->dev, index, SND_AICA_DRIVER,
 582                           THIS_MODULE, 0, &dreamcastcard->card);
 583        if (unlikely(err < 0)) {
 584                kfree(dreamcastcard);
 585                return err;
 586        }
 587        strcpy(dreamcastcard->card->driver, "snd_aica");
 588        strcpy(dreamcastcard->card->shortname, SND_AICA_DRIVER);
 589        strcpy(dreamcastcard->card->longname,
 590               "Yamaha AICA Super Intelligent Sound Processor for SEGA Dreamcast");
 591        /* Prepare to use the queue */
 592        INIT_WORK(&(dreamcastcard->spu_dma_work), run_spu_dma);
 593        timer_setup(&dreamcastcard->timer, aica_period_elapsed, 0);
 594        /* Load the PCM 'chip' */
 595        err = snd_aicapcmchip(dreamcastcard, 0);
 596        if (unlikely(err < 0))
 597                goto freedreamcast;
 598        /* Add basic controls */
 599        err = add_aicamixer_controls(dreamcastcard);
 600        if (unlikely(err < 0))
 601                goto freedreamcast;
 602        /* Register the card with ALSA subsystem */
 603        err = snd_card_register(dreamcastcard->card);
 604        if (unlikely(err < 0))
 605                goto freedreamcast;
 606        platform_set_drvdata(devptr, dreamcastcard);
 607        snd_printk
 608            ("ALSA Driver for Yamaha AICA Super Intelligent Sound Processor\n");
 609        return 0;
 610      freedreamcast:
 611        snd_card_free(dreamcastcard->card);
 612        kfree(dreamcastcard);
 613        return err;
 614}
 615
 616static struct platform_driver snd_aica_driver = {
 617        .probe = snd_aica_probe,
 618        .remove = snd_aica_remove,
 619        .driver = {
 620                .name = SND_AICA_DRIVER,
 621        },
 622};
 623
 624static int __init aica_init(void)
 625{
 626        int err;
 627        err = platform_driver_register(&snd_aica_driver);
 628        if (unlikely(err < 0))
 629                return err;
 630        pd = platform_device_register_simple(SND_AICA_DRIVER, -1,
 631                                             aica_memory_space, 2);
 632        if (IS_ERR(pd)) {
 633                platform_driver_unregister(&snd_aica_driver);
 634                return PTR_ERR(pd);
 635        }
 636        /* Load the firmware */
 637        return load_aica_firmware();
 638}
 639
 640static void __exit aica_exit(void)
 641{
 642        platform_device_unregister(pd);
 643        platform_driver_unregister(&snd_aica_driver);
 644        /* Kill any sound still playing and reset ARM7 to safe state */
 645        spu_reset();
 646}
 647
 648module_init(aica_init);
 649module_exit(aica_exit);
 650