Add support for audio on SC7280 based targets
Subsystems (5)
cover Add support for audio on SC7280 based targets
This patch set is to add support for Audio over wcd codec, digital mics, through digital codecs and without ADSP. This patch set depends on:
-- https://patchwork.kernel.org/project/alsa-devel/list/?series=549577 -- https://patchwork.kernel.org/project/alsa-devel/list/?series=548765 -- https://patchwork.kernel.org/project/alsa-devel/list/?series=543829
Srinivasa Rao Mandadapu (8):
ASoC: qcom: Move lpass_pcm_data structure to lpass header
ASoC: qcom: lpass: Add dma fields for codec dma lpass interface
ASoC: qcom: Add register definition for codec rddma and wrdma
ASoC: qcom: Add lapss CPU driver for codec dma control
ASoC: qcom: Add support for codec dma driver
ASoC: dt-bindings: Add SC7280 sound card bindings
ASoC: qcom: lpass-sc7280: Add platform driver for lpass audio
ASoc: qcom: lpass: Add suspend and resume for sc7280 platform
.../devicetree/bindings/sound/qcom,lpass-cpu.yaml | 69 ++- sound/soc/qcom/lpass-cdc-dma.c | 263 +++++++++ sound/soc/qcom/lpass-cpu.c | 334 +++++++++++- sound/soc/qcom/lpass-lpaif-reg.h | 103 +++- sound/soc/qcom/lpass-platform.c | 504 +++++++++++++++-- sound/soc/qcom/lpass-sc7280.c | 602 +++++++++++++++++++++ sound/soc/qcom/lpass.h | 156 ++++++ 7 files changed, 1974 insertions(+), 57 deletions(-) create mode 100644 sound/soc/qcom/lpass-cdc-dma.c create mode 100644 sound/soc/qcom/lpass-sc7280.c
Signature · 2 lines
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc., is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
PATCH 1/8 ASoC: qcom: Move lpass_pcm_data structure to lpass header
Declare lpass_pcm_data structure in lpass header file instead of platform source file to make common use of it by other drivers
--- sound/soc/qcom/lpass-platform.c | 5 ----- sound/soc/qcom/lpass.h | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-)
sound/soc/qcom/lpass-platform.c +0 -5
@@ -18,11 +18,6 @@#define DRV_NAME "lpass-platform" -struct lpass_pcm_data { -int dma_ch; -int i2s_port; -}; -#define LPASS_PLATFORM_BUFFER_SIZE (24 * 2 * 1024)#define LPASS_PLATFORM_PERIODS 2
sound/soc/qcom/lpass.h +5 -0
@@ -256,6 +256,11 @@ struct lpass_variant {int num_clks; }; +struct lpass_pcm_data { +int dma_ch; +int i2s_port; +}; +/* register the platform driver from the CPU DAI driver */ int asoc_qcom_lpass_platform_register (struct platform_device *);int asoc_qcom_lpass_cpu_platform_remove (struct platform_device *pdev);
Signature · 2 lines
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc., is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
PATCH 2/8 ASoC: qcom: lpass: Add dma fields for codec dma lpass interface
In reply to Srinivasa Rao MandadapuAdd lpass interface memebers to support audio path over codec dma.
--- sound/soc/qcom/lpass.h | 148 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+)
sound/soc/qcom/lpass.h +148 -0
@@ -19,6 +19,28 @@#define LPASS_MAX_MI2S_PORTS (8)#define LPASS_MAX_DMA_CHANNELS (8)#define LPASS_MAX_HDMI_DMA_CHANNELS (4) +#define LPASS_MAX_CDC_DMA_CHANNELS (8) +#define LPASS_MAX_VA_CDC_DMA_CHANNELS (8) +#define LPASS_CDC_DMA_INTF_ONE_CHANNEL (0x01) +#define LPASS_CDC_DMA_INTF_TWO_CHANNEL (0x03) +#define LPASS_CDC_DMA_INTF_FOUR_CHANNEL (0x0F) +#define LPASS_CDC_DMA_INTF_SIX_CHANNEL (0x3F) +#define LPASS_CDC_DMA_INTF_EIGHT_CHANNEL (0xFF) +#define LPASS_CDC_DMA_RX0_INTERFACE (0x1) +#define LPASS_CDC_DMA_TX0_INTERFACE (0x1) +#define LPASS_CDC_DMA_TX1_INTERFACE (0x2) +#define LPASS_CDC_DMA_TX2_INTERFACE (0x3) +#define LPASS_CDC_DMA_TX3_INTERFACE (0x4) +#define LPASS_CDC_DMA_VA0_INTERFACE (0x1) + +#define LPASS_CDC_DMA_INTERFACE (dai_id) \ + ((dai_id == LPASS_CDC_DMA_TX3) ? \ + LPASS_CDC_DMA_TX3_INTERFACE : \ + LPASS_CDC_DMA_VA0_INTERFACE) + +#define LPASS_MAX_CDC_CLKS (9) +#define LPASS_ACTIVE_PDS (4) +#define LPASS_PROXY_PDS (8)#define QCOM_REGMAP_FIELD_ALLOC (d, m, f, mf) \ do { \
@@ -50,6 +72,12 @@ struct lpaif_dmactl {struct regmap_field *burst8;struct regmap_field *burst16;struct regmap_field *dynburst; +struct regmap_field *codec_enable; +struct regmap_field *codec_pack; +struct regmap_field *codec_intf; +struct regmap_field *codec_fs_sel; +struct regmap_field *codec_channel; +struct regmap_field *codec_fs_delay; };/* Both the CPU DAI and platform drivers will access this data */
@@ -64,6 +92,25 @@ struct lpass_data {/* MI2S bit clock (derived from system clock by a divider */ struct clk *mi2s_bit_clk[LPASS_MAX_MI2S_PORTS ]; +struct clk *cdc_dma_clks[LPASS_MAX_CDC_CLKS ]; + +struct clk *xo; +struct clk *gcc_cfg_noc_lpass; +struct clk *core_cc_core; +struct clk *aon_cc_audio_hm_h; +struct clk *core_cc_sysnoc_mport_core; +struct clk *audio_cc_ext_mclk0; +struct clk *audio_cc_ext_mclk1; +struct clk *core_cc_lpm_core; +struct clk *core_cc_lpm_mem0_core; +struct clk *audio_cc_codec_mem; +struct clk *audio_cc_codec_mem0; +struct clk *audio_cc_codec_mem1; +struct clk *audio_cc_codec_mem2; +struct clk *audio_cc_rx_mclk_2x; +struct clk *audio_cc_rx_mclk; +struct clk *aon_cc_va_mem0; +/* MI2S SD lines to use for playback/capture */ unsigned int mi2s_playback_sd_mode[LPASS_MAX_MI2S_PORTS ];unsigned int mi2s_capture_sd_mode[LPASS_MAX_MI2S_PORTS ];
@@ -72,38 +119,58 @@ struct lpass_data {bool mi2s_was_prepared[LPASS_MAX_MI2S_PORTS ];int hdmi_port_enable; +int wcd_codec_enable;/* low-power audio interface (LPAIF) registers */ void __iomem *lpaif;void __iomem *hdmiif; +void __iomem *rxtx_lpaif; +void __iomem *va_lpaif;/* regmap backed by the low-power audio interface (LPAIF) registers */ struct regmap *lpaif_map;struct regmap *hdmiif_map; +struct regmap *rxtx_lpaif_map; +struct regmap *va_lpaif_map;/* interrupts from the low-power audio interface (LPAIF) */ int lpaif_irq;int hdmiif_irq; +int rxtxif_irq; +int vaif_irq; +/* SOC specific variations in the LPASS IP integration */ struct lpass_variant *variant;/* bit map to keep track of static channel allocations */ unsigned long dma_ch_bit_map;unsigned long hdmi_dma_ch_bit_map; +unsigned long rxtx_dma_ch_bit_map; +unsigned long va_dma_ch_bit_map;/* used it for handling interrupt per dma channel */ struct snd_pcm_substream *substream[LPASS_MAX_DMA_CHANNELS ];struct snd_pcm_substream *hdmi_substream[LPASS_MAX_HDMI_DMA_CHANNELS ]; +struct snd_pcm_substream *rxtx_substream[LPASS_MAX_CDC_DMA_CHANNELS ]; +struct snd_pcm_substream *va_substream[LPASS_MAX_CDC_DMA_CHANNELS ];/* SOC specific clock list */ struct clk_bulk_data *clks;int num_clks; +struct clk_bulk_data *cdc_clks; +int cdc_num_clks;/* Regmap fields of I2SCTL & DMACTL registers bitfields */ struct lpaif_i2sctl *i2sctl;struct lpaif_dmactl *rd_dmactl;struct lpaif_dmactl *wr_dmactl;struct lpaif_dmactl *hdmi_rd_dmactl; + +/* Regmap fields of CODEC DMA CTRL registers*/ +struct lpaif_dmactl *rxtx_rd_dmactl; +struct lpaif_dmactl *rxtx_wr_dmactl; +struct lpaif_dmactl *va_wr_dmactl; +/* Regmap fields of HDMI_CTRL registers*/ struct regmap_field *hdmitx_legacy_en;struct regmap_field *hdmitx_parity_calc_en;
@@ -130,6 +197,24 @@ struct lpass_variant {u32 wrdma_reg_base;u32 wrdma_reg_stride;u32 wrdma_channels; +u32 rxtx_irq_reg_base; +u32 rxtx_irq_reg_stride; +u32 rxtx_irq_ports; +u32 rxtx_rdma_reg_base; +u32 rxtx_rdma_reg_stride; +u32 rxtx_rdma_channels; +u32 rxtx_wrdma_reg_base; +u32 rxtx_wrdma_reg_stride; +u32 rxtx_wrdma_channels; +u32 va_irq_reg_base; +u32 va_irq_reg_stride; +u32 va_irq_ports; +u32 va_rdma_reg_base; +u32 va_rdma_reg_stride; +u32 va_rdma_channels; +u32 va_wrdma_reg_base; +u32 va_wrdma_reg_stride; +u32 va_wrdma_channels;u32 i2sctrl_reg_base;u32 i2sctrl_reg_stride;u32 i2s_ports;
@@ -233,12 +318,66 @@ struct lpass_variant {struct reg_field wrdma_enable;struct reg_field wrdma_dyncclk; +/*CDC RXTX RD_DMA */ +struct reg_field rxtx_rdma_intf; +struct reg_field rxtx_rdma_bursten; +struct reg_field rxtx_rdma_wpscnt; +struct reg_field rxtx_rdma_fifowm; +struct reg_field rxtx_rdma_enable; +struct reg_field rxtx_rdma_dyncclk; +struct reg_field rxtx_rdma_burst8; +struct reg_field rxtx_rdma_burst16; +struct reg_field rxtx_rdma_dynburst; +struct reg_field rxtx_rdma_codec_enable; +struct reg_field rxtx_rdma_codec_pack; +struct reg_field rxtx_rdma_codec_intf; +struct reg_field rxtx_rdma_codec_fs_sel; +struct reg_field rxtx_rdma_codec_ch; +struct reg_field rxtx_rdma_codec_fs_delay; + +/*CDC RXTX WR_DMA */ +struct reg_field rxtx_wrdma_intf; +struct reg_field rxtx_wrdma_bursten; +struct reg_field rxtx_wrdma_wpscnt; +struct reg_field rxtx_wrdma_fifowm; +struct reg_field rxtx_wrdma_enable; +struct reg_field rxtx_wrdma_dyncclk; +struct reg_field rxtx_wrdma_burst8; +struct reg_field rxtx_wrdma_burst16; +struct reg_field rxtx_wrdma_dynburst; +struct reg_field rxtx_wrdma_codec_enable; +struct reg_field rxtx_wrdma_codec_pack; +struct reg_field rxtx_wrdma_codec_intf; +struct reg_field rxtx_wrdma_codec_fs_sel; +struct reg_field rxtx_wrdma_codec_ch; +struct reg_field rxtx_wrdma_codec_fs_delay; + +/*CDC VA WR_DMA */ +struct reg_field va_wrdma_intf; +struct reg_field va_wrdma_bursten; +struct reg_field va_wrdma_wpscnt; +struct reg_field va_wrdma_fifowm; +struct reg_field va_wrdma_enable; +struct reg_field va_wrdma_dyncclk; +struct reg_field va_wrdma_burst8; +struct reg_field va_wrdma_burst16; +struct reg_field va_wrdma_dynburst; +struct reg_field va_wrdma_codec_enable; +struct reg_field va_wrdma_codec_pack; +struct reg_field va_wrdma_codec_intf; +struct reg_field va_wrdma_codec_fs_sel; +struct reg_field va_wrdma_codec_ch; +struct reg_field va_wrdma_codec_fs_delay; +/** * on SOCs like APQ8016 the channel control bits start * at different offset to ipq806x **/ u32 dmactl_audif_start;u32 wrdma_channel_start; +u32 rxtx_wrdma_channel_start; +u32 va_wrdma_channel_start; +/* SOC specific initialization like clocks */ int (*init)(struct platform_device *pdev);int (*exit)(struct platform_device *pdev);
@@ -250,10 +389,19 @@ struct lpass_variant {int num_dai;const char *const *dai_osr_clk_names;const char *const *dai_bit_clk_names; +const char *const *cdc_dma_clk_names; + +const char *const *active_pd_names; +const char *const *proxy_pd_names; +struct device *active_pds[LPASS_ACTIVE_PDS ]; +struct device *proxy_pds[LPASS_ACTIVE_PDS ]; +int active_pd_count; +int proxy_pd_count;/* SOC specific clocks configuration */ const char **clk_name;int num_clks; +int cdc_dma_num_clks; };struct lpass_pcm_data {
Signature · 2 lines
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc., is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
PATCH 3/8 ASoC: qcom: Add register definition for codec rddma and wrdma
In reply to Srinivasa Rao MandadapuThis patch adds register definitions for codec read dma and write dma lpass interface.
--- sound/soc/qcom/lpass-lpaif-reg.h | 103 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 97 insertions(+), 6 deletions(-)
sound/soc/qcom/lpass-lpaif-reg.h +97 -6
@@ -74,6 +74,16 @@#define LPAIF_IRQSTAT_REG (v, port) LPAIF_IRQ_REG_ADDR(v, 0x4, (port))#define LPAIF_IRQCLEAR_REG (v, port) LPAIF_IRQ_REG_ADDR(v, 0xC, (port)) +/* LPAIF RXTX IRQ */ +#define LPAIF_RXTX_IRQ_REG_ADDR (v, addr, port, dai_id) \ + ((dai_id == LPASS_CDC_DMA_RX0 || dai_id == LPASS_CDC_DMA_TX3) ? \ + (v->rxtx_irq_reg_base + (addr) + v->rxtx_irq_reg_stride * (port)) : \ + (v->va_irq_reg_base + (addr) + v->va_irq_reg_stride * (port))) + +#define LPAIF_RXTX_IRQEN_REG (v, port, dai_id) LPAIF_RXTX_IRQ_REG_ADDR(v, 0x0, port, dai_id) +#define LPAIF_RXTX_IRQSTAT_REG (v, port, dai_id) LPAIF_RXTX_IRQ_REG_ADDR(v, 0x4, port, dai_id) +#define LPAIF_RXTX_IRQCLEAR_REG (v, port, dai_id) LPAIF_RXTX_IRQ_REG_ADDR(v, 0xC, port, dai_id) +#define LPASS_HDMITX_APP_IRQ_REG_ADDR (v, addr) \ ((v->hdmi_irq_reg_base) + (addr))
@@ -139,12 +149,93 @@ (LPAIF_INTFDMA_REG(v, chan, reg, dai_id)) : \ LPAIF_WRDMA##reg##_REG(v, chan)) -#define LPAIF_DMACTL_REG (v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, CTL, dai_id) -#define LPAIF_DMABASE_REG (v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, BASE, dai_id) -#define LPAIF_DMABUFF_REG (v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, BUFF, dai_id) -#define LPAIF_DMACURR_REG (v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, CURR, dai_id) -#define LPAIF_DMAPER_REG (v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, PER, dai_id) -#define LPAIF_DMAPERCNT_REG (v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, PERCNT, dai_id) +#define LPAIF_DMACTL_REG (v, chan, dir, dai_id) \ + (((dai_id == LPASS_CDC_DMA_RX0) || \ + (dai_id == LPASS_CDC_DMA_TX3) || \ + (dai_id == LPASS_CDC_DMA_VA_TX0)) ? \ + __LPAIF_CDC_DMA_REG(v, chan, dir, CTL, dai_id) : \ + __LPAIF_DMA_REG(v, chan, dir, CTL, dai_id)) +#define LPAIF_DMABASE_REG (v, chan, dir, dai_id) \ + ((dai_id == LPASS_CDC_DMA_RX0 || \ + dai_id == LPASS_CDC_DMA_TX3 || \ + dai_id == LPASS_CDC_DMA_VA_TX0) ? \ + __LPAIF_CDC_DMA_REG(v, chan, dir, BASE, dai_id) : \ + __LPAIF_DMA_REG(v, chan, dir, BASE, dai_id)) +#define LPAIF_DMABUFF_REG (v, chan, dir, dai_id) \ + ((dai_id == LPASS_CDC_DMA_RX0 || \ + dai_id == LPASS_CDC_DMA_TX3 || \ + dai_id == LPASS_CDC_DMA_VA_TX0) ? \ + __LPAIF_CDC_DMA_REG(v, chan, dir, BUFF, dai_id) : \ + __LPAIF_DMA_REG(v, chan, dir, BUFF, dai_id)) +#define LPAIF_DMACURR_REG (v, chan, dir, dai_id) \ + ((dai_id == LPASS_CDC_DMA_RX0 || \ + dai_id == LPASS_CDC_DMA_TX3 || \ + dai_id == LPASS_CDC_DMA_VA_TX0) ? \ + __LPAIF_CDC_DMA_REG(v, chan, dir, CURR, dai_id) : \ + __LPAIF_DMA_REG(v, chan, dir, CURR, dai_id)) +#define LPAIF_DMAPER_REG (v, chan, dir, dai_id) \ + ((dai_id == LPASS_CDC_DMA_RX0 || \ + dai_id == LPASS_CDC_DMA_TX3 || \ + dai_id == LPASS_CDC_DMA_VA_TX0) ? \ + __LPAIF_CDC_DMA_REG(v, chan, dir, PER, dai_id) : \ + __LPAIF_DMA_REG(v, chan, dir, PER, dai_id)) +#define LPAIF_DMAPERCNT_REG (v, chan, dir, dai_id) \ + ((dai_id == LPASS_CDC_DMA_RX0 || \ + dai_id == LPASS_CDC_DMA_TX3 || \ + dai_id == LPASS_CDC_DMA_VA_TX0) ? \ + __LPAIF_CDC_DMA_REG(v, chan, dir, PERCNT, dai_id) : \ + __LPAIF_DMA_REG(v, chan, dir, PERCNT, dai_id)) + +#define LPAIF_CDC_RDMA_REG_ADDR (v, addr, chan, dai_id) \ + ((dai_id == LPASS_CDC_DMA_RX0 || dai_id == LPASS_CDC_DMA_TX3) ? \ + (v->rxtx_rdma_reg_base + (addr) + v->rxtx_rdma_reg_stride * (chan)) : \ + (v->va_rdma_reg_base + (addr) + v->va_rdma_reg_stride * (chan))) + +#define LPAIF_CDC_RDMACTL_REG (v, chan, dai_id) LPAIF_CDC_RDMA_REG_ADDR(v, 0x00, (chan), dai_id) +#define LPAIF_CDC_RDMABASE_REG (v, chan, dai_id) LPAIF_CDC_RDMA_REG_ADDR(v, 0x04, (chan), dai_id) +#define LPAIF_CDC_RDMABUFF_REG (v, chan, dai_id) LPAIF_CDC_RDMA_REG_ADDR(v, 0x08, (chan), dai_id) +#define LPAIF_CDC_RDMACURR_REG (v, chan, dai_id) LPAIF_CDC_RDMA_REG_ADDR(v, 0x0C, (chan), dai_id) +#define LPAIF_CDC_RDMAPER_REG (v, chan, dai_id) LPAIF_CDC_RDMA_REG_ADDR(v, 0x10, (chan), dai_id) + +#define LPAIF_CDC_RDMA_INTF_REG (v, chan, dai_id) \ + LPAIF_CDC_RDMA_REG_ADDR(v, 0x50, (chan), dai_id) + +#define LPAIF_CDC_WRDMA_REG_ADDR (v, addr, chan, dai_id) \ + ((dai_id == LPASS_CDC_DMA_RX0 || dai_id == LPASS_CDC_DMA_TX3) ? \ + (v->rxtx_wrdma_reg_base + (addr) + \ + v->rxtx_wrdma_reg_stride * (chan - v->rxtx_wrdma_channel_start)) : \ + (v->va_wrdma_reg_base + (addr) + \ + v->va_wrdma_reg_stride * (chan - v->va_wrdma_channel_start))) + +#define LPAIF_CDC_WRDMACTL_REG (v, chan, dai_id) \ + LPAIF_CDC_WRDMA_REG_ADDR(v, 0x00, (chan), dai_id) +#define LPAIF_CDC_WRDMABASE_REG (v, chan, dai_id) \ + LPAIF_CDC_WRDMA_REG_ADDR(v, 0x04, (chan), dai_id) +#define LPAIF_CDC_WRDMABUFF_REG (v, chan, dai_id) \ + LPAIF_CDC_WRDMA_REG_ADDR(v, 0x08, (chan), dai_id) +#define LPAIF_CDC_WRDMACURR_REG (v, chan, dai_id) \ + LPAIF_CDC_WRDMA_REG_ADDR(v, 0x0C, (chan), dai_id) +#define LPAIF_CDC_WRDMAPER_REG (v, chan, dai_id) \ + LPAIF_CDC_WRDMA_REG_ADDR(v, 0x10, (chan), dai_id) +#define LPAIF_CDC_WRDMA_INTF_REG (v, chan, dai_id) \ + LPAIF_CDC_WRDMA_REG_ADDR(v, 0x50, (chan), dai_id) + +#define __LPAIF_CDC_DMA_REG (v, chan, dir, reg, dai_id) \ + ((dir == SNDRV_PCM_STREAM_PLAYBACK) ? \ + (LPAIF_CDC_RDMA##reg##_REG(v, chan, dai_id)) : \ + LPAIF_CDC_WRDMA##reg##_REG(v, chan, dai_id)) + +#define LPAIF_CDC_INTF_REG (v, chan, dir, dai_id) \ + ((dir == SNDRV_PCM_STREAM_PLAYBACK) ? \ + LPAIF_CDC_RDMA_INTF_REG(v, chan, dai_id) : \ + LPAIF_CDC_WRDMA_INTF_REG(v, chan, dai_id)) + +#define LPAIF_INTF_REG (v, chan, dir, dai_id) \ + ((dai_id == LPASS_CDC_DMA_RX0 || \ + dai_id == LPASS_CDC_DMA_TX3 || \ + dai_id == LPASS_CDC_DMA_VA_TX0) ? \ + LPAIF_CDC_INTF_REG(v, chan, dir, dai_id) : \ + LPAIF_DMACTL_REG(v, chan, dir, dai_id))#define LPAIF_DMACTL_BURSTEN_SINGLE 0#define LPAIF_DMACTL_BURSTEN_INCR4 1
Signature · 2 lines
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc., is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
PATCH 4/8 ASoC: qcom: Add lapss CPU driver for codec dma control
In reply to Srinivasa Rao MandadapuAdd lpass cpu driver to support audio over codec dma for ADSP bypass usecase.
--- sound/soc/qcom/lpass-cdc-dma.c | 263 +++++++++++++++++++++++++++++++++++++++++ sound/soc/qcom/lpass.h | 1 + 2 files changed, 264 insertions(+) create mode 100644 sound/soc/qcom/lpass-cdc-dma.c
sound/soc/qcom/lpass-cdc-dma.c new file +263 -0
@@ -0,0 +1,263 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* +* Copyright (c) 2021 The Linux Foundation. All rights reserved. +* +* lpass-cdc-dma.c -- ALSA SoC WCD -CPU DAI driver for QTi LPASS WCD +*/ + +#include <linux/module.h> +#include <sound/soc.h> +#include <sound/soc-dai.h> + +#include "lpass-lpaif-reg.h" +#include "lpass.h" + +static int __lpass_platform_codec_intf_init (struct snd_soc_dai *dai, +struct snd_pcm_substream *substream) +{ +struct snd_soc_pcm_runtime *soc_runtime =asoc_substream_to_rtd (substream); +struct snd_soc_dai *cpu_dai =asoc_rtd_to_cpu (soc_runtime,0 ); +struct lpass_data *drvdata =snd_soc_dai_get_drvdata (dai); +struct snd_pcm_runtime *rt = substream->runtime; +struct lpass_pcm_data *pcm_data = rt->private_data; +struct lpass_variant *v = drvdata->variant; +struct lpaif_dmactl *dmactl; +struct regmap *map; +int dir = substream->stream; +int ret, id; +unsigned int dai_id = cpu_dai->driver->id; + +if (dir ==SNDRV_PCM_STREAM_PLAYBACK ) { + dmactl = drvdata->rxtx_rd_dmactl; + map = drvdata->rxtx_lpaif_map; + id = pcm_data->dma_ch; + }else { +if (dai_id ==LPASS_CDC_DMA_TX3 ) { + dmactl = drvdata->rxtx_wr_dmactl; + map = drvdata->rxtx_lpaif_map; + id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start; + }else if (dai_id ==LPASS_CDC_DMA_VA_TX0 ) { + dmactl = drvdata->va_wr_dmactl; + map = drvdata->va_lpaif_map; + id = pcm_data->dma_ch - v->va_wrdma_channel_start; + } + } + +if (dir ==SNDRV_PCM_STREAM_PLAYBACK ) { + ret =regmap_fields_write (dmactl->codec_intf, id,LPASS_CDC_DMA_RX0_INTERFACE ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl reg: %d\n" , ret); +return ret; + } + ret =regmap_fields_write (dmactl->codec_fs_sel, id,0x0 ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl reg: %d\n" , ret); +return ret; + } + ret =regmap_fields_write (dmactl->codec_fs_delay, id,0x0 ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl codec_fs_delay reg field: %d\n" , ret); +return ret; + } + ret =regmap_fields_write (dmactl->codec_pack, id,0x1 ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl codec_pack reg field: %d\n" , ret); +return ret; + } + ret =regmap_fields_write (dmactl->codec_enable, id,LPAIF_DMACTL_ENABLE_ON ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl reg: %d\n" , ret); +return ret; + } + + }else { + ret =regmap_fields_write (dmactl->codec_intf, id,LPASS_CDC_DMA_INTERFACE (dai_id)); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to wrdmactl codec_intf reg field: %d\n" , ret); +return ret; + } + ret =regmap_fields_write (dmactl->codec_fs_sel, id,0x0 ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to wrdmactl codec_fs_sel reg field: %d\n" , ret); +return ret; + } + ret =regmap_fields_write (dmactl->codec_fs_delay, id,0x0 ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to wrdmactl codec_fs_delay reg field: %d\n" , ret); +return ret; + } + ret =regmap_fields_write (dmactl->codec_pack, id,0x1 ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to wrdmactl codec_pack reg field: %d\n" , ret); +return ret; + } + ret =regmap_fields_write (dmactl->codec_enable, id,LPAIF_DMACTL_ENABLE_ON ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to wrdmactl codec_enable reg field: %d\n" , ret); +return ret; + } + } +return 0 ; +} + +static int lpass_wcd_daiops_startup (struct snd_pcm_substream *substream, +struct snd_soc_dai *dai) +{ +struct lpass_data *drvdata =snd_soc_dai_get_drvdata (dai); +int ret, i; + +for (i =0 ; i < drvdata->cdc_num_clks; i++) { + ret =clk_prepare_enable (drvdata->cdc_dma_clks[i]); +if (ret) { +dev_err (dai->dev,"error in enabling cdc dma clks: %d\n" , ret); +return ret; + } + } + +return 0 ; +} + +static void lpass_wcd_daiops_shutdown (struct snd_pcm_substream *substream, +struct snd_soc_dai *dai) +{ +int i; +struct lpass_data *drvdata =snd_soc_dai_get_drvdata (dai); + +for (i =0 ; i < drvdata->cdc_num_clks; i++) +clk_disable_unprepare (drvdata->cdc_dma_clks[i]); +} + +static int lpass_wcd_daiops_hw_params (struct snd_pcm_substream *substream, +struct snd_pcm_hw_params *params,struct snd_soc_dai *dai) +{ +struct snd_soc_pcm_runtime *soc_runtime =asoc_substream_to_rtd (substream); +struct snd_soc_dai *cpu_dai =asoc_rtd_to_cpu (soc_runtime,0 ); +struct lpaif_dmactl *dmactl; +struct lpass_data *drvdata =snd_soc_dai_get_drvdata (dai); +struct snd_pcm_runtime *rt = substream->runtime; +struct lpass_pcm_data *pcm_data = rt->private_data; +struct lpass_variant *v = drvdata->variant; +struct regmap *map; +int dir = substream->stream; +unsigned int ret, regval; +unsigned int channels =params_channels (params); +int id; +unsigned int dai_id = cpu_dai->driver->id; + +if (dir ==SNDRV_PCM_STREAM_PLAYBACK ) { + dmactl = drvdata->rxtx_rd_dmactl; + map = drvdata->rxtx_lpaif_map; + id = pcm_data->dma_ch; + }else { +if (dai_id ==LPASS_CDC_DMA_TX3 ) { + dmactl = drvdata->rxtx_wr_dmactl; + map = drvdata->rxtx_lpaif_map; + id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start; + }else if (dai_id ==LPASS_CDC_DMA_VA_TX0 ) { + dmactl = drvdata->va_wr_dmactl; + map = drvdata->va_lpaif_map; + id = pcm_data->dma_ch - v->va_wrdma_channel_start; + } + } + +switch (channels) { +case 1 : + regval =LPASS_CDC_DMA_INTF_ONE_CHANNEL ; +break ; +case 2 : + regval =LPASS_CDC_DMA_INTF_TWO_CHANNEL ; +break ; +case 4 : + regval =LPASS_CDC_DMA_INTF_FOUR_CHANNEL ; +break ; +case 6 : + regval =LPASS_CDC_DMA_INTF_SIX_CHANNEL ; +break ; +case 8 : + regval =LPASS_CDC_DMA_INTF_EIGHT_CHANNEL ; +break ; +default : +dev_err (soc_runtime->dev,"invalid PCM config\n" ); +return -EINVAL ; + } + + ret =regmap_fields_write (dmactl->codec_channel, id, regval); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl codec_channel reg field: %d\n" , ret); +return ret; + } +return ret; +} + +static int lpass_wcd_daiops_trigger (struct snd_pcm_substream *substream, +int cmd,struct snd_soc_dai *dai) +{ +struct snd_soc_pcm_runtime *soc_runtime =asoc_substream_to_rtd (substream); +struct snd_soc_dai *cpu_dai =asoc_rtd_to_cpu (soc_runtime,0 ); +struct lpass_data *drvdata =snd_soc_dai_get_drvdata (dai); +struct snd_pcm_runtime *rt = substream->runtime; +struct lpass_pcm_data *pcm_data = rt->private_data; +struct lpass_variant *v = drvdata->variant; +int dir = substream->stream; +struct lpaif_dmactl *dmactl; +struct regmap *map; +unsigned int dai_id = cpu_dai->driver->id; +int ret =0 , id; + +if (dir ==SNDRV_PCM_STREAM_PLAYBACK ) { + dmactl = drvdata->rxtx_rd_dmactl; + map = drvdata->rxtx_lpaif_map; + id = pcm_data->dma_ch; + }else { +if (dai_id ==LPASS_CDC_DMA_TX3 ) { + dmactl = drvdata->rxtx_wr_dmactl; + map = drvdata->rxtx_lpaif_map; + id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start; + }else if (dai_id ==LPASS_CDC_DMA_VA_TX0 ) { + dmactl = drvdata->va_wr_dmactl; + map = drvdata->va_lpaif_map; + id = pcm_data->dma_ch - v->va_wrdma_channel_start; + } + } +switch (cmd) { +case SNDRV_PCM_TRIGGER_START : +case SNDRV_PCM_TRIGGER_RESUME : +case SNDRV_PCM_TRIGGER_PAUSE_RELEASE : +__lpass_platform_codec_intf_init (dai, substream); +break ; +case SNDRV_PCM_TRIGGER_STOP : +case SNDRV_PCM_TRIGGER_SUSPEND : +case SNDRV_PCM_TRIGGER_PAUSE_PUSH : + ret =regmap_fields_write (dmactl->codec_enable, id,LPAIF_DMACTL_ENABLE_OFF ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl reg: %d\n" , ret); +return ret; + } + +break ; + } +return ret; +} + +const struct snd_soc_dai_ops asoc_qcom_lpass_wcd_dai_ops = { + .startup = lpass_wcd_daiops_startup, + .shutdown = lpass_wcd_daiops_shutdown, + .hw_params = lpass_wcd_daiops_hw_params, + .trigger = lpass_wcd_daiops_trigger, +}; +EXPORT_SYMBOL_GPL (asoc_qcom_lpass_wcd_dai_ops); + +MODULE_DESCRIPTION ("QTi LPASS CDC DMA Driver" ); +MODULE_LICENSE ("GPL v2" );
sound/soc/qcom/lpass.h +1 -0
@@ -418,5 +418,6 @@ int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai);extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops;int lpass_cpu_pcm_new (struct snd_soc_pcm_runtime *rtd,struct snd_soc_dai *dai); +extern const struct snd_soc_dai_ops asoc_qcom_lpass_wcd_dai_ops;#endif /* __LPASS_H__ */
Signature · 2 lines
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc., is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
Re: [PATCH 4/8] ASoC: qcom: Add lapss CPU driver for codec dma control
Quoted 1 line · Srinivasa Rao Mandadapu
Subject: ASoC: qcom: Add lapss CPU driver for codec dma control
nit: s/lapss/lpass/
Quoted 38 lines
Add lpass cpu driver to support audio over codec dma for ADSP bypass usecase.
Signed-off-by Venkata Prasad Potturu <[email protected]>Signed-off-by Srinivasa Rao Mandadapu <[email protected]>--- sound/soc/qcom/lpass-cdc-dma.c | 263 +++++++++++++++++++++++++++++++++++++++++ sound/soc/qcom/lpass.h | 1 + 2 files changed, 264 insertions(+) create mode 100644 sound/soc/qcom/lpass-cdc-dma.csound/soc/qcom/lpass-cdc-dma.c new file +20
-0@@ -0,0 +1,263 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* +* Copyright (c) 2021 The Linux Foundation. All rights reserved. +* +* lpass-cdc-dma.c -- ALSA SoC WCD -CPU DAI driver for QTi LPASS WCD +*/ + +#include <linux/module.h> +#include <sound/soc.h> +#include <sound/soc-dai.h> + +#include "lpass-lpaif-reg.h" +#include "lpass.h" + +static int __lpass_platform_codec_intf_init (struct snd_soc_dai *dai, +struct snd_pcm_substream *substream) +{ +struct snd_soc_pcm_runtime *soc_runtime =asoc_substream_to_rtd (substream); +struct snd_soc_dai *cpu_dai =asoc_rtd_to_cpu (soc_runtime,0 ); +struct lpass_data *drvdata =snd_soc_dai_get_drvdata (dai);
sound/soc/qcom/lpass-cdc-dma.c line 30
Quoted 10 lines
sound/soc/qcom/lpass-cdc-dma.c new file +10
-0+struct snd_pcm_runtime *rt = substream->runtime; +struct lpass_pcm_data *pcm_data = rt->private_data; +struct lpass_variant *v = drvdata->variant; +struct lpaif_dmactl *dmactl; +struct regmap *map; +int dir = substream->stream; +int ret, id; +unsigned int dai_id = cpu_dai->driver->id; + +if (dir ==SNDRV_PCM_STREAM_PLAYBACK ) {
s/ == / == /
Quoted 4 lines
sound/soc/qcom/lpass-cdc-dma.c new file +4
-0+ dmactl = drvdata->rxtx_rd_dmactl; + map = drvdata->rxtx_lpaif_map; + id = pcm_data->dma_ch; + }else {
sound/soc/qcom/lpass-cdc-dma.c line 44
Quoted 10 lines
sound/soc/qcom/lpass-cdc-dma.c new file +10
-0+if (dai_id ==LPASS_CDC_DMA_TX3 ) { + dmactl = drvdata->rxtx_wr_dmactl; + map = drvdata->rxtx_lpaif_map; + id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start; + }else if (dai_id ==LPASS_CDC_DMA_VA_TX0 ) { + dmactl = drvdata->va_wr_dmactl; + map = drvdata->va_lpaif_map; + id = pcm_data->dma_ch - v->va_wrdma_channel_start; + } + }
'map' is assigned here, but not used in the rest of the function, drop it.
sound/soc/qcom/lpass-cdc-dma.c line 46
Quoted 2 lines
sound/soc/qcom/lpass-cdc-dma.c new file +2
-0+ +if (dir ==SNDRV_PCM_STREAM_PLAYBACK ) {
s/ == / == /
sound/soc/qcom/lpass-cdc-dma.c line 50
Quoted 4 lines
sound/soc/qcom/lpass-cdc-dma.c new file +4
-0+ ret =regmap_fields_write (dmactl->codec_intf, id,LPASS_CDC_DMA_RX0_INTERFACE ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl reg: %d\n" , ret);
Some of the logs print the register name, others don't, why not log it always?
sound/soc/qcom/lpass-cdc-dma.c line 53
Quoted 3 lines
sound/soc/qcom/lpass-cdc-dma.c new file +3
-0+return ret; + } + ret =regmap_fields_write (dmactl->codec_fs_sel, id,0x0 );
fix indentation
Quoted 14 lines
sound/soc/qcom/lpass-cdc-dma.c new file +14
-0+if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl reg: %d\n" , ret); +return ret; + } + ret =regmap_fields_write (dmactl->codec_fs_delay, id,0x0 ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl codec_fs_delay reg field: %d\n" , ret); +return ret; + } + ret =regmap_fields_write (dmactl->codec_pack, id,0x1 ); +if (ret) { + dev_err(soc_runtime->dev,
sound/soc/qcom/lpass-cdc-dma.c line 77
Quoted 10 lines
sound/soc/qcom/lpass-cdc-dma.c new file +10
-0+ "error writing to rdmactl codec_pack reg field: %d\n", ret); +return ret; + } + ret =regmap_fields_write (dmactl->codec_enable, id,LPAIF_DMACTL_ENABLE_ON ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl reg: %d\n" , ret); +return ret; + } +
Remove empty line
sound/soc/qcom/lpass-cdc-dma.c line 85
Quoted 8 lines
sound/soc/qcom/lpass-cdc-dma.c new file +8
-0+ }else { + ret =regmap_fields_write (dmactl->codec_intf, id,LPASS_CDC_DMA_INTERFACE (dai_id)); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to wrdmactl codec_intf reg field: %d\n" , ret); +return ret; + } + ret =regmap_fields_write (dmactl->codec_fs_sel, id,0x0 );
fix indentation
Quoted 13 lines
sound/soc/qcom/lpass-cdc-dma.c new file +13
-0+if (ret) { +dev_err (soc_runtime->dev, +"error writing to wrdmactl codec_fs_sel reg field: %d\n" , ret); +return ret; + } + ret =regmap_fields_write (dmactl->codec_fs_delay, id,0x0 ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to wrdmactl codec_fs_delay reg field: %d\n" , ret); +return ret; + } + ret =regmap_fields_write (dmactl->codec_pack, id,0x1 ); +if (ret) {
sound/soc/qcom/lpass-cdc-dma.c line 108
Quoted 10 lines
sound/soc/qcom/lpass-cdc-dma.c new file +10
-0+dev_err (soc_runtime->dev, +"error writing to wrdmactl codec_pack reg field: %d\n" , ret); +return ret; + } + ret =regmap_fields_write (dmactl->codec_enable, id,LPAIF_DMACTL_ENABLE_ON ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to wrdmactl codec_enable reg field: %d\n" , ret); +return ret; + }
The last four register writes are exactly the same in both branches, only the logging distinguishes between 'rdmactl' and 'wrdmactl'. Those should be in the main branch, if you really need to distinguish between 'rdmactl' and 'wrdmactl' in the logging you can assign a string pointer in the 'if (dir == SNDRV_PCM_STREAM_PLAYBACK)' branches.
Quoted 5 lines
sound/soc/qcom/lpass-cdc-dma.c new file +5
-0+ } +return 0 ; +} + +static int lpass_wcd_daiops_startup(struct snd_pcm_substream *substream,
sound/soc/qcom/lpass-cdc-dma.c line 123
Quoted 10 lines
sound/soc/qcom/lpass-cdc-dma.c new file +10
-0+ struct snd_soc_dai *dai) +{ +struct lpass_data *drvdata =snd_soc_dai_get_drvdata (dai); +int ret, i; + +for (i =0 ; i < drvdata->cdc_num_clks; i++) { + ret =clk_prepare_enable (drvdata->cdc_dma_clks[i]); +if (ret) { +dev_err (dai->dev,"error in enabling cdc dma clks: %d\n" , ret); +return ret;
Disable clocks that have been enabled previously?
Quoted 38 lines
sound/soc/qcom/lpass-cdc-dma.c new file +38
-0+ } + } + +return 0 ; +} + +static void lpass_wcd_daiops_shutdown (struct snd_pcm_substream *substream, +struct snd_soc_dai *dai) +{ +int i; +struct lpass_data *drvdata =snd_soc_dai_get_drvdata (dai); + +for (i =0 ; i < drvdata->cdc_num_clks; i++) +clk_disable_unprepare (drvdata->cdc_dma_clks[i]); +} + +static int lpass_wcd_daiops_hw_params (struct snd_pcm_substream *substream, +struct snd_pcm_hw_params *params,struct snd_soc_dai *dai) +{ +struct snd_soc_pcm_runtime *soc_runtime =asoc_substream_to_rtd (substream); +struct snd_soc_dai *cpu_dai =asoc_rtd_to_cpu (soc_runtime,0 ); +struct lpaif_dmactl *dmactl; +struct lpass_data *drvdata =snd_soc_dai_get_drvdata (dai); +struct snd_pcm_runtime *rt = substream->runtime; +struct lpass_pcm_data *pcm_data = rt->private_data; +struct lpass_variant *v = drvdata->variant; +struct regmap *map; +int dir = substream->stream; +unsigned int ret, regval; +unsigned int channels =params_channels (params); +int id; +unsigned int dai_id = cpu_dai->driver->id; + +if (dir ==SNDRV_PCM_STREAM_PLAYBACK ) { + dmactl = drvdata->rxtx_rd_dmactl; + map = drvdata->rxtx_lpaif_map; + id = pcm_data->dma_ch; + }else {
sound/soc/qcom/lpass-cdc-dma.c line 171
Quoted 10 lines
sound/soc/qcom/lpass-cdc-dma.c new file +10
-0+if (dai_id ==LPASS_CDC_DMA_TX3 ) { + dmactl = drvdata->rxtx_wr_dmactl; + map = drvdata->rxtx_lpaif_map; + id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start; + }else if (dai_id ==LPASS_CDC_DMA_VA_TX0 ) { + dmactl = drvdata->va_wr_dmactl; + map = drvdata->va_lpaif_map; + id = pcm_data->dma_ch - v->va_wrdma_channel_start; + } + }
The exact same code block is used 3 times in this driver. Add a helper with 'substream' and 'dai' as parameters, which determines 'dmactl and 'id'. That would also make the variable declaration/assignment section of these functions signifcantly shorter.
Quoted 16 lines
sound/soc/qcom/lpass-cdc-dma.c new file +16
-0+ +switch (channels) { +case 1 : + regval =LPASS_CDC_DMA_INTF_ONE_CHANNEL ; +break ; +case 2 : + regval =LPASS_CDC_DMA_INTF_TWO_CHANNEL ; +break ; +case 4 : + regval =LPASS_CDC_DMA_INTF_FOUR_CHANNEL ; +break ; +case 6 : + regval =LPASS_CDC_DMA_INTF_SIX_CHANNEL ; +break ; +case 8 : + regval =LPASS_CDC_DMA_INTF_EIGHT_CHANNEL ;
sound/soc/qcom/lpass-cdc-dma.c line 197
Quoted 10 lines
sound/soc/qcom/lpass-cdc-dma.c new file +10
-0+break ; +default : +dev_err (soc_runtime->dev,"invalid PCM config\n" ); +return -EINVAL ; + } + + ret =regmap_fields_write (dmactl->codec_channel, id, regval); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl codec_channel reg field: %d\n" , ret);
not necessarily 'rdmactl'.
sound/soc/qcom/lpass-cdc-dma.c line 57
Quoted 3 lines
sound/soc/qcom/lpass-cdc-dma.c new file +3
-0+return ret; + } +return ret;
return 0
Quoted 22 lines
sound/soc/qcom/lpass-cdc-dma.c new file +22
-0+} + +static int lpass_wcd_daiops_trigger (struct snd_pcm_substream *substream, +int cmd,struct snd_soc_dai *dai) +{ +struct snd_soc_pcm_runtime *soc_runtime =asoc_substream_to_rtd (substream); +struct snd_soc_dai *cpu_dai =asoc_rtd_to_cpu (soc_runtime,0 ); +struct lpass_data *drvdata =snd_soc_dai_get_drvdata (dai); +struct snd_pcm_runtime *rt = substream->runtime; +struct lpass_pcm_data *pcm_data = rt->private_data; +struct lpass_variant *v = drvdata->variant; +int dir = substream->stream; +struct lpaif_dmactl *dmactl; +struct regmap *map; +unsigned int dai_id = cpu_dai->driver->id; +int ret =0 , id; + +if (dir ==SNDRV_PCM_STREAM_PLAYBACK ) { + dmactl = drvdata->rxtx_rd_dmactl; + map = drvdata->rxtx_lpaif_map; + id = pcm_data->dma_ch; + }else {
sound/soc/qcom/lpass-cdc-dma.c line 232
Quoted 10 lines
sound/soc/qcom/lpass-cdc-dma.c new file +10
-0+if (dai_id ==LPASS_CDC_DMA_TX3 ) { + dmactl = drvdata->rxtx_wr_dmactl; + map = drvdata->rxtx_lpaif_map; + id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start; + }else if (dai_id ==LPASS_CDC_DMA_VA_TX0 ) { + dmactl = drvdata->va_wr_dmactl; + map = drvdata->va_lpaif_map; + id = pcm_data->dma_ch - v->va_wrdma_channel_start; + } + }
see above
sound/soc/qcom/lpass-cdc-dma.c line 245
Quoted 13 lines
sound/soc/qcom/lpass-cdc-dma.c new file +13
-0+switch (cmd) { +case SNDRV_PCM_TRIGGER_START : +case SNDRV_PCM_TRIGGER_RESUME : +case SNDRV_PCM_TRIGGER_PAUSE_RELEASE : +__lpass_platform_codec_intf_init (dai, substream); +break ; +case SNDRV_PCM_TRIGGER_STOP : +case SNDRV_PCM_TRIGGER_SUSPEND : +case SNDRV_PCM_TRIGGER_PAUSE_PUSH : + ret =regmap_fields_write (dmactl->codec_enable, id,LPAIF_DMACTL_ENABLE_OFF ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl reg: %d\n" , ret);
not necessarily rdmactl, better log that it's the codec enable reg.
Quoted 33 lines
sound/soc/qcom/lpass-cdc-dma.c new file +18
-0+return ret; + } + +break ; + } +return ret; +} + +const struct snd_soc_dai_ops asoc_qcom_lpass_wcd_dai_ops = { + .startup = lpass_wcd_daiops_startup, + .shutdown = lpass_wcd_daiops_shutdown, + .hw_params = lpass_wcd_daiops_hw_params, + .trigger = lpass_wcd_daiops_trigger, +}; +EXPORT_SYMBOL_GPL (asoc_qcom_lpass_wcd_dai_ops); + +MODULE_DESCRIPTION ("QTi LPASS CDC DMA Driver" ); +MODULE_LICENSE ("GPL v2" );sound/soc/qcom/lpass.h +1
-0@@ -418,5 +418,6 @@ int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai);extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops;int lpass_cpu_pcm_new (struct snd_soc_pcm_runtime *rtd,struct snd_soc_dai *dai); +extern const struct snd_soc_dai_ops asoc_qcom_lpass_wcd_dai_ops;#endif /* __LPASS_H__ */ Signature · 2 lines
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc., is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
Re: [PATCH 4/8] ASoC: qcom: Add lapss CPU driver for codec dma control
On 10/1/2021 9:22 PM, Matthias Kaehlcke wrote:
Thanks for Your time Matthias!!!
Quoted 3 lines · Srinivasa Rao Mandadapu
Quoted 1 line
Subject: ASoC: qcom: Add lapss CPU driver for codec dma control
nit: s/lapss/lpass/
Okay. Will change.
Quoted 40 lines
Quoted 40 lines
Add lpass cpu driver to support audio over codec dma for ADSP bypass usecase.
Signed-off-by Venkata Prasad Potturu <[email protected]>Signed-off-by Srinivasa Rao Mandadapu <[email protected]>--- sound/soc/qcom/lpass-cdc-dma.c | 263 +++++++++++++++++++++++++++++++++++++++++ sound/soc/qcom/lpass.h | 1 + 2 files changed, 264 insertions(+)create mode 100644
sound/soc/qcom/lpass-cdc-dma.csound/soc/qcom/lpass-cdc-dma.c new file +23
-0@@ -0,0 +1,263 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* +* Copyright (c) 2021 The Linux Foundation. All rights reserved. +* +* lpass-cdc-dma.c -- ALSA SoC WCD -CPU DAI driver for QTi LPASS WCD +*/ + +#include <linux/module.h> +#include <sound/soc.h> +#include <sound/soc-dai.h> + +#include "lpass-lpaif-reg.h" +#include "lpass.h" + +static int __lpass_platform_codec_intf_init (struct snd_soc_dai *dai, +struct snd_pcm_substream *substream) +{ +struct snd_soc_pcm_runtime *soc_runtime =asoc_substream_to_rtd (substream); +struct snd_soc_dai *cpu_dai =asoc_rtd_to_cpu (soc_runtime,0 ); +struct lpass_data *drvdata =snd_soc_dai_get_drvdata (dai); +struct snd_pcm_runtime *rt = substream->runtime; +struct lpass_pcm_data *pcm_data = rt->private_data; +struct lpass_variant *v = drvdata->variant;
Quoted 8 lines
sound/soc/qcom/lpass-cdc-dma.c line 30
Quoted 7 lines
sound/soc/qcom/lpass-cdc-dma.c new file +7
-0+struct lpaif_dmactl *dmactl; +struct regmap *map; +int dir = substream->stream; +int ret, id; +unsigned int dai_id = cpu_dai->driver->id; + +if (dir ==SNDRV_PCM_STREAM_PLAYBACK ) {s/ == / == /
Okay. Will change it.
Quoted 7 lines
Quoted 7 lines
sound/soc/qcom/lpass-cdc-dma.c new file +7
-0+ dmactl = drvdata->rxtx_rd_dmactl; + map = drvdata->rxtx_lpaif_map; + id = pcm_data->dma_ch; + }else { +if (dai_id ==LPASS_CDC_DMA_TX3 ) { + dmactl = drvdata->rxtx_wr_dmactl; + map = drvdata->rxtx_lpaif_map;
Quoted 8 lines
sound/soc/qcom/lpass-cdc-dma.c line 44
Quoted 7 lines
sound/soc/qcom/lpass-cdc-dma.c new file +7
-0+ id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start; + }else if (dai_id ==LPASS_CDC_DMA_VA_TX0 ) { + dmactl = drvdata->va_wr_dmactl; + map = drvdata->va_lpaif_map; + id = pcm_data->dma_ch - v->va_wrdma_channel_start; + } + }'map' is assigned here, but not used in the rest of the function, drop it.
Okay. will remove it.
Quoted 3 lines
sound/soc/qcom/lpass-cdc-dma.c line 46
Quoted 2 lines
sound/soc/qcom/lpass-cdc-dma.c new file +2
-0+ +if (dir ==SNDRV_PCM_STREAM_PLAYBACK ) {s/ == / == /
Okay. Will change it.
Quoted 11 lines
sound/soc/qcom/lpass-cdc-dma.c line 50
Quoted 4 lines
sound/soc/qcom/lpass-cdc-dma.c new file +4
-0+ ret =regmap_fields_write (dmactl->codec_intf, id,LPASS_CDC_DMA_RX0_INTERFACE ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl reg: %d\n" , ret);Some of the logs print the register name, others don't, why not log it always?
sound/soc/qcom/lpass-cdc-dma.c line 53
Quoted 3 lines
sound/soc/qcom/lpass-cdc-dma.c new file +3
-0+return ret; + } + ret =regmap_fields_write (dmactl->codec_fs_sel, id,0x0 );fix indentation
Okay. will change it.
Quoted 18 lines
Quoted 18 lines
sound/soc/qcom/lpass-cdc-dma.c new file +17
-0+if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl reg: %d\n" , ret); +return ret; + } + ret =regmap_fields_write (dmactl->codec_fs_delay, id,0x0 ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl codec_fs_delay reg field: %d\n" , ret); +return ret; + } + ret =regmap_fields_write (dmactl->codec_pack, id,0x1 ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl codec_pack reg field: %d\n" , ret); +return ret; + }
Quoted 8 lines
sound/soc/qcom/lpass-cdc-dma.c line 77
Quoted 7 lines
sound/soc/qcom/lpass-cdc-dma.c new file +7
-0+ ret =regmap_fields_write (dmactl->codec_enable, id,LPAIF_DMACTL_ENABLE_ON ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl reg: %d\n" , ret); +return ret; + } +Remove empty line
Okay. will remove it.
Quoted 10 lines
sound/soc/qcom/lpass-cdc-dma.c line 85
Quoted 9 lines
sound/soc/qcom/lpass-cdc-dma.c new file +8
-0+ }else { + ret =regmap_fields_write (dmactl->codec_intf, id,LPASS_CDC_DMA_INTERFACE (dai_id)); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to wrdmactl codec_intf reg field: %d\n" , ret); +return ret; + } + ret =regmap_fields_write (dmactl->codec_fs_sel, id,0x0 );fix indentation
Okay. Will change it.
Quoted 21 lines
Quoted 21 lines
sound/soc/qcom/lpass-cdc-dma.c new file +20
-0+if (ret) { +dev_err (soc_runtime->dev, +"error writing to wrdmactl codec_fs_sel reg field: %d\n" , ret); +return ret; + } + ret =regmap_fields_write (dmactl->codec_fs_delay, id,0x0 ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to wrdmactl codec_fs_delay reg field: %d\n" , ret); +return ret; + } + ret =regmap_fields_write (dmactl->codec_pack, id,0x1 ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to wrdmactl codec_pack reg field: %d\n" , ret); +return ret; + } + ret =regmap_fields_write (dmactl->codec_enable, id,LPAIF_DMACTL_ENABLE_ON ); +if (ret) { + dev_err(soc_runtime->dev,
Quoted 8 lines
sound/soc/qcom/lpass-cdc-dma.c line 108
Quoted 3 lines
sound/soc/qcom/lpass-cdc-dma.c new file +3
-0+ "error writing to wrdmactl codec_enable reg field: %d\n", ret); +return ret; + }The last four register writes are exactly the same in both branches, only the logging distinguishes between 'rdmactl' and 'wrdmactl'. Those should be in the main branch, if you really need to distinguish between 'rdmactl' and 'wrdmactl' in the logging you can assign a string pointer in the 'if (dir ==
SNDRV_PCM_STREAM_PLAYBACK)' branches.
Okay. Will optimize code. I don't think rdmactl/wrdmactl is distinguish required.
Quoted 8 lines
Quoted 8 lines
sound/soc/qcom/lpass-cdc-dma.c new file +8
-0+ } +return 0 ; +} + +static int lpass_wcd_daiops_startup (struct snd_pcm_substream *substream, +struct snd_soc_dai *dai) +{ +struct lpass_data *drvdata =snd_soc_dai_get_drvdata (dai);
Quoted 8 lines
sound/soc/qcom/lpass-cdc-dma.c line 123
Quoted 7 lines
sound/soc/qcom/lpass-cdc-dma.c new file +7
-0+int ret, i; + +for (i =0 ; i < drvdata->cdc_num_clks; i++) { + ret =clk_prepare_enable (drvdata->cdc_dma_clks[i]); +if (ret) { +dev_err (dai->dev,"error in enabling cdc dma clks: %d\n" , ret); +return ret;Disable clocks that have been enabled previously?
Okay. will use bulk clock API here.
Quoted 45 lines
Quoted 45 lines
sound/soc/qcom/lpass-cdc-dma.c new file +44
-0+ } + } + +return 0 ; +} + +static void lpass_wcd_daiops_shutdown (struct snd_pcm_substream *substream, +struct snd_soc_dai *dai) +{ +int i; +struct lpass_data *drvdata =snd_soc_dai_get_drvdata (dai); + +for (i =0 ; i < drvdata->cdc_num_clks; i++) +clk_disable_unprepare (drvdata->cdc_dma_clks[i]); +} + +static int lpass_wcd_daiops_hw_params (struct snd_pcm_substream *substream, +struct snd_pcm_hw_params *params,struct snd_soc_dai *dai) +{ +struct snd_soc_pcm_runtime *soc_runtime =asoc_substream_to_rtd (substream); +struct snd_soc_dai *cpu_dai =asoc_rtd_to_cpu (soc_runtime,0 ); +struct lpaif_dmactl *dmactl; +struct lpass_data *drvdata =snd_soc_dai_get_drvdata (dai); +struct snd_pcm_runtime *rt = substream->runtime; +struct lpass_pcm_data *pcm_data = rt->private_data; +struct lpass_variant *v = drvdata->variant; +struct regmap *map; +int dir = substream->stream; +unsigned int ret, regval; +unsigned int channels =params_channels (params); +int id; +unsigned int dai_id = cpu_dai->driver->id; + +if (dir ==SNDRV_PCM_STREAM_PLAYBACK ) { + dmactl = drvdata->rxtx_rd_dmactl; + map = drvdata->rxtx_lpaif_map; + id = pcm_data->dma_ch; + }else { +if (dai_id ==LPASS_CDC_DMA_TX3 ) { + dmactl = drvdata->rxtx_wr_dmactl; + map = drvdata->rxtx_lpaif_map; + id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start; + }else if (dai_id ==LPASS_CDC_DMA_VA_TX0 ) { + dmactl = drvdata->va_wr_dmactl;
Quoted 8 lines
sound/soc/qcom/lpass-cdc-dma.c line 44
Quoted 4 lines
sound/soc/qcom/lpass-cdc-dma.c new file +4
-0+ map = drvdata->va_lpaif_map; + id = pcm_data->dma_ch - v->va_wrdma_channel_start; + } + }The exact same code block is used 3 times in this driver. Add a helper with 'substream' and 'dai' as parameters, which determines 'dmactl and 'id'. That would also make the variable declaration/assignment section of these functions signifcantly shorter.
Okay. will optimize it.
Quoted 19 lines
Quoted 19 lines
sound/soc/qcom/lpass-cdc-dma.c new file +19
-0+ +switch (channels) { +case 1 : + regval =LPASS_CDC_DMA_INTF_ONE_CHANNEL ; +break ; +case 2 : + regval =LPASS_CDC_DMA_INTF_TWO_CHANNEL ; +break ; +case 4 : + regval =LPASS_CDC_DMA_INTF_FOUR_CHANNEL ; +break ; +case 6 : + regval =LPASS_CDC_DMA_INTF_SIX_CHANNEL ; +break ; +case 8 : + regval =LPASS_CDC_DMA_INTF_EIGHT_CHANNEL ; +break ; +default : +dev_err (soc_runtime->dev,"invalid PCM config\n" );
Quoted 8 lines
sound/soc/qcom/lpass-cdc-dma.c line 197
Quoted 7 lines
sound/soc/qcom/lpass-cdc-dma.c new file +7
-0+return -EINVAL ; + } + + ret =regmap_fields_write (dmactl->codec_channel, id, regval); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl codec_channel reg field: %d\n" , ret);not necessarily 'rdmactl'.
Okay. will change it.
Quoted 30 lines
sound/soc/qcom/lpass-cdc-dma.c line 57
Quoted 3 lines
sound/soc/qcom/lpass-cdc-dma.c new file +3
-0+return ret; + } +return ret;return 0
Quoted 25 lines
sound/soc/qcom/lpass-cdc-dma.c new file +25
-0+} + +static int lpass_wcd_daiops_trigger (struct snd_pcm_substream *substream, +int cmd,struct snd_soc_dai *dai) +{ +struct snd_soc_pcm_runtime *soc_runtime =asoc_substream_to_rtd (substream); +struct snd_soc_dai *cpu_dai =asoc_rtd_to_cpu (soc_runtime,0 ); +struct lpass_data *drvdata =snd_soc_dai_get_drvdata (dai); +struct snd_pcm_runtime *rt = substream->runtime; +struct lpass_pcm_data *pcm_data = rt->private_data; +struct lpass_variant *v = drvdata->variant; +int dir = substream->stream; +struct lpaif_dmactl *dmactl; +struct regmap *map; +unsigned int dai_id = cpu_dai->driver->id; +int ret =0 , id; + +if (dir ==SNDRV_PCM_STREAM_PLAYBACK ) { + dmactl = drvdata->rxtx_rd_dmactl; + map = drvdata->rxtx_lpaif_map; + id = pcm_data->dma_ch; + }else { +if (dai_id ==LPASS_CDC_DMA_TX3 ) { + dmactl = drvdata->rxtx_wr_dmactl; + map = drvdata->rxtx_lpaif_map;
Quoted 8 lines
sound/soc/qcom/lpass-cdc-dma.c line 44
Quoted 7 lines
sound/soc/qcom/lpass-cdc-dma.c new file +7
-0+ id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start; + }else if (dai_id ==LPASS_CDC_DMA_VA_TX0 ) { + dmactl = drvdata->va_wr_dmactl; + map = drvdata->va_lpaif_map; + id = pcm_data->dma_ch - v->va_wrdma_channel_start; + } + }see above
okay.
Quoted 6 lines
Quoted 6 lines
sound/soc/qcom/lpass-cdc-dma.c new file +6
-0+switch (cmd) { +case SNDRV_PCM_TRIGGER_START : +case SNDRV_PCM_TRIGGER_RESUME : +case SNDRV_PCM_TRIGGER_PAUSE_RELEASE : +__lpass_platform_codec_intf_init (dai, substream); +break ;
Quoted 8 lines
sound/soc/qcom/lpass-cdc-dma.c line 245
Quoted 7 lines
sound/soc/qcom/lpass-cdc-dma.c new file +7
-0+case SNDRV_PCM_TRIGGER_STOP : +case SNDRV_PCM_TRIGGER_SUSPEND : +case SNDRV_PCM_TRIGGER_PAUSE_PUSH : + ret =regmap_fields_write (dmactl->codec_enable, id,LPAIF_DMACTL_ENABLE_OFF ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl reg: %d\n" , ret);not necessarily rdmactl, better log that it's the codec enable reg.
okay. will change it.
Quoted 34 lines
Quoted 34 lines
sound/soc/qcom/lpass-cdc-dma.c new file +18
-0+return ret; + } + +break ; + } +return ret; +} + +const struct snd_soc_dai_ops asoc_qcom_lpass_wcd_dai_ops = { + .startup = lpass_wcd_daiops_startup, + .shutdown = lpass_wcd_daiops_shutdown, + .hw_params = lpass_wcd_daiops_hw_params, + .trigger = lpass_wcd_daiops_trigger, +}; +EXPORT_SYMBOL_GPL (asoc_qcom_lpass_wcd_dai_ops); + +MODULE_DESCRIPTION ("QTi LPASS CDC DMA Driver" ); +MODULE_LICENSE ("GPL v2" );sound/soc/qcom/lpass.h +1
-0@@ -418,5 +418,6 @@ int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai);extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops;int lpass_cpu_pcm_new (struct snd_soc_pcm_runtime *rtd,struct snd_soc_dai *dai); +extern const struct snd_soc_dai_ops asoc_qcom_lpass_wcd_dai_ops;#endif /* __LPASS_H__ */ Signature · 2 lines
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc., is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
Signature · 2 lines
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc., is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
PATCH 5/8 ASoC: qcom: Add support for codec dma driver
In reply to Srinivasa Rao MandadapuUpadate lpass cpu and platform driver to support audio over codec dma in ADSP bypass use case.
--- sound/soc/qcom/lpass-cpu.c | 312 ++++++++++++++++++++++++- sound/soc/qcom/lpass-platform.c | 499 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 773 insertions(+), 38 deletions(-)
sound/soc/qcom/lpass-cpu.c +310 -2
@@ -798,6 +798,251 @@ static struct regmap_config lpass_hdmi_regmap_config = { .cache_type = REGCACHE_FLAT, }; +static bool lpass_rxtx_regmap_writeable (struct device *dev,unsigned int reg) +{ +struct lpass_data *drvdata =dev_get_drvdata (dev); +struct lpass_variant *v = drvdata->variant; +int i; + +for (i =0 ; i < v->rxtx_irq_ports; ++i) { +if (reg ==LPAIF_RXTX_IRQCLEAR_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQEN_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQSTAT_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; + } + +for (i =0 ; i < v->rxtx_rdma_channels; ++i) { +if (reg ==LPAIF_CDC_RDMACTL_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMABASE_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMABUFF_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMAPER_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMA_INTF_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; + } + +for (i =0 ; i < v->rxtx_wrdma_channels; ++i) { +if (reg ==LPAIF_CDC_WRDMACTL_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMABASE_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMABUFF_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMAPER_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMA_INTF_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; + } + +return false; +} + +static bool lpass_rxtx_regmap_readable (struct device *dev,unsigned int reg) +{ +struct lpass_data *drvdata =dev_get_drvdata (dev); +struct lpass_variant *v = drvdata->variant; +int i; + +for (i =0 ; i < v->rxtx_irq_ports; ++i) { +if (reg ==LPAIF_RXTX_IRQCLEAR_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQEN_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQSTAT_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; + } + +for (i =0 ; i < v->rxtx_rdma_channels; ++i) { +if (reg ==LPAIF_CDC_RDMACTL_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMABASE_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMABUFF_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMACURR_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMAPER_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMA_INTF_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; + } + +for (i =0 ; i < v->rxtx_wrdma_channels; ++i) { +if (reg ==LPAIF_CDC_WRDMACTL_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMABASE_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMABUFF_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMACURR_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMAPER_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMA_INTF_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; + } + +return false; +} + +static bool lpass_rxtx_regmap_volatile (struct device *dev,unsigned int reg) +{ +struct lpass_data *drvdata =dev_get_drvdata (dev); +struct lpass_variant *v = drvdata->variant; +int i; + +for (i =0 ; i < v->rxtx_irq_ports; ++i) { +if (reg ==LPAIF_RXTX_IRQCLEAR_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQSTAT_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; + } + +for (i =0 ; i < v->rxtx_rdma_channels; ++i) +if (reg ==LPAIF_CDC_RDMACURR_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; + +for (i =0 ; i < v->rxtx_wrdma_channels; ++i) +if (reg ==LPAIF_CDC_WRDMACURR_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; + +return false; +} + +static bool lpass_va_regmap_writeable (struct device *dev,unsigned int reg) +{ +struct lpass_data *drvdata =dev_get_drvdata (dev); +struct lpass_variant *v = drvdata->variant; +int i; + +for (i =0 ; i < v->va_irq_ports; ++i) { +if (reg ==LPAIF_RXTX_IRQCLEAR_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQEN_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQSTAT_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; + } + +for (i =0 ; i < v->va_wrdma_channels; ++i) { +if (reg ==LPAIF_CDC_WRDMACTL_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMABASE_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMABUFF_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMAPER_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMA_INTF_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; + } + +return false; +} + +static bool lpass_va_regmap_readable (struct device *dev,unsigned int reg) +{ +struct lpass_data *drvdata =dev_get_drvdata (dev); +struct lpass_variant *v = drvdata->variant; +int i; + +for (i =0 ; i < v->va_irq_ports; ++i) { +if (reg ==LPAIF_RXTX_IRQCLEAR_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQEN_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQSTAT_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; + } + +for (i =0 ; i < v->va_wrdma_channels; ++i) { +if (reg ==LPAIF_CDC_WRDMACTL_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMABASE_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMABUFF_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMACURR_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMAPER_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMA_INTF_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; + } + +return false; +} + +static bool lpass_va_regmap_volatile (struct device *dev,unsigned int reg) +{ +struct lpass_data *drvdata =dev_get_drvdata (dev); +struct lpass_variant *v = drvdata->variant; +int i; + +for (i =0 ; i < v->va_irq_ports; ++i) { +if (reg ==LPAIF_RXTX_IRQCLEAR_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQSTAT_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; + } + +for (i =0 ; i < v->va_wrdma_channels; ++i) { +if (reg ==LPAIF_CDC_WRDMACURR_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; + } + +return false; +} + +static struct regmap_config lpass_rxtx_regmap_config = { + .reg_bits =32 , + .reg_stride =4 , + .val_bits =32 , + .writeable_reg = lpass_rxtx_regmap_writeable, + .readable_reg = lpass_rxtx_regmap_readable, + .volatile_reg = lpass_rxtx_regmap_volatile, + .cache_type =REGCACHE_FLAT , +}; + +static struct regmap_config lpass_va_regmap_config = { + .reg_bits =32 , + .reg_stride =4 , + .val_bits =32 , + .writeable_reg = lpass_va_regmap_writeable, + .readable_reg = lpass_va_regmap_readable, + .volatile_reg = lpass_va_regmap_volatile, + .cache_type =REGCACHE_FLAT , +}; +static unsigned int of_lpass_cpu_parse_sd_lines (struct device *dev,struct device_node *node,const char *name)
@@ -837,6 +1082,17 @@ static unsigned int of_lpass_cpu_parse_sd_lines(struct device *dev, } } +static bool is_cdc_dma_port (int dai_id) +{ +switch (dai_id) { +case LPASS_CDC_DMA_RX0 : +case LPASS_CDC_DMA_TX3 : +case LPASS_CDC_DMA_VA_TX0 : +return true; +default : +return false; + } +}static void of_lpass_cpu_parse_dai_data (struct device *dev,struct lpass_data *data) {
@@ -857,7 +1113,9 @@ static void of_lpass_cpu_parse_dai_data(struct device *dev, }if (id ==LPASS_DP_RX ) { data->hdmi_port_enable =1 ; - }else { + }else if (is_cdc_dma_port (id)) + data->wcd_codec_enable =1 ; +else { data->mi2s_playback_sd_mode[id] =of_lpass_cpu_parse_sd_lines (dev, node,"qcom,playback-sd-lines" );
@@ -897,6 +1155,53 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)of_lpass_cpu_parse_dai_data (dev, drvdata); + drvdata->num_clks = variant->num_clks; +if (drvdata->wcd_codec_enable) { + drvdata->rxtx_lpaif = +devm_platform_ioremap_resource_byname (pdev,"lpass-rxtx-lpaif" ); +if (IS_ERR (drvdata->rxtx_lpaif)) +return PTR_ERR (drvdata->rxtx_lpaif); + + drvdata->va_lpaif =devm_platform_ioremap_resource_byname (pdev,"lpass-va-lpaif" ); +if (IS_ERR (drvdata->va_lpaif)) +return PTR_ERR (drvdata->va_lpaif); + + lpass_rxtx_regmap_config.max_register =LPAIF_CDC_WRDMAPER_REG (variant, + variant->rxtx_wrdma_channels + + variant->rxtx_wrdma_channel_start,LPASS_CDC_DMA_TX3 ); + + drvdata->rxtx_lpaif_map =devm_regmap_init_mmio (dev, drvdata->rxtx_lpaif, + &lpass_rxtx_regmap_config); +if (IS_ERR (drvdata->rxtx_lpaif_map)) { +dev_err (dev,"error initializing regmap: %ld\n" , +PTR_ERR (drvdata->rxtx_lpaif_map)); +return PTR_ERR (drvdata->rxtx_lpaif_map); + } + lpass_va_regmap_config.max_register =LPAIF_CDC_WRDMAPER_REG (variant, + variant->va_wrdma_channels + + variant->va_wrdma_channel_start,LPASS_CDC_DMA_VA_TX0 ); + + drvdata->va_lpaif_map =devm_regmap_init_mmio (dev, drvdata->va_lpaif, + &lpass_va_regmap_config); +if (IS_ERR (drvdata->va_lpaif_map)) { +dev_err (dev,"error initializing regmap: %ld\n" , +PTR_ERR (drvdata->va_lpaif_map)); +return PTR_ERR (drvdata->va_lpaif_map); + } + drvdata->cdc_num_clks = variant->cdc_dma_num_clks; +for (i =0 ; i < variant->cdc_dma_num_clks; i++) { + drvdata->cdc_dma_clks[i] =devm_clk_get (dev, + variant->cdc_dma_clk_names[i]); +if (IS_ERR (drvdata->cdc_dma_clks[i])) { +dev_err (dev, +"error getting %s: %ld\n" , + variant->cdc_dma_clk_names[i], +PTR_ERR (drvdata->cdc_dma_clks[i])); +return PTR_ERR (drvdata->cdc_dma_clks[i]); + } + } + } + drvdata->lpaif =devm_platform_ioremap_resource_byname (pdev,"lpass-lpaif" );if (IS_ERR (drvdata->lpaif))return PTR_ERR (drvdata->lpaif);
@@ -939,7 +1244,10 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)for (i =0 ; i < variant->num_dai; i++) { dai_id = variant->dai_driver[i].id; -if (dai_id ==LPASS_DP_RX ) +if (dai_id ==LPASS_DP_RX || + dai_id ==LPASS_CDC_DMA_RX0 || + dai_id ==LPASS_CDC_DMA_TX3 || + dai_id ==LPASS_CDC_DMA_VA_TX0 )continue ; drvdata->mi2s_osr_clk[dai_id] = devm_clk_get_optional(dev,
sound/soc/qcom/lpass-platform.c +463 -36
674 lines not on this page · raw message
Signature · 2 lines
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc., is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
Re: [PATCH 5/8] ASoC: qcom: Add support for codec dma driver
Quoted 110 lines · Srinivasa Rao Mandadapu
Upadate lpass cpu and platform driver to support audio over codec dma in ADSP bypass use case.
Signed-off-by Venkata Prasad Potturu <[email protected]>Signed-off-by Srinivasa Rao Mandadapu <[email protected]>--- sound/soc/qcom/lpass-cpu.c | 312 ++++++++++++++++++++++++- sound/soc/qcom/lpass-platform.c | 499 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 773 insertions(+), 38 deletions(-)sound/soc/qcom/lpass-cpu.c +92
-0@@ -798,6 +798,251 @@ static struct regmap_config lpass_hdmi_regmap_config = { .cache_type = REGCACHE_FLAT, }; +static bool lpass_rxtx_regmap_writeable (struct device *dev,unsigned int reg) +{ +struct lpass_data *drvdata =dev_get_drvdata (dev); +struct lpass_variant *v = drvdata->variant; +int i; + +for (i =0 ; i < v->rxtx_irq_ports; ++i) { +if (reg ==LPAIF_RXTX_IRQCLEAR_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQEN_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQSTAT_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; + } + +for (i =0 ; i < v->rxtx_rdma_channels; ++i) { +if (reg ==LPAIF_CDC_RDMACTL_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMABASE_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMABUFF_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMAPER_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMA_INTF_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; + } + +for (i =0 ; i < v->rxtx_wrdma_channels; ++i) { +if (reg ==LPAIF_CDC_WRDMACTL_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMABASE_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMABUFF_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMAPER_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMA_INTF_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; + } + +return false; +} + +static bool lpass_rxtx_regmap_readable (struct device *dev,unsigned int reg) +{ +struct lpass_data *drvdata =dev_get_drvdata (dev); +struct lpass_variant *v = drvdata->variant; +int i; + +for (i =0 ; i < v->rxtx_irq_ports; ++i) { +if (reg ==LPAIF_RXTX_IRQCLEAR_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQEN_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQSTAT_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; + } + +for (i =0 ; i < v->rxtx_rdma_channels; ++i) { +if (reg ==LPAIF_CDC_RDMACTL_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMABASE_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMABUFF_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMACURR_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMAPER_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMA_INTF_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; + } + +for (i =0 ; i < v->rxtx_wrdma_channels; ++i) { +if (reg ==LPAIF_CDC_WRDMACTL_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMABASE_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMABUFF_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMACURR_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true;
sound/soc/qcom/lpass-cpu.c static struct regmap_config lpass_hdmi_regmap_config = { · line 902
Quoted 10 lines
sound/soc/qcom/lpass-cpu.c +10
-0+if (reg ==LPAIF_CDC_WRDMAPER_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMA_INTF_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; + } + +return false; +}
lpass_rxtx_regmap_readable() is almost the same as lpass_rxtx_regmap_writeable(), except for LPAIF_CDC_RDMACURR_REG and LPAIF_CDC_WRDMACURR_REG. Add something like
static bool __lpass_rxtx_regmap_accessible(struct device *dev, unsigned int reg, bool rw)
which would look essentially like lpass_rxtx_regmap_readable() but checks the 'rw' parameter for LPAIF_CDC_RDMACURR_REG and LPAIF_CDC_WRDMACURR_REG. lpass_rxtx_regmap_readable() and lpass_rxtx_regmap_writeable() then call this function with the corresponding value for 'rw'
Quoted 90 lines
sound/soc/qcom/lpass-cpu.c +90
-0+ +static bool lpass_rxtx_regmap_volatile (struct device *dev,unsigned int reg) +{ +struct lpass_data *drvdata =dev_get_drvdata (dev); +struct lpass_variant *v = drvdata->variant; +int i; + +for (i =0 ; i < v->rxtx_irq_ports; ++i) { +if (reg ==LPAIF_RXTX_IRQCLEAR_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQSTAT_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; + } + +for (i =0 ; i < v->rxtx_rdma_channels; ++i) +if (reg ==LPAIF_CDC_RDMACURR_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; + +for (i =0 ; i < v->rxtx_wrdma_channels; ++i) +if (reg ==LPAIF_CDC_WRDMACURR_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; + +return false; +} + +static bool lpass_va_regmap_writeable (struct device *dev,unsigned int reg) +{ +struct lpass_data *drvdata =dev_get_drvdata (dev); +struct lpass_variant *v = drvdata->variant; +int i; + +for (i =0 ; i < v->va_irq_ports; ++i) { +if (reg ==LPAIF_RXTX_IRQCLEAR_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQEN_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQSTAT_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; + } + +for (i =0 ; i < v->va_wrdma_channels; ++i) { +if (reg ==LPAIF_CDC_WRDMACTL_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMABASE_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMABUFF_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMAPER_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMA_INTF_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; + } + +return false; +} + +static bool lpass_va_regmap_readable (struct device *dev,unsigned int reg) +{ +struct lpass_data *drvdata =dev_get_drvdata (dev); +struct lpass_variant *v = drvdata->variant; +int i; + +for (i =0 ; i < v->va_irq_ports; ++i) { +if (reg ==LPAIF_RXTX_IRQCLEAR_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQEN_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQSTAT_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; + } + +for (i =0 ; i < v->va_wrdma_channels; ++i) { +if (reg ==LPAIF_CDC_WRDMACTL_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMABASE_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMABUFF_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMACURR_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true;
sound/soc/qcom/lpass-cpu.c static struct regmap_config lpass_hdmi_regmap_config = { · line 1002
Quoted 10 lines
sound/soc/qcom/lpass-cpu.c +10
-0+if (reg ==LPAIF_CDC_WRDMAPER_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMA_INTF_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; + } + +return false; +}
Same as for lpass_rxtx_regmap_readable/writable()
Quoted 88 lines
sound/soc/qcom/lpass-cpu.c +66
-1+ +static bool lpass_va_regmap_volatile (struct device *dev,unsigned int reg) +{ +struct lpass_data *drvdata =dev_get_drvdata (dev); +struct lpass_variant *v = drvdata->variant; +int i; + +for (i =0 ; i < v->va_irq_ports; ++i) { +if (reg ==LPAIF_RXTX_IRQCLEAR_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQSTAT_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; + } + +for (i =0 ; i < v->va_wrdma_channels; ++i) { +if (reg ==LPAIF_CDC_WRDMACURR_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; + } + +return false; +} + +static struct regmap_config lpass_rxtx_regmap_config = { + .reg_bits =32 , + .reg_stride =4 , + .val_bits =32 , + .writeable_reg = lpass_rxtx_regmap_writeable, + .readable_reg = lpass_rxtx_regmap_readable, + .volatile_reg = lpass_rxtx_regmap_volatile, + .cache_type =REGCACHE_FLAT , +}; + +static struct regmap_config lpass_va_regmap_config = { + .reg_bits =32 , + .reg_stride =4 , + .val_bits =32 , + .writeable_reg = lpass_va_regmap_writeable, + .readable_reg = lpass_va_regmap_readable, + .volatile_reg = lpass_va_regmap_volatile, + .cache_type =REGCACHE_FLAT , +}; +static unsigned int of_lpass_cpu_parse_sd_lines (struct device *dev,struct device_node *node,const char *name)@@ -837,6 +1082,17 @@ static unsigned int of_lpass_cpu_parse_sd_lines(struct device *dev, } } +static bool is_cdc_dma_port (int dai_id) +{ +switch (dai_id) { +case LPASS_CDC_DMA_RX0 : +case LPASS_CDC_DMA_TX3 : +case LPASS_CDC_DMA_VA_TX0 : +return true; +default : +return false; + } +}static void of_lpass_cpu_parse_dai_data (struct device *dev,struct lpass_data *data) {@@ -857,7 +1113,9 @@ static void of_lpass_cpu_parse_dai_data(struct device *dev, }if (id ==LPASS_DP_RX ) { data->hdmi_port_enable =1 ; - }else { + }else if (is_cdc_dma_port (id)) + data->wcd_codec_enable =1 ; +else { data->mi2s_playback_sd_mode[id] =of_lpass_cpu_parse_sd_lines (dev, node,"qcom,playback-sd-lines" );@@ -897,6 +1155,53 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)of_lpass_cpu_parse_dai_data (dev, drvdata); + drvdata->num_clks = variant->num_clks; +if (drvdata->wcd_codec_enable) { + drvdata->rxtx_lpaif = +devm_platform_ioremap_resource_byname (pdev,"lpass-rxtx-lpaif" ); +if (IS_ERR (drvdata->rxtx_lpaif)) +return PTR_ERR (drvdata->rxtx_lpaif); + + drvdata->va_lpaif =devm_platform_ioremap_resource_byname (pdev,"lpass-va-lpaif" ); +if (IS_ERR (drvdata->va_lpaif))
sound/soc/qcom/lpass-cpu.c int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) · line 1176
Quoted 10 lines
sound/soc/qcom/lpass-cpu.c +10
-0+return PTR_ERR (drvdata->va_lpaif); + + lpass_rxtx_regmap_config.max_register =LPAIF_CDC_WRDMAPER_REG (variant, + variant->rxtx_wrdma_channels + + variant->rxtx_wrdma_channel_start,LPASS_CDC_DMA_TX3 ); + + drvdata->rxtx_lpaif_map =devm_regmap_init_mmio (dev, drvdata->rxtx_lpaif, + &lpass_rxtx_regmap_config); +if (IS_ERR (drvdata->rxtx_lpaif_map)) { + dev_err(dev, "error initializing regmap: %ld\n",
The same error is logged a few lines below, you might want to log which regmap couldn't be initialized.
sound/soc/qcom/lpass-cpu.c int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) · line 1177
Quoted 1 line
sound/soc/qcom/lpass-cpu.c +1
-0+ PTR_ERR(drvdata->rxtx_lpaif_map));
fix indentation
sound/soc/qcom/lpass-cpu.c int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) · line 1187
Quoted 10 lines
sound/soc/qcom/lpass-cpu.c +10
-0+return PTR_ERR (drvdata->rxtx_lpaif_map); + } + lpass_va_regmap_config.max_register =LPAIF_CDC_WRDMAPER_REG (variant, + variant->va_wrdma_channels + + variant->va_wrdma_channel_start,LPASS_CDC_DMA_VA_TX0 ); + + drvdata->va_lpaif_map =devm_regmap_init_mmio (dev, drvdata->va_lpaif, + &lpass_va_regmap_config); +if (IS_ERR (drvdata->va_lpaif_map)) { + dev_err(dev, "error initializing regmap: %ld\n",
see above
sound/soc/qcom/lpass-cpu.c int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) · line 1188
Quoted 1 line
sound/soc/qcom/lpass-cpu.c +1
-0+ PTR_ERR(drvdata->va_lpaif_map));
fix indentation
Quoted 47 lines
sound/soc/qcom/lpass-cpu.c +25
-3+return PTR_ERR (drvdata->va_lpaif_map); + } + drvdata->cdc_num_clks = variant->cdc_dma_num_clks; +for (i =0 ; i < variant->cdc_dma_num_clks; i++) { + drvdata->cdc_dma_clks[i] =devm_clk_get (dev, + variant->cdc_dma_clk_names[i]); +if (IS_ERR (drvdata->cdc_dma_clks[i])) { + vdata->lpaif_map; + } } ret = regmap_write(map, LPAIF_DMABASE_REG(v, ch, dir, dai_id),@@ -423,6 +578,16 @@ static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,return ret; } +if (dai_id ==LPASS_CDC_DMA_RX0 || + dai_id ==LPASS_CDC_DMA_TX3 || + dai_id ==LPASS_CDC_DMA_VA_TX0 ) { + ret =regmap_fields_write (dmactl->fifowm, id,LPAIF_DMACTL_FIFOWM_8 ); +if (ret) { +dev_err (soc_runtime->dev,"error writing fifowm field to dmactl reg: %d, id: %d\n" , + ret, id); +return ret; + } + } ret =regmap_fields_write (dmactl->enable, id,LPAIF_DMACTL_ENABLE_ON );if (ret) { dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",@@ -457,14 +622,27 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,if (dai_id ==LPASS_DP_RX ) { dmactl = drvdata->hdmi_rd_dmactl; map = drvdata->hdmiif_map; + }else if (dai_id ==LPASS_CDC_DMA_RX0 ) { + map = drvdata->rxtx_lpaif_map; + dmactl = drvdata->rxtx_rd_dmactl; }else { dmactl = drvdata->rd_dmactl; map = drvdata->lpaif_map; } }else { - dmactl = drvdata->wr_dmactl; - id = pcm_data->dma_ch - v->wrdma_channel_start; - map = drvdata->lpaif_map; +if (dai_id ==LPASS_CDC_DMA_TX3 ) { + dmactl = drvdata->rxtx_wr_dmactl; + map = drvdata->rxtx_lpaif_map;
sound/soc/qcom/lpass-cpu.c static int lpass_platform_pcmops_trigger(struct snd_soc_component *component, · line 645
Quoted 10 lines
sound/soc/qcom/lpass-cpu.c +10
-0+ id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start; + }else if (dai_id ==LPASS_CDC_DMA_VA_TX0 ) { + dmactl = drvdata->va_wr_dmactl; + map = drvdata->va_lpaif_map; + id = pcm_data->dma_ch - v->va_wrdma_channel_start; + }else { + dmactl = drvdata->wr_dmactl; + id = pcm_data->dma_ch - v->wrdma_channel_start; + map = drvdata->lpaif_map; + }
As for "[4/8] ASoC: qcom: Add lapss CPU driver for codec dma control", I think you want a helper that encapsulates the above, instead of open coding it multiple times in the driver.
Quoted 8 lines
sound/soc/qcom/lpass-cpu.c +1
-0}switch (cmd) {@@ -479,6 +657,24 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,return ret; }switch (dai_id) { +case LPASS_CDC_DMA_RX0 :
sound/soc/qcom/lpass-cpu.c static int lpass_platform_pcmops_trigger(struct snd_soc_component *component, · line 670
Quoted 10 lines
sound/soc/qcom/lpass-cpu.c +10
-0+case LPASS_CDC_DMA_TX3 : +case LPASS_CDC_DMA_VA_TX0 : + ret =regmap_fields_write (dmactl->dyncclk, id,LPAIF_DMACTL_DYNCLK_ON ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl reg field: %d\n" , ret); +return ret; + } + map = (dai_id ==LPASS_CDC_DMA_VA_TX0 ) ? + drvdata->va_lpaif_map : drvdata->rxtx_lpaif_map;
'map' was already assigned earlier.
Quoted 15 lines
sound/soc/qcom/lpass-cpu.c +8
-0+ reg_irqclr =LPAIF_RXTX_IRQCLEAR_REG (v,LPAIF_IRQ_PORT_HOST , dai_id); + val_irqclr =LPAIF_IRQ_ALL (ch); + + reg_irqen =LPAIF_RXTX_IRQEN_REG (v,LPAIF_IRQ_PORT_HOST , dai_id); + val_mask =LPAIF_IRQ_ALL (ch); + val_irqen =LPAIF_IRQ_ALL (ch); +break ;case LPASS_DP_RX : ret =regmap_fields_write (dmactl->dyncclk, id,LPAIF_DMACTL_DYNCLK_ON );@@ -543,6 +739,26 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,return ret; }switch (dai_id) { +case LPASS_CDC_DMA_RX0 :
sound/soc/qcom/lpass-cpu.c static int lpass_platform_pcmops_trigger(struct snd_soc_component *component, · line 752
Quoted 10 lines
sound/soc/qcom/lpass-cpu.c +10
-0+case LPASS_CDC_DMA_TX3 : +case LPASS_CDC_DMA_VA_TX0 : + ret =regmap_fields_write (dmactl->dyncclk, id,LPAIF_DMACTL_DYNCLK_OFF ); +if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl reg field: %d\n" , ret); +return ret; + } + map = (dai_id ==LPASS_CDC_DMA_VA_TX0 ) ? + drvdata->va_lpaif_map : drvdata->rxtx_lpaif_map;
ditto
Quoted 14 lines
sound/soc/qcom/lpass-cpu.c +9
-0+ + reg_irqclr =LPAIF_RXTX_IRQCLEAR_REG (v,LPAIF_IRQ_PORT_HOST , dai_id); + val_irqclr =LPAIF_IRQ_ALL (ch); + + reg_irqen =LPAIF_RXTX_IRQEN_REG (v,LPAIF_IRQ_PORT_HOST , dai_id); + val_mask =LPAIF_IRQ_ALL (ch); + val_irqen =LPAIF_IRQ_ALL (ch); + +break ;case LPASS_DP_RX : ret =regmap_fields_write (dmactl->dyncclk, id,LPAIF_DMACTL_DYNCLK_OFF );@@ -601,6 +817,12 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
sound/soc/qcom/lpass-cpu.c static snd_pcm_uframes_t lpass_platform_pcmops_pointer( · line 827
Quoted 10 lines
sound/soc/qcom/lpass-cpu.c +6
-0if (dai_id ==LPASS_DP_RX ) map = drvdata->hdmiif_map; +else if (dai_id ==LPASS_CDC_DMA_RX0 || + dai_id ==LPASS_CDC_DMA_TX3 || + dai_id ==LPASS_CDC_DMA_VA_TX0 ) + map = (dai_id ==LPASS_CDC_DMA_VA_TX0 ) ? + drvdata->va_lpaif_map : + drvdata->rxtx_lpaif_map;else map = drvdata->lpaif_map;
use helper to get map from dai id
Quoted 11 lines
sound/soc/qcom/lpass-cpu.c +6
-0@@ -625,12 +847,39 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(return bytes_to_frames (substream->runtime, curr_addr - base_addr); } +static int lpass_platform_cdc_dma_mmap (struct snd_soc_component *component, +struct snd_pcm_substream *substream, +struct vm_area_struct *vma) +{ +struct snd_pcm_runtime *runtime = substream->runtime; +unsigned long size, offset;
sound/soc/qcom/lpass-cpu.c static snd_pcm_uframes_t lpass_platform_pcmops_pointer( · line 865
Quoted 10 lines
sound/soc/qcom/lpass-cpu.c +10
-0+int ret; + + vma->vm_page_prot =pgprot_noncached (vma->vm_page_prot); + size = vma->vm_end - vma->vm_start; + offset = vma->vm_pgoff <<PAGE_SHIFT ; + ret =io_remap_pfn_range (vma, vma->vm_start, + (runtime->dma_addr + offset) >>PAGE_SHIFT , + size, vma->vm_page_prot); + +return ret;
no need for 'ret' just 'return io_remap_pfn_range(...);'
Quoted 203 lines
sound/soc/qcom/lpass-cpu.c +133
-16+} +static int lpass_platform_pcmops_mmap (struct snd_soc_component *component,struct snd_pcm_substream *substream,struct vm_area_struct *vma) {struct snd_pcm_runtime *runtime = substream->runtime; +struct snd_soc_pcm_runtime *soc_runtime =asoc_substream_to_rtd (substream); +struct snd_soc_dai *cpu_dai =asoc_rtd_to_cpu (soc_runtime,0 ); +unsigned int dai_id = cpu_dai->driver->id; +if (dai_id ==LPASS_CDC_DMA_RX0 || + dai_id ==LPASS_CDC_DMA_TX3 || + dai_id ==LPASS_CDC_DMA_VA_TX0 ) { +lpass_platform_cdc_dma_mmap (component, substream, vma); +return 0 ; + }return dma_mmap_coherent (component->dev, vma, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes); }@@ -651,6 +900,14 @@ static irqreturn_t lpass_dma_interrupt_handler( mask =LPAIF_IRQ_ALL (chan);switch (dai_id) { +case LPASS_CDC_DMA_RX0 : +case LPASS_CDC_DMA_TX3 : +case LPASS_CDC_DMA_VA_TX0 : + map = (dai_id ==LPASS_CDC_DMA_VA_TX0 ) ? + drvdata->va_lpaif_map : drvdata->rxtx_lpaif_map; + reg =LPAIF_RXTX_IRQCLEAR_REG (v,LPAIF_IRQ_PORT_HOST , dai_id); + val =0 ; +break ;case LPASS_DP_RX : map = drvdata->hdmiif_map; reg =LPASS_HDMITX_APP_IRQCLEAR_REG (v);@@ -774,41 +1031,131 @@ static irqreturn_t lpass_platform_hdmiif_irq(int irq, void *data)return rv; } } +return IRQ_HANDLED ; +} + +static irqreturn_t lpass_platform_rxtxif_irq (int irq,void *data) +{ +struct lpass_data *drvdata = data; +struct lpass_variant *v = drvdata->variant; +unsigned int irqs; +int rv, chan; + + rv =regmap_read (drvdata->rxtx_lpaif_map, +LPAIF_RXTX_IRQSTAT_REG (v,LPAIF_IRQ_PORT_HOST ,LPASS_CDC_DMA_RX0 ), &irqs); +if (rv) +return IRQ_NONE ; +/* Handle per channel interrupts */ +for (chan =0 ; chan <LPASS_MAX_CDC_DMA_CHANNELS ; chan++) { +if (irqs &LPAIF_IRQ_ALL (chan) && drvdata->rxtx_substream[chan]) { + rv =lpass_dma_interrupt_handler ( + drvdata->rxtx_substream[chan], + drvdata, chan, irqs); +if (rv !=IRQ_HANDLED ) +return rv; + } + } + +return IRQ_HANDLED ; +} + +static irqreturn_t lpass_platform_vaif_irq (int irq,void *data) +{ +struct lpass_data *drvdata = data; +struct lpass_variant *v = drvdata->variant; +unsigned int irqs; +int rv, chan; + rv =regmap_read (drvdata->va_lpaif_map, +LPAIF_RXTX_IRQSTAT_REG (v,LPAIF_IRQ_PORT_HOST , +LPASS_CDC_DMA_VA_TX0 ), &irqs); +if (rv) +return IRQ_NONE ; +/* Handle per channel interrupts */ +for (chan =0 ; chan <LPASS_MAX_VA_CDC_DMA_CHANNELS ; chan++) { +if (irqs &LPAIF_IRQ_ALL (chan) && drvdata->va_substream[chan]) { + rv =lpass_dma_interrupt_handler ( + drvdata->va_substream[chan], + drvdata, chan, irqs); +if (rv !=IRQ_HANDLED ) +return rv; + } + }return IRQ_HANDLED ; } +static int lpass_platform_prealloc_cdc_dma_buffer (struct snd_pcm *pcm, +struct snd_pcm_substream *substream,int dai_id) +{ +struct snd_dma_buffer *buf = &substream->dma_buffer; +int ret; + + ret =dma_coerce_mask_and_coherent (pcm->card->dev,DMA_BIT_MASK (64 )); +if (ret) +return ret; + + buf->dev.dev = pcm->card->dev; + buf->private_data =NULL ; + +/* Assign Codec DMA buffer pointers */ + buf->dev.type =SNDRV_DMA_TYPE_CONTINUOUS ; +if (dai_id ==LPASS_CDC_DMA_RX0 ) { + buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max; + buf->addr =LPSAS_RXTX_CDC_DMA_LPM_ADDR ; + }else if (dai_id ==LPASS_CDC_DMA_TX3 ) { + buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max; + buf->addr =LPSAS_RXTX_CDC_DMA_LPM_ADDR +LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE ; + }else if (dai_id ==LPASS_CDC_DMA_VA_TX0 ) { + buf->bytes = lpass_platform_va_hardware.buffer_bytes_max; + buf->addr =LPSAS_VA_CDC_DMA_LPM_ADDR ; + } + + buf->area = (unsigned char *__force )ioremap (buf->addr, buf->bytes); + +return 0 ; +} +static int lpass_platform_pcm_new (struct snd_soc_component *component,struct snd_soc_pcm_runtime *soc_runtime) {struct snd_pcm *pcm = soc_runtime->pcm;struct snd_pcm_substream *psubstream, *csubstream;int ret; +struct snd_soc_dai *cpu_dai =asoc_rtd_to_cpu (soc_runtime,0 ); +unsigned int dai_id = cpu_dai->driver->id; +size_t size = lpass_platform_pcm_hardware.buffer_bytes_max; psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK ].substream;if (psubstream) { - ret =snd_dma_alloc_pages (SNDRV_DMA_TYPE_DEV , - component->dev, - size, &psubstream->dma_buffer); -if (ret) { -dev_err (soc_runtime->dev,"Cannot allocate buffer(s)\n" ); -return ret; +if (dai_id ==LPASS_CDC_DMA_RX0 ) { +lpass_platform_prealloc_cdc_dma_buffer (pcm, psubstream, dai_id); + }else { + ret =snd_dma_alloc_pages (SNDRV_DMA_TYPE_DEV , + component->dev, + size, &psubstream->dma_buffer); +if (ret) { +dev_err (soc_runtime->dev,"Cannot allocate buffer(s)\n" ); +return ret; + } } } csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE ].substream;if (csubstream) { - ret =snd_dma_alloc_pages (SNDRV_DMA_TYPE_DEV , - component->dev, - size, &csubstream->dma_buffer); -if (ret) { -dev_err (soc_runtime->dev,"Cannot allocate buffer(s)\n" ); -if (psubstream) -snd_dma_free_pages (&psubstream->dma_buffer); -return ret; +if (dai_id ==LPASS_CDC_DMA_TX3 || dai_id ==LPASS_CDC_DMA_VA_TX0 ) { +lpass_platform_prealloc_cdc_dma_buffer (pcm, csubstream, dai_id); + }else { + ret =snd_dma_alloc_pages (SNDRV_DMA_TYPE_DEV , + component->dev, + size, &csubstream->dma_buffer); +if (ret) { +dev_err (soc_runtime->dev,"Cannot allocate buffer(s)\n" ); +if (psubstream) +snd_dma_free_pages (&psubstream->dma_buffer); +return ret; + } } - }return 0 ;@@ -818,18 +1165,43 @@ static void lpass_platform_pcm_free(struct snd_soc_component *component, struct snd_pcm *pcm) {struct snd_pcm_substream *substream; +unsigned int dai_id = component->id;int i;for_each_pcm_streams (i) { substream = pcm->streams[i].substream;if (substream) { -snd_dma_free_pages (&substream->dma_buffer); +if (dai_id ==LPASS_CDC_DMA_RX0 || + dai_id ==LPASS_CDC_DMA_TX3 || + dai_id ==LPASS_CDC_DMA_VA_TX0 ) { +if (substream->dma_buffer.area) +iounmap ((void __iomem *)substream->dma_buffer.area); + }else { +snd_dma_free_pages (&substream->dma_buffer); + } substream->dma_buffer.area =NULL ; substream->dma_buffer.addr =0 ;
sound/soc/qcom/lpass-cpu.c static void lpass_platform_pcm_free(struct snd_soc_component *component, · line 1193
Quoted 10 lines
sound/soc/qcom/lpass-cpu.c +6
-0} } } +int lpass_platform_copy (struct snd_soc_component *component, +struct snd_pcm_substream *substream,int channel, +unsigned long pos,void __user *buf,unsigned long bytes) +{ +struct snd_pcm_runtime *rt = substream->runtime; +
delete empty line
sound/soc/qcom/lpass-cpu.c static void lpass_platform_pcm_free(struct snd_soc_component *component, · line 1202
Quoted 9 lines
sound/soc/qcom/lpass-cpu.c +9
-0+unsigned char *dma_buf = rt->dma_area + pos + + channel * (rt->dma_bytes / rt->channels); + +if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) +return copy_from_user_toio (dma_buf, buf, bytes); +else if (substream->stream ==SNDRV_PCM_STREAM_CAPTURE ) +return copy_to_user_fromio (buf, dma_buf, bytes); + +return 0 ;
Can 'substream->stream' have any other value than SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE? If not maybe return -EINVAL here?
Quoted 78 lines
sound/soc/qcom/lpass-cpu.c +57
-0+} +static int lpass_platform_pcmops_suspend (struct snd_soc_component *component) {struct lpass_data *drvdata =snd_soc_component_get_drvdata (component);@@ -875,6 +1247,7 @@ static const struct snd_soc_component_driver lpass_component_driver = { .mmap = lpass_platform_pcmops_mmap, .pcm_construct = lpass_platform_pcm_new, .pcm_destruct = lpass_platform_pcm_free, + .copy_user = lpass_platform_copy, .suspend = lpass_platform_pcmops_suspend, .resume = lpass_platform_pcmops_resume,@@ -914,6 +1287,60 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)return ret; } +if (drvdata->wcd_codec_enable) { + ret =regmap_write (drvdata->rxtx_lpaif_map, +LPAIF_RXTX_IRQEN_REG (v,LPAIF_IRQ_PORT_HOST ,LPASS_CDC_DMA_TX3 ),0x0 ); +if (ret) { +dev_err (&pdev->dev,"error writing to rxtx irqen reg: %d\n" , ret); +return ret; + } + ret =regmap_write (drvdata->va_lpaif_map, +LPAIF_RXTX_IRQEN_REG (v,LPAIF_IRQ_PORT_HOST ,LPASS_CDC_DMA_VA_TX0 ),0x0 ); +if (ret) { +dev_err (&pdev->dev,"error writing to rxtx irqen reg: %d\n" , ret); +return ret; + } + drvdata->rxtxif_irq =platform_get_irq_byname (pdev,"lpass-irq-rxtxif" ); +if (drvdata->rxtxif_irq <0 ) +return -ENODEV ; + + ret =devm_request_irq (&pdev->dev, drvdata->rxtxif_irq, + lpass_platform_rxtxif_irq,IRQF_TRIGGER_RISING , +"lpass-irq-rxtxif" , drvdata); +if (ret) { +dev_err (&pdev->dev,"rxtx irq request failed: %d\n" , ret); +return ret; + } + + ret =lpass_platform_alloc_rxtx_dmactl_fields (&pdev->dev, + drvdata->rxtx_lpaif_map); +if (ret) { +dev_err (&pdev->dev, +"error initializing rxtx dmactl fields: %d\n" , ret); +return ret; + } + + drvdata->vaif_irq =platform_get_irq_byname (pdev,"lpass-irq-vaif" ); +if (drvdata->vaif_irq <0 ) +return -ENODEV ; + + ret =devm_request_irq (&pdev->dev, drvdata->vaif_irq, + lpass_platform_vaif_irq,IRQF_TRIGGER_RISING , +"lpass-irq-vaif" , drvdata); +if (ret) { +dev_err (&pdev->dev,"va irq request failed: %d\n" , ret); +return ret; + } + + ret =lpass_platform_alloc_va_dmactl_fields (&pdev->dev, + drvdata->va_lpaif_map); +if (ret) { +dev_err (&pdev->dev, +"error initializing va dmactl fields: %d\n" , ret); +return ret; + } + } +if (drvdata->hdmi_port_enable) { drvdata->hdmiif_irq =platform_get_irq_byname (pdev,"lpass-irq-hdmi" );if (drvdata->hdmiif_irq <0 )Signature · 2 lines
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc., is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
Re: [PATCH 5/8] ASoC: qcom: Add support for codec dma driver
On 10/1/2021 10:22 PM, Matthias Kaehlcke wrote:
Thanks for your time Matthias!!!
Quoted 124 lines · Srinivasa Rao Mandadapu
Quoted 110 lines
Upadate lpass cpu and platform driver to support audio over codec dma in ADSP bypass use case.
Signed-off-by Venkata Prasad Potturu <[email protected]>Signed-off-by Srinivasa Rao Mandadapu <[email protected]>--- sound/soc/qcom/lpass-cpu.c | 312 ++++++++++++++++++++++++- sound/soc/qcom/lpass-platform.c | 499 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 773 insertions(+), 38 deletions(-)sound/soc/qcom/lpass-cpu.c +92
-0@@ -798,6 +798,251 @@ static struct regmap_config lpass_hdmi_regmap_config = { .cache_type = REGCACHE_FLAT, }; +static bool lpass_rxtx_regmap_writeable (struct device *dev,unsigned int reg) +{ +struct lpass_data *drvdata =dev_get_drvdata (dev); +struct lpass_variant *v = drvdata->variant; +int i; + +for (i =0 ; i < v->rxtx_irq_ports; ++i) { +if (reg ==LPAIF_RXTX_IRQCLEAR_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQEN_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQSTAT_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; + } + +for (i =0 ; i < v->rxtx_rdma_channels; ++i) { +if (reg ==LPAIF_CDC_RDMACTL_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMABASE_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMABUFF_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMAPER_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMA_INTF_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; + } + +for (i =0 ; i < v->rxtx_wrdma_channels; ++i) { +if (reg ==LPAIF_CDC_WRDMACTL_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMABASE_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMABUFF_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMAPER_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMA_INTF_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; + } + +return false; +} + +static bool lpass_rxtx_regmap_readable (struct device *dev,unsigned int reg) +{ +struct lpass_data *drvdata =dev_get_drvdata (dev); +struct lpass_variant *v = drvdata->variant; +int i; + +for (i =0 ; i < v->rxtx_irq_ports; ++i) { +if (reg ==LPAIF_RXTX_IRQCLEAR_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQEN_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQSTAT_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; + } + +for (i =0 ; i < v->rxtx_rdma_channels; ++i) { +if (reg ==LPAIF_CDC_RDMACTL_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMABASE_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMABUFF_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMACURR_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMAPER_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_CDC_RDMA_INTF_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; + } + +for (i =0 ; i < v->rxtx_wrdma_channels; ++i) { +if (reg ==LPAIF_CDC_WRDMACTL_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMABASE_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMABUFF_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMACURR_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true;sound/soc/qcom/lpass-cpu.c static struct regmap_config lpass_hdmi_regmap_config = { · line 902
Quoted 10 lines
sound/soc/qcom/lpass-cpu.c +10
-0+if (reg ==LPAIF_CDC_WRDMAPER_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; +if (reg ==LPAIF_CDC_WRDMA_INTF_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; + } + +return false; +}
lpass_rxtx_regmap_readable()is almost the same aslpass_rxtx_regmap_writeable(), except forLPAIF_CDC_RDMACURR_REGandLPAIF_CDC_WRDMACURR_REG. Add something like
Quoted 6 lines
static bool
__lpass_rxtx_regmap_accessible(struct device *dev, unsigned int reg, bool rw)which would look essentially like
lpass_rxtx_regmap_readable()but checks the 'rw' parameter forLPAIF_CDC_RDMACURR_REGandLPAIF_CDC_WRDMACURR_REG.lpass_rxtx_regmap_readable()andlpass_rxtx_regmap_writeable()then call this function with the corresponding value for 'rw'
Okay. Will change it accordingly.
Quoted 93 lines
Quoted 93 lines
sound/soc/qcom/lpass-cpu.c +93
-0+ +static bool lpass_rxtx_regmap_volatile (struct device *dev,unsigned int reg) +{ +struct lpass_data *drvdata =dev_get_drvdata (dev); +struct lpass_variant *v = drvdata->variant; +int i; + +for (i =0 ; i < v->rxtx_irq_ports; ++i) { +if (reg ==LPAIF_RXTX_IRQCLEAR_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQSTAT_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; + } + +for (i =0 ; i < v->rxtx_rdma_channels; ++i) +if (reg ==LPAIF_CDC_RDMACURR_REG (v, i,LPASS_CDC_DMA_RX0 )) +return true; + +for (i =0 ; i < v->rxtx_wrdma_channels; ++i) +if (reg ==LPAIF_CDC_WRDMACURR_REG (v, i + v->rxtx_wrdma_channel_start, +LPASS_CDC_DMA_TX3 )) +return true; + +return false; +} + +static bool lpass_va_regmap_writeable (struct device *dev,unsigned int reg) +{ +struct lpass_data *drvdata =dev_get_drvdata (dev); +struct lpass_variant *v = drvdata->variant; +int i; + +for (i =0 ; i < v->va_irq_ports; ++i) { +if (reg ==LPAIF_RXTX_IRQCLEAR_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQEN_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQSTAT_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; + } + +for (i =0 ; i < v->va_wrdma_channels; ++i) { +if (reg ==LPAIF_CDC_WRDMACTL_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMABASE_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMABUFF_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMAPER_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMA_INTF_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; + } + +return false; +} + +static bool lpass_va_regmap_readable (struct device *dev,unsigned int reg) +{ +struct lpass_data *drvdata =dev_get_drvdata (dev); +struct lpass_variant *v = drvdata->variant; +int i; + +for (i =0 ; i < v->va_irq_ports; ++i) { +if (reg ==LPAIF_RXTX_IRQCLEAR_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQEN_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQSTAT_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; + } + +for (i =0 ; i < v->va_wrdma_channels; ++i) { +if (reg ==LPAIF_CDC_WRDMACTL_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMABASE_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMABUFF_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMACURR_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_CDC_WRDMAPER_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true;
Quoted 8 lines
sound/soc/qcom/lpass-cpu.c static struct regmap_config lpass_hdmi_regmap_config = { · line 963
Quoted 7 lines
sound/soc/qcom/lpass-cpu.c +7
-0+if (reg ==LPAIF_CDC_WRDMA_INTF_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; + } + +return false; +}Same as for lpass_rxtx_regmap_readable/writable()
Okay. Will change it.
Quoted 93 lines
Quoted 93 lines
sound/soc/qcom/lpass-cpu.c +70
-1+ +static bool lpass_va_regmap_volatile (struct device *dev,unsigned int reg) +{ +struct lpass_data *drvdata =dev_get_drvdata (dev); +struct lpass_variant *v = drvdata->variant; +int i; + +for (i =0 ; i < v->va_irq_ports; ++i) { +if (reg ==LPAIF_RXTX_IRQCLEAR_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; +if (reg ==LPAIF_RXTX_IRQSTAT_REG (v, i,LPASS_CDC_DMA_VA_TX0 )) +return true; + } + +for (i =0 ; i < v->va_wrdma_channels; ++i) { +if (reg ==LPAIF_CDC_WRDMACURR_REG (v, i + v->va_wrdma_channel_start, +LPASS_CDC_DMA_VA_TX0 )) +return true; + } + +return false; +} + +static struct regmap_config lpass_rxtx_regmap_config = { + .reg_bits =32 , + .reg_stride =4 , + .val_bits =32 , + .writeable_reg = lpass_rxtx_regmap_writeable, + .readable_reg = lpass_rxtx_regmap_readable, + .volatile_reg = lpass_rxtx_regmap_volatile, + .cache_type =REGCACHE_FLAT , +}; + +static struct regmap_config lpass_va_regmap_config = { + .reg_bits =32 , + .reg_stride =4 , + .val_bits =32 , + .writeable_reg = lpass_va_regmap_writeable, + .readable_reg = lpass_va_regmap_readable, + .volatile_reg = lpass_va_regmap_volatile, + .cache_type =REGCACHE_FLAT , +}; +static unsigned int of_lpass_cpu_parse_sd_lines (struct device *dev,struct device_node *node,const char *name)@@ -837,6 +1082,17 @@ static unsigned int of_lpass_cpu_parse_sd_lines(struct device *dev, } } +static bool is_cdc_dma_port (int dai_id) +{ +switch (dai_id) { +case LPASS_CDC_DMA_RX0 : +case LPASS_CDC_DMA_TX3 : +case LPASS_CDC_DMA_VA_TX0 : +return true; +default : +return false; + } +}static void of_lpass_cpu_parse_dai_data (struct device *dev,struct lpass_data *data) {@@ -857,7 +1113,9 @@ static void of_lpass_cpu_parse_dai_data(struct device *dev, }if (id ==LPASS_DP_RX ) { data->hdmi_port_enable =1 ; - }else { + }else if (is_cdc_dma_port (id)) + data->wcd_codec_enable =1 ; +else { data->mi2s_playback_sd_mode[id] =of_lpass_cpu_parse_sd_lines (dev, node,"qcom,playback-sd-lines" );@@ -897,6 +1155,53 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)of_lpass_cpu_parse_dai_data (dev, drvdata); + drvdata->num_clks = variant->num_clks; +if (drvdata->wcd_codec_enable) { + drvdata->rxtx_lpaif = +devm_platform_ioremap_resource_byname (pdev,"lpass-rxtx-lpaif" ); +if (IS_ERR (drvdata->rxtx_lpaif)) +return PTR_ERR (drvdata->rxtx_lpaif); + + drvdata->va_lpaif =devm_platform_ioremap_resource_byname (pdev,"lpass-va-lpaif" ); +if (IS_ERR (drvdata->va_lpaif)) +return PTR_ERR (drvdata->va_lpaif); + + lpass_rxtx_regmap_config.max_register = LPAIF_CDC_WRDMAPER_REG(variant, + variant->rxtx_wrdma_channels +
Quoted 8 lines
sound/soc/qcom/lpass-cpu.c int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) · line 1176
Quoted 6 lines
sound/soc/qcom/lpass-cpu.c +6
-0+ variant->rxtx_wrdma_channel_start, LPASS_CDC_DMA_TX3); + + drvdata->rxtx_lpaif_map =devm_regmap_init_mmio (dev, drvdata->rxtx_lpaif, + &lpass_rxtx_regmap_config); +if (IS_ERR (drvdata->rxtx_lpaif_map)) { + dev_err(dev, "error initializing regmap: %ld\n",The same error is logged a few lines below, you might want to log which regmap couldn't be initialized.
Okay. will update it.
Quoted 3 lines
sound/soc/qcom/lpass-cpu.c int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) · line 1177
Quoted 2 lines
sound/soc/qcom/lpass-cpu.c +1
-0+ PTR_ERR(drvdata->rxtx_lpaif_map));fix indentation
Okay. will fix it.
Quoted 12 lines
sound/soc/qcom/lpass-cpu.c int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) · line 1187
Quoted 10 lines
sound/soc/qcom/lpass-cpu.c +10
-0+return PTR_ERR (drvdata->rxtx_lpaif_map); + } + lpass_va_regmap_config.max_register =LPAIF_CDC_WRDMAPER_REG (variant, + variant->va_wrdma_channels + + variant->va_wrdma_channel_start,LPASS_CDC_DMA_VA_TX0 ); + + drvdata->va_lpaif_map =devm_regmap_init_mmio (dev, drvdata->va_lpaif, + &lpass_va_regmap_config); +if (IS_ERR (drvdata->va_lpaif_map)) { + dev_err(dev, "error initializing regmap: %ld\n",see above
Quoted 2 lines
sound/soc/qcom/lpass-cpu.c int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) · line 1188
Quoted 1 line
sound/soc/qcom/lpass-cpu.c +1
-0+ PTR_ERR(drvdata->va_lpaif_map));fix indentation
Okay. will update it.
Quoted 53 lines
Quoted 53 lines
sound/soc/qcom/lpass-cpu.c +31
-3+return PTR_ERR (drvdata->va_lpaif_map); + } + drvdata->cdc_num_clks = variant->cdc_dma_num_clks; +for (i =0 ; i < variant->cdc_dma_num_clks; i++) { + drvdata->cdc_dma_clks[i] =devm_clk_get (dev, + variant->cdc_dma_clk_names[i]); +if (IS_ERR (drvdata->cdc_dma_clks[i])) { + vdata->lpaif_map; + } } ret = regmap_write(map, LPAIF_DMABASE_REG(v, ch, dir, dai_id),@@ -423,6 +578,16 @@ static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,return ret; } +if (dai_id ==LPASS_CDC_DMA_RX0 || + dai_id ==LPASS_CDC_DMA_TX3 || + dai_id ==LPASS_CDC_DMA_VA_TX0 ) { + ret =regmap_fields_write (dmactl->fifowm, id,LPAIF_DMACTL_FIFOWM_8 ); +if (ret) { +dev_err (soc_runtime->dev,"error writing fifowm field to dmactl reg: %d, id: %d\n" , + ret, id); +return ret; + } + } ret =regmap_fields_write (dmactl->enable, id,LPAIF_DMACTL_ENABLE_ON );if (ret) { dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",@@ -457,14 +622,27 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,if (dai_id ==LPASS_DP_RX ) { dmactl = drvdata->hdmi_rd_dmactl; map = drvdata->hdmiif_map; + }else if (dai_id ==LPASS_CDC_DMA_RX0 ) { + map = drvdata->rxtx_lpaif_map; + dmactl = drvdata->rxtx_rd_dmactl; }else { dmactl = drvdata->rd_dmactl; map = drvdata->lpaif_map; } }else { - dmactl = drvdata->wr_dmactl; - id = pcm_data->dma_ch - v->wrdma_channel_start; - map = drvdata->lpaif_map; +if (dai_id ==LPASS_CDC_DMA_TX3 ) { + dmactl = drvdata->rxtx_wr_dmactl; + map = drvdata->rxtx_lpaif_map; + id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start; + }else if (dai_id ==LPASS_CDC_DMA_VA_TX0 ) { + dmactl = drvdata->va_wr_dmactl; + map = drvdata->va_lpaif_map; + id = pcm_data->dma_ch - v->va_wrdma_channel_start; + }else {
Quoted 8 lines
sound/soc/qcom/lpass-cpu.c static int lpass_platform_pcmops_trigger(struct snd_soc_component *component, · line 645
Quoted 4 lines
sound/soc/qcom/lpass-cpu.c +4
-0+ dmactl = drvdata->wr_dmactl; + id = pcm_data->dma_ch - v->wrdma_channel_start; + map = drvdata->lpaif_map; + }As for "[4/8] ASoC: qcom: Add lapss CPU driver for codec dma control", I think you want a helper that encapsulates the above, instead of open coding it multiple times in the driver.
Okay Agreed. But will post as a separate patch.
Quoted 11 lines
Quoted 11 lines
sound/soc/qcom/lpass-cpu.c +4
-0}switch (cmd) {@@ -479,6 +657,24 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,return ret; }switch (dai_id) { +case LPASS_CDC_DMA_RX0 : +case LPASS_CDC_DMA_TX3 : +case LPASS_CDC_DMA_VA_TX0 : + ret =regmap_fields_write (dmactl->dyncclk, id,LPAIF_DMACTL_DYNCLK_ON );
Quoted 8 lines
sound/soc/qcom/lpass-cpu.c static int lpass_platform_pcmops_trigger(struct snd_soc_component *component, · line 670
Quoted 7 lines
sound/soc/qcom/lpass-cpu.c +7
-0+if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl reg field: %d\n" , ret); +return ret; + } + map = (dai_id ==LPASS_CDC_DMA_VA_TX0 ) ? + drvdata->va_lpaif_map : drvdata->rxtx_lpaif_map;'map' was already assigned earlier.
Okay. will remove it.
Quoted 19 lines
Quoted 19 lines
sound/soc/qcom/lpass-cpu.c +11
-0+ reg_irqclr =LPAIF_RXTX_IRQCLEAR_REG (v,LPAIF_IRQ_PORT_HOST , dai_id); + val_irqclr =LPAIF_IRQ_ALL (ch); + + reg_irqen =LPAIF_RXTX_IRQEN_REG (v,LPAIF_IRQ_PORT_HOST , dai_id); + val_mask =LPAIF_IRQ_ALL (ch); + val_irqen =LPAIF_IRQ_ALL (ch); +break ;case LPASS_DP_RX : ret =regmap_fields_write (dmactl->dyncclk, id,LPAIF_DMACTL_DYNCLK_ON );@@ -543,6 +739,26 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,return ret; }switch (dai_id) { +case LPASS_CDC_DMA_RX0 : +case LPASS_CDC_DMA_TX3 : +case LPASS_CDC_DMA_VA_TX0 : + ret =regmap_fields_write (dmactl->dyncclk, id,LPAIF_DMACTL_DYNCLK_OFF );
Quoted 8 lines
sound/soc/qcom/lpass-cpu.c static int lpass_platform_pcmops_trigger(struct snd_soc_component *component, · line 752
Quoted 7 lines
sound/soc/qcom/lpass-cpu.c +7
-0+if (ret) { +dev_err (soc_runtime->dev, +"error writing to rdmactl reg field: %d\n" , ret); +return ret; + } + map = (dai_id ==LPASS_CDC_DMA_VA_TX0 ) ? + drvdata->va_lpaif_map : drvdata->rxtx_lpaif_map;ditto
Okay.
Quoted 15 lines
Quoted 15 lines
sound/soc/qcom/lpass-cpu.c +9
-0+ + reg_irqclr =LPAIF_RXTX_IRQCLEAR_REG (v,LPAIF_IRQ_PORT_HOST , dai_id); + val_irqclr =LPAIF_IRQ_ALL (ch); + + reg_irqen =LPAIF_RXTX_IRQEN_REG (v,LPAIF_IRQ_PORT_HOST , dai_id); + val_mask =LPAIF_IRQ_ALL (ch); + val_irqen =LPAIF_IRQ_ALL (ch); + +break ;case LPASS_DP_RX : ret =regmap_fields_write (dmactl->dyncclk, id,LPAIF_DMACTL_DYNCLK_OFF );@@ -601,6 +817,12 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
Quoted 11 lines
sound/soc/qcom/lpass-cpu.c static snd_pcm_uframes_t lpass_platform_pcmops_pointer( · line 827
Quoted 10 lines
sound/soc/qcom/lpass-cpu.c +6
-0if (dai_id ==LPASS_DP_RX ) map = drvdata->hdmiif_map; +else if (dai_id ==LPASS_CDC_DMA_RX0 || + dai_id ==LPASS_CDC_DMA_TX3 || + dai_id ==LPASS_CDC_DMA_VA_TX0 ) + map = (dai_id ==LPASS_CDC_DMA_VA_TX0 ) ? + drvdata->va_lpaif_map : + drvdata->rxtx_lpaif_map;else map = drvdata->lpaif_map;use helper to get map from dai id
Okay. As existing code also needs changes, will do as a separate patch.
Quoted 15 lines
Quoted 15 lines
sound/soc/qcom/lpass-cpu.c +9
-0@@ -625,12 +847,39 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(return bytes_to_frames (substream->runtime, curr_addr - base_addr); } +static int lpass_platform_cdc_dma_mmap (struct snd_soc_component *component, +struct snd_pcm_substream *substream, +struct vm_area_struct *vma) +{ +struct snd_pcm_runtime *runtime = substream->runtime; +unsigned long size, offset; +int ret; + + vma->vm_page_prot =pgprot_noncached (vma->vm_page_prot);
Quoted 8 lines
sound/soc/qcom/lpass-cpu.c static snd_pcm_uframes_t lpass_platform_pcmops_pointer( · line 865
Quoted 7 lines
sound/soc/qcom/lpass-cpu.c +7
-0+ size = vma->vm_end - vma->vm_start; + offset = vma->vm_pgoff <<PAGE_SHIFT ; + ret =io_remap_pfn_range (vma, vma->vm_start, + (runtime->dma_addr + offset) >>PAGE_SHIFT , + size, vma->vm_page_prot); + +return ret;no need for 'ret' just 'return
io_remap_pfn_range(...);'
Okay. will change it.
Quoted 207 lines
Quoted 207 lines
sound/soc/qcom/lpass-cpu.c +133
-16+} +static int lpass_platform_pcmops_mmap (struct snd_soc_component *component,struct snd_pcm_substream *substream,struct vm_area_struct *vma) {struct snd_pcm_runtime *runtime = substream->runtime; +struct snd_soc_pcm_runtime *soc_runtime =asoc_substream_to_rtd (substream); +struct snd_soc_dai *cpu_dai =asoc_rtd_to_cpu (soc_runtime,0 ); +unsigned int dai_id = cpu_dai->driver->id; +if (dai_id ==LPASS_CDC_DMA_RX0 || + dai_id ==LPASS_CDC_DMA_TX3 || + dai_id ==LPASS_CDC_DMA_VA_TX0 ) { +lpass_platform_cdc_dma_mmap (component, substream, vma); +return 0 ; + }return dma_mmap_coherent (component->dev, vma, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes); }@@ -651,6 +900,14 @@ static irqreturn_t lpass_dma_interrupt_handler( mask =LPAIF_IRQ_ALL (chan);switch (dai_id) { +case LPASS_CDC_DMA_RX0 : +case LPASS_CDC_DMA_TX3 : +case LPASS_CDC_DMA_VA_TX0 : + map = (dai_id ==LPASS_CDC_DMA_VA_TX0 ) ? + drvdata->va_lpaif_map : drvdata->rxtx_lpaif_map; + reg =LPAIF_RXTX_IRQCLEAR_REG (v,LPAIF_IRQ_PORT_HOST , dai_id); + val =0 ; +break ;case LPASS_DP_RX : map = drvdata->hdmiif_map; reg =LPASS_HDMITX_APP_IRQCLEAR_REG (v);@@ -774,41 +1031,131 @@ static irqreturn_t lpass_platform_hdmiif_irq(int irq, void *data)return rv; } } +return IRQ_HANDLED ; +} + +static irqreturn_t lpass_platform_rxtxif_irq (int irq,void *data) +{ +struct lpass_data *drvdata = data; +struct lpass_variant *v = drvdata->variant; +unsigned int irqs; +int rv, chan; + + rv =regmap_read (drvdata->rxtx_lpaif_map, +LPAIF_RXTX_IRQSTAT_REG (v,LPAIF_IRQ_PORT_HOST ,LPASS_CDC_DMA_RX0 ), &irqs); +if (rv) +return IRQ_NONE ; +/* Handle per channel interrupts */ +for (chan =0 ; chan <LPASS_MAX_CDC_DMA_CHANNELS ; chan++) { +if (irqs &LPAIF_IRQ_ALL (chan) && drvdata->rxtx_substream[chan]) { + rv =lpass_dma_interrupt_handler ( + drvdata->rxtx_substream[chan], + drvdata, chan, irqs); +if (rv !=IRQ_HANDLED ) +return rv; + } + } + +return IRQ_HANDLED ; +} + +static irqreturn_t lpass_platform_vaif_irq (int irq,void *data) +{ +struct lpass_data *drvdata = data; +struct lpass_variant *v = drvdata->variant; +unsigned int irqs; +int rv, chan; + rv =regmap_read (drvdata->va_lpaif_map, +LPAIF_RXTX_IRQSTAT_REG (v,LPAIF_IRQ_PORT_HOST , +LPASS_CDC_DMA_VA_TX0 ), &irqs); +if (rv) +return IRQ_NONE ; +/* Handle per channel interrupts */ +for (chan =0 ; chan <LPASS_MAX_VA_CDC_DMA_CHANNELS ; chan++) { +if (irqs &LPAIF_IRQ_ALL (chan) && drvdata->va_substream[chan]) { + rv =lpass_dma_interrupt_handler ( + drvdata->va_substream[chan], + drvdata, chan, irqs); +if (rv !=IRQ_HANDLED ) +return rv; + } + }return IRQ_HANDLED ; } +static int lpass_platform_prealloc_cdc_dma_buffer (struct snd_pcm *pcm, +struct snd_pcm_substream *substream,int dai_id) +{ +struct snd_dma_buffer *buf = &substream->dma_buffer; +int ret; + + ret =dma_coerce_mask_and_coherent (pcm->card->dev,DMA_BIT_MASK (64 )); +if (ret) +return ret; + + buf->dev.dev = pcm->card->dev; + buf->private_data =NULL ; + +/* Assign Codec DMA buffer pointers */ + buf->dev.type =SNDRV_DMA_TYPE_CONTINUOUS ; +if (dai_id ==LPASS_CDC_DMA_RX0 ) { + buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max; + buf->addr =LPSAS_RXTX_CDC_DMA_LPM_ADDR ; + }else if (dai_id ==LPASS_CDC_DMA_TX3 ) { + buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max; + buf->addr =LPSAS_RXTX_CDC_DMA_LPM_ADDR +LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE ; + }else if (dai_id ==LPASS_CDC_DMA_VA_TX0 ) { + buf->bytes = lpass_platform_va_hardware.buffer_bytes_max; + buf->addr =LPSAS_VA_CDC_DMA_LPM_ADDR ; + } + + buf->area = (unsigned char *__force )ioremap (buf->addr, buf->bytes); + +return 0 ; +} +static int lpass_platform_pcm_new (struct snd_soc_component *component,struct snd_soc_pcm_runtime *soc_runtime) {struct snd_pcm *pcm = soc_runtime->pcm;struct snd_pcm_substream *psubstream, *csubstream;int ret; +struct snd_soc_dai *cpu_dai =asoc_rtd_to_cpu (soc_runtime,0 ); +unsigned int dai_id = cpu_dai->driver->id; +size_t size = lpass_platform_pcm_hardware.buffer_bytes_max; psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK ].substream;if (psubstream) { - ret =snd_dma_alloc_pages (SNDRV_DMA_TYPE_DEV , - component->dev, - size, &psubstream->dma_buffer); -if (ret) { -dev_err (soc_runtime->dev,"Cannot allocate buffer(s)\n" ); -return ret; +if (dai_id ==LPASS_CDC_DMA_RX0 ) { +lpass_platform_prealloc_cdc_dma_buffer (pcm, psubstream, dai_id); + }else { + ret =snd_dma_alloc_pages (SNDRV_DMA_TYPE_DEV , + component->dev, + size, &psubstream->dma_buffer); +if (ret) { +dev_err (soc_runtime->dev,"Cannot allocate buffer(s)\n" ); +return ret; + } } } csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE ].substream;if (csubstream) { - ret =snd_dma_alloc_pages (SNDRV_DMA_TYPE_DEV , - component->dev, - size, &csubstream->dma_buffer); -if (ret) { -dev_err (soc_runtime->dev,"Cannot allocate buffer(s)\n" ); -if (psubstream) -snd_dma_free_pages (&psubstream->dma_buffer); -return ret; +if (dai_id ==LPASS_CDC_DMA_TX3 || dai_id ==LPASS_CDC_DMA_VA_TX0 ) { +lpass_platform_prealloc_cdc_dma_buffer (pcm, csubstream, dai_id); + }else { + ret =snd_dma_alloc_pages (SNDRV_DMA_TYPE_DEV , + component->dev, + size, &csubstream->dma_buffer); +if (ret) { +dev_err (soc_runtime->dev,"Cannot allocate buffer(s)\n" ); +if (psubstream) +snd_dma_free_pages (&psubstream->dma_buffer); +return ret; + } } - }return 0 ;@@ -818,18 +1165,43 @@ static void lpass_platform_pcm_free(struct snd_soc_component *component, struct snd_pcm *pcm) {struct snd_pcm_substream *substream; +unsigned int dai_id = component->id;int i;for_each_pcm_streams (i) { substream = pcm->streams[i].substream;if (substream) { -snd_dma_free_pages (&substream->dma_buffer); +if (dai_id ==LPASS_CDC_DMA_RX0 || + dai_id ==LPASS_CDC_DMA_TX3 || + dai_id ==LPASS_CDC_DMA_VA_TX0 ) { +if (substream->dma_buffer.area) +iounmap ((void __iomem *)substream->dma_buffer.area); + }else { +snd_dma_free_pages (&substream->dma_buffer); + } substream->dma_buffer.area =NULL ; substream->dma_buffer.addr =0 ; } } }
Quoted 7 lines
sound/soc/qcom/lpass-cpu.c static void lpass_platform_pcm_free(struct snd_soc_component *component, · line 1193
Quoted 6 lines
sound/soc/qcom/lpass-cpu.c +6
-0+int lpass_platform_copy (struct snd_soc_component *component, +struct snd_pcm_substream *substream,int channel, +unsigned long pos,void __user *buf,unsigned long bytes) +{ +struct snd_pcm_runtime *rt = substream->runtime; +delete empty line
Okay. will remove it.
Quoted 12 lines
sound/soc/qcom/lpass-cpu.c static void lpass_platform_pcm_free(struct snd_soc_component *component, · line 1202
Quoted 10 lines
sound/soc/qcom/lpass-cpu.c +9
-0+unsigned char *dma_buf = rt->dma_area + pos + + channel * (rt->dma_bytes / rt->channels); + +if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) +return copy_from_user_toio (dma_buf, buf, bytes); +else if (substream->stream ==SNDRV_PCM_STREAM_CAPTURE ) +return copy_to_user_fromio (buf, dma_buf, bytes); + +return 0 ;Can '
substream->stream' have any other value thanSNDRV_PCM_STREAM_PLAYBACKorSNDRV_PCM_STREAM_CAPTURE? If not maybe return-EINVALhere?
Okay. will update it.
Quoted 78 lines
Quoted 78 lines
sound/soc/qcom/lpass-cpu.c +57
-0+} +static int lpass_platform_pcmops_suspend (struct snd_soc_component *component) {struct lpass_data *drvdata =snd_soc_component_get_drvdata (component);@@ -875,6 +1247,7 @@ static const struct snd_soc_component_driver lpass_component_driver = { .mmap = lpass_platform_pcmops_mmap, .pcm_construct = lpass_platform_pcm_new, .pcm_destruct = lpass_platform_pcm_free, + .copy_user = lpass_platform_copy, .suspend = lpass_platform_pcmops_suspend, .resume = lpass_platform_pcmops_resume,@@ -914,6 +1287,60 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)return ret; } +if (drvdata->wcd_codec_enable) { + ret =regmap_write (drvdata->rxtx_lpaif_map, +LPAIF_RXTX_IRQEN_REG (v,LPAIF_IRQ_PORT_HOST ,LPASS_CDC_DMA_TX3 ),0x0 ); +if (ret) { +dev_err (&pdev->dev,"error writing to rxtx irqen reg: %d\n" , ret); +return ret; + } + ret =regmap_write (drvdata->va_lpaif_map, +LPAIF_RXTX_IRQEN_REG (v,LPAIF_IRQ_PORT_HOST ,LPASS_CDC_DMA_VA_TX0 ),0x0 ); +if (ret) { +dev_err (&pdev->dev,"error writing to rxtx irqen reg: %d\n" , ret); +return ret; + } + drvdata->rxtxif_irq =platform_get_irq_byname (pdev,"lpass-irq-rxtxif" ); +if (drvdata->rxtxif_irq <0 ) +return -ENODEV ; + + ret =devm_request_irq (&pdev->dev, drvdata->rxtxif_irq, + lpass_platform_rxtxif_irq,IRQF_TRIGGER_RISING , +"lpass-irq-rxtxif" , drvdata); +if (ret) { +dev_err (&pdev->dev,"rxtx irq request failed: %d\n" , ret); +return ret; + } + + ret =lpass_platform_alloc_rxtx_dmactl_fields (&pdev->dev, + drvdata->rxtx_lpaif_map); +if (ret) { +dev_err (&pdev->dev, +"error initializing rxtx dmactl fields: %d\n" , ret); +return ret; + } + + drvdata->vaif_irq =platform_get_irq_byname (pdev,"lpass-irq-vaif" ); +if (drvdata->vaif_irq <0 ) +return -ENODEV ; + + ret =devm_request_irq (&pdev->dev, drvdata->vaif_irq, + lpass_platform_vaif_irq,IRQF_TRIGGER_RISING , +"lpass-irq-vaif" , drvdata); +if (ret) { +dev_err (&pdev->dev,"va irq request failed: %d\n" , ret); +return ret; + } + + ret =lpass_platform_alloc_va_dmactl_fields (&pdev->dev, + drvdata->va_lpaif_map); +if (ret) { +dev_err (&pdev->dev, +"error initializing va dmactl fields: %d\n" , ret); +return ret; + } + } +if (drvdata->hdmi_port_enable) { drvdata->hdmiif_irq =platform_get_irq_byname (pdev,"lpass-irq-hdmi" );if (drvdata->hdmiif_irq <0 )Signature · 2 lines
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc., is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
Signature · 2 lines
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc., is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
PATCH 6/8 ASoC: dt-bindings: Add SC7280 sound card bindings
In reply to Srinivasa Rao MandadapuAdd bindings for lpass sc7280 based soundcards which supports audio over i2s based speaker, soundwire based headset, msm dmics and HDMI Port.
--- .../devicetree/bindings/sound/qcom,lpass-cpu.yaml | 69 +++++++++++++++++++--- 1 file changed, 61 insertions(+), 8 deletions(-)
Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml +61 -8
@@ -22,35 +22,36 @@ properties: - qcom,lpass-cpu - qcom,apq8016-lpass-cpu - qcom,sc7180-lpass-cpu + - qcom,sc7280-lpass-cpu reg: - maxItems: 2 + maxItems: 5 description: LPAIF core registers reg-names: - maxItems: 2 + maxItems: 5 clocks: minItems: 3 - maxItems: 6 + maxItems: 7 clock-names: minItems: 3 - maxItems: 6 + maxItems: 7 interrupts: - maxItems: 2 + maxItems: 4 description: LPAIF DMA buffer interrupt interrupt-names: - maxItems: 2 + maxItems: 4 qcom,adsp: $ref: /schemas/types.yaml#/definitions/phandle description: Phandle for the audio DSP node iommus: - maxItems: 2 + maxItems: 3 description: Phandle to apps_smmu node with sid mask power-domains:
@@ -69,7 +70,7 @@ patternProperties: "^dai-link@[0-9a-f]$": type: object description: | - LPASS CPU dai node for each I2S device. Bindings of each node + LPASS CPU dai node for each I2S device or Soundwire device. Bindings of each node depends on the specific driver providing the functionality and properties. properties:
@@ -174,6 +175,58 @@ allOf: - iommus - power-domains + - if: + properties: + compatible: + contains: + const: qcom,sc7280-lpass-cpu + + then: + properties: + clock-names: + oneOf: + - items: #for I2S + - const: lpass_aon_cc_audio_hm_h_clk + - const: lpass_core_cc_sysnoc_mport_core_clk + - const: lpass_core_cc_ext_if1_ibit_clk + - items: #for Soundwire + - const: lpass_aon_cc_audio_hm_h_clk + - const: lpass_audio_cc_codec_mem0_clk + - const: lpass_audio_cc_codec_mem1_clk + - const: lpass_audio_cc_codec_mem2_clk + - items: #for HDMI + - const: lpass_aon_cc_audio_hm_h_clk + + reg-names: + anyOf: + - items: #for I2S + - const: lpass-lpaif + - items: #for I2S and HDMI + - const: lpass-hdmiif + - const: lpass-lpaif + - items: #for I2S, soundwire and HDMI + - const: lpass-cdc-lpm + - const: lpass-rxtx-lpaif + - const: lpass-va-lpaif + - const: lpass-hdmiif + - const: lpass-lpaif + interrupt-names: + anyOf: + - items: #for I2S + - const: lpass-irq-lpaif + - items: #for I2S and HDMI + - const: lpass-irq-lpaif + - const: lpass-irq-hdmi + - items: #for I2S, soundwire and HDMI + - const: lpass-irq-lpaif + - lpass-irq-vaif + - lpass-irq-rxtxif + - lpass-irq-hdmi + + required: + - iommus + - power-domains + examples: - | #include <dt-bindings/sound/sc7180-lpass.h>
Signature · 2 lines
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc., is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
Rob Herring
maintainerRe: [PATCH 6/8] ASoC: dt-bindings: Add SC7280 sound card bindings
Quoted 10 lines · Srinivasa Rao Mandadapu
Add bindings for lpass sc7280 based soundcards which supports audio over i2s based speaker, soundwire based headset, msm dmics and HDMI Port.
Signed-off-by Venkata Prasad Potturu <[email protected]>Signed-off-by Srinivasa Rao Mandadapu <[email protected]>--- .../devicetree/bindings/sound/qcom,lpass-cpu.yaml | 69 +++++++++++++++++++--- 1 file changed, 61 insertions(+), 8 deletions(-)
My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check' on your patch (DT_CHECKER_FLAGS is new in v5.13):
yamllint warnings/errors:
dtschema/dtc warnings/errors:
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml: allOf:3:then:properties:interrupt-names:anyOf:2:items: 'anyOf' conditional failed, one must be fixed:
[{'const': 'lpass-irq-lpaif'}, 'lpass-irq-vaif', 'lpass-irq-rxtxif', 'lpass-irq-hdmi'] is not of type 'object', 'boolean'
'lpass-irq-vaif' is not of type 'object', 'boolean'
'lpass-irq-rxtxif' is not of type 'object', 'boolean'
'lpass-irq-hdmi' is not of type 'object', 'boolean'
from schema $id: http://json-schema.org/draft-07/schema#
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml: ignoring, error in schema: allOf: 3: then: properties: interrupt-names: anyOf: 2: items
warning: no schema found in file: ./Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml Documentation/devicetree/bindings/sound/qcom,lpass-cpu.example.dt.yaml:0:0: /example-0/soc/lpass@62d80000: failed to match any schema with compatible: ['qcom,sc7180-lpass-cpu']
doc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/patch/1535291
This check can fail if there are any dependencies. The base for a patch series is generally the most recent rc1.
If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure 'yamllint' is installed and dt-schema is up to date:
pip3 install dtschema --upgrade
Please check and re-submit.
PATCH 7/8 ASoC: qcom: lpass-sc7280: Add platform driver for lpass audio
In reply to Srinivasa Rao MandadapuAdd platform driver for configuring sc7280 lpass core I2S and DMA configuration to support playback & capture to external codecs connected over secondary MI2S interface and soundwire interface.
--- sound/soc/qcom/lpass-sc7280.c | 600 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 600 insertions(+) create mode 100644 sound/soc/qcom/lpass-sc7280.c
sound/soc/qcom/lpass-sc7280.c new file +600 -0
@@ -0,0 +1,600 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* +* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. +* +* lpass-sc7180.c -- ALSA SoC platform-machine driver for QTi LPASS +*/ + +#include <linux/module.h> +#include <sound/pcm.h> +#include <sound/soc.h> +#include <linux/pm_domain.h> +#include <linux/pm_runtime.h> + +#include <dt-bindings/sound/sc7180-lpass.h> + +#include "lpass-lpaif-reg.h" +#include "lpass.h" + +static struct snd_soc_dai_driver sc7280_lpass_cpu_dai_driver[] = { + { + .id =LPASS_CDC_DMA_RX0 , + .name ="CDC DMA RX" , + .playback = { + .stream_name ="WCD Playback" , + .formats =SNDRV_PCM_FMTBIT_S16 , + .rates =SNDRV_PCM_RATE_48000 , + .rate_min =48000 , + .rate_max =48000 , + .channels_min =2 , + .channels_max =2 , + }, + .ops = &asoc_qcom_lpass_wcd_dai_ops, + }, + { + .id =LPASS_CDC_DMA_TX3 , + .name ="CDC DMA TX" , + .capture = { + .stream_name ="WCD Capture" , + .formats =SNDRV_PCM_FMTBIT_S16 , + .rates =SNDRV_PCM_RATE_48000 , + .rate_min =48000 , + .rate_max =48000 , + .channels_min =1 , + .channels_max =2 , + }, + .ops = &asoc_qcom_lpass_wcd_dai_ops, + }, + + { + .id =MI2S_SECONDARY , + .name ="Secondary MI2S" , + .playback = { + .stream_name ="Secondary MI2S Playback" , + .formats =SNDRV_PCM_FMTBIT_S16 , + .rates =SNDRV_PCM_RATE_48000 , + .rate_min =48000 , + .rate_max =48000 , + .channels_min =2 , + .channels_max =2 , + }, + .probe = &asoc_qcom_lpass_cpu_dai_probe, + .ops = &asoc_qcom_lpass_cpu_dai_ops, + }, + { + .id =LPASS_DP_RX , + .name ="Hdmi" , + .playback = { + .stream_name ="DP Playback" , + .formats =SNDRV_PCM_FMTBIT_S24 , + .rates =SNDRV_PCM_RATE_48000 , + .rate_min =48000 , + .rate_max =48000 , + .channels_min =2 , + .channels_max =2 , + }, + .ops = &asoc_qcom_lpass_hdmi_dai_ops, + }, + { + .id =LPASS_CDC_DMA_VA_TX0 , + .name ="CDC DMA VA" , + .capture = { + .stream_name ="DMIC Capture" , + .formats =SNDRV_PCM_FMTBIT_S16 , + .rates =SNDRV_PCM_RATE_48000 , + .rate_min =48000 , + .rate_max =48000 , + .channels_min =2 , + .channels_max =4 , + }, + .ops = &asoc_qcom_lpass_wcd_dai_ops, + }, +}; + +static int sc7280_lpass_alloc_dma_channel (struct lpass_data *drvdata, +int direction,unsigned int dai_id) +{ +struct lpass_variant *v = drvdata->variant; +int chan =0 ; + +if (dai_id ==LPASS_CDC_DMA_RX0 || + dai_id ==LPASS_CDC_DMA_TX3 ) { +if (direction ==SNDRV_PCM_STREAM_PLAYBACK ) { + chan =find_first_zero_bit (&drvdata->rxtx_dma_ch_bit_map, + v->rxtx_rdma_channels); + +if (chan >= v->rxtx_rdma_channels) +return -EBUSY ; + }else { + chan =find_next_zero_bit (&drvdata->rxtx_dma_ch_bit_map, + v->rxtx_wrdma_channel_start + + v->rxtx_wrdma_channels, + v->rxtx_wrdma_channel_start); + +if (chan >= v->rxtx_wrdma_channel_start + v->rxtx_wrdma_channels) +return -EBUSY ; + } + +set_bit (chan, &drvdata->rxtx_dma_ch_bit_map); + }else if (dai_id ==LPASS_CDC_DMA_VA_TX0 ) { +if (direction ==SNDRV_PCM_STREAM_PLAYBACK ) { + chan =find_first_zero_bit (&drvdata->va_dma_ch_bit_map, + v->va_rdma_channels); + +if (chan >= v->va_rdma_channels) +return -EBUSY ; + }else { + chan =find_next_zero_bit (&drvdata->va_dma_ch_bit_map, + v->va_wrdma_channel_start + + v->va_wrdma_channels, + v->va_wrdma_channel_start); + +if (chan >= v->va_wrdma_channel_start + v->va_wrdma_channels) +return -EBUSY ; + } + +set_bit (chan, &drvdata->va_dma_ch_bit_map); + }else if (dai_id ==LPASS_DP_RX ) { +if (direction ==SNDRV_PCM_STREAM_PLAYBACK ) { + chan =find_first_zero_bit (&drvdata->hdmi_dma_ch_bit_map, + v->hdmi_rdma_channels); + +if (chan >= v->hdmi_rdma_channels) +return -EBUSY ; + } +set_bit (chan, &drvdata->hdmi_dma_ch_bit_map); + }else { +if (direction ==SNDRV_PCM_STREAM_PLAYBACK ) { + chan =find_first_zero_bit (&drvdata->dma_ch_bit_map, + v->rdma_channels); + +if (chan >= v->rdma_channels) +return -EBUSY ; + }else { + chan =find_next_zero_bit (&drvdata->dma_ch_bit_map, + v->wrdma_channel_start + + v->wrdma_channels, + v->wrdma_channel_start); + +if (chan >= v->wrdma_channel_start + v->wrdma_channels) +return -EBUSY ; + } +set_bit (chan, &drvdata->dma_ch_bit_map); + } +return chan; +} + +static int sc7280_lpass_free_dma_channel (struct lpass_data *drvdata,int chan,unsigned int dai_id) +{ +if (dai_id ==LPASS_CDC_DMA_RX0 || + dai_id ==LPASS_CDC_DMA_TX3 ) +clear_bit (chan, &drvdata->rxtx_dma_ch_bit_map); +else if (dai_id ==LPASS_CDC_DMA_VA_TX0 ) +clear_bit (chan, &drvdata->va_dma_ch_bit_map); +else if (dai_id ==LPASS_DP_RX ) +clear_bit (chan, &drvdata->hdmi_dma_ch_bit_map); +else +clear_bit (chan, &drvdata->dma_ch_bit_map); + +return 0 ; +} + +static int lpass_sc7280_pds_enable (struct platform_device *pdev) +{ +int ret; +int i; +struct lpass_data *drvdata =platform_get_drvdata (pdev); +struct lpass_variant *variant = drvdata->variant; +struct device **pds = variant->proxy_pds; +size_t pd_count = variant->proxy_pd_count; + +for (i =0 ; i < pd_count; i++) { +dev_pm_genpd_set_performance_state (pds[i],INT_MAX ); + ret =pm_runtime_get_sync (pds[i]); +if (ret <0 ) { +pm_runtime_put_noidle (pds[i]); +dev_pm_genpd_set_performance_state (pds[i],0 ); + goto unroll_pd_votes; + } + } + pds = variant->active_pds; + pd_count = variant->active_pd_count; + +for (i =0 ; i < pd_count; i++) { +dev_pm_genpd_set_performance_state (pds[i],INT_MAX ); + ret =pm_runtime_get_sync (pds[i]); +if (ret <0 ) { +pm_runtime_put_noidle (pds[i]); +dev_pm_genpd_set_performance_state (pds[i],0 ); + goto unroll_pd_votes; + } + } +return 0 ; + +unroll_pd_votes: +for (i--; i >=0 ; i--) { +dev_pm_genpd_set_performance_state (pds[i],0 ); +pm_runtime_put (pds[i]); + } +return ret; +}; + +static void lpass_sc7280_pds_disable (struct platform_device *pdev) +{ +int i; +struct lpass_data *drvdata =platform_get_drvdata (pdev); +struct lpass_variant *variant = drvdata->variant; +struct device **pds = variant->proxy_pds; +size_t pd_count = variant->proxy_pd_count; + +for (i =0 ; i < pd_count; i++) { +dev_pm_genpd_set_performance_state (pds[i],0 ); +pm_runtime_put (pds[i]); + } + + pds = variant->active_pds; + pd_count = variant->active_pd_count; + +for (i =0 ; i < pd_count; i++) { +dev_pm_genpd_set_performance_state (pds[i],0 ); +pm_runtime_put (pds[i]); + } +} + +static int lpass_sc7280_pds_attach (struct platform_device *pdev) +{ +int ret; +int i; +struct lpass_data *drvdata =platform_get_drvdata (pdev); +struct lpass_variant *variant = drvdata->variant; +struct device *dev = &pdev->dev; +const char *const *pd_names = variant->proxy_pd_names; +struct device **devs = variant->proxy_pds; +size_t num_pds = variant->proxy_pd_count; + +if (!pd_names) +return 0 ; + +/* Handle single power domain */ +if (dev->pm_domain) { + devs[0 ] = dev; +pm_runtime_enable (dev); +return 1 ; + } + +for (i =0 ; i < num_pds; i++) { + devs[i] =dev_pm_domain_attach_by_name (dev, pd_names[i]); +if (IS_ERR_OR_NULL (devs[i])) { + ret =PTR_ERR (devs[i]) ? : -ENODATA ; + goto unroll_attach; + } + } + + pd_names = variant->active_pd_names; + devs = variant->active_pds; + num_pds = variant->active_pd_count; +for (i =0 ; i < num_pds; i++) { + devs[i] =dev_pm_domain_attach_by_name (dev, pd_names[i]); +if (IS_ERR_OR_NULL (devs[i])) { + ret =PTR_ERR (devs[i]) ? : -ENODATA ; + goto unroll_attach; + } + } +return 0 ; + +unroll_attach: +for (i--; i >=0 ; i--) +dev_pm_domain_detach (devs[i], false); + +return ret; +}; + +static void lpass_sc7280_pds_detach (struct platform_device *pdev) +{ +int i; +struct lpass_data *drvdata =platform_get_drvdata (pdev); +struct lpass_variant *variant = drvdata->variant; +struct device *dev = &pdev->dev; +struct device **pds = variant->proxy_pds; +size_t pd_count = variant->proxy_pd_count; + +/* Handle single power domain */ +if (dev->pm_domain && pd_count) { +pm_runtime_disable (dev); +return ; + } + +for (i =0 ; i < pd_count; i++) +dev_pm_domain_detach (pds[i], false); + + pds = variant->active_pds; + pd_count = variant->active_pd_count; + +/* Handle single power domain */ +if (dev->pm_domain && pd_count) { +pm_runtime_disable (dev); +return ; + } + +for (i =0 ; i < pd_count; i++) +dev_pm_domain_detach (pds[i], false); +} + +static int sc7280_lpass_pds_init (struct platform_device *pdev) +{ +struct device *dev = &pdev->dev; +int ret; + + ret =lpass_sc7280_pds_attach (pdev); +if (ret) { +dev_err (dev,"Failed to attach power domains %d\n" , ret); +return ret; + } + ret =lpass_sc7280_pds_enable (pdev); +if (ret) { +lpass_sc7280_pds_detach (pdev); +dev_err (dev,"Failed to enable power domains %d\n" , ret); +return ret; + } + +return 0 ; +} + +static void sc7280_lpass_pds_exit (struct platform_device *pdev) +{ +lpass_sc7280_pds_disable (pdev); +lpass_sc7280_pds_detach (pdev); +} + +static int sc7280_lpass_init (struct platform_device *pdev) +{ +struct lpass_data *drvdata =platform_get_drvdata (pdev); +struct lpass_variant *variant = drvdata->variant; +struct device *dev = &pdev->dev; +int ret; + + drvdata->clks =devm_kcalloc (dev, variant->num_clks, +sizeof (*drvdata->clks),GFP_KERNEL ); + drvdata->num_clks = variant->num_clks; + + drvdata->aon_cc_audio_hm_h =devm_clk_get (dev,"lpass_aon_cc_audio_hm_h_clk" ); +if (IS_ERR (drvdata->aon_cc_audio_hm_h)) +return PTR_ERR (drvdata->aon_cc_audio_hm_h); + drvdata->core_cc_sysnoc_mport_core =devm_clk_get (dev, +"lpass_core_cc_sysnoc_mport_core_clk" ); +if (IS_ERR (drvdata->core_cc_sysnoc_mport_core)) +return PTR_ERR (drvdata->core_cc_sysnoc_mport_core); + + ret =sc7280_lpass_pds_init (pdev); +if (ret) { +dev_err (dev,"sc7280 power domains init failed\n" ); +return ret; + } +clk_prepare_enable (drvdata->aon_cc_audio_hm_h); +clk_prepare_enable (drvdata->core_cc_sysnoc_mport_core); +return 0 ; +} + +static int sc7280_lpass_exit (struct platform_device *pdev) +{ +struct lpass_data *drvdata =platform_get_drvdata (pdev); + +clk_disable_unprepare (drvdata->core_cc_sysnoc_mport_core); +clk_disable_unprepare (drvdata->aon_cc_audio_hm_h); + +sc7280_lpass_pds_exit (pdev); +return 0 ; +} + +static struct lpass_variant sc7280_data = { + .i2sctrl_reg_base =0x1000 , + .i2sctrl_reg_stride =0x1000 , + .i2s_ports =3 , + .irq_reg_base =0x9000 , + .irq_reg_stride =0x1000 , + .irq_ports =3 , + .rdma_reg_base =0xC000 , + .rdma_reg_stride =0x1000 , + .rdma_channels =5 , + .rxtx_rdma_reg_base =0xC000 , + .rxtx_rdma_reg_stride =0x1000 , + .rxtx_rdma_channels =8 , + .hdmi_rdma_reg_base =0x64000 , + .hdmi_rdma_reg_stride =0x1000 , + .hdmi_rdma_channels =4 , + .dmactl_audif_start =1 , + .wrdma_reg_base =0x18000 , + .wrdma_reg_stride =0x1000 , + .wrdma_channel_start =5 , + .wrdma_channels =4 , + .rxtx_irq_reg_base =0x9000 , + .rxtx_irq_reg_stride =0x1000 , + .rxtx_irq_ports =3 , + .rxtx_wrdma_reg_base =0x18000 , + .rxtx_wrdma_reg_stride =0x1000 , + .rxtx_wrdma_channel_start =5 , + .rxtx_wrdma_channels =6 , + .va_wrdma_reg_base =0x18000 , + .va_wrdma_reg_stride =0x1000 , + .va_wrdma_channel_start =5 , + .va_wrdma_channels =3 , + .va_irq_reg_base =0x9000 , + .va_irq_reg_stride =0x1000 , + .va_irq_ports =3 , + + .loopback =REG_FIELD_ID (0x1000 ,17 ,17 ,3 ,0x1000 ), + .spken =REG_FIELD_ID (0x1000 ,16 ,16 ,3 ,0x1000 ), + .spkmode =REG_FIELD_ID (0x1000 ,11 ,15 ,3 ,0x1000 ), + .spkmono =REG_FIELD_ID (0x1000 ,10 ,10 ,3 ,0x1000 ), + .micen =REG_FIELD_ID (0x1000 ,9 ,9 ,3 ,0x1000 ), + .micmode =REG_FIELD_ID (0x1000 ,4 ,8 ,3 ,0x1000 ), + .micmono =REG_FIELD_ID (0x1000 ,3 ,3 ,3 ,0x1000 ), + .wssrc =REG_FIELD_ID (0x1000 ,2 ,2 ,3 ,0x1000 ), + .bitwidth =REG_FIELD_ID (0x1000 ,0 ,1 ,3 ,0x1000 ), + + .rdma_dyncclk =REG_FIELD_ID (0xC000 ,21 ,21 ,5 ,0x1000 ), + .rdma_bursten =REG_FIELD_ID (0xC000 ,20 ,20 ,5 ,0x1000 ), + .rdma_wpscnt =REG_FIELD_ID (0xC000 ,16 ,19 ,5 ,0x1000 ), + .rdma_intf =REG_FIELD_ID (0xC000 ,12 ,15 ,5 ,0x1000 ), + .rdma_fifowm =REG_FIELD_ID (0xC000 ,1 ,5 ,5 ,0x1000 ), + .rdma_enable =REG_FIELD_ID (0xC000 ,0 ,0 ,5 ,0x1000 ), + + .rxtx_rdma_enable =REG_FIELD_ID (0xC000 ,0 ,0 ,7 ,0x1000 ), + .rxtx_rdma_fifowm =REG_FIELD_ID (0xC000 ,1 ,11 ,7 ,0x1000 ), + .rxtx_rdma_intf =REG_FIELD_ID (0xC000 ,12 ,15 ,7 ,0x1000 ), + .rxtx_rdma_wpscnt =REG_FIELD_ID (0xC000 ,16 ,19 ,7 ,0x1000 ), + .rxtx_rdma_bursten =REG_FIELD_ID (0xC000 ,20 ,20 ,7 ,0x1000 ), + .rxtx_rdma_dyncclk =REG_FIELD_ID (0xC000 ,21 ,21 ,7 ,0x1000 ), + + .rxtx_rdma_codec_ch =REG_FIELD_ID (0xC050 ,0 ,7 ,7 ,0x1000 ), + .rxtx_rdma_codec_intf =REG_FIELD_ID (0xC050 ,16 ,19 ,7 ,0x1000 ), + .rxtx_rdma_codec_fs_delay =REG_FIELD_ID (0xC050 ,21 ,24 ,7 ,0x1000 ), + .rxtx_rdma_codec_fs_sel =REG_FIELD_ID (0xC050 ,25 ,27 ,7 ,0x1000 ), + .rxtx_rdma_codec_pack =REG_FIELD_ID (0xC050 ,29 ,29 ,5 ,0x1000 ), + .rxtx_rdma_codec_enable =REG_FIELD_ID (0xC050 ,30 ,30 ,7 ,0x1000 ), + + .rxtx_wrdma_enable =REG_FIELD_ID (0x18000 ,0 ,0 ,5 ,0x1000 ), + .rxtx_wrdma_fifowm =REG_FIELD_ID (0x18000 ,1 ,11 ,5 ,0x1000 ), + .rxtx_wrdma_intf =REG_FIELD_ID (0x18000 ,12 ,16 ,5 ,0x1000 ), + .rxtx_wrdma_wpscnt =REG_FIELD_ID (0x18000 ,17 ,20 ,5 ,0x1000 ), + .rxtx_wrdma_bursten =REG_FIELD_ID (0x18000 ,21 ,21 ,5 ,0x1000 ), + .rxtx_wrdma_dyncclk =REG_FIELD_ID (0x18000 ,22 ,22 ,5 ,0x1000 ), + + .rxtx_wrdma_codec_ch =REG_FIELD_ID (0x18050 ,0 ,7 ,5 ,0x1000 ), + .rxtx_wrdma_codec_intf =REG_FIELD_ID (0x18050 ,16 ,19 ,5 ,0x1000 ), + .rxtx_wrdma_codec_fs_delay =REG_FIELD_ID (0x18050 ,21 ,24 ,5 ,0x1000 ), + .rxtx_wrdma_codec_fs_sel =REG_FIELD_ID (0x18050 ,25 ,27 ,5 ,0x1000 ), + .rxtx_wrdma_codec_pack =REG_FIELD_ID (0x18050 ,29 ,29 ,5 ,0x1000 ), + .rxtx_wrdma_codec_enable =REG_FIELD_ID (0x18050 ,30 ,30 ,5 ,0x1000 ), + + .va_wrdma_enable =REG_FIELD_ID (0x18000 ,0 ,0 ,5 ,0x1000 ), + .va_wrdma_fifowm =REG_FIELD_ID (0x18000 ,1 ,11 ,5 ,0x1000 ), + .va_wrdma_intf =REG_FIELD_ID (0x18000 ,12 ,16 ,5 ,0x1000 ), + .va_wrdma_wpscnt =REG_FIELD_ID (0x18000 ,17 ,20 ,5 ,0x1000 ), + .va_wrdma_bursten =REG_FIELD_ID (0x18000 ,21 ,21 ,5 ,0x1000 ), + .va_wrdma_dyncclk =REG_FIELD_ID (0x18000 ,22 ,22 ,5 ,0x1000 ), + + .va_wrdma_codec_ch =REG_FIELD_ID (0x18050 ,0 ,7 ,5 ,0x1000 ), + .va_wrdma_codec_intf =REG_FIELD_ID (0x18050 ,16 ,19 ,5 ,0x1000 ), + .va_wrdma_codec_fs_delay =REG_FIELD_ID (0x18050 ,21 ,24 ,5 ,0x1000 ), + .va_wrdma_codec_fs_sel =REG_FIELD_ID (0x18050 ,25 ,27 ,5 ,0x1000 ), + .va_wrdma_codec_pack =REG_FIELD_ID (0x18050 ,29 ,29 ,5 ,0x1000 ), + .va_wrdma_codec_enable =REG_FIELD_ID (0x18050 ,30 ,30 ,5 ,0x1000 ), + + .hdmi_tx_ctl_addr =0x1000 , + .hdmi_legacy_addr =0x1008 , + .hdmi_vbit_addr =0x610c0 , + .hdmi_ch_lsb_addr =0x61048 , + .hdmi_ch_msb_addr =0x6104c , + .ch_stride =0x8 , + .hdmi_parity_addr =0x61034 , + .hdmi_dmactl_addr =0x61038 , + .hdmi_dma_stride =0x4 , + .hdmi_DP_addr =0x610c8 , + .hdmi_sstream_addr =0x6101c , + .hdmi_irq_reg_base =0x63000 , + .hdmi_irq_ports =1 , + + .hdmi_rdma_dyncclk =REG_FIELD_ID (0x64000 ,14 ,14 ,4 ,0x1000 ), + .hdmi_rdma_bursten =REG_FIELD_ID (0x64000 ,13 ,13 ,4 ,0x1000 ), + .hdmi_rdma_burst8 =REG_FIELD_ID (0x64000 ,15 ,15 ,4 ,0x1000 ), + .hdmi_rdma_burst16 =REG_FIELD_ID (0x64000 ,16 ,16 ,4 ,0x1000 ), + .hdmi_rdma_dynburst =REG_FIELD_ID (0x64000 ,18 ,18 ,4 ,0x1000 ), + .hdmi_rdma_wpscnt =REG_FIELD_ID (0x64000 ,10 ,12 ,4 ,0x1000 ), + .hdmi_rdma_fifowm =REG_FIELD_ID (0x64000 ,1 ,5 ,4 ,0x1000 ), + .hdmi_rdma_enable =REG_FIELD_ID (0x64000 ,0 ,0 ,4 ,0x1000 ), + + .sstream_en =REG_FIELD (0x6101c ,0 ,0 ), + .dma_sel =REG_FIELD (0x6101c ,1 ,2 ), + .auto_bbit_en =REG_FIELD (0x6101c ,3 ,3 ), + .layout =REG_FIELD (0x6101c ,4 ,4 ), + .layout_sp =REG_FIELD (0x6101c ,5 ,8 ), + .set_sp_on_en =REG_FIELD (0x6101c ,10 ,10 ), + .dp_audio =REG_FIELD (0x6101c ,11 ,11 ), + .dp_staffing_en =REG_FIELD (0x6101c ,12 ,12 ), + .dp_sp_b_hw_en =REG_FIELD (0x6101c ,13 ,13 ), + + .mute =REG_FIELD (0x610c8 ,0 ,0 ), + .as_sdp_cc =REG_FIELD (0x610c8 ,1 ,3 ), + .as_sdp_ct =REG_FIELD (0x610c8 ,4 ,7 ), + .aif_db4 =REG_FIELD (0x610c8 ,8 ,15 ), + .frequency =REG_FIELD (0x610c8 ,16 ,21 ), + .mst_index =REG_FIELD (0x610c8 ,28 ,29 ), + .dptx_index =REG_FIELD (0x610c8 ,30 ,31 ), + + .soft_reset =REG_FIELD (0x1000 ,31 ,31 ), + .force_reset =REG_FIELD (0x1000 ,30 ,30 ), + + .use_hw_chs =REG_FIELD (0x61038 ,0 ,0 ), + .use_hw_usr =REG_FIELD (0x61038 ,1 ,1 ), + .hw_chs_sel =REG_FIELD (0x61038 ,2 ,4 ), + .hw_usr_sel =REG_FIELD (0x61038 ,5 ,6 ), + + .replace_vbit =REG_FIELD (0x610c0 ,0 ,0 ), + .vbit_stream =REG_FIELD (0x610c0 ,1 ,1 ), + + .legacy_en =REG_FIELD (0x1008 ,0 ,0 ), + .calc_en =REG_FIELD (0x61034 ,0 ,0 ), + .lsb_bits =REG_FIELD (0x61048 ,0 ,31 ), + .msb_bits =REG_FIELD (0x6104c ,0 ,31 ), + + + .clk_name = (const char *[]) { +"lpass_aon_cc_audio_hm_h_clk" , +"lpass_core_cc_sysnoc_mport_core_clk" + }, + .num_clks =2 , + .cdc_dma_clk_names = (const char *[]) { +"lpass_audio_cc_codec_mem0_clk" , +"lpass_audio_cc_codec_mem1_clk" , +"lpass_audio_cc_codec_mem2_clk" , +"lpass_aon_cc_va_mem0_clk" + }, + .cdc_dma_num_clks =4 , + .dai_driver = sc7280_lpass_cpu_dai_driver, + .num_dai =ARRAY_SIZE (sc7280_lpass_cpu_dai_driver), + .dai_osr_clk_names = (const char *[]) { +"null" , +"null" + }, + .dai_bit_clk_names = (const char *[]) { +"null" , +"lpass_core_cc_ext_if0_ibit_clk" , +"lpass_core_cc_ext_if1_ibit_clk" + }, + .active_pd_names = (const char *[]){ +NULL + }, + .active_pd_count =0 , + .proxy_pd_names = (const char *[]){ +"lcx" , +NULL + }, + .proxy_pd_count =1 , + .init = sc7280_lpass_init, + .exit = sc7280_lpass_exit, + .alloc_dma_channel = sc7280_lpass_alloc_dma_channel, + .free_dma_channel = sc7280_lpass_free_dma_channel, +}; + +static const struct of_device_id sc7280_lpass_cpu_device_id[] = { + {.compatible ="qcom,sc7280-lpass-cpu" , .data = &sc7280_data}, + {} +}; +MODULE_DEVICE_TABLE (of, sc7280_lpass_cpu_device_id); + +static struct platform_driver sc7280_lpass_cpu_platform_driver = { + .driver = { + .name ="sc7280-lpass-cpu" , + .of_match_table =of_match_ptr (sc7280_lpass_cpu_device_id), + }, + .probe = asoc_qcom_lpass_cpu_platform_probe, + .remove = asoc_qcom_lpass_cpu_platform_remove, + .shutdown = asoc_qcom_lpass_cpu_platform_shutdown, +}; + +module_platform_driver (sc7280_lpass_cpu_platform_driver); + +MODULE_DESCRIPTION ("SC7280 LPASS CPU DRIVER" ); +MODULE_LICENSE ("GPL v2" ); +
Signature · 2 lines
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc., is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
PATCH 8/8 ASoc: qcom: lpass: Add suspend and resume for sc7280 platform
In reply to Srinivasa Rao MandadapuAdds device suspend and resume callbacks for sc7280 platform driver ops.
--- sound/soc/qcom/lpass-cpu.c | 22 ++++++++++++++++++++++ sound/soc/qcom/lpass-sc7280.c | 2 ++ sound/soc/qcom/lpass.h | 2 ++ 3 files changed, 26 insertions(+)
sound/soc/qcom/lpass-cpu.c +22 -0
@@ -1307,6 +1307,28 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) }EXPORT_SYMBOL_GPL (asoc_qcom_lpass_cpu_platform_probe); +int asoc_qcom_lpass_cpu_platform_resume (struct platform_device *pdev) +{ +struct lpass_data *drvdata =platform_get_drvdata (pdev); + +if (drvdata->variant->init) + drvdata->variant->init (pdev); + +return 0 ; +} +EXPORT_SYMBOL_GPL (asoc_qcom_lpass_cpu_platform_resume); + +int asoc_qcom_lpass_cpu_platform_suspend (struct platform_device *pdev,pm_message_t state) +{ +struct lpass_data *drvdata =platform_get_drvdata (pdev); + +if (drvdata->variant->exit) + drvdata->variant->exit (pdev); + +return 0 ; +} +EXPORT_SYMBOL_GPL (asoc_qcom_lpass_cpu_platform_suspend); +int asoc_qcom_lpass_cpu_platform_remove (struct platform_device *pdev) {struct lpass_data *drvdata =platform_get_drvdata (pdev);
sound/soc/qcom/lpass-sc7280.c +2 -0
@@ -591,6 +591,8 @@ static struct platform_driver sc7280_lpass_cpu_platform_driver = { .probe = asoc_qcom_lpass_cpu_platform_probe, .remove = asoc_qcom_lpass_cpu_platform_remove, .shutdown = asoc_qcom_lpass_cpu_platform_shutdown, + .resume = asoc_qcom_lpass_cpu_platform_resume, + .suspend = asoc_qcom_lpass_cpu_platform_suspend, };module_platform_driver (sc7280_lpass_cpu_platform_driver);
sound/soc/qcom/lpass.h +2 -0
@@ -419,5 +419,7 @@ extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops;int lpass_cpu_pcm_new (struct snd_soc_pcm_runtime *rtd,struct snd_soc_dai *dai);extern const struct snd_soc_dai_ops asoc_qcom_lpass_wcd_dai_ops; +int asoc_qcom_lpass_cpu_platform_suspend (struct platform_device *pdev,pm_message_t state); +int asoc_qcom_lpass_cpu_platform_resume (struct platform_device *pdev);#endif /* __LPASS_H__ */
Signature · 2 lines
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc., is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.