1215 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// Freescale ESAI ALSA SoC Digital Audio Interface (DAI) driver4//5// Copyright (C) 2014 Freescale Semiconductor, Inc.6 7#include <linux/clk.h>8#include <linux/dmaengine.h>9#include <linux/module.h>10#include <linux/of_irq.h>11#include <linux/of_platform.h>12#include <linux/pm_runtime.h>13#include <sound/dmaengine_pcm.h>14#include <sound/pcm_params.h>15 16#include "fsl_esai.h"17#include "imx-pcm.h"18 19#define FSL_ESAI_FORMATS (SNDRV_PCM_FMTBIT_S8 | \20 SNDRV_PCM_FMTBIT_S16_LE | \21 SNDRV_PCM_FMTBIT_S20_3LE | \22 SNDRV_PCM_FMTBIT_S24_LE)23 24/**25 * struct fsl_esai_soc_data - soc specific data26 * @reset_at_xrun: flags for enable reset operaton27 */28struct fsl_esai_soc_data {29 bool reset_at_xrun;30};31 32/**33 * struct fsl_esai - ESAI private data34 * @dma_params_rx: DMA parameters for receive channel35 * @dma_params_tx: DMA parameters for transmit channel36 * @pdev: platform device pointer37 * @regmap: regmap handler38 * @coreclk: clock source to access register39 * @extalclk: esai clock source to derive HCK, SCK and FS40 * @fsysclk: system clock source to derive HCK, SCK and FS41 * @spbaclk: SPBA clock (optional, depending on SoC design)42 * @work: work to handle the reset operation43 * @soc: soc specific data44 * @lock: spin lock between hw_reset() and trigger()45 * @fifo_depth: depth of tx/rx FIFO46 * @slot_width: width of each DAI slot47 * @slots: number of slots48 * @tx_mask: slot mask for TX49 * @rx_mask: slot mask for RX50 * @channels: channel num for tx or rx51 * @hck_rate: clock rate of desired HCKx clock52 * @sck_rate: clock rate of desired SCKx clock53 * @hck_dir: the direction of HCKx pads54 * @sck_div: if using PSR/PM dividers for SCKx clock55 * @consumer_mode: if fully using DAI clock consumer mode56 * @synchronous: if using tx/rx synchronous mode57 * @name: driver name58 */59struct fsl_esai {60 struct snd_dmaengine_dai_dma_data dma_params_rx;61 struct snd_dmaengine_dai_dma_data dma_params_tx;62 struct platform_device *pdev;63 struct regmap *regmap;64 struct clk *coreclk;65 struct clk *extalclk;66 struct clk *fsysclk;67 struct clk *spbaclk;68 struct work_struct work;69 const struct fsl_esai_soc_data *soc;70 spinlock_t lock; /* Protect hw_reset and trigger */71 u32 fifo_depth;72 u32 slot_width;73 u32 slots;74 u32 tx_mask;75 u32 rx_mask;76 u32 channels[2];77 u32 hck_rate[2];78 u32 sck_rate[2];79 bool hck_dir[2];80 bool sck_div[2];81 bool consumer_mode;82 bool synchronous;83 char name[32];84};85 86static struct fsl_esai_soc_data fsl_esai_vf610 = {87 .reset_at_xrun = true,88};89 90static struct fsl_esai_soc_data fsl_esai_imx35 = {91 .reset_at_xrun = true,92};93 94static struct fsl_esai_soc_data fsl_esai_imx6ull = {95 .reset_at_xrun = false,96};97 98static irqreturn_t esai_isr(int irq, void *devid)99{100 struct fsl_esai *esai_priv = (struct fsl_esai *)devid;101 struct platform_device *pdev = esai_priv->pdev;102 u32 esr;103 u32 saisr;104 105 regmap_read(esai_priv->regmap, REG_ESAI_ESR, &esr);106 regmap_read(esai_priv->regmap, REG_ESAI_SAISR, &saisr);107 108 if ((saisr & (ESAI_SAISR_TUE | ESAI_SAISR_ROE)) &&109 esai_priv->soc->reset_at_xrun) {110 dev_dbg(&pdev->dev, "reset module for xrun\n");111 regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR,112 ESAI_xCR_xEIE_MASK, 0);113 regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR,114 ESAI_xCR_xEIE_MASK, 0);115 schedule_work(&esai_priv->work);116 }117 118 if (esr & ESAI_ESR_TINIT_MASK)119 dev_dbg(&pdev->dev, "isr: Transmission Initialized\n");120 121 if (esr & ESAI_ESR_RFF_MASK)122 dev_dbg(&pdev->dev, "isr: Receiving overrun\n");123 124 if (esr & ESAI_ESR_TFE_MASK)125 dev_dbg(&pdev->dev, "isr: Transmission underrun\n");126 127 if (esr & ESAI_ESR_TLS_MASK)128 dev_dbg(&pdev->dev, "isr: Just transmitted the last slot\n");129 130 if (esr & ESAI_ESR_TDE_MASK)131 dev_dbg(&pdev->dev, "isr: Transmission data exception\n");132 133 if (esr & ESAI_ESR_TED_MASK)134 dev_dbg(&pdev->dev, "isr: Transmitting even slots\n");135 136 if (esr & ESAI_ESR_TD_MASK)137 dev_dbg(&pdev->dev, "isr: Transmitting data\n");138 139 if (esr & ESAI_ESR_RLS_MASK)140 dev_dbg(&pdev->dev, "isr: Just received the last slot\n");141 142 if (esr & ESAI_ESR_RDE_MASK)143 dev_dbg(&pdev->dev, "isr: Receiving data exception\n");144 145 if (esr & ESAI_ESR_RED_MASK)146 dev_dbg(&pdev->dev, "isr: Receiving even slots\n");147 148 if (esr & ESAI_ESR_RD_MASK)149 dev_dbg(&pdev->dev, "isr: Receiving data\n");150 151 return IRQ_HANDLED;152}153 154/**155 * fsl_esai_divisor_cal - This function is used to calculate the156 * divisors of psr, pm, fp and it is supposed to be called in157 * set_dai_sysclk() and set_bclk().158 *159 * @dai: pointer to DAI160 * @tx: current setting is for playback or capture161 * @ratio: desired overall ratio for the paticipating dividers162 * @usefp: for HCK setting, there is no need to set fp divider163 * @fp: bypass other dividers by setting fp directly if fp != 0164 */165static int fsl_esai_divisor_cal(struct snd_soc_dai *dai, bool tx, u32 ratio,166 bool usefp, u32 fp)167{168 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);169 u32 psr, pm = 999, maxfp, prod, sub, savesub, i, j;170 171 maxfp = usefp ? 16 : 1;172 173 if (usefp && fp)174 goto out_fp;175 176 if (ratio > 2 * 8 * 256 * maxfp || ratio < 2) {177 dev_err(dai->dev, "the ratio is out of range (2 ~ %d)\n",178 2 * 8 * 256 * maxfp);179 return -EINVAL;180 } else if (ratio % 2) {181 dev_err(dai->dev, "the raio must be even if using upper divider\n");182 return -EINVAL;183 }184 185 ratio /= 2;186 187 psr = ratio <= 256 * maxfp ? ESAI_xCCR_xPSR_BYPASS : ESAI_xCCR_xPSR_DIV8;188 189 /* Do not loop-search if PM (1 ~ 256) alone can serve the ratio */190 if (ratio <= 256) {191 pm = ratio;192 fp = 1;193 goto out;194 }195 196 /* Set the max fluctuation -- 0.1% of the max devisor */197 savesub = (psr ? 1 : 8) * 256 * maxfp / 1000;198 199 /* Find the best value for PM */200 for (i = 1; i <= 256; i++) {201 for (j = 1; j <= maxfp; j++) {202 /* PSR (1 or 8) * PM (1 ~ 256) * FP (1 ~ 16) */203 prod = (psr ? 1 : 8) * i * j;204 205 if (prod == ratio)206 sub = 0;207 else if (prod / ratio == 1)208 sub = prod - ratio;209 else if (ratio / prod == 1)210 sub = ratio - prod;211 else212 continue;213 214 /* Calculate the fraction */215 sub = sub * 1000 / ratio;216 if (sub < savesub) {217 savesub = sub;218 pm = i;219 fp = j;220 }221 222 /* We are lucky */223 if (savesub == 0)224 goto out;225 }226 }227 228 if (pm == 999) {229 dev_err(dai->dev, "failed to calculate proper divisors\n");230 return -EINVAL;231 }232 233out:234 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx),235 ESAI_xCCR_xPSR_MASK | ESAI_xCCR_xPM_MASK,236 psr | ESAI_xCCR_xPM(pm));237 238out_fp:239 /* Bypass fp if not being required */240 if (maxfp <= 1)241 return 0;242 243 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx),244 ESAI_xCCR_xFP_MASK, ESAI_xCCR_xFP(fp));245 246 return 0;247}248 249/**250 * fsl_esai_set_dai_sysclk - configure the clock frequency of MCLK (HCKT/HCKR)251 * @dai: pointer to DAI252 * @clk_id: The clock source of HCKT/HCKR253 * (Input from outside; output from inside, FSYS or EXTAL)254 * @freq: The required clock rate of HCKT/HCKR255 * @dir: The clock direction of HCKT/HCKR256 *257 * Note: If the direction is input, we do not care about clk_id.258 */259static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,260 unsigned int freq, int dir)261{262 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);263 struct clk *clksrc = esai_priv->extalclk;264 bool tx = (clk_id <= ESAI_HCKT_EXTAL || esai_priv->synchronous);265 bool in = dir == SND_SOC_CLOCK_IN;266 u32 ratio, ecr = 0;267 unsigned long clk_rate;268 int ret;269 270 if (freq == 0) {271 dev_err(dai->dev, "%sput freq of HCK%c should not be 0Hz\n",272 in ? "in" : "out", tx ? 'T' : 'R');273 return -EINVAL;274 }275 276 /* Bypass divider settings if the requirement doesn't change */277 if (freq == esai_priv->hck_rate[tx] && dir == esai_priv->hck_dir[tx])278 return 0;279 280 /* sck_div can be only bypassed if ETO/ERO=0 and SNC_SOC_CLOCK_OUT */281 esai_priv->sck_div[tx] = true;282 283 /* Set the direction of HCKT/HCKR pins */284 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx),285 ESAI_xCCR_xHCKD, in ? 0 : ESAI_xCCR_xHCKD);286 287 if (in)288 goto out;289 290 switch (clk_id) {291 case ESAI_HCKT_FSYS:292 case ESAI_HCKR_FSYS:293 clksrc = esai_priv->fsysclk;294 break;295 case ESAI_HCKT_EXTAL:296 ecr |= ESAI_ECR_ETI;297 break;298 case ESAI_HCKR_EXTAL:299 ecr |= esai_priv->synchronous ? ESAI_ECR_ETI : ESAI_ECR_ERI;300 break;301 default:302 return -EINVAL;303 }304 305 if (IS_ERR(clksrc)) {306 dev_err(dai->dev, "no assigned %s clock\n",307 (clk_id % 2) ? "extal" : "fsys");308 return PTR_ERR(clksrc);309 }310 clk_rate = clk_get_rate(clksrc);311 312 ratio = clk_rate / freq;313 if (ratio * freq > clk_rate)314 ret = ratio * freq - clk_rate;315 else if (ratio * freq < clk_rate)316 ret = clk_rate - ratio * freq;317 else318 ret = 0;319 320 /* Block if clock source can not be divided into the required rate */321 if (ret != 0 && clk_rate / ret < 1000) {322 dev_err(dai->dev, "failed to derive required HCK%c rate\n",323 tx ? 'T' : 'R');324 return -EINVAL;325 }326 327 /* Only EXTAL source can be output directly without using PSR and PM */328 if (ratio == 1 && clksrc == esai_priv->extalclk) {329 /* Bypass all the dividers if not being needed */330 ecr |= tx ? ESAI_ECR_ETO : ESAI_ECR_ERO;331 goto out;332 } else if (ratio < 2) {333 /* The ratio should be no less than 2 if using other sources */334 dev_err(dai->dev, "failed to derive required HCK%c rate\n",335 tx ? 'T' : 'R');336 return -EINVAL;337 }338 339 ret = fsl_esai_divisor_cal(dai, tx, ratio, false, 0);340 if (ret)341 return ret;342 343 esai_priv->sck_div[tx] = false;344 345out:346 esai_priv->hck_dir[tx] = dir;347 esai_priv->hck_rate[tx] = freq;348 349 regmap_update_bits(esai_priv->regmap, REG_ESAI_ECR,350 tx ? ESAI_ECR_ETI | ESAI_ECR_ETO :351 ESAI_ECR_ERI | ESAI_ECR_ERO, ecr);352 353 return 0;354}355 356/**357 * fsl_esai_set_bclk - configure the related dividers according to the bclk rate358 * @dai: pointer to DAI359 * @tx: direction boolean360 * @freq: bclk freq361 */362static int fsl_esai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)363{364 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);365 u32 hck_rate = esai_priv->hck_rate[tx];366 u32 sub, ratio = hck_rate / freq;367 int ret;368 369 /* Don't apply for fully consumer mode or unchanged bclk */370 if (esai_priv->consumer_mode || esai_priv->sck_rate[tx] == freq)371 return 0;372 373 if (ratio * freq > hck_rate)374 sub = ratio * freq - hck_rate;375 else if (ratio * freq < hck_rate)376 sub = hck_rate - ratio * freq;377 else378 sub = 0;379 380 /* Block if clock source can not be divided into the required rate */381 if (sub != 0 && hck_rate / sub < 1000) {382 dev_err(dai->dev, "failed to derive required SCK%c rate\n",383 tx ? 'T' : 'R');384 return -EINVAL;385 }386 387 /* The ratio should be contented by FP alone if bypassing PM and PSR */388 if (!esai_priv->sck_div[tx] && (ratio > 16 || ratio == 0)) {389 dev_err(dai->dev, "the ratio is out of range (1 ~ 16)\n");390 return -EINVAL;391 }392 393 ret = fsl_esai_divisor_cal(dai, tx, ratio, true,394 esai_priv->sck_div[tx] ? 0 : ratio);395 if (ret)396 return ret;397 398 /* Save current bclk rate */399 esai_priv->sck_rate[tx] = freq;400 401 return 0;402}403 404static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,405 u32 rx_mask, int slots, int slot_width)406{407 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);408 409 regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR,410 ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots));411 412 regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,413 ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots));414 415 esai_priv->slot_width = slot_width;416 esai_priv->slots = slots;417 esai_priv->tx_mask = tx_mask;418 esai_priv->rx_mask = rx_mask;419 420 return 0;421}422 423static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)424{425 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);426 u32 xcr = 0, xccr = 0, mask;427 428 /* DAI mode */429 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {430 case SND_SOC_DAIFMT_I2S:431 /* Data on rising edge of bclk, frame low, 1clk before data */432 xcr |= ESAI_xCR_xFSR;433 xccr |= ESAI_xCCR_xFSP | ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;434 break;435 case SND_SOC_DAIFMT_LEFT_J:436 /* Data on rising edge of bclk, frame high */437 xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;438 break;439 case SND_SOC_DAIFMT_RIGHT_J:440 /* Data on rising edge of bclk, frame high, right aligned */441 xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;442 xcr |= ESAI_xCR_xWA;443 break;444 case SND_SOC_DAIFMT_DSP_A:445 /* Data on rising edge of bclk, frame high, 1clk before data */446 xcr |= ESAI_xCR_xFSL | ESAI_xCR_xFSR;447 xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;448 break;449 case SND_SOC_DAIFMT_DSP_B:450 /* Data on rising edge of bclk, frame high */451 xcr |= ESAI_xCR_xFSL;452 xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;453 break;454 default:455 return -EINVAL;456 }457 458 /* DAI clock inversion */459 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {460 case SND_SOC_DAIFMT_NB_NF:461 /* Nothing to do for both normal cases */462 break;463 case SND_SOC_DAIFMT_IB_NF:464 /* Invert bit clock */465 xccr ^= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;466 break;467 case SND_SOC_DAIFMT_NB_IF:468 /* Invert frame clock */469 xccr ^= ESAI_xCCR_xFSP;470 break;471 case SND_SOC_DAIFMT_IB_IF:472 /* Invert both clocks */473 xccr ^= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCCR_xFSP;474 break;475 default:476 return -EINVAL;477 }478 479 esai_priv->consumer_mode = false;480 481 /* DAI clock provider masks */482 switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {483 case SND_SOC_DAIFMT_BC_FC:484 esai_priv->consumer_mode = true;485 break;486 case SND_SOC_DAIFMT_BP_FC:487 xccr |= ESAI_xCCR_xCKD;488 break;489 case SND_SOC_DAIFMT_BC_FP:490 xccr |= ESAI_xCCR_xFSD;491 break;492 case SND_SOC_DAIFMT_BP_FP:493 xccr |= ESAI_xCCR_xFSD | ESAI_xCCR_xCKD;494 break;495 default:496 return -EINVAL;497 }498 499 mask = ESAI_xCR_xFSL | ESAI_xCR_xFSR | ESAI_xCR_xWA;500 regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR, mask, xcr);501 regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR, mask, xcr);502 503 mask = ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCCR_xFSP |504 ESAI_xCCR_xFSD | ESAI_xCCR_xCKD;505 regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR, mask, xccr);506 regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR, mask, xccr);507 508 return 0;509}510 511static int fsl_esai_startup(struct snd_pcm_substream *substream,512 struct snd_soc_dai *dai)513{514 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);515 516 if (!snd_soc_dai_active(dai)) {517 /* Set synchronous mode */518 regmap_update_bits(esai_priv->regmap, REG_ESAI_SAICR,519 ESAI_SAICR_SYNC, esai_priv->synchronous ?520 ESAI_SAICR_SYNC : 0);521 522 /* Set slots count */523 regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR,524 ESAI_xCCR_xDC_MASK,525 ESAI_xCCR_xDC(esai_priv->slots));526 regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,527 ESAI_xCCR_xDC_MASK,528 ESAI_xCCR_xDC(esai_priv->slots));529 }530 531 return 0;532 533}534 535static int fsl_esai_hw_params(struct snd_pcm_substream *substream,536 struct snd_pcm_hw_params *params,537 struct snd_soc_dai *dai)538{539 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);540 bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;541 u32 width = params_width(params);542 u32 channels = params_channels(params);543 u32 pins = DIV_ROUND_UP(channels, esai_priv->slots);544 u32 slot_width = width;545 u32 bclk, mask, val;546 int ret;547 548 /* Override slot_width if being specifically set */549 if (esai_priv->slot_width)550 slot_width = esai_priv->slot_width;551 552 bclk = params_rate(params) * slot_width * esai_priv->slots;553 554 ret = fsl_esai_set_bclk(dai, esai_priv->synchronous || tx, bclk);555 if (ret)556 return ret;557 558 mask = ESAI_xCR_xSWS_MASK;559 val = ESAI_xCR_xSWS(slot_width, width);560 561 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val);562 /* Recording in synchronous mode needs to set TCR also */563 if (!tx && esai_priv->synchronous)564 regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR, mask, val);565 566 /* Use Normal mode to support monaural audio */567 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),568 ESAI_xCR_xMOD_MASK, params_channels(params) > 1 ?569 ESAI_xCR_xMOD_NETWORK : 0);570 571 regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),572 ESAI_xFCR_xFR_MASK, ESAI_xFCR_xFR);573 574 mask = ESAI_xFCR_xFR_MASK | ESAI_xFCR_xWA_MASK | ESAI_xFCR_xFWM_MASK |575 (tx ? ESAI_xFCR_TE_MASK | ESAI_xFCR_TIEN : ESAI_xFCR_RE_MASK);576 val = ESAI_xFCR_xWA(width) | ESAI_xFCR_xFWM(esai_priv->fifo_depth) |577 (tx ? ESAI_xFCR_TE(pins) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(pins));578 579 regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val);580 581 if (tx)582 regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR,583 ESAI_xCR_PADC, ESAI_xCR_PADC);584 585 /* Remove ESAI personal reset by configuring ESAI_PCRC and ESAI_PRRC */586 regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC,587 ESAI_PRRC_PDC_MASK, ESAI_PRRC_PDC(ESAI_GPIO));588 regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC,589 ESAI_PCRC_PC_MASK, ESAI_PCRC_PC(ESAI_GPIO));590 return 0;591}592 593static int fsl_esai_hw_init(struct fsl_esai *esai_priv)594{595 struct platform_device *pdev = esai_priv->pdev;596 int ret;597 598 /* Reset ESAI unit */599 ret = regmap_update_bits(esai_priv->regmap, REG_ESAI_ECR,600 ESAI_ECR_ESAIEN_MASK | ESAI_ECR_ERST_MASK,601 ESAI_ECR_ESAIEN | ESAI_ECR_ERST);602 if (ret) {603 dev_err(&pdev->dev, "failed to reset ESAI: %d\n", ret);604 return ret;605 }606 607 /*608 * We need to enable ESAI so as to access some of its registers.609 * Otherwise, we would fail to dump regmap from user space.610 */611 ret = regmap_update_bits(esai_priv->regmap, REG_ESAI_ECR,612 ESAI_ECR_ESAIEN_MASK | ESAI_ECR_ERST_MASK,613 ESAI_ECR_ESAIEN);614 if (ret) {615 dev_err(&pdev->dev, "failed to enable ESAI: %d\n", ret);616 return ret;617 }618 619 regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC,620 ESAI_PRRC_PDC_MASK, 0);621 regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC,622 ESAI_PCRC_PC_MASK, 0);623 624 return 0;625}626 627static int fsl_esai_register_restore(struct fsl_esai *esai_priv)628{629 int ret;630 631 /* FIFO reset for safety */632 regmap_update_bits(esai_priv->regmap, REG_ESAI_TFCR,633 ESAI_xFCR_xFR, ESAI_xFCR_xFR);634 regmap_update_bits(esai_priv->regmap, REG_ESAI_RFCR,635 ESAI_xFCR_xFR, ESAI_xFCR_xFR);636 637 regcache_mark_dirty(esai_priv->regmap);638 ret = regcache_sync(esai_priv->regmap);639 if (ret)640 return ret;641 642 /* FIFO reset done */643 regmap_update_bits(esai_priv->regmap, REG_ESAI_TFCR, ESAI_xFCR_xFR, 0);644 regmap_update_bits(esai_priv->regmap, REG_ESAI_RFCR, ESAI_xFCR_xFR, 0);645 646 return 0;647}648 649static void fsl_esai_trigger_start(struct fsl_esai *esai_priv, bool tx)650{651 u8 i, channels = esai_priv->channels[tx];652 u32 pins = DIV_ROUND_UP(channels, esai_priv->slots);653 u32 mask;654 655 regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),656 ESAI_xFCR_xFEN_MASK, ESAI_xFCR_xFEN);657 658 /* Write initial words reqiured by ESAI as normal procedure */659 for (i = 0; tx && i < channels; i++)660 regmap_write(esai_priv->regmap, REG_ESAI_ETDR, 0x0);661 662 /*663 * When set the TE/RE in the end of enablement flow, there664 * will be channel swap issue for multi data line case.665 * In order to workaround this issue, we switch the bit666 * enablement sequence to below sequence667 * 1) clear the xSMB & xSMA: which is done in probe and668 * stop state.669 * 2) set TE/RE670 * 3) set xSMB671 * 4) set xSMA: xSMA is the last one in this flow, which672 * will trigger esai to start.673 */674 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),675 tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK,676 tx ? ESAI_xCR_TE(pins) : ESAI_xCR_RE(pins));677 mask = tx ? esai_priv->tx_mask : esai_priv->rx_mask;678 679 regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx),680 ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(mask));681 regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx),682 ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(mask));683 684 /* Enable Exception interrupt */685 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),686 ESAI_xCR_xEIE_MASK, ESAI_xCR_xEIE);687}688 689static void fsl_esai_trigger_stop(struct fsl_esai *esai_priv, bool tx)690{691 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),692 ESAI_xCR_xEIE_MASK, 0);693 694 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),695 tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, 0);696 regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx),697 ESAI_xSMA_xS_MASK, 0);698 regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx),699 ESAI_xSMB_xS_MASK, 0);700 701 /* Disable and reset FIFO */702 regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),703 ESAI_xFCR_xFR | ESAI_xFCR_xFEN, ESAI_xFCR_xFR);704 regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),705 ESAI_xFCR_xFR, 0);706}707 708static void fsl_esai_hw_reset(struct work_struct *work)709{710 struct fsl_esai *esai_priv = container_of(work, struct fsl_esai, work);711 bool tx = true, rx = false, enabled[2];712 unsigned long lock_flags;713 u32 tfcr, rfcr;714 715 spin_lock_irqsave(&esai_priv->lock, lock_flags);716 /* Save the registers */717 regmap_read(esai_priv->regmap, REG_ESAI_TFCR, &tfcr);718 regmap_read(esai_priv->regmap, REG_ESAI_RFCR, &rfcr);719 enabled[tx] = tfcr & ESAI_xFCR_xFEN;720 enabled[rx] = rfcr & ESAI_xFCR_xFEN;721 722 /* Stop the tx & rx */723 fsl_esai_trigger_stop(esai_priv, tx);724 fsl_esai_trigger_stop(esai_priv, rx);725 726 /* Reset the esai, and ignore return value */727 fsl_esai_hw_init(esai_priv);728 729 /* Enforce ESAI personal resets for both TX and RX */730 regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR,731 ESAI_xCR_xPR_MASK, ESAI_xCR_xPR);732 regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR,733 ESAI_xCR_xPR_MASK, ESAI_xCR_xPR);734 735 /* Restore registers by regcache_sync, and ignore return value */736 fsl_esai_register_restore(esai_priv);737 738 /* Remove ESAI personal resets by configuring PCRC and PRRC also */739 regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR,740 ESAI_xCR_xPR_MASK, 0);741 regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR,742 ESAI_xCR_xPR_MASK, 0);743 regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC,744 ESAI_PRRC_PDC_MASK, ESAI_PRRC_PDC(ESAI_GPIO));745 regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC,746 ESAI_PCRC_PC_MASK, ESAI_PCRC_PC(ESAI_GPIO));747 748 /* Restart tx / rx, if they already enabled */749 if (enabled[tx])750 fsl_esai_trigger_start(esai_priv, tx);751 if (enabled[rx])752 fsl_esai_trigger_start(esai_priv, rx);753 754 spin_unlock_irqrestore(&esai_priv->lock, lock_flags);755}756 757static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,758 struct snd_soc_dai *dai)759{760 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);761 bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;762 unsigned long lock_flags;763 764 esai_priv->channels[tx] = substream->runtime->channels;765 766 switch (cmd) {767 case SNDRV_PCM_TRIGGER_START:768 case SNDRV_PCM_TRIGGER_RESUME:769 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:770 spin_lock_irqsave(&esai_priv->lock, lock_flags);771 fsl_esai_trigger_start(esai_priv, tx);772 spin_unlock_irqrestore(&esai_priv->lock, lock_flags);773 break;774 case SNDRV_PCM_TRIGGER_SUSPEND:775 case SNDRV_PCM_TRIGGER_STOP:776 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:777 spin_lock_irqsave(&esai_priv->lock, lock_flags);778 fsl_esai_trigger_stop(esai_priv, tx);779 spin_unlock_irqrestore(&esai_priv->lock, lock_flags);780 break;781 default:782 return -EINVAL;783 }784 785 return 0;786}787 788static int fsl_esai_dai_probe(struct snd_soc_dai *dai)789{790 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);791 792 snd_soc_dai_init_dma_data(dai, &esai_priv->dma_params_tx,793 &esai_priv->dma_params_rx);794 795 return 0;796}797 798static const struct snd_soc_dai_ops fsl_esai_dai_ops = {799 .probe = fsl_esai_dai_probe,800 .startup = fsl_esai_startup,801 .trigger = fsl_esai_trigger,802 .hw_params = fsl_esai_hw_params,803 .set_sysclk = fsl_esai_set_dai_sysclk,804 .set_fmt = fsl_esai_set_dai_fmt,805 .set_tdm_slot = fsl_esai_set_dai_tdm_slot,806};807 808static struct snd_soc_dai_driver fsl_esai_dai = {809 .playback = {810 .stream_name = "CPU-Playback",811 .channels_min = 1,812 .channels_max = 12,813 .rates = SNDRV_PCM_RATE_8000_192000,814 .formats = FSL_ESAI_FORMATS,815 },816 .capture = {817 .stream_name = "CPU-Capture",818 .channels_min = 1,819 .channels_max = 8,820 .rates = SNDRV_PCM_RATE_8000_192000,821 .formats = FSL_ESAI_FORMATS,822 },823 .ops = &fsl_esai_dai_ops,824};825 826static const struct snd_soc_component_driver fsl_esai_component = {827 .name = "fsl-esai",828 .legacy_dai_naming = 1,829};830 831static const struct reg_default fsl_esai_reg_defaults[] = {832 {REG_ESAI_ETDR, 0x00000000},833 {REG_ESAI_ECR, 0x00000000},834 {REG_ESAI_TFCR, 0x00000000},835 {REG_ESAI_RFCR, 0x00000000},836 {REG_ESAI_TX0, 0x00000000},837 {REG_ESAI_TX1, 0x00000000},838 {REG_ESAI_TX2, 0x00000000},839 {REG_ESAI_TX3, 0x00000000},840 {REG_ESAI_TX4, 0x00000000},841 {REG_ESAI_TX5, 0x00000000},842 {REG_ESAI_TSR, 0x00000000},843 {REG_ESAI_SAICR, 0x00000000},844 {REG_ESAI_TCR, 0x00000000},845 {REG_ESAI_TCCR, 0x00000000},846 {REG_ESAI_RCR, 0x00000000},847 {REG_ESAI_RCCR, 0x00000000},848 {REG_ESAI_TSMA, 0x0000ffff},849 {REG_ESAI_TSMB, 0x0000ffff},850 {REG_ESAI_RSMA, 0x0000ffff},851 {REG_ESAI_RSMB, 0x0000ffff},852 {REG_ESAI_PRRC, 0x00000000},853 {REG_ESAI_PCRC, 0x00000000},854};855 856static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg)857{858 switch (reg) {859 case REG_ESAI_ERDR:860 case REG_ESAI_ECR:861 case REG_ESAI_ESR:862 case REG_ESAI_TFCR:863 case REG_ESAI_TFSR:864 case REG_ESAI_RFCR:865 case REG_ESAI_RFSR:866 case REG_ESAI_RX0:867 case REG_ESAI_RX1:868 case REG_ESAI_RX2:869 case REG_ESAI_RX3:870 case REG_ESAI_SAISR:871 case REG_ESAI_SAICR:872 case REG_ESAI_TCR:873 case REG_ESAI_TCCR:874 case REG_ESAI_RCR:875 case REG_ESAI_RCCR:876 case REG_ESAI_TSMA:877 case REG_ESAI_TSMB:878 case REG_ESAI_RSMA:879 case REG_ESAI_RSMB:880 case REG_ESAI_PRRC:881 case REG_ESAI_PCRC:882 return true;883 default:884 return false;885 }886}887 888static bool fsl_esai_volatile_reg(struct device *dev, unsigned int reg)889{890 switch (reg) {891 case REG_ESAI_ERDR:892 case REG_ESAI_ESR:893 case REG_ESAI_TFSR:894 case REG_ESAI_RFSR:895 case REG_ESAI_RX0:896 case REG_ESAI_RX1:897 case REG_ESAI_RX2:898 case REG_ESAI_RX3:899 case REG_ESAI_SAISR:900 return true;901 default:902 return false;903 }904}905 906static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg)907{908 switch (reg) {909 case REG_ESAI_ETDR:910 case REG_ESAI_ECR:911 case REG_ESAI_TFCR:912 case REG_ESAI_RFCR:913 case REG_ESAI_TX0:914 case REG_ESAI_TX1:915 case REG_ESAI_TX2:916 case REG_ESAI_TX3:917 case REG_ESAI_TX4:918 case REG_ESAI_TX5:919 case REG_ESAI_TSR:920 case REG_ESAI_SAICR:921 case REG_ESAI_TCR:922 case REG_ESAI_TCCR:923 case REG_ESAI_RCR:924 case REG_ESAI_RCCR:925 case REG_ESAI_TSMA:926 case REG_ESAI_TSMB:927 case REG_ESAI_RSMA:928 case REG_ESAI_RSMB:929 case REG_ESAI_PRRC:930 case REG_ESAI_PCRC:931 return true;932 default:933 return false;934 }935}936 937static const struct regmap_config fsl_esai_regmap_config = {938 .reg_bits = 32,939 .reg_stride = 4,940 .val_bits = 32,941 942 .max_register = REG_ESAI_PCRC,943 .reg_defaults = fsl_esai_reg_defaults,944 .num_reg_defaults = ARRAY_SIZE(fsl_esai_reg_defaults),945 .readable_reg = fsl_esai_readable_reg,946 .volatile_reg = fsl_esai_volatile_reg,947 .writeable_reg = fsl_esai_writeable_reg,948 .cache_type = REGCACHE_FLAT,949};950 951static int fsl_esai_runtime_resume(struct device *dev);952static int fsl_esai_runtime_suspend(struct device *dev);953 954static int fsl_esai_probe(struct platform_device *pdev)955{956 struct device_node *np = pdev->dev.of_node;957 struct fsl_esai *esai_priv;958 struct resource *res;959 const __be32 *iprop;960 void __iomem *regs;961 int irq, ret;962 963 esai_priv = devm_kzalloc(&pdev->dev, sizeof(*esai_priv), GFP_KERNEL);964 if (!esai_priv)965 return -ENOMEM;966 967 esai_priv->pdev = pdev;968 snprintf(esai_priv->name, sizeof(esai_priv->name), "%pOFn", np);969 970 esai_priv->soc = of_device_get_match_data(&pdev->dev);971 972 /* Get the addresses and IRQ */973 regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);974 if (IS_ERR(regs))975 return PTR_ERR(regs);976 977 esai_priv->regmap = devm_regmap_init_mmio(&pdev->dev, regs, &fsl_esai_regmap_config);978 if (IS_ERR(esai_priv->regmap)) {979 dev_err(&pdev->dev, "failed to init regmap: %ld\n",980 PTR_ERR(esai_priv->regmap));981 return PTR_ERR(esai_priv->regmap);982 }983 984 esai_priv->coreclk = devm_clk_get(&pdev->dev, "core");985 if (IS_ERR(esai_priv->coreclk)) {986 dev_err(&pdev->dev, "failed to get core clock: %ld\n",987 PTR_ERR(esai_priv->coreclk));988 return PTR_ERR(esai_priv->coreclk);989 }990 991 esai_priv->extalclk = devm_clk_get(&pdev->dev, "extal");992 if (IS_ERR(esai_priv->extalclk))993 dev_warn(&pdev->dev, "failed to get extal clock: %ld\n",994 PTR_ERR(esai_priv->extalclk));995 996 esai_priv->fsysclk = devm_clk_get(&pdev->dev, "fsys");997 if (IS_ERR(esai_priv->fsysclk))998 dev_warn(&pdev->dev, "failed to get fsys clock: %ld\n",999 PTR_ERR(esai_priv->fsysclk));1000 1001 esai_priv->spbaclk = devm_clk_get(&pdev->dev, "spba");1002 if (IS_ERR(esai_priv->spbaclk))1003 dev_warn(&pdev->dev, "failed to get spba clock: %ld\n",1004 PTR_ERR(esai_priv->spbaclk));1005 1006 irq = platform_get_irq(pdev, 0);1007 if (irq < 0)1008 return irq;1009 1010 ret = devm_request_irq(&pdev->dev, irq, esai_isr, IRQF_SHARED,1011 esai_priv->name, esai_priv);1012 if (ret) {1013 dev_err(&pdev->dev, "failed to claim irq %u\n", irq);1014 return ret;1015 }1016 1017 /* Set a default slot number */1018 esai_priv->slots = 2;1019 1020 /* Set a default clock provider state */1021 esai_priv->consumer_mode = true;1022 1023 /* Determine the FIFO depth */1024 iprop = of_get_property(np, "fsl,fifo-depth", NULL);1025 if (iprop)1026 esai_priv->fifo_depth = be32_to_cpup(iprop);1027 else1028 esai_priv->fifo_depth = 64;1029 1030 esai_priv->dma_params_tx.maxburst = 16;1031 esai_priv->dma_params_rx.maxburst = 16;1032 esai_priv->dma_params_tx.addr = res->start + REG_ESAI_ETDR;1033 esai_priv->dma_params_rx.addr = res->start + REG_ESAI_ERDR;1034 1035 esai_priv->synchronous =1036 of_property_read_bool(np, "fsl,esai-synchronous");1037 1038 /* Implement full symmetry for synchronous mode */1039 if (esai_priv->synchronous) {1040 fsl_esai_dai.symmetric_rate = 1;1041 fsl_esai_dai.symmetric_channels = 1;1042 fsl_esai_dai.symmetric_sample_bits = 1;1043 }1044 1045 dev_set_drvdata(&pdev->dev, esai_priv);1046 spin_lock_init(&esai_priv->lock);1047 pm_runtime_enable(&pdev->dev);1048 if (!pm_runtime_enabled(&pdev->dev)) {1049 ret = fsl_esai_runtime_resume(&pdev->dev);1050 if (ret)1051 goto err_pm_disable;1052 }1053 1054 ret = pm_runtime_resume_and_get(&pdev->dev);1055 if (ret < 0)1056 goto err_pm_get_sync;1057 1058 ret = fsl_esai_hw_init(esai_priv);1059 if (ret)1060 goto err_pm_get_sync;1061 1062 esai_priv->tx_mask = 0xFFFFFFFF;1063 esai_priv->rx_mask = 0xFFFFFFFF;1064 1065 /* Clear the TSMA, TSMB, RSMA, RSMB */1066 regmap_write(esai_priv->regmap, REG_ESAI_TSMA, 0);1067 regmap_write(esai_priv->regmap, REG_ESAI_TSMB, 0);1068 regmap_write(esai_priv->regmap, REG_ESAI_RSMA, 0);1069 regmap_write(esai_priv->regmap, REG_ESAI_RSMB, 0);1070 1071 ret = pm_runtime_put_sync(&pdev->dev);1072 if (ret < 0 && ret != -ENOSYS)1073 goto err_pm_get_sync;1074 1075 /*1076 * Register platform component before registering cpu dai for there1077 * is not defer probe for platform component in snd_soc_add_pcm_runtime().1078 */1079 ret = imx_pcm_dma_init(pdev);1080 if (ret) {1081 dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret);1082 goto err_pm_get_sync;1083 }1084 1085 ret = devm_snd_soc_register_component(&pdev->dev, &fsl_esai_component,1086 &fsl_esai_dai, 1);1087 if (ret) {1088 dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);1089 goto err_pm_get_sync;1090 }1091 1092 INIT_WORK(&esai_priv->work, fsl_esai_hw_reset);1093 1094 return ret;1095 1096err_pm_get_sync:1097 if (!pm_runtime_status_suspended(&pdev->dev))1098 fsl_esai_runtime_suspend(&pdev->dev);1099err_pm_disable:1100 pm_runtime_disable(&pdev->dev);1101 return ret;1102}1103 1104static void fsl_esai_remove(struct platform_device *pdev)1105{1106 struct fsl_esai *esai_priv = platform_get_drvdata(pdev);1107 1108 pm_runtime_disable(&pdev->dev);1109 if (!pm_runtime_status_suspended(&pdev->dev))1110 fsl_esai_runtime_suspend(&pdev->dev);1111 1112 cancel_work_sync(&esai_priv->work);1113}1114 1115static const struct of_device_id fsl_esai_dt_ids[] = {1116 { .compatible = "fsl,imx35-esai", .data = &fsl_esai_imx35 },1117 { .compatible = "fsl,vf610-esai", .data = &fsl_esai_vf610 },1118 { .compatible = "fsl,imx6ull-esai", .data = &fsl_esai_imx6ull },1119 {}1120};1121MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids);1122 1123static int fsl_esai_runtime_resume(struct device *dev)1124{1125 struct fsl_esai *esai = dev_get_drvdata(dev);1126 int ret;1127 1128 /*1129 * Some platforms might use the same bit to gate all three or two of1130 * clocks, so keep all clocks open/close at the same time for safety1131 */1132 ret = clk_prepare_enable(esai->coreclk);1133 if (ret)1134 return ret;1135 if (!IS_ERR(esai->spbaclk)) {1136 ret = clk_prepare_enable(esai->spbaclk);1137 if (ret)1138 goto err_spbaclk;1139 }1140 if (!IS_ERR(esai->extalclk)) {1141 ret = clk_prepare_enable(esai->extalclk);1142 if (ret)1143 goto err_extalclk;1144 }1145 if (!IS_ERR(esai->fsysclk)) {1146 ret = clk_prepare_enable(esai->fsysclk);1147 if (ret)1148 goto err_fsysclk;1149 }1150 1151 regcache_cache_only(esai->regmap, false);1152 1153 ret = fsl_esai_register_restore(esai);1154 if (ret)1155 goto err_regcache_sync;1156 1157 return 0;1158 1159err_regcache_sync:1160 if (!IS_ERR(esai->fsysclk))1161 clk_disable_unprepare(esai->fsysclk);1162err_fsysclk:1163 if (!IS_ERR(esai->extalclk))1164 clk_disable_unprepare(esai->extalclk);1165err_extalclk:1166 if (!IS_ERR(esai->spbaclk))1167 clk_disable_unprepare(esai->spbaclk);1168err_spbaclk:1169 clk_disable_unprepare(esai->coreclk);1170 1171 return ret;1172}1173 1174static int fsl_esai_runtime_suspend(struct device *dev)1175{1176 struct fsl_esai *esai = dev_get_drvdata(dev);1177 1178 regcache_cache_only(esai->regmap, true);1179 1180 if (!IS_ERR(esai->fsysclk))1181 clk_disable_unprepare(esai->fsysclk);1182 if (!IS_ERR(esai->extalclk))1183 clk_disable_unprepare(esai->extalclk);1184 if (!IS_ERR(esai->spbaclk))1185 clk_disable_unprepare(esai->spbaclk);1186 clk_disable_unprepare(esai->coreclk);1187 1188 return 0;1189}1190 1191static const struct dev_pm_ops fsl_esai_pm_ops = {1192 SET_RUNTIME_PM_OPS(fsl_esai_runtime_suspend,1193 fsl_esai_runtime_resume,1194 NULL)1195 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,1196 pm_runtime_force_resume)1197};1198 1199static struct platform_driver fsl_esai_driver = {1200 .probe = fsl_esai_probe,1201 .remove = fsl_esai_remove,1202 .driver = {1203 .name = "fsl-esai-dai",1204 .pm = &fsl_esai_pm_ops,1205 .of_match_table = fsl_esai_dt_ids,1206 },1207};1208 1209module_platform_driver(fsl_esai_driver);1210 1211MODULE_AUTHOR("Freescale Semiconductor, Inc.");1212MODULE_DESCRIPTION("Freescale ESAI CPU DAI driver");1213MODULE_LICENSE("GPL v2");1214MODULE_ALIAS("platform:fsl-esai-dai");1215