linux/sound/soc/imx/mxc-ssi.c
<<
>>
Prefs
   1/*
   2 * mxc-ssi.c  --  SSI driver for Freescale IMX
   3 *
   4 * Copyright 2006 Wolfson Microelectronics PLC.
   5 * Author: Liam Girdwood
   6 *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
   7 *
   8 *  Based on mxc-alsa-mc13783 (C) 2006 Freescale.
   9 *
  10 *  This program is free software; you can redistribute  it and/or modify it
  11 *  under  the terms of  the GNU General  Public License as published by the
  12 *  Free Software Foundation;  either version 2 of the  License, or (at your
  13 *  option) any later version.
  14 *
  15 * TODO:
  16 *   Need to rework SSI register defs when new defs go into mainline.
  17 *   Add support for TDM and FIFO 1.
  18 *   Add support for i.mx3x DMA interface.
  19 *
  20 */
  21
  22
  23#include <linux/module.h>
  24#include <linux/init.h>
  25#include <linux/platform_device.h>
  26#include <linux/slab.h>
  27#include <linux/dma-mapping.h>
  28#include <linux/clk.h>
  29#include <sound/core.h>
  30#include <sound/pcm.h>
  31#include <sound/pcm_params.h>
  32#include <sound/soc.h>
  33#include <mach/dma-mx1-mx2.h>
  34#include <asm/mach-types.h>
  35
  36#include "mxc-ssi.h"
  37#include "mx1_mx2-pcm.h"
  38
  39#define SSI1_PORT       0
  40#define SSI2_PORT       1
  41
  42static int ssi_active[2] = {0, 0};
  43
  44/* DMA information for mx1_mx2 platforms */
  45static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_out0 = {
  46        .name                   = "SSI1 PCM Stereo out 0",
  47        .transfer_type = DMA_MODE_WRITE,
  48        .per_address = SSI1_BASE_ADDR + STX0,
  49        .event_id = DMA_REQ_SSI1_TX0,
  50        .watermark_level = TXFIFO_WATERMARK,
  51        .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
  52        .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
  53};
  54
  55static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_out1 = {
  56        .name                   = "SSI1 PCM Stereo out 1",
  57        .transfer_type = DMA_MODE_WRITE,
  58        .per_address = SSI1_BASE_ADDR + STX1,
  59        .event_id = DMA_REQ_SSI1_TX1,
  60        .watermark_level = TXFIFO_WATERMARK,
  61        .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
  62        .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
  63};
  64
  65static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_in0 = {
  66        .name                   = "SSI1 PCM Stereo in 0",
  67        .transfer_type = DMA_MODE_READ,
  68        .per_address = SSI1_BASE_ADDR + SRX0,
  69        .event_id = DMA_REQ_SSI1_RX0,
  70        .watermark_level = RXFIFO_WATERMARK,
  71        .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
  72        .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
  73};
  74
  75static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_in1 = {
  76        .name                   = "SSI1 PCM Stereo in 1",
  77        .transfer_type = DMA_MODE_READ,
  78        .per_address = SSI1_BASE_ADDR + SRX1,
  79        .event_id = DMA_REQ_SSI1_RX1,
  80        .watermark_level = RXFIFO_WATERMARK,
  81        .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
  82        .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
  83};
  84
  85static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_out0 = {
  86        .name                   = "SSI2 PCM Stereo out 0",
  87        .transfer_type = DMA_MODE_WRITE,
  88        .per_address = SSI2_BASE_ADDR + STX0,
  89        .event_id = DMA_REQ_SSI2_TX0,
  90        .watermark_level = TXFIFO_WATERMARK,
  91        .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
  92        .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
  93};
  94
  95static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_out1 = {
  96        .name                   = "SSI2 PCM Stereo out 1",
  97        .transfer_type = DMA_MODE_WRITE,
  98        .per_address = SSI2_BASE_ADDR + STX1,
  99        .event_id = DMA_REQ_SSI2_TX1,
 100        .watermark_level = TXFIFO_WATERMARK,
 101        .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
 102        .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
 103};
 104
 105static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_in0 = {
 106        .name                   = "SSI2 PCM Stereo in 0",
 107        .transfer_type = DMA_MODE_READ,
 108        .per_address = SSI2_BASE_ADDR + SRX0,
 109        .event_id = DMA_REQ_SSI2_RX0,
 110        .watermark_level = RXFIFO_WATERMARK,
 111        .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
 112        .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
 113};
 114
 115static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_in1 = {
 116        .name                   = "SSI2 PCM Stereo in 1",
 117        .transfer_type = DMA_MODE_READ,
 118        .per_address = SSI2_BASE_ADDR + SRX1,
 119        .event_id = DMA_REQ_SSI2_RX1,
 120        .watermark_level = RXFIFO_WATERMARK,
 121        .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
 122        .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
 123};
 124
 125static struct clk *ssi_clk0, *ssi_clk1;
 126
 127int get_ssi_clk(int ssi, struct device *dev)
 128{
 129        switch (ssi) {
 130        case 0:
 131                ssi_clk0 = clk_get(dev, "ssi1");
 132                if (IS_ERR(ssi_clk0))
 133                        return PTR_ERR(ssi_clk0);
 134                return 0;
 135        case 1:
 136                ssi_clk1 = clk_get(dev, "ssi2");
 137                if (IS_ERR(ssi_clk1))
 138                        return PTR_ERR(ssi_clk1);
 139                return 0;
 140        default:
 141                return -EINVAL;
 142        }
 143}
 144EXPORT_SYMBOL(get_ssi_clk);
 145
 146void put_ssi_clk(int ssi)
 147{
 148        switch (ssi) {
 149        case 0:
 150                clk_put(ssi_clk0);
 151                ssi_clk0 = NULL;
 152                break;
 153        case 1:
 154                clk_put(ssi_clk1);
 155                ssi_clk1 = NULL;
 156                break;
 157        }
 158}
 159EXPORT_SYMBOL(put_ssi_clk);
 160
 161/*
 162 * SSI system clock configuration.
 163 * Should only be called when port is inactive (i.e. SSIEN = 0).
 164 */
 165static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
 166        int clk_id, unsigned int freq, int dir)
 167{
 168        u32 scr;
 169
 170        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 171                scr = SSI1_SCR;
 172                pr_debug("%s: SCR for SSI1 is %x\n", __func__, scr);
 173        } else {
 174                scr = SSI2_SCR;
 175                pr_debug("%s: SCR for SSI2 is %x\n", __func__, scr);
 176        }
 177
 178        if (scr & SSI_SCR_SSIEN) {
 179                printk(KERN_WARNING "Warning ssi already enabled\n");
 180                return 0;
 181        }
 182
 183        switch (clk_id) {
 184        case IMX_SSP_SYS_CLK:
 185                if (dir == SND_SOC_CLOCK_OUT) {
 186                        scr |= SSI_SCR_SYS_CLK_EN;
 187                        pr_debug("%s: clk of is output\n", __func__);
 188                } else {
 189                        scr &= ~SSI_SCR_SYS_CLK_EN;
 190                        pr_debug("%s: clk of is input\n", __func__);
 191                }
 192                break;
 193        default:
 194                return -EINVAL;
 195        }
 196
 197        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 198                pr_debug("%s: writeback of SSI1_SCR\n", __func__);
 199                SSI1_SCR = scr;
 200        } else {
 201                pr_debug("%s: writeback of SSI2_SCR\n", __func__);
 202                SSI2_SCR = scr;
 203        }
 204
 205        return 0;
 206}
 207
 208/*
 209 * SSI Clock dividers
 210 * Should only be called when port is inactive (i.e. SSIEN = 0).
 211 */
 212static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
 213        int div_id, int div)
 214{
 215        u32 stccr, srccr;
 216
 217        pr_debug("%s\n", __func__);
 218        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 219                if (SSI1_SCR & SSI_SCR_SSIEN)
 220                        return 0;
 221                srccr = SSI1_STCCR;
 222                stccr = SSI1_STCCR;
 223        } else {
 224                if (SSI2_SCR & SSI_SCR_SSIEN)
 225                        return 0;
 226                srccr = SSI2_STCCR;
 227                stccr = SSI2_STCCR;
 228        }
 229
 230        switch (div_id) {
 231        case IMX_SSI_TX_DIV_2:
 232                stccr &= ~SSI_STCCR_DIV2;
 233                stccr |= div;
 234                break;
 235        case IMX_SSI_TX_DIV_PSR:
 236                stccr &= ~SSI_STCCR_PSR;
 237                stccr |= div;
 238                break;
 239        case IMX_SSI_TX_DIV_PM:
 240                stccr &= ~0xff;
 241                stccr |= SSI_STCCR_PM(div);
 242                break;
 243        case IMX_SSI_RX_DIV_2:
 244                stccr &= ~SSI_STCCR_DIV2;
 245                stccr |= div;
 246                break;
 247        case IMX_SSI_RX_DIV_PSR:
 248                stccr &= ~SSI_STCCR_PSR;
 249                stccr |= div;
 250                break;
 251        case IMX_SSI_RX_DIV_PM:
 252                stccr &= ~0xff;
 253                stccr |= SSI_STCCR_PM(div);
 254                break;
 255        default:
 256                return -EINVAL;
 257        }
 258
 259        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 260                SSI1_STCCR = stccr;
 261                SSI1_SRCCR = srccr;
 262        } else {
 263                SSI2_STCCR = stccr;
 264                SSI2_SRCCR = srccr;
 265        }
 266        return 0;
 267}
 268
 269/*
 270 * SSI Network Mode or TDM slots configuration.
 271 * Should only be called when port is inactive (i.e. SSIEN = 0).
 272 */
 273static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 274        unsigned int mask, int slots)
 275{
 276        u32 stmsk, srmsk, stccr;
 277
 278        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 279                if (SSI1_SCR & SSI_SCR_SSIEN) {
 280                        printk(KERN_WARNING "Warning ssi already enabled\n");
 281                        return 0;
 282                }
 283                stccr = SSI1_STCCR;
 284        } else {
 285                if (SSI2_SCR & SSI_SCR_SSIEN) {
 286                        printk(KERN_WARNING "Warning ssi already enabled\n");
 287                        return 0;
 288                }
 289                stccr = SSI2_STCCR;
 290        }
 291
 292        stmsk = srmsk = mask;
 293        stccr &= ~SSI_STCCR_DC_MASK;
 294        stccr |= SSI_STCCR_DC(slots - 1);
 295
 296        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 297                SSI1_STMSK = stmsk;
 298                SSI1_SRMSK = srmsk;
 299                SSI1_SRCCR = SSI1_STCCR = stccr;
 300        } else {
 301                SSI2_STMSK = stmsk;
 302                SSI2_SRMSK = srmsk;
 303                SSI2_SRCCR = SSI2_STCCR = stccr;
 304        }
 305
 306        return 0;
 307}
 308
 309/*
 310 * SSI DAI format configuration.
 311 * Should only be called when port is inactive (i.e. SSIEN = 0).
 312 * Note: We don't use the I2S modes but instead manually configure the
 313 * SSI for I2S.
 314 */
 315static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 316                unsigned int fmt)
 317{
 318        u32 stcr = 0, srcr = 0, scr;
 319
 320        /*
 321         * This is done to avoid this function to modify
 322         * previous set values in stcr
 323         */
 324        stcr = SSI1_STCR;
 325
 326        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2)
 327                scr = SSI1_SCR & ~(SSI_SCR_SYN | SSI_SCR_NET);
 328        else
 329                scr = SSI2_SCR & ~(SSI_SCR_SYN | SSI_SCR_NET);
 330
 331        if (scr & SSI_SCR_SSIEN) {
 332                printk(KERN_WARNING "Warning ssi already enabled\n");
 333                return 0;
 334        }
 335
 336        /* DAI mode */
 337        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 338        case SND_SOC_DAIFMT_I2S:
 339                /* data on rising edge of bclk, frame low 1clk before data */
 340                stcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0;
 341                srcr |= SSI_SRCR_RFSI | SSI_SRCR_REFS | SSI_SRCR_RXBIT0;
 342                break;
 343        case SND_SOC_DAIFMT_LEFT_J:
 344                /* data on rising edge of bclk, frame high with data */
 345                stcr |= SSI_STCR_TXBIT0;
 346                srcr |= SSI_SRCR_RXBIT0;
 347                break;
 348        case SND_SOC_DAIFMT_DSP_B:
 349                /* data on rising edge of bclk, frame high with data */
 350                stcr |= SSI_STCR_TFSL;
 351                srcr |= SSI_SRCR_RFSL;
 352                break;
 353        case SND_SOC_DAIFMT_DSP_A:
 354                /* data on rising edge of bclk, frame high 1clk before data */
 355                stcr |= SSI_STCR_TFSL | SSI_STCR_TEFS;
 356                srcr |= SSI_SRCR_RFSL | SSI_SRCR_REFS;
 357                break;
 358        }
 359
 360        /* DAI clock inversion */
 361        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 362        case SND_SOC_DAIFMT_IB_IF:
 363                stcr |= SSI_STCR_TFSI;
 364                stcr &= ~SSI_STCR_TSCKP;
 365                srcr |= SSI_SRCR_RFSI;
 366                srcr &= ~SSI_SRCR_RSCKP;
 367                break;
 368        case SND_SOC_DAIFMT_IB_NF:
 369                stcr &= ~(SSI_STCR_TSCKP | SSI_STCR_TFSI);
 370                srcr &= ~(SSI_SRCR_RSCKP | SSI_SRCR_RFSI);
 371                break;
 372        case SND_SOC_DAIFMT_NB_IF:
 373                stcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP;
 374                srcr |= SSI_SRCR_RFSI | SSI_SRCR_RSCKP;
 375                break;
 376        case SND_SOC_DAIFMT_NB_NF:
 377                stcr &= ~SSI_STCR_TFSI;
 378                stcr |= SSI_STCR_TSCKP;
 379                srcr &= ~SSI_SRCR_RFSI;
 380                srcr |= SSI_SRCR_RSCKP;
 381                break;
 382        }
 383
 384        /* DAI clock master masks */
 385        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 386        case SND_SOC_DAIFMT_CBS_CFS:
 387                stcr |= SSI_STCR_TFDIR | SSI_STCR_TXDIR;
 388                srcr |= SSI_SRCR_RFDIR | SSI_SRCR_RXDIR;
 389                break;
 390        case SND_SOC_DAIFMT_CBM_CFS:
 391                stcr |= SSI_STCR_TFDIR;
 392                srcr |= SSI_SRCR_RFDIR;
 393                break;
 394        case SND_SOC_DAIFMT_CBS_CFM:
 395                stcr |= SSI_STCR_TXDIR;
 396                srcr |= SSI_SRCR_RXDIR;
 397                break;
 398        }
 399
 400        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 401                SSI1_STCR = stcr;
 402                SSI1_SRCR = srcr;
 403                SSI1_SCR = scr;
 404        } else {
 405                SSI2_STCR = stcr;
 406                SSI2_SRCR = srcr;
 407                SSI2_SCR = scr;
 408        }
 409
 410        return 0;
 411}
 412
 413static int imx_ssi_startup(struct snd_pcm_substream *substream,
 414                        struct snd_soc_dai *dai)
 415{
 416        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 417        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 418
 419        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 420                /* set up TX DMA params */
 421                switch (cpu_dai->id) {
 422                case IMX_DAI_SSI0:
 423                        cpu_dai->dma_data = &imx_ssi1_pcm_stereo_out0;
 424                        break;
 425                case IMX_DAI_SSI1:
 426                        cpu_dai->dma_data = &imx_ssi1_pcm_stereo_out1;
 427                        break;
 428                case IMX_DAI_SSI2:
 429                        cpu_dai->dma_data = &imx_ssi2_pcm_stereo_out0;
 430                        break;
 431                case IMX_DAI_SSI3:
 432                        cpu_dai->dma_data = &imx_ssi2_pcm_stereo_out1;
 433                }
 434                pr_debug("%s: (playback)\n", __func__);
 435        } else {
 436                /* set up RX DMA params */
 437                switch (cpu_dai->id) {
 438                case IMX_DAI_SSI0:
 439                        cpu_dai->dma_data = &imx_ssi1_pcm_stereo_in0;
 440                        break;
 441                case IMX_DAI_SSI1:
 442                        cpu_dai->dma_data = &imx_ssi1_pcm_stereo_in1;
 443                        break;
 444                case IMX_DAI_SSI2:
 445                        cpu_dai->dma_data = &imx_ssi2_pcm_stereo_in0;
 446                        break;
 447                case IMX_DAI_SSI3:
 448                        cpu_dai->dma_data = &imx_ssi2_pcm_stereo_in1;
 449                }
 450                pr_debug("%s: (capture)\n", __func__);
 451        }
 452
 453        /*
 454         * we cant really change any SSI values after SSI is enabled
 455         * need to fix in software for max flexibility - lrg
 456         */
 457        if (cpu_dai->active) {
 458                printk(KERN_WARNING "Warning ssi already enabled\n");
 459                return 0;
 460        }
 461
 462        /* reset the SSI port - Sect 45.4.4 */
 463        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 464
 465                if (!ssi_clk0)
 466                        return -EINVAL;
 467
 468                if (ssi_active[SSI1_PORT]++) {
 469                        pr_debug("%s: exit before reset\n", __func__);
 470                        return 0;
 471                }
 472
 473                /* SSI1 Reset */
 474                SSI1_SCR = 0;
 475
 476                SSI1_SFCSR = SSI_SFCSR_RFWM1(RXFIFO_WATERMARK) |
 477                        SSI_SFCSR_RFWM0(RXFIFO_WATERMARK) |
 478                        SSI_SFCSR_TFWM1(TXFIFO_WATERMARK) |
 479                        SSI_SFCSR_TFWM0(TXFIFO_WATERMARK);
 480        } else {
 481
 482                if (!ssi_clk1)
 483                        return -EINVAL;
 484
 485                if (ssi_active[SSI2_PORT]++) {
 486                        pr_debug("%s: exit before reset\n", __func__);
 487                        return 0;
 488                }
 489
 490                /* SSI2 Reset */
 491                SSI2_SCR = 0;
 492
 493                SSI2_SFCSR = SSI_SFCSR_RFWM1(RXFIFO_WATERMARK) |
 494                        SSI_SFCSR_RFWM0(RXFIFO_WATERMARK) |
 495                        SSI_SFCSR_TFWM1(TXFIFO_WATERMARK) |
 496                        SSI_SFCSR_TFWM0(TXFIFO_WATERMARK);
 497        }
 498
 499        return 0;
 500}
 501
 502int imx_ssi_hw_tx_params(struct snd_pcm_substream *substream,
 503                                struct snd_pcm_hw_params *params)
 504{
 505        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 506        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 507        u32 stccr, stcr, sier;
 508
 509        pr_debug("%s\n", __func__);
 510
 511        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 512                stccr = SSI1_STCCR & ~SSI_STCCR_WL_MASK;
 513                stcr = SSI1_STCR;
 514                sier = SSI1_SIER;
 515        } else {
 516                stccr = SSI2_STCCR & ~SSI_STCCR_WL_MASK;
 517                stcr = SSI2_STCR;
 518                sier = SSI2_SIER;
 519        }
 520
 521        /* DAI data (word) size */
 522        switch (params_format(params)) {
 523        case SNDRV_PCM_FORMAT_S16_LE:
 524                stccr |= SSI_STCCR_WL(16);
 525                break;
 526        case SNDRV_PCM_FORMAT_S20_3LE:
 527                stccr |= SSI_STCCR_WL(20);
 528                break;
 529        case SNDRV_PCM_FORMAT_S24_LE:
 530                stccr |= SSI_STCCR_WL(24);
 531                break;
 532        }
 533
 534        /* enable interrupts */
 535        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2)
 536                stcr |= SSI_STCR_TFEN0;
 537        else
 538                stcr |= SSI_STCR_TFEN1;
 539        sier |= SSI_SIER_TDMAE;
 540
 541        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 542                SSI1_STCR = stcr;
 543                SSI1_STCCR = stccr;
 544                SSI1_SIER = sier;
 545        } else {
 546                SSI2_STCR = stcr;
 547                SSI2_STCCR = stccr;
 548                SSI2_SIER = sier;
 549        }
 550
 551        return 0;
 552}
 553
 554int imx_ssi_hw_rx_params(struct snd_pcm_substream *substream,
 555                                struct snd_pcm_hw_params *params)
 556{
 557        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 558        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 559        u32 srccr, srcr, sier;
 560
 561        pr_debug("%s\n", __func__);
 562
 563        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 564                srccr = SSI1_SRCCR & ~SSI_SRCCR_WL_MASK;
 565                srcr = SSI1_SRCR;
 566                sier = SSI1_SIER;
 567        } else {
 568                srccr = SSI2_SRCCR & ~SSI_SRCCR_WL_MASK;
 569                srcr = SSI2_SRCR;
 570                sier = SSI2_SIER;
 571        }
 572
 573        /* DAI data (word) size */
 574        switch (params_format(params)) {
 575        case SNDRV_PCM_FORMAT_S16_LE:
 576                srccr |= SSI_SRCCR_WL(16);
 577                break;
 578        case SNDRV_PCM_FORMAT_S20_3LE:
 579                srccr |= SSI_SRCCR_WL(20);
 580                break;
 581        case SNDRV_PCM_FORMAT_S24_LE:
 582                srccr |= SSI_SRCCR_WL(24);
 583                break;
 584        }
 585
 586        /* enable interrupts */
 587        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2)
 588                srcr |= SSI_SRCR_RFEN0;
 589        else
 590                srcr |= SSI_SRCR_RFEN1;
 591        sier |= SSI_SIER_RDMAE;
 592
 593        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 594                SSI1_SRCR = srcr;
 595                SSI1_SRCCR = srccr;
 596                SSI1_SIER = sier;
 597        } else {
 598                SSI2_SRCR = srcr;
 599                SSI2_SRCCR = srccr;
 600                SSI2_SIER = sier;
 601        }
 602
 603        return 0;
 604}
 605
 606/*
 607 * Should only be called when port is inactive (i.e. SSIEN = 0),
 608 * although can be called multiple times by upper layers.
 609 */
 610int imx_ssi_hw_params(struct snd_pcm_substream *substream,
 611                                struct snd_pcm_hw_params *params,
 612                                struct snd_soc_dai *dai)
 613{
 614        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 615        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 616
 617        int ret;
 618
 619        /* cant change any parameters when SSI is running */
 620        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 621                if (SSI1_SCR & SSI_SCR_SSIEN) {
 622                        printk(KERN_WARNING "Warning ssi already enabled\n");
 623                        return 0;
 624                }
 625        } else {
 626                if (SSI2_SCR & SSI_SCR_SSIEN) {
 627                        printk(KERN_WARNING "Warning ssi already enabled\n");
 628                        return 0;
 629                }
 630        }
 631
 632        /*
 633         * Configure both tx and rx params with the same settings. This is
 634         * really a harware restriction because SSI must be disabled until
 635         * we can change those values. If there is an active audio stream in
 636         * one direction, enabling the other direction with different
 637         * settings would mean disturbing the running one.
 638         */
 639        ret = imx_ssi_hw_tx_params(substream, params);
 640        if (ret < 0)
 641                return ret;
 642        return imx_ssi_hw_rx_params(substream, params);
 643}
 644
 645int imx_ssi_prepare(struct snd_pcm_substream *substream,
 646                        struct snd_soc_dai *dai)
 647{
 648        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 649        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 650        int ret;
 651
 652        pr_debug("%s\n", __func__);
 653
 654        /* Enable clks here to follow SSI recommended init sequence */
 655        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 656                ret = clk_enable(ssi_clk0);
 657                if (ret < 0)
 658                        printk(KERN_ERR "Unable to enable ssi_clk0\n");
 659        } else {
 660                ret = clk_enable(ssi_clk1);
 661                if (ret < 0)
 662                        printk(KERN_ERR "Unable to enable ssi_clk1\n");
 663        }
 664
 665        return 0;
 666}
 667
 668static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
 669                        struct snd_soc_dai *dai)
 670{
 671        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 672        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 673        u32 scr;
 674
 675        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2)
 676                scr = SSI1_SCR;
 677        else
 678                scr = SSI2_SCR;
 679
 680        switch (cmd) {
 681        case SNDRV_PCM_TRIGGER_START:
 682        case SNDRV_PCM_TRIGGER_RESUME:
 683        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 684                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 685                        scr |= SSI_SCR_TE | SSI_SCR_SSIEN;
 686                else
 687                        scr |= SSI_SCR_RE | SSI_SCR_SSIEN;
 688                break;
 689        case SNDRV_PCM_TRIGGER_SUSPEND:
 690        case SNDRV_PCM_TRIGGER_STOP:
 691        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 692                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 693                        scr &= ~SSI_SCR_TE;
 694                else
 695                        scr &= ~SSI_SCR_RE;
 696                break;
 697        default:
 698                return -EINVAL;
 699        }
 700
 701        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2)
 702                SSI1_SCR = scr;
 703        else
 704                SSI2_SCR = scr;
 705
 706        return 0;
 707}
 708
 709static void imx_ssi_shutdown(struct snd_pcm_substream *substream,
 710                        struct snd_soc_dai *dai)
 711{
 712        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 713        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 714
 715        /* shutdown SSI if neither Tx or Rx is active */
 716        if (!cpu_dai->active) {
 717
 718                if (cpu_dai->id == IMX_DAI_SSI0 ||
 719                        cpu_dai->id == IMX_DAI_SSI2) {
 720
 721                        if (--ssi_active[SSI1_PORT] > 1)
 722                                return;
 723
 724                        SSI1_SCR = 0;
 725                        clk_disable(ssi_clk0);
 726                } else {
 727                        if (--ssi_active[SSI2_PORT])
 728                                return;
 729                        SSI2_SCR = 0;
 730                        clk_disable(ssi_clk1);
 731                }
 732        }
 733}
 734
 735#ifdef CONFIG_PM
 736static int imx_ssi_suspend(struct platform_device *dev,
 737        struct snd_soc_dai *dai)
 738{
 739        return 0;
 740}
 741
 742static int imx_ssi_resume(struct platform_device *pdev,
 743        struct snd_soc_dai *dai)
 744{
 745        return 0;
 746}
 747
 748#else
 749#define imx_ssi_suspend NULL
 750#define imx_ssi_resume  NULL
 751#endif
 752
 753#define IMX_SSI_RATES \
 754        (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \
 755        SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
 756        SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
 757        SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \
 758        SNDRV_PCM_RATE_96000)
 759
 760#define IMX_SSI_BITS \
 761        (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 762        SNDRV_PCM_FMTBIT_S24_LE)
 763
 764static struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
 765        .startup = imx_ssi_startup,
 766        .shutdown = imx_ssi_shutdown,
 767        .trigger = imx_ssi_trigger,
 768        .prepare = imx_ssi_prepare,
 769        .hw_params = imx_ssi_hw_params,
 770        .set_sysclk = imx_ssi_set_dai_sysclk,
 771        .set_clkdiv = imx_ssi_set_dai_clkdiv,
 772        .set_fmt = imx_ssi_set_dai_fmt,
 773        .set_tdm_slot = imx_ssi_set_dai_tdm_slot,
 774};
 775
 776struct snd_soc_dai imx_ssi_pcm_dai[] = {
 777{
 778        .name = "imx-i2s-1-0",
 779        .id = IMX_DAI_SSI0,
 780        .suspend = imx_ssi_suspend,
 781        .resume = imx_ssi_resume,
 782        .playback = {
 783                .channels_min = 1,
 784                .channels_max = 2,
 785                .formats = IMX_SSI_BITS,
 786                .rates = IMX_SSI_RATES,},
 787        .capture = {
 788                .channels_min = 1,
 789                .channels_max = 2,
 790                .formats = IMX_SSI_BITS,
 791                .rates = IMX_SSI_RATES,},
 792        .ops = &imx_ssi_pcm_dai_ops,
 793},
 794{
 795        .name = "imx-i2s-2-0",
 796        .id = IMX_DAI_SSI1,
 797        .playback = {
 798                .channels_min = 1,
 799                .channels_max = 2,
 800                .formats = IMX_SSI_BITS,
 801                .rates = IMX_SSI_RATES,},
 802        .capture = {
 803                .channels_min = 1,
 804                .channels_max = 2,
 805                .formats = IMX_SSI_BITS,
 806                .rates = IMX_SSI_RATES,},
 807        .ops = &imx_ssi_pcm_dai_ops,
 808},
 809{
 810        .name = "imx-i2s-1-1",
 811        .id = IMX_DAI_SSI2,
 812        .suspend = imx_ssi_suspend,
 813        .resume = imx_ssi_resume,
 814        .playback = {
 815                .channels_min = 1,
 816                .channels_max = 2,
 817                .formats = IMX_SSI_BITS,
 818                .rates = IMX_SSI_RATES,},
 819        .capture = {
 820                .channels_min = 1,
 821                .channels_max = 2,
 822                .formats = IMX_SSI_BITS,
 823                .rates = IMX_SSI_RATES,},
 824        .ops = &imx_ssi_pcm_dai_ops,
 825},
 826{
 827        .name = "imx-i2s-2-1",
 828        .id = IMX_DAI_SSI3,
 829        .playback = {
 830                .channels_min = 1,
 831                .channels_max = 2,
 832                .formats = IMX_SSI_BITS,
 833                .rates = IMX_SSI_RATES,},
 834        .capture = {
 835                .channels_min = 1,
 836                .channels_max = 2,
 837                .formats = IMX_SSI_BITS,
 838                .rates = IMX_SSI_RATES,},
 839        .ops = &imx_ssi_pcm_dai_ops,
 840},
 841};
 842EXPORT_SYMBOL_GPL(imx_ssi_pcm_dai);
 843
 844static int __init imx_ssi_init(void)
 845{
 846        return snd_soc_register_dais(imx_ssi_pcm_dai,
 847                                ARRAY_SIZE(imx_ssi_pcm_dai));
 848}
 849
 850static void __exit imx_ssi_exit(void)
 851{
 852        snd_soc_unregister_dais(imx_ssi_pcm_dai,
 853                                ARRAY_SIZE(imx_ssi_pcm_dai));
 854}
 855
 856module_init(imx_ssi_init);
 857module_exit(imx_ssi_exit);
 858MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com");
 859MODULE_DESCRIPTION("i.MX ASoC I2S driver");
 860MODULE_LICENSE("GPL");
 861