189dd0842SJon Smirl /* 289dd0842SJon Smirl * Freescale MPC5200 PSC DMA 389dd0842SJon Smirl * ALSA SoC Platform driver 489dd0842SJon Smirl * 589dd0842SJon Smirl * Copyright (C) 2008 Secret Lab Technologies Ltd. 6dbcc3475SJon Smirl * Copyright (C) 2009 Jon Smirl, Digispeaker 789dd0842SJon Smirl */ 889dd0842SJon Smirl 989dd0842SJon Smirl #include <linux/module.h> 1089dd0842SJon Smirl #include <linux/of_device.h> 115a0e3ad6STejun Heo #include <linux/slab.h> 12f0fba2adSLiam Girdwood #include <linux/of_platform.h> 1389dd0842SJon Smirl 1489dd0842SJon Smirl #include <sound/soc.h> 1589dd0842SJon Smirl 1689dd0842SJon Smirl #include <sysdev/bestcomm/bestcomm.h> 1789dd0842SJon Smirl #include <sysdev/bestcomm/gen_bd.h> 1889dd0842SJon Smirl #include <asm/mpc52xx_psc.h> 1989dd0842SJon Smirl 2089dd0842SJon Smirl #include "mpc5200_dma.h" 2189dd0842SJon Smirl 2289dd0842SJon Smirl /* 2389dd0842SJon Smirl * Interrupt handlers 2489dd0842SJon Smirl */ 25cebe7767SJon Smirl static irqreturn_t psc_dma_status_irq(int irq, void *_psc_dma) 2689dd0842SJon Smirl { 27cebe7767SJon Smirl struct psc_dma *psc_dma = _psc_dma; 28cebe7767SJon Smirl struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; 2989dd0842SJon Smirl u16 isr; 3089dd0842SJon Smirl 3189dd0842SJon Smirl isr = in_be16(®s->mpc52xx_psc_isr); 3289dd0842SJon Smirl 3389dd0842SJon Smirl /* Playback underrun error */ 34cebe7767SJon Smirl if (psc_dma->playback.active && (isr & MPC52xx_PSC_IMR_TXEMP)) 35cebe7767SJon Smirl psc_dma->stats.underrun_count++; 3689dd0842SJon Smirl 3789dd0842SJon Smirl /* Capture overrun error */ 38cebe7767SJon Smirl if (psc_dma->capture.active && (isr & MPC52xx_PSC_IMR_ORERR)) 39cebe7767SJon Smirl psc_dma->stats.overrun_count++; 4089dd0842SJon Smirl 41dbcc3475SJon Smirl out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT); 4289dd0842SJon Smirl 4389dd0842SJon Smirl return IRQ_HANDLED; 4489dd0842SJon Smirl } 4589dd0842SJon Smirl 4689dd0842SJon Smirl /** 47cebe7767SJon Smirl * psc_dma_bcom_enqueue_next_buffer - Enqueue another audio buffer 4889dd0842SJon Smirl * @s: pointer to stream private data structure 4989dd0842SJon Smirl * 5089dd0842SJon Smirl * Enqueues another audio period buffer into the bestcomm queue. 5189dd0842SJon Smirl * 5289dd0842SJon Smirl * Note: The routine must only be called when there is space available in 5389dd0842SJon Smirl * the queue. Otherwise the enqueue will fail and the audio ring buffer 5489dd0842SJon Smirl * will get out of sync 5589dd0842SJon Smirl */ 56cebe7767SJon Smirl static void psc_dma_bcom_enqueue_next_buffer(struct psc_dma_stream *s) 5789dd0842SJon Smirl { 5889dd0842SJon Smirl struct bcom_bd *bd; 5989dd0842SJon Smirl 6089dd0842SJon Smirl /* Prepare and enqueue the next buffer descriptor */ 6189dd0842SJon Smirl bd = bcom_prepare_next_buffer(s->bcom_task); 6289dd0842SJon Smirl bd->status = s->period_bytes; 638f159d72SGrant Likely bd->data[0] = s->runtime->dma_addr + (s->period_next * s->period_bytes); 6489dd0842SJon Smirl bcom_submit_next_buffer(s->bcom_task, NULL); 6589dd0842SJon Smirl 6689dd0842SJon Smirl /* Update for next period */ 678f159d72SGrant Likely s->period_next = (s->period_next + 1) % s->runtime->periods; 6889dd0842SJon Smirl } 6989dd0842SJon Smirl 7089dd0842SJon Smirl /* Bestcomm DMA irq handler */ 71a68cc8daSGrant Likely static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream) 7289dd0842SJon Smirl { 73dbcc3475SJon Smirl struct psc_dma_stream *s = _psc_dma_stream; 7489dd0842SJon Smirl 75dbcc3475SJon Smirl spin_lock(&s->psc_dma->lock); 76dbcc3475SJon Smirl /* For each finished period, dequeue the completed period buffer 77dbcc3475SJon Smirl * and enqueue a new one in it's place. */ 78dbcc3475SJon Smirl while (bcom_buffer_done(s->bcom_task)) { 79dbcc3475SJon Smirl bcom_retrieve_buffer(s->bcom_task, NULL, NULL); 8089dd0842SJon Smirl 818f159d72SGrant Likely s->period_current = (s->period_current+1) % s->runtime->periods; 82c4878274SGrant Likely s->period_count++; 83dbcc3475SJon Smirl 84dbcc3475SJon Smirl psc_dma_bcom_enqueue_next_buffer(s); 8589dd0842SJon Smirl } 86dbcc3475SJon Smirl spin_unlock(&s->psc_dma->lock); 87dbcc3475SJon Smirl 88dbcc3475SJon Smirl /* If the stream is active, then also inform the PCM middle layer 89dbcc3475SJon Smirl * of the period finished event. */ 90dbcc3475SJon Smirl if (s->active) 91dbcc3475SJon Smirl snd_pcm_period_elapsed(s->stream); 92dbcc3475SJon Smirl 93dbcc3475SJon Smirl return IRQ_HANDLED; 9489dd0842SJon Smirl } 9589dd0842SJon Smirl 96dbcc3475SJon Smirl static int psc_dma_hw_free(struct snd_pcm_substream *substream) 9789dd0842SJon Smirl { 9889dd0842SJon Smirl snd_pcm_set_runtime_buffer(substream, NULL); 9989dd0842SJon Smirl return 0; 10089dd0842SJon Smirl } 10189dd0842SJon Smirl 10289dd0842SJon Smirl /** 103cebe7767SJon Smirl * psc_dma_trigger: start and stop the DMA transfer. 10489dd0842SJon Smirl * 10589dd0842SJon Smirl * This function is called by ALSA to start, stop, pause, and resume the DMA 10689dd0842SJon Smirl * transfer of data. 10789dd0842SJon Smirl */ 108dbcc3475SJon Smirl static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd) 10989dd0842SJon Smirl { 11089dd0842SJon Smirl struct snd_soc_pcm_runtime *rtd = substream->private_data; 111f0fba2adSLiam Girdwood struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai); 11289dd0842SJon Smirl struct snd_pcm_runtime *runtime = substream->runtime; 1131d8222e8SGrant Likely struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma); 114cebe7767SJon Smirl struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; 11589dd0842SJon Smirl u16 imr; 11689dd0842SJon Smirl unsigned long flags; 117dbcc3475SJon Smirl int i; 11889dd0842SJon Smirl 11989dd0842SJon Smirl switch (cmd) { 12089dd0842SJon Smirl case SNDRV_PCM_TRIGGER_START: 121c4878274SGrant Likely dev_dbg(psc_dma->dev, "START: stream=%i fbits=%u ps=%u #p=%u\n", 122c4878274SGrant Likely substream->pstr->stream, runtime->frame_bits, 123c4878274SGrant Likely (int)runtime->period_size, runtime->periods); 12489dd0842SJon Smirl s->period_bytes = frames_to_bytes(runtime, 12589dd0842SJon Smirl runtime->period_size); 1268f159d72SGrant Likely s->period_next = 0; 1278f159d72SGrant Likely s->period_current = 0; 12889dd0842SJon Smirl s->active = 1; 129c4878274SGrant Likely s->period_count = 0; 130dbcc3475SJon Smirl s->runtime = runtime; 131dbcc3475SJon Smirl 132dbcc3475SJon Smirl /* Fill up the bestcomm bd queue and enable DMA. 133dbcc3475SJon Smirl * This will begin filling the PSC's fifo. 134dbcc3475SJon Smirl */ 135dbcc3475SJon Smirl spin_lock_irqsave(&psc_dma->lock, flags); 136dbcc3475SJon Smirl 137d56b6eb6SGrant Likely if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) 138dbcc3475SJon Smirl bcom_gen_bd_rx_reset(s->bcom_task); 139d56b6eb6SGrant Likely else 140d56b6eb6SGrant Likely bcom_gen_bd_tx_reset(s->bcom_task); 141d56b6eb6SGrant Likely 142dbcc3475SJon Smirl for (i = 0; i < runtime->periods; i++) 143dbcc3475SJon Smirl if (!bcom_queue_full(s->bcom_task)) 144dbcc3475SJon Smirl psc_dma_bcom_enqueue_next_buffer(s); 14589dd0842SJon Smirl 14689dd0842SJon Smirl bcom_enable(s->bcom_task); 147cebe7767SJon Smirl spin_unlock_irqrestore(&psc_dma->lock, flags); 14889dd0842SJon Smirl 149dbcc3475SJon Smirl out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT); 150dbcc3475SJon Smirl 15189dd0842SJon Smirl break; 15289dd0842SJon Smirl 15389dd0842SJon Smirl case SNDRV_PCM_TRIGGER_STOP: 154c4878274SGrant Likely dev_dbg(psc_dma->dev, "STOP: stream=%i periods_count=%i\n", 155c4878274SGrant Likely substream->pstr->stream, s->period_count); 15689dd0842SJon Smirl s->active = 0; 15789dd0842SJon Smirl 158dbcc3475SJon Smirl spin_lock_irqsave(&psc_dma->lock, flags); 15989dd0842SJon Smirl bcom_disable(s->bcom_task); 160dbcc3475SJon Smirl if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) 161dbcc3475SJon Smirl bcom_gen_bd_rx_reset(s->bcom_task); 162dbcc3475SJon Smirl else 163dbcc3475SJon Smirl bcom_gen_bd_tx_reset(s->bcom_task); 164dbcc3475SJon Smirl spin_unlock_irqrestore(&psc_dma->lock, flags); 16589dd0842SJon Smirl 16689dd0842SJon Smirl break; 16789dd0842SJon Smirl 16889dd0842SJon Smirl default: 169c4878274SGrant Likely dev_dbg(psc_dma->dev, "unhandled trigger: stream=%i cmd=%i\n", 170c4878274SGrant Likely substream->pstr->stream, cmd); 17189dd0842SJon Smirl return -EINVAL; 17289dd0842SJon Smirl } 17389dd0842SJon Smirl 17489dd0842SJon Smirl /* Update interrupt enable settings */ 17589dd0842SJon Smirl imr = 0; 176cebe7767SJon Smirl if (psc_dma->playback.active) 17789dd0842SJon Smirl imr |= MPC52xx_PSC_IMR_TXEMP; 178cebe7767SJon Smirl if (psc_dma->capture.active) 17989dd0842SJon Smirl imr |= MPC52xx_PSC_IMR_ORERR; 180dbcc3475SJon Smirl out_be16(®s->isr_imr.imr, psc_dma->imr | imr); 18189dd0842SJon Smirl 18289dd0842SJon Smirl return 0; 18389dd0842SJon Smirl } 18489dd0842SJon Smirl 18589dd0842SJon Smirl 18689dd0842SJon Smirl /* --------------------------------------------------------------------- 18789dd0842SJon Smirl * The PSC DMA 'ASoC platform' driver 18889dd0842SJon Smirl * 18989dd0842SJon Smirl * Can be referenced by an 'ASoC machine' driver 19089dd0842SJon Smirl * This driver only deals with the audio bus; it doesn't have any 19189dd0842SJon Smirl * interaction with the attached codec 19289dd0842SJon Smirl */ 19389dd0842SJon Smirl 194dbcc3475SJon Smirl static const struct snd_pcm_hardware psc_dma_hardware = { 19589dd0842SJon Smirl .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | 19689dd0842SJon Smirl SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | 19789dd0842SJon Smirl SNDRV_PCM_INFO_BATCH, 19889dd0842SJon Smirl .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | 19989dd0842SJon Smirl SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE, 20089dd0842SJon Smirl .rate_min = 8000, 20189dd0842SJon Smirl .rate_max = 48000, 202dbcc3475SJon Smirl .channels_min = 1, 20389dd0842SJon Smirl .channels_max = 2, 20489dd0842SJon Smirl .period_bytes_max = 1024 * 1024, 20589dd0842SJon Smirl .period_bytes_min = 32, 20689dd0842SJon Smirl .periods_min = 2, 20789dd0842SJon Smirl .periods_max = 256, 20889dd0842SJon Smirl .buffer_bytes_max = 2 * 1024 * 1024, 209dbcc3475SJon Smirl .fifo_size = 512, 21089dd0842SJon Smirl }; 21189dd0842SJon Smirl 212dbcc3475SJon Smirl static int psc_dma_open(struct snd_pcm_substream *substream) 21389dd0842SJon Smirl { 214dbcc3475SJon Smirl struct snd_pcm_runtime *runtime = substream->runtime; 21589dd0842SJon Smirl struct snd_soc_pcm_runtime *rtd = substream->private_data; 216f0fba2adSLiam Girdwood struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai); 217cebe7767SJon Smirl struct psc_dma_stream *s; 218dbcc3475SJon Smirl int rc; 21989dd0842SJon Smirl 220dbcc3475SJon Smirl dev_dbg(psc_dma->dev, "psc_dma_open(substream=%p)\n", substream); 22189dd0842SJon Smirl 22289dd0842SJon Smirl if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) 223cebe7767SJon Smirl s = &psc_dma->capture; 22489dd0842SJon Smirl else 225cebe7767SJon Smirl s = &psc_dma->playback; 22689dd0842SJon Smirl 227dbcc3475SJon Smirl snd_soc_set_runtime_hwparams(substream, &psc_dma_hardware); 228dbcc3475SJon Smirl 229dbcc3475SJon Smirl rc = snd_pcm_hw_constraint_integer(runtime, 230dbcc3475SJon Smirl SNDRV_PCM_HW_PARAM_PERIODS); 231dbcc3475SJon Smirl if (rc < 0) { 232dbcc3475SJon Smirl dev_err(substream->pcm->card->dev, "invalid buffer size\n"); 233dbcc3475SJon Smirl return rc; 234dbcc3475SJon Smirl } 23589dd0842SJon Smirl 23689dd0842SJon Smirl s->stream = substream; 23789dd0842SJon Smirl return 0; 23889dd0842SJon Smirl } 23989dd0842SJon Smirl 240dbcc3475SJon Smirl static int psc_dma_close(struct snd_pcm_substream *substream) 24189dd0842SJon Smirl { 24289dd0842SJon Smirl struct snd_soc_pcm_runtime *rtd = substream->private_data; 243f0fba2adSLiam Girdwood struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai); 244cebe7767SJon Smirl struct psc_dma_stream *s; 24589dd0842SJon Smirl 246dbcc3475SJon Smirl dev_dbg(psc_dma->dev, "psc_dma_close(substream=%p)\n", substream); 24789dd0842SJon Smirl 24889dd0842SJon Smirl if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) 249cebe7767SJon Smirl s = &psc_dma->capture; 25089dd0842SJon Smirl else 251cebe7767SJon Smirl s = &psc_dma->playback; 25289dd0842SJon Smirl 253dbcc3475SJon Smirl if (!psc_dma->playback.active && 254dbcc3475SJon Smirl !psc_dma->capture.active) { 255dbcc3475SJon Smirl 256dbcc3475SJon Smirl /* Disable all interrupts and reset the PSC */ 257dbcc3475SJon Smirl out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr); 258dbcc3475SJon Smirl out_8(&psc_dma->psc_regs->command, 4 << 4); /* reset error */ 259dbcc3475SJon Smirl } 26089dd0842SJon Smirl s->stream = NULL; 26189dd0842SJon Smirl return 0; 26289dd0842SJon Smirl } 26389dd0842SJon Smirl 26489dd0842SJon Smirl static snd_pcm_uframes_t 265dbcc3475SJon Smirl psc_dma_pointer(struct snd_pcm_substream *substream) 26689dd0842SJon Smirl { 26789dd0842SJon Smirl struct snd_soc_pcm_runtime *rtd = substream->private_data; 268f0fba2adSLiam Girdwood struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai); 269cebe7767SJon Smirl struct psc_dma_stream *s; 27089dd0842SJon Smirl dma_addr_t count; 27189dd0842SJon Smirl 27289dd0842SJon Smirl if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) 273cebe7767SJon Smirl s = &psc_dma->capture; 27489dd0842SJon Smirl else 275cebe7767SJon Smirl s = &psc_dma->playback; 27689dd0842SJon Smirl 2778f159d72SGrant Likely count = s->period_current * s->period_bytes; 27889dd0842SJon Smirl 27989dd0842SJon Smirl return bytes_to_frames(substream->runtime, count); 28089dd0842SJon Smirl } 28189dd0842SJon Smirl 282dbcc3475SJon Smirl static int 283dbcc3475SJon Smirl psc_dma_hw_params(struct snd_pcm_substream *substream, 284dbcc3475SJon Smirl struct snd_pcm_hw_params *params) 285dbcc3475SJon Smirl { 286dbcc3475SJon Smirl snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); 287dbcc3475SJon Smirl 288dbcc3475SJon Smirl return 0; 289dbcc3475SJon Smirl } 290dbcc3475SJon Smirl 291dbcc3475SJon Smirl static struct snd_pcm_ops psc_dma_ops = { 292dbcc3475SJon Smirl .open = psc_dma_open, 293dbcc3475SJon Smirl .close = psc_dma_close, 294dbcc3475SJon Smirl .hw_free = psc_dma_hw_free, 29589dd0842SJon Smirl .ioctl = snd_pcm_lib_ioctl, 296dbcc3475SJon Smirl .pointer = psc_dma_pointer, 297dbcc3475SJon Smirl .trigger = psc_dma_trigger, 298dbcc3475SJon Smirl .hw_params = psc_dma_hw_params, 29989dd0842SJon Smirl }; 30089dd0842SJon Smirl 301350e16d5SJoachim Eastwood static u64 psc_dma_dmamask = DMA_BIT_MASK(32); 302552d1ef6SLiam Girdwood static int psc_dma_new(struct snd_soc_pcm_runtime *rtd) 30389dd0842SJon Smirl { 304552d1ef6SLiam Girdwood struct snd_card *card = rtd->card->snd_card; 305552d1ef6SLiam Girdwood struct snd_soc_dai *dai = rtd->cpu_dai; 306552d1ef6SLiam Girdwood struct snd_pcm *pcm = rtd->pcm; 307f0fba2adSLiam Girdwood struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai); 308dbcc3475SJon Smirl size_t size = psc_dma_hardware.buffer_bytes_max; 30989dd0842SJon Smirl int rc = 0; 31089dd0842SJon Smirl 311f0fba2adSLiam Girdwood dev_dbg(rtd->platform->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n", 31289dd0842SJon Smirl card, dai, pcm); 31389dd0842SJon Smirl 31489dd0842SJon Smirl if (!card->dev->dma_mask) 315dbcc3475SJon Smirl card->dev->dma_mask = &psc_dma_dmamask; 31689dd0842SJon Smirl if (!card->dev->coherent_dma_mask) 317350e16d5SJoachim Eastwood card->dev->coherent_dma_mask = DMA_BIT_MASK(32); 31889dd0842SJon Smirl 3196296914cSJoachim Eastwood if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { 320dbcc3475SJon Smirl rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev, 3216296914cSJoachim Eastwood size, &pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->dma_buffer); 32289dd0842SJon Smirl if (rc) 32389dd0842SJon Smirl goto playback_alloc_err; 32489dd0842SJon Smirl } 32589dd0842SJon Smirl 3266296914cSJoachim Eastwood if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { 327dbcc3475SJon Smirl rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev, 3286296914cSJoachim Eastwood size, &pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->dma_buffer); 32989dd0842SJon Smirl if (rc) 33089dd0842SJon Smirl goto capture_alloc_err; 33189dd0842SJon Smirl } 33289dd0842SJon Smirl 333f0fba2adSLiam Girdwood if (rtd->codec->ac97) 334f0fba2adSLiam Girdwood rtd->codec->ac97->private_data = psc_dma; 335dbcc3475SJon Smirl 33689dd0842SJon Smirl return 0; 33789dd0842SJon Smirl 33889dd0842SJon Smirl capture_alloc_err: 3396296914cSJoachim Eastwood if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) 3406296914cSJoachim Eastwood snd_dma_free_pages(&pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->dma_buffer); 341dbcc3475SJon Smirl 34289dd0842SJon Smirl playback_alloc_err: 34389dd0842SJon Smirl dev_err(card->dev, "Cannot allocate buffer(s)\n"); 344dbcc3475SJon Smirl 34589dd0842SJon Smirl return -ENOMEM; 34689dd0842SJon Smirl } 34789dd0842SJon Smirl 348dbcc3475SJon Smirl static void psc_dma_free(struct snd_pcm *pcm) 34989dd0842SJon Smirl { 35089dd0842SJon Smirl struct snd_soc_pcm_runtime *rtd = pcm->private_data; 35189dd0842SJon Smirl struct snd_pcm_substream *substream; 35289dd0842SJon Smirl int stream; 35389dd0842SJon Smirl 354f0fba2adSLiam Girdwood dev_dbg(rtd->platform->dev, "psc_dma_free(pcm=%p)\n", pcm); 35589dd0842SJon Smirl 35689dd0842SJon Smirl for (stream = 0; stream < 2; stream++) { 35789dd0842SJon Smirl substream = pcm->streams[stream].substream; 35889dd0842SJon Smirl if (substream) { 35989dd0842SJon Smirl snd_dma_free_pages(&substream->dma_buffer); 36089dd0842SJon Smirl substream->dma_buffer.area = NULL; 36189dd0842SJon Smirl substream->dma_buffer.addr = 0; 36289dd0842SJon Smirl } 36389dd0842SJon Smirl } 36489dd0842SJon Smirl } 36589dd0842SJon Smirl 366f0fba2adSLiam Girdwood static struct snd_soc_platform_driver mpc5200_audio_dma_platform = { 367f0fba2adSLiam Girdwood .ops = &psc_dma_ops, 368dbcc3475SJon Smirl .pcm_new = &psc_dma_new, 369dbcc3475SJon Smirl .pcm_free = &psc_dma_free, 37089dd0842SJon Smirl }; 37189dd0842SJon Smirl 3723bdf28feSTimur Tabi static int mpc5200_hpcd_probe(struct platform_device *op) 373dbcc3475SJon Smirl { 374dbcc3475SJon Smirl phys_addr_t fifo; 375dbcc3475SJon Smirl struct psc_dma *psc_dma; 376dbcc3475SJon Smirl struct resource res; 377dbcc3475SJon Smirl int size, irq, rc; 378dbcc3475SJon Smirl const __be32 *prop; 379dbcc3475SJon Smirl void __iomem *regs; 38033d7f778SJulia Lawall int ret; 381dbcc3475SJon Smirl 382dbcc3475SJon Smirl /* Fetch the registers and IRQ of the PSC */ 38361c7a080SGrant Likely irq = irq_of_parse_and_map(op->dev.of_node, 0); 38461c7a080SGrant Likely if (of_address_to_resource(op->dev.of_node, 0, &res)) { 385dbcc3475SJon Smirl dev_err(&op->dev, "Missing reg property\n"); 386dbcc3475SJon Smirl return -ENODEV; 387dbcc3475SJon Smirl } 38828f65c11SJoe Perches regs = ioremap(res.start, resource_size(&res)); 389dbcc3475SJon Smirl if (!regs) { 390dbcc3475SJon Smirl dev_err(&op->dev, "Could not map registers\n"); 391dbcc3475SJon Smirl return -ENODEV; 392dbcc3475SJon Smirl } 393dbcc3475SJon Smirl 394dbcc3475SJon Smirl /* Allocate and initialize the driver private data */ 395dbcc3475SJon Smirl psc_dma = kzalloc(sizeof *psc_dma, GFP_KERNEL); 396dbcc3475SJon Smirl if (!psc_dma) { 39733d7f778SJulia Lawall ret = -ENOMEM; 39833d7f778SJulia Lawall goto out_unmap; 399dbcc3475SJon Smirl } 400dbcc3475SJon Smirl 401dbcc3475SJon Smirl /* Get the PSC ID */ 40261c7a080SGrant Likely prop = of_get_property(op->dev.of_node, "cell-index", &size); 40333d7f778SJulia Lawall if (!prop || size < sizeof *prop) { 40433d7f778SJulia Lawall ret = -ENODEV; 40533d7f778SJulia Lawall goto out_free; 40633d7f778SJulia Lawall } 407dbcc3475SJon Smirl 408dbcc3475SJon Smirl spin_lock_init(&psc_dma->lock); 4090827d6baSGrant Likely mutex_init(&psc_dma->mutex); 410dbcc3475SJon Smirl psc_dma->id = be32_to_cpu(*prop); 411dbcc3475SJon Smirl psc_dma->irq = irq; 412dbcc3475SJon Smirl psc_dma->psc_regs = regs; 413dbcc3475SJon Smirl psc_dma->fifo_regs = regs + sizeof *psc_dma->psc_regs; 414dbcc3475SJon Smirl psc_dma->dev = &op->dev; 415dbcc3475SJon Smirl psc_dma->playback.psc_dma = psc_dma; 416dbcc3475SJon Smirl psc_dma->capture.psc_dma = psc_dma; 417dbcc3475SJon Smirl snprintf(psc_dma->name, sizeof psc_dma->name, "PSC%u", psc_dma->id); 418dbcc3475SJon Smirl 419dbcc3475SJon Smirl /* Find the address of the fifo data registers and setup the 420dbcc3475SJon Smirl * DMA tasks */ 421dbcc3475SJon Smirl fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32); 422dbcc3475SJon Smirl psc_dma->capture.bcom_task = 423dbcc3475SJon Smirl bcom_psc_gen_bd_rx_init(psc_dma->id, 10, fifo, 512); 424dbcc3475SJon Smirl psc_dma->playback.bcom_task = 425dbcc3475SJon Smirl bcom_psc_gen_bd_tx_init(psc_dma->id, 10, fifo); 426dbcc3475SJon Smirl if (!psc_dma->capture.bcom_task || 427dbcc3475SJon Smirl !psc_dma->playback.bcom_task) { 428dbcc3475SJon Smirl dev_err(&op->dev, "Could not allocate bestcomm tasks\n"); 42933d7f778SJulia Lawall ret = -ENODEV; 43033d7f778SJulia Lawall goto out_free; 431dbcc3475SJon Smirl } 432dbcc3475SJon Smirl 433dbcc3475SJon Smirl /* Disable all interrupts and reset the PSC */ 434dbcc3475SJon Smirl out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr); 435dbcc3475SJon Smirl /* reset receiver */ 436dbcc3475SJon Smirl out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_RX); 437dbcc3475SJon Smirl /* reset transmitter */ 438dbcc3475SJon Smirl out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_TX); 439dbcc3475SJon Smirl /* reset error */ 440dbcc3475SJon Smirl out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_ERR_STAT); 441dbcc3475SJon Smirl /* reset mode */ 442dbcc3475SJon Smirl out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_SEL_MODE_REG_1); 443dbcc3475SJon Smirl 444dbcc3475SJon Smirl /* Set up mode register; 445dbcc3475SJon Smirl * First write: RxRdy (FIFO Alarm) generates rx FIFO irq 446dbcc3475SJon Smirl * Second write: register Normal mode for non loopback 447dbcc3475SJon Smirl */ 448dbcc3475SJon Smirl out_8(&psc_dma->psc_regs->mode, 0); 449dbcc3475SJon Smirl out_8(&psc_dma->psc_regs->mode, 0); 450dbcc3475SJon Smirl 451dbcc3475SJon Smirl /* Set the TX and RX fifo alarm thresholds */ 452dbcc3475SJon Smirl out_be16(&psc_dma->fifo_regs->rfalarm, 0x100); 453dbcc3475SJon Smirl out_8(&psc_dma->fifo_regs->rfcntl, 0x4); 454dbcc3475SJon Smirl out_be16(&psc_dma->fifo_regs->tfalarm, 0x100); 455dbcc3475SJon Smirl out_8(&psc_dma->fifo_regs->tfcntl, 0x7); 456dbcc3475SJon Smirl 457dbcc3475SJon Smirl /* Lookup the IRQ numbers */ 458dbcc3475SJon Smirl psc_dma->playback.irq = 459dbcc3475SJon Smirl bcom_get_task_irq(psc_dma->playback.bcom_task); 460dbcc3475SJon Smirl psc_dma->capture.irq = 461dbcc3475SJon Smirl bcom_get_task_irq(psc_dma->capture.bcom_task); 462dbcc3475SJon Smirl 463dbcc3475SJon Smirl rc = request_irq(psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED, 464dbcc3475SJon Smirl "psc-dma-status", psc_dma); 465a68cc8daSGrant Likely rc |= request_irq(psc_dma->capture.irq, &psc_dma_bcom_irq, IRQF_SHARED, 466dbcc3475SJon Smirl "psc-dma-capture", &psc_dma->capture); 467a68cc8daSGrant Likely rc |= request_irq(psc_dma->playback.irq, &psc_dma_bcom_irq, IRQF_SHARED, 468dbcc3475SJon Smirl "psc-dma-playback", &psc_dma->playback); 469dbcc3475SJon Smirl if (rc) { 47033d7f778SJulia Lawall ret = -ENODEV; 47133d7f778SJulia Lawall goto out_irq; 472dbcc3475SJon Smirl } 473dbcc3475SJon Smirl 474dbcc3475SJon Smirl /* Save what we've done so it can be found again later */ 475dbcc3475SJon Smirl dev_set_drvdata(&op->dev, psc_dma); 476dbcc3475SJon Smirl 477dbcc3475SJon Smirl /* Tell the ASoC OF helpers about it */ 478f0fba2adSLiam Girdwood return snd_soc_register_platform(&op->dev, &mpc5200_audio_dma_platform); 47933d7f778SJulia Lawall out_irq: 48033d7f778SJulia Lawall free_irq(psc_dma->irq, psc_dma); 48133d7f778SJulia Lawall free_irq(psc_dma->capture.irq, &psc_dma->capture); 48233d7f778SJulia Lawall free_irq(psc_dma->playback.irq, &psc_dma->playback); 48333d7f778SJulia Lawall out_free: 48433d7f778SJulia Lawall kfree(psc_dma); 48533d7f778SJulia Lawall out_unmap: 48633d7f778SJulia Lawall iounmap(regs); 48733d7f778SJulia Lawall return ret; 488dbcc3475SJon Smirl } 489dbcc3475SJon Smirl 4903bdf28feSTimur Tabi static int mpc5200_hpcd_remove(struct platform_device *op) 491dbcc3475SJon Smirl { 492dbcc3475SJon Smirl struct psc_dma *psc_dma = dev_get_drvdata(&op->dev); 493dbcc3475SJon Smirl 494dbcc3475SJon Smirl dev_dbg(&op->dev, "mpc5200_audio_dma_destroy()\n"); 495dbcc3475SJon Smirl 496f0fba2adSLiam Girdwood snd_soc_unregister_platform(&op->dev); 497dbcc3475SJon Smirl 498dbcc3475SJon Smirl bcom_gen_bd_rx_release(psc_dma->capture.bcom_task); 499dbcc3475SJon Smirl bcom_gen_bd_tx_release(psc_dma->playback.bcom_task); 500dbcc3475SJon Smirl 501dbcc3475SJon Smirl /* Release irqs */ 502dbcc3475SJon Smirl free_irq(psc_dma->irq, psc_dma); 503dbcc3475SJon Smirl free_irq(psc_dma->capture.irq, &psc_dma->capture); 504dbcc3475SJon Smirl free_irq(psc_dma->playback.irq, &psc_dma->playback); 505dbcc3475SJon Smirl 506dbcc3475SJon Smirl iounmap(psc_dma->psc_regs); 507dbcc3475SJon Smirl kfree(psc_dma); 508dbcc3475SJon Smirl dev_set_drvdata(&op->dev, NULL); 509dbcc3475SJon Smirl 510dbcc3475SJon Smirl return 0; 511dbcc3475SJon Smirl } 512f0fba2adSLiam Girdwood 513f0fba2adSLiam Girdwood static struct of_device_id mpc5200_hpcd_match[] = { 514f07eb223SGrant Likely { .compatible = "fsl,mpc5200-pcm", }, 515f0fba2adSLiam Girdwood {} 516f0fba2adSLiam Girdwood }; 517f0fba2adSLiam Girdwood MODULE_DEVICE_TABLE(of, mpc5200_hpcd_match); 518f0fba2adSLiam Girdwood 519f07eb223SGrant Likely static struct platform_driver mpc5200_hpcd_of_driver = { 520f0fba2adSLiam Girdwood .probe = mpc5200_hpcd_probe, 521f0fba2adSLiam Girdwood .remove = mpc5200_hpcd_remove, 5223bdf28feSTimur Tabi .driver = { 523f07eb223SGrant Likely .owner = THIS_MODULE, 524f07eb223SGrant Likely .name = "mpc5200-pcm-audio", 525f07eb223SGrant Likely .of_match_table = mpc5200_hpcd_match, 526f07eb223SGrant Likely } 527f0fba2adSLiam Girdwood }; 528f0fba2adSLiam Girdwood 529ba0a7e02SAxel Lin module_platform_driver(mpc5200_hpcd_of_driver); 530dbcc3475SJon Smirl 531dbcc3475SJon Smirl MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>"); 532dbcc3475SJon Smirl MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver"); 533dbcc3475SJon Smirl MODULE_LICENSE("GPL"); 534