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
{
32 #define LPASS_PLATFORM_BUFFER_SIZE (16 * 1024)
33 #define LPASS_PLATFORM_PERIODS 2
35 static struct snd_pcm_hardware lpass_platform_pcm_hardware
= {
36 .info
= SNDRV_PCM_INFO_MMAP
|
37 SNDRV_PCM_INFO_MMAP_VALID
|
38 SNDRV_PCM_INFO_INTERLEAVED
|
39 SNDRV_PCM_INFO_PAUSE
|
40 SNDRV_PCM_INFO_RESUME
,
41 .formats
= SNDRV_PCM_FMTBIT_S16
|
42 SNDRV_PCM_FMTBIT_S24
|
44 .rates
= SNDRV_PCM_RATE_8000_192000
,
49 .buffer_bytes_max
= LPASS_PLATFORM_BUFFER_SIZE
,
50 .period_bytes_max
= LPASS_PLATFORM_BUFFER_SIZE
/
51 LPASS_PLATFORM_PERIODS
,
52 .period_bytes_min
= LPASS_PLATFORM_BUFFER_SIZE
/
53 LPASS_PLATFORM_PERIODS
,
54 .periods_min
= LPASS_PLATFORM_PERIODS
,
55 .periods_max
= LPASS_PLATFORM_PERIODS
,
59 static int lpass_platform_pcmops_open(struct snd_pcm_substream
*substream
)
61 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
62 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
63 struct snd_soc_dai
*cpu_dai
= soc_runtime
->cpu_dai
;
64 struct lpass_data
*drvdata
=
65 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
66 struct lpass_variant
*v
= drvdata
->variant
;
67 int ret
, dma_ch
, dir
= substream
->stream
;
68 struct lpass_pcm_data
*data
;
70 data
= devm_kzalloc(soc_runtime
->dev
, sizeof(*data
), GFP_KERNEL
);
74 data
->i2s_port
= cpu_dai
->driver
->id
;
75 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 data
->dma_ch
= dma_ch
;
99 snd_soc_set_runtime_hwparams(substream
, &lpass_platform_pcm_hardware
);
101 runtime
->dma_bytes
= lpass_platform_pcm_hardware
.buffer_bytes_max
;
103 ret
= snd_pcm_hw_constraint_integer(runtime
,
104 SNDRV_PCM_HW_PARAM_PERIODS
);
106 dev_err(soc_runtime
->dev
, "%s() setting constraints failed: %d\n",
111 snd_pcm_set_runtime_buffer(substream
, &substream
->dma_buffer
);
116 static int lpass_platform_pcmops_close(struct snd_pcm_substream
*substream
)
118 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
119 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
120 struct lpass_data
*drvdata
=
121 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
122 struct lpass_variant
*v
= drvdata
->variant
;
123 struct lpass_pcm_data
*data
;
125 data
= runtime
->private_data
;
126 v
= drvdata
->variant
;
127 drvdata
->substream
[data
->dma_ch
] = NULL
;
128 if (v
->free_dma_channel
)
129 v
->free_dma_channel(drvdata
, data
->dma_ch
);
134 static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream
*substream
,
135 struct snd_pcm_hw_params
*params
)
137 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
138 struct lpass_data
*drvdata
=
139 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
140 struct snd_pcm_runtime
*rt
= substream
->runtime
;
141 struct lpass_pcm_data
*pcm_data
= rt
->private_data
;
142 struct lpass_variant
*v
= drvdata
->variant
;
143 snd_pcm_format_t format
= params_format(params
);
144 unsigned int channels
= params_channels(params
);
146 int ch
, dir
= substream
->stream
;
148 int ret
, dma_port
= pcm_data
->i2s_port
+ v
->dmactl_audif_start
;
150 ch
= pcm_data
->dma_ch
;
152 bitwidth
= snd_pcm_format_width(format
);
154 dev_err(soc_runtime
->dev
, "%s() invalid bit width given: %d\n",
159 regval
= LPAIF_DMACTL_BURSTEN_INCR4
|
160 LPAIF_DMACTL_AUDINTF(dma_port
) |
161 LPAIF_DMACTL_FIFOWM_8
;
168 regval
|= LPAIF_DMACTL_WPSCNT_ONE
;
171 regval
|= LPAIF_DMACTL_WPSCNT_TWO
;
174 regval
|= LPAIF_DMACTL_WPSCNT_THREE
;
177 regval
|= LPAIF_DMACTL_WPSCNT_FOUR
;
180 dev_err(soc_runtime
->dev
, "%s() invalid PCM config given: bw=%d, ch=%u\n",
181 __func__
, bitwidth
, channels
);
189 regval
|= LPAIF_DMACTL_WPSCNT_ONE
;
192 regval
|= LPAIF_DMACTL_WPSCNT_TWO
;
195 regval
|= LPAIF_DMACTL_WPSCNT_FOUR
;
198 regval
|= LPAIF_DMACTL_WPSCNT_SIX
;
201 regval
|= LPAIF_DMACTL_WPSCNT_EIGHT
;
204 dev_err(soc_runtime
->dev
, "%s() invalid PCM config given: bw=%d, ch=%u\n",
205 __func__
, bitwidth
, channels
);
210 dev_err(soc_runtime
->dev
, "%s() invalid PCM config given: bw=%d, ch=%u\n",
211 __func__
, bitwidth
, channels
);
215 ret
= regmap_write(drvdata
->lpaif_map
,
216 LPAIF_DMACTL_REG(v
, ch
, dir
), regval
);
218 dev_err(soc_runtime
->dev
, "%s() error writing to rdmactl reg: %d\n",
226 static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream
*substream
)
228 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
229 struct lpass_data
*drvdata
=
230 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
231 struct snd_pcm_runtime
*rt
= substream
->runtime
;
232 struct lpass_pcm_data
*pcm_data
= rt
->private_data
;
233 struct lpass_variant
*v
= drvdata
->variant
;
237 reg
= LPAIF_DMACTL_REG(v
, pcm_data
->dma_ch
, substream
->stream
);
238 ret
= regmap_write(drvdata
->lpaif_map
, reg
, 0);
240 dev_err(soc_runtime
->dev
, "%s() error writing to rdmactl reg: %d\n",
246 static int lpass_platform_pcmops_prepare(struct snd_pcm_substream
*substream
)
248 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
249 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
250 struct lpass_data
*drvdata
=
251 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
252 struct snd_pcm_runtime
*rt
= substream
->runtime
;
253 struct lpass_pcm_data
*pcm_data
= rt
->private_data
;
254 struct lpass_variant
*v
= drvdata
->variant
;
255 int ret
, ch
, dir
= substream
->stream
;
257 ch
= pcm_data
->dma_ch
;
259 ret
= regmap_write(drvdata
->lpaif_map
,
260 LPAIF_DMABASE_REG(v
, ch
, dir
),
263 dev_err(soc_runtime
->dev
, "%s() error writing to rdmabase reg: %d\n",
268 ret
= regmap_write(drvdata
->lpaif_map
,
269 LPAIF_DMABUFF_REG(v
, ch
, dir
),
270 (snd_pcm_lib_buffer_bytes(substream
) >> 2) - 1);
272 dev_err(soc_runtime
->dev
, "%s() error writing to rdmabuff reg: %d\n",
277 ret
= regmap_write(drvdata
->lpaif_map
,
278 LPAIF_DMAPER_REG(v
, ch
, dir
),
279 (snd_pcm_lib_period_bytes(substream
) >> 2) - 1);
281 dev_err(soc_runtime
->dev
, "%s() error writing to rdmaper reg: %d\n",
286 ret
= regmap_update_bits(drvdata
->lpaif_map
,
287 LPAIF_DMACTL_REG(v
, ch
, dir
),
288 LPAIF_DMACTL_ENABLE_MASK
, LPAIF_DMACTL_ENABLE_ON
);
290 dev_err(soc_runtime
->dev
, "%s() error writing to rdmactl reg: %d\n",
298 static int lpass_platform_pcmops_trigger(struct snd_pcm_substream
*substream
,
301 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
302 struct lpass_data
*drvdata
=
303 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
304 struct snd_pcm_runtime
*rt
= substream
->runtime
;
305 struct lpass_pcm_data
*pcm_data
= rt
->private_data
;
306 struct lpass_variant
*v
= drvdata
->variant
;
307 int ret
, ch
, dir
= substream
->stream
;
309 ch
= pcm_data
->dma_ch
;
312 case SNDRV_PCM_TRIGGER_START
:
313 case SNDRV_PCM_TRIGGER_RESUME
:
314 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
315 /* clear status before enabling interrupts */
316 ret
= regmap_write(drvdata
->lpaif_map
,
317 LPAIF_IRQCLEAR_REG(v
, LPAIF_IRQ_PORT_HOST
),
320 dev_err(soc_runtime
->dev
, "%s() error writing to irqclear reg: %d\n",
325 ret
= regmap_update_bits(drvdata
->lpaif_map
,
326 LPAIF_IRQEN_REG(v
, LPAIF_IRQ_PORT_HOST
),
330 dev_err(soc_runtime
->dev
, "%s() error writing to irqen reg: %d\n",
335 ret
= regmap_update_bits(drvdata
->lpaif_map
,
336 LPAIF_DMACTL_REG(v
, ch
, dir
),
337 LPAIF_DMACTL_ENABLE_MASK
,
338 LPAIF_DMACTL_ENABLE_ON
);
340 dev_err(soc_runtime
->dev
, "%s() error writing to rdmactl reg: %d\n",
345 case SNDRV_PCM_TRIGGER_STOP
:
346 case SNDRV_PCM_TRIGGER_SUSPEND
:
347 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
348 ret
= regmap_update_bits(drvdata
->lpaif_map
,
349 LPAIF_DMACTL_REG(v
, ch
, dir
),
350 LPAIF_DMACTL_ENABLE_MASK
,
351 LPAIF_DMACTL_ENABLE_OFF
);
353 dev_err(soc_runtime
->dev
, "%s() error writing to rdmactl reg: %d\n",
358 ret
= regmap_update_bits(drvdata
->lpaif_map
,
359 LPAIF_IRQEN_REG(v
, LPAIF_IRQ_PORT_HOST
),
360 LPAIF_IRQ_ALL(ch
), 0);
362 dev_err(soc_runtime
->dev
, "%s() error writing to irqen reg: %d\n",
372 static snd_pcm_uframes_t
lpass_platform_pcmops_pointer(
373 struct snd_pcm_substream
*substream
)
375 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
376 struct lpass_data
*drvdata
=
377 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
378 struct snd_pcm_runtime
*rt
= substream
->runtime
;
379 struct lpass_pcm_data
*pcm_data
= rt
->private_data
;
380 struct lpass_variant
*v
= drvdata
->variant
;
381 unsigned int base_addr
, curr_addr
;
382 int ret
, ch
, dir
= substream
->stream
;
384 ch
= pcm_data
->dma_ch
;
386 ret
= regmap_read(drvdata
->lpaif_map
,
387 LPAIF_DMABASE_REG(v
, ch
, dir
), &base_addr
);
389 dev_err(soc_runtime
->dev
, "%s() error reading from rdmabase reg: %d\n",
394 ret
= regmap_read(drvdata
->lpaif_map
,
395 LPAIF_DMACURR_REG(v
, ch
, dir
), &curr_addr
);
397 dev_err(soc_runtime
->dev
, "%s() error reading from rdmacurr reg: %d\n",
402 return bytes_to_frames(substream
->runtime
, curr_addr
- base_addr
);
405 static int lpass_platform_pcmops_mmap(struct snd_pcm_substream
*substream
,
406 struct vm_area_struct
*vma
)
408 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
410 return dma_mmap_coherent(substream
->pcm
->card
->dev
, vma
,
411 runtime
->dma_area
, runtime
->dma_addr
,
415 static const struct snd_pcm_ops lpass_platform_pcm_ops
= {
416 .open
= lpass_platform_pcmops_open
,
417 .close
= lpass_platform_pcmops_close
,
418 .ioctl
= snd_pcm_lib_ioctl
,
419 .hw_params
= lpass_platform_pcmops_hw_params
,
420 .hw_free
= lpass_platform_pcmops_hw_free
,
421 .prepare
= lpass_platform_pcmops_prepare
,
422 .trigger
= lpass_platform_pcmops_trigger
,
423 .pointer
= lpass_platform_pcmops_pointer
,
424 .mmap
= lpass_platform_pcmops_mmap
,
427 static irqreturn_t
lpass_dma_interrupt_handler(
428 struct snd_pcm_substream
*substream
,
429 struct lpass_data
*drvdata
,
430 int chan
, u32 interrupts
)
432 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
433 struct lpass_variant
*v
= drvdata
->variant
;
434 irqreturn_t ret
= IRQ_NONE
;
437 if (interrupts
& LPAIF_IRQ_PER(chan
)) {
438 rv
= regmap_write(drvdata
->lpaif_map
,
439 LPAIF_IRQCLEAR_REG(v
, LPAIF_IRQ_PORT_HOST
),
440 LPAIF_IRQ_PER(chan
));
442 dev_err(soc_runtime
->dev
, "%s() error writing to irqclear reg: %d\n",
446 snd_pcm_period_elapsed(substream
);
450 if (interrupts
& LPAIF_IRQ_XRUN(chan
)) {
451 rv
= regmap_write(drvdata
->lpaif_map
,
452 LPAIF_IRQCLEAR_REG(v
, LPAIF_IRQ_PORT_HOST
),
453 LPAIF_IRQ_XRUN(chan
));
455 dev_err(soc_runtime
->dev
, "%s() error writing to irqclear reg: %d\n",
459 dev_warn(soc_runtime
->dev
, "%s() xrun warning\n", __func__
);
460 snd_pcm_stop(substream
, SNDRV_PCM_STATE_XRUN
);
464 if (interrupts
& LPAIF_IRQ_ERR(chan
)) {
465 rv
= regmap_write(drvdata
->lpaif_map
,
466 LPAIF_IRQCLEAR_REG(v
, LPAIF_IRQ_PORT_HOST
),
467 LPAIF_IRQ_ERR(chan
));
469 dev_err(soc_runtime
->dev
, "%s() error writing to irqclear reg: %d\n",
473 dev_err(soc_runtime
->dev
, "%s() bus access error\n", __func__
);
474 snd_pcm_stop(substream
, SNDRV_PCM_STATE_DISCONNECTED
);
481 static irqreturn_t
lpass_platform_lpaif_irq(int irq
, void *data
)
483 struct lpass_data
*drvdata
= data
;
484 struct lpass_variant
*v
= drvdata
->variant
;
488 rv
= regmap_read(drvdata
->lpaif_map
,
489 LPAIF_IRQSTAT_REG(v
, LPAIF_IRQ_PORT_HOST
), &irqs
);
491 pr_err("%s() error reading from irqstat reg: %d\n",
496 /* Handle per channel interrupts */
497 for (chan
= 0; chan
< LPASS_MAX_DMA_CHANNELS
; chan
++) {
498 if (irqs
& LPAIF_IRQ_ALL(chan
) && drvdata
->substream
[chan
]) {
499 rv
= lpass_dma_interrupt_handler(
500 drvdata
->substream
[chan
],
501 drvdata
, chan
, irqs
);
502 if (rv
!= IRQ_HANDLED
)
510 static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime
*soc_runtime
)
512 struct snd_pcm
*pcm
= soc_runtime
->pcm
;
513 struct snd_pcm_substream
*psubstream
, *csubstream
;
515 size_t size
= lpass_platform_pcm_hardware
.buffer_bytes_max
;
517 psubstream
= pcm
->streams
[SNDRV_PCM_STREAM_PLAYBACK
].substream
;
519 ret
= snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV
,
520 soc_runtime
->platform
->dev
,
521 size
, &psubstream
->dma_buffer
);
523 dev_err(soc_runtime
->dev
, "Cannot allocate buffer(s)\n");
528 csubstream
= pcm
->streams
[SNDRV_PCM_STREAM_CAPTURE
].substream
;
530 ret
= snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV
,
531 soc_runtime
->platform
->dev
,
532 size
, &csubstream
->dma_buffer
);
534 dev_err(soc_runtime
->dev
, "Cannot allocate buffer(s)\n");
536 snd_dma_free_pages(&psubstream
->dma_buffer
);
545 static void lpass_platform_pcm_free(struct snd_pcm
*pcm
)
547 struct snd_pcm_substream
*substream
;
550 for (i
= 0; i
< ARRAY_SIZE(pcm
->streams
); i
++) {
551 substream
= pcm
->streams
[i
].substream
;
553 snd_dma_free_pages(&substream
->dma_buffer
);
554 substream
->dma_buffer
.area
= NULL
;
555 substream
->dma_buffer
.addr
= 0;
560 static struct snd_soc_platform_driver lpass_platform_driver
= {
561 .pcm_new
= lpass_platform_pcm_new
,
562 .pcm_free
= lpass_platform_pcm_free
,
563 .ops
= &lpass_platform_pcm_ops
,
566 int asoc_qcom_lpass_platform_register(struct platform_device
*pdev
)
568 struct lpass_data
*drvdata
= platform_get_drvdata(pdev
);
569 struct lpass_variant
*v
= drvdata
->variant
;
572 drvdata
->lpaif_irq
= platform_get_irq_byname(pdev
, "lpass-irq-lpaif");
573 if (drvdata
->lpaif_irq
< 0) {
574 dev_err(&pdev
->dev
, "%s() error getting irq handle: %d\n",
575 __func__
, drvdata
->lpaif_irq
);
579 /* ensure audio hardware is disabled */
580 ret
= regmap_write(drvdata
->lpaif_map
,
581 LPAIF_IRQEN_REG(v
, LPAIF_IRQ_PORT_HOST
), 0);
583 dev_err(&pdev
->dev
, "%s() error writing to irqen reg: %d\n",
588 ret
= devm_request_irq(&pdev
->dev
, drvdata
->lpaif_irq
,
589 lpass_platform_lpaif_irq
, IRQF_TRIGGER_RISING
,
590 "lpass-irq-lpaif", drvdata
);
592 dev_err(&pdev
->dev
, "%s() irq request failed: %d\n",
598 return devm_snd_soc_register_platform(&pdev
->dev
,
599 &lpass_platform_driver
);
601 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register
);
603 MODULE_DESCRIPTION("QTi LPASS Platform Driver");
604 MODULE_LICENSE("GPL v2");