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