2 * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
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.
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.
13 * lpass-platform.c -- ALSA SoC platform driver for QTi LPASS
16 #include <linux/dma-mapping.h>
17 #include <linux/export.h>
18 #include <linux/kernel.h>
19 #include <linux/module.h>
20 #include <linux/platform_device.h>
21 #include <sound/pcm_params.h>
22 #include <linux/regmap.h>
23 #include <sound/soc.h>
24 #include "lpass-lpaif-reg.h"
27 struct lpass_pcm_data
{
33 #define LPASS_PLATFORM_BUFFER_SIZE (16 * 1024)
34 #define LPASS_PLATFORM_PERIODS 2
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
|
45 .rates
= SNDRV_PCM_RATE_8000_192000
,
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
,
60 static int lpass_platform_pcmops_open(struct snd_pcm_substream
*substream
)
62 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
63 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
64 struct snd_soc_dai
*cpu_dai
= soc_runtime
->cpu_dai
;
65 struct lpass_data
*drvdata
=
66 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
67 struct lpass_variant
*v
= drvdata
->variant
;
68 int ret
, dma_ch
, dir
= substream
->stream
;
69 struct lpass_pcm_data
*data
;
71 data
= devm_kzalloc(soc_runtime
->dev
, sizeof(*data
), GFP_KERNEL
);
75 data
->i2s_port
= cpu_dai
->driver
->id
;
76 runtime
->private_data
= data
;
78 if (v
->alloc_dma_channel
)
79 dma_ch
= v
->alloc_dma_channel(drvdata
, dir
);
86 drvdata
->substream
[dma_ch
] = substream
;
88 ret
= regmap_write(drvdata
->lpaif_map
,
89 LPAIF_DMACTL_REG(v
, dma_ch
, dir
), 0);
91 dev_err(soc_runtime
->dev
,
92 "%s() error writing to rdmactl reg: %d\n",
97 if (dir
== SNDRV_PCM_STREAM_PLAYBACK
)
98 data
->rdma_ch
= dma_ch
;
100 data
->wrdma_ch
= dma_ch
;
102 snd_soc_set_runtime_hwparams(substream
, &lpass_platform_pcm_hardware
);
104 runtime
->dma_bytes
= lpass_platform_pcm_hardware
.buffer_bytes_max
;
106 ret
= snd_pcm_hw_constraint_integer(runtime
,
107 SNDRV_PCM_HW_PARAM_PERIODS
);
109 dev_err(soc_runtime
->dev
, "%s() setting constraints failed: %d\n",
114 snd_pcm_set_runtime_buffer(substream
, &substream
->dma_buffer
);
119 static int lpass_platform_pcmops_close(struct snd_pcm_substream
*substream
)
121 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
122 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
123 struct lpass_data
*drvdata
=
124 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
125 struct lpass_variant
*v
= drvdata
->variant
;
126 struct lpass_pcm_data
*data
;
127 int dma_ch
, dir
= substream
->stream
;
129 data
= runtime
->private_data
;
130 v
= drvdata
->variant
;
132 if (dir
== SNDRV_PCM_STREAM_PLAYBACK
)
133 dma_ch
= data
->rdma_ch
;
135 dma_ch
= data
->wrdma_ch
;
137 drvdata
->substream
[dma_ch
] = NULL
;
139 if (v
->free_dma_channel
)
140 v
->free_dma_channel(drvdata
, dma_ch
);
145 static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream
*substream
,
146 struct snd_pcm_hw_params
*params
)
148 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
149 struct lpass_data
*drvdata
=
150 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
151 struct snd_pcm_runtime
*rt
= substream
->runtime
;
152 struct lpass_pcm_data
*pcm_data
= rt
->private_data
;
153 struct lpass_variant
*v
= drvdata
->variant
;
154 snd_pcm_format_t format
= params_format(params
);
155 unsigned int channels
= params_channels(params
);
157 int ch
, dir
= substream
->stream
;
159 int ret
, dma_port
= pcm_data
->i2s_port
+ v
->dmactl_audif_start
;
161 if (dir
== SNDRV_PCM_STREAM_PLAYBACK
)
162 ch
= pcm_data
->rdma_ch
;
164 ch
= pcm_data
->wrdma_ch
;
166 bitwidth
= snd_pcm_format_width(format
);
168 dev_err(soc_runtime
->dev
, "%s() invalid bit width given: %d\n",
173 regval
= LPAIF_DMACTL_BURSTEN_INCR4
|
174 LPAIF_DMACTL_AUDINTF(dma_port
) |
175 LPAIF_DMACTL_FIFOWM_8
;
182 regval
|= LPAIF_DMACTL_WPSCNT_ONE
;
185 regval
|= LPAIF_DMACTL_WPSCNT_TWO
;
188 regval
|= LPAIF_DMACTL_WPSCNT_THREE
;
191 regval
|= LPAIF_DMACTL_WPSCNT_FOUR
;
194 dev_err(soc_runtime
->dev
, "%s() invalid PCM config given: bw=%d, ch=%u\n",
195 __func__
, bitwidth
, channels
);
203 regval
|= LPAIF_DMACTL_WPSCNT_ONE
;
206 regval
|= LPAIF_DMACTL_WPSCNT_TWO
;
209 regval
|= LPAIF_DMACTL_WPSCNT_FOUR
;
212 regval
|= LPAIF_DMACTL_WPSCNT_SIX
;
215 regval
|= LPAIF_DMACTL_WPSCNT_EIGHT
;
218 dev_err(soc_runtime
->dev
, "%s() invalid PCM config given: bw=%d, ch=%u\n",
219 __func__
, bitwidth
, channels
);
224 dev_err(soc_runtime
->dev
, "%s() invalid PCM config given: bw=%d, ch=%u\n",
225 __func__
, bitwidth
, channels
);
229 ret
= regmap_write(drvdata
->lpaif_map
,
230 LPAIF_DMACTL_REG(v
, ch
, dir
), regval
);
232 dev_err(soc_runtime
->dev
, "%s() error writing to rdmactl reg: %d\n",
240 static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream
*substream
)
242 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
243 struct lpass_data
*drvdata
=
244 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
245 struct snd_pcm_runtime
*rt
= substream
->runtime
;
246 struct lpass_pcm_data
*pcm_data
= rt
->private_data
;
247 struct lpass_variant
*v
= drvdata
->variant
;
251 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
252 reg
= LPAIF_RDMACTL_REG(v
, pcm_data
->rdma_ch
);
254 reg
= LPAIF_WRDMACTL_REG(v
, pcm_data
->wrdma_ch
);
256 ret
= regmap_write(drvdata
->lpaif_map
, reg
, 0);
258 dev_err(soc_runtime
->dev
, "%s() error writing to rdmactl reg: %d\n",
264 static int lpass_platform_pcmops_prepare(struct snd_pcm_substream
*substream
)
266 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
267 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
268 struct lpass_data
*drvdata
=
269 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
270 struct snd_pcm_runtime
*rt
= substream
->runtime
;
271 struct lpass_pcm_data
*pcm_data
= rt
->private_data
;
272 struct lpass_variant
*v
= drvdata
->variant
;
273 int ret
, ch
, dir
= substream
->stream
;
275 if (dir
== SNDRV_PCM_STREAM_PLAYBACK
)
276 ch
= pcm_data
->rdma_ch
;
278 ch
= pcm_data
->wrdma_ch
;
280 ret
= regmap_write(drvdata
->lpaif_map
,
281 LPAIF_DMABASE_REG(v
, ch
, dir
),
284 dev_err(soc_runtime
->dev
, "%s() error writing to rdmabase reg: %d\n",
289 ret
= regmap_write(drvdata
->lpaif_map
,
290 LPAIF_DMABUFF_REG(v
, ch
, dir
),
291 (snd_pcm_lib_buffer_bytes(substream
) >> 2) - 1);
293 dev_err(soc_runtime
->dev
, "%s() error writing to rdmabuff reg: %d\n",
298 ret
= regmap_write(drvdata
->lpaif_map
,
299 LPAIF_DMAPER_REG(v
, ch
, dir
),
300 (snd_pcm_lib_period_bytes(substream
) >> 2) - 1);
302 dev_err(soc_runtime
->dev
, "%s() error writing to rdmaper reg: %d\n",
307 ret
= regmap_update_bits(drvdata
->lpaif_map
,
308 LPAIF_DMACTL_REG(v
, ch
, dir
),
309 LPAIF_DMACTL_ENABLE_MASK
, LPAIF_DMACTL_ENABLE_ON
);
311 dev_err(soc_runtime
->dev
, "%s() error writing to rdmactl reg: %d\n",
319 static int lpass_platform_pcmops_trigger(struct snd_pcm_substream
*substream
,
322 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
323 struct lpass_data
*drvdata
=
324 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
325 struct snd_pcm_runtime
*rt
= substream
->runtime
;
326 struct lpass_pcm_data
*pcm_data
= rt
->private_data
;
327 struct lpass_variant
*v
= drvdata
->variant
;
328 int ret
, ch
, dir
= substream
->stream
;
330 if (dir
== SNDRV_PCM_STREAM_PLAYBACK
)
331 ch
= pcm_data
->rdma_ch
;
333 ch
= pcm_data
->wrdma_ch
;
336 case SNDRV_PCM_TRIGGER_START
:
337 case SNDRV_PCM_TRIGGER_RESUME
:
338 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
339 /* clear status before enabling interrupts */
340 ret
= regmap_write(drvdata
->lpaif_map
,
341 LPAIF_IRQCLEAR_REG(v
, LPAIF_IRQ_PORT_HOST
),
344 dev_err(soc_runtime
->dev
, "%s() error writing to irqclear reg: %d\n",
349 ret
= regmap_update_bits(drvdata
->lpaif_map
,
350 LPAIF_IRQEN_REG(v
, LPAIF_IRQ_PORT_HOST
),
354 dev_err(soc_runtime
->dev
, "%s() error writing to irqen reg: %d\n",
359 ret
= regmap_update_bits(drvdata
->lpaif_map
,
360 LPAIF_DMACTL_REG(v
, ch
, dir
),
361 LPAIF_DMACTL_ENABLE_MASK
,
362 LPAIF_DMACTL_ENABLE_ON
);
364 dev_err(soc_runtime
->dev
, "%s() error writing to rdmactl reg: %d\n",
369 case SNDRV_PCM_TRIGGER_STOP
:
370 case SNDRV_PCM_TRIGGER_SUSPEND
:
371 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
372 ret
= regmap_update_bits(drvdata
->lpaif_map
,
373 LPAIF_DMACTL_REG(v
, ch
, dir
),
374 LPAIF_DMACTL_ENABLE_MASK
,
375 LPAIF_DMACTL_ENABLE_OFF
);
377 dev_err(soc_runtime
->dev
, "%s() error writing to rdmactl reg: %d\n",
382 ret
= regmap_update_bits(drvdata
->lpaif_map
,
383 LPAIF_IRQEN_REG(v
, LPAIF_IRQ_PORT_HOST
),
384 LPAIF_IRQ_ALL(ch
), 0);
386 dev_err(soc_runtime
->dev
, "%s() error writing to irqen reg: %d\n",
396 static snd_pcm_uframes_t
lpass_platform_pcmops_pointer(
397 struct snd_pcm_substream
*substream
)
399 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
400 struct lpass_data
*drvdata
=
401 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
402 struct snd_pcm_runtime
*rt
= substream
->runtime
;
403 struct lpass_pcm_data
*pcm_data
= rt
->private_data
;
404 struct lpass_variant
*v
= drvdata
->variant
;
405 unsigned int base_addr
, curr_addr
;
406 int ret
, ch
, dir
= substream
->stream
;
408 if (dir
== SNDRV_PCM_STREAM_PLAYBACK
)
409 ch
= pcm_data
->rdma_ch
;
411 ch
= pcm_data
->wrdma_ch
;
413 ret
= regmap_read(drvdata
->lpaif_map
,
414 LPAIF_DMABASE_REG(v
, ch
, dir
), &base_addr
);
416 dev_err(soc_runtime
->dev
, "%s() error reading from rdmabase reg: %d\n",
421 ret
= regmap_read(drvdata
->lpaif_map
,
422 LPAIF_DMACURR_REG(v
, ch
, dir
), &curr_addr
);
424 dev_err(soc_runtime
->dev
, "%s() error reading from rdmacurr reg: %d\n",
429 return bytes_to_frames(substream
->runtime
, curr_addr
- base_addr
);
432 static int lpass_platform_pcmops_mmap(struct snd_pcm_substream
*substream
,
433 struct vm_area_struct
*vma
)
435 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
437 return dma_mmap_coherent(substream
->pcm
->card
->dev
, vma
,
438 runtime
->dma_area
, runtime
->dma_addr
,
442 static const struct snd_pcm_ops lpass_platform_pcm_ops
= {
443 .open
= lpass_platform_pcmops_open
,
444 .close
= lpass_platform_pcmops_close
,
445 .ioctl
= snd_pcm_lib_ioctl
,
446 .hw_params
= lpass_platform_pcmops_hw_params
,
447 .hw_free
= lpass_platform_pcmops_hw_free
,
448 .prepare
= lpass_platform_pcmops_prepare
,
449 .trigger
= lpass_platform_pcmops_trigger
,
450 .pointer
= lpass_platform_pcmops_pointer
,
451 .mmap
= lpass_platform_pcmops_mmap
,
454 static irqreturn_t
lpass_dma_interrupt_handler(
455 struct snd_pcm_substream
*substream
,
456 struct lpass_data
*drvdata
,
457 int chan
, u32 interrupts
)
459 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
460 struct lpass_variant
*v
= drvdata
->variant
;
461 irqreturn_t ret
= IRQ_NONE
;
464 if (interrupts
& LPAIF_IRQ_PER(chan
)) {
465 rv
= regmap_write(drvdata
->lpaif_map
,
466 LPAIF_IRQCLEAR_REG(v
, LPAIF_IRQ_PORT_HOST
),
467 LPAIF_IRQ_PER(chan
));
469 dev_err(soc_runtime
->dev
, "%s() error writing to irqclear reg: %d\n",
473 snd_pcm_period_elapsed(substream
);
477 if (interrupts
& LPAIF_IRQ_XRUN(chan
)) {
478 rv
= regmap_write(drvdata
->lpaif_map
,
479 LPAIF_IRQCLEAR_REG(v
, LPAIF_IRQ_PORT_HOST
),
480 LPAIF_IRQ_XRUN(chan
));
482 dev_err(soc_runtime
->dev
, "%s() error writing to irqclear reg: %d\n",
486 dev_warn(soc_runtime
->dev
, "%s() xrun warning\n", __func__
);
487 snd_pcm_stop(substream
, SNDRV_PCM_STATE_XRUN
);
491 if (interrupts
& LPAIF_IRQ_ERR(chan
)) {
492 rv
= regmap_write(drvdata
->lpaif_map
,
493 LPAIF_IRQCLEAR_REG(v
, LPAIF_IRQ_PORT_HOST
),
494 LPAIF_IRQ_ERR(chan
));
496 dev_err(soc_runtime
->dev
, "%s() error writing to irqclear reg: %d\n",
500 dev_err(soc_runtime
->dev
, "%s() bus access error\n", __func__
);
501 snd_pcm_stop(substream
, SNDRV_PCM_STATE_DISCONNECTED
);
508 static irqreturn_t
lpass_platform_lpaif_irq(int irq
, void *data
)
510 struct lpass_data
*drvdata
= data
;
511 struct lpass_variant
*v
= drvdata
->variant
;
515 rv
= regmap_read(drvdata
->lpaif_map
,
516 LPAIF_IRQSTAT_REG(v
, LPAIF_IRQ_PORT_HOST
), &irqs
);
518 pr_err("%s() error reading from irqstat reg: %d\n",
523 /* Handle per channel interrupts */
524 for (chan
= 0; chan
< LPASS_MAX_DMA_CHANNELS
; chan
++) {
525 if (irqs
& LPAIF_IRQ_ALL(chan
) && drvdata
->substream
[chan
]) {
526 rv
= lpass_dma_interrupt_handler(
527 drvdata
->substream
[chan
],
528 drvdata
, chan
, irqs
);
529 if (rv
!= IRQ_HANDLED
)
537 static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime
*soc_runtime
)
539 struct snd_pcm
*pcm
= soc_runtime
->pcm
;
540 struct snd_pcm_substream
*psubstream
, *csubstream
;
542 size_t size
= lpass_platform_pcm_hardware
.buffer_bytes_max
;
544 psubstream
= pcm
->streams
[SNDRV_PCM_STREAM_PLAYBACK
].substream
;
546 ret
= snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV
,
547 soc_runtime
->platform
->dev
,
548 size
, &psubstream
->dma_buffer
);
550 dev_err(soc_runtime
->dev
, "Cannot allocate buffer(s)\n");
555 csubstream
= pcm
->streams
[SNDRV_PCM_STREAM_CAPTURE
].substream
;
557 ret
= snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV
,
558 soc_runtime
->platform
->dev
,
559 size
, &csubstream
->dma_buffer
);
561 dev_err(soc_runtime
->dev
, "Cannot allocate buffer(s)\n");
563 snd_dma_free_pages(&psubstream
->dma_buffer
);
572 static void lpass_platform_pcm_free(struct snd_pcm
*pcm
)
574 struct snd_pcm_substream
*substream
;
577 for (i
= 0; i
< ARRAY_SIZE(pcm
->streams
); i
++) {
578 substream
= pcm
->streams
[i
].substream
;
580 snd_dma_free_pages(&substream
->dma_buffer
);
581 substream
->dma_buffer
.area
= NULL
;
582 substream
->dma_buffer
.addr
= 0;
587 static struct snd_soc_platform_driver lpass_platform_driver
= {
588 .pcm_new
= lpass_platform_pcm_new
,
589 .pcm_free
= lpass_platform_pcm_free
,
590 .ops
= &lpass_platform_pcm_ops
,
593 int asoc_qcom_lpass_platform_register(struct platform_device
*pdev
)
595 struct lpass_data
*drvdata
= platform_get_drvdata(pdev
);
596 struct lpass_variant
*v
= drvdata
->variant
;
599 drvdata
->lpaif_irq
= platform_get_irq_byname(pdev
, "lpass-irq-lpaif");
600 if (drvdata
->lpaif_irq
< 0) {
601 dev_err(&pdev
->dev
, "%s() error getting irq handle: %d\n",
602 __func__
, drvdata
->lpaif_irq
);
606 /* ensure audio hardware is disabled */
607 ret
= regmap_write(drvdata
->lpaif_map
,
608 LPAIF_IRQEN_REG(v
, LPAIF_IRQ_PORT_HOST
), 0);
610 dev_err(&pdev
->dev
, "%s() error writing to irqen reg: %d\n",
615 ret
= devm_request_irq(&pdev
->dev
, drvdata
->lpaif_irq
,
616 lpass_platform_lpaif_irq
, IRQF_TRIGGER_RISING
,
617 "lpass-irq-lpaif", drvdata
);
619 dev_err(&pdev
->dev
, "%s() irq request failed: %d\n",
625 return devm_snd_soc_register_platform(&pdev
->dev
,
626 &lpass_platform_driver
);
628 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register
);
630 MODULE_DESCRIPTION("QTi LPASS Platform Driver");
631 MODULE_LICENSE("GPL v2");