linux/sound/soc/fsl/fsl_esai.c
<<
>>
Prefs
   1/*
   2 * Freescale ESAI ALSA SoC Digital Audio Interface (DAI) driver
   3 *
   4 * Copyright (C) 2014 Freescale Semiconductor, Inc.
   5 *
   6 * This file is licensed under the terms of the GNU General Public License
   7 * version 2. This program is licensed "as is" without any warranty of any
   8 * kind, whether express or implied.
   9 */
  10
  11#include <linux/clk.h>
  12#include <linux/dmaengine.h>
  13#include <linux/module.h>
  14#include <linux/of_irq.h>
  15#include <linux/of_platform.h>
  16#include <sound/dmaengine_pcm.h>
  17#include <sound/pcm_params.h>
  18
  19#include "fsl_esai.h"
  20#include "imx-pcm.h"
  21#include "fsl_utils.h"
  22
  23#define FSL_ESAI_RATES          SNDRV_PCM_RATE_8000_192000
  24#define FSL_ESAI_FORMATS        (SNDRV_PCM_FMTBIT_S8 | \
  25                                SNDRV_PCM_FMTBIT_S16_LE | \
  26                                SNDRV_PCM_FMTBIT_S20_3LE | \
  27                                SNDRV_PCM_FMTBIT_S24_LE)
  28
  29/**
  30 * fsl_esai: ESAI private data
  31 *
  32 * @dma_params_rx: DMA parameters for receive channel
  33 * @dma_params_tx: DMA parameters for transmit channel
  34 * @pdev: platform device pointer
  35 * @regmap: regmap handler
  36 * @coreclk: clock source to access register
  37 * @extalclk: esai clock source to derive HCK, SCK and FS
  38 * @fsysclk: system clock source to derive HCK, SCK and FS
  39 * @fifo_depth: depth of tx/rx FIFO
  40 * @slot_width: width of each DAI slot
  41 * @hck_rate: clock rate of desired HCKx clock
  42 * @sck_rate: clock rate of desired SCKx clock
  43 * @hck_dir: the direction of HCKx pads
  44 * @sck_div: if using PSR/PM dividers for SCKx clock
  45 * @slave_mode: if fully using DAI slave mode
  46 * @synchronous: if using tx/rx synchronous mode
  47 * @name: driver name
  48 */
  49struct fsl_esai {
  50        struct snd_dmaengine_dai_dma_data dma_params_rx;
  51        struct snd_dmaengine_dai_dma_data dma_params_tx;
  52        struct platform_device *pdev;
  53        struct regmap *regmap;
  54        struct clk *coreclk;
  55        struct clk *extalclk;
  56        struct clk *fsysclk;
  57        u32 fifo_depth;
  58        u32 slot_width;
  59        u32 hck_rate[2];
  60        u32 sck_rate[2];
  61        bool hck_dir[2];
  62        bool sck_div[2];
  63        bool slave_mode;
  64        bool synchronous;
  65        char name[32];
  66};
  67
  68static irqreturn_t esai_isr(int irq, void *devid)
  69{
  70        struct fsl_esai *esai_priv = (struct fsl_esai *)devid;
  71        struct platform_device *pdev = esai_priv->pdev;
  72        u32 esr;
  73
  74        regmap_read(esai_priv->regmap, REG_ESAI_ESR, &esr);
  75
  76        if (esr & ESAI_ESR_TINIT_MASK)
  77                dev_dbg(&pdev->dev, "isr: Transmition Initialized\n");
  78
  79        if (esr & ESAI_ESR_RFF_MASK)
  80                dev_warn(&pdev->dev, "isr: Receiving overrun\n");
  81
  82        if (esr & ESAI_ESR_TFE_MASK)
  83                dev_warn(&pdev->dev, "isr: Transmition underrun\n");
  84
  85        if (esr & ESAI_ESR_TLS_MASK)
  86                dev_dbg(&pdev->dev, "isr: Just transmitted the last slot\n");
  87
  88        if (esr & ESAI_ESR_TDE_MASK)
  89                dev_dbg(&pdev->dev, "isr: Transmition data exception\n");
  90
  91        if (esr & ESAI_ESR_TED_MASK)
  92                dev_dbg(&pdev->dev, "isr: Transmitting even slots\n");
  93
  94        if (esr & ESAI_ESR_TD_MASK)
  95                dev_dbg(&pdev->dev, "isr: Transmitting data\n");
  96
  97        if (esr & ESAI_ESR_RLS_MASK)
  98                dev_dbg(&pdev->dev, "isr: Just received the last slot\n");
  99
 100        if (esr & ESAI_ESR_RDE_MASK)
 101                dev_dbg(&pdev->dev, "isr: Receiving data exception\n");
 102
 103        if (esr & ESAI_ESR_RED_MASK)
 104                dev_dbg(&pdev->dev, "isr: Receiving even slots\n");
 105
 106        if (esr & ESAI_ESR_RD_MASK)
 107                dev_dbg(&pdev->dev, "isr: Receiving data\n");
 108
 109        return IRQ_HANDLED;
 110}
 111
 112/**
 113 * This function is used to calculate the divisors of psr, pm, fp and it is
 114 * supposed to be called in set_dai_sysclk() and set_bclk().
 115 *
 116 * @ratio: desired overall ratio for the paticipating dividers
 117 * @usefp: for HCK setting, there is no need to set fp divider
 118 * @fp: bypass other dividers by setting fp directly if fp != 0
 119 * @tx: current setting is for playback or capture
 120 */
 121static int fsl_esai_divisor_cal(struct snd_soc_dai *dai, bool tx, u32 ratio,
 122                                bool usefp, u32 fp)
 123{
 124        struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
 125        u32 psr, pm = 999, maxfp, prod, sub, savesub, i, j;
 126
 127        maxfp = usefp ? 16 : 1;
 128
 129        if (usefp && fp)
 130                goto out_fp;
 131
 132        if (ratio > 2 * 8 * 256 * maxfp || ratio < 2) {
 133                dev_err(dai->dev, "the ratio is out of range (2 ~ %d)\n",
 134                                2 * 8 * 256 * maxfp);
 135                return -EINVAL;
 136        } else if (ratio % 2) {
 137                dev_err(dai->dev, "the raio must be even if using upper divider\n");
 138                return -EINVAL;
 139        }
 140
 141        ratio /= 2;
 142
 143        psr = ratio <= 256 * maxfp ? ESAI_xCCR_xPSR_BYPASS : ESAI_xCCR_xPSR_DIV8;
 144
 145        /* Set the max fluctuation -- 0.1% of the max devisor */
 146        savesub = (psr ? 1 : 8)  * 256 * maxfp / 1000;
 147
 148        /* Find the best value for PM */
 149        for (i = 1; i <= 256; i++) {
 150                for (j = 1; j <= maxfp; j++) {
 151                        /* PSR (1 or 8) * PM (1 ~ 256) * FP (1 ~ 16) */
 152                        prod = (psr ? 1 : 8) * i * j;
 153
 154                        if (prod == ratio)
 155                                sub = 0;
 156                        else if (prod / ratio == 1)
 157                                sub = prod - ratio;
 158                        else if (ratio / prod == 1)
 159                                sub = ratio - prod;
 160                        else
 161                                continue;
 162
 163                        /* Calculate the fraction */
 164                        sub = sub * 1000 / ratio;
 165                        if (sub < savesub) {
 166                                savesub = sub;
 167                                pm = i;
 168                                fp = j;
 169                        }
 170
 171                        /* We are lucky */
 172                        if (savesub == 0)
 173                                goto out;
 174                }
 175        }
 176
 177        if (pm == 999) {
 178                dev_err(dai->dev, "failed to calculate proper divisors\n");
 179                return -EINVAL;
 180        }
 181
 182out:
 183        regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx),
 184                           ESAI_xCCR_xPSR_MASK | ESAI_xCCR_xPM_MASK,
 185                           psr | ESAI_xCCR_xPM(pm));
 186
 187out_fp:
 188        /* Bypass fp if not being required */
 189        if (maxfp <= 1)
 190                return 0;
 191
 192        regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx),
 193                           ESAI_xCCR_xFP_MASK, ESAI_xCCR_xFP(fp));
 194
 195        return 0;
 196}
 197
 198/**
 199 * This function mainly configures the clock frequency of MCLK (HCKT/HCKR)
 200 *
 201 * @Parameters:
 202 * clk_id: The clock source of HCKT/HCKR
 203 *        (Input from outside; output from inside, FSYS or EXTAL)
 204 * freq: The required clock rate of HCKT/HCKR
 205 * dir: The clock direction of HCKT/HCKR
 206 *
 207 * Note: If the direction is input, we do not care about clk_id.
 208 */
 209static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 210                                   unsigned int freq, int dir)
 211{
 212        struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
 213        struct clk *clksrc = esai_priv->extalclk;
 214        bool tx = clk_id <= ESAI_HCKT_EXTAL;
 215        bool in = dir == SND_SOC_CLOCK_IN;
 216        u32 ratio, ecr = 0;
 217        unsigned long clk_rate;
 218        int ret;
 219
 220        /* Bypass divider settings if the requirement doesn't change */
 221        if (freq == esai_priv->hck_rate[tx] && dir == esai_priv->hck_dir[tx])
 222                return 0;
 223
 224        /* sck_div can be only bypassed if ETO/ERO=0 and SNC_SOC_CLOCK_OUT */
 225        esai_priv->sck_div[tx] = true;
 226
 227        /* Set the direction of HCKT/HCKR pins */
 228        regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx),
 229                           ESAI_xCCR_xHCKD, in ? 0 : ESAI_xCCR_xHCKD);
 230
 231        if (in)
 232                goto out;
 233
 234        switch (clk_id) {
 235        case ESAI_HCKT_FSYS:
 236        case ESAI_HCKR_FSYS:
 237                clksrc = esai_priv->fsysclk;
 238                break;
 239        case ESAI_HCKT_EXTAL:
 240                ecr |= ESAI_ECR_ETI;
 241        case ESAI_HCKR_EXTAL:
 242                ecr |= ESAI_ECR_ERI;
 243                break;
 244        default:
 245                return -EINVAL;
 246        }
 247
 248        if (IS_ERR(clksrc)) {
 249                dev_err(dai->dev, "no assigned %s clock\n",
 250                                clk_id % 2 ? "extal" : "fsys");
 251                return PTR_ERR(clksrc);
 252        }
 253        clk_rate = clk_get_rate(clksrc);
 254
 255        ratio = clk_rate / freq;
 256        if (ratio * freq > clk_rate)
 257                ret = ratio * freq - clk_rate;
 258        else if (ratio * freq < clk_rate)
 259                ret = clk_rate - ratio * freq;
 260        else
 261                ret = 0;
 262
 263        /* Block if clock source can not be divided into the required rate */
 264        if (ret != 0 && clk_rate / ret < 1000) {
 265                dev_err(dai->dev, "failed to derive required HCK%c rate\n",
 266                                tx ? 'T' : 'R');
 267                return -EINVAL;
 268        }
 269
 270        /* Only EXTAL source can be output directly without using PSR and PM */
 271        if (ratio == 1 && clksrc == esai_priv->extalclk) {
 272                /* Bypass all the dividers if not being needed */
 273                ecr |= tx ? ESAI_ECR_ETO : ESAI_ECR_ERO;
 274                goto out;
 275        } else if (ratio < 2) {
 276                /* The ratio should be no less than 2 if using other sources */
 277                dev_err(dai->dev, "failed to derive required HCK%c rate\n",
 278                                tx ? 'T' : 'R');
 279                return -EINVAL;
 280        }
 281
 282        ret = fsl_esai_divisor_cal(dai, tx, ratio, false, 0);
 283        if (ret)
 284                return ret;
 285
 286        esai_priv->sck_div[tx] = false;
 287
 288out:
 289        esai_priv->hck_dir[tx] = dir;
 290        esai_priv->hck_rate[tx] = freq;
 291
 292        regmap_update_bits(esai_priv->regmap, REG_ESAI_ECR,
 293                           tx ? ESAI_ECR_ETI | ESAI_ECR_ETO :
 294                           ESAI_ECR_ERI | ESAI_ECR_ERO, ecr);
 295
 296        return 0;
 297}
 298
 299/**
 300 * This function configures the related dividers according to the bclk rate
 301 */
 302static int fsl_esai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
 303{
 304        struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
 305        u32 hck_rate = esai_priv->hck_rate[tx];
 306        u32 sub, ratio = hck_rate / freq;
 307        int ret;
 308
 309        /* Don't apply for fully slave mode or unchanged bclk */
 310        if (esai_priv->slave_mode || esai_priv->sck_rate[tx] == freq)
 311                return 0;
 312
 313        if (ratio * freq > hck_rate)
 314                sub = ratio * freq - hck_rate;
 315        else if (ratio * freq < hck_rate)
 316                sub = hck_rate - ratio * freq;
 317        else
 318                sub = 0;
 319
 320        /* Block if clock source can not be divided into the required rate */
 321        if (sub != 0 && hck_rate / sub < 1000) {
 322                dev_err(dai->dev, "failed to derive required SCK%c rate\n",
 323                                tx ? 'T' : 'R');
 324                return -EINVAL;
 325        }
 326
 327        /* The ratio should be contented by FP alone if bypassing PM and PSR */
 328        if (!esai_priv->sck_div[tx] && (ratio > 16 || ratio == 0)) {
 329                dev_err(dai->dev, "the ratio is out of range (1 ~ 16)\n");
 330                return -EINVAL;
 331        }
 332
 333        ret = fsl_esai_divisor_cal(dai, tx, ratio, true,
 334                        esai_priv->sck_div[tx] ? 0 : ratio);
 335        if (ret)
 336                return ret;
 337
 338        /* Save current bclk rate */
 339        esai_priv->sck_rate[tx] = freq;
 340
 341        return 0;
 342}
 343
 344static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,
 345                                     u32 rx_mask, int slots, int slot_width)
 346{
 347        struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
 348
 349        regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR,
 350                           ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots));
 351
 352        regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMA,
 353                           ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(tx_mask));
 354        regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMB,
 355                           ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(tx_mask));
 356
 357        regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,
 358                           ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots));
 359
 360        regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMA,
 361                           ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(rx_mask));
 362        regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMB,
 363                           ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask));
 364
 365        esai_priv->slot_width = slot_width;
 366
 367        return 0;
 368}
 369
 370static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 371{
 372        struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
 373        u32 xcr = 0, xccr = 0, mask;
 374
 375        /* DAI mode */
 376        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 377        case SND_SOC_DAIFMT_I2S:
 378                /* Data on rising edge of bclk, frame low, 1clk before data */
 379                xcr |= ESAI_xCR_xFSR;
 380                xccr |= ESAI_xCCR_xFSP | ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
 381                break;
 382        case SND_SOC_DAIFMT_LEFT_J:
 383                /* Data on rising edge of bclk, frame high */
 384                xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
 385                break;
 386        case SND_SOC_DAIFMT_RIGHT_J:
 387                /* Data on rising edge of bclk, frame high, right aligned */
 388                xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCR_xWA;
 389                break;
 390        case SND_SOC_DAIFMT_DSP_A:
 391                /* Data on rising edge of bclk, frame high, 1clk before data */
 392                xcr |= ESAI_xCR_xFSL | ESAI_xCR_xFSR;
 393                xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
 394                break;
 395        case SND_SOC_DAIFMT_DSP_B:
 396                /* Data on rising edge of bclk, frame high */
 397                xcr |= ESAI_xCR_xFSL;
 398                xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
 399                break;
 400        default:
 401                return -EINVAL;
 402        }
 403
 404        /* DAI clock inversion */
 405        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 406        case SND_SOC_DAIFMT_NB_NF:
 407                /* Nothing to do for both normal cases */
 408                break;
 409        case SND_SOC_DAIFMT_IB_NF:
 410                /* Invert bit clock */
 411                xccr ^= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
 412                break;
 413        case SND_SOC_DAIFMT_NB_IF:
 414                /* Invert frame clock */
 415                xccr ^= ESAI_xCCR_xFSP;
 416                break;
 417        case SND_SOC_DAIFMT_IB_IF:
 418                /* Invert both clocks */
 419                xccr ^= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCCR_xFSP;
 420                break;
 421        default:
 422                return -EINVAL;
 423        }
 424
 425        esai_priv->slave_mode = false;
 426
 427        /* DAI clock master masks */
 428        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 429        case SND_SOC_DAIFMT_CBM_CFM:
 430                esai_priv->slave_mode = true;
 431                break;
 432        case SND_SOC_DAIFMT_CBS_CFM:
 433                xccr |= ESAI_xCCR_xCKD;
 434                break;
 435        case SND_SOC_DAIFMT_CBM_CFS:
 436                xccr |= ESAI_xCCR_xFSD;
 437                break;
 438        case SND_SOC_DAIFMT_CBS_CFS:
 439                xccr |= ESAI_xCCR_xFSD | ESAI_xCCR_xCKD;
 440                break;
 441        default:
 442                return -EINVAL;
 443        }
 444
 445        mask = ESAI_xCR_xFSL | ESAI_xCR_xFSR;
 446        regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR, mask, xcr);
 447        regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR, mask, xcr);
 448
 449        mask = ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCCR_xFSP |
 450                ESAI_xCCR_xFSD | ESAI_xCCR_xCKD | ESAI_xCR_xWA;
 451        regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR, mask, xccr);
 452        regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR, mask, xccr);
 453
 454        return 0;
 455}
 456
 457static int fsl_esai_startup(struct snd_pcm_substream *substream,
 458                            struct snd_soc_dai *dai)
 459{
 460        struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
 461        int ret;
 462
 463        /*
 464         * Some platforms might use the same bit to gate all three or two of
 465         * clocks, so keep all clocks open/close at the same time for safety
 466         */
 467        ret = clk_prepare_enable(esai_priv->coreclk);
 468        if (ret)
 469                return ret;
 470        if (!IS_ERR(esai_priv->extalclk)) {
 471                ret = clk_prepare_enable(esai_priv->extalclk);
 472                if (ret)
 473                        goto err_extalck;
 474        }
 475        if (!IS_ERR(esai_priv->fsysclk)) {
 476                ret = clk_prepare_enable(esai_priv->fsysclk);
 477                if (ret)
 478                        goto err_fsysclk;
 479        }
 480
 481        if (!dai->active) {
 482                /* Set synchronous mode */
 483                regmap_update_bits(esai_priv->regmap, REG_ESAI_SAICR,
 484                                   ESAI_SAICR_SYNC, esai_priv->synchronous ?
 485                                   ESAI_SAICR_SYNC : 0);
 486
 487                /* Set a default slot number -- 2 */
 488                regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR,
 489                                   ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(2));
 490                regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,
 491                                   ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(2));
 492        }
 493
 494        return 0;
 495
 496err_fsysclk:
 497        if (!IS_ERR(esai_priv->extalclk))
 498                clk_disable_unprepare(esai_priv->extalclk);
 499err_extalck:
 500        clk_disable_unprepare(esai_priv->coreclk);
 501
 502        return ret;
 503}
 504
 505static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
 506                              struct snd_pcm_hw_params *params,
 507                              struct snd_soc_dai *dai)
 508{
 509        struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
 510        bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 511        u32 width = snd_pcm_format_width(params_format(params));
 512        u32 channels = params_channels(params);
 513        u32 bclk, mask, val;
 514        int ret;
 515
 516        bclk = params_rate(params) * esai_priv->slot_width * 2;
 517
 518        ret = fsl_esai_set_bclk(dai, tx, bclk);
 519        if (ret)
 520                return ret;
 521
 522        /* Use Normal mode to support monaural audio */
 523        regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
 524                           ESAI_xCR_xMOD_MASK, params_channels(params) > 1 ?
 525                           ESAI_xCR_xMOD_NETWORK : 0);
 526
 527        regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
 528                           ESAI_xFCR_xFR_MASK, ESAI_xFCR_xFR);
 529
 530        mask = ESAI_xFCR_xFR_MASK | ESAI_xFCR_xWA_MASK | ESAI_xFCR_xFWM_MASK |
 531              (tx ? ESAI_xFCR_TE_MASK | ESAI_xFCR_TIEN : ESAI_xFCR_RE_MASK);
 532        val = ESAI_xFCR_xWA(width) | ESAI_xFCR_xFWM(esai_priv->fifo_depth) |
 533             (tx ? ESAI_xFCR_TE(channels) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(channels));
 534
 535        regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val);
 536
 537        mask = ESAI_xCR_xSWS_MASK | (tx ? ESAI_xCR_PADC : 0);
 538        val = ESAI_xCR_xSWS(esai_priv->slot_width, width) | (tx ? ESAI_xCR_PADC : 0);
 539
 540        regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val);
 541
 542        /* Remove ESAI personal reset by configuring ESAI_PCRC and ESAI_PRRC */
 543        regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC,
 544                           ESAI_PRRC_PDC_MASK, ESAI_PRRC_PDC(ESAI_GPIO));
 545        regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC,
 546                           ESAI_PCRC_PC_MASK, ESAI_PCRC_PC(ESAI_GPIO));
 547        return 0;
 548}
 549
 550static void fsl_esai_shutdown(struct snd_pcm_substream *substream,
 551                              struct snd_soc_dai *dai)
 552{
 553        struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
 554
 555        if (!IS_ERR(esai_priv->fsysclk))
 556                clk_disable_unprepare(esai_priv->fsysclk);
 557        if (!IS_ERR(esai_priv->extalclk))
 558                clk_disable_unprepare(esai_priv->extalclk);
 559        clk_disable_unprepare(esai_priv->coreclk);
 560}
 561
 562static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
 563                            struct snd_soc_dai *dai)
 564{
 565        struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
 566        bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 567        u8 i, channels = substream->runtime->channels;
 568
 569        switch (cmd) {
 570        case SNDRV_PCM_TRIGGER_START:
 571        case SNDRV_PCM_TRIGGER_RESUME:
 572        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 573                regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
 574                                   ESAI_xFCR_xFEN_MASK, ESAI_xFCR_xFEN);
 575
 576                /* Write initial words reqiured by ESAI as normal procedure */
 577                for (i = 0; tx && i < channels; i++)
 578                        regmap_write(esai_priv->regmap, REG_ESAI_ETDR, 0x0);
 579
 580                regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
 581                                   tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK,
 582                                   tx ? ESAI_xCR_TE(channels) : ESAI_xCR_RE(channels));
 583                break;
 584        case SNDRV_PCM_TRIGGER_SUSPEND:
 585        case SNDRV_PCM_TRIGGER_STOP:
 586        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 587                regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
 588                                   tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, 0);
 589
 590                /* Disable and reset FIFO */
 591                regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
 592                                   ESAI_xFCR_xFR | ESAI_xFCR_xFEN, ESAI_xFCR_xFR);
 593                regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
 594                                   ESAI_xFCR_xFR, 0);
 595                break;
 596        default:
 597                return -EINVAL;
 598        }
 599
 600        return 0;
 601}
 602
 603static struct snd_soc_dai_ops fsl_esai_dai_ops = {
 604        .startup = fsl_esai_startup,
 605        .shutdown = fsl_esai_shutdown,
 606        .trigger = fsl_esai_trigger,
 607        .hw_params = fsl_esai_hw_params,
 608        .set_sysclk = fsl_esai_set_dai_sysclk,
 609        .set_fmt = fsl_esai_set_dai_fmt,
 610        .xlate_tdm_slot_mask = fsl_asoc_xlate_tdm_slot_mask,
 611        .set_tdm_slot = fsl_esai_set_dai_tdm_slot,
 612};
 613
 614static int fsl_esai_dai_probe(struct snd_soc_dai *dai)
 615{
 616        struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
 617
 618        snd_soc_dai_init_dma_data(dai, &esai_priv->dma_params_tx,
 619                                  &esai_priv->dma_params_rx);
 620
 621        return 0;
 622}
 623
 624static struct snd_soc_dai_driver fsl_esai_dai = {
 625        .probe = fsl_esai_dai_probe,
 626        .playback = {
 627                .channels_min = 1,
 628                .channels_max = 12,
 629                .rates = FSL_ESAI_RATES,
 630                .formats = FSL_ESAI_FORMATS,
 631        },
 632        .capture = {
 633                .channels_min = 1,
 634                .channels_max = 8,
 635                .rates = FSL_ESAI_RATES,
 636                .formats = FSL_ESAI_FORMATS,
 637        },
 638        .ops = &fsl_esai_dai_ops,
 639};
 640
 641static const struct snd_soc_component_driver fsl_esai_component = {
 642        .name           = "fsl-esai",
 643};
 644
 645static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg)
 646{
 647        switch (reg) {
 648        case REG_ESAI_ERDR:
 649        case REG_ESAI_ECR:
 650        case REG_ESAI_ESR:
 651        case REG_ESAI_TFCR:
 652        case REG_ESAI_TFSR:
 653        case REG_ESAI_RFCR:
 654        case REG_ESAI_RFSR:
 655        case REG_ESAI_RX0:
 656        case REG_ESAI_RX1:
 657        case REG_ESAI_RX2:
 658        case REG_ESAI_RX3:
 659        case REG_ESAI_SAISR:
 660        case REG_ESAI_SAICR:
 661        case REG_ESAI_TCR:
 662        case REG_ESAI_TCCR:
 663        case REG_ESAI_RCR:
 664        case REG_ESAI_RCCR:
 665        case REG_ESAI_TSMA:
 666        case REG_ESAI_TSMB:
 667        case REG_ESAI_RSMA:
 668        case REG_ESAI_RSMB:
 669        case REG_ESAI_PRRC:
 670        case REG_ESAI_PCRC:
 671                return true;
 672        default:
 673                return false;
 674        }
 675}
 676
 677static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg)
 678{
 679        switch (reg) {
 680        case REG_ESAI_ETDR:
 681        case REG_ESAI_ECR:
 682        case REG_ESAI_TFCR:
 683        case REG_ESAI_RFCR:
 684        case REG_ESAI_TX0:
 685        case REG_ESAI_TX1:
 686        case REG_ESAI_TX2:
 687        case REG_ESAI_TX3:
 688        case REG_ESAI_TX4:
 689        case REG_ESAI_TX5:
 690        case REG_ESAI_TSR:
 691        case REG_ESAI_SAICR:
 692        case REG_ESAI_TCR:
 693        case REG_ESAI_TCCR:
 694        case REG_ESAI_RCR:
 695        case REG_ESAI_RCCR:
 696        case REG_ESAI_TSMA:
 697        case REG_ESAI_TSMB:
 698        case REG_ESAI_RSMA:
 699        case REG_ESAI_RSMB:
 700        case REG_ESAI_PRRC:
 701        case REG_ESAI_PCRC:
 702                return true;
 703        default:
 704                return false;
 705        }
 706}
 707
 708static struct regmap_config fsl_esai_regmap_config = {
 709        .reg_bits = 32,
 710        .reg_stride = 4,
 711        .val_bits = 32,
 712
 713        .max_register = REG_ESAI_PCRC,
 714        .readable_reg = fsl_esai_readable_reg,
 715        .writeable_reg = fsl_esai_writeable_reg,
 716};
 717
 718static int fsl_esai_probe(struct platform_device *pdev)
 719{
 720        struct device_node *np = pdev->dev.of_node;
 721        struct fsl_esai *esai_priv;
 722        struct resource *res;
 723        const uint32_t *iprop;
 724        void __iomem *regs;
 725        int irq, ret;
 726
 727        esai_priv = devm_kzalloc(&pdev->dev, sizeof(*esai_priv), GFP_KERNEL);
 728        if (!esai_priv)
 729                return -ENOMEM;
 730
 731        esai_priv->pdev = pdev;
 732        strcpy(esai_priv->name, np->name);
 733
 734        if (of_property_read_bool(np, "big-endian"))
 735                fsl_esai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
 736
 737        /* Get the addresses and IRQ */
 738        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 739        regs = devm_ioremap_resource(&pdev->dev, res);
 740        if (IS_ERR(regs))
 741                return PTR_ERR(regs);
 742
 743        esai_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
 744                        "core", regs, &fsl_esai_regmap_config);
 745        if (IS_ERR(esai_priv->regmap)) {
 746                dev_err(&pdev->dev, "failed to init regmap: %ld\n",
 747                                PTR_ERR(esai_priv->regmap));
 748                return PTR_ERR(esai_priv->regmap);
 749        }
 750
 751        esai_priv->coreclk = devm_clk_get(&pdev->dev, "core");
 752        if (IS_ERR(esai_priv->coreclk)) {
 753                dev_err(&pdev->dev, "failed to get core clock: %ld\n",
 754                                PTR_ERR(esai_priv->coreclk));
 755                return PTR_ERR(esai_priv->coreclk);
 756        }
 757
 758        esai_priv->extalclk = devm_clk_get(&pdev->dev, "extal");
 759        if (IS_ERR(esai_priv->extalclk))
 760                dev_warn(&pdev->dev, "failed to get extal clock: %ld\n",
 761                                PTR_ERR(esai_priv->extalclk));
 762
 763        esai_priv->fsysclk = devm_clk_get(&pdev->dev, "fsys");
 764        if (IS_ERR(esai_priv->fsysclk))
 765                dev_warn(&pdev->dev, "failed to get fsys clock: %ld\n",
 766                                PTR_ERR(esai_priv->fsysclk));
 767
 768        irq = platform_get_irq(pdev, 0);
 769        if (irq < 0) {
 770                dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
 771                return irq;
 772        }
 773
 774        ret = devm_request_irq(&pdev->dev, irq, esai_isr, 0,
 775                               esai_priv->name, esai_priv);
 776        if (ret) {
 777                dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
 778                return ret;
 779        }
 780
 781        /* Set a default slot size */
 782        esai_priv->slot_width = 32;
 783
 784        /* Set a default master/slave state */
 785        esai_priv->slave_mode = true;
 786
 787        /* Determine the FIFO depth */
 788        iprop = of_get_property(np, "fsl,fifo-depth", NULL);
 789        if (iprop)
 790                esai_priv->fifo_depth = be32_to_cpup(iprop);
 791        else
 792                esai_priv->fifo_depth = 64;
 793
 794        esai_priv->dma_params_tx.maxburst = 16;
 795        esai_priv->dma_params_rx.maxburst = 16;
 796        esai_priv->dma_params_tx.addr = res->start + REG_ESAI_ETDR;
 797        esai_priv->dma_params_rx.addr = res->start + REG_ESAI_ERDR;
 798
 799        esai_priv->synchronous =
 800                of_property_read_bool(np, "fsl,esai-synchronous");
 801
 802        /* Implement full symmetry for synchronous mode */
 803        if (esai_priv->synchronous) {
 804                fsl_esai_dai.symmetric_rates = 1;
 805                fsl_esai_dai.symmetric_channels = 1;
 806                fsl_esai_dai.symmetric_samplebits = 1;
 807        }
 808
 809        dev_set_drvdata(&pdev->dev, esai_priv);
 810
 811        /* Reset ESAI unit */
 812        ret = regmap_write(esai_priv->regmap, REG_ESAI_ECR, ESAI_ECR_ERST);
 813        if (ret) {
 814                dev_err(&pdev->dev, "failed to reset ESAI: %d\n", ret);
 815                return ret;
 816        }
 817
 818        /*
 819         * We need to enable ESAI so as to access some of its registers.
 820         * Otherwise, we would fail to dump regmap from user space.
 821         */
 822        ret = regmap_write(esai_priv->regmap, REG_ESAI_ECR, ESAI_ECR_ESAIEN);
 823        if (ret) {
 824                dev_err(&pdev->dev, "failed to enable ESAI: %d\n", ret);
 825                return ret;
 826        }
 827
 828        ret = devm_snd_soc_register_component(&pdev->dev, &fsl_esai_component,
 829                                              &fsl_esai_dai, 1);
 830        if (ret) {
 831                dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
 832                return ret;
 833        }
 834
 835        ret = imx_pcm_dma_init(pdev);
 836        if (ret)
 837                dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret);
 838
 839        return ret;
 840}
 841
 842static const struct of_device_id fsl_esai_dt_ids[] = {
 843        { .compatible = "fsl,imx35-esai", },
 844        { .compatible = "fsl,vf610-esai", },
 845        {}
 846};
 847MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids);
 848
 849static struct platform_driver fsl_esai_driver = {
 850        .probe = fsl_esai_probe,
 851        .driver = {
 852                .name = "fsl-esai-dai",
 853                .owner = THIS_MODULE,
 854                .of_match_table = fsl_esai_dt_ids,
 855        },
 856};
 857
 858module_platform_driver(fsl_esai_driver);
 859
 860MODULE_AUTHOR("Freescale Semiconductor, Inc.");
 861MODULE_DESCRIPTION("Freescale ESAI CPU DAI driver");
 862MODULE_LICENSE("GPL v2");
 863MODULE_ALIAS("platform:fsl-esai-dai");
 864