linux/sound/soc/fsl/imx-ssi.c
<<
>>
Prefs
   1/*
   2 * imx-ssi.c  --  ALSA Soc Audio Layer
   3 *
   4 * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
   5 *
   6 * This code is based on code copyrighted by Freescale,
   7 * Liam Girdwood, Javier Martin and probably others.
   8 *
   9 *  This program is free software; you can redistribute  it and/or modify it
  10 *  under  the terms of  the GNU General  Public License as published by the
  11 *  Free Software Foundation;  either version 2 of the  License, or (at your
  12 *  option) any later version.
  13 *
  14 *
  15 * The i.MX SSI core has some nasty limitations in AC97 mode. While most
  16 * sane processor vendors have a FIFO per AC97 slot, the i.MX has only
  17 * one FIFO which combines all valid receive slots. We cannot even select
  18 * which slots we want to receive. The WM9712 with which this driver
  19 * was developed with always sends GPIO status data in slot 12 which
  20 * we receive in our (PCM-) data stream. The only chance we have is to
  21 * manually skip this data in the FIQ handler. With sampling rates different
  22 * from 48000Hz not every frame has valid receive data, so the ratio
  23 * between pcm data and GPIO status data changes. Our FIQ handler is not
  24 * able to handle this, hence this driver only works with 48000Hz sampling
  25 * rate.
  26 * Reading and writing AC97 registers is another challenge. The core
  27 * provides us status bits when the read register is updated with *another*
  28 * value. When we read the same register two times (and the register still
  29 * contains the same value) these status bits are not set. We work
  30 * around this by not polling these bits but only wait a fixed delay.
  31 *
  32 */
  33
  34#include <linux/clk.h>
  35#include <linux/delay.h>
  36#include <linux/device.h>
  37#include <linux/dma-mapping.h>
  38#include <linux/init.h>
  39#include <linux/interrupt.h>
  40#include <linux/module.h>
  41#include <linux/platform_device.h>
  42#include <linux/slab.h>
  43
  44#include <sound/core.h>
  45#include <sound/initval.h>
  46#include <sound/pcm.h>
  47#include <sound/pcm_params.h>
  48#include <sound/soc.h>
  49
  50#include <linux/platform_data/asoc-imx-ssi.h>
  51
  52#include "imx-ssi.h"
  53
  54#define SSI_SACNT_DEFAULT (SSI_SACNT_AC97EN | SSI_SACNT_FV)
  55
  56/*
  57 * SSI Network Mode or TDM slots configuration.
  58 * Should only be called when port is inactive (i.e. SSIEN = 0).
  59 */
  60static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
  61        unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
  62{
  63        struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
  64        u32 sccr;
  65
  66        sccr = readl(ssi->base + SSI_STCCR);
  67        sccr &= ~SSI_STCCR_DC_MASK;
  68        sccr |= SSI_STCCR_DC(slots - 1);
  69        writel(sccr, ssi->base + SSI_STCCR);
  70
  71        sccr = readl(ssi->base + SSI_SRCCR);
  72        sccr &= ~SSI_STCCR_DC_MASK;
  73        sccr |= SSI_STCCR_DC(slots - 1);
  74        writel(sccr, ssi->base + SSI_SRCCR);
  75
  76        writel(tx_mask, ssi->base + SSI_STMSK);
  77        writel(rx_mask, ssi->base + SSI_SRMSK);
  78
  79        return 0;
  80}
  81
  82/*
  83 * SSI DAI format configuration.
  84 * Should only be called when port is inactive (i.e. SSIEN = 0).
  85 */
  86static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
  87{
  88        struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
  89        u32 strcr = 0, scr;
  90
  91        scr = readl(ssi->base + SSI_SCR) & ~(SSI_SCR_SYN | SSI_SCR_NET);
  92
  93        /* DAI mode */
  94        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
  95        case SND_SOC_DAIFMT_I2S:
  96                /* data on rising edge of bclk, frame low 1clk before data */
  97                strcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0;
  98                scr |= SSI_SCR_NET;
  99                if (ssi->flags & IMX_SSI_USE_I2S_SLAVE) {
 100                        scr &= ~SSI_I2S_MODE_MASK;
 101                        scr |= SSI_SCR_I2S_MODE_SLAVE;
 102                }
 103                break;
 104        case SND_SOC_DAIFMT_LEFT_J:
 105                /* data on rising edge of bclk, frame high with data */
 106                strcr |= SSI_STCR_TXBIT0;
 107                break;
 108        case SND_SOC_DAIFMT_DSP_B:
 109                /* data on rising edge of bclk, frame high with data */
 110                strcr |= SSI_STCR_TFSL | SSI_STCR_TXBIT0;
 111                break;
 112        case SND_SOC_DAIFMT_DSP_A:
 113                /* data on rising edge of bclk, frame high 1clk before data */
 114                strcr |= SSI_STCR_TFSL | SSI_STCR_TXBIT0 | SSI_STCR_TEFS;
 115                break;
 116        }
 117
 118        /* DAI clock inversion */
 119        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 120        case SND_SOC_DAIFMT_IB_IF:
 121                strcr |= SSI_STCR_TFSI;
 122                strcr &= ~SSI_STCR_TSCKP;
 123                break;
 124        case SND_SOC_DAIFMT_IB_NF:
 125                strcr &= ~(SSI_STCR_TSCKP | SSI_STCR_TFSI);
 126                break;
 127        case SND_SOC_DAIFMT_NB_IF:
 128                strcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP;
 129                break;
 130        case SND_SOC_DAIFMT_NB_NF:
 131                strcr &= ~SSI_STCR_TFSI;
 132                strcr |= SSI_STCR_TSCKP;
 133                break;
 134        }
 135
 136        /* DAI clock master masks */
 137        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 138        case SND_SOC_DAIFMT_CBM_CFM:
 139                break;
 140        default:
 141                /* Master mode not implemented, needs handling of clocks. */
 142                return -EINVAL;
 143        }
 144
 145        strcr |= SSI_STCR_TFEN0;
 146
 147        if (ssi->flags & IMX_SSI_NET)
 148                scr |= SSI_SCR_NET;
 149        if (ssi->flags & IMX_SSI_SYN)
 150                scr |= SSI_SCR_SYN;
 151
 152        writel(strcr, ssi->base + SSI_STCR);
 153        writel(strcr, ssi->base + SSI_SRCR);
 154        writel(scr, ssi->base + SSI_SCR);
 155
 156        return 0;
 157}
 158
 159/*
 160 * SSI system clock configuration.
 161 * Should only be called when port is inactive (i.e. SSIEN = 0).
 162 */
 163static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
 164                                  int clk_id, unsigned int freq, int dir)
 165{
 166        struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
 167        u32 scr;
 168
 169        scr = readl(ssi->base + SSI_SCR);
 170
 171        switch (clk_id) {
 172        case IMX_SSP_SYS_CLK:
 173                if (dir == SND_SOC_CLOCK_OUT)
 174                        scr |= SSI_SCR_SYS_CLK_EN;
 175                else
 176                        scr &= ~SSI_SCR_SYS_CLK_EN;
 177                break;
 178        default:
 179                return -EINVAL;
 180        }
 181
 182        writel(scr, ssi->base + SSI_SCR);
 183
 184        return 0;
 185}
 186
 187/*
 188 * SSI Clock dividers
 189 * Should only be called when port is inactive (i.e. SSIEN = 0).
 190 */
 191static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
 192                                  int div_id, int div)
 193{
 194        struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
 195        u32 stccr, srccr;
 196
 197        stccr = readl(ssi->base + SSI_STCCR);
 198        srccr = readl(ssi->base + SSI_SRCCR);
 199
 200        switch (div_id) {
 201        case IMX_SSI_TX_DIV_2:
 202                stccr &= ~SSI_STCCR_DIV2;
 203                stccr |= div;
 204                break;
 205        case IMX_SSI_TX_DIV_PSR:
 206                stccr &= ~SSI_STCCR_PSR;
 207                stccr |= div;
 208                break;
 209        case IMX_SSI_TX_DIV_PM:
 210                stccr &= ~0xff;
 211                stccr |= SSI_STCCR_PM(div);
 212                break;
 213        case IMX_SSI_RX_DIV_2:
 214                stccr &= ~SSI_STCCR_DIV2;
 215                stccr |= div;
 216                break;
 217        case IMX_SSI_RX_DIV_PSR:
 218                stccr &= ~SSI_STCCR_PSR;
 219                stccr |= div;
 220                break;
 221        case IMX_SSI_RX_DIV_PM:
 222                stccr &= ~0xff;
 223                stccr |= SSI_STCCR_PM(div);
 224                break;
 225        default:
 226                return -EINVAL;
 227        }
 228
 229        writel(stccr, ssi->base + SSI_STCCR);
 230        writel(srccr, ssi->base + SSI_SRCCR);
 231
 232        return 0;
 233}
 234
 235/*
 236 * Should only be called when port is inactive (i.e. SSIEN = 0),
 237 * although can be called multiple times by upper layers.
 238 */
 239static int imx_ssi_hw_params(struct snd_pcm_substream *substream,
 240                             struct snd_pcm_hw_params *params,
 241                             struct snd_soc_dai *cpu_dai)
 242{
 243        struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
 244        u32 reg, sccr;
 245
 246        /* Tx/Rx config */
 247        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 248                reg = SSI_STCCR;
 249        else
 250                reg = SSI_SRCCR;
 251
 252        if (ssi->flags & IMX_SSI_SYN)
 253                reg = SSI_STCCR;
 254
 255        sccr = readl(ssi->base + reg) & ~SSI_STCCR_WL_MASK;
 256
 257        /* DAI data (word) size */
 258        switch (params_format(params)) {
 259        case SNDRV_PCM_FORMAT_S16_LE:
 260                sccr |= SSI_SRCCR_WL(16);
 261                break;
 262        case SNDRV_PCM_FORMAT_S20_3LE:
 263                sccr |= SSI_SRCCR_WL(20);
 264                break;
 265        case SNDRV_PCM_FORMAT_S24_LE:
 266                sccr |= SSI_SRCCR_WL(24);
 267                break;
 268        }
 269
 270        writel(sccr, ssi->base + reg);
 271
 272        return 0;
 273}
 274
 275static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
 276                struct snd_soc_dai *dai)
 277{
 278        struct imx_ssi *ssi = snd_soc_dai_get_drvdata(dai);
 279        unsigned int sier_bits, sier;
 280        unsigned int scr;
 281
 282        scr = readl(ssi->base + SSI_SCR);
 283        sier = readl(ssi->base + SSI_SIER);
 284
 285        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 286                if (ssi->flags & IMX_SSI_DMA)
 287                        sier_bits = SSI_SIER_TDMAE;
 288                else
 289                        sier_bits = SSI_SIER_TIE | SSI_SIER_TFE0_EN;
 290        } else {
 291                if (ssi->flags & IMX_SSI_DMA)
 292                        sier_bits = SSI_SIER_RDMAE;
 293                else
 294                        sier_bits = SSI_SIER_RIE | SSI_SIER_RFF0_EN;
 295        }
 296
 297        switch (cmd) {
 298        case SNDRV_PCM_TRIGGER_START:
 299        case SNDRV_PCM_TRIGGER_RESUME:
 300        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 301                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 302                        scr |= SSI_SCR_TE;
 303                else
 304                        scr |= SSI_SCR_RE;
 305                sier |= sier_bits;
 306
 307                if (++ssi->enabled == 1)
 308                        scr |= SSI_SCR_SSIEN;
 309
 310                break;
 311
 312        case SNDRV_PCM_TRIGGER_STOP:
 313        case SNDRV_PCM_TRIGGER_SUSPEND:
 314        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 315                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 316                        scr &= ~SSI_SCR_TE;
 317                else
 318                        scr &= ~SSI_SCR_RE;
 319                sier &= ~sier_bits;
 320
 321                if (--ssi->enabled == 0)
 322                        scr &= ~SSI_SCR_SSIEN;
 323
 324                break;
 325        default:
 326                return -EINVAL;
 327        }
 328
 329        if (!(ssi->flags & IMX_SSI_USE_AC97))
 330                /* rx/tx are always enabled to access ac97 registers */
 331                writel(scr, ssi->base + SSI_SCR);
 332
 333        writel(sier, ssi->base + SSI_SIER);
 334
 335        return 0;
 336}
 337
 338static const struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
 339        .hw_params      = imx_ssi_hw_params,
 340        .set_fmt        = imx_ssi_set_dai_fmt,
 341        .set_clkdiv     = imx_ssi_set_dai_clkdiv,
 342        .set_sysclk     = imx_ssi_set_dai_sysclk,
 343        .set_tdm_slot   = imx_ssi_set_dai_tdm_slot,
 344        .trigger        = imx_ssi_trigger,
 345};
 346
 347static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
 348{
 349        struct imx_ssi *ssi = dev_get_drvdata(dai->dev);
 350        uint32_t val;
 351
 352        snd_soc_dai_set_drvdata(dai, ssi);
 353
 354        val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.maxburst) |
 355                SSI_SFCSR_RFWM0(ssi->dma_params_rx.maxburst);
 356        writel(val, ssi->base + SSI_SFCSR);
 357
 358        /* Tx/Rx config */
 359        dai->playback_dma_data = &ssi->dma_params_tx;
 360        dai->capture_dma_data = &ssi->dma_params_rx;
 361
 362        return 0;
 363}
 364
 365static struct snd_soc_dai_driver imx_ssi_dai = {
 366        .probe = imx_ssi_dai_probe,
 367        .playback = {
 368                .channels_min = 1,
 369                .channels_max = 2,
 370                .rates = SNDRV_PCM_RATE_8000_96000,
 371                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 372        },
 373        .capture = {
 374                .channels_min = 1,
 375                .channels_max = 2,
 376                .rates = SNDRV_PCM_RATE_8000_96000,
 377                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 378        },
 379        .ops = &imx_ssi_pcm_dai_ops,
 380};
 381
 382static struct snd_soc_dai_driver imx_ac97_dai = {
 383        .probe = imx_ssi_dai_probe,
 384        .ac97_control = 1,
 385        .playback = {
 386                .stream_name = "AC97 Playback",
 387                .channels_min = 2,
 388                .channels_max = 2,
 389                .rates = SNDRV_PCM_RATE_8000_48000,
 390                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 391        },
 392        .capture = {
 393                .stream_name = "AC97 Capture",
 394                .channels_min = 2,
 395                .channels_max = 2,
 396                .rates = SNDRV_PCM_RATE_48000,
 397                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 398        },
 399        .ops = &imx_ssi_pcm_dai_ops,
 400};
 401
 402static const struct snd_soc_component_driver imx_component = {
 403        .name           = DRV_NAME,
 404};
 405
 406static void setup_channel_to_ac97(struct imx_ssi *imx_ssi)
 407{
 408        void __iomem *base = imx_ssi->base;
 409
 410        writel(0x0, base + SSI_SCR);
 411        writel(0x0, base + SSI_STCR);
 412        writel(0x0, base + SSI_SRCR);
 413
 414        writel(SSI_SCR_SYN | SSI_SCR_NET, base + SSI_SCR);
 415
 416        writel(SSI_SFCSR_RFWM0(8) |
 417                SSI_SFCSR_TFWM0(8) |
 418                SSI_SFCSR_RFWM1(8) |
 419                SSI_SFCSR_TFWM1(8), base + SSI_SFCSR);
 420
 421        writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_STCCR);
 422        writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_SRCCR);
 423
 424        writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN, base + SSI_SCR);
 425        writel(SSI_SOR_WAIT(3), base + SSI_SOR);
 426
 427        writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN |
 428                        SSI_SCR_TE | SSI_SCR_RE,
 429                        base + SSI_SCR);
 430
 431        writel(SSI_SACNT_DEFAULT, base + SSI_SACNT);
 432        writel(0xff, base + SSI_SACCDIS);
 433        writel(0x300, base + SSI_SACCEN);
 434}
 435
 436static struct imx_ssi *ac97_ssi;
 437
 438static void imx_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 439                unsigned short val)
 440{
 441        struct imx_ssi *imx_ssi = ac97_ssi;
 442        void __iomem *base = imx_ssi->base;
 443        unsigned int lreg;
 444        unsigned int lval;
 445
 446        if (reg > 0x7f)
 447                return;
 448
 449        pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val);
 450
 451        lreg = reg <<  12;
 452        writel(lreg, base + SSI_SACADD);
 453
 454        lval = val << 4;
 455        writel(lval , base + SSI_SACDAT);
 456
 457        writel(SSI_SACNT_DEFAULT | SSI_SACNT_WR, base + SSI_SACNT);
 458        udelay(100);
 459}
 460
 461static unsigned short imx_ssi_ac97_read(struct snd_ac97 *ac97,
 462                unsigned short reg)
 463{
 464        struct imx_ssi *imx_ssi = ac97_ssi;
 465        void __iomem *base = imx_ssi->base;
 466
 467        unsigned short val = -1;
 468        unsigned int lreg;
 469
 470        lreg = (reg & 0x7f) <<  12 ;
 471        writel(lreg, base + SSI_SACADD);
 472        writel(SSI_SACNT_DEFAULT | SSI_SACNT_RD, base + SSI_SACNT);
 473
 474        udelay(100);
 475
 476        val = (readl(base + SSI_SACDAT) >> 4) & 0xffff;
 477
 478        pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val);
 479
 480        return val;
 481}
 482
 483static void imx_ssi_ac97_reset(struct snd_ac97 *ac97)
 484{
 485        struct imx_ssi *imx_ssi = ac97_ssi;
 486
 487        if (imx_ssi->ac97_reset)
 488                imx_ssi->ac97_reset(ac97);
 489        /* First read sometimes fails, do a dummy read */
 490        imx_ssi_ac97_read(ac97, 0);
 491}
 492
 493static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97)
 494{
 495        struct imx_ssi *imx_ssi = ac97_ssi;
 496
 497        if (imx_ssi->ac97_warm_reset)
 498                imx_ssi->ac97_warm_reset(ac97);
 499
 500        /* First read sometimes fails, do a dummy read */
 501        imx_ssi_ac97_read(ac97, 0);
 502}
 503
 504static struct snd_ac97_bus_ops imx_ssi_ac97_ops = {
 505        .read           = imx_ssi_ac97_read,
 506        .write          = imx_ssi_ac97_write,
 507        .reset          = imx_ssi_ac97_reset,
 508        .warm_reset     = imx_ssi_ac97_warm_reset
 509};
 510
 511static int imx_ssi_probe(struct platform_device *pdev)
 512{
 513        struct resource *res;
 514        struct imx_ssi *ssi;
 515        struct imx_ssi_platform_data *pdata = pdev->dev.platform_data;
 516        int ret = 0;
 517        struct snd_soc_dai_driver *dai;
 518
 519        ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi), GFP_KERNEL);
 520        if (!ssi)
 521                return -ENOMEM;
 522        dev_set_drvdata(&pdev->dev, ssi);
 523
 524        if (pdata) {
 525                ssi->ac97_reset = pdata->ac97_reset;
 526                ssi->ac97_warm_reset = pdata->ac97_warm_reset;
 527                ssi->flags = pdata->flags;
 528        }
 529
 530        ssi->irq = platform_get_irq(pdev, 0);
 531
 532        ssi->clk = devm_clk_get(&pdev->dev, NULL);
 533        if (IS_ERR(ssi->clk)) {
 534                ret = PTR_ERR(ssi->clk);
 535                dev_err(&pdev->dev, "Cannot get the clock: %d\n",
 536                        ret);
 537                goto failed_clk;
 538        }
 539        clk_prepare_enable(ssi->clk);
 540
 541        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 542        ssi->base = devm_ioremap_resource(&pdev->dev, res);
 543        if (IS_ERR(ssi->base)) {
 544                ret = PTR_ERR(ssi->base);
 545                goto failed_register;
 546        }
 547
 548        if (ssi->flags & IMX_SSI_USE_AC97) {
 549                if (ac97_ssi) {
 550                        dev_err(&pdev->dev, "AC'97 SSI already registered\n");
 551                        ret = -EBUSY;
 552                        goto failed_register;
 553                }
 554                ac97_ssi = ssi;
 555                setup_channel_to_ac97(ssi);
 556                dai = &imx_ac97_dai;
 557        } else
 558                dai = &imx_ssi_dai;
 559
 560        writel(0x0, ssi->base + SSI_SIER);
 561
 562        ssi->dma_params_rx.addr = res->start + SSI_SRX0;
 563        ssi->dma_params_tx.addr = res->start + SSI_STX0;
 564
 565        ssi->dma_params_tx.maxburst = 6;
 566        ssi->dma_params_rx.maxburst = 4;
 567
 568        ssi->dma_params_tx.filter_data = &ssi->filter_data_tx;
 569        ssi->dma_params_rx.filter_data = &ssi->filter_data_rx;
 570
 571        res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
 572        if (res) {
 573                imx_pcm_dma_params_init_data(&ssi->filter_data_tx, res->start,
 574                        false);
 575        }
 576
 577        res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0");
 578        if (res) {
 579                imx_pcm_dma_params_init_data(&ssi->filter_data_rx, res->start,
 580                        false);
 581        }
 582
 583        platform_set_drvdata(pdev, ssi);
 584
 585        ret = snd_soc_set_ac97_ops(&imx_ssi_ac97_ops);
 586        if (ret != 0) {
 587                dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
 588                goto failed_register;
 589        }
 590
 591        ret = snd_soc_register_component(&pdev->dev, &imx_component,
 592                                         dai, 1);
 593        if (ret) {
 594                dev_err(&pdev->dev, "register DAI failed\n");
 595                goto failed_register;
 596        }
 597
 598        ret = imx_pcm_fiq_init(pdev);
 599        if (ret)
 600                goto failed_pcm_fiq;
 601
 602        ret = imx_pcm_dma_init(pdev);
 603        if (ret)
 604                goto failed_pcm_dma;
 605
 606        return 0;
 607
 608failed_pcm_dma:
 609        imx_pcm_fiq_exit(pdev);
 610failed_pcm_fiq:
 611        snd_soc_unregister_component(&pdev->dev);
 612failed_register:
 613        release_mem_region(res->start, resource_size(res));
 614        clk_disable_unprepare(ssi->clk);
 615failed_clk:
 616        snd_soc_set_ac97_ops(NULL);
 617
 618        return ret;
 619}
 620
 621static int imx_ssi_remove(struct platform_device *pdev)
 622{
 623        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 624        struct imx_ssi *ssi = platform_get_drvdata(pdev);
 625
 626        imx_pcm_dma_exit(pdev);
 627        imx_pcm_fiq_exit(pdev);
 628
 629        snd_soc_unregister_component(&pdev->dev);
 630
 631        if (ssi->flags & IMX_SSI_USE_AC97)
 632                ac97_ssi = NULL;
 633
 634        release_mem_region(res->start, resource_size(res));
 635        clk_disable_unprepare(ssi->clk);
 636        snd_soc_set_ac97_ops(NULL);
 637
 638        return 0;
 639}
 640
 641static struct platform_driver imx_ssi_driver = {
 642        .probe = imx_ssi_probe,
 643        .remove = imx_ssi_remove,
 644
 645        .driver = {
 646                .name = "imx-ssi",
 647                .owner = THIS_MODULE,
 648        },
 649};
 650
 651module_platform_driver(imx_ssi_driver);
 652
 653/* Module information */
 654MODULE_AUTHOR("Sascha Hauer, <s.hauer@pengutronix.de>");
 655MODULE_DESCRIPTION("i.MX I2S/ac97 SoC Interface");
 656MODULE_LICENSE("GPL");
 657MODULE_ALIAS("platform:imx-ssi");
 658