1ac097cacSAndra Danciu // SPDX-License-Identifier: GPL-2.0-only 21edfc248SAndra Danciu // 31edfc248SAndra Danciu // Freescale MPC5200 PSC DMA 41edfc248SAndra Danciu // ALSA SoC Platform driver 51edfc248SAndra Danciu // 61edfc248SAndra Danciu // Copyright (C) 2008 Secret Lab Technologies Ltd. 71edfc248SAndra Danciu // Copyright (C) 2009 Jon Smirl, Digispeaker 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> 135af50730SRob Herring #include <linux/of_address.h> 145af50730SRob Herring #include <linux/of_irq.h> 15f0fba2adSLiam Girdwood #include <linux/of_platform.h> 1689dd0842SJon Smirl 1789dd0842SJon Smirl #include <sound/soc.h> 1889dd0842SJon Smirl 199a322993SPhilippe De Muyter #include <linux/fsl/bestcomm/bestcomm.h> 209a322993SPhilippe De Muyter #include <linux/fsl/bestcomm/gen_bd.h> 2189dd0842SJon Smirl #include <asm/mpc52xx_psc.h> 2289dd0842SJon Smirl 2389dd0842SJon Smirl #include "mpc5200_dma.h" 2489dd0842SJon Smirl 2560bceb80SKuninori Morimoto #define DRV_NAME "mpc5200_dma" 2660bceb80SKuninori Morimoto 2789dd0842SJon Smirl /* 2889dd0842SJon Smirl * Interrupt handlers 2989dd0842SJon Smirl */ 30cebe7767SJon Smirl static irqreturn_t psc_dma_status_irq(int irq, void *_psc_dma) 3189dd0842SJon Smirl { 32cebe7767SJon Smirl struct psc_dma *psc_dma = _psc_dma; 33cebe7767SJon Smirl struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; 3489dd0842SJon Smirl u16 isr; 3589dd0842SJon Smirl 3689dd0842SJon Smirl isr = in_be16(®s->mpc52xx_psc_isr); 3789dd0842SJon Smirl 3889dd0842SJon Smirl /* Playback underrun error */ 39cebe7767SJon Smirl if (psc_dma->playback.active && (isr & MPC52xx_PSC_IMR_TXEMP)) 40cebe7767SJon Smirl psc_dma->stats.underrun_count++; 4189dd0842SJon Smirl 4289dd0842SJon Smirl /* Capture overrun error */ 43cebe7767SJon Smirl if (psc_dma->capture.active && (isr & MPC52xx_PSC_IMR_ORERR)) 44cebe7767SJon Smirl psc_dma->stats.overrun_count++; 4589dd0842SJon Smirl 46dbcc3475SJon Smirl out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT); 4789dd0842SJon Smirl 4889dd0842SJon Smirl return IRQ_HANDLED; 4989dd0842SJon Smirl } 5089dd0842SJon Smirl 5189dd0842SJon Smirl /** 52cebe7767SJon Smirl * psc_dma_bcom_enqueue_next_buffer - Enqueue another audio buffer 5389dd0842SJon Smirl * @s: pointer to stream private data structure 5489dd0842SJon Smirl * 5589dd0842SJon Smirl * Enqueues another audio period buffer into the bestcomm queue. 5689dd0842SJon Smirl * 5789dd0842SJon Smirl * Note: The routine must only be called when there is space available in 5889dd0842SJon Smirl * the queue. Otherwise the enqueue will fail and the audio ring buffer 5989dd0842SJon Smirl * will get out of sync 6089dd0842SJon Smirl */ 61cebe7767SJon Smirl static void psc_dma_bcom_enqueue_next_buffer(struct psc_dma_stream *s) 6289dd0842SJon Smirl { 6389dd0842SJon Smirl struct bcom_bd *bd; 6489dd0842SJon Smirl 6589dd0842SJon Smirl /* Prepare and enqueue the next buffer descriptor */ 6689dd0842SJon Smirl bd = bcom_prepare_next_buffer(s->bcom_task); 6789dd0842SJon Smirl bd->status = s->period_bytes; 688f159d72SGrant Likely bd->data[0] = s->runtime->dma_addr + (s->period_next * s->period_bytes); 6989dd0842SJon Smirl bcom_submit_next_buffer(s->bcom_task, NULL); 7089dd0842SJon Smirl 7189dd0842SJon Smirl /* Update for next period */ 728f159d72SGrant Likely s->period_next = (s->period_next + 1) % s->runtime->periods; 7389dd0842SJon Smirl } 7489dd0842SJon Smirl 7589dd0842SJon Smirl /* Bestcomm DMA irq handler */ 76a68cc8daSGrant Likely static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream) 7789dd0842SJon Smirl { 78dbcc3475SJon Smirl struct psc_dma_stream *s = _psc_dma_stream; 7989dd0842SJon Smirl 80dbcc3475SJon Smirl spin_lock(&s->psc_dma->lock); 81dbcc3475SJon Smirl /* For each finished period, dequeue the completed period buffer 82dbcc3475SJon Smirl * and enqueue a new one in it's place. */ 83dbcc3475SJon Smirl while (bcom_buffer_done(s->bcom_task)) { 84dbcc3475SJon Smirl bcom_retrieve_buffer(s->bcom_task, NULL, NULL); 8589dd0842SJon Smirl 868f159d72SGrant Likely s->period_current = (s->period_current+1) % s->runtime->periods; 87c4878274SGrant Likely s->period_count++; 88dbcc3475SJon Smirl 89dbcc3475SJon Smirl psc_dma_bcom_enqueue_next_buffer(s); 9089dd0842SJon Smirl } 91dbcc3475SJon Smirl spin_unlock(&s->psc_dma->lock); 92dbcc3475SJon Smirl 93dbcc3475SJon Smirl /* If the stream is active, then also inform the PCM middle layer 94dbcc3475SJon Smirl * of the period finished event. */ 95dbcc3475SJon Smirl if (s->active) 96dbcc3475SJon Smirl snd_pcm_period_elapsed(s->stream); 97dbcc3475SJon Smirl 98dbcc3475SJon Smirl return IRQ_HANDLED; 9989dd0842SJon Smirl } 10089dd0842SJon Smirl 10189dd0842SJon Smirl /** 102cebe7767SJon Smirl * psc_dma_trigger: start and stop the DMA transfer. 10389dd0842SJon Smirl * 10489dd0842SJon Smirl * This function is called by ALSA to start, stop, pause, and resume the DMA 10589dd0842SJon Smirl * transfer of data. 10689dd0842SJon Smirl */ 1076d1048bcSKuninori Morimoto static int psc_dma_trigger(struct snd_soc_component *component, 1086d1048bcSKuninori Morimoto struct snd_pcm_substream *substream, int cmd) 10989dd0842SJon Smirl { 1109f5f078aSKuninori Morimoto struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 11117198ae7SKuninori Morimoto struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); 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 .period_bytes_max = 1024 * 1024, 20189dd0842SJon Smirl .period_bytes_min = 32, 20289dd0842SJon Smirl .periods_min = 2, 20389dd0842SJon Smirl .periods_max = 256, 20489dd0842SJon Smirl .buffer_bytes_max = 2 * 1024 * 1024, 205dbcc3475SJon Smirl .fifo_size = 512, 20689dd0842SJon Smirl }; 20789dd0842SJon Smirl 2086d1048bcSKuninori Morimoto static int psc_dma_open(struct snd_soc_component *component, 2096d1048bcSKuninori Morimoto struct snd_pcm_substream *substream) 21089dd0842SJon Smirl { 211dbcc3475SJon Smirl struct snd_pcm_runtime *runtime = substream->runtime; 2129f5f078aSKuninori Morimoto struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 21317198ae7SKuninori Morimoto struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); 214cebe7767SJon Smirl struct psc_dma_stream *s; 215dbcc3475SJon Smirl int rc; 21689dd0842SJon Smirl 217dbcc3475SJon Smirl dev_dbg(psc_dma->dev, "psc_dma_open(substream=%p)\n", substream); 21889dd0842SJon Smirl 21989dd0842SJon Smirl if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) 220cebe7767SJon Smirl s = &psc_dma->capture; 22189dd0842SJon Smirl else 222cebe7767SJon Smirl s = &psc_dma->playback; 22389dd0842SJon Smirl 224dbcc3475SJon Smirl snd_soc_set_runtime_hwparams(substream, &psc_dma_hardware); 225dbcc3475SJon Smirl 226dbcc3475SJon Smirl rc = snd_pcm_hw_constraint_integer(runtime, 227dbcc3475SJon Smirl SNDRV_PCM_HW_PARAM_PERIODS); 228dbcc3475SJon Smirl if (rc < 0) { 229dbcc3475SJon Smirl dev_err(substream->pcm->card->dev, "invalid buffer size\n"); 230dbcc3475SJon Smirl return rc; 231dbcc3475SJon Smirl } 23289dd0842SJon Smirl 23389dd0842SJon Smirl s->stream = substream; 23489dd0842SJon Smirl return 0; 23589dd0842SJon Smirl } 23689dd0842SJon Smirl 2376d1048bcSKuninori Morimoto static int psc_dma_close(struct snd_soc_component *component, 2386d1048bcSKuninori Morimoto struct snd_pcm_substream *substream) 23989dd0842SJon Smirl { 2409f5f078aSKuninori Morimoto struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 24117198ae7SKuninori Morimoto struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); 242cebe7767SJon Smirl struct psc_dma_stream *s; 24389dd0842SJon Smirl 244dbcc3475SJon Smirl dev_dbg(psc_dma->dev, "psc_dma_close(substream=%p)\n", substream); 24589dd0842SJon Smirl 24689dd0842SJon Smirl if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) 247cebe7767SJon Smirl s = &psc_dma->capture; 24889dd0842SJon Smirl else 249cebe7767SJon Smirl s = &psc_dma->playback; 25089dd0842SJon Smirl 251dbcc3475SJon Smirl if (!psc_dma->playback.active && 252dbcc3475SJon Smirl !psc_dma->capture.active) { 253dbcc3475SJon Smirl 254dbcc3475SJon Smirl /* Disable all interrupts and reset the PSC */ 255dbcc3475SJon Smirl out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr); 256dbcc3475SJon Smirl out_8(&psc_dma->psc_regs->command, 4 << 4); /* reset error */ 257dbcc3475SJon Smirl } 25889dd0842SJon Smirl s->stream = NULL; 25989dd0842SJon Smirl return 0; 26089dd0842SJon Smirl } 26189dd0842SJon Smirl 26289dd0842SJon Smirl static snd_pcm_uframes_t 2636d1048bcSKuninori Morimoto psc_dma_pointer(struct snd_soc_component *component, 2646d1048bcSKuninori Morimoto struct snd_pcm_substream *substream) 26589dd0842SJon Smirl { 2669f5f078aSKuninori Morimoto struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 26717198ae7SKuninori Morimoto struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); 268cebe7767SJon Smirl struct psc_dma_stream *s; 26989dd0842SJon Smirl dma_addr_t count; 27089dd0842SJon Smirl 27189dd0842SJon Smirl if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) 272cebe7767SJon Smirl s = &psc_dma->capture; 27389dd0842SJon Smirl else 274cebe7767SJon Smirl s = &psc_dma->playback; 27589dd0842SJon Smirl 2768f159d72SGrant Likely count = s->period_current * s->period_bytes; 27789dd0842SJon Smirl 27889dd0842SJon Smirl return bytes_to_frames(substream->runtime, count); 27989dd0842SJon Smirl } 28089dd0842SJon Smirl 2816d1048bcSKuninori Morimoto static int psc_dma_new(struct snd_soc_component *component, 2826d1048bcSKuninori Morimoto struct snd_soc_pcm_runtime *rtd) 28389dd0842SJon Smirl { 284552d1ef6SLiam Girdwood struct snd_card *card = rtd->card->snd_card; 28517198ae7SKuninori Morimoto struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0); 286552d1ef6SLiam Girdwood struct snd_pcm *pcm = rtd->pcm; 287dbcc3475SJon Smirl size_t size = psc_dma_hardware.buffer_bytes_max; 288c9bd5e69SRussell King int rc; 28989dd0842SJon Smirl 29060bceb80SKuninori Morimoto dev_dbg(component->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n", 29189dd0842SJon Smirl card, dai, pcm); 29289dd0842SJon Smirl 293c9bd5e69SRussell King rc = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); 294c9bd5e69SRussell King if (rc) 295c9bd5e69SRussell King return rc; 29689dd0842SJon Smirl 297*3610a6d1STakashi Iwai return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, card->dev, 298*3610a6d1STakashi Iwai size); 29989dd0842SJon Smirl } 30089dd0842SJon Smirl 30160bceb80SKuninori Morimoto static const struct snd_soc_component_driver mpc5200_audio_dma_component = { 30260bceb80SKuninori Morimoto .name = DRV_NAME, 3036d1048bcSKuninori Morimoto .open = psc_dma_open, 3046d1048bcSKuninori Morimoto .close = psc_dma_close, 3056d1048bcSKuninori Morimoto .pointer = psc_dma_pointer, 3066d1048bcSKuninori Morimoto .trigger = psc_dma_trigger, 3076d1048bcSKuninori Morimoto .pcm_construct = psc_dma_new, 30889dd0842SJon Smirl }; 30989dd0842SJon Smirl 310f515b673SEric Millbrandt int mpc5200_audio_dma_create(struct platform_device *op) 311dbcc3475SJon Smirl { 312dbcc3475SJon Smirl phys_addr_t fifo; 313dbcc3475SJon Smirl struct psc_dma *psc_dma; 314dbcc3475SJon Smirl struct resource res; 315dbcc3475SJon Smirl int size, irq, rc; 316dbcc3475SJon Smirl const __be32 *prop; 317dbcc3475SJon Smirl void __iomem *regs; 31833d7f778SJulia Lawall int ret; 319dbcc3475SJon Smirl 320dbcc3475SJon Smirl /* Fetch the registers and IRQ of the PSC */ 32161c7a080SGrant Likely irq = irq_of_parse_and_map(op->dev.of_node, 0); 32261c7a080SGrant Likely if (of_address_to_resource(op->dev.of_node, 0, &res)) { 323dbcc3475SJon Smirl dev_err(&op->dev, "Missing reg property\n"); 324dbcc3475SJon Smirl return -ENODEV; 325dbcc3475SJon Smirl } 32628f65c11SJoe Perches regs = ioremap(res.start, resource_size(&res)); 327dbcc3475SJon Smirl if (!regs) { 328dbcc3475SJon Smirl dev_err(&op->dev, "Could not map registers\n"); 329dbcc3475SJon Smirl return -ENODEV; 330dbcc3475SJon Smirl } 331dbcc3475SJon Smirl 332dbcc3475SJon Smirl /* Allocate and initialize the driver private data */ 333dbcc3475SJon Smirl psc_dma = kzalloc(sizeof *psc_dma, GFP_KERNEL); 334dbcc3475SJon Smirl if (!psc_dma) { 33533d7f778SJulia Lawall ret = -ENOMEM; 33633d7f778SJulia Lawall goto out_unmap; 337dbcc3475SJon Smirl } 338dbcc3475SJon Smirl 339dbcc3475SJon Smirl /* Get the PSC ID */ 34061c7a080SGrant Likely prop = of_get_property(op->dev.of_node, "cell-index", &size); 34133d7f778SJulia Lawall if (!prop || size < sizeof *prop) { 34233d7f778SJulia Lawall ret = -ENODEV; 34333d7f778SJulia Lawall goto out_free; 34433d7f778SJulia Lawall } 345dbcc3475SJon Smirl 346dbcc3475SJon Smirl spin_lock_init(&psc_dma->lock); 3470827d6baSGrant Likely mutex_init(&psc_dma->mutex); 348dbcc3475SJon Smirl psc_dma->id = be32_to_cpu(*prop); 349dbcc3475SJon Smirl psc_dma->irq = irq; 350dbcc3475SJon Smirl psc_dma->psc_regs = regs; 351dbcc3475SJon Smirl psc_dma->fifo_regs = regs + sizeof *psc_dma->psc_regs; 352dbcc3475SJon Smirl psc_dma->dev = &op->dev; 353dbcc3475SJon Smirl psc_dma->playback.psc_dma = psc_dma; 354dbcc3475SJon Smirl psc_dma->capture.psc_dma = psc_dma; 35591ab7743SPierre-Louis Bossart snprintf(psc_dma->name, sizeof(psc_dma->name), "PSC%d", psc_dma->id); 356dbcc3475SJon Smirl 357dbcc3475SJon Smirl /* Find the address of the fifo data registers and setup the 358dbcc3475SJon Smirl * DMA tasks */ 359dbcc3475SJon Smirl fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32); 360dbcc3475SJon Smirl psc_dma->capture.bcom_task = 361dbcc3475SJon Smirl bcom_psc_gen_bd_rx_init(psc_dma->id, 10, fifo, 512); 362dbcc3475SJon Smirl psc_dma->playback.bcom_task = 363dbcc3475SJon Smirl bcom_psc_gen_bd_tx_init(psc_dma->id, 10, fifo); 364dbcc3475SJon Smirl if (!psc_dma->capture.bcom_task || 365dbcc3475SJon Smirl !psc_dma->playback.bcom_task) { 366dbcc3475SJon Smirl dev_err(&op->dev, "Could not allocate bestcomm tasks\n"); 36733d7f778SJulia Lawall ret = -ENODEV; 36833d7f778SJulia Lawall goto out_free; 369dbcc3475SJon Smirl } 370dbcc3475SJon Smirl 371dbcc3475SJon Smirl /* Disable all interrupts and reset the PSC */ 372dbcc3475SJon Smirl out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr); 373dbcc3475SJon Smirl /* reset receiver */ 374dbcc3475SJon Smirl out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_RX); 375dbcc3475SJon Smirl /* reset transmitter */ 376dbcc3475SJon Smirl out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_TX); 377dbcc3475SJon Smirl /* reset error */ 378dbcc3475SJon Smirl out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_ERR_STAT); 379dbcc3475SJon Smirl /* reset mode */ 380dbcc3475SJon Smirl out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_SEL_MODE_REG_1); 381dbcc3475SJon Smirl 382dbcc3475SJon Smirl /* Set up mode register; 383dbcc3475SJon Smirl * First write: RxRdy (FIFO Alarm) generates rx FIFO irq 384dbcc3475SJon Smirl * Second write: register Normal mode for non loopback 385dbcc3475SJon Smirl */ 386dbcc3475SJon Smirl out_8(&psc_dma->psc_regs->mode, 0); 387dbcc3475SJon Smirl out_8(&psc_dma->psc_regs->mode, 0); 388dbcc3475SJon Smirl 389dbcc3475SJon Smirl /* Set the TX and RX fifo alarm thresholds */ 390dbcc3475SJon Smirl out_be16(&psc_dma->fifo_regs->rfalarm, 0x100); 391dbcc3475SJon Smirl out_8(&psc_dma->fifo_regs->rfcntl, 0x4); 392dbcc3475SJon Smirl out_be16(&psc_dma->fifo_regs->tfalarm, 0x100); 393dbcc3475SJon Smirl out_8(&psc_dma->fifo_regs->tfcntl, 0x7); 394dbcc3475SJon Smirl 395dbcc3475SJon Smirl /* Lookup the IRQ numbers */ 396dbcc3475SJon Smirl psc_dma->playback.irq = 397dbcc3475SJon Smirl bcom_get_task_irq(psc_dma->playback.bcom_task); 398dbcc3475SJon Smirl psc_dma->capture.irq = 399dbcc3475SJon Smirl bcom_get_task_irq(psc_dma->capture.bcom_task); 400dbcc3475SJon Smirl 401dbcc3475SJon Smirl rc = request_irq(psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED, 402dbcc3475SJon Smirl "psc-dma-status", psc_dma); 403a68cc8daSGrant Likely rc |= request_irq(psc_dma->capture.irq, &psc_dma_bcom_irq, IRQF_SHARED, 404dbcc3475SJon Smirl "psc-dma-capture", &psc_dma->capture); 405a68cc8daSGrant Likely rc |= request_irq(psc_dma->playback.irq, &psc_dma_bcom_irq, IRQF_SHARED, 406dbcc3475SJon Smirl "psc-dma-playback", &psc_dma->playback); 407dbcc3475SJon Smirl if (rc) { 40833d7f778SJulia Lawall ret = -ENODEV; 40933d7f778SJulia Lawall goto out_irq; 410dbcc3475SJon Smirl } 411dbcc3475SJon Smirl 412dbcc3475SJon Smirl /* Save what we've done so it can be found again later */ 413dbcc3475SJon Smirl dev_set_drvdata(&op->dev, psc_dma); 414dbcc3475SJon Smirl 415dbcc3475SJon Smirl /* Tell the ASoC OF helpers about it */ 41660bceb80SKuninori Morimoto return devm_snd_soc_register_component(&op->dev, 41760bceb80SKuninori Morimoto &mpc5200_audio_dma_component, NULL, 0); 41833d7f778SJulia Lawall out_irq: 41933d7f778SJulia Lawall free_irq(psc_dma->irq, psc_dma); 42033d7f778SJulia Lawall free_irq(psc_dma->capture.irq, &psc_dma->capture); 42133d7f778SJulia Lawall free_irq(psc_dma->playback.irq, &psc_dma->playback); 42233d7f778SJulia Lawall out_free: 42333d7f778SJulia Lawall kfree(psc_dma); 42433d7f778SJulia Lawall out_unmap: 42533d7f778SJulia Lawall iounmap(regs); 42633d7f778SJulia Lawall return ret; 427dbcc3475SJon Smirl } 428f515b673SEric Millbrandt EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create); 429dbcc3475SJon Smirl 430f515b673SEric Millbrandt int mpc5200_audio_dma_destroy(struct platform_device *op) 431dbcc3475SJon Smirl { 432dbcc3475SJon Smirl struct psc_dma *psc_dma = dev_get_drvdata(&op->dev); 433dbcc3475SJon Smirl 434dbcc3475SJon Smirl dev_dbg(&op->dev, "mpc5200_audio_dma_destroy()\n"); 435dbcc3475SJon Smirl 436dbcc3475SJon Smirl bcom_gen_bd_rx_release(psc_dma->capture.bcom_task); 437dbcc3475SJon Smirl bcom_gen_bd_tx_release(psc_dma->playback.bcom_task); 438dbcc3475SJon Smirl 439dbcc3475SJon Smirl /* Release irqs */ 440dbcc3475SJon Smirl free_irq(psc_dma->irq, psc_dma); 441dbcc3475SJon Smirl free_irq(psc_dma->capture.irq, &psc_dma->capture); 442dbcc3475SJon Smirl free_irq(psc_dma->playback.irq, &psc_dma->playback); 443dbcc3475SJon Smirl 444dbcc3475SJon Smirl iounmap(psc_dma->psc_regs); 445dbcc3475SJon Smirl kfree(psc_dma); 446dbcc3475SJon Smirl dev_set_drvdata(&op->dev, NULL); 447dbcc3475SJon Smirl 448dbcc3475SJon Smirl return 0; 449dbcc3475SJon Smirl } 450f515b673SEric Millbrandt EXPORT_SYMBOL_GPL(mpc5200_audio_dma_destroy); 451dbcc3475SJon Smirl 452dbcc3475SJon Smirl MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>"); 453dbcc3475SJon Smirl MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver"); 454dbcc3475SJon Smirl MODULE_LICENSE("GPL"); 455