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> 1107a38b1bSPaul Gortmaker #include <linux/dma-mapping.h> 125a0e3ad6STejun Heo #include <linux/slab.h> 13f0fba2adSLiam Girdwood #include <linux/of_platform.h> 1489dd0842SJon Smirl 1589dd0842SJon Smirl #include <sound/soc.h> 1689dd0842SJon Smirl 1789dd0842SJon Smirl #include <sysdev/bestcomm/bestcomm.h> 1889dd0842SJon Smirl #include <sysdev/bestcomm/gen_bd.h> 1989dd0842SJon Smirl #include <asm/mpc52xx_psc.h> 2089dd0842SJon Smirl 2189dd0842SJon Smirl #include "mpc5200_dma.h" 2289dd0842SJon Smirl 2389dd0842SJon Smirl /* 2489dd0842SJon Smirl * Interrupt handlers 2589dd0842SJon Smirl */ 26cebe7767SJon Smirl static irqreturn_t psc_dma_status_irq(int irq, void *_psc_dma) 2789dd0842SJon Smirl { 28cebe7767SJon Smirl struct psc_dma *psc_dma = _psc_dma; 29cebe7767SJon Smirl struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; 3089dd0842SJon Smirl u16 isr; 3189dd0842SJon Smirl 3289dd0842SJon Smirl isr = in_be16(®s->mpc52xx_psc_isr); 3389dd0842SJon Smirl 3489dd0842SJon Smirl /* Playback underrun error */ 35cebe7767SJon Smirl if (psc_dma->playback.active && (isr & MPC52xx_PSC_IMR_TXEMP)) 36cebe7767SJon Smirl psc_dma->stats.underrun_count++; 3789dd0842SJon Smirl 3889dd0842SJon Smirl /* Capture overrun error */ 39cebe7767SJon Smirl if (psc_dma->capture.active && (isr & MPC52xx_PSC_IMR_ORERR)) 40cebe7767SJon Smirl psc_dma->stats.overrun_count++; 4189dd0842SJon Smirl 42dbcc3475SJon Smirl out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT); 4389dd0842SJon Smirl 4489dd0842SJon Smirl return IRQ_HANDLED; 4589dd0842SJon Smirl } 4689dd0842SJon Smirl 4789dd0842SJon Smirl /** 48cebe7767SJon Smirl * psc_dma_bcom_enqueue_next_buffer - Enqueue another audio buffer 4989dd0842SJon Smirl * @s: pointer to stream private data structure 5089dd0842SJon Smirl * 5189dd0842SJon Smirl * Enqueues another audio period buffer into the bestcomm queue. 5289dd0842SJon Smirl * 5389dd0842SJon Smirl * Note: The routine must only be called when there is space available in 5489dd0842SJon Smirl * the queue. Otherwise the enqueue will fail and the audio ring buffer 5589dd0842SJon Smirl * will get out of sync 5689dd0842SJon Smirl */ 57cebe7767SJon Smirl static void psc_dma_bcom_enqueue_next_buffer(struct psc_dma_stream *s) 5889dd0842SJon Smirl { 5989dd0842SJon Smirl struct bcom_bd *bd; 6089dd0842SJon Smirl 6189dd0842SJon Smirl /* Prepare and enqueue the next buffer descriptor */ 6289dd0842SJon Smirl bd = bcom_prepare_next_buffer(s->bcom_task); 6389dd0842SJon Smirl bd->status = s->period_bytes; 648f159d72SGrant Likely bd->data[0] = s->runtime->dma_addr + (s->period_next * s->period_bytes); 6589dd0842SJon Smirl bcom_submit_next_buffer(s->bcom_task, NULL); 6689dd0842SJon Smirl 6789dd0842SJon Smirl /* Update for next period */ 688f159d72SGrant Likely s->period_next = (s->period_next + 1) % s->runtime->periods; 6989dd0842SJon Smirl } 7089dd0842SJon Smirl 7189dd0842SJon Smirl /* Bestcomm DMA irq handler */ 72a68cc8daSGrant Likely static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream) 7389dd0842SJon Smirl { 74dbcc3475SJon Smirl struct psc_dma_stream *s = _psc_dma_stream; 7589dd0842SJon Smirl 76dbcc3475SJon Smirl spin_lock(&s->psc_dma->lock); 77dbcc3475SJon Smirl /* For each finished period, dequeue the completed period buffer 78dbcc3475SJon Smirl * and enqueue a new one in it's place. */ 79dbcc3475SJon Smirl while (bcom_buffer_done(s->bcom_task)) { 80dbcc3475SJon Smirl bcom_retrieve_buffer(s->bcom_task, NULL, NULL); 8189dd0842SJon Smirl 828f159d72SGrant Likely s->period_current = (s->period_current+1) % s->runtime->periods; 83c4878274SGrant Likely s->period_count++; 84dbcc3475SJon Smirl 85dbcc3475SJon Smirl psc_dma_bcom_enqueue_next_buffer(s); 8689dd0842SJon Smirl } 87dbcc3475SJon Smirl spin_unlock(&s->psc_dma->lock); 88dbcc3475SJon Smirl 89dbcc3475SJon Smirl /* If the stream is active, then also inform the PCM middle layer 90dbcc3475SJon Smirl * of the period finished event. */ 91dbcc3475SJon Smirl if (s->active) 92dbcc3475SJon Smirl snd_pcm_period_elapsed(s->stream); 93dbcc3475SJon Smirl 94dbcc3475SJon Smirl return IRQ_HANDLED; 9589dd0842SJon Smirl } 9689dd0842SJon Smirl 97dbcc3475SJon Smirl static int psc_dma_hw_free(struct snd_pcm_substream *substream) 9889dd0842SJon Smirl { 9989dd0842SJon Smirl snd_pcm_set_runtime_buffer(substream, NULL); 10089dd0842SJon Smirl return 0; 10189dd0842SJon Smirl } 10289dd0842SJon Smirl 10389dd0842SJon Smirl /** 104cebe7767SJon Smirl * psc_dma_trigger: start and stop the DMA transfer. 10589dd0842SJon Smirl * 10689dd0842SJon Smirl * This function is called by ALSA to start, stop, pause, and resume the DMA 10789dd0842SJon Smirl * transfer of data. 10889dd0842SJon Smirl */ 109dbcc3475SJon Smirl static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd) 11089dd0842SJon Smirl { 11189dd0842SJon Smirl struct snd_soc_pcm_runtime *rtd = substream->private_data; 112f0fba2adSLiam Girdwood struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai); 11389dd0842SJon Smirl struct snd_pcm_runtime *runtime = substream->runtime; 1141d8222e8SGrant Likely struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma); 115cebe7767SJon Smirl struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; 11689dd0842SJon Smirl u16 imr; 11789dd0842SJon Smirl unsigned long flags; 118dbcc3475SJon Smirl int i; 11989dd0842SJon Smirl 12089dd0842SJon Smirl switch (cmd) { 12189dd0842SJon Smirl case SNDRV_PCM_TRIGGER_START: 122c4878274SGrant Likely dev_dbg(psc_dma->dev, "START: stream=%i fbits=%u ps=%u #p=%u\n", 123c4878274SGrant Likely substream->pstr->stream, runtime->frame_bits, 124c4878274SGrant Likely (int)runtime->period_size, runtime->periods); 12589dd0842SJon Smirl s->period_bytes = frames_to_bytes(runtime, 12689dd0842SJon Smirl runtime->period_size); 1278f159d72SGrant Likely s->period_next = 0; 1288f159d72SGrant Likely s->period_current = 0; 12989dd0842SJon Smirl s->active = 1; 130c4878274SGrant Likely s->period_count = 0; 131dbcc3475SJon Smirl s->runtime = runtime; 132dbcc3475SJon Smirl 133dbcc3475SJon Smirl /* Fill up the bestcomm bd queue and enable DMA. 134dbcc3475SJon Smirl * This will begin filling the PSC's fifo. 135dbcc3475SJon Smirl */ 136dbcc3475SJon Smirl spin_lock_irqsave(&psc_dma->lock, flags); 137dbcc3475SJon Smirl 138d56b6eb6SGrant Likely if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) 139dbcc3475SJon Smirl bcom_gen_bd_rx_reset(s->bcom_task); 140d56b6eb6SGrant Likely else 141d56b6eb6SGrant Likely bcom_gen_bd_tx_reset(s->bcom_task); 142d56b6eb6SGrant Likely 143dbcc3475SJon Smirl for (i = 0; i < runtime->periods; i++) 144dbcc3475SJon Smirl if (!bcom_queue_full(s->bcom_task)) 145dbcc3475SJon Smirl psc_dma_bcom_enqueue_next_buffer(s); 14689dd0842SJon Smirl 14789dd0842SJon Smirl bcom_enable(s->bcom_task); 148cebe7767SJon Smirl spin_unlock_irqrestore(&psc_dma->lock, flags); 14989dd0842SJon Smirl 150dbcc3475SJon Smirl out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT); 151dbcc3475SJon Smirl 15289dd0842SJon Smirl break; 15389dd0842SJon Smirl 15489dd0842SJon Smirl case SNDRV_PCM_TRIGGER_STOP: 155c4878274SGrant Likely dev_dbg(psc_dma->dev, "STOP: stream=%i periods_count=%i\n", 156c4878274SGrant Likely substream->pstr->stream, s->period_count); 15789dd0842SJon Smirl s->active = 0; 15889dd0842SJon Smirl 159dbcc3475SJon Smirl spin_lock_irqsave(&psc_dma->lock, flags); 16089dd0842SJon Smirl bcom_disable(s->bcom_task); 161dbcc3475SJon Smirl if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) 162dbcc3475SJon Smirl bcom_gen_bd_rx_reset(s->bcom_task); 163dbcc3475SJon Smirl else 164dbcc3475SJon Smirl bcom_gen_bd_tx_reset(s->bcom_task); 165dbcc3475SJon Smirl spin_unlock_irqrestore(&psc_dma->lock, flags); 16689dd0842SJon Smirl 16789dd0842SJon Smirl break; 16889dd0842SJon Smirl 16989dd0842SJon Smirl default: 170c4878274SGrant Likely dev_dbg(psc_dma->dev, "unhandled trigger: stream=%i cmd=%i\n", 171c4878274SGrant Likely substream->pstr->stream, cmd); 17289dd0842SJon Smirl return -EINVAL; 17389dd0842SJon Smirl } 17489dd0842SJon Smirl 17589dd0842SJon Smirl /* Update interrupt enable settings */ 17689dd0842SJon Smirl imr = 0; 177cebe7767SJon Smirl if (psc_dma->playback.active) 17889dd0842SJon Smirl imr |= MPC52xx_PSC_IMR_TXEMP; 179cebe7767SJon Smirl if (psc_dma->capture.active) 18089dd0842SJon Smirl imr |= MPC52xx_PSC_IMR_ORERR; 181dbcc3475SJon Smirl out_be16(®s->isr_imr.imr, psc_dma->imr | imr); 18289dd0842SJon Smirl 18389dd0842SJon Smirl return 0; 18489dd0842SJon Smirl } 18589dd0842SJon Smirl 18689dd0842SJon Smirl 18789dd0842SJon Smirl /* --------------------------------------------------------------------- 18889dd0842SJon Smirl * The PSC DMA 'ASoC platform' driver 18989dd0842SJon Smirl * 19089dd0842SJon Smirl * Can be referenced by an 'ASoC machine' driver 19189dd0842SJon Smirl * This driver only deals with the audio bus; it doesn't have any 19289dd0842SJon Smirl * interaction with the attached codec 19389dd0842SJon Smirl */ 19489dd0842SJon Smirl 195dbcc3475SJon Smirl static const struct snd_pcm_hardware psc_dma_hardware = { 19689dd0842SJon Smirl .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | 19789dd0842SJon Smirl SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | 19889dd0842SJon Smirl SNDRV_PCM_INFO_BATCH, 19989dd0842SJon Smirl .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | 20089dd0842SJon Smirl SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE, 20189dd0842SJon Smirl .rate_min = 8000, 20289dd0842SJon Smirl .rate_max = 48000, 203dbcc3475SJon Smirl .channels_min = 1, 20489dd0842SJon Smirl .channels_max = 2, 20589dd0842SJon Smirl .period_bytes_max = 1024 * 1024, 20689dd0842SJon Smirl .period_bytes_min = 32, 20789dd0842SJon Smirl .periods_min = 2, 20889dd0842SJon Smirl .periods_max = 256, 20989dd0842SJon Smirl .buffer_bytes_max = 2 * 1024 * 1024, 210dbcc3475SJon Smirl .fifo_size = 512, 21189dd0842SJon Smirl }; 21289dd0842SJon Smirl 213dbcc3475SJon Smirl static int psc_dma_open(struct snd_pcm_substream *substream) 21489dd0842SJon Smirl { 215dbcc3475SJon Smirl struct snd_pcm_runtime *runtime = substream->runtime; 21689dd0842SJon Smirl struct snd_soc_pcm_runtime *rtd = substream->private_data; 217f0fba2adSLiam Girdwood struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai); 218cebe7767SJon Smirl struct psc_dma_stream *s; 219dbcc3475SJon Smirl int rc; 22089dd0842SJon Smirl 221dbcc3475SJon Smirl dev_dbg(psc_dma->dev, "psc_dma_open(substream=%p)\n", substream); 22289dd0842SJon Smirl 22389dd0842SJon Smirl if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) 224cebe7767SJon Smirl s = &psc_dma->capture; 22589dd0842SJon Smirl else 226cebe7767SJon Smirl s = &psc_dma->playback; 22789dd0842SJon Smirl 228dbcc3475SJon Smirl snd_soc_set_runtime_hwparams(substream, &psc_dma_hardware); 229dbcc3475SJon Smirl 230dbcc3475SJon Smirl rc = snd_pcm_hw_constraint_integer(runtime, 231dbcc3475SJon Smirl SNDRV_PCM_HW_PARAM_PERIODS); 232dbcc3475SJon Smirl if (rc < 0) { 233dbcc3475SJon Smirl dev_err(substream->pcm->card->dev, "invalid buffer size\n"); 234dbcc3475SJon Smirl return rc; 235dbcc3475SJon Smirl } 23689dd0842SJon Smirl 23789dd0842SJon Smirl s->stream = substream; 23889dd0842SJon Smirl return 0; 23989dd0842SJon Smirl } 24089dd0842SJon Smirl 241dbcc3475SJon Smirl static int psc_dma_close(struct snd_pcm_substream *substream) 24289dd0842SJon Smirl { 24389dd0842SJon Smirl struct snd_soc_pcm_runtime *rtd = substream->private_data; 244f0fba2adSLiam Girdwood struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai); 245cebe7767SJon Smirl struct psc_dma_stream *s; 24689dd0842SJon Smirl 247dbcc3475SJon Smirl dev_dbg(psc_dma->dev, "psc_dma_close(substream=%p)\n", substream); 24889dd0842SJon Smirl 24989dd0842SJon Smirl if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) 250cebe7767SJon Smirl s = &psc_dma->capture; 25189dd0842SJon Smirl else 252cebe7767SJon Smirl s = &psc_dma->playback; 25389dd0842SJon Smirl 254dbcc3475SJon Smirl if (!psc_dma->playback.active && 255dbcc3475SJon Smirl !psc_dma->capture.active) { 256dbcc3475SJon Smirl 257dbcc3475SJon Smirl /* Disable all interrupts and reset the PSC */ 258dbcc3475SJon Smirl out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr); 259dbcc3475SJon Smirl out_8(&psc_dma->psc_regs->command, 4 << 4); /* reset error */ 260dbcc3475SJon Smirl } 26189dd0842SJon Smirl s->stream = NULL; 26289dd0842SJon Smirl return 0; 26389dd0842SJon Smirl } 26489dd0842SJon Smirl 26589dd0842SJon Smirl static snd_pcm_uframes_t 266dbcc3475SJon Smirl psc_dma_pointer(struct snd_pcm_substream *substream) 26789dd0842SJon Smirl { 26889dd0842SJon Smirl struct snd_soc_pcm_runtime *rtd = substream->private_data; 269f0fba2adSLiam Girdwood struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai); 270cebe7767SJon Smirl struct psc_dma_stream *s; 27189dd0842SJon Smirl dma_addr_t count; 27289dd0842SJon Smirl 27389dd0842SJon Smirl if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) 274cebe7767SJon Smirl s = &psc_dma->capture; 27589dd0842SJon Smirl else 276cebe7767SJon Smirl s = &psc_dma->playback; 27789dd0842SJon Smirl 2788f159d72SGrant Likely count = s->period_current * s->period_bytes; 27989dd0842SJon Smirl 28089dd0842SJon Smirl return bytes_to_frames(substream->runtime, count); 28189dd0842SJon Smirl } 28289dd0842SJon Smirl 283dbcc3475SJon Smirl static int 284dbcc3475SJon Smirl psc_dma_hw_params(struct snd_pcm_substream *substream, 285dbcc3475SJon Smirl struct snd_pcm_hw_params *params) 286dbcc3475SJon Smirl { 287dbcc3475SJon Smirl snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); 288dbcc3475SJon Smirl 289dbcc3475SJon Smirl return 0; 290dbcc3475SJon Smirl } 291dbcc3475SJon Smirl 292dbcc3475SJon Smirl static struct snd_pcm_ops psc_dma_ops = { 293dbcc3475SJon Smirl .open = psc_dma_open, 294dbcc3475SJon Smirl .close = psc_dma_close, 295dbcc3475SJon Smirl .hw_free = psc_dma_hw_free, 29689dd0842SJon Smirl .ioctl = snd_pcm_lib_ioctl, 297dbcc3475SJon Smirl .pointer = psc_dma_pointer, 298dbcc3475SJon Smirl .trigger = psc_dma_trigger, 299dbcc3475SJon Smirl .hw_params = psc_dma_hw_params, 30089dd0842SJon Smirl }; 30189dd0842SJon Smirl 302350e16d5SJoachim Eastwood static u64 psc_dma_dmamask = DMA_BIT_MASK(32); 303552d1ef6SLiam Girdwood static int psc_dma_new(struct snd_soc_pcm_runtime *rtd) 30489dd0842SJon Smirl { 305552d1ef6SLiam Girdwood struct snd_card *card = rtd->card->snd_card; 306552d1ef6SLiam Girdwood struct snd_soc_dai *dai = rtd->cpu_dai; 307552d1ef6SLiam Girdwood struct snd_pcm *pcm = rtd->pcm; 308f0fba2adSLiam Girdwood struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai); 309dbcc3475SJon Smirl size_t size = psc_dma_hardware.buffer_bytes_max; 31089dd0842SJon Smirl int rc = 0; 31189dd0842SJon Smirl 312f0fba2adSLiam Girdwood dev_dbg(rtd->platform->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n", 31389dd0842SJon Smirl card, dai, pcm); 31489dd0842SJon Smirl 31589dd0842SJon Smirl if (!card->dev->dma_mask) 316dbcc3475SJon Smirl card->dev->dma_mask = &psc_dma_dmamask; 31789dd0842SJon Smirl if (!card->dev->coherent_dma_mask) 318350e16d5SJoachim Eastwood card->dev->coherent_dma_mask = DMA_BIT_MASK(32); 31989dd0842SJon Smirl 3206296914cSJoachim Eastwood if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { 321dbcc3475SJon Smirl rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev, 3226296914cSJoachim Eastwood size, &pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->dma_buffer); 32389dd0842SJon Smirl if (rc) 32489dd0842SJon Smirl goto playback_alloc_err; 32589dd0842SJon Smirl } 32689dd0842SJon Smirl 3276296914cSJoachim Eastwood if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { 328dbcc3475SJon Smirl rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev, 3296296914cSJoachim Eastwood size, &pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->dma_buffer); 33089dd0842SJon Smirl if (rc) 33189dd0842SJon Smirl goto capture_alloc_err; 33289dd0842SJon Smirl } 33389dd0842SJon Smirl 334f0fba2adSLiam Girdwood if (rtd->codec->ac97) 335f0fba2adSLiam Girdwood rtd->codec->ac97->private_data = psc_dma; 336dbcc3475SJon Smirl 33789dd0842SJon Smirl return 0; 33889dd0842SJon Smirl 33989dd0842SJon Smirl capture_alloc_err: 3406296914cSJoachim Eastwood if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) 3416296914cSJoachim Eastwood snd_dma_free_pages(&pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->dma_buffer); 342dbcc3475SJon Smirl 34389dd0842SJon Smirl playback_alloc_err: 34489dd0842SJon Smirl dev_err(card->dev, "Cannot allocate buffer(s)\n"); 345dbcc3475SJon Smirl 34689dd0842SJon Smirl return -ENOMEM; 34789dd0842SJon Smirl } 34889dd0842SJon Smirl 349dbcc3475SJon Smirl static void psc_dma_free(struct snd_pcm *pcm) 35089dd0842SJon Smirl { 35189dd0842SJon Smirl struct snd_soc_pcm_runtime *rtd = pcm->private_data; 35289dd0842SJon Smirl struct snd_pcm_substream *substream; 35389dd0842SJon Smirl int stream; 35489dd0842SJon Smirl 355f0fba2adSLiam Girdwood dev_dbg(rtd->platform->dev, "psc_dma_free(pcm=%p)\n", pcm); 35689dd0842SJon Smirl 35789dd0842SJon Smirl for (stream = 0; stream < 2; stream++) { 35889dd0842SJon Smirl substream = pcm->streams[stream].substream; 35989dd0842SJon Smirl if (substream) { 36089dd0842SJon Smirl snd_dma_free_pages(&substream->dma_buffer); 36189dd0842SJon Smirl substream->dma_buffer.area = NULL; 36289dd0842SJon Smirl substream->dma_buffer.addr = 0; 36389dd0842SJon Smirl } 36489dd0842SJon Smirl } 36589dd0842SJon Smirl } 36689dd0842SJon Smirl 367f0fba2adSLiam Girdwood static struct snd_soc_platform_driver mpc5200_audio_dma_platform = { 368f0fba2adSLiam Girdwood .ops = &psc_dma_ops, 369dbcc3475SJon Smirl .pcm_new = &psc_dma_new, 370dbcc3475SJon Smirl .pcm_free = &psc_dma_free, 37189dd0842SJon Smirl }; 37289dd0842SJon Smirl 3733bdf28feSTimur Tabi static int mpc5200_hpcd_probe(struct platform_device *op) 374dbcc3475SJon Smirl { 375dbcc3475SJon Smirl phys_addr_t fifo; 376dbcc3475SJon Smirl struct psc_dma *psc_dma; 377dbcc3475SJon Smirl struct resource res; 378dbcc3475SJon Smirl int size, irq, rc; 379dbcc3475SJon Smirl const __be32 *prop; 380dbcc3475SJon Smirl void __iomem *regs; 38133d7f778SJulia Lawall int ret; 382dbcc3475SJon Smirl 383dbcc3475SJon Smirl /* Fetch the registers and IRQ of the PSC */ 38461c7a080SGrant Likely irq = irq_of_parse_and_map(op->dev.of_node, 0); 38561c7a080SGrant Likely if (of_address_to_resource(op->dev.of_node, 0, &res)) { 386dbcc3475SJon Smirl dev_err(&op->dev, "Missing reg property\n"); 387dbcc3475SJon Smirl return -ENODEV; 388dbcc3475SJon Smirl } 38928f65c11SJoe Perches regs = ioremap(res.start, resource_size(&res)); 390dbcc3475SJon Smirl if (!regs) { 391dbcc3475SJon Smirl dev_err(&op->dev, "Could not map registers\n"); 392dbcc3475SJon Smirl return -ENODEV; 393dbcc3475SJon Smirl } 394dbcc3475SJon Smirl 395dbcc3475SJon Smirl /* Allocate and initialize the driver private data */ 396dbcc3475SJon Smirl psc_dma = kzalloc(sizeof *psc_dma, GFP_KERNEL); 397dbcc3475SJon Smirl if (!psc_dma) { 39833d7f778SJulia Lawall ret = -ENOMEM; 39933d7f778SJulia Lawall goto out_unmap; 400dbcc3475SJon Smirl } 401dbcc3475SJon Smirl 402dbcc3475SJon Smirl /* Get the PSC ID */ 40361c7a080SGrant Likely prop = of_get_property(op->dev.of_node, "cell-index", &size); 40433d7f778SJulia Lawall if (!prop || size < sizeof *prop) { 40533d7f778SJulia Lawall ret = -ENODEV; 40633d7f778SJulia Lawall goto out_free; 40733d7f778SJulia Lawall } 408dbcc3475SJon Smirl 409dbcc3475SJon Smirl spin_lock_init(&psc_dma->lock); 4100827d6baSGrant Likely mutex_init(&psc_dma->mutex); 411dbcc3475SJon Smirl psc_dma->id = be32_to_cpu(*prop); 412dbcc3475SJon Smirl psc_dma->irq = irq; 413dbcc3475SJon Smirl psc_dma->psc_regs = regs; 414dbcc3475SJon Smirl psc_dma->fifo_regs = regs + sizeof *psc_dma->psc_regs; 415dbcc3475SJon Smirl psc_dma->dev = &op->dev; 416dbcc3475SJon Smirl psc_dma->playback.psc_dma = psc_dma; 417dbcc3475SJon Smirl psc_dma->capture.psc_dma = psc_dma; 418dbcc3475SJon Smirl snprintf(psc_dma->name, sizeof psc_dma->name, "PSC%u", psc_dma->id); 419dbcc3475SJon Smirl 420dbcc3475SJon Smirl /* Find the address of the fifo data registers and setup the 421dbcc3475SJon Smirl * DMA tasks */ 422dbcc3475SJon Smirl fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32); 423dbcc3475SJon Smirl psc_dma->capture.bcom_task = 424dbcc3475SJon Smirl bcom_psc_gen_bd_rx_init(psc_dma->id, 10, fifo, 512); 425dbcc3475SJon Smirl psc_dma->playback.bcom_task = 426dbcc3475SJon Smirl bcom_psc_gen_bd_tx_init(psc_dma->id, 10, fifo); 427dbcc3475SJon Smirl if (!psc_dma->capture.bcom_task || 428dbcc3475SJon Smirl !psc_dma->playback.bcom_task) { 429dbcc3475SJon Smirl dev_err(&op->dev, "Could not allocate bestcomm tasks\n"); 43033d7f778SJulia Lawall ret = -ENODEV; 43133d7f778SJulia Lawall goto out_free; 432dbcc3475SJon Smirl } 433dbcc3475SJon Smirl 434dbcc3475SJon Smirl /* Disable all interrupts and reset the PSC */ 435dbcc3475SJon Smirl out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr); 436dbcc3475SJon Smirl /* reset receiver */ 437dbcc3475SJon Smirl out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_RX); 438dbcc3475SJon Smirl /* reset transmitter */ 439dbcc3475SJon Smirl out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_TX); 440dbcc3475SJon Smirl /* reset error */ 441dbcc3475SJon Smirl out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_ERR_STAT); 442dbcc3475SJon Smirl /* reset mode */ 443dbcc3475SJon Smirl out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_SEL_MODE_REG_1); 444dbcc3475SJon Smirl 445dbcc3475SJon Smirl /* Set up mode register; 446dbcc3475SJon Smirl * First write: RxRdy (FIFO Alarm) generates rx FIFO irq 447dbcc3475SJon Smirl * Second write: register Normal mode for non loopback 448dbcc3475SJon Smirl */ 449dbcc3475SJon Smirl out_8(&psc_dma->psc_regs->mode, 0); 450dbcc3475SJon Smirl out_8(&psc_dma->psc_regs->mode, 0); 451dbcc3475SJon Smirl 452dbcc3475SJon Smirl /* Set the TX and RX fifo alarm thresholds */ 453dbcc3475SJon Smirl out_be16(&psc_dma->fifo_regs->rfalarm, 0x100); 454dbcc3475SJon Smirl out_8(&psc_dma->fifo_regs->rfcntl, 0x4); 455dbcc3475SJon Smirl out_be16(&psc_dma->fifo_regs->tfalarm, 0x100); 456dbcc3475SJon Smirl out_8(&psc_dma->fifo_regs->tfcntl, 0x7); 457dbcc3475SJon Smirl 458dbcc3475SJon Smirl /* Lookup the IRQ numbers */ 459dbcc3475SJon Smirl psc_dma->playback.irq = 460dbcc3475SJon Smirl bcom_get_task_irq(psc_dma->playback.bcom_task); 461dbcc3475SJon Smirl psc_dma->capture.irq = 462dbcc3475SJon Smirl bcom_get_task_irq(psc_dma->capture.bcom_task); 463dbcc3475SJon Smirl 464dbcc3475SJon Smirl rc = request_irq(psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED, 465dbcc3475SJon Smirl "psc-dma-status", psc_dma); 466a68cc8daSGrant Likely rc |= request_irq(psc_dma->capture.irq, &psc_dma_bcom_irq, IRQF_SHARED, 467dbcc3475SJon Smirl "psc-dma-capture", &psc_dma->capture); 468a68cc8daSGrant Likely rc |= request_irq(psc_dma->playback.irq, &psc_dma_bcom_irq, IRQF_SHARED, 469dbcc3475SJon Smirl "psc-dma-playback", &psc_dma->playback); 470dbcc3475SJon Smirl if (rc) { 47133d7f778SJulia Lawall ret = -ENODEV; 47233d7f778SJulia Lawall goto out_irq; 473dbcc3475SJon Smirl } 474dbcc3475SJon Smirl 475dbcc3475SJon Smirl /* Save what we've done so it can be found again later */ 476dbcc3475SJon Smirl dev_set_drvdata(&op->dev, psc_dma); 477dbcc3475SJon Smirl 478dbcc3475SJon Smirl /* Tell the ASoC OF helpers about it */ 479f0fba2adSLiam Girdwood return snd_soc_register_platform(&op->dev, &mpc5200_audio_dma_platform); 48033d7f778SJulia Lawall out_irq: 48133d7f778SJulia Lawall free_irq(psc_dma->irq, psc_dma); 48233d7f778SJulia Lawall free_irq(psc_dma->capture.irq, &psc_dma->capture); 48333d7f778SJulia Lawall free_irq(psc_dma->playback.irq, &psc_dma->playback); 48433d7f778SJulia Lawall out_free: 48533d7f778SJulia Lawall kfree(psc_dma); 48633d7f778SJulia Lawall out_unmap: 48733d7f778SJulia Lawall iounmap(regs); 48833d7f778SJulia Lawall return ret; 489dbcc3475SJon Smirl } 490dbcc3475SJon Smirl 4913bdf28feSTimur Tabi static int mpc5200_hpcd_remove(struct platform_device *op) 492dbcc3475SJon Smirl { 493dbcc3475SJon Smirl struct psc_dma *psc_dma = dev_get_drvdata(&op->dev); 494dbcc3475SJon Smirl 495dbcc3475SJon Smirl dev_dbg(&op->dev, "mpc5200_audio_dma_destroy()\n"); 496dbcc3475SJon Smirl 497f0fba2adSLiam Girdwood snd_soc_unregister_platform(&op->dev); 498dbcc3475SJon Smirl 499dbcc3475SJon Smirl bcom_gen_bd_rx_release(psc_dma->capture.bcom_task); 500dbcc3475SJon Smirl bcom_gen_bd_tx_release(psc_dma->playback.bcom_task); 501dbcc3475SJon Smirl 502dbcc3475SJon Smirl /* Release irqs */ 503dbcc3475SJon Smirl free_irq(psc_dma->irq, psc_dma); 504dbcc3475SJon Smirl free_irq(psc_dma->capture.irq, &psc_dma->capture); 505dbcc3475SJon Smirl free_irq(psc_dma->playback.irq, &psc_dma->playback); 506dbcc3475SJon Smirl 507dbcc3475SJon Smirl iounmap(psc_dma->psc_regs); 508dbcc3475SJon Smirl kfree(psc_dma); 509dbcc3475SJon Smirl dev_set_drvdata(&op->dev, NULL); 510dbcc3475SJon Smirl 511dbcc3475SJon Smirl return 0; 512dbcc3475SJon Smirl } 513f0fba2adSLiam Girdwood 514f0fba2adSLiam Girdwood static struct of_device_id mpc5200_hpcd_match[] = { 515f07eb223SGrant Likely { .compatible = "fsl,mpc5200-pcm", }, 516f0fba2adSLiam Girdwood {} 517f0fba2adSLiam Girdwood }; 518f0fba2adSLiam Girdwood MODULE_DEVICE_TABLE(of, mpc5200_hpcd_match); 519f0fba2adSLiam Girdwood 520f07eb223SGrant Likely static struct platform_driver mpc5200_hpcd_of_driver = { 521f0fba2adSLiam Girdwood .probe = mpc5200_hpcd_probe, 522f0fba2adSLiam Girdwood .remove = mpc5200_hpcd_remove, 5233bdf28feSTimur Tabi .driver = { 524f07eb223SGrant Likely .owner = THIS_MODULE, 525f07eb223SGrant Likely .name = "mpc5200-pcm-audio", 526f07eb223SGrant Likely .of_match_table = mpc5200_hpcd_match, 527f07eb223SGrant Likely } 528f0fba2adSLiam Girdwood }; 529f0fba2adSLiam Girdwood 530ba0a7e02SAxel Lin module_platform_driver(mpc5200_hpcd_of_driver); 531dbcc3475SJon Smirl 532dbcc3475SJon Smirl MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>"); 533dbcc3475SJon Smirl MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver"); 534dbcc3475SJon Smirl MODULE_LICENSE("GPL"); 535