xref: /openbmc/linux/sound/soc/bcm/cygnus-pcm.c (revision 6726d552)
1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright (C) 2014-2015 Broadcom Corporation
3 #include <linux/debugfs.h>
4 #include <linux/dma-mapping.h>
5 #include <linux/init.h>
6 #include <linux/io.h>
7 #include <linux/module.h>
8 #include <linux/slab.h>
9 #include <linux/timer.h>
10 #include <sound/core.h>
11 #include <sound/pcm.h>
12 #include <sound/pcm_params.h>
13 #include <sound/soc.h>
14 #include <sound/soc-dai.h>
15 
16 #include "cygnus-ssp.h"
17 
18 /* Register offset needed for ASoC PCM module */
19 
20 #define INTH_R5F_STATUS_OFFSET     0x040
21 #define INTH_R5F_CLEAR_OFFSET      0x048
22 #define INTH_R5F_MASK_SET_OFFSET   0x050
23 #define INTH_R5F_MASK_CLEAR_OFFSET 0x054
24 
25 #define BF_REARM_FREE_MARK_OFFSET 0x344
26 #define BF_REARM_FULL_MARK_OFFSET 0x348
27 
28 /* Ring Buffer Ctrl Regs --- Start */
29 /* AUD_FMM_BF_CTRL_SOURCECH_RINGBUF_X_RDADDR_REG_BASE */
30 #define SRC_RBUF_0_RDADDR_OFFSET 0x500
31 #define SRC_RBUF_1_RDADDR_OFFSET 0x518
32 #define SRC_RBUF_2_RDADDR_OFFSET 0x530
33 #define SRC_RBUF_3_RDADDR_OFFSET 0x548
34 #define SRC_RBUF_4_RDADDR_OFFSET 0x560
35 #define SRC_RBUF_5_RDADDR_OFFSET 0x578
36 #define SRC_RBUF_6_RDADDR_OFFSET 0x590
37 
38 /* AUD_FMM_BF_CTRL_SOURCECH_RINGBUF_X_WRADDR_REG_BASE */
39 #define SRC_RBUF_0_WRADDR_OFFSET 0x504
40 #define SRC_RBUF_1_WRADDR_OFFSET 0x51c
41 #define SRC_RBUF_2_WRADDR_OFFSET 0x534
42 #define SRC_RBUF_3_WRADDR_OFFSET 0x54c
43 #define SRC_RBUF_4_WRADDR_OFFSET 0x564
44 #define SRC_RBUF_5_WRADDR_OFFSET 0x57c
45 #define SRC_RBUF_6_WRADDR_OFFSET 0x594
46 
47 /* AUD_FMM_BF_CTRL_SOURCECH_RINGBUF_X_BASEADDR_REG_BASE */
48 #define SRC_RBUF_0_BASEADDR_OFFSET 0x508
49 #define SRC_RBUF_1_BASEADDR_OFFSET 0x520
50 #define SRC_RBUF_2_BASEADDR_OFFSET 0x538
51 #define SRC_RBUF_3_BASEADDR_OFFSET 0x550
52 #define SRC_RBUF_4_BASEADDR_OFFSET 0x568
53 #define SRC_RBUF_5_BASEADDR_OFFSET 0x580
54 #define SRC_RBUF_6_BASEADDR_OFFSET 0x598
55 
56 /* AUD_FMM_BF_CTRL_SOURCECH_RINGBUF_X_ENDADDR_REG_BASE */
57 #define SRC_RBUF_0_ENDADDR_OFFSET 0x50c
58 #define SRC_RBUF_1_ENDADDR_OFFSET 0x524
59 #define SRC_RBUF_2_ENDADDR_OFFSET 0x53c
60 #define SRC_RBUF_3_ENDADDR_OFFSET 0x554
61 #define SRC_RBUF_4_ENDADDR_OFFSET 0x56c
62 #define SRC_RBUF_5_ENDADDR_OFFSET 0x584
63 #define SRC_RBUF_6_ENDADDR_OFFSET 0x59c
64 
65 /* AUD_FMM_BF_CTRL_SOURCECH_RINGBUF_X_FREE_MARK_REG_BASE */
66 #define SRC_RBUF_0_FREE_MARK_OFFSET 0x510
67 #define SRC_RBUF_1_FREE_MARK_OFFSET 0x528
68 #define SRC_RBUF_2_FREE_MARK_OFFSET 0x540
69 #define SRC_RBUF_3_FREE_MARK_OFFSET 0x558
70 #define SRC_RBUF_4_FREE_MARK_OFFSET 0x570
71 #define SRC_RBUF_5_FREE_MARK_OFFSET 0x588
72 #define SRC_RBUF_6_FREE_MARK_OFFSET 0x5a0
73 
74 /* AUD_FMM_BF_CTRL_DESTCH_RINGBUF_X_RDADDR_REG_BASE */
75 #define DST_RBUF_0_RDADDR_OFFSET 0x5c0
76 #define DST_RBUF_1_RDADDR_OFFSET 0x5d8
77 #define DST_RBUF_2_RDADDR_OFFSET 0x5f0
78 #define DST_RBUF_3_RDADDR_OFFSET 0x608
79 #define DST_RBUF_4_RDADDR_OFFSET 0x620
80 #define DST_RBUF_5_RDADDR_OFFSET 0x638
81 
82 /* AUD_FMM_BF_CTRL_DESTCH_RINGBUF_X_WRADDR_REG_BASE */
83 #define DST_RBUF_0_WRADDR_OFFSET 0x5c4
84 #define DST_RBUF_1_WRADDR_OFFSET 0x5dc
85 #define DST_RBUF_2_WRADDR_OFFSET 0x5f4
86 #define DST_RBUF_3_WRADDR_OFFSET 0x60c
87 #define DST_RBUF_4_WRADDR_OFFSET 0x624
88 #define DST_RBUF_5_WRADDR_OFFSET 0x63c
89 
90 /* AUD_FMM_BF_CTRL_DESTCH_RINGBUF_X_BASEADDR_REG_BASE */
91 #define DST_RBUF_0_BASEADDR_OFFSET 0x5c8
92 #define DST_RBUF_1_BASEADDR_OFFSET 0x5e0
93 #define DST_RBUF_2_BASEADDR_OFFSET 0x5f8
94 #define DST_RBUF_3_BASEADDR_OFFSET 0x610
95 #define DST_RBUF_4_BASEADDR_OFFSET 0x628
96 #define DST_RBUF_5_BASEADDR_OFFSET 0x640
97 
98 /* AUD_FMM_BF_CTRL_DESTCH_RINGBUF_X_ENDADDR_REG_BASE */
99 #define DST_RBUF_0_ENDADDR_OFFSET 0x5cc
100 #define DST_RBUF_1_ENDADDR_OFFSET 0x5e4
101 #define DST_RBUF_2_ENDADDR_OFFSET 0x5fc
102 #define DST_RBUF_3_ENDADDR_OFFSET 0x614
103 #define DST_RBUF_4_ENDADDR_OFFSET 0x62c
104 #define DST_RBUF_5_ENDADDR_OFFSET 0x644
105 
106 /* AUD_FMM_BF_CTRL_DESTCH_RINGBUF_X_FULL_MARK_REG_BASE */
107 #define DST_RBUF_0_FULL_MARK_OFFSET 0x5d0
108 #define DST_RBUF_1_FULL_MARK_OFFSET 0x5e8
109 #define DST_RBUF_2_FULL_MARK_OFFSET 0x600
110 #define DST_RBUF_3_FULL_MARK_OFFSET 0x618
111 #define DST_RBUF_4_FULL_MARK_OFFSET 0x630
112 #define DST_RBUF_5_FULL_MARK_OFFSET 0x648
113 /* Ring Buffer Ctrl Regs --- End */
114 
115 /* Error Status Regs --- Start */
116 /* AUD_FMM_BF_ESR_ESRX_STATUS_REG_BASE */
117 #define ESR0_STATUS_OFFSET 0x900
118 #define ESR1_STATUS_OFFSET 0x918
119 #define ESR2_STATUS_OFFSET 0x930
120 #define ESR3_STATUS_OFFSET 0x948
121 #define ESR4_STATUS_OFFSET 0x960
122 
123 /* AUD_FMM_BF_ESR_ESRX_STATUS_CLEAR_REG_BASE */
124 #define ESR0_STATUS_CLR_OFFSET 0x908
125 #define ESR1_STATUS_CLR_OFFSET 0x920
126 #define ESR2_STATUS_CLR_OFFSET 0x938
127 #define ESR3_STATUS_CLR_OFFSET 0x950
128 #define ESR4_STATUS_CLR_OFFSET 0x968
129 
130 /* AUD_FMM_BF_ESR_ESRX_MASK_REG_BASE */
131 #define ESR0_MASK_STATUS_OFFSET 0x90c
132 #define ESR1_MASK_STATUS_OFFSET 0x924
133 #define ESR2_MASK_STATUS_OFFSET 0x93c
134 #define ESR3_MASK_STATUS_OFFSET 0x954
135 #define ESR4_MASK_STATUS_OFFSET 0x96c
136 
137 /* AUD_FMM_BF_ESR_ESRX_MASK_SET_REG_BASE */
138 #define ESR0_MASK_SET_OFFSET 0x910
139 #define ESR1_MASK_SET_OFFSET 0x928
140 #define ESR2_MASK_SET_OFFSET 0x940
141 #define ESR3_MASK_SET_OFFSET 0x958
142 #define ESR4_MASK_SET_OFFSET 0x970
143 
144 /* AUD_FMM_BF_ESR_ESRX_MASK_CLEAR_REG_BASE */
145 #define ESR0_MASK_CLR_OFFSET 0x914
146 #define ESR1_MASK_CLR_OFFSET 0x92c
147 #define ESR2_MASK_CLR_OFFSET 0x944
148 #define ESR3_MASK_CLR_OFFSET 0x95c
149 #define ESR4_MASK_CLR_OFFSET 0x974
150 /* Error Status Regs --- End */
151 
152 #define R5F_ESR0_SHIFT  0    /* esr0 = fifo underflow */
153 #define R5F_ESR1_SHIFT  1    /* esr1 = ringbuf underflow */
154 #define R5F_ESR2_SHIFT  2    /* esr2 = ringbuf overflow */
155 #define R5F_ESR3_SHIFT  3    /* esr3 = freemark */
156 #define R5F_ESR4_SHIFT  4    /* esr4 = fullmark */
157 
158 
159 /* Mask for R5F register.  Set all relevant interrupt for playback handler */
160 #define ANY_PLAYBACK_IRQ  (BIT(R5F_ESR0_SHIFT) | \
161 			   BIT(R5F_ESR1_SHIFT) | \
162 			   BIT(R5F_ESR3_SHIFT))
163 
164 /* Mask for R5F register.  Set all relevant interrupt for capture handler */
165 #define ANY_CAPTURE_IRQ   (BIT(R5F_ESR2_SHIFT) | BIT(R5F_ESR4_SHIFT))
166 
167 /*
168  * PERIOD_BYTES_MIN is the number of bytes to at which the interrupt will tick.
169  * This number should be a multiple of 256. Minimum value is 256
170  */
171 #define PERIOD_BYTES_MIN 0x100
172 
173 static const struct snd_pcm_hardware cygnus_pcm_hw = {
174 	.info = SNDRV_PCM_INFO_MMAP |
175 			SNDRV_PCM_INFO_MMAP_VALID |
176 			SNDRV_PCM_INFO_INTERLEAVED,
177 	.formats = SNDRV_PCM_FMTBIT_S16_LE |
178 			SNDRV_PCM_FMTBIT_S32_LE,
179 
180 	/* A period is basically an interrupt */
181 	.period_bytes_min = PERIOD_BYTES_MIN,
182 	.period_bytes_max = 0x10000,
183 
184 	/* period_min/max gives range of approx interrupts per buffer */
185 	.periods_min = 2,
186 	.periods_max = 8,
187 
188 	/*
189 	 * maximum buffer size in bytes = period_bytes_max * periods_max
190 	 * We allocate this amount of data for each enabled channel
191 	 */
192 	.buffer_bytes_max = 4 * 0x8000,
193 };
194 
195 static u64 cygnus_dma_dmamask = DMA_BIT_MASK(32);
196 
197 static struct cygnus_aio_port *cygnus_dai_get_dma_data(
198 				struct snd_pcm_substream *substream)
199 {
200 	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
201 
202 	return snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(soc_runtime, 0), substream);
203 }
204 
205 static void ringbuf_set_initial(void __iomem *audio_io,
206 		struct ringbuf_regs *p_rbuf,
207 		bool is_playback,
208 		u32 start,
209 		u32 periodsize,
210 		u32 bufsize)
211 {
212 	u32 initial_rd;
213 	u32 initial_wr;
214 	u32 end;
215 	u32 fmark_val; /* free or full mark */
216 
217 	p_rbuf->period_bytes = periodsize;
218 	p_rbuf->buf_size = bufsize;
219 
220 	if (is_playback) {
221 		/* Set the pointers to indicate full (flip uppermost bit) */
222 		initial_rd = start;
223 		initial_wr = initial_rd ^ BIT(31);
224 	} else {
225 		/* Set the pointers to indicate empty */
226 		initial_wr = start;
227 		initial_rd = initial_wr;
228 	}
229 
230 	end = start + bufsize - 1;
231 
232 	/*
233 	 * The interrupt will fire when free/full mark is *exceeded*
234 	 * The fmark value must be multiple of PERIOD_BYTES_MIN so set fmark
235 	 * to be PERIOD_BYTES_MIN less than the period size.
236 	 */
237 	fmark_val = periodsize - PERIOD_BYTES_MIN;
238 
239 	writel(start, audio_io + p_rbuf->baseaddr);
240 	writel(end, audio_io + p_rbuf->endaddr);
241 	writel(fmark_val, audio_io + p_rbuf->fmark);
242 	writel(initial_rd, audio_io + p_rbuf->rdaddr);
243 	writel(initial_wr, audio_io + p_rbuf->wraddr);
244 }
245 
246 static int configure_ringbuf_regs(struct snd_pcm_substream *substream)
247 {
248 	struct cygnus_aio_port *aio;
249 	struct ringbuf_regs *p_rbuf;
250 	int status = 0;
251 
252 	aio = cygnus_dai_get_dma_data(substream);
253 
254 	/* Map the ssp portnum to a set of ring buffers. */
255 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
256 		p_rbuf = &aio->play_rb_regs;
257 
258 		switch (aio->portnum) {
259 		case 0:
260 			*p_rbuf = RINGBUF_REG_PLAYBACK(0);
261 			break;
262 		case 1:
263 			*p_rbuf = RINGBUF_REG_PLAYBACK(2);
264 			break;
265 		case 2:
266 			*p_rbuf = RINGBUF_REG_PLAYBACK(4);
267 			break;
268 		case 3: /* SPDIF */
269 			*p_rbuf = RINGBUF_REG_PLAYBACK(6);
270 			break;
271 		default:
272 			status = -EINVAL;
273 		}
274 	} else {
275 		p_rbuf = &aio->capture_rb_regs;
276 
277 		switch (aio->portnum) {
278 		case 0:
279 			*p_rbuf = RINGBUF_REG_CAPTURE(0);
280 			break;
281 		case 1:
282 			*p_rbuf = RINGBUF_REG_CAPTURE(2);
283 			break;
284 		case 2:
285 			*p_rbuf = RINGBUF_REG_CAPTURE(4);
286 			break;
287 		default:
288 			status = -EINVAL;
289 		}
290 	}
291 
292 	return status;
293 }
294 
295 static struct ringbuf_regs *get_ringbuf(struct snd_pcm_substream *substream)
296 {
297 	struct cygnus_aio_port *aio;
298 	struct ringbuf_regs *p_rbuf = NULL;
299 
300 	aio = cygnus_dai_get_dma_data(substream);
301 
302 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
303 		p_rbuf = &aio->play_rb_regs;
304 	else
305 		p_rbuf = &aio->capture_rb_regs;
306 
307 	return p_rbuf;
308 }
309 
310 static void enable_intr(struct snd_pcm_substream *substream)
311 {
312 	struct cygnus_aio_port *aio;
313 	u32 clear_mask;
314 
315 	aio = cygnus_dai_get_dma_data(substream);
316 
317 	/* The port number maps to the bit position to be cleared */
318 	clear_mask = BIT(aio->portnum);
319 
320 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
321 		/* Clear interrupt status before enabling them */
322 		writel(clear_mask, aio->cygaud->audio + ESR0_STATUS_CLR_OFFSET);
323 		writel(clear_mask, aio->cygaud->audio + ESR1_STATUS_CLR_OFFSET);
324 		writel(clear_mask, aio->cygaud->audio + ESR3_STATUS_CLR_OFFSET);
325 		/* Unmask the interrupts of the given port*/
326 		writel(clear_mask, aio->cygaud->audio + ESR0_MASK_CLR_OFFSET);
327 		writel(clear_mask, aio->cygaud->audio + ESR1_MASK_CLR_OFFSET);
328 		writel(clear_mask, aio->cygaud->audio + ESR3_MASK_CLR_OFFSET);
329 
330 		writel(ANY_PLAYBACK_IRQ,
331 			aio->cygaud->audio + INTH_R5F_MASK_CLEAR_OFFSET);
332 	} else {
333 		writel(clear_mask, aio->cygaud->audio + ESR2_STATUS_CLR_OFFSET);
334 		writel(clear_mask, aio->cygaud->audio + ESR4_STATUS_CLR_OFFSET);
335 		writel(clear_mask, aio->cygaud->audio + ESR2_MASK_CLR_OFFSET);
336 		writel(clear_mask, aio->cygaud->audio + ESR4_MASK_CLR_OFFSET);
337 
338 		writel(ANY_CAPTURE_IRQ,
339 			aio->cygaud->audio + INTH_R5F_MASK_CLEAR_OFFSET);
340 	}
341 
342 }
343 
344 static void disable_intr(struct snd_pcm_substream *substream)
345 {
346 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
347 	struct cygnus_aio_port *aio;
348 	u32 set_mask;
349 
350 	aio = cygnus_dai_get_dma_data(substream);
351 
352 	dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "%s on port %d\n", __func__, aio->portnum);
353 
354 	/* The port number maps to the bit position to be set */
355 	set_mask = BIT(aio->portnum);
356 
357 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
358 		/* Mask the interrupts of the given port*/
359 		writel(set_mask, aio->cygaud->audio + ESR0_MASK_SET_OFFSET);
360 		writel(set_mask, aio->cygaud->audio + ESR1_MASK_SET_OFFSET);
361 		writel(set_mask, aio->cygaud->audio + ESR3_MASK_SET_OFFSET);
362 	} else {
363 		writel(set_mask, aio->cygaud->audio + ESR2_MASK_SET_OFFSET);
364 		writel(set_mask, aio->cygaud->audio + ESR4_MASK_SET_OFFSET);
365 	}
366 
367 }
368 
369 static int cygnus_pcm_trigger(struct snd_soc_component *component,
370 			      struct snd_pcm_substream *substream, int cmd)
371 {
372 	int ret = 0;
373 
374 	switch (cmd) {
375 	case SNDRV_PCM_TRIGGER_START:
376 	case SNDRV_PCM_TRIGGER_RESUME:
377 		enable_intr(substream);
378 		break;
379 
380 	case SNDRV_PCM_TRIGGER_STOP:
381 	case SNDRV_PCM_TRIGGER_SUSPEND:
382 		disable_intr(substream);
383 		break;
384 	default:
385 		ret = -EINVAL;
386 	}
387 
388 	return ret;
389 }
390 
391 static void cygnus_pcm_period_elapsed(struct snd_pcm_substream *substream)
392 {
393 	struct cygnus_aio_port *aio;
394 	struct ringbuf_regs *p_rbuf = NULL;
395 	u32 regval;
396 
397 	aio = cygnus_dai_get_dma_data(substream);
398 
399 	p_rbuf = get_ringbuf(substream);
400 
401 	/*
402 	 * If free/full mark interrupt occurs, provide timestamp
403 	 * to ALSA and update appropriate idx by period_bytes
404 	 */
405 	snd_pcm_period_elapsed(substream);
406 
407 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
408 		/* Set the ring buffer to full */
409 		regval = readl(aio->cygaud->audio + p_rbuf->rdaddr);
410 		regval = regval ^ BIT(31);
411 		writel(regval, aio->cygaud->audio + p_rbuf->wraddr);
412 	} else {
413 		/* Set the ring buffer to empty */
414 		regval = readl(aio->cygaud->audio + p_rbuf->wraddr);
415 		writel(regval, aio->cygaud->audio + p_rbuf->rdaddr);
416 	}
417 }
418 
419 /*
420  * ESR0/1/3 status  Description
421  *  0x1	I2S0_out port caused interrupt
422  *  0x2	I2S1_out port caused interrupt
423  *  0x4	I2S2_out port caused interrupt
424  *  0x8	SPDIF_out port caused interrupt
425  */
426 static void handle_playback_irq(struct cygnus_audio *cygaud)
427 {
428 	void __iomem *audio_io;
429 	u32 port;
430 	u32 esr_status0, esr_status1, esr_status3;
431 
432 	audio_io = cygaud->audio;
433 
434 	/*
435 	 * ESR status gets updates with/without interrupts enabled.
436 	 * So, check the ESR mask, which provides interrupt enable/
437 	 * disable status and use it to determine which ESR status
438 	 * should be serviced.
439 	 */
440 	esr_status0 = readl(audio_io + ESR0_STATUS_OFFSET);
441 	esr_status0 &= ~readl(audio_io + ESR0_MASK_STATUS_OFFSET);
442 	esr_status1 = readl(audio_io + ESR1_STATUS_OFFSET);
443 	esr_status1 &= ~readl(audio_io + ESR1_MASK_STATUS_OFFSET);
444 	esr_status3 = readl(audio_io + ESR3_STATUS_OFFSET);
445 	esr_status3 &= ~readl(audio_io + ESR3_MASK_STATUS_OFFSET);
446 
447 	for (port = 0; port < CYGNUS_MAX_PLAYBACK_PORTS; port++) {
448 		u32 esrmask = BIT(port);
449 
450 		/*
451 		 * Ringbuffer or FIFO underflow
452 		 * If we get this interrupt then, it is also true that we have
453 		 * not yet responded to the freemark interrupt.
454 		 * Log a debug message.  The freemark handler below will
455 		 * handle getting everything going again.
456 		 */
457 		if ((esrmask & esr_status1) || (esrmask & esr_status0)) {
458 			dev_dbg(cygaud->dev,
459 				"Underrun: esr0=0x%x, esr1=0x%x esr3=0x%x\n",
460 				esr_status0, esr_status1, esr_status3);
461 		}
462 
463 		/*
464 		 * Freemark is hit. This is the normal interrupt.
465 		 * In typical operation the read and write regs will be equal
466 		 */
467 		if (esrmask & esr_status3) {
468 			struct snd_pcm_substream *playstr;
469 
470 			playstr = cygaud->portinfo[port].play_stream;
471 			cygnus_pcm_period_elapsed(playstr);
472 		}
473 	}
474 
475 	/* Clear ESR interrupt */
476 	writel(esr_status0, audio_io + ESR0_STATUS_CLR_OFFSET);
477 	writel(esr_status1, audio_io + ESR1_STATUS_CLR_OFFSET);
478 	writel(esr_status3, audio_io + ESR3_STATUS_CLR_OFFSET);
479 	/* Rearm freemark logic by writing 1 to the correct bit */
480 	writel(esr_status3, audio_io + BF_REARM_FREE_MARK_OFFSET);
481 }
482 
483 /*
484  * ESR2/4 status  Description
485  *  0x1	I2S0_in port caused interrupt
486  *  0x2	I2S1_in port caused interrupt
487  *  0x4	I2S2_in port caused interrupt
488  */
489 static void handle_capture_irq(struct cygnus_audio *cygaud)
490 {
491 	void __iomem *audio_io;
492 	u32 port;
493 	u32 esr_status2, esr_status4;
494 
495 	audio_io = cygaud->audio;
496 
497 	/*
498 	 * ESR status gets updates with/without interrupts enabled.
499 	 * So, check the ESR mask, which provides interrupt enable/
500 	 * disable status and use it to determine which ESR status
501 	 * should be serviced.
502 	 */
503 	esr_status2 = readl(audio_io + ESR2_STATUS_OFFSET);
504 	esr_status2 &= ~readl(audio_io + ESR2_MASK_STATUS_OFFSET);
505 	esr_status4 = readl(audio_io + ESR4_STATUS_OFFSET);
506 	esr_status4 &= ~readl(audio_io + ESR4_MASK_STATUS_OFFSET);
507 
508 	for (port = 0; port < CYGNUS_MAX_CAPTURE_PORTS; port++) {
509 		u32 esrmask = BIT(port);
510 
511 		/*
512 		 * Ringbuffer or FIFO overflow
513 		 * If we get this interrupt then, it is also true that we have
514 		 * not yet responded to the fullmark interrupt.
515 		 * Log a debug message.  The fullmark handler below will
516 		 * handle getting everything going again.
517 		 */
518 		if (esrmask & esr_status2)
519 			dev_dbg(cygaud->dev,
520 				"Overflow: esr2=0x%x\n", esr_status2);
521 
522 		if (esrmask & esr_status4) {
523 			struct snd_pcm_substream *capstr;
524 
525 			capstr = cygaud->portinfo[port].capture_stream;
526 			cygnus_pcm_period_elapsed(capstr);
527 		}
528 	}
529 
530 	writel(esr_status2, audio_io + ESR2_STATUS_CLR_OFFSET);
531 	writel(esr_status4, audio_io + ESR4_STATUS_CLR_OFFSET);
532 	/* Rearm fullmark logic by writing 1 to the correct bit */
533 	writel(esr_status4, audio_io + BF_REARM_FULL_MARK_OFFSET);
534 }
535 
536 static irqreturn_t cygnus_dma_irq(int irq, void *data)
537 {
538 	u32 r5_status;
539 	struct cygnus_audio *cygaud = data;
540 
541 	/*
542 	 * R5 status bits	Description
543 	 *  0		ESR0 (playback FIFO interrupt)
544 	 *  1		ESR1 (playback rbuf interrupt)
545 	 *  2		ESR2 (capture rbuf interrupt)
546 	 *  3		ESR3 (Freemark play. interrupt)
547 	 *  4		ESR4 (Fullmark capt. interrupt)
548 	 */
549 	r5_status = readl(cygaud->audio + INTH_R5F_STATUS_OFFSET);
550 
551 	if (!(r5_status & (ANY_PLAYBACK_IRQ | ANY_CAPTURE_IRQ)))
552 		return IRQ_NONE;
553 
554 	/* If playback interrupt happened */
555 	if (ANY_PLAYBACK_IRQ & r5_status) {
556 		handle_playback_irq(cygaud);
557 		writel(ANY_PLAYBACK_IRQ & r5_status,
558 			cygaud->audio + INTH_R5F_CLEAR_OFFSET);
559 	}
560 
561 	/* If  capture interrupt happened */
562 	if (ANY_CAPTURE_IRQ & r5_status) {
563 		handle_capture_irq(cygaud);
564 		writel(ANY_CAPTURE_IRQ & r5_status,
565 			cygaud->audio + INTH_R5F_CLEAR_OFFSET);
566 	}
567 
568 	return IRQ_HANDLED;
569 }
570 
571 static int cygnus_pcm_open(struct snd_soc_component *component,
572 			   struct snd_pcm_substream *substream)
573 {
574 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
575 	struct snd_pcm_runtime *runtime = substream->runtime;
576 	struct cygnus_aio_port *aio;
577 	int ret;
578 
579 	aio = cygnus_dai_get_dma_data(substream);
580 	if (!aio)
581 		return -ENODEV;
582 
583 	dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "%s port %d\n", __func__, aio->portnum);
584 
585 	snd_soc_set_runtime_hwparams(substream, &cygnus_pcm_hw);
586 
587 	ret = snd_pcm_hw_constraint_step(runtime, 0,
588 		SNDRV_PCM_HW_PARAM_PERIOD_BYTES, PERIOD_BYTES_MIN);
589 	if (ret < 0)
590 		return ret;
591 
592 	ret = snd_pcm_hw_constraint_step(runtime, 0,
593 		SNDRV_PCM_HW_PARAM_BUFFER_BYTES, PERIOD_BYTES_MIN);
594 	if (ret < 0)
595 		return ret;
596 	/*
597 	 * Keep track of which substream belongs to which port.
598 	 * This info is needed by snd_pcm_period_elapsed() in irq_handler
599 	 */
600 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
601 		aio->play_stream = substream;
602 	else
603 		aio->capture_stream = substream;
604 
605 	return 0;
606 }
607 
608 static int cygnus_pcm_close(struct snd_soc_component *component,
609 			    struct snd_pcm_substream *substream)
610 {
611 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
612 	struct cygnus_aio_port *aio;
613 
614 	aio = cygnus_dai_get_dma_data(substream);
615 
616 	dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "%s  port %d\n", __func__, aio->portnum);
617 
618 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
619 		aio->play_stream = NULL;
620 	else
621 		aio->capture_stream = NULL;
622 
623 	if (!aio->play_stream && !aio->capture_stream)
624 		dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "freed  port %d\n", aio->portnum);
625 
626 	return 0;
627 }
628 
629 static int cygnus_pcm_prepare(struct snd_soc_component *component,
630 			      struct snd_pcm_substream *substream)
631 {
632 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
633 	struct snd_pcm_runtime *runtime = substream->runtime;
634 	struct cygnus_aio_port *aio;
635 	unsigned long bufsize, periodsize;
636 	bool is_play;
637 	u32 start;
638 	struct ringbuf_regs *p_rbuf = NULL;
639 
640 	aio = cygnus_dai_get_dma_data(substream);
641 	dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "%s port %d\n", __func__, aio->portnum);
642 
643 	bufsize = snd_pcm_lib_buffer_bytes(substream);
644 	periodsize = snd_pcm_lib_period_bytes(substream);
645 
646 	dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "%s (buf_size %lu) (period_size %lu)\n",
647 			__func__, bufsize, periodsize);
648 
649 	configure_ringbuf_regs(substream);
650 
651 	p_rbuf = get_ringbuf(substream);
652 
653 	start = runtime->dma_addr;
654 
655 	is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 1 : 0;
656 
657 	ringbuf_set_initial(aio->cygaud->audio, p_rbuf, is_play, start,
658 				periodsize, bufsize);
659 
660 	return 0;
661 }
662 
663 static snd_pcm_uframes_t cygnus_pcm_pointer(struct snd_soc_component *component,
664 					    struct snd_pcm_substream *substream)
665 {
666 	struct cygnus_aio_port *aio;
667 	unsigned int res = 0, cur = 0, base = 0;
668 	struct ringbuf_regs *p_rbuf = NULL;
669 
670 	aio = cygnus_dai_get_dma_data(substream);
671 
672 	/*
673 	 * Get the offset of the current read (for playack) or write
674 	 * index (for capture).  Report this value back to the asoc framework.
675 	 */
676 	p_rbuf = get_ringbuf(substream);
677 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
678 		cur = readl(aio->cygaud->audio + p_rbuf->rdaddr);
679 	else
680 		cur = readl(aio->cygaud->audio + p_rbuf->wraddr);
681 
682 	base = readl(aio->cygaud->audio + p_rbuf->baseaddr);
683 
684 	/*
685 	 * Mask off the MSB of the rdaddr,wraddr and baseaddr
686 	 * since MSB is not part of the address
687 	 */
688 	res = (cur & 0x7fffffff) - (base & 0x7fffffff);
689 
690 	return bytes_to_frames(substream->runtime, res);
691 }
692 
693 static int cygnus_dma_new(struct snd_soc_component *component,
694 			  struct snd_soc_pcm_runtime *rtd)
695 {
696 	size_t size = cygnus_pcm_hw.buffer_bytes_max;
697 	struct snd_card *card = rtd->card->snd_card;
698 
699 	if (!card->dev->dma_mask)
700 		card->dev->dma_mask = &cygnus_dma_dmamask;
701 	if (!card->dev->coherent_dma_mask)
702 		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
703 
704 	snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
705 				       card->dev, size, size);
706 
707 	return 0;
708 }
709 
710 static struct snd_soc_component_driver cygnus_soc_platform = {
711 	.open		= cygnus_pcm_open,
712 	.close		= cygnus_pcm_close,
713 	.prepare	= cygnus_pcm_prepare,
714 	.trigger	= cygnus_pcm_trigger,
715 	.pointer	= cygnus_pcm_pointer,
716 	.pcm_construct	= cygnus_dma_new,
717 };
718 
719 int cygnus_soc_platform_register(struct device *dev,
720 				 struct cygnus_audio *cygaud)
721 {
722 	int rc;
723 
724 	dev_dbg(dev, "%s Enter\n", __func__);
725 
726 	rc = devm_request_irq(dev, cygaud->irq_num, cygnus_dma_irq,
727 				IRQF_SHARED, "cygnus-audio", cygaud);
728 	if (rc) {
729 		dev_err(dev, "%s request_irq error %d\n", __func__, rc);
730 		return rc;
731 	}
732 
733 	rc = devm_snd_soc_register_component(dev, &cygnus_soc_platform,
734 					     NULL, 0);
735 	if (rc) {
736 		dev_err(dev, "%s failed\n", __func__);
737 		return rc;
738 	}
739 
740 	return 0;
741 }
742 
743 int cygnus_soc_platform_unregister(struct device *dev)
744 {
745 	return 0;
746 }
747 
748 MODULE_LICENSE("GPL v2");
749 MODULE_AUTHOR("Broadcom");
750 MODULE_DESCRIPTION("Cygnus ASoC PCM module");
751