921 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * atmel_ssc_dai.c -- ALSA SoC ATMEL SSC Audio Layer Platform driver4 *5 * Copyright (C) 2005 SAN People6 * Copyright (C) 2008 Atmel7 *8 * Author: Sedji Gaouaou <sedji.gaouaou@atmel.com>9 * ATMEL CORP.10 *11 * Based on at91-ssc.c by12 * Frank Mandarino <fmandarino@endrelia.com>13 * Based on pxa2xx Platform drivers by14 * Liam Girdwood <lrg@slimlogic.co.uk>15 */16 17#include <linux/init.h>18#include <linux/module.h>19#include <linux/interrupt.h>20#include <linux/device.h>21#include <linux/delay.h>22#include <linux/clk.h>23#include <linux/atmel_pdc.h>24 25#include <linux/atmel-ssc.h>26#include <sound/core.h>27#include <sound/pcm.h>28#include <sound/pcm_params.h>29#include <sound/initval.h>30#include <sound/soc.h>31 32#include "atmel-pcm.h"33#include "atmel_ssc_dai.h"34 35 36#define NUM_SSC_DEVICES 337 38/*39 * SSC PDC registers required by the PCM DMA engine.40 */41static struct atmel_pdc_regs pdc_tx_reg = {42 .xpr = ATMEL_PDC_TPR,43 .xcr = ATMEL_PDC_TCR,44 .xnpr = ATMEL_PDC_TNPR,45 .xncr = ATMEL_PDC_TNCR,46};47 48static struct atmel_pdc_regs pdc_rx_reg = {49 .xpr = ATMEL_PDC_RPR,50 .xcr = ATMEL_PDC_RCR,51 .xnpr = ATMEL_PDC_RNPR,52 .xncr = ATMEL_PDC_RNCR,53};54 55/*56 * SSC & PDC status bits for transmit and receive.57 */58static struct atmel_ssc_mask ssc_tx_mask = {59 .ssc_enable = SSC_BIT(CR_TXEN),60 .ssc_disable = SSC_BIT(CR_TXDIS),61 .ssc_endx = SSC_BIT(SR_ENDTX),62 .ssc_endbuf = SSC_BIT(SR_TXBUFE),63 .ssc_error = SSC_BIT(SR_OVRUN),64 .pdc_enable = ATMEL_PDC_TXTEN,65 .pdc_disable = ATMEL_PDC_TXTDIS,66};67 68static struct atmel_ssc_mask ssc_rx_mask = {69 .ssc_enable = SSC_BIT(CR_RXEN),70 .ssc_disable = SSC_BIT(CR_RXDIS),71 .ssc_endx = SSC_BIT(SR_ENDRX),72 .ssc_endbuf = SSC_BIT(SR_RXBUFF),73 .ssc_error = SSC_BIT(SR_OVRUN),74 .pdc_enable = ATMEL_PDC_RXTEN,75 .pdc_disable = ATMEL_PDC_RXTDIS,76};77 78 79/*80 * DMA parameters.81 */82static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {83 {{84 .name = "SSC0 PCM out",85 .pdc = &pdc_tx_reg,86 .mask = &ssc_tx_mask,87 },88 {89 .name = "SSC0 PCM in",90 .pdc = &pdc_rx_reg,91 .mask = &ssc_rx_mask,92 } },93 {{94 .name = "SSC1 PCM out",95 .pdc = &pdc_tx_reg,96 .mask = &ssc_tx_mask,97 },98 {99 .name = "SSC1 PCM in",100 .pdc = &pdc_rx_reg,101 .mask = &ssc_rx_mask,102 } },103 {{104 .name = "SSC2 PCM out",105 .pdc = &pdc_tx_reg,106 .mask = &ssc_tx_mask,107 },108 {109 .name = "SSC2 PCM in",110 .pdc = &pdc_rx_reg,111 .mask = &ssc_rx_mask,112 } },113};114 115 116static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = {117 {118 .name = "ssc0",119 .dir_mask = SSC_DIR_MASK_UNUSED,120 .initialized = 0,121 },122 {123 .name = "ssc1",124 .dir_mask = SSC_DIR_MASK_UNUSED,125 .initialized = 0,126 },127 {128 .name = "ssc2",129 .dir_mask = SSC_DIR_MASK_UNUSED,130 .initialized = 0,131 },132};133 134 135/*136 * SSC interrupt handler. Passes PDC interrupts to the DMA137 * interrupt handler in the PCM driver.138 */139static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id)140{141 struct atmel_ssc_info *ssc_p = dev_id;142 struct atmel_pcm_dma_params *dma_params;143 u32 ssc_sr;144 u32 ssc_substream_mask;145 int i;146 147 ssc_sr = (unsigned long)ssc_readl(ssc_p->ssc->regs, SR)148 & (unsigned long)ssc_readl(ssc_p->ssc->regs, IMR);149 150 /*151 * Loop through the substreams attached to this SSC. If152 * a DMA-related interrupt occurred on that substream, call153 * the DMA interrupt handler function, if one has been154 * registered in the dma_params structure by the PCM driver.155 */156 for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) {157 dma_params = ssc_p->dma_params[i];158 159 if ((dma_params != NULL) &&160 (dma_params->dma_intr_handler != NULL)) {161 ssc_substream_mask = (dma_params->mask->ssc_endx |162 dma_params->mask->ssc_endbuf);163 if (ssc_sr & ssc_substream_mask) {164 dma_params->dma_intr_handler(ssc_sr,165 dma_params->166 substream);167 }168 }169 }170 171 return IRQ_HANDLED;172}173 174/*175 * When the bit clock is input, limit the maximum rate according to the176 * Serial Clock Ratio Considerations section from the SSC documentation:177 *178 * The Transmitter and the Receiver can be programmed to operate179 * with the clock signals provided on either the TK or RK pins.180 * This allows the SSC to support many slave-mode data transfers.181 * In this case, the maximum clock speed allowed on the RK pin is:182 * - Peripheral clock divided by 2 if Receiver Frame Synchro is input183 * - Peripheral clock divided by 3 if Receiver Frame Synchro is output184 * In addition, the maximum clock speed allowed on the TK pin is:185 * - Peripheral clock divided by 6 if Transmit Frame Synchro is input186 * - Peripheral clock divided by 2 if Transmit Frame Synchro is output187 *188 * When the bit clock is output, limit the rate according to the189 * SSC divider restrictions.190 */191static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params,192 struct snd_pcm_hw_rule *rule)193{194 struct atmel_ssc_info *ssc_p = rule->private;195 struct ssc_device *ssc = ssc_p->ssc;196 struct snd_interval *i = hw_param_interval(params, rule->var);197 struct snd_interval t;198 struct snd_ratnum r = {199 .den_min = 1,200 .den_max = 4095,201 .den_step = 1,202 };203 unsigned int num = 0, den = 0;204 int frame_size;205 int mck_div = 2;206 int ret;207 208 frame_size = snd_soc_params_to_frame_size(params);209 if (frame_size < 0)210 return frame_size;211 212 switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {213 case SND_SOC_DAIFMT_BC_FP:214 if ((ssc_p->dir_mask & SSC_DIR_MASK_CAPTURE)215 && ssc->clk_from_rk_pin)216 /* Receiver Frame Synchro (i.e. capture)217 * is output (format is _CFS) and the RK pin218 * is used for input (format is _CBM_).219 */220 mck_div = 3;221 break;222 223 case SND_SOC_DAIFMT_BC_FC:224 if ((ssc_p->dir_mask & SSC_DIR_MASK_PLAYBACK)225 && !ssc->clk_from_rk_pin)226 /* Transmit Frame Synchro (i.e. playback)227 * is input (format is _CFM) and the TK pin228 * is used for input (format _CBM_ but not229 * using the RK pin).230 */231 mck_div = 6;232 break;233 }234 235 switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {236 case SND_SOC_DAIFMT_BP_FP:237 r.num = ssc_p->mck_rate / mck_div / frame_size;238 239 ret = snd_interval_ratnum(i, 1, &r, &num, &den);240 if (ret >= 0 && den && rule->var == SNDRV_PCM_HW_PARAM_RATE) {241 params->rate_num = num;242 params->rate_den = den;243 }244 break;245 246 case SND_SOC_DAIFMT_BC_FP:247 case SND_SOC_DAIFMT_BC_FC:248 t.min = 8000;249 t.max = ssc_p->mck_rate / mck_div / frame_size;250 t.openmin = t.openmax = 0;251 t.integer = 0;252 ret = snd_interval_refine(i, &t);253 break;254 255 default:256 ret = -EINVAL;257 break;258 }259 260 return ret;261}262 263/*-------------------------------------------------------------------------*\264 * DAI functions265\*-------------------------------------------------------------------------*/266/*267 * Startup. Only that one substream allowed in each direction.268 */269static int atmel_ssc_startup(struct snd_pcm_substream *substream,270 struct snd_soc_dai *dai)271{272 struct platform_device *pdev = to_platform_device(dai->dev);273 struct atmel_ssc_info *ssc_p = &ssc_info[pdev->id];274 struct atmel_pcm_dma_params *dma_params;275 int dir, dir_mask;276 int ret;277 278 pr_debug("atmel_ssc_startup: SSC_SR=0x%x\n",279 ssc_readl(ssc_p->ssc->regs, SR));280 281 /* Enable PMC peripheral clock for this SSC */282 pr_debug("atmel_ssc_dai: Starting clock\n");283 ret = clk_enable(ssc_p->ssc->clk);284 if (ret)285 return ret;286 287 ssc_p->mck_rate = clk_get_rate(ssc_p->ssc->clk);288 289 /* Reset the SSC unless initialized to keep it in a clean state */290 if (!ssc_p->initialized)291 ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));292 293 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {294 dir = 0;295 dir_mask = SSC_DIR_MASK_PLAYBACK;296 } else {297 dir = 1;298 dir_mask = SSC_DIR_MASK_CAPTURE;299 }300 301 ret = snd_pcm_hw_rule_add(substream->runtime, 0,302 SNDRV_PCM_HW_PARAM_RATE,303 atmel_ssc_hw_rule_rate,304 ssc_p,305 SNDRV_PCM_HW_PARAM_FRAME_BITS,306 SNDRV_PCM_HW_PARAM_CHANNELS, -1);307 if (ret < 0) {308 dev_err(dai->dev, "Failed to specify rate rule: %d\n", ret);309 return ret;310 }311 312 dma_params = &ssc_dma_params[pdev->id][dir];313 dma_params->ssc = ssc_p->ssc;314 dma_params->substream = substream;315 316 ssc_p->dma_params[dir] = dma_params;317 318 snd_soc_dai_set_dma_data(dai, substream, dma_params);319 320 if (ssc_p->dir_mask & dir_mask)321 return -EBUSY;322 323 ssc_p->dir_mask |= dir_mask;324 325 return 0;326}327 328/*329 * Shutdown. Clear DMA parameters and shutdown the SSC if there330 * are no other substreams open.331 */332static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,333 struct snd_soc_dai *dai)334{335 struct platform_device *pdev = to_platform_device(dai->dev);336 struct atmel_ssc_info *ssc_p = &ssc_info[pdev->id];337 struct atmel_pcm_dma_params *dma_params;338 int dir, dir_mask;339 340 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)341 dir = 0;342 else343 dir = 1;344 345 dma_params = ssc_p->dma_params[dir];346 347 if (dma_params != NULL) {348 dma_params->ssc = NULL;349 dma_params->substream = NULL;350 ssc_p->dma_params[dir] = NULL;351 }352 353 dir_mask = 1 << dir;354 355 ssc_p->dir_mask &= ~dir_mask;356 if (!ssc_p->dir_mask) {357 if (ssc_p->initialized) {358 free_irq(ssc_p->ssc->irq, ssc_p);359 ssc_p->initialized = 0;360 }361 362 /* Reset the SSC */363 ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));364 /* Clear the SSC dividers */365 ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0;366 ssc_p->forced_divider = 0;367 }368 369 /* Shutdown the SSC clock. */370 pr_debug("atmel_ssc_dai: Stopping clock\n");371 clk_disable(ssc_p->ssc->clk);372}373 374 375/*376 * Record the DAI format for use in hw_params().377 */378static int atmel_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai,379 unsigned int fmt)380{381 struct platform_device *pdev = to_platform_device(cpu_dai->dev);382 struct atmel_ssc_info *ssc_p = &ssc_info[pdev->id];383 384 ssc_p->daifmt = fmt;385 return 0;386}387 388/*389 * Record SSC clock dividers for use in hw_params().390 */391static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,392 int div_id, int div)393{394 struct platform_device *pdev = to_platform_device(cpu_dai->dev);395 struct atmel_ssc_info *ssc_p = &ssc_info[pdev->id];396 397 switch (div_id) {398 case ATMEL_SSC_CMR_DIV:399 /*400 * The same master clock divider is used for both401 * transmit and receive, so if a value has already402 * been set, it must match this value.403 */404 if (ssc_p->dir_mask !=405 (SSC_DIR_MASK_PLAYBACK | SSC_DIR_MASK_CAPTURE))406 ssc_p->cmr_div = div;407 else if (ssc_p->cmr_div == 0)408 ssc_p->cmr_div = div;409 else410 if (div != ssc_p->cmr_div)411 return -EBUSY;412 ssc_p->forced_divider |= BIT(ATMEL_SSC_CMR_DIV);413 break;414 415 case ATMEL_SSC_TCMR_PERIOD:416 ssc_p->tcmr_period = div;417 ssc_p->forced_divider |= BIT(ATMEL_SSC_TCMR_PERIOD);418 break;419 420 case ATMEL_SSC_RCMR_PERIOD:421 ssc_p->rcmr_period = div;422 ssc_p->forced_divider |= BIT(ATMEL_SSC_RCMR_PERIOD);423 break;424 425 default:426 return -EINVAL;427 }428 429 return 0;430}431 432/* Is the cpu-dai master of the frame clock? */433static int atmel_ssc_cfs(struct atmel_ssc_info *ssc_p)434{435 switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {436 case SND_SOC_DAIFMT_BC_FP:437 case SND_SOC_DAIFMT_BP_FP:438 return 1;439 }440 return 0;441}442 443/* Is the cpu-dai master of the bit clock? */444static int atmel_ssc_cbs(struct atmel_ssc_info *ssc_p)445{446 switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {447 case SND_SOC_DAIFMT_BP_FC:448 case SND_SOC_DAIFMT_BP_FP:449 return 1;450 }451 return 0;452}453 454/*455 * Configure the SSC.456 */457static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,458 struct snd_pcm_hw_params *params,459 struct snd_soc_dai *dai)460{461 struct platform_device *pdev = to_platform_device(dai->dev);462 int id = pdev->id;463 struct atmel_ssc_info *ssc_p = &ssc_info[id];464 struct ssc_device *ssc = ssc_p->ssc;465 struct atmel_pcm_dma_params *dma_params;466 int dir, channels, bits;467 u32 tfmr, rfmr, tcmr, rcmr;468 int ret;469 int fslen, fslen_ext, fs_osync, fs_edge;470 u32 cmr_div;471 u32 tcmr_period;472 u32 rcmr_period;473 474 /*475 * Currently, there is only one set of dma params for476 * each direction. If more are added, this code will477 * have to be changed to select the proper set.478 */479 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)480 dir = 0;481 else482 dir = 1;483 484 /*485 * If the cpu dai should provide BCLK, but noone has provided the486 * divider needed for that to work, fall back to something sensible.487 */488 cmr_div = ssc_p->cmr_div;489 if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_CMR_DIV)) &&490 atmel_ssc_cbs(ssc_p)) {491 int bclk_rate = snd_soc_params_to_bclk(params);492 493 if (bclk_rate < 0) {494 dev_err(dai->dev, "unable to calculate cmr_div: %d\n",495 bclk_rate);496 return bclk_rate;497 }498 499 cmr_div = DIV_ROUND_CLOSEST(ssc_p->mck_rate, 2 * bclk_rate);500 }501 502 /*503 * If the cpu dai should provide LRCLK, but noone has provided the504 * dividers needed for that to work, fall back to something sensible.505 */506 tcmr_period = ssc_p->tcmr_period;507 rcmr_period = ssc_p->rcmr_period;508 if (atmel_ssc_cfs(ssc_p)) {509 int frame_size = snd_soc_params_to_frame_size(params);510 511 if (frame_size < 0) {512 dev_err(dai->dev,513 "unable to calculate tx/rx cmr_period: %d\n",514 frame_size);515 return frame_size;516 }517 518 if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_TCMR_PERIOD)))519 tcmr_period = frame_size / 2 - 1;520 if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_RCMR_PERIOD)))521 rcmr_period = frame_size / 2 - 1;522 }523 524 dma_params = ssc_p->dma_params[dir];525 526 channels = params_channels(params);527 528 /*529 * Determine sample size in bits and the PDC increment.530 */531 switch (params_format(params)) {532 case SNDRV_PCM_FORMAT_S8:533 bits = 8;534 dma_params->pdc_xfer_size = 1;535 break;536 case SNDRV_PCM_FORMAT_S16_LE:537 bits = 16;538 dma_params->pdc_xfer_size = 2;539 break;540 case SNDRV_PCM_FORMAT_S24_LE:541 bits = 24;542 dma_params->pdc_xfer_size = 4;543 break;544 case SNDRV_PCM_FORMAT_S32_LE:545 bits = 32;546 dma_params->pdc_xfer_size = 4;547 break;548 default:549 printk(KERN_WARNING "atmel_ssc_dai: unsupported PCM format");550 return -EINVAL;551 }552 553 /*554 * Compute SSC register settings.555 */556 557 fslen_ext = (bits - 1) / 16;558 fslen = (bits - 1) % 16;559 560 switch (ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) {561 562 case SND_SOC_DAIFMT_LEFT_J:563 fs_osync = SSC_FSOS_POSITIVE;564 fs_edge = SSC_START_RISING_RF;565 566 rcmr = SSC_BF(RCMR_STTDLY, 0);567 tcmr = SSC_BF(TCMR_STTDLY, 0);568 569 break;570 571 case SND_SOC_DAIFMT_I2S:572 fs_osync = SSC_FSOS_NEGATIVE;573 fs_edge = SSC_START_FALLING_RF;574 575 rcmr = SSC_BF(RCMR_STTDLY, 1);576 tcmr = SSC_BF(TCMR_STTDLY, 1);577 578 break;579 580 case SND_SOC_DAIFMT_DSP_A:581 /*582 * DSP/PCM Mode A format583 *584 * Data is transferred on first BCLK after LRC pulse rising585 * edge.If stereo, the right channel data is contiguous with586 * the left channel data.587 */588 fs_osync = SSC_FSOS_POSITIVE;589 fs_edge = SSC_START_RISING_RF;590 fslen = fslen_ext = 0;591 592 rcmr = SSC_BF(RCMR_STTDLY, 1);593 tcmr = SSC_BF(TCMR_STTDLY, 1);594 595 break;596 597 default:598 printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n",599 ssc_p->daifmt);600 return -EINVAL;601 }602 603 if (!atmel_ssc_cfs(ssc_p)) {604 fslen = fslen_ext = 0;605 rcmr_period = tcmr_period = 0;606 fs_osync = SSC_FSOS_NONE;607 }608 609 rcmr |= SSC_BF(RCMR_START, fs_edge);610 tcmr |= SSC_BF(TCMR_START, fs_edge);611 612 if (atmel_ssc_cbs(ssc_p)) {613 /*614 * SSC provides BCLK615 *616 * The SSC transmit and receive clocks are generated from the617 * MCK divider, and the BCLK signal is output618 * on the SSC TK line.619 */620 rcmr |= SSC_BF(RCMR_CKS, SSC_CKS_DIV)621 | SSC_BF(RCMR_CKO, SSC_CKO_NONE);622 623 tcmr |= SSC_BF(TCMR_CKS, SSC_CKS_DIV)624 | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS);625 } else {626 rcmr |= SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ?627 SSC_CKS_PIN : SSC_CKS_CLOCK)628 | SSC_BF(RCMR_CKO, SSC_CKO_NONE);629 630 tcmr |= SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ?631 SSC_CKS_CLOCK : SSC_CKS_PIN)632 | SSC_BF(TCMR_CKO, SSC_CKO_NONE);633 }634 635 rcmr |= SSC_BF(RCMR_PERIOD, rcmr_period)636 | SSC_BF(RCMR_CKI, SSC_CKI_RISING);637 638 tcmr |= SSC_BF(TCMR_PERIOD, tcmr_period)639 | SSC_BF(TCMR_CKI, SSC_CKI_FALLING);640 641 rfmr = SSC_BF(RFMR_FSLEN_EXT, fslen_ext)642 | SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)643 | SSC_BF(RFMR_FSOS, fs_osync)644 | SSC_BF(RFMR_FSLEN, fslen)645 | SSC_BF(RFMR_DATNB, (channels - 1))646 | SSC_BIT(RFMR_MSBF)647 | SSC_BF(RFMR_LOOP, 0)648 | SSC_BF(RFMR_DATLEN, (bits - 1));649 650 tfmr = SSC_BF(TFMR_FSLEN_EXT, fslen_ext)651 | SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)652 | SSC_BF(TFMR_FSDEN, 0)653 | SSC_BF(TFMR_FSOS, fs_osync)654 | SSC_BF(TFMR_FSLEN, fslen)655 | SSC_BF(TFMR_DATNB, (channels - 1))656 | SSC_BIT(TFMR_MSBF)657 | SSC_BF(TFMR_DATDEF, 0)658 | SSC_BF(TFMR_DATLEN, (bits - 1));659 660 if (fslen_ext && !ssc->pdata->has_fslen_ext) {661 dev_err(dai->dev, "sample size %d is too large for SSC device\n",662 bits);663 return -EINVAL;664 }665 666 pr_debug("atmel_ssc_hw_params: "667 "RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n",668 rcmr, rfmr, tcmr, tfmr);669 670 if (!ssc_p->initialized) {671 if (!ssc_p->ssc->pdata->use_dma) {672 ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0);673 ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0);674 ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0);675 ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0);676 677 ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0);678 ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0);679 ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0);680 ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0);681 }682 683 ret = request_irq(ssc_p->ssc->irq, atmel_ssc_interrupt, 0,684 ssc_p->name, ssc_p);685 if (ret < 0) {686 printk(KERN_WARNING687 "atmel_ssc_dai: request_irq failure\n");688 pr_debug("Atmel_ssc_dai: Stopping clock\n");689 clk_disable(ssc_p->ssc->clk);690 return ret;691 }692 693 ssc_p->initialized = 1;694 }695 696 /* set SSC clock mode register */697 ssc_writel(ssc_p->ssc->regs, CMR, cmr_div);698 699 /* set receive clock mode and format */700 ssc_writel(ssc_p->ssc->regs, RCMR, rcmr);701 ssc_writel(ssc_p->ssc->regs, RFMR, rfmr);702 703 /* set transmit clock mode and format */704 ssc_writel(ssc_p->ssc->regs, TCMR, tcmr);705 ssc_writel(ssc_p->ssc->regs, TFMR, tfmr);706 707 pr_debug("atmel_ssc_dai,hw_params: SSC initialized\n");708 return 0;709}710 711 712static int atmel_ssc_prepare(struct snd_pcm_substream *substream,713 struct snd_soc_dai *dai)714{715 struct platform_device *pdev = to_platform_device(dai->dev);716 struct atmel_ssc_info *ssc_p = &ssc_info[pdev->id];717 struct atmel_pcm_dma_params *dma_params;718 int dir;719 720 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)721 dir = 0;722 else723 dir = 1;724 725 dma_params = ssc_p->dma_params[dir];726 727 ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_disable);728 ssc_writel(ssc_p->ssc->regs, IDR, dma_params->mask->ssc_error);729 730 pr_debug("%s enabled SSC_SR=0x%08x\n",731 dir ? "receive" : "transmit",732 ssc_readl(ssc_p->ssc->regs, SR));733 return 0;734}735 736static int atmel_ssc_trigger(struct snd_pcm_substream *substream,737 int cmd, struct snd_soc_dai *dai)738{739 struct platform_device *pdev = to_platform_device(dai->dev);740 struct atmel_ssc_info *ssc_p = &ssc_info[pdev->id];741 struct atmel_pcm_dma_params *dma_params;742 int dir;743 744 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)745 dir = 0;746 else747 dir = 1;748 749 dma_params = ssc_p->dma_params[dir];750 751 switch (cmd) {752 case SNDRV_PCM_TRIGGER_START:753 case SNDRV_PCM_TRIGGER_RESUME:754 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:755 ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_enable);756 break;757 default:758 ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_disable);759 break;760 }761 762 return 0;763}764 765static int atmel_ssc_suspend(struct snd_soc_component *component)766{767 struct atmel_ssc_info *ssc_p;768 struct platform_device *pdev = to_platform_device(component->dev);769 770 if (!snd_soc_component_active(component))771 return 0;772 773 ssc_p = &ssc_info[pdev->id];774 775 /* Save the status register before disabling transmit and receive */776 ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR);777 ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_TXDIS) | SSC_BIT(CR_RXDIS));778 779 /* Save the current interrupt mask, then disable unmasked interrupts */780 ssc_p->ssc_state.ssc_imr = ssc_readl(ssc_p->ssc->regs, IMR);781 ssc_writel(ssc_p->ssc->regs, IDR, ssc_p->ssc_state.ssc_imr);782 783 ssc_p->ssc_state.ssc_cmr = ssc_readl(ssc_p->ssc->regs, CMR);784 ssc_p->ssc_state.ssc_rcmr = ssc_readl(ssc_p->ssc->regs, RCMR);785 ssc_p->ssc_state.ssc_rfmr = ssc_readl(ssc_p->ssc->regs, RFMR);786 ssc_p->ssc_state.ssc_tcmr = ssc_readl(ssc_p->ssc->regs, TCMR);787 ssc_p->ssc_state.ssc_tfmr = ssc_readl(ssc_p->ssc->regs, TFMR);788 789 return 0;790}791 792static int atmel_ssc_resume(struct snd_soc_component *component)793{794 struct atmel_ssc_info *ssc_p;795 struct platform_device *pdev = to_platform_device(component->dev);796 u32 cr;797 798 if (!snd_soc_component_active(component))799 return 0;800 801 ssc_p = &ssc_info[pdev->id];802 803 /* restore SSC register settings */804 ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr);805 ssc_writel(ssc_p->ssc->regs, TCMR, ssc_p->ssc_state.ssc_tcmr);806 ssc_writel(ssc_p->ssc->regs, RFMR, ssc_p->ssc_state.ssc_rfmr);807 ssc_writel(ssc_p->ssc->regs, RCMR, ssc_p->ssc_state.ssc_rcmr);808 ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->ssc_state.ssc_cmr);809 810 /* re-enable interrupts */811 ssc_writel(ssc_p->ssc->regs, IER, ssc_p->ssc_state.ssc_imr);812 813 /* Re-enable receive and transmit as appropriate */814 cr = 0;815 cr |=816 (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_RXEN)) ? SSC_BIT(CR_RXEN) : 0;817 cr |=818 (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_TXEN)) ? SSC_BIT(CR_TXEN) : 0;819 ssc_writel(ssc_p->ssc->regs, CR, cr);820 821 return 0;822}823 824#define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\825 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)826 827static const struct snd_soc_dai_ops atmel_ssc_dai_ops = {828 .startup = atmel_ssc_startup,829 .shutdown = atmel_ssc_shutdown,830 .prepare = atmel_ssc_prepare,831 .trigger = atmel_ssc_trigger,832 .hw_params = atmel_ssc_hw_params,833 .set_fmt = atmel_ssc_set_dai_fmt,834 .set_clkdiv = atmel_ssc_set_dai_clkdiv,835};836 837static struct snd_soc_dai_driver atmel_ssc_dai = {838 .playback = {839 .channels_min = 1,840 .channels_max = 2,841 .rates = SNDRV_PCM_RATE_CONTINUOUS,842 .rate_min = 8000,843 .rate_max = 384000,844 .formats = ATMEL_SSC_FORMATS,},845 .capture = {846 .channels_min = 1,847 .channels_max = 2,848 .rates = SNDRV_PCM_RATE_CONTINUOUS,849 .rate_min = 8000,850 .rate_max = 384000,851 .formats = ATMEL_SSC_FORMATS,},852 .ops = &atmel_ssc_dai_ops,853};854 855static const struct snd_soc_component_driver atmel_ssc_component = {856 .name = "atmel-ssc",857 .suspend = pm_ptr(atmel_ssc_suspend),858 .resume = pm_ptr(atmel_ssc_resume),859 .legacy_dai_naming = 1,860};861 862static int asoc_ssc_init(struct device *dev)863{864 struct ssc_device *ssc = dev_get_drvdata(dev);865 int ret;866 867 ret = devm_snd_soc_register_component(dev, &atmel_ssc_component,868 &atmel_ssc_dai, 1);869 if (ret) {870 dev_err(dev, "Could not register DAI: %d\n", ret);871 return ret;872 }873 874 if (ssc->pdata->use_dma)875 ret = atmel_pcm_dma_platform_register(dev);876 else877 ret = atmel_pcm_pdc_platform_register(dev);878 879 if (ret) {880 dev_err(dev, "Could not register PCM: %d\n", ret);881 return ret;882 }883 884 return 0;885}886 887/**888 * atmel_ssc_set_audio - Allocate the specified SSC for audio use.889 * @ssc_id: SSD ID in [0, NUM_SSC_DEVICES[890 */891int atmel_ssc_set_audio(int ssc_id)892{893 struct ssc_device *ssc;894 895 /* If we can grab the SSC briefly to parent the DAI device off it */896 ssc = ssc_request(ssc_id);897 if (IS_ERR(ssc)) {898 pr_err("Unable to parent ASoC SSC DAI on SSC: %ld\n",899 PTR_ERR(ssc));900 return PTR_ERR(ssc);901 } else {902 ssc_info[ssc_id].ssc = ssc;903 }904 905 return asoc_ssc_init(&ssc->pdev->dev);906}907EXPORT_SYMBOL_GPL(atmel_ssc_set_audio);908 909void atmel_ssc_put_audio(int ssc_id)910{911 struct ssc_device *ssc = ssc_info[ssc_id].ssc;912 913 ssc_free(ssc);914}915EXPORT_SYMBOL_GPL(atmel_ssc_put_audio);916 917/* Module information */918MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com");919MODULE_DESCRIPTION("ATMEL SSC ASoC Interface");920MODULE_LICENSE("GPL");921