mpc5200_dma.c 14.7 KB
Newer Older
1 2 3 4 5
/*
 * Freescale MPC5200 PSC DMA
 * ALSA SoC Platform driver
 *
 * Copyright (C) 2008 Secret Lab Technologies Ltd.
6
 * Copyright (C) 2009 Jon Smirl, Digispeaker
7 8 9 10
 */

#include <linux/module.h>
#include <linux/of_device.h>
11
#include <linux/slab.h>
12
#include <linux/of_platform.h>
13 14 15 16 17 18 19 20 21 22 23 24

#include <sound/soc.h>

#include <sysdev/bestcomm/bestcomm.h>
#include <sysdev/bestcomm/gen_bd.h>
#include <asm/mpc52xx_psc.h>

#include "mpc5200_dma.h"

/*
 * Interrupt handlers
 */
25
static irqreturn_t psc_dma_status_irq(int irq, void *_psc_dma)
26
{
27 28
	struct psc_dma *psc_dma = _psc_dma;
	struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
29 30 31 32 33
	u16 isr;

	isr = in_be16(&regs->mpc52xx_psc_isr);

	/* Playback underrun error */
34 35
	if (psc_dma->playback.active && (isr & MPC52xx_PSC_IMR_TXEMP))
		psc_dma->stats.underrun_count++;
36 37

	/* Capture overrun error */
38 39
	if (psc_dma->capture.active && (isr & MPC52xx_PSC_IMR_ORERR))
		psc_dma->stats.overrun_count++;
40

41
	out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
42 43 44 45 46

	return IRQ_HANDLED;
}

/**
47
 * psc_dma_bcom_enqueue_next_buffer - Enqueue another audio buffer
48 49 50 51 52 53 54 55
 * @s: pointer to stream private data structure
 *
 * Enqueues another audio period buffer into the bestcomm queue.
 *
 * Note: The routine must only be called when there is space available in
 * the queue.  Otherwise the enqueue will fail and the audio ring buffer
 * will get out of sync
 */
56
static void psc_dma_bcom_enqueue_next_buffer(struct psc_dma_stream *s)
57 58 59 60 61 62
{
	struct bcom_bd *bd;

	/* Prepare and enqueue the next buffer descriptor */
	bd = bcom_prepare_next_buffer(s->bcom_task);
	bd->status = s->period_bytes;
63
	bd->data[0] = s->runtime->dma_addr + (s->period_next * s->period_bytes);
64 65 66
	bcom_submit_next_buffer(s->bcom_task, NULL);

	/* Update for next period */
67
	s->period_next = (s->period_next + 1) % s->runtime->periods;
68 69 70
}

/* Bestcomm DMA irq handler */
71
static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream)
72
{
73
	struct psc_dma_stream *s = _psc_dma_stream;
74

75 76 77 78 79
	spin_lock(&s->psc_dma->lock);
	/* For each finished period, dequeue the completed period buffer
	 * and enqueue a new one in it's place. */
	while (bcom_buffer_done(s->bcom_task)) {
		bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
80

81
		s->period_current = (s->period_current+1) % s->runtime->periods;
82
		s->period_count++;
83 84

		psc_dma_bcom_enqueue_next_buffer(s);
85
	}
86
	spin_unlock(&s->psc_dma->lock);
87

88 89 90 91 92 93
	/* If the stream is active, then also inform the PCM middle layer
	 * of the period finished event. */
	if (s->active)
		snd_pcm_period_elapsed(s->stream);

	return IRQ_HANDLED;
94 95
}

96
static int psc_dma_hw_free(struct snd_pcm_substream *substream)
97 98 99 100 101 102
{
	snd_pcm_set_runtime_buffer(substream, NULL);
	return 0;
}

/**
103
 * psc_dma_trigger: start and stop the DMA transfer.
104 105 106 107
 *
 * This function is called by ALSA to start, stop, pause, and resume the DMA
 * transfer of data.
 */
108
static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
109 110
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
111
	struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
112
	struct snd_pcm_runtime *runtime = substream->runtime;
113
	struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
114
	struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
115 116
	u16 imr;
	unsigned long flags;
117
	int i;
118 119 120

	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
121 122 123
		dev_dbg(psc_dma->dev, "START: stream=%i fbits=%u ps=%u #p=%u\n",
			substream->pstr->stream, runtime->frame_bits,
			(int)runtime->period_size, runtime->periods);
124 125
		s->period_bytes = frames_to_bytes(runtime,
						  runtime->period_size);
126 127
		s->period_next = 0;
		s->period_current = 0;
128
		s->active = 1;
129
		s->period_count = 0;
130 131 132 133 134 135 136
		s->runtime = runtime;

		/* Fill up the bestcomm bd queue and enable DMA.
		 * This will begin filling the PSC's fifo.
		 */
		spin_lock_irqsave(&psc_dma->lock, flags);

137
		if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
138
			bcom_gen_bd_rx_reset(s->bcom_task);
139
		else
140
			bcom_gen_bd_tx_reset(s->bcom_task);
141 142 143 144

		for (i = 0; i < runtime->periods; i++)
			if (!bcom_queue_full(s->bcom_task))
				psc_dma_bcom_enqueue_next_buffer(s);
145 146

		bcom_enable(s->bcom_task);
147
		spin_unlock_irqrestore(&psc_dma->lock, flags);
148

149 150
		out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);

151 152 153
		break;

	case SNDRV_PCM_TRIGGER_STOP:
154 155
		dev_dbg(psc_dma->dev, "STOP: stream=%i periods_count=%i\n",
			substream->pstr->stream, s->period_count);
156 157
		s->active = 0;

158
		spin_lock_irqsave(&psc_dma->lock, flags);
159
		bcom_disable(s->bcom_task);
160 161 162 163 164
		if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
			bcom_gen_bd_rx_reset(s->bcom_task);
		else
			bcom_gen_bd_tx_reset(s->bcom_task);
		spin_unlock_irqrestore(&psc_dma->lock, flags);
165 166 167 168

		break;

	default:
169 170
		dev_dbg(psc_dma->dev, "unhandled trigger: stream=%i cmd=%i\n",
			substream->pstr->stream, cmd);
171 172 173 174 175
		return -EINVAL;
	}

	/* Update interrupt enable settings */
	imr = 0;
176
	if (psc_dma->playback.active)
177
		imr |= MPC52xx_PSC_IMR_TXEMP;
178
	if (psc_dma->capture.active)
179
		imr |= MPC52xx_PSC_IMR_ORERR;
180
	out_be16(&regs->isr_imr.imr, psc_dma->imr | imr);
181 182 183 184 185 186 187 188 189 190 191 192 193

	return 0;
}


/* ---------------------------------------------------------------------
 * The PSC DMA 'ASoC platform' driver
 *
 * Can be referenced by an 'ASoC machine' driver
 * This driver only deals with the audio bus; it doesn't have any
 * interaction with the attached codec
 */

194
static const struct snd_pcm_hardware psc_dma_hardware = {
195 196 197 198
	.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
		SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
		SNDRV_PCM_INFO_BATCH,
	.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |
199
		SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE,
200 201
	.rate_min = 8000,
	.rate_max = 48000,
202
	.channels_min = 1,
203 204 205 206 207 208
	.channels_max = 2,
	.period_bytes_max	= 1024 * 1024,
	.period_bytes_min	= 32,
	.periods_min		= 2,
	.periods_max		= 256,
	.buffer_bytes_max	= 2 * 1024 * 1024,
209
	.fifo_size		= 512,
210 211
};

212
static int psc_dma_open(struct snd_pcm_substream *substream)
213
{
214
	struct snd_pcm_runtime *runtime = substream->runtime;
215
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
216
	struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
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
	else
225
		s = &psc_dma->playback;
226

227 228 229 230 231 232 233 234
	snd_soc_set_runtime_hwparams(substream, &psc_dma_hardware);

	rc = snd_pcm_hw_constraint_integer(runtime,
		SNDRV_PCM_HW_PARAM_PERIODS);
	if (rc < 0) {
		dev_err(substream->pcm->card->dev, "invalid buffer size\n");
		return rc;
	}
235 236 237 238 239

	s->stream = substream;
	return 0;
}

240
static int psc_dma_close(struct snd_pcm_substream *substream)
241 242
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
243
	struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
244
	struct psc_dma_stream *s;
245

246
	dev_dbg(psc_dma->dev, "psc_dma_close(substream=%p)\n", substream);
247 248

	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
249
		s = &psc_dma->capture;
250
	else
251
		s = &psc_dma->playback;
252

253 254 255 256 257 258 259
	if (!psc_dma->playback.active &&
	    !psc_dma->capture.active) {

		/* Disable all interrupts and reset the PSC */
		out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
		out_8(&psc_dma->psc_regs->command, 4 << 4); /* reset error */
	}
260 261 262 263 264
	s->stream = NULL;
	return 0;
}

static snd_pcm_uframes_t
265
psc_dma_pointer(struct snd_pcm_substream *substream)
266 267
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
268
	struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
269
	struct psc_dma_stream *s;
270 271 272
	dma_addr_t count;

	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
273
		s = &psc_dma->capture;
274
	else
275
		s = &psc_dma->playback;
276

277
	count = s->period_current * s->period_bytes;
278 279 280 281

	return bytes_to_frames(substream->runtime, count);
}

282 283 284 285 286 287 288 289 290 291 292 293 294
static int
psc_dma_hw_params(struct snd_pcm_substream *substream,
			 struct snd_pcm_hw_params *params)
{
	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);

	return 0;
}

static struct snd_pcm_ops psc_dma_ops = {
	.open		= psc_dma_open,
	.close		= psc_dma_close,
	.hw_free	= psc_dma_hw_free,
295
	.ioctl		= snd_pcm_lib_ioctl,
296 297 298
	.pointer	= psc_dma_pointer,
	.trigger	= psc_dma_trigger,
	.hw_params	= psc_dma_hw_params,
299 300
};

301
static u64 psc_dma_dmamask = 0xffffffff;
302
static int psc_dma_new(struct snd_soc_pcm_runtime *rtd)
303
{
304 305 306
	struct snd_card *card = rtd->card->snd_card;
	struct snd_soc_dai *dai = rtd->cpu_dai;
	struct snd_pcm *pcm = rtd->pcm;
307
	struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
308
	size_t size = psc_dma_hardware.buffer_bytes_max;
309 310
	int rc = 0;

311
	dev_dbg(rtd->platform->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n",
312 313 314
		card, dai, pcm);

	if (!card->dev->dma_mask)
315
		card->dev->dma_mask = &psc_dma_dmamask;
316 317 318 319
	if (!card->dev->coherent_dma_mask)
		card->dev->coherent_dma_mask = 0xffffffff;

	if (pcm->streams[0].substream) {
320 321
		rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev,
				size, &pcm->streams[0].substream->dma_buffer);
322 323 324 325 326
		if (rc)
			goto playback_alloc_err;
	}

	if (pcm->streams[1].substream) {
327 328
		rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev,
				size, &pcm->streams[1].substream->dma_buffer);
329 330 331 332
		if (rc)
			goto capture_alloc_err;
	}

333 334
	if (rtd->codec->ac97)
		rtd->codec->ac97->private_data = psc_dma;
335

336 337 338 339 340
	return 0;

 capture_alloc_err:
	if (pcm->streams[0].substream)
		snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
341

342 343
 playback_alloc_err:
	dev_err(card->dev, "Cannot allocate buffer(s)\n");
344

345 346 347
	return -ENOMEM;
}

348
static void psc_dma_free(struct snd_pcm *pcm)
349 350 351 352 353
{
	struct snd_soc_pcm_runtime *rtd = pcm->private_data;
	struct snd_pcm_substream *substream;
	int stream;

354
	dev_dbg(rtd->platform->dev, "psc_dma_free(pcm=%p)\n", pcm);
355 356 357 358 359 360 361 362 363 364 365

	for (stream = 0; stream < 2; stream++) {
		substream = pcm->streams[stream].substream;
		if (substream) {
			snd_dma_free_pages(&substream->dma_buffer);
			substream->dma_buffer.area = NULL;
			substream->dma_buffer.addr = 0;
		}
	}
}

366 367
static struct snd_soc_platform_driver mpc5200_audio_dma_platform = {
	.ops		= &psc_dma_ops,
368 369
	.pcm_new	= &psc_dma_new,
	.pcm_free	= &psc_dma_free,
370
};
371

372
static int mpc5200_hpcd_probe(struct platform_device *op)
373 374 375 376 377 378 379
{
	phys_addr_t fifo;
	struct psc_dma *psc_dma;
	struct resource res;
	int size, irq, rc;
	const __be32 *prop;
	void __iomem *regs;
380
	int ret;
381 382

	/* Fetch the registers and IRQ of the PSC */
383 384
	irq = irq_of_parse_and_map(op->dev.of_node, 0);
	if (of_address_to_resource(op->dev.of_node, 0, &res)) {
385 386 387
		dev_err(&op->dev, "Missing reg property\n");
		return -ENODEV;
	}
388
	regs = ioremap(res.start, resource_size(&res));
389 390 391 392 393 394 395 396
	if (!regs) {
		dev_err(&op->dev, "Could not map registers\n");
		return -ENODEV;
	}

	/* Allocate and initialize the driver private data */
	psc_dma = kzalloc(sizeof *psc_dma, GFP_KERNEL);
	if (!psc_dma) {
397 398
		ret = -ENOMEM;
		goto out_unmap;
399 400 401
	}

	/* Get the PSC ID */
402
	prop = of_get_property(op->dev.of_node, "cell-index", &size);
403 404 405 406
	if (!prop || size < sizeof *prop) {
		ret = -ENODEV;
		goto out_free;
	}
407 408

	spin_lock_init(&psc_dma->lock);
409
	mutex_init(&psc_dma->mutex);
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
	psc_dma->id = be32_to_cpu(*prop);
	psc_dma->irq = irq;
	psc_dma->psc_regs = regs;
	psc_dma->fifo_regs = regs + sizeof *psc_dma->psc_regs;
	psc_dma->dev = &op->dev;
	psc_dma->playback.psc_dma = psc_dma;
	psc_dma->capture.psc_dma = psc_dma;
	snprintf(psc_dma->name, sizeof psc_dma->name, "PSC%u", psc_dma->id);

	/* Find the address of the fifo data registers and setup the
	 * DMA tasks */
	fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32);
	psc_dma->capture.bcom_task =
		bcom_psc_gen_bd_rx_init(psc_dma->id, 10, fifo, 512);
	psc_dma->playback.bcom_task =
		bcom_psc_gen_bd_tx_init(psc_dma->id, 10, fifo);
	if (!psc_dma->capture.bcom_task ||
	    !psc_dma->playback.bcom_task) {
		dev_err(&op->dev, "Could not allocate bestcomm tasks\n");
429 430
		ret = -ENODEV;
		goto out_free;
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
	}

	/* Disable all interrupts and reset the PSC */
	out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
	 /* reset receiver */
	out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_RX);
	 /* reset transmitter */
	out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_TX);
	 /* reset error */
	out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_ERR_STAT);
	 /* reset mode */
	out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_SEL_MODE_REG_1);

	/* Set up mode register;
	 * First write: RxRdy (FIFO Alarm) generates rx FIFO irq
	 * Second write: register Normal mode for non loopback
	 */
	out_8(&psc_dma->psc_regs->mode, 0);
	out_8(&psc_dma->psc_regs->mode, 0);

	/* Set the TX and RX fifo alarm thresholds */
	out_be16(&psc_dma->fifo_regs->rfalarm, 0x100);
	out_8(&psc_dma->fifo_regs->rfcntl, 0x4);
	out_be16(&psc_dma->fifo_regs->tfalarm, 0x100);
	out_8(&psc_dma->fifo_regs->tfcntl, 0x7);

	/* Lookup the IRQ numbers */
	psc_dma->playback.irq =
		bcom_get_task_irq(psc_dma->playback.bcom_task);
	psc_dma->capture.irq =
		bcom_get_task_irq(psc_dma->capture.bcom_task);

	rc = request_irq(psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED,
			 "psc-dma-status", psc_dma);
465
	rc |= request_irq(psc_dma->capture.irq, &psc_dma_bcom_irq, IRQF_SHARED,
466
			  "psc-dma-capture", &psc_dma->capture);
467
	rc |= request_irq(psc_dma->playback.irq, &psc_dma_bcom_irq, IRQF_SHARED,
468 469
			  "psc-dma-playback", &psc_dma->playback);
	if (rc) {
470 471
		ret = -ENODEV;
		goto out_irq;
472
	}
473

474 475 476 477
	/* Save what we've done so it can be found again later */
	dev_set_drvdata(&op->dev, psc_dma);

	/* Tell the ASoC OF helpers about it */
478
	return snd_soc_register_platform(&op->dev, &mpc5200_audio_dma_platform);
479 480 481 482 483 484 485 486 487
out_irq:
	free_irq(psc_dma->irq, psc_dma);
	free_irq(psc_dma->capture.irq, &psc_dma->capture);
	free_irq(psc_dma->playback.irq, &psc_dma->playback);
out_free:
	kfree(psc_dma);
out_unmap:
	iounmap(regs);
	return ret;
488 489
}

490
static int mpc5200_hpcd_remove(struct platform_device *op)
491 492 493 494 495
{
	struct psc_dma *psc_dma = dev_get_drvdata(&op->dev);

	dev_dbg(&op->dev, "mpc5200_audio_dma_destroy()\n");

496
	snd_soc_unregister_platform(&op->dev);
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511

	bcom_gen_bd_rx_release(psc_dma->capture.bcom_task);
	bcom_gen_bd_tx_release(psc_dma->playback.bcom_task);

	/* Release irqs */
	free_irq(psc_dma->irq, psc_dma);
	free_irq(psc_dma->capture.irq, &psc_dma->capture);
	free_irq(psc_dma->playback.irq, &psc_dma->playback);

	iounmap(psc_dma->psc_regs);
	kfree(psc_dma);
	dev_set_drvdata(&op->dev, NULL);

	return 0;
}
512 513

static struct of_device_id mpc5200_hpcd_match[] = {
514
	{ .compatible = "fsl,mpc5200-pcm", },
515 516 517 518
	{}
};
MODULE_DEVICE_TABLE(of, mpc5200_hpcd_match);

519
static struct platform_driver mpc5200_hpcd_of_driver = {
520 521
	.probe		= mpc5200_hpcd_probe,
	.remove		= mpc5200_hpcd_remove,
522
	.driver = {
523 524 525 526
		.owner		= THIS_MODULE,
		.name		= "mpc5200-pcm-audio",
		.of_match_table    = mpc5200_hpcd_match,
	}
527 528 529 530
};

static int __init mpc5200_hpcd_init(void)
{
531
	return platform_driver_register(&mpc5200_hpcd_of_driver);
532
}
533
module_init(mpc5200_hpcd_init);
534 535 536

static void __exit mpc5200_hpcd_exit(void)
{
537
	platform_driver_unregister(&mpc5200_hpcd_of_driver);
538 539
}
module_exit(mpc5200_hpcd_exit);
540 541 542 543

MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver");
MODULE_LICENSE("GPL");