458 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2//3// Freescale MPC5200 PSC DMA4// ALSA SoC Platform driver5//6// Copyright (C) 2008 Secret Lab Technologies Ltd.7// Copyright (C) 2009 Jon Smirl, Digispeaker8 9#include <linux/module.h>10#include <linux/dma-mapping.h>11#include <linux/slab.h>12#include <linux/of.h>13#include <linux/of_address.h>14#include <linux/of_irq.h>15#include <linux/platform_device.h>16 17#include <sound/soc.h>18 19#include <linux/fsl/bestcomm/bestcomm.h>20#include <linux/fsl/bestcomm/gen_bd.h>21#include <asm/mpc52xx_psc.h>22 23#include "mpc5200_dma.h"24 25#define DRV_NAME "mpc5200_dma"26 27/*28 * Interrupt handlers29 */30static irqreturn_t psc_dma_status_irq(int irq, void *_psc_dma)31{32 struct psc_dma *psc_dma = _psc_dma;33 struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;34 u16 isr;35 36 isr = in_be16(®s->mpc52xx_psc_isr);37 38 /* Playback underrun error */39 if (psc_dma->playback.active && (isr & MPC52xx_PSC_IMR_TXEMP))40 psc_dma->stats.underrun_count++;41 42 /* Capture overrun error */43 if (psc_dma->capture.active && (isr & MPC52xx_PSC_IMR_ORERR))44 psc_dma->stats.overrun_count++;45 46 out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT);47 48 return IRQ_HANDLED;49}50 51/**52 * psc_dma_bcom_enqueue_next_buffer - Enqueue another audio buffer53 * @s: pointer to stream private data structure54 *55 * Enqueues another audio period buffer into the bestcomm queue.56 *57 * Note: The routine must only be called when there is space available in58 * the queue. Otherwise the enqueue will fail and the audio ring buffer59 * will get out of sync60 */61static void psc_dma_bcom_enqueue_next_buffer(struct psc_dma_stream *s)62{63 struct bcom_bd *bd;64 65 /* Prepare and enqueue the next buffer descriptor */66 bd = bcom_prepare_next_buffer(s->bcom_task);67 bd->status = s->period_bytes;68 bd->data[0] = s->runtime->dma_addr + (s->period_next * s->period_bytes);69 bcom_submit_next_buffer(s->bcom_task, NULL);70 71 /* Update for next period */72 s->period_next = (s->period_next + 1) % s->runtime->periods;73}74 75/* Bestcomm DMA irq handler */76static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream)77{78 struct psc_dma_stream *s = _psc_dma_stream;79 80 spin_lock(&s->psc_dma->lock);81 /* For each finished period, dequeue the completed period buffer82 * and enqueue a new one in it's place. */83 while (bcom_buffer_done(s->bcom_task)) {84 bcom_retrieve_buffer(s->bcom_task, NULL, NULL);85 86 s->period_current = (s->period_current+1) % s->runtime->periods;87 s->period_count++;88 89 psc_dma_bcom_enqueue_next_buffer(s);90 }91 spin_unlock(&s->psc_dma->lock);92 93 /* If the stream is active, then also inform the PCM middle layer94 * of the period finished event. */95 if (s->active)96 snd_pcm_period_elapsed(s->stream);97 98 return IRQ_HANDLED;99}100 101/**102 * psc_dma_trigger: start and stop the DMA transfer.103 * @component: triggered component104 * @substream: triggered substream105 * @cmd: triggered command106 *107 * This function is called by ALSA to start, stop, pause, and resume the DMA108 * transfer of data.109 */110static int psc_dma_trigger(struct snd_soc_component *component,111 struct snd_pcm_substream *substream, int cmd)112{113 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);114 struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));115 struct snd_pcm_runtime *runtime = substream->runtime;116 struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);117 struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;118 u16 imr;119 unsigned long flags;120 int i;121 122 switch (cmd) {123 case SNDRV_PCM_TRIGGER_START:124 dev_dbg(psc_dma->dev, "START: stream=%i fbits=%u ps=%u #p=%u\n",125 substream->pstr->stream, runtime->frame_bits,126 (int)runtime->period_size, runtime->periods);127 s->period_bytes = frames_to_bytes(runtime,128 runtime->period_size);129 s->period_next = 0;130 s->period_current = 0;131 s->active = 1;132 s->period_count = 0;133 s->runtime = runtime;134 135 /* Fill up the bestcomm bd queue and enable DMA.136 * This will begin filling the PSC's fifo.137 */138 spin_lock_irqsave(&psc_dma->lock, flags);139 140 if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)141 bcom_gen_bd_rx_reset(s->bcom_task);142 else143 bcom_gen_bd_tx_reset(s->bcom_task);144 145 for (i = 0; i < runtime->periods; i++)146 if (!bcom_queue_full(s->bcom_task))147 psc_dma_bcom_enqueue_next_buffer(s);148 149 bcom_enable(s->bcom_task);150 spin_unlock_irqrestore(&psc_dma->lock, flags);151 152 out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT);153 154 break;155 156 case SNDRV_PCM_TRIGGER_STOP:157 dev_dbg(psc_dma->dev, "STOP: stream=%i periods_count=%i\n",158 substream->pstr->stream, s->period_count);159 s->active = 0;160 161 spin_lock_irqsave(&psc_dma->lock, flags);162 bcom_disable(s->bcom_task);163 if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)164 bcom_gen_bd_rx_reset(s->bcom_task);165 else166 bcom_gen_bd_tx_reset(s->bcom_task);167 spin_unlock_irqrestore(&psc_dma->lock, flags);168 169 break;170 171 default:172 dev_dbg(psc_dma->dev, "unhandled trigger: stream=%i cmd=%i\n",173 substream->pstr->stream, cmd);174 return -EINVAL;175 }176 177 /* Update interrupt enable settings */178 imr = 0;179 if (psc_dma->playback.active)180 imr |= MPC52xx_PSC_IMR_TXEMP;181 if (psc_dma->capture.active)182 imr |= MPC52xx_PSC_IMR_ORERR;183 out_be16(®s->isr_imr.imr, psc_dma->imr | imr);184 185 return 0;186}187 188 189/* ---------------------------------------------------------------------190 * The PSC DMA 'ASoC platform' driver191 *192 * Can be referenced by an 'ASoC machine' driver193 * This driver only deals with the audio bus; it doesn't have any194 * interaction with the attached codec195 */196 197static const struct snd_pcm_hardware psc_dma_hardware = {198 .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |199 SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |200 SNDRV_PCM_INFO_BATCH,201 .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |202 SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE,203 .period_bytes_max = 1024 * 1024,204 .period_bytes_min = 32,205 .periods_min = 2,206 .periods_max = 256,207 .buffer_bytes_max = 2 * 1024 * 1024,208 .fifo_size = 512,209};210 211static int psc_dma_open(struct snd_soc_component *component,212 struct snd_pcm_substream *substream)213{214 struct snd_pcm_runtime *runtime = substream->runtime;215 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);216 struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));217 struct psc_dma_stream *s;218 int rc;219 220 dev_dbg(psc_dma->dev, "psc_dma_open(substream=%p)\n", substream);221 222 if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)223 s = &psc_dma->capture;224 else225 s = &psc_dma->playback;226 227 snd_soc_set_runtime_hwparams(substream, &psc_dma_hardware);228 229 rc = snd_pcm_hw_constraint_integer(runtime,230 SNDRV_PCM_HW_PARAM_PERIODS);231 if (rc < 0) {232 dev_err(substream->pcm->card->dev, "invalid buffer size\n");233 return rc;234 }235 236 s->stream = substream;237 return 0;238}239 240static int psc_dma_close(struct snd_soc_component *component,241 struct snd_pcm_substream *substream)242{243 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);244 struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));245 struct psc_dma_stream *s;246 247 dev_dbg(psc_dma->dev, "psc_dma_close(substream=%p)\n", substream);248 249 if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)250 s = &psc_dma->capture;251 else252 s = &psc_dma->playback;253 254 if (!psc_dma->playback.active &&255 !psc_dma->capture.active) {256 257 /* Disable all interrupts and reset the PSC */258 out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);259 out_8(&psc_dma->psc_regs->command, 4 << 4); /* reset error */260 }261 s->stream = NULL;262 return 0;263}264 265static snd_pcm_uframes_t266psc_dma_pointer(struct snd_soc_component *component,267 struct snd_pcm_substream *substream)268{269 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);270 struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));271 struct psc_dma_stream *s;272 dma_addr_t count;273 274 if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)275 s = &psc_dma->capture;276 else277 s = &psc_dma->playback;278 279 count = s->period_current * s->period_bytes;280 281 return bytes_to_frames(substream->runtime, count);282}283 284static int psc_dma_new(struct snd_soc_component *component,285 struct snd_soc_pcm_runtime *rtd)286{287 struct snd_card *card = rtd->card->snd_card;288 struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0);289 struct snd_pcm *pcm = rtd->pcm;290 size_t size = psc_dma_hardware.buffer_bytes_max;291 int rc;292 293 dev_dbg(component->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n",294 card, dai, pcm);295 296 rc = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));297 if (rc)298 return rc;299 300 return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, card->dev,301 size);302}303 304static const struct snd_soc_component_driver mpc5200_audio_dma_component = {305 .name = DRV_NAME,306 .open = psc_dma_open,307 .close = psc_dma_close,308 .pointer = psc_dma_pointer,309 .trigger = psc_dma_trigger,310 .pcm_construct = psc_dma_new,311};312 313int mpc5200_audio_dma_create(struct platform_device *op)314{315 phys_addr_t fifo;316 struct psc_dma *psc_dma;317 struct resource res;318 int size, irq, rc;319 const __be32 *prop;320 void __iomem *regs;321 int ret;322 323 /* Fetch the registers and IRQ of the PSC */324 irq = irq_of_parse_and_map(op->dev.of_node, 0);325 if (of_address_to_resource(op->dev.of_node, 0, &res)) {326 dev_err(&op->dev, "Missing reg property\n");327 return -ENODEV;328 }329 regs = ioremap(res.start, resource_size(&res));330 if (!regs) {331 dev_err(&op->dev, "Could not map registers\n");332 return -ENODEV;333 }334 335 /* Allocate and initialize the driver private data */336 psc_dma = kzalloc(sizeof *psc_dma, GFP_KERNEL);337 if (!psc_dma) {338 ret = -ENOMEM;339 goto out_unmap;340 }341 342 /* Get the PSC ID */343 prop = of_get_property(op->dev.of_node, "cell-index", &size);344 if (!prop || size < sizeof *prop) {345 ret = -ENODEV;346 goto out_free;347 }348 349 spin_lock_init(&psc_dma->lock);350 mutex_init(&psc_dma->mutex);351 psc_dma->id = be32_to_cpu(*prop);352 psc_dma->irq = irq;353 psc_dma->psc_regs = regs;354 psc_dma->fifo_regs = regs + sizeof *psc_dma->psc_regs;355 psc_dma->dev = &op->dev;356 psc_dma->playback.psc_dma = psc_dma;357 psc_dma->capture.psc_dma = psc_dma;358 snprintf(psc_dma->name, sizeof(psc_dma->name), "PSC%d", psc_dma->id);359 360 /* Find the address of the fifo data registers and setup the361 * DMA tasks */362 fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32);363 psc_dma->capture.bcom_task =364 bcom_psc_gen_bd_rx_init(psc_dma->id, 10, fifo, 512);365 psc_dma->playback.bcom_task =366 bcom_psc_gen_bd_tx_init(psc_dma->id, 10, fifo);367 if (!psc_dma->capture.bcom_task ||368 !psc_dma->playback.bcom_task) {369 dev_err(&op->dev, "Could not allocate bestcomm tasks\n");370 ret = -ENODEV;371 goto out_free;372 }373 374 /* Disable all interrupts and reset the PSC */375 out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);376 /* reset receiver */377 out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_RX);378 /* reset transmitter */379 out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_TX);380 /* reset error */381 out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_ERR_STAT);382 /* reset mode */383 out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_SEL_MODE_REG_1);384 385 /* Set up mode register;386 * First write: RxRdy (FIFO Alarm) generates rx FIFO irq387 * Second write: register Normal mode for non loopback388 */389 out_8(&psc_dma->psc_regs->mode, 0);390 out_8(&psc_dma->psc_regs->mode, 0);391 392 /* Set the TX and RX fifo alarm thresholds */393 out_be16(&psc_dma->fifo_regs->rfalarm, 0x100);394 out_8(&psc_dma->fifo_regs->rfcntl, 0x4);395 out_be16(&psc_dma->fifo_regs->tfalarm, 0x100);396 out_8(&psc_dma->fifo_regs->tfcntl, 0x7);397 398 /* Lookup the IRQ numbers */399 psc_dma->playback.irq =400 bcom_get_task_irq(psc_dma->playback.bcom_task);401 psc_dma->capture.irq =402 bcom_get_task_irq(psc_dma->capture.bcom_task);403 404 rc = request_irq(psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED,405 "psc-dma-status", psc_dma);406 rc |= request_irq(psc_dma->capture.irq, &psc_dma_bcom_irq, IRQF_SHARED,407 "psc-dma-capture", &psc_dma->capture);408 rc |= request_irq(psc_dma->playback.irq, &psc_dma_bcom_irq, IRQF_SHARED,409 "psc-dma-playback", &psc_dma->playback);410 if (rc) {411 ret = -ENODEV;412 goto out_irq;413 }414 415 /* Save what we've done so it can be found again later */416 dev_set_drvdata(&op->dev, psc_dma);417 418 /* Tell the ASoC OF helpers about it */419 return devm_snd_soc_register_component(&op->dev,420 &mpc5200_audio_dma_component, NULL, 0);421out_irq:422 free_irq(psc_dma->irq, psc_dma);423 free_irq(psc_dma->capture.irq, &psc_dma->capture);424 free_irq(psc_dma->playback.irq, &psc_dma->playback);425out_free:426 kfree(psc_dma);427out_unmap:428 iounmap(regs);429 return ret;430}431EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create);432 433int mpc5200_audio_dma_destroy(struct platform_device *op)434{435 struct psc_dma *psc_dma = dev_get_drvdata(&op->dev);436 437 dev_dbg(&op->dev, "mpc5200_audio_dma_destroy()\n");438 439 bcom_gen_bd_rx_release(psc_dma->capture.bcom_task);440 bcom_gen_bd_tx_release(psc_dma->playback.bcom_task);441 442 /* Release irqs */443 free_irq(psc_dma->irq, psc_dma);444 free_irq(psc_dma->capture.irq, &psc_dma->capture);445 free_irq(psc_dma->playback.irq, &psc_dma->playback);446 447 iounmap(psc_dma->psc_regs);448 kfree(psc_dma);449 dev_set_drvdata(&op->dev, NULL);450 451 return 0;452}453EXPORT_SYMBOL_GPL(mpc5200_audio_dma_destroy);454 455MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");456MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver");457MODULE_LICENSE("GPL");458