blob: 2fa6280dfb234b213904ad73dfad91c7f575538c [file] [log] [blame]
Kenneth Westfieldc5c86352015-03-03 16:21:55 -08001/*
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");