Lines Matching +full:lpass +full:- +full:irq +full:- +full:lpaif
1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
5 * lpass-platform.c -- ALSA SoC platform driver for QTi LPASS
8 #include <linux/dma-mapping.h>
16 #include "lpass-lpaif-reg.h"
17 #include "lpass.h"
19 #define DRV_NAME "lpass-platform"
57 struct lpass_variant *v = drvdata->variant; in lpass_platform_alloc_dmactl_fields()
61 drvdata->rd_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl), in lpass_platform_alloc_dmactl_fields()
63 if (drvdata->rd_dmactl == NULL) in lpass_platform_alloc_dmactl_fields()
64 return -ENOMEM; in lpass_platform_alloc_dmactl_fields()
66 drvdata->wr_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl), in lpass_platform_alloc_dmactl_fields()
68 if (drvdata->wr_dmactl == NULL) in lpass_platform_alloc_dmactl_fields()
69 return -ENOMEM; in lpass_platform_alloc_dmactl_fields()
71 rd_dmactl = drvdata->rd_dmactl; in lpass_platform_alloc_dmactl_fields()
72 wr_dmactl = drvdata->wr_dmactl; in lpass_platform_alloc_dmactl_fields()
74 rval = devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->intf, in lpass_platform_alloc_dmactl_fields()
75 &v->rdma_intf, 6); in lpass_platform_alloc_dmactl_fields()
79 return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf, in lpass_platform_alloc_dmactl_fields()
80 &v->wrdma_intf, 6); in lpass_platform_alloc_dmactl_fields()
87 struct lpass_variant *v = drvdata->variant; in lpass_platform_alloc_hdmidmactl_fields()
92 return -ENOMEM; in lpass_platform_alloc_hdmidmactl_fields()
94 drvdata->hdmi_rd_dmactl = rd_dmactl; in lpass_platform_alloc_hdmidmactl_fields()
96 return devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->bursten, in lpass_platform_alloc_hdmidmactl_fields()
97 &v->hdmi_rdma_bursten, 8); in lpass_platform_alloc_hdmidmactl_fields()
103 struct snd_pcm_runtime *runtime = substream->runtime; in lpass_platform_pcmops_open()
107 struct lpass_variant *v = drvdata->variant; in lpass_platform_pcmops_open()
108 int ret, dma_ch, dir = substream->stream; in lpass_platform_pcmops_open()
111 unsigned int dai_id = cpu_dai->driver->id; in lpass_platform_pcmops_open()
113 component->id = dai_id; in lpass_platform_pcmops_open()
116 return -ENOMEM; in lpass_platform_pcmops_open()
118 data->i2s_port = cpu_dai->driver->id; in lpass_platform_pcmops_open()
119 runtime->private_data = data; in lpass_platform_pcmops_open()
121 if (v->alloc_dma_channel) in lpass_platform_pcmops_open()
122 dma_ch = v->alloc_dma_channel(drvdata, dir, dai_id); in lpass_platform_pcmops_open()
131 if (cpu_dai->driver->id == LPASS_DP_RX) { in lpass_platform_pcmops_open()
132 map = drvdata->hdmiif_map; in lpass_platform_pcmops_open()
133 drvdata->hdmi_substream[dma_ch] = substream; in lpass_platform_pcmops_open()
135 map = drvdata->lpaif_map; in lpass_platform_pcmops_open()
136 drvdata->substream[dma_ch] = substream; in lpass_platform_pcmops_open()
138 data->dma_ch = dma_ch; in lpass_platform_pcmops_open()
140 LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0); in lpass_platform_pcmops_open()
142 dev_err(soc_runtime->dev, in lpass_platform_pcmops_open()
148 runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max; in lpass_platform_pcmops_open()
154 dev_err(soc_runtime->dev, "setting constraints failed: %d\n", in lpass_platform_pcmops_open()
156 return -EINVAL; in lpass_platform_pcmops_open()
159 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); in lpass_platform_pcmops_open()
167 struct snd_pcm_runtime *runtime = substream->runtime; in lpass_platform_pcmops_close()
171 struct lpass_variant *v = drvdata->variant; in lpass_platform_pcmops_close()
173 unsigned int dai_id = cpu_dai->driver->id; in lpass_platform_pcmops_close()
175 data = runtime->private_data; in lpass_platform_pcmops_close()
177 drvdata->hdmi_substream[data->dma_ch] = NULL; in lpass_platform_pcmops_close()
179 drvdata->substream[data->dma_ch] = NULL; in lpass_platform_pcmops_close()
180 if (v->free_dma_channel) in lpass_platform_pcmops_close()
181 v->free_dma_channel(drvdata, data->dma_ch, dai_id); in lpass_platform_pcmops_close()
194 struct snd_pcm_runtime *rt = substream->runtime; in lpass_platform_pcmops_hw_params()
195 struct lpass_pcm_data *pcm_data = rt->private_data; in lpass_platform_pcmops_hw_params()
196 struct lpass_variant *v = drvdata->variant; in lpass_platform_pcmops_hw_params()
201 int id, dir = substream->stream; in lpass_platform_pcmops_hw_params()
203 int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start; in lpass_platform_pcmops_hw_params()
204 unsigned int dai_id = cpu_dai->driver->id; in lpass_platform_pcmops_hw_params()
207 id = pcm_data->dma_ch; in lpass_platform_pcmops_hw_params()
209 dmactl = drvdata->hdmi_rd_dmactl; in lpass_platform_pcmops_hw_params()
211 dmactl = drvdata->rd_dmactl; in lpass_platform_pcmops_hw_params()
214 dmactl = drvdata->wr_dmactl; in lpass_platform_pcmops_hw_params()
215 id = pcm_data->dma_ch - v->wrdma_channel_start; in lpass_platform_pcmops_hw_params()
220 dev_err(soc_runtime->dev, "invalid bit width given: %d\n", in lpass_platform_pcmops_hw_params()
225 ret = regmap_fields_write(dmactl->bursten, id, LPAIF_DMACTL_BURSTEN_INCR4); in lpass_platform_pcmops_hw_params()
227 dev_err(soc_runtime->dev, "error updating bursten field: %d\n", ret); in lpass_platform_pcmops_hw_params()
231 ret = regmap_fields_write(dmactl->fifowm, id, LPAIF_DMACTL_FIFOWM_8); in lpass_platform_pcmops_hw_params()
233 dev_err(soc_runtime->dev, "error updating fifowm field: %d\n", ret); in lpass_platform_pcmops_hw_params()
239 ret = regmap_fields_write(dmactl->burst8, id, in lpass_platform_pcmops_hw_params()
242 dev_err(soc_runtime->dev, "error updating burst8en field: %d\n", ret); in lpass_platform_pcmops_hw_params()
245 ret = regmap_fields_write(dmactl->burst16, id, in lpass_platform_pcmops_hw_params()
248 dev_err(soc_runtime->dev, "error updating burst16en field: %d\n", ret); in lpass_platform_pcmops_hw_params()
251 ret = regmap_fields_write(dmactl->dynburst, id, in lpass_platform_pcmops_hw_params()
254 dev_err(soc_runtime->dev, "error updating dynbursten field: %d\n", ret); in lpass_platform_pcmops_hw_params()
260 ret = regmap_fields_write(dmactl->intf, id, in lpass_platform_pcmops_hw_params()
263 dev_err(soc_runtime->dev, "error updating audio interface field: %d\n", in lpass_platform_pcmops_hw_params()
270 dev_err(soc_runtime->dev, "%s: invalid interface: %d\n", __func__, dai_id); in lpass_platform_pcmops_hw_params()
290 dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n", in lpass_platform_pcmops_hw_params()
292 return -EINVAL; in lpass_platform_pcmops_hw_params()
322 dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n", in lpass_platform_pcmops_hw_params()
324 return -EINVAL; in lpass_platform_pcmops_hw_params()
328 dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n", in lpass_platform_pcmops_hw_params()
330 return -EINVAL; in lpass_platform_pcmops_hw_params()
333 ret = regmap_fields_write(dmactl->wpscnt, id, regval); in lpass_platform_pcmops_hw_params()
335 dev_err(soc_runtime->dev, "error writing to dmactl reg: %d\n", in lpass_platform_pcmops_hw_params()
349 struct snd_pcm_runtime *rt = substream->runtime; in lpass_platform_pcmops_hw_free()
350 struct lpass_pcm_data *pcm_data = rt->private_data; in lpass_platform_pcmops_hw_free()
351 struct lpass_variant *v = drvdata->variant; in lpass_platform_pcmops_hw_free()
355 unsigned int dai_id = cpu_dai->driver->id; in lpass_platform_pcmops_hw_free()
358 map = drvdata->hdmiif_map; in lpass_platform_pcmops_hw_free()
360 map = drvdata->lpaif_map; in lpass_platform_pcmops_hw_free()
362 reg = LPAIF_DMACTL_REG(v, pcm_data->dma_ch, substream->stream, dai_id); in lpass_platform_pcmops_hw_free()
365 dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n", in lpass_platform_pcmops_hw_free()
374 struct snd_pcm_runtime *runtime = substream->runtime; in lpass_platform_pcmops_prepare()
378 struct snd_pcm_runtime *rt = substream->runtime; in lpass_platform_pcmops_prepare()
379 struct lpass_pcm_data *pcm_data = rt->private_data; in lpass_platform_pcmops_prepare()
380 struct lpass_variant *v = drvdata->variant; in lpass_platform_pcmops_prepare()
383 int ret, id, ch, dir = substream->stream; in lpass_platform_pcmops_prepare()
384 unsigned int dai_id = cpu_dai->driver->id; in lpass_platform_pcmops_prepare()
387 ch = pcm_data->dma_ch; in lpass_platform_pcmops_prepare()
390 dmactl = drvdata->hdmi_rd_dmactl; in lpass_platform_pcmops_prepare()
391 map = drvdata->hdmiif_map; in lpass_platform_pcmops_prepare()
393 dmactl = drvdata->rd_dmactl; in lpass_platform_pcmops_prepare()
394 map = drvdata->lpaif_map; in lpass_platform_pcmops_prepare()
397 id = pcm_data->dma_ch; in lpass_platform_pcmops_prepare()
399 dmactl = drvdata->wr_dmactl; in lpass_platform_pcmops_prepare()
400 id = pcm_data->dma_ch - v->wrdma_channel_start; in lpass_platform_pcmops_prepare()
401 map = drvdata->lpaif_map; in lpass_platform_pcmops_prepare()
405 runtime->dma_addr); in lpass_platform_pcmops_prepare()
407 dev_err(soc_runtime->dev, "error writing to rdmabase reg: %d\n", in lpass_platform_pcmops_prepare()
413 (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1); in lpass_platform_pcmops_prepare()
415 dev_err(soc_runtime->dev, "error writing to rdmabuff reg: %d\n", in lpass_platform_pcmops_prepare()
421 (snd_pcm_lib_period_bytes(substream) >> 2) - 1); in lpass_platform_pcmops_prepare()
423 dev_err(soc_runtime->dev, "error writing to rdmaper reg: %d\n", in lpass_platform_pcmops_prepare()
428 ret = regmap_fields_write(dmactl->enable, id, LPAIF_DMACTL_ENABLE_ON); in lpass_platform_pcmops_prepare()
430 dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n", in lpass_platform_pcmops_prepare()
445 struct snd_pcm_runtime *rt = substream->runtime; in lpass_platform_pcmops_trigger()
446 struct lpass_pcm_data *pcm_data = rt->private_data; in lpass_platform_pcmops_trigger()
447 struct lpass_variant *v = drvdata->variant; in lpass_platform_pcmops_trigger()
451 int dir = substream->stream; in lpass_platform_pcmops_trigger()
454 unsigned int dai_id = cpu_dai->driver->id; in lpass_platform_pcmops_trigger()
457 ch = pcm_data->dma_ch; in lpass_platform_pcmops_trigger()
459 id = pcm_data->dma_ch; in lpass_platform_pcmops_trigger()
461 dmactl = drvdata->hdmi_rd_dmactl; in lpass_platform_pcmops_trigger()
462 map = drvdata->hdmiif_map; in lpass_platform_pcmops_trigger()
464 dmactl = drvdata->rd_dmactl; in lpass_platform_pcmops_trigger()
465 map = drvdata->lpaif_map; in lpass_platform_pcmops_trigger()
468 dmactl = drvdata->wr_dmactl; in lpass_platform_pcmops_trigger()
469 id = pcm_data->dma_ch - v->wrdma_channel_start; in lpass_platform_pcmops_trigger()
470 map = drvdata->lpaif_map; in lpass_platform_pcmops_trigger()
474 dev_err(soc_runtime->dev, "error reading from rdmactl reg: %d\n", ret); in lpass_platform_pcmops_trigger()
480 dev_err(soc_runtime->dev, "error in rdmactl register state\n"); in lpass_platform_pcmops_trigger()
481 return -ENOTRECOVERABLE; in lpass_platform_pcmops_trigger()
487 ret = regmap_fields_write(dmactl->enable, id, in lpass_platform_pcmops_trigger()
490 dev_err(soc_runtime->dev, in lpass_platform_pcmops_trigger()
496 ret = regmap_fields_write(dmactl->dyncclk, id, in lpass_platform_pcmops_trigger()
499 dev_err(soc_runtime->dev, in lpass_platform_pcmops_trigger()
503 map = drvdata->hdmiif_map; in lpass_platform_pcmops_trigger()
522 map = drvdata->lpaif_map; in lpass_platform_pcmops_trigger()
532 dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id); in lpass_platform_pcmops_trigger()
533 return -EINVAL; in lpass_platform_pcmops_trigger()
538 dev_err(soc_runtime->dev, "error writing to irqclear reg: %d\n", ret); in lpass_platform_pcmops_trigger()
543 dev_err(soc_runtime->dev, "error writing to irqen reg: %d\n", ret); in lpass_platform_pcmops_trigger()
550 ret = regmap_fields_write(dmactl->enable, id, in lpass_platform_pcmops_trigger()
553 dev_err(soc_runtime->dev, in lpass_platform_pcmops_trigger()
559 ret = regmap_fields_write(dmactl->dyncclk, id, in lpass_platform_pcmops_trigger()
562 dev_err(soc_runtime->dev, in lpass_platform_pcmops_trigger()
566 map = drvdata->hdmiif_map; in lpass_platform_pcmops_trigger()
576 map = drvdata->lpaif_map; in lpass_platform_pcmops_trigger()
582 dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id); in lpass_platform_pcmops_trigger()
583 return -EINVAL; in lpass_platform_pcmops_trigger()
588 dev_err(soc_runtime->dev, in lpass_platform_pcmops_trigger()
605 struct snd_pcm_runtime *rt = substream->runtime; in lpass_platform_pcmops_pointer()
606 struct lpass_pcm_data *pcm_data = rt->private_data; in lpass_platform_pcmops_pointer()
607 struct lpass_variant *v = drvdata->variant; in lpass_platform_pcmops_pointer()
609 int ret, ch, dir = substream->stream; in lpass_platform_pcmops_pointer()
611 unsigned int dai_id = cpu_dai->driver->id; in lpass_platform_pcmops_pointer()
614 map = drvdata->hdmiif_map; in lpass_platform_pcmops_pointer()
616 map = drvdata->lpaif_map; in lpass_platform_pcmops_pointer()
618 ch = pcm_data->dma_ch; in lpass_platform_pcmops_pointer()
623 dev_err(soc_runtime->dev, in lpass_platform_pcmops_pointer()
631 dev_err(soc_runtime->dev, in lpass_platform_pcmops_pointer()
636 return bytes_to_frames(substream->runtime, curr_addr - base_addr); in lpass_platform_pcmops_pointer()
643 struct snd_pcm_runtime *runtime = substream->runtime; in lpass_platform_pcmops_mmap()
645 return dma_mmap_coherent(component->dev, vma, runtime->dma_area, in lpass_platform_pcmops_mmap()
646 runtime->dma_addr, runtime->dma_bytes); in lpass_platform_pcmops_mmap()
656 struct lpass_variant *v = drvdata->variant; in lpass_dma_interrupt_handler()
661 unsigned int dai_id = cpu_dai->driver->id; in lpass_dma_interrupt_handler()
665 map = drvdata->hdmiif_map; in lpass_dma_interrupt_handler()
673 map = drvdata->lpaif_map; in lpass_dma_interrupt_handler()
678 dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id); in lpass_dma_interrupt_handler()
679 return -EINVAL; in lpass_dma_interrupt_handler()
685 dev_err(soc_runtime->dev, in lpass_dma_interrupt_handler()
696 dev_err(soc_runtime->dev, in lpass_dma_interrupt_handler()
700 dev_warn(soc_runtime->dev, "xrun warning\n"); in lpass_dma_interrupt_handler()
708 dev_err(soc_runtime->dev, in lpass_dma_interrupt_handler()
712 dev_err(soc_runtime->dev, "bus access error\n"); in lpass_dma_interrupt_handler()
720 dev_err(soc_runtime->dev, in lpass_dma_interrupt_handler()
730 static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data) in lpass_platform_lpaif_irq() argument
733 struct lpass_variant *v = drvdata->variant; in lpass_platform_lpaif_irq()
737 rv = regmap_read(drvdata->lpaif_map, in lpass_platform_lpaif_irq()
746 if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->substream[chan]) { in lpass_platform_lpaif_irq()
748 drvdata->substream[chan], in lpass_platform_lpaif_irq()
758 static irqreturn_t lpass_platform_hdmiif_irq(int irq, void *data) in lpass_platform_hdmiif_irq() argument
761 struct lpass_variant *v = drvdata->variant; in lpass_platform_hdmiif_irq()
765 rv = regmap_read(drvdata->hdmiif_map, in lpass_platform_hdmiif_irq()
777 && drvdata->hdmi_substream[chan]) { in lpass_platform_hdmiif_irq()
779 drvdata->hdmi_substream[chan], in lpass_platform_hdmiif_irq()
792 struct snd_pcm *pcm = soc_runtime->pcm; in lpass_platform_pcm_new()
794 int ret = -EINVAL; in lpass_platform_pcm_new()
797 psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; in lpass_platform_pcm_new()
800 component->dev, in lpass_platform_pcm_new()
801 size, &psubstream->dma_buffer); in lpass_platform_pcm_new()
803 dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n"); in lpass_platform_pcm_new()
808 csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; in lpass_platform_pcm_new()
811 component->dev, in lpass_platform_pcm_new()
812 size, &csubstream->dma_buffer); in lpass_platform_pcm_new()
814 dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n"); in lpass_platform_pcm_new()
816 snd_dma_free_pages(&psubstream->dma_buffer); in lpass_platform_pcm_new()
832 substream = pcm->streams[i].substream; in lpass_platform_pcm_free()
834 snd_dma_free_pages(&substream->dma_buffer); in lpass_platform_pcm_free()
835 substream->dma_buffer.area = NULL; in lpass_platform_pcm_free()
836 substream->dma_buffer.addr = 0; in lpass_platform_pcm_free()
859 struct lpass_variant *v = drvdata->variant; in asoc_qcom_lpass_platform_register()
862 drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif"); in asoc_qcom_lpass_platform_register()
863 if (drvdata->lpaif_irq < 0) in asoc_qcom_lpass_platform_register()
864 return -ENODEV; in asoc_qcom_lpass_platform_register()
867 ret = regmap_write(drvdata->lpaif_map, in asoc_qcom_lpass_platform_register()
870 dev_err(&pdev->dev, "error writing to irqen reg: %d\n", ret); in asoc_qcom_lpass_platform_register()
874 ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq, in asoc_qcom_lpass_platform_register()
876 "lpass-irq-lpaif", drvdata); in asoc_qcom_lpass_platform_register()
878 dev_err(&pdev->dev, "irq request failed: %d\n", ret); in asoc_qcom_lpass_platform_register()
882 ret = lpass_platform_alloc_dmactl_fields(&pdev->dev, in asoc_qcom_lpass_platform_register()
883 drvdata->lpaif_map); in asoc_qcom_lpass_platform_register()
885 dev_err(&pdev->dev, in asoc_qcom_lpass_platform_register()
890 if (drvdata->hdmi_port_enable) { in asoc_qcom_lpass_platform_register()
891 drvdata->hdmiif_irq = platform_get_irq_byname(pdev, "lpass-irq-hdmi"); in asoc_qcom_lpass_platform_register()
892 if (drvdata->hdmiif_irq < 0) in asoc_qcom_lpass_platform_register()
893 return -ENODEV; in asoc_qcom_lpass_platform_register()
895 ret = devm_request_irq(&pdev->dev, drvdata->hdmiif_irq, in asoc_qcom_lpass_platform_register()
896 lpass_platform_hdmiif_irq, 0, "lpass-irq-hdmi", drvdata); in asoc_qcom_lpass_platform_register()
898 dev_err(&pdev->dev, "irq hdmi request failed: %d\n", ret); in asoc_qcom_lpass_platform_register()
901 ret = regmap_write(drvdata->hdmiif_map, in asoc_qcom_lpass_platform_register()
904 dev_err(&pdev->dev, "error writing to hdmi irqen reg: %d\n", ret); in asoc_qcom_lpass_platform_register()
908 ret = lpass_platform_alloc_hdmidmactl_fields(&pdev->dev, in asoc_qcom_lpass_platform_register()
909 drvdata->hdmiif_map); in asoc_qcom_lpass_platform_register()
911 dev_err(&pdev->dev, in asoc_qcom_lpass_platform_register()
916 return devm_snd_soc_register_component(&pdev->dev, in asoc_qcom_lpass_platform_register()
921 MODULE_DESCRIPTION("QTi LPASS Platform Driver");