xref: /openbmc/linux/sound/soc/qcom/lpass-platform.c (revision 94cdda6b)
1 /*
2  * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 and
6  * only version 2 as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * lpass-platform.c -- ALSA SoC platform driver for QTi LPASS
14  */
15 
16 #include <linux/compiler.h>
17 #include <linux/device.h>
18 #include <linux/dma-mapping.h>
19 #include <linux/err.h>
20 #include <linux/export.h>
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/io.h>
24 #include <linux/platform_device.h>
25 #include <sound/memalloc.h>
26 #include <sound/pcm.h>
27 #include <sound/pcm_params.h>
28 #include <linux/regmap.h>
29 #include <sound/soc.h>
30 #include "lpass-lpaif-ipq806x.h"
31 #include "lpass.h"
32 
33 #define LPASS_PLATFORM_BUFFER_SIZE	(16 * 1024)
34 #define LPASS_PLATFORM_PERIODS		2
35 
36 static struct snd_pcm_hardware lpass_platform_pcm_hardware = {
37 	.info			=	SNDRV_PCM_INFO_MMAP |
38 					SNDRV_PCM_INFO_MMAP_VALID |
39 					SNDRV_PCM_INFO_INTERLEAVED |
40 					SNDRV_PCM_INFO_PAUSE |
41 					SNDRV_PCM_INFO_RESUME,
42 	.formats		=	SNDRV_PCM_FMTBIT_S16 |
43 					SNDRV_PCM_FMTBIT_S24 |
44 					SNDRV_PCM_FMTBIT_S32,
45 	.rates			=	SNDRV_PCM_RATE_8000_192000,
46 	.rate_min		=	8000,
47 	.rate_max		=	192000,
48 	.channels_min		=	1,
49 	.channels_max		=	8,
50 	.buffer_bytes_max	=	LPASS_PLATFORM_BUFFER_SIZE,
51 	.period_bytes_max	=	LPASS_PLATFORM_BUFFER_SIZE /
52 						LPASS_PLATFORM_PERIODS,
53 	.period_bytes_min	=	LPASS_PLATFORM_BUFFER_SIZE /
54 						LPASS_PLATFORM_PERIODS,
55 	.periods_min		=	LPASS_PLATFORM_PERIODS,
56 	.periods_max		=	LPASS_PLATFORM_PERIODS,
57 	.fifo_size		=	0,
58 };
59 
60 static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)
61 {
62 	struct snd_pcm_runtime *runtime = substream->runtime;
63 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
64 	int ret;
65 
66 	snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
67 
68 	runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
69 
70 	ret = snd_pcm_hw_constraint_integer(runtime,
71 			SNDRV_PCM_HW_PARAM_PERIODS);
72 	if (ret < 0) {
73 		dev_err(soc_runtime->dev, "%s() setting constraints failed: %d\n",
74 				__func__, ret);
75 		return -EINVAL;
76 	}
77 
78 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
79 
80 	return 0;
81 }
82 
83 static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
84 		struct snd_pcm_hw_params *params)
85 {
86 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
87 	struct lpass_data *drvdata =
88 		snd_soc_platform_get_drvdata(soc_runtime->platform);
89 	snd_pcm_format_t format = params_format(params);
90 	unsigned int channels = params_channels(params);
91 	unsigned int regval;
92 	int bitwidth;
93 	int ret;
94 
95 	bitwidth = snd_pcm_format_width(format);
96 	if (bitwidth < 0) {
97 		dev_err(soc_runtime->dev, "%s() invalid bit width given: %d\n",
98 				__func__, bitwidth);
99 		return bitwidth;
100 	}
101 
102 	regval = LPAIF_RDMACTL_BURSTEN_INCR4 |
103 			LPAIF_RDMACTL_AUDINTF_MI2S |
104 			LPAIF_RDMACTL_FIFOWM_8;
105 
106 	switch (bitwidth) {
107 	case 16:
108 		switch (channels) {
109 		case 1:
110 		case 2:
111 			regval |= LPAIF_RDMACTL_WPSCNT_ONE;
112 			break;
113 		case 4:
114 			regval |= LPAIF_RDMACTL_WPSCNT_TWO;
115 			break;
116 		case 6:
117 			regval |= LPAIF_RDMACTL_WPSCNT_THREE;
118 			break;
119 		case 8:
120 			regval |= LPAIF_RDMACTL_WPSCNT_FOUR;
121 			break;
122 		default:
123 			dev_err(soc_runtime->dev, "%s() invalid PCM config given: bw=%d, ch=%u\n",
124 					__func__, bitwidth, channels);
125 			return -EINVAL;
126 		}
127 		break;
128 	case 24:
129 	case 32:
130 		switch (channels) {
131 		case 1:
132 			regval |= LPAIF_RDMACTL_WPSCNT_ONE;
133 			break;
134 		case 2:
135 			regval |= LPAIF_RDMACTL_WPSCNT_TWO;
136 			break;
137 		case 4:
138 			regval |= LPAIF_RDMACTL_WPSCNT_FOUR;
139 			break;
140 		case 6:
141 			regval |= LPAIF_RDMACTL_WPSCNT_SIX;
142 			break;
143 		case 8:
144 			regval |= LPAIF_RDMACTL_WPSCNT_EIGHT;
145 			break;
146 		default:
147 			dev_err(soc_runtime->dev, "%s() invalid PCM config given: bw=%d, ch=%u\n",
148 					__func__, bitwidth, channels);
149 			return -EINVAL;
150 		}
151 		break;
152 	default:
153 		dev_err(soc_runtime->dev, "%s() invalid PCM config given: bw=%d, ch=%u\n",
154 				__func__, bitwidth, channels);
155 		return -EINVAL;
156 	}
157 
158 	ret = regmap_write(drvdata->lpaif_map,
159 			LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), regval);
160 	if (ret) {
161 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
162 				__func__, ret);
163 		return ret;
164 	}
165 
166 	return 0;
167 }
168 
169 static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
170 {
171 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
172 	struct lpass_data *drvdata =
173 		snd_soc_platform_get_drvdata(soc_runtime->platform);
174 	int ret;
175 
176 	ret = regmap_write(drvdata->lpaif_map,
177 			LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 0);
178 	if (ret)
179 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
180 				__func__, ret);
181 
182 	return ret;
183 }
184 
185 static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
186 {
187 	struct snd_pcm_runtime *runtime = substream->runtime;
188 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
189 	struct lpass_data *drvdata =
190 		snd_soc_platform_get_drvdata(soc_runtime->platform);
191 	int ret;
192 
193 	ret = regmap_write(drvdata->lpaif_map,
194 			LPAIF_RDMABASE_REG(LPAIF_RDMA_CHAN_MI2S),
195 			runtime->dma_addr);
196 	if (ret) {
197 		dev_err(soc_runtime->dev, "%s() error writing to rdmabase reg: %d\n",
198 				__func__, ret);
199 		return ret;
200 	}
201 
202 	ret = regmap_write(drvdata->lpaif_map,
203 			LPAIF_RDMABUFF_REG(LPAIF_RDMA_CHAN_MI2S),
204 			(snd_pcm_lib_buffer_bytes(substream) >> 2) - 1);
205 	if (ret) {
206 		dev_err(soc_runtime->dev, "%s() error writing to rdmabuff reg: %d\n",
207 				__func__, ret);
208 		return ret;
209 	}
210 
211 	ret = regmap_write(drvdata->lpaif_map,
212 			LPAIF_RDMAPER_REG(LPAIF_RDMA_CHAN_MI2S),
213 			(snd_pcm_lib_period_bytes(substream) >> 2) - 1);
214 	if (ret) {
215 		dev_err(soc_runtime->dev, "%s() error writing to rdmaper reg: %d\n",
216 				__func__, ret);
217 		return ret;
218 	}
219 
220 	ret = regmap_update_bits(drvdata->lpaif_map,
221 			LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S),
222 			LPAIF_RDMACTL_ENABLE_MASK, LPAIF_RDMACTL_ENABLE_ON);
223 	if (ret) {
224 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
225 				__func__, ret);
226 		return ret;
227 	}
228 
229 	return 0;
230 }
231 
232 static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
233 		int cmd)
234 {
235 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
236 	struct lpass_data *drvdata =
237 		snd_soc_platform_get_drvdata(soc_runtime->platform);
238 	int ret;
239 
240 	switch (cmd) {
241 	case SNDRV_PCM_TRIGGER_START:
242 	case SNDRV_PCM_TRIGGER_RESUME:
243 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
244 		/* clear status before enabling interrupts */
245 		ret = regmap_write(drvdata->lpaif_map,
246 				LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
247 				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S));
248 		if (ret) {
249 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
250 					__func__, ret);
251 			return ret;
252 		}
253 
254 		ret = regmap_update_bits(drvdata->lpaif_map,
255 				LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST),
256 				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S),
257 				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S));
258 		if (ret) {
259 			dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
260 					__func__, ret);
261 			return ret;
262 		}
263 
264 		ret = regmap_update_bits(drvdata->lpaif_map,
265 				LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S),
266 				LPAIF_RDMACTL_ENABLE_MASK,
267 				LPAIF_RDMACTL_ENABLE_ON);
268 		if (ret) {
269 			dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
270 					__func__, ret);
271 			return ret;
272 		}
273 		break;
274 	case SNDRV_PCM_TRIGGER_STOP:
275 	case SNDRV_PCM_TRIGGER_SUSPEND:
276 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
277 		ret = regmap_update_bits(drvdata->lpaif_map,
278 				LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S),
279 				LPAIF_RDMACTL_ENABLE_MASK,
280 				LPAIF_RDMACTL_ENABLE_OFF);
281 		if (ret) {
282 			dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
283 					__func__, ret);
284 			return ret;
285 		}
286 
287 		ret = regmap_update_bits(drvdata->lpaif_map,
288 				LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST),
289 				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S), 0);
290 		if (ret) {
291 			dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
292 					__func__, ret);
293 			return ret;
294 		}
295 		break;
296 	}
297 
298 	return 0;
299 }
300 
301 static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
302 		struct snd_pcm_substream *substream)
303 {
304 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
305 	struct lpass_data *drvdata =
306 			snd_soc_platform_get_drvdata(soc_runtime->platform);
307 	unsigned int base_addr, curr_addr;
308 	int ret;
309 
310 	ret = regmap_read(drvdata->lpaif_map,
311 			LPAIF_RDMABASE_REG(LPAIF_RDMA_CHAN_MI2S), &base_addr);
312 	if (ret) {
313 		dev_err(soc_runtime->dev, "%s() error reading from rdmabase reg: %d\n",
314 				__func__, ret);
315 		return ret;
316 	}
317 
318 	ret = regmap_read(drvdata->lpaif_map,
319 			LPAIF_RDMACURR_REG(LPAIF_RDMA_CHAN_MI2S), &curr_addr);
320 	if (ret) {
321 		dev_err(soc_runtime->dev, "%s() error reading from rdmacurr reg: %d\n",
322 				__func__, ret);
323 		return ret;
324 	}
325 
326 	return bytes_to_frames(substream->runtime, curr_addr - base_addr);
327 }
328 
329 static int lpass_platform_pcmops_mmap(struct snd_pcm_substream *substream,
330 		struct vm_area_struct *vma)
331 {
332 	struct snd_pcm_runtime *runtime = substream->runtime;
333 
334 	return dma_mmap_coherent(substream->pcm->card->dev, vma,
335 			runtime->dma_area, runtime->dma_addr,
336 			runtime->dma_bytes);
337 }
338 
339 static struct snd_pcm_ops lpass_platform_pcm_ops = {
340 	.open		= lpass_platform_pcmops_open,
341 	.ioctl		= snd_pcm_lib_ioctl,
342 	.hw_params	= lpass_platform_pcmops_hw_params,
343 	.hw_free	= lpass_platform_pcmops_hw_free,
344 	.prepare	= lpass_platform_pcmops_prepare,
345 	.trigger	= lpass_platform_pcmops_trigger,
346 	.pointer	= lpass_platform_pcmops_pointer,
347 	.mmap		= lpass_platform_pcmops_mmap,
348 };
349 
350 static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
351 {
352 	struct snd_pcm_substream *substream = data;
353 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
354 	struct lpass_data *drvdata =
355 		snd_soc_platform_get_drvdata(soc_runtime->platform);
356 	unsigned int interrupts;
357 	irqreturn_t ret = IRQ_NONE;
358 	int rv;
359 
360 	rv = regmap_read(drvdata->lpaif_map,
361 			LPAIF_IRQSTAT_REG(LPAIF_IRQ_PORT_HOST), &interrupts);
362 	if (rv) {
363 		dev_err(soc_runtime->dev, "%s() error reading from irqstat reg: %d\n",
364 				__func__, rv);
365 		return IRQ_NONE;
366 	}
367 	interrupts &= LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S);
368 
369 	if (interrupts & LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S)) {
370 		rv = regmap_write(drvdata->lpaif_map,
371 				LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
372 				LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S));
373 		if (rv) {
374 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
375 					__func__, rv);
376 			return IRQ_NONE;
377 		}
378 		snd_pcm_period_elapsed(substream);
379 		ret = IRQ_HANDLED;
380 	}
381 
382 	if (interrupts & LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S)) {
383 		rv = regmap_write(drvdata->lpaif_map,
384 				LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
385 				LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S));
386 		if (rv) {
387 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
388 					__func__, rv);
389 			return IRQ_NONE;
390 		}
391 		dev_warn(soc_runtime->dev, "%s() xrun warning\n", __func__);
392 		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
393 		ret = IRQ_HANDLED;
394 	}
395 
396 	if (interrupts & LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S)) {
397 		rv = regmap_write(drvdata->lpaif_map,
398 				LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
399 				LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S));
400 		if (rv) {
401 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
402 					__func__, rv);
403 			return IRQ_NONE;
404 		}
405 		dev_err(soc_runtime->dev, "%s() bus access error\n", __func__);
406 		snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
407 		ret = IRQ_HANDLED;
408 	}
409 
410 	return ret;
411 }
412 
413 static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream,
414 		struct snd_soc_pcm_runtime *soc_runtime)
415 {
416 	struct snd_dma_buffer *buf = &substream->dma_buffer;
417 	size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
418 
419 	buf->dev.type = SNDRV_DMA_TYPE_DEV;
420 	buf->dev.dev = soc_runtime->dev;
421 	buf->private_data = NULL;
422 	buf->area = dma_alloc_coherent(soc_runtime->dev, size, &buf->addr,
423 			GFP_KERNEL);
424 	if (!buf->area) {
425 		dev_err(soc_runtime->dev, "%s: Could not allocate DMA buffer\n",
426 				__func__);
427 		return -ENOMEM;
428 	}
429 	buf->bytes = size;
430 
431 	return 0;
432 }
433 
434 static void lpass_platform_free_buffer(struct snd_pcm_substream *substream,
435 		struct snd_soc_pcm_runtime *soc_runtime)
436 {
437 	struct snd_dma_buffer *buf = &substream->dma_buffer;
438 
439 	if (buf->area) {
440 		dma_free_coherent(soc_runtime->dev, buf->bytes, buf->area,
441 				buf->addr);
442 	}
443 	buf->area = NULL;
444 }
445 
446 static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
447 {
448 	struct snd_pcm *pcm = soc_runtime->pcm;
449 	struct snd_pcm_substream *substream =
450 		pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
451 	struct lpass_data *drvdata =
452 		snd_soc_platform_get_drvdata(soc_runtime->platform);
453 	int ret;
454 
455 	soc_runtime->dev->coherent_dma_mask = DMA_BIT_MASK(32);
456 	soc_runtime->dev->dma_mask = &soc_runtime->dev->coherent_dma_mask;
457 
458 	ret = lpass_platform_alloc_buffer(substream, soc_runtime);
459 	if (ret)
460 		return ret;
461 
462 	ret = devm_request_irq(soc_runtime->dev, drvdata->lpaif_irq,
463 			lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
464 			"lpass-irq-lpaif", substream);
465 	if (ret) {
466 		dev_err(soc_runtime->dev, "%s() irq request failed: %d\n",
467 				__func__, ret);
468 		goto err_buf;
469 	}
470 
471 	/* ensure audio hardware is disabled */
472 	ret = regmap_write(drvdata->lpaif_map,
473 			LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST), 0);
474 	if (ret) {
475 		dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
476 				__func__, ret);
477 		return ret;
478 	}
479 	ret = regmap_write(drvdata->lpaif_map,
480 			LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 0);
481 	if (ret) {
482 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
483 				__func__, ret);
484 		return ret;
485 	}
486 
487 	return 0;
488 
489 err_buf:
490 	lpass_platform_free_buffer(substream, soc_runtime);
491 	return ret;
492 }
493 
494 static void lpass_platform_pcm_free(struct snd_pcm *pcm)
495 {
496 	struct snd_pcm_substream *substream =
497 		pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
498 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
499 
500 	lpass_platform_free_buffer(substream, soc_runtime);
501 }
502 
503 static struct snd_soc_platform_driver lpass_platform_driver = {
504 	.pcm_new	= lpass_platform_pcm_new,
505 	.pcm_free	= lpass_platform_pcm_free,
506 	.ops		= &lpass_platform_pcm_ops,
507 };
508 
509 int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
510 {
511 	struct lpass_data *drvdata = platform_get_drvdata(pdev);
512 
513 	drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
514 	if (drvdata->lpaif_irq < 0) {
515 		dev_err(&pdev->dev, "%s() error getting irq handle: %d\n",
516 				__func__, drvdata->lpaif_irq);
517 		return -ENODEV;
518 	}
519 
520 	return devm_snd_soc_register_platform(&pdev->dev,
521 			&lpass_platform_driver);
522 }
523 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register);
524 
525 MODULE_DESCRIPTION("QTi LPASS Platform Driver");
526 MODULE_LICENSE("GPL v2");
527