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
;
66 snd_soc_set_runtime_hwparams(substream
, &lpass_platform_pcm_hardware
);
68 runtime
->dma_bytes
= lpass_platform_pcm_hardware
.buffer_bytes_max
;
70 ret
= snd_pcm_hw_constraint_integer(runtime
,
71 SNDRV_PCM_HW_PARAM_PERIODS
);
73 dev_err(soc_runtime
->dev
, "%s() setting constraints failed: %d\n",
78 snd_pcm_set_runtime_buffer(substream
, &substream
->dma_buffer
);
83 static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream
*substream
,
84 struct snd_pcm_hw_params
*params
)
86 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
87 struct lpass_pcm_data
*pcm_data
= snd_soc_pcm_get_drvdata(soc_runtime
);
88 struct lpass_data
*drvdata
=
89 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
90 struct lpass_variant
*v
= drvdata
->variant
;
91 snd_pcm_format_t format
= params_format(params
);
92 unsigned int channels
= params_channels(params
);
94 int ch
, dir
= substream
->stream
;
96 int ret
, dma_port
= pcm_data
->i2s_port
+ v
->dmactl_audif_start
;
98 if (dir
== SNDRV_PCM_STREAM_PLAYBACK
)
99 ch
= pcm_data
->rdma_ch
;
101 ch
= pcm_data
->wrdma_ch
;
103 bitwidth
= snd_pcm_format_width(format
);
105 dev_err(soc_runtime
->dev
, "%s() invalid bit width given: %d\n",
110 regval
= LPAIF_DMACTL_BURSTEN_INCR4
|
111 LPAIF_DMACTL_AUDINTF(dma_port
) |
112 LPAIF_DMACTL_FIFOWM_8
;
119 regval
|= LPAIF_DMACTL_WPSCNT_ONE
;
122 regval
|= LPAIF_DMACTL_WPSCNT_TWO
;
125 regval
|= LPAIF_DMACTL_WPSCNT_THREE
;
128 regval
|= LPAIF_DMACTL_WPSCNT_FOUR
;
131 dev_err(soc_runtime
->dev
, "%s() invalid PCM config given: bw=%d, ch=%u\n",
132 __func__
, bitwidth
, channels
);
140 regval
|= LPAIF_DMACTL_WPSCNT_ONE
;
143 regval
|= LPAIF_DMACTL_WPSCNT_TWO
;
146 regval
|= LPAIF_DMACTL_WPSCNT_FOUR
;
149 regval
|= LPAIF_DMACTL_WPSCNT_SIX
;
152 regval
|= LPAIF_DMACTL_WPSCNT_EIGHT
;
155 dev_err(soc_runtime
->dev
, "%s() invalid PCM config given: bw=%d, ch=%u\n",
156 __func__
, bitwidth
, channels
);
161 dev_err(soc_runtime
->dev
, "%s() invalid PCM config given: bw=%d, ch=%u\n",
162 __func__
, bitwidth
, channels
);
166 ret
= regmap_write(drvdata
->lpaif_map
,
167 LPAIF_DMACTL_REG(v
, ch
, dir
), regval
);
169 dev_err(soc_runtime
->dev
, "%s() error writing to rdmactl reg: %d\n",
177 static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream
*substream
)
179 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
180 struct lpass_pcm_data
*pcm_data
= snd_soc_pcm_get_drvdata(soc_runtime
);
181 struct lpass_data
*drvdata
=
182 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
183 struct lpass_variant
*v
= drvdata
->variant
;
187 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
188 reg
= LPAIF_RDMACTL_REG(v
, pcm_data
->rdma_ch
);
190 reg
= LPAIF_WRDMACTL_REG(v
, pcm_data
->wrdma_ch
);
192 ret
= regmap_write(drvdata
->lpaif_map
, reg
, 0);
194 dev_err(soc_runtime
->dev
, "%s() error writing to rdmactl reg: %d\n",
200 static int lpass_platform_pcmops_prepare(struct snd_pcm_substream
*substream
)
202 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
203 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
204 struct lpass_pcm_data
*pcm_data
= snd_soc_pcm_get_drvdata(soc_runtime
);
205 struct lpass_data
*drvdata
=
206 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
207 struct lpass_variant
*v
= drvdata
->variant
;
208 int ret
, ch
, dir
= substream
->stream
;
210 if (dir
== SNDRV_PCM_STREAM_PLAYBACK
)
211 ch
= pcm_data
->rdma_ch
;
213 ch
= pcm_data
->wrdma_ch
;
215 ret
= regmap_write(drvdata
->lpaif_map
,
216 LPAIF_DMABASE_REG(v
, ch
, dir
),
219 dev_err(soc_runtime
->dev
, "%s() error writing to rdmabase reg: %d\n",
224 ret
= regmap_write(drvdata
->lpaif_map
,
225 LPAIF_DMABUFF_REG(v
, ch
, dir
),
226 (snd_pcm_lib_buffer_bytes(substream
) >> 2) - 1);
228 dev_err(soc_runtime
->dev
, "%s() error writing to rdmabuff reg: %d\n",
233 ret
= regmap_write(drvdata
->lpaif_map
,
234 LPAIF_DMAPER_REG(v
, ch
, dir
),
235 (snd_pcm_lib_period_bytes(substream
) >> 2) - 1);
237 dev_err(soc_runtime
->dev
, "%s() error writing to rdmaper reg: %d\n",
242 ret
= regmap_update_bits(drvdata
->lpaif_map
,
243 LPAIF_DMACTL_REG(v
, ch
, dir
),
244 LPAIF_DMACTL_ENABLE_MASK
, LPAIF_DMACTL_ENABLE_ON
);
246 dev_err(soc_runtime
->dev
, "%s() error writing to rdmactl reg: %d\n",
254 static int lpass_platform_pcmops_trigger(struct snd_pcm_substream
*substream
,
257 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
258 struct lpass_pcm_data
*pcm_data
= snd_soc_pcm_get_drvdata(soc_runtime
);
259 struct lpass_data
*drvdata
=
260 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
261 struct lpass_variant
*v
= drvdata
->variant
;
262 int ret
, ch
, dir
= substream
->stream
;
264 if (dir
== SNDRV_PCM_STREAM_PLAYBACK
)
265 ch
= pcm_data
->rdma_ch
;
267 ch
= pcm_data
->wrdma_ch
;
270 case SNDRV_PCM_TRIGGER_START
:
271 case SNDRV_PCM_TRIGGER_RESUME
:
272 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
273 /* clear status before enabling interrupts */
274 ret
= regmap_write(drvdata
->lpaif_map
,
275 LPAIF_IRQCLEAR_REG(v
, LPAIF_IRQ_PORT_HOST
),
278 dev_err(soc_runtime
->dev
, "%s() error writing to irqclear reg: %d\n",
283 ret
= regmap_update_bits(drvdata
->lpaif_map
,
284 LPAIF_IRQEN_REG(v
, LPAIF_IRQ_PORT_HOST
),
288 dev_err(soc_runtime
->dev
, "%s() error writing to irqen reg: %d\n",
293 ret
= regmap_update_bits(drvdata
->lpaif_map
,
294 LPAIF_DMACTL_REG(v
, ch
, dir
),
295 LPAIF_DMACTL_ENABLE_MASK
,
296 LPAIF_DMACTL_ENABLE_ON
);
298 dev_err(soc_runtime
->dev
, "%s() error writing to rdmactl reg: %d\n",
303 case SNDRV_PCM_TRIGGER_STOP
:
304 case SNDRV_PCM_TRIGGER_SUSPEND
:
305 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
306 ret
= regmap_update_bits(drvdata
->lpaif_map
,
307 LPAIF_DMACTL_REG(v
, ch
, dir
),
308 LPAIF_DMACTL_ENABLE_MASK
,
309 LPAIF_DMACTL_ENABLE_OFF
);
311 dev_err(soc_runtime
->dev
, "%s() error writing to rdmactl reg: %d\n",
316 ret
= regmap_update_bits(drvdata
->lpaif_map
,
317 LPAIF_IRQEN_REG(v
, LPAIF_IRQ_PORT_HOST
),
318 LPAIF_IRQ_ALL(ch
), 0);
320 dev_err(soc_runtime
->dev
, "%s() error writing to irqen reg: %d\n",
330 static snd_pcm_uframes_t
lpass_platform_pcmops_pointer(
331 struct snd_pcm_substream
*substream
)
333 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
334 struct lpass_pcm_data
*pcm_data
= snd_soc_pcm_get_drvdata(soc_runtime
);
335 struct lpass_data
*drvdata
=
336 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
337 struct lpass_variant
*v
= drvdata
->variant
;
338 unsigned int base_addr
, curr_addr
;
339 int ret
, ch
, dir
= substream
->stream
;
341 if (dir
== SNDRV_PCM_STREAM_PLAYBACK
)
342 ch
= pcm_data
->rdma_ch
;
344 ch
= pcm_data
->wrdma_ch
;
346 ret
= regmap_read(drvdata
->lpaif_map
,
347 LPAIF_DMABASE_REG(v
, ch
, dir
), &base_addr
);
349 dev_err(soc_runtime
->dev
, "%s() error reading from rdmabase reg: %d\n",
354 ret
= regmap_read(drvdata
->lpaif_map
,
355 LPAIF_DMACURR_REG(v
, ch
, dir
), &curr_addr
);
357 dev_err(soc_runtime
->dev
, "%s() error reading from rdmacurr reg: %d\n",
362 return bytes_to_frames(substream
->runtime
, curr_addr
- base_addr
);
365 static int lpass_platform_pcmops_mmap(struct snd_pcm_substream
*substream
,
366 struct vm_area_struct
*vma
)
368 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
370 return dma_mmap_coherent(substream
->pcm
->card
->dev
, vma
,
371 runtime
->dma_area
, runtime
->dma_addr
,
375 static struct snd_pcm_ops lpass_platform_pcm_ops
= {
376 .open
= lpass_platform_pcmops_open
,
377 .ioctl
= snd_pcm_lib_ioctl
,
378 .hw_params
= lpass_platform_pcmops_hw_params
,
379 .hw_free
= lpass_platform_pcmops_hw_free
,
380 .prepare
= lpass_platform_pcmops_prepare
,
381 .trigger
= lpass_platform_pcmops_trigger
,
382 .pointer
= lpass_platform_pcmops_pointer
,
383 .mmap
= lpass_platform_pcmops_mmap
,
386 static irqreturn_t
lpass_dma_interrupt_handler(
387 struct snd_pcm_substream
*substream
,
388 struct lpass_data
*drvdata
,
389 int chan
, u32 interrupts
)
391 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
392 struct lpass_variant
*v
= drvdata
->variant
;
393 irqreturn_t ret
= IRQ_NONE
;
396 if (interrupts
& LPAIF_IRQ_PER(chan
)) {
397 rv
= regmap_write(drvdata
->lpaif_map
,
398 LPAIF_IRQCLEAR_REG(v
, LPAIF_IRQ_PORT_HOST
),
399 LPAIF_IRQ_PER(chan
));
401 dev_err(soc_runtime
->dev
, "%s() error writing to irqclear reg: %d\n",
405 snd_pcm_period_elapsed(substream
);
409 if (interrupts
& LPAIF_IRQ_XRUN(chan
)) {
410 rv
= regmap_write(drvdata
->lpaif_map
,
411 LPAIF_IRQCLEAR_REG(v
, LPAIF_IRQ_PORT_HOST
),
412 LPAIF_IRQ_XRUN(chan
));
414 dev_err(soc_runtime
->dev
, "%s() error writing to irqclear reg: %d\n",
418 dev_warn(soc_runtime
->dev
, "%s() xrun warning\n", __func__
);
419 snd_pcm_stop(substream
, SNDRV_PCM_STATE_XRUN
);
423 if (interrupts
& LPAIF_IRQ_ERR(chan
)) {
424 rv
= regmap_write(drvdata
->lpaif_map
,
425 LPAIF_IRQCLEAR_REG(v
, LPAIF_IRQ_PORT_HOST
),
426 LPAIF_IRQ_ERR(chan
));
428 dev_err(soc_runtime
->dev
, "%s() error writing to irqclear reg: %d\n",
432 dev_err(soc_runtime
->dev
, "%s() bus access error\n", __func__
);
433 snd_pcm_stop(substream
, SNDRV_PCM_STATE_DISCONNECTED
);
440 static irqreturn_t
lpass_platform_lpaif_irq(int irq
, void *data
)
442 struct lpass_data
*drvdata
= data
;
443 struct lpass_variant
*v
= drvdata
->variant
;
447 rv
= regmap_read(drvdata
->lpaif_map
,
448 LPAIF_IRQSTAT_REG(v
, LPAIF_IRQ_PORT_HOST
), &irqs
);
450 pr_err("%s() error reading from irqstat reg: %d\n",
455 /* Handle per channel interrupts */
456 for (chan
= 0; chan
< LPASS_MAX_DMA_CHANNELS
; chan
++) {
457 if (irqs
& LPAIF_IRQ_ALL(chan
) && drvdata
->substream
[chan
]) {
458 rv
= lpass_dma_interrupt_handler(
459 drvdata
->substream
[chan
],
460 drvdata
, chan
, irqs
);
461 if (rv
!= IRQ_HANDLED
)
469 static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime
*soc_runtime
)
471 struct snd_pcm
*pcm
= soc_runtime
->pcm
;
472 struct snd_pcm_substream
*psubstream
, *csubstream
;
473 struct snd_soc_dai
*cpu_dai
= soc_runtime
->cpu_dai
;
474 struct lpass_data
*drvdata
=
475 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
476 struct lpass_variant
*v
= drvdata
->variant
;
478 struct lpass_pcm_data
*data
;
479 size_t size
= lpass_platform_pcm_hardware
.buffer_bytes_max
;
481 data
= devm_kzalloc(soc_runtime
->dev
, sizeof(*data
), GFP_KERNEL
);
485 data
->i2s_port
= cpu_dai
->driver
->id
;
486 snd_soc_pcm_set_drvdata(soc_runtime
, data
);
488 psubstream
= pcm
->streams
[SNDRV_PCM_STREAM_PLAYBACK
].substream
;
490 if (v
->alloc_dma_channel
)
491 data
->rdma_ch
= v
->alloc_dma_channel(drvdata
,
492 SNDRV_PCM_STREAM_PLAYBACK
);
494 if (IS_ERR_VALUE(data
->rdma_ch
))
495 return data
->rdma_ch
;
497 drvdata
->substream
[data
->rdma_ch
] = psubstream
;
499 ret
= snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV
,
500 soc_runtime
->platform
->dev
,
501 size
, &psubstream
->dma_buffer
);
503 goto playback_alloc_err
;
505 ret
= regmap_write(drvdata
->lpaif_map
,
506 LPAIF_RDMACTL_REG(v
, data
->rdma_ch
), 0);
508 dev_err(soc_runtime
->dev
,
509 "%s() error writing to rdmactl reg: %d\n",
511 goto capture_alloc_err
;
515 csubstream
= pcm
->streams
[SNDRV_PCM_STREAM_CAPTURE
].substream
;
517 if (v
->alloc_dma_channel
)
518 data
->wrdma_ch
= v
->alloc_dma_channel(drvdata
,
519 SNDRV_PCM_STREAM_CAPTURE
);
521 if (IS_ERR_VALUE(data
->wrdma_ch
))
522 goto capture_alloc_err
;
524 drvdata
->substream
[data
->wrdma_ch
] = csubstream
;
526 ret
= snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV
,
527 soc_runtime
->platform
->dev
,
528 size
, &csubstream
->dma_buffer
);
530 goto capture_alloc_err
;
532 ret
= regmap_write(drvdata
->lpaif_map
,
533 LPAIF_WRDMACTL_REG(v
, data
->wrdma_ch
), 0);
535 dev_err(soc_runtime
->dev
,
536 "%s() error writing to wrdmactl reg: %d\n",
538 goto capture_reg_err
;
546 snd_dma_free_pages(&csubstream
->dma_buffer
);
550 snd_dma_free_pages(&psubstream
->dma_buffer
);
553 dev_err(soc_runtime
->dev
, "Cannot allocate buffer(s)\n");
558 static void lpass_platform_pcm_free(struct snd_pcm
*pcm
)
560 struct snd_soc_pcm_runtime
*rt
;
561 struct lpass_data
*drvdata
;
562 struct lpass_pcm_data
*data
;
563 struct lpass_variant
*v
;
564 struct snd_pcm_substream
*substream
;
567 for (i
= 0; i
< ARRAY_SIZE(pcm
->streams
); i
++) {
568 substream
= pcm
->streams
[i
].substream
;
570 rt
= substream
->private_data
;
571 data
= snd_soc_pcm_get_drvdata(rt
);
572 drvdata
= snd_soc_platform_get_drvdata(rt
->platform
);
574 ch
= (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
577 v
= drvdata
->variant
;
578 drvdata
->substream
[ch
] = NULL
;
579 if (v
->free_dma_channel
)
580 v
->free_dma_channel(drvdata
, ch
);
582 snd_dma_free_pages(&substream
->dma_buffer
);
583 substream
->dma_buffer
.area
= NULL
;
584 substream
->dma_buffer
.addr
= 0;
589 static struct snd_soc_platform_driver lpass_platform_driver
= {
590 .pcm_new
= lpass_platform_pcm_new
,
591 .pcm_free
= lpass_platform_pcm_free
,
592 .ops
= &lpass_platform_pcm_ops
,
595 int asoc_qcom_lpass_platform_register(struct platform_device
*pdev
)
597 struct lpass_data
*drvdata
= platform_get_drvdata(pdev
);
598 struct lpass_variant
*v
= drvdata
->variant
;
601 drvdata
->lpaif_irq
= platform_get_irq_byname(pdev
, "lpass-irq-lpaif");
602 if (drvdata
->lpaif_irq
< 0) {
603 dev_err(&pdev
->dev
, "%s() error getting irq handle: %d\n",
604 __func__
, drvdata
->lpaif_irq
);
608 /* ensure audio hardware is disabled */
609 ret
= regmap_write(drvdata
->lpaif_map
,
610 LPAIF_IRQEN_REG(v
, LPAIF_IRQ_PORT_HOST
), 0);
612 dev_err(&pdev
->dev
, "%s() error writing to irqen reg: %d\n",
617 ret
= devm_request_irq(&pdev
->dev
, drvdata
->lpaif_irq
,
618 lpass_platform_lpaif_irq
, IRQF_TRIGGER_RISING
,
619 "lpass-irq-lpaif", drvdata
);
621 dev_err(&pdev
->dev
, "%s() irq request failed: %d\n",
627 return devm_snd_soc_register_platform(&pdev
->dev
,
628 &lpass_platform_driver
);
630 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register
);
632 MODULE_DESCRIPTION("QTi LPASS Platform Driver");
633 MODULE_LICENSE("GPL v2");