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
;
65 snd_soc_set_runtime_hwparams(substream
, &lpass_platform_pcm_hardware
);
67 runtime
->dma_bytes
= lpass_platform_pcm_hardware
.buffer_bytes_max
;
69 ret
= snd_pcm_hw_constraint_integer(runtime
,
70 SNDRV_PCM_HW_PARAM_PERIODS
);
72 dev_err(soc_runtime
->dev
, "%s() setting constraints failed: %d\n",
77 snd_pcm_set_runtime_buffer(substream
, &substream
->dma_buffer
);
82 static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream
*substream
,
83 struct snd_pcm_hw_params
*params
)
85 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
86 struct lpass_pcm_data
*pcm_data
= snd_soc_pcm_get_drvdata(soc_runtime
);
87 struct lpass_data
*drvdata
=
88 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
89 struct lpass_variant
*v
= drvdata
->variant
;
90 snd_pcm_format_t format
= params_format(params
);
91 unsigned int channels
= params_channels(params
);
93 int dir
= substream
->stream
;
95 int ret
, dma_port
= pcm_data
->i2s_port
+ v
->dmactl_audif_start
;
97 bitwidth
= snd_pcm_format_width(format
);
99 dev_err(soc_runtime
->dev
, "%s() invalid bit width given: %d\n",
104 regval
= LPAIF_DMACTL_BURSTEN_INCR4
|
105 LPAIF_DMACTL_AUDINTF(dma_port
) |
106 LPAIF_DMACTL_FIFOWM_8
;
113 regval
|= LPAIF_DMACTL_WPSCNT_ONE
;
116 regval
|= LPAIF_DMACTL_WPSCNT_TWO
;
119 regval
|= LPAIF_DMACTL_WPSCNT_THREE
;
122 regval
|= LPAIF_DMACTL_WPSCNT_FOUR
;
125 dev_err(soc_runtime
->dev
, "%s() invalid PCM config given: bw=%d, ch=%u\n",
126 __func__
, bitwidth
, channels
);
134 regval
|= LPAIF_DMACTL_WPSCNT_ONE
;
137 regval
|= LPAIF_DMACTL_WPSCNT_TWO
;
140 regval
|= LPAIF_DMACTL_WPSCNT_FOUR
;
143 regval
|= LPAIF_DMACTL_WPSCNT_SIX
;
146 regval
|= LPAIF_DMACTL_WPSCNT_EIGHT
;
149 dev_err(soc_runtime
->dev
, "%s() invalid PCM config given: bw=%d, ch=%u\n",
150 __func__
, bitwidth
, channels
);
155 dev_err(soc_runtime
->dev
, "%s() invalid PCM config given: bw=%d, ch=%u\n",
156 __func__
, bitwidth
, channels
);
160 ret
= regmap_write(drvdata
->lpaif_map
,
161 LPAIF_DMACTL_REG(v
, pcm_data
->rdma_ch
, dir
), regval
);
163 dev_err(soc_runtime
->dev
, "%s() error writing to rdmactl reg: %d\n",
171 static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream
*substream
)
173 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
174 struct lpass_pcm_data
*pcm_data
= snd_soc_pcm_get_drvdata(soc_runtime
);
175 struct lpass_data
*drvdata
=
176 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
177 struct lpass_variant
*v
= drvdata
->variant
;
180 ret
= regmap_write(drvdata
->lpaif_map
,
181 LPAIF_RDMACTL_REG(v
, pcm_data
->rdma_ch
), 0);
183 dev_err(soc_runtime
->dev
, "%s() error writing to rdmactl reg: %d\n",
189 static int lpass_platform_pcmops_prepare(struct snd_pcm_substream
*substream
)
191 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
192 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
193 struct lpass_pcm_data
*pcm_data
= snd_soc_pcm_get_drvdata(soc_runtime
);
194 struct lpass_data
*drvdata
=
195 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
196 struct lpass_variant
*v
= drvdata
->variant
;
197 int ret
, ch
= pcm_data
->rdma_ch
;
198 int dir
= substream
->stream
;
200 ret
= regmap_write(drvdata
->lpaif_map
,
201 LPAIF_RDMABASE_REG(v
, ch
),
204 dev_err(soc_runtime
->dev
, "%s() error writing to rdmabase reg: %d\n",
209 ret
= regmap_write(drvdata
->lpaif_map
,
210 LPAIF_DMABUFF_REG(v
, ch
, dir
),
211 (snd_pcm_lib_buffer_bytes(substream
) >> 2) - 1);
213 dev_err(soc_runtime
->dev
, "%s() error writing to rdmabuff reg: %d\n",
218 ret
= regmap_write(drvdata
->lpaif_map
,
219 LPAIF_DMAPER_REG(v
, ch
, dir
),
220 (snd_pcm_lib_period_bytes(substream
) >> 2) - 1);
222 dev_err(soc_runtime
->dev
, "%s() error writing to rdmaper reg: %d\n",
227 ret
= regmap_update_bits(drvdata
->lpaif_map
,
228 LPAIF_DMACTL_REG(v
, ch
, dir
),
229 LPAIF_DMACTL_ENABLE_MASK
, LPAIF_DMACTL_ENABLE_ON
);
231 dev_err(soc_runtime
->dev
, "%s() error writing to rdmactl reg: %d\n",
239 static int lpass_platform_pcmops_trigger(struct snd_pcm_substream
*substream
,
242 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
243 struct lpass_pcm_data
*pcm_data
= snd_soc_pcm_get_drvdata(soc_runtime
);
244 struct lpass_data
*drvdata
=
245 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
246 struct lpass_variant
*v
= drvdata
->variant
;
247 int ret
, ch
= pcm_data
->rdma_ch
;
248 int dir
= substream
->stream
;
251 case SNDRV_PCM_TRIGGER_START
:
252 case SNDRV_PCM_TRIGGER_RESUME
:
253 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
254 /* clear status before enabling interrupts */
255 ret
= regmap_write(drvdata
->lpaif_map
,
256 LPAIF_IRQCLEAR_REG(v
, LPAIF_IRQ_PORT_HOST
),
259 dev_err(soc_runtime
->dev
, "%s() error writing to irqclear reg: %d\n",
264 ret
= regmap_update_bits(drvdata
->lpaif_map
,
265 LPAIF_IRQEN_REG(v
, LPAIF_IRQ_PORT_HOST
),
269 dev_err(soc_runtime
->dev
, "%s() error writing to irqen reg: %d\n",
274 ret
= regmap_update_bits(drvdata
->lpaif_map
,
275 LPAIF_DMACTL_REG(v
, ch
, dir
),
276 LPAIF_DMACTL_ENABLE_MASK
,
277 LPAIF_DMACTL_ENABLE_ON
);
279 dev_err(soc_runtime
->dev
, "%s() error writing to rdmactl reg: %d\n",
284 case SNDRV_PCM_TRIGGER_STOP
:
285 case SNDRV_PCM_TRIGGER_SUSPEND
:
286 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
287 ret
= regmap_update_bits(drvdata
->lpaif_map
,
288 LPAIF_DMACTL_REG(v
, ch
, dir
),
289 LPAIF_DMACTL_ENABLE_MASK
,
290 LPAIF_DMACTL_ENABLE_OFF
);
292 dev_err(soc_runtime
->dev
, "%s() error writing to rdmactl reg: %d\n",
297 ret
= regmap_update_bits(drvdata
->lpaif_map
,
298 LPAIF_IRQEN_REG(v
, LPAIF_IRQ_PORT_HOST
),
299 LPAIF_IRQ_ALL(ch
), 0);
301 dev_err(soc_runtime
->dev
, "%s() error writing to irqen reg: %d\n",
311 static snd_pcm_uframes_t
lpass_platform_pcmops_pointer(
312 struct snd_pcm_substream
*substream
)
314 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
315 struct lpass_pcm_data
*pcm_data
= snd_soc_pcm_get_drvdata(soc_runtime
);
316 struct lpass_data
*drvdata
=
317 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
318 struct lpass_variant
*v
= drvdata
->variant
;
319 unsigned int base_addr
, curr_addr
;
320 int ret
, ch
= pcm_data
->rdma_ch
;
321 int dir
= substream
->stream
;
323 ret
= regmap_read(drvdata
->lpaif_map
,
324 LPAIF_DMABASE_REG(v
, ch
, dir
), &base_addr
);
326 dev_err(soc_runtime
->dev
, "%s() error reading from rdmabase reg: %d\n",
331 ret
= regmap_read(drvdata
->lpaif_map
,
332 LPAIF_DMACURR_REG(v
, ch
, dir
), &curr_addr
);
334 dev_err(soc_runtime
->dev
, "%s() error reading from rdmacurr reg: %d\n",
339 return bytes_to_frames(substream
->runtime
, curr_addr
- base_addr
);
342 static int lpass_platform_pcmops_mmap(struct snd_pcm_substream
*substream
,
343 struct vm_area_struct
*vma
)
345 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
347 return dma_mmap_coherent(substream
->pcm
->card
->dev
, vma
,
348 runtime
->dma_area
, runtime
->dma_addr
,
352 static struct snd_pcm_ops lpass_platform_pcm_ops
= {
353 .open
= lpass_platform_pcmops_open
,
354 .ioctl
= snd_pcm_lib_ioctl
,
355 .hw_params
= lpass_platform_pcmops_hw_params
,
356 .hw_free
= lpass_platform_pcmops_hw_free
,
357 .prepare
= lpass_platform_pcmops_prepare
,
358 .trigger
= lpass_platform_pcmops_trigger
,
359 .pointer
= lpass_platform_pcmops_pointer
,
360 .mmap
= lpass_platform_pcmops_mmap
,
363 static irqreturn_t
lpass_dma_interrupt_handler(
364 struct snd_pcm_substream
*substream
,
365 struct lpass_data
*drvdata
,
366 int chan
, u32 interrupts
)
368 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
369 struct lpass_variant
*v
= drvdata
->variant
;
370 irqreturn_t ret
= IRQ_NONE
;
373 if (interrupts
& LPAIF_IRQ_PER(chan
)) {
374 rv
= regmap_write(drvdata
->lpaif_map
,
375 LPAIF_IRQCLEAR_REG(v
, LPAIF_IRQ_PORT_HOST
),
376 LPAIF_IRQ_PER(chan
));
378 dev_err(soc_runtime
->dev
, "%s() error writing to irqclear reg: %d\n",
382 snd_pcm_period_elapsed(substream
);
386 if (interrupts
& LPAIF_IRQ_XRUN(chan
)) {
387 rv
= regmap_write(drvdata
->lpaif_map
,
388 LPAIF_IRQCLEAR_REG(v
, LPAIF_IRQ_PORT_HOST
),
389 LPAIF_IRQ_XRUN(chan
));
391 dev_err(soc_runtime
->dev
, "%s() error writing to irqclear reg: %d\n",
395 dev_warn(soc_runtime
->dev
, "%s() xrun warning\n", __func__
);
396 snd_pcm_stop(substream
, SNDRV_PCM_STATE_XRUN
);
400 if (interrupts
& LPAIF_IRQ_ERR(chan
)) {
401 rv
= regmap_write(drvdata
->lpaif_map
,
402 LPAIF_IRQCLEAR_REG(v
, LPAIF_IRQ_PORT_HOST
),
403 LPAIF_IRQ_ERR(chan
));
405 dev_err(soc_runtime
->dev
, "%s() error writing to irqclear reg: %d\n",
409 dev_err(soc_runtime
->dev
, "%s() bus access error\n", __func__
);
410 snd_pcm_stop(substream
, SNDRV_PCM_STATE_DISCONNECTED
);
417 static irqreturn_t
lpass_platform_lpaif_irq(int irq
, void *data
)
419 struct lpass_data
*drvdata
= data
;
420 struct lpass_variant
*v
= drvdata
->variant
;
424 rv
= regmap_read(drvdata
->lpaif_map
,
425 LPAIF_IRQSTAT_REG(v
, LPAIF_IRQ_PORT_HOST
), &irqs
);
427 pr_err("%s() error reading from irqstat reg: %d\n",
432 /* Handle per channel interrupts */
433 for (chan
= 0; chan
< LPASS_MAX_DMA_CHANNELS
; chan
++) {
434 if (irqs
& LPAIF_IRQ_ALL(chan
) && drvdata
->substream
[chan
]) {
435 rv
= lpass_dma_interrupt_handler(
436 drvdata
->substream
[chan
],
437 drvdata
, chan
, irqs
);
438 if (rv
!= IRQ_HANDLED
)
446 static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime
*soc_runtime
)
448 struct snd_pcm
*pcm
= soc_runtime
->pcm
;
449 struct snd_pcm_substream
*substream
=
450 pcm
->streams
[SNDRV_PCM_STREAM_PLAYBACK
].substream
;
451 struct snd_soc_dai
*cpu_dai
= soc_runtime
->cpu_dai
;
452 struct lpass_data
*drvdata
=
453 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
454 struct lpass_variant
*v
= drvdata
->variant
;
456 struct lpass_pcm_data
*data
;
457 size_t size
= lpass_platform_pcm_hardware
.buffer_bytes_max
;
459 data
= devm_kzalloc(soc_runtime
->dev
, sizeof(*data
), GFP_KERNEL
);
463 if (v
->alloc_dma_channel
)
464 data
->rdma_ch
= v
->alloc_dma_channel(drvdata
,
465 SNDRV_PCM_STREAM_PLAYBACK
);
467 if (IS_ERR_VALUE(data
->rdma_ch
))
468 return data
->rdma_ch
;
470 drvdata
->substream
[data
->rdma_ch
] = substream
;
471 data
->i2s_port
= cpu_dai
->driver
->id
;
473 snd_soc_pcm_set_drvdata(soc_runtime
, data
);
475 ret
= snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV
,
476 soc_runtime
->platform
->dev
,
477 size
, &substream
->dma_buffer
);
481 ret
= regmap_write(drvdata
->lpaif_map
,
482 LPAIF_RDMACTL_REG(v
, data
->rdma_ch
), 0);
484 dev_err(soc_runtime
->dev
, "%s() error writing to rdmactl reg: %d\n",
492 snd_dma_free_pages(&substream
->dma_buffer
);
496 static void lpass_platform_pcm_free(struct snd_pcm
*pcm
)
498 struct snd_pcm_substream
*substream
=
499 pcm
->streams
[SNDRV_PCM_STREAM_PLAYBACK
].substream
;
500 struct snd_soc_pcm_runtime
*soc_runtime
= substream
->private_data
;
501 struct lpass_data
*drvdata
=
502 snd_soc_platform_get_drvdata(soc_runtime
->platform
);
503 struct lpass_pcm_data
*data
= snd_soc_pcm_get_drvdata(soc_runtime
);
504 struct lpass_variant
*v
= drvdata
->variant
;
506 drvdata
->substream
[data
->rdma_ch
] = NULL
;
508 if (v
->free_dma_channel
)
509 v
->free_dma_channel(drvdata
, data
->rdma_ch
);
511 snd_dma_free_pages(&substream
->dma_buffer
);
514 static struct snd_soc_platform_driver lpass_platform_driver
= {
515 .pcm_new
= lpass_platform_pcm_new
,
516 .pcm_free
= lpass_platform_pcm_free
,
517 .ops
= &lpass_platform_pcm_ops
,
520 int asoc_qcom_lpass_platform_register(struct platform_device
*pdev
)
522 struct lpass_data
*drvdata
= platform_get_drvdata(pdev
);
523 struct lpass_variant
*v
= drvdata
->variant
;
526 drvdata
->lpaif_irq
= platform_get_irq_byname(pdev
, "lpass-irq-lpaif");
527 if (drvdata
->lpaif_irq
< 0) {
528 dev_err(&pdev
->dev
, "%s() error getting irq handle: %d\n",
529 __func__
, drvdata
->lpaif_irq
);
533 /* ensure audio hardware is disabled */
534 ret
= regmap_write(drvdata
->lpaif_map
,
535 LPAIF_IRQEN_REG(v
, LPAIF_IRQ_PORT_HOST
), 0);
537 dev_err(&pdev
->dev
, "%s() error writing to irqen reg: %d\n",
542 ret
= devm_request_irq(&pdev
->dev
, drvdata
->lpaif_irq
,
543 lpass_platform_lpaif_irq
, IRQF_TRIGGER_RISING
,
544 "lpass-irq-lpaif", drvdata
);
546 dev_err(&pdev
->dev
, "%s() irq request failed: %d\n",
552 return devm_snd_soc_register_platform(&pdev
->dev
,
553 &lpass_platform_driver
);
555 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register
);
557 MODULE_DESCRIPTION("QTi LPASS Platform Driver");
558 MODULE_LICENSE("GPL v2");