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
36static 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
60static 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
83static 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
169static 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
185static 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
232static 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
301static 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
329static 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
339static 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
350static 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
413static 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
434static 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
446static 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
489err_buf:
490	lpass_platform_free_buffer(substream, soc_runtime);
491	return ret;
492}
493
494static 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
503static 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
509int 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}
523EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register);
524
525MODULE_DESCRIPTION("QTi LPASS Platform Driver");
526MODULE_LICENSE("GPL v2");
527