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#include "fsl_utils.h"
  54
  55#define SSI_SACNT_DEFAULT (SSI_SACNT_AC97EN | SSI_SACNT_FV)
  56
  57/*
  58 * SSI Network Mode or TDM slots configuration.
  59 * Should only be called when port is inactive (i.e. SSIEN = 0).
  60 */
  61static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
  62        unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
  63{
  64        struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
  65        u32 sccr;
  66
  67        sccr = readl(ssi->base + SSI_STCCR);
  68        sccr &= ~SSI_STCCR_DC_MASK;
  69        sccr |= SSI_STCCR_DC(slots - 1);
  70        writel(sccr, ssi->base + SSI_STCCR);
  71
  72        sccr = readl(ssi->base + SSI_SRCCR);
  73        sccr &= ~SSI_STCCR_DC_MASK;
  74        sccr |= SSI_STCCR_DC(slots - 1);
  75        writel(sccr, ssi->base + SSI_SRCCR);
  76
  77        writel(~tx_mask, ssi->base + SSI_STMSK);
  78        writel(~rx_mask, ssi->base + SSI_SRMSK);
  79
  80        return 0;
  81}
  82
  83/*
  84 * SSI DAI format configuration.
  85 * Should only be called when port is inactive (i.e. SSIEN = 0).
  86 */
  87static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
  88{
  89        struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
  90        u32 strcr = 0, scr;
  91
  92        scr = readl(ssi->base + SSI_SCR) & ~(SSI_SCR_SYN | SSI_SCR_NET);
  93
  94        /* DAI mode */
  95        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
  96        case SND_SOC_DAIFMT_I2S:
  97                /* data on rising edge of bclk, frame low 1clk before data */
  98                strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP | SSI_STCR_TFSI |
  99                        SSI_STCR_TEFS;
 100                scr |= SSI_SCR_NET;
 101                if (ssi->flags & IMX_SSI_USE_I2S_SLAVE) {
 102                        scr &= ~SSI_I2S_MODE_MASK;
 103                        scr |= SSI_SCR_I2S_MODE_SLAVE;
 104                }
 105                break;
 106        case SND_SOC_DAIFMT_LEFT_J:
 107                /* data on rising edge of bclk, frame high with data */
 108                strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP;
 109                break;
 110        case SND_SOC_DAIFMT_DSP_B:
 111                /* data on rising edge of bclk, frame high with data */
 112                strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP | SSI_STCR_TFSL;
 113                break;
 114        case SND_SOC_DAIFMT_DSP_A:
 115                /* data on rising edge of bclk, frame high 1clk before data */
 116                strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP | SSI_STCR_TFSL |
 117                        SSI_STCR_TEFS;
 118                break;
 119        }
 120
 121        /* DAI clock inversion */
 122        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 123        case SND_SOC_DAIFMT_IB_IF:
 124                strcr ^= SSI_STCR_TSCKP | SSI_STCR_TFSI;
 125                break;
 126        case SND_SOC_DAIFMT_IB_NF:
 127                strcr ^= SSI_STCR_TSCKP;
 128                break;
 129        case SND_SOC_DAIFMT_NB_IF:
 130                strcr ^= SSI_STCR_TFSI;
 131                break;
 132        case SND_SOC_DAIFMT_NB_NF:
 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                scr |= SSI_SCR_SSIEN;
 308
 309                break;
 310
 311        case SNDRV_PCM_TRIGGER_STOP:
 312        case SNDRV_PCM_TRIGGER_SUSPEND:
 313        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 314                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 315                        scr &= ~SSI_SCR_TE;
 316                else
 317                        scr &= ~SSI_SCR_RE;
 318                sier &= ~sier_bits;
 319
 320                if (!(scr & (SSI_SCR_TE | SSI_SCR_RE)))
 321                        scr &= ~SSI_SCR_SSIEN;
 322
 323                break;
 324        default:
 325                return -EINVAL;
 326        }
 327
 328        if (!(ssi->flags & IMX_SSI_USE_AC97))
 329                /* rx/tx are always enabled to access ac97 registers */
 330                writel(scr, ssi->base + SSI_SCR);
 331
 332        writel(sier, ssi->base + SSI_SIER);
 333
 334        return 0;
 335}
 336
 337static const struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
 338        .hw_params      = imx_ssi_hw_params,
 339        .set_fmt        = imx_ssi_set_dai_fmt,
 340        .set_clkdiv     = imx_ssi_set_dai_clkdiv,
 341        .set_sysclk     = imx_ssi_set_dai_sysclk,
 342        .set_tdm_slot   = imx_ssi_set_dai_tdm_slot,
 343        .trigger        = imx_ssi_trigger,
 344};
 345
 346static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
 347{
 348        struct imx_ssi *ssi = dev_get_drvdata(dai->dev);
 349        uint32_t val;
 350
 351        snd_soc_dai_set_drvdata(dai, ssi);
 352
 353        val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.maxburst) |
 354                SSI_SFCSR_RFWM0(ssi->dma_params_rx.maxburst);
 355        writel(val, ssi->base + SSI_SFCSR);
 356
 357        /* Tx/Rx config */
 358        dai->playback_dma_data = &ssi->dma_params_tx;
 359        dai->capture_dma_data = &ssi->dma_params_rx;
 360
 361        return 0;
 362}
 363
 364static struct snd_soc_dai_driver imx_ssi_dai = {
 365        .probe = imx_ssi_dai_probe,
 366        .playback = {
 367                .channels_min = 1,
 368                .channels_max = 2,
 369                .rates = SNDRV_PCM_RATE_8000_96000,
 370                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 371        },
 372        .capture = {
 373                .channels_min = 1,
 374                .channels_max = 2,
 375                .rates = SNDRV_PCM_RATE_8000_96000,
 376                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 377        },
 378        .ops = &imx_ssi_pcm_dai_ops,
 379};
 380
 381static struct snd_soc_dai_driver imx_ac97_dai = {
 382        .probe = imx_ssi_dai_probe,
 383        .bus_control = true,
 384        .playback = {
 385                .stream_name = "AC97 Playback",
 386                .channels_min = 2,
 387                .channels_max = 2,
 388                .rates = SNDRV_PCM_RATE_8000_48000,
 389                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 390        },
 391        .capture = {
 392                .stream_name = "AC97 Capture",
 393                .channels_min = 2,
 394                .channels_max = 2,
 395                .rates = SNDRV_PCM_RATE_48000,
 396                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 397        },
 398        .ops = &imx_ssi_pcm_dai_ops,
 399};
 400
 401static const struct snd_soc_component_driver imx_component = {
 402        .name           = DRV_NAME,
 403};
 404
 405static void setup_channel_to_ac97(struct imx_ssi *imx_ssi)
 406{
 407        void __iomem *base = imx_ssi->base;
 408
 409        writel(0x0, base + SSI_SCR);
 410        writel(0x0, base + SSI_STCR);
 411        writel(0x0, base + SSI_SRCR);
 412
 413        writel(SSI_SCR_SYN | SSI_SCR_NET, base + SSI_SCR);
 414
 415        writel(SSI_SFCSR_RFWM0(8) |
 416                SSI_SFCSR_TFWM0(8) |
 417                SSI_SFCSR_RFWM1(8) |
 418                SSI_SFCSR_TFWM1(8), base + SSI_SFCSR);
 419
 420        writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_STCCR);
 421        writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_SRCCR);
 422
 423        writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN, base + SSI_SCR);
 424        writel(SSI_SOR_WAIT(3), base + SSI_SOR);
 425
 426        writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN |
 427                        SSI_SCR_TE | SSI_SCR_RE,
 428                        base + SSI_SCR);
 429
 430        writel(SSI_SACNT_DEFAULT, base + SSI_SACNT);
 431        writel(0xff, base + SSI_SACCDIS);
 432        writel(0x300, base + SSI_SACCEN);
 433}
 434
 435static struct imx_ssi *ac97_ssi;
 436
 437static void imx_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 438                unsigned short val)
 439{
 440        struct imx_ssi *imx_ssi = ac97_ssi;
 441        void __iomem *base = imx_ssi->base;
 442        unsigned int lreg;
 443        unsigned int lval;
 444
 445        if (reg > 0x7f)
 446                return;
 447
 448        pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val);
 449
 450        lreg = reg <<  12;
 451        writel(lreg, base + SSI_SACADD);
 452
 453        lval = val << 4;
 454        writel(lval , base + SSI_SACDAT);
 455
 456        writel(SSI_SACNT_DEFAULT | SSI_SACNT_WR, base + SSI_SACNT);
 457        udelay(100);
 458}
 459
 460static unsigned short imx_ssi_ac97_read(struct snd_ac97 *ac97,
 461                unsigned short reg)
 462{
 463        struct imx_ssi *imx_ssi = ac97_ssi;
 464        void __iomem *base = imx_ssi->base;
 465
 466        unsigned short val = -1;
 467        unsigned int lreg;
 468
 469        lreg = (reg & 0x7f) <<  12 ;
 470        writel(lreg, base + SSI_SACADD);
 471        writel(SSI_SACNT_DEFAULT | SSI_SACNT_RD, base + SSI_SACNT);
 472
 473        udelay(100);
 474
 475        val = (readl(base + SSI_SACDAT) >> 4) & 0xffff;
 476
 477        pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val);
 478
 479        return val;
 480}
 481
 482static void imx_ssi_ac97_reset(struct snd_ac97 *ac97)
 483{
 484        struct imx_ssi *imx_ssi = ac97_ssi;
 485
 486        if (imx_ssi->ac97_reset)
 487                imx_ssi->ac97_reset(ac97);
 488        /* First read sometimes fails, do a dummy read */
 489        imx_ssi_ac97_read(ac97, 0);
 490}
 491
 492static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97)
 493{
 494        struct imx_ssi *imx_ssi = ac97_ssi;
 495
 496        if (imx_ssi->ac97_warm_reset)
 497                imx_ssi->ac97_warm_reset(ac97);
 498
 499        /* First read sometimes fails, do a dummy read */
 500        imx_ssi_ac97_read(ac97, 0);
 501}
 502
 503static struct snd_ac97_bus_ops imx_ssi_ac97_ops = {
 504        .read           = imx_ssi_ac97_read,
 505        .write          = imx_ssi_ac97_write,
 506        .reset          = imx_ssi_ac97_reset,
 507        .warm_reset     = imx_ssi_ac97_warm_reset
 508};
 509
 510static int imx_ssi_probe(struct platform_device *pdev)
 511{
 512        struct resource *res;
 513        struct imx_ssi *ssi;
 514        struct imx_ssi_platform_data *pdata = pdev->dev.platform_data;
 515        int ret = 0;
 516        struct snd_soc_dai_driver *dai;
 517
 518        ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi), GFP_KERNEL);
 519        if (!ssi)
 520                return -ENOMEM;
 521        dev_set_drvdata(&pdev->dev, ssi);
 522
 523        if (pdata) {
 524                ssi->ac97_reset = pdata->ac97_reset;
 525                ssi->ac97_warm_reset = pdata->ac97_warm_reset;
 526                ssi->flags = pdata->flags;
 527        }
 528
 529        ssi->irq = platform_get_irq(pdev, 0);
 530        if (ssi->irq < 0) {
 531                dev_err(&pdev->dev, "Failed to get IRQ: %d\n", ssi->irq);
 532                return ssi->irq;
 533        }
 534
 535        ssi->clk = devm_clk_get(&pdev->dev, NULL);
 536        if (IS_ERR(ssi->clk)) {
 537                ret = PTR_ERR(ssi->clk);
 538                dev_err(&pdev->dev, "Cannot get the clock: %d\n",
 539                        ret);
 540                goto failed_clk;
 541        }
 542        ret = clk_prepare_enable(ssi->clk);
 543        if (ret)
 544                goto failed_clk;
 545
 546        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 547        ssi->base = devm_ioremap_resource(&pdev->dev, res);
 548        if (IS_ERR(ssi->base)) {
 549                ret = PTR_ERR(ssi->base);
 550                goto failed_register;
 551        }
 552
 553        if (ssi->flags & IMX_SSI_USE_AC97) {
 554                if (ac97_ssi) {
 555                        dev_err(&pdev->dev, "AC'97 SSI already registered\n");
 556                        ret = -EBUSY;
 557                        goto failed_register;
 558                }
 559                ac97_ssi = ssi;
 560                setup_channel_to_ac97(ssi);
 561                dai = &imx_ac97_dai;
 562        } else
 563                dai = &imx_ssi_dai;
 564
 565        writel(0x0, ssi->base + SSI_SIER);
 566
 567        ssi->dma_params_rx.addr = res->start + SSI_SRX0;
 568        ssi->dma_params_tx.addr = res->start + SSI_STX0;
 569
 570        ssi->dma_params_tx.maxburst = 6;
 571        ssi->dma_params_rx.maxburst = 4;
 572
 573        ssi->dma_params_tx.filter_data = &ssi->filter_data_tx;
 574        ssi->dma_params_rx.filter_data = &ssi->filter_data_rx;
 575
 576        res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
 577        if (res) {
 578                imx_pcm_dma_params_init_data(&ssi->filter_data_tx, res->start,
 579                        IMX_DMATYPE_SSI);
 580        }
 581
 582        res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0");
 583        if (res) {
 584                imx_pcm_dma_params_init_data(&ssi->filter_data_rx, res->start,
 585                        IMX_DMATYPE_SSI);
 586        }
 587
 588        platform_set_drvdata(pdev, ssi);
 589
 590        ret = snd_soc_set_ac97_ops(&imx_ssi_ac97_ops);
 591        if (ret != 0) {
 592                dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
 593                goto failed_register;
 594        }
 595
 596        ret = snd_soc_register_component(&pdev->dev, &imx_component,
 597                                         dai, 1);
 598        if (ret) {
 599                dev_err(&pdev->dev, "register DAI failed\n");
 600                goto failed_register;
 601        }
 602
 603        ssi->fiq_params.irq = ssi->irq;
 604        ssi->fiq_params.base = ssi->base;
 605        ssi->fiq_params.dma_params_rx = &ssi->dma_params_rx;
 606        ssi->fiq_params.dma_params_tx = &ssi->dma_params_tx;
 607
 608        ssi->fiq_init = imx_pcm_fiq_init(pdev, &ssi->fiq_params);
 609        ssi->dma_init = imx_pcm_dma_init(pdev, IMX_SSI_DMABUF_SIZE);
 610
 611        if (ssi->fiq_init && ssi->dma_init) {
 612                ret = ssi->fiq_init;
 613                goto failed_pcm;
 614        }
 615
 616        return 0;
 617
 618failed_pcm:
 619        snd_soc_unregister_component(&pdev->dev);
 620failed_register:
 621        clk_disable_unprepare(ssi->clk);
 622failed_clk:
 623        snd_soc_set_ac97_ops(NULL);
 624
 625        return ret;
 626}
 627
 628static int imx_ssi_remove(struct platform_device *pdev)
 629{
 630        struct imx_ssi *ssi = platform_get_drvdata(pdev);
 631
 632        if (!ssi->fiq_init)
 633                imx_pcm_fiq_exit(pdev);
 634
 635        snd_soc_unregister_component(&pdev->dev);
 636
 637        if (ssi->flags & IMX_SSI_USE_AC97)
 638                ac97_ssi = NULL;
 639
 640        clk_disable_unprepare(ssi->clk);
 641        snd_soc_set_ac97_ops(NULL);
 642
 643        return 0;
 644}
 645
 646static struct platform_driver imx_ssi_driver = {
 647        .probe = imx_ssi_probe,
 648        .remove = imx_ssi_remove,
 649
 650        .driver = {
 651                .name = "imx-ssi",
 652        },
 653};
 654
 655module_platform_driver(imx_ssi_driver);
 656
 657/* Module information */
 658MODULE_AUTHOR("Sascha Hauer, <s.hauer@pengutronix.de>");
 659MODULE_DESCRIPTION("i.MX I2S/ac97 SoC Interface");
 660MODULE_LICENSE("GPL");
 661MODULE_ALIAS("platform:imx-ssi");
 662