2021-10-23 09:55:49

by Srinivasa Rao Mandadapu

[permalink] [raw]
Subject: [PATCH v3 00/10] Add support for audio on SC7280 based targets

Changes Since V2:
-- Split lpass sc7280 cpu driver patch and create regmap config patch.
-- Create patches based on latest kernel tip.
-- Add helper function to get dma control and lpaif handle.
-- Remove unused variables.
Changes Since V1:
-- Typo errors fix
-- CPU driver readable/writable apis optimization.
-- Add Missing config patch
-- Add Common api for repeated dmactl initialization.

Srinivasa Rao Mandadapu (10):
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 lpass CPU driver for codec dma control
ASoC: qcom: Add helper function to get dma control and lpaif handle
ASoC: qcom: Add support for codec dma driver
ASoC: qcom: Add regmap config 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: SC7280: Update config for building codec dma drivers

.../devicetree/bindings/sound/qcom,lpass-cpu.yaml | 69 ++-
sound/soc/qcom/Kconfig | 13 +
sound/soc/qcom/Makefile | 4 +
sound/soc/qcom/common.c | 39 ++
sound/soc/qcom/common.h | 1 +
sound/soc/qcom/lpass-cdc-dma.c | 195 +++++++
sound/soc/qcom/lpass-cpu.c | 245 ++++++++-
sound/soc/qcom/lpass-lpaif-reg.h | 103 +++-
sound/soc/qcom/lpass-platform.c | 513 +++++++++++++++---
sound/soc/qcom/lpass-sc7280.c | 599 +++++++++++++++++++++
sound/soc/qcom/lpass.h | 157 ++++++
11 files changed, 1859 insertions(+), 79 deletions(-)
create mode 100644 sound/soc/qcom/lpass-cdc-dma.c
create mode 100644 sound/soc/qcom/lpass-sc7280.c

--
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.


2021-10-23 09:55:52

by Srinivasa Rao Mandadapu

[permalink] [raw]
Subject: [PATCH v3 01/10] 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

Signed-off-by: Srinivasa Rao Mandadapu <[email protected]>
Co-developed-by: Venkata Prasad Potturu <[email protected]>
Signed-off-by: Venkata Prasad Potturu <[email protected]>
---
sound/soc/qcom/lpass-platform.c | 5 -----
sound/soc/qcom/lpass.h | 5 +++++
2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index a59e9d2..a44162c 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -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

diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 67ef497..63aaa6f 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -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);
--
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.

2021-10-23 09:56:13

by Srinivasa Rao Mandadapu

[permalink] [raw]
Subject: [PATCH v3 02/10] ASoC: qcom: lpass: Add dma fields for codec dma lpass interface

Add lpass interface memebers to support audio path over codec dma.

Signed-off-by: Srinivasa Rao Mandadapu <[email protected]>
Co-developed-by: Venkata Prasad Potturu <[email protected]>
Signed-off-by: Venkata Prasad Potturu <[email protected]>
---
sound/soc/qcom/lpass.h | 151 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 151 insertions(+)

diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 63aaa6f..33e4ee5 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -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,61 @@ struct lpass_data {
bool mi2s_was_prepared[LPASS_MAX_MI2S_PORTS];

int hdmi_port_enable;
+ int codec_dma_enable;

/* low-power audio interface (LPAIF) registers */
void __iomem *lpaif;
void __iomem *hdmiif;
+ void __iomem *rxtx_lpaif;
+ void __iomem *va_lpaif;
+
+ u32 rxtx_cdc_dma_lpm_buf;
+ u32 va_cdc_dma_lpm_buf;

/* 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 +200,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 +321,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 +392,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 {
--
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.

2021-10-23 09:56:24

by Srinivasa Rao Mandadapu

[permalink] [raw]
Subject: [PATCH v3 04/10] ASoC: qcom: Add lpass CPU driver for codec dma control

Add lpass cpu driver to support audio over codec dma for
ADSP bypass usecase.

Signed-off-by: Srinivasa Rao Mandadapu <[email protected]>
Co-developed-by: Venkata Prasad Potturu <[email protected]>
Signed-off-by: Venkata Prasad Potturu <[email protected]>
---
sound/soc/qcom/lpass-cdc-dma.c | 195 +++++++++++++++++++++++++++++++++++++++++
sound/soc/qcom/lpass.h | 1 +
2 files changed, 196 insertions(+)
create mode 100644 sound/soc/qcom/lpass-cdc-dma.c

diff --git a/sound/soc/qcom/lpass-cdc-dma.c b/sound/soc/qcom/lpass-cdc-dma.c
new file mode 100644
index 0000000..f5bfda9
--- /dev/null
+++ b/sound/soc/qcom/lpass-cdc-dma.c
@@ -0,0 +1,195 @@
+// 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/clk.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "lpass-lpaif-reg.h"
+#include "lpass.h"
+
+static void __get_dmactl_handle(struct snd_pcm_substream *substream, struct snd_soc_dai *dai,
+ struct lpaif_dmactl **dmactl, int *id)
+{
+ 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;
+ unsigned int dai_id = cpu_dai->driver->id;
+
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+ *dmactl = drvdata->rxtx_rd_dmactl;
+ *id = pcm_data->dma_ch;
+ } else {
+ if (dai_id == LPASS_CDC_DMA_TX3) {
+ *dmactl = drvdata->rxtx_wr_dmactl;
+ *id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start;
+ } else if (dai_id == LPASS_CDC_DMA_VA_TX0) {
+ *dmactl = drvdata->va_wr_dmactl;
+ *id = pcm_data->dma_ch - v->va_wrdma_channel_start;
+ }
+ }
+}
+
+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 lpaif_dmactl *dmactl;
+ int dir = substream->stream;
+ int ret, id, codec_intf;
+ unsigned int dai_id = cpu_dai->driver->id;
+
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK)
+ codec_intf = LPASS_CDC_DMA_RX0_INTERFACE;
+ else
+ codec_intf = LPASS_CDC_DMA_INTERFACE(dai_id);
+
+ __get_dmactl_handle(substream, dai, &dmactl, &id);
+
+ ret = regmap_fields_write(dmactl->codec_intf, id, codec_intf);
+ if (ret) {
+ dev_err(soc_runtime->dev,
+ "error writing to dmactl 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 dmactl 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 dmactl 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 dmactl 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 dmactl 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;
+
+ ret = clk_bulk_prepare_enable(drvdata->cdc_num_clks, drvdata->cdc_clks);
+ 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)
+{
+ struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
+
+ clk_bulk_disable_unprepare(drvdata->cdc_num_clks, drvdata->cdc_clks);
+}
+
+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 lpaif_dmactl *dmactl;
+ unsigned int ret, regval;
+ unsigned int channels = params_channels(params);
+ int id;
+
+ __get_dmactl_handle(substream, dai, &dmactl, &id);
+
+ 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 dmactl codec_channel reg field: %d\n", ret);
+ return ret;
+ }
+ return 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 lpaif_dmactl *dmactl;
+ int ret = 0, id;
+
+ __get_dmactl_handle(substream, dai, &dmactl, &id);
+
+ 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 dmactl codec_enable 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");
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 33e4ee5..74da4e9 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -421,5 +421,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__ */
--
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.

2021-10-23 09:56:43

by Srinivasa Rao Mandadapu

[permalink] [raw]
Subject: [PATCH v3 06/10] ASoC: qcom: Add support for codec dma driver

Upadate lpass cpu and platform driver to support audio over codec dma
in ADSP bypass use case.

Signed-off-by: Srinivasa Rao Mandadapu <[email protected]>
Co-developed-by: Venkata Prasad Potturu <[email protected]>
Signed-off-by: Venkata Prasad Potturu <[email protected]>
---
sound/soc/qcom/common.c | 39 ++++
sound/soc/qcom/common.h | 1 +
sound/soc/qcom/lpass-cpu.c | 60 +++++-
sound/soc/qcom/lpass-platform.c | 424 ++++++++++++++++++++++++++++++++++++++--
4 files changed, 508 insertions(+), 16 deletions(-)

diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
index 09af007..26d3752 100644
--- a/sound/soc/qcom/common.c
+++ b/sound/soc/qcom/common.c
@@ -4,6 +4,7 @@

#include <linux/module.h>
#include "common.h"
+#include "lpass.h"

int qcom_snd_parse_of(struct snd_soc_card *card)
{
@@ -169,4 +170,42 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
}
EXPORT_SYMBOL(qcom_snd_parse_of);

+bool is_cdc_dma_port(int dai_id)
+{
+ switch (dai_id) {
+ case LPASS_CDC_DMA_RX0:
+ case LPASS_CDC_DMA_RX1:
+ case LPASS_CDC_DMA_RX2:
+ case LPASS_CDC_DMA_RX3:
+ case LPASS_CDC_DMA_RX4:
+ case LPASS_CDC_DMA_RX5:
+ case LPASS_CDC_DMA_RX6:
+ case LPASS_CDC_DMA_RX7:
+ case LPASS_CDC_DMA_RX8:
+ case LPASS_CDC_DMA_RX9:
+ case LPASS_CDC_DMA_TX0:
+ case LPASS_CDC_DMA_TX1:
+ case LPASS_CDC_DMA_TX2:
+ case LPASS_CDC_DMA_TX3:
+ case LPASS_CDC_DMA_TX4:
+ case LPASS_CDC_DMA_TX5:
+ case LPASS_CDC_DMA_TX6:
+ case LPASS_CDC_DMA_TX7:
+ case LPASS_CDC_DMA_TX8:
+ case LPASS_CDC_DMA_VA_TX0:
+ case LPASS_CDC_DMA_VA_TX1:
+ case LPASS_CDC_DMA_VA_TX2:
+ case LPASS_CDC_DMA_VA_TX3:
+ case LPASS_CDC_DMA_VA_TX4:
+ case LPASS_CDC_DMA_VA_TX5:
+ case LPASS_CDC_DMA_VA_TX6:
+ case LPASS_CDC_DMA_VA_TX7:
+ case LPASS_CDC_DMA_VA_TX8:
+ return true;
+ default:
+ return false;
+ }
+}
+EXPORT_SYMBOL(is_cdc_dma_port);
+
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/common.h b/sound/soc/qcom/common.h
index f05c05b..a8fea4c 100644
--- a/sound/soc/qcom/common.h
+++ b/sound/soc/qcom/common.h
@@ -7,5 +7,6 @@
#include <sound/soc.h>

int qcom_snd_parse_of(struct snd_soc_card *card);
+bool is_cdc_dma_port(int dai_id);

#endif
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 3bd9eb3..9e6656c 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -17,6 +17,7 @@
#include <sound/soc.h>
#include <sound/soc-dai.h>
#include "lpass-lpaif-reg.h"
+#include "common.h"
#include "lpass.h"

#define LPASS_CPU_MAX_MI2S_LINES 4
@@ -857,7 +858,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->codec_dma_enable = 1;
+ else {
data->mi2s_playback_sd_mode[id] =
of_lpass_cpu_parse_sd_lines(dev, node,
"qcom,playback-sd-lines");
@@ -872,6 +875,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
{
struct lpass_data *drvdata;
struct device_node *dsp_of_node;
+ struct resource *res;
struct lpass_variant *variant;
struct device *dev = &pdev->dev;
const struct of_device_id *match;
@@ -897,6 +901,58 @@ 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->codec_dma_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 rxtx 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 va regmap: %ld\n",
+ PTR_ERR(drvdata->va_lpaif_map));
+ return PTR_ERR(drvdata->va_lpaif_map);
+ }
+ drvdata->cdc_clks = devm_kcalloc(dev, variant->cdc_dma_num_clks,
+ sizeof(*drvdata->cdc_clks), GFP_KERNEL);
+ drvdata->cdc_num_clks = variant->cdc_dma_num_clks;
+
+ for (i = 0; i < drvdata->cdc_num_clks; i++)
+ drvdata->cdc_clks[i].id = variant->cdc_dma_clk_names[i];
+
+ ret = devm_clk_bulk_get(dev, drvdata->cdc_num_clks, drvdata->cdc_clks);
+ if (ret) {
+ dev_err(dev, "Failed to get clocks %d\n", ret);
+ return ret;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-rxtx-cdc-dma-lpm");
+ drvdata->rxtx_cdc_dma_lpm_buf = res->start;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-va-cdc-dma-lpm");
+ drvdata->va_cdc_dma_lpm_buf = res->start;
+ }
drvdata->lpaif = devm_platform_ioremap_resource_byname(pdev, "lpass-lpaif");
if (IS_ERR(drvdata->lpaif))
return PTR_ERR(drvdata->lpaif);
@@ -939,7 +995,7 @@ 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 || is_cdc_dma_port(dai_id))
continue;

drvdata->mi2s_osr_clk[dai_id] = devm_clk_get_optional(dev,
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index 59c0884..4b79908 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -14,12 +14,15 @@
#include <linux/regmap.h>
#include <sound/soc.h>
#include "lpass-lpaif-reg.h"
+#include "common.h"
#include "lpass.h"

#define DRV_NAME "lpass-platform"

#define LPASS_PLATFORM_BUFFER_SIZE (24 * 2 * 1024)
#define LPASS_PLATFORM_PERIODS 2
+#define LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE (24 * 1024)
+#define LPSAS_VA_CDC_DMA_LPM_BUFF_SIZE (12 * 1024)

static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
.info = SNDRV_PCM_INFO_MMAP |
@@ -45,6 +48,103 @@ static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
.fifo_size = 0,
};

+static const struct snd_pcm_hardware lpass_platform_rxtx_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16 |
+ SNDRV_PCM_FMTBIT_S24 |
+ SNDRV_PCM_FMTBIT_S32,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 8,
+ .buffer_bytes_max = LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE,
+ .period_bytes_max = LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE /
+ LPASS_PLATFORM_PERIODS,
+ .period_bytes_min = LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE /
+ LPASS_PLATFORM_PERIODS,
+ .periods_min = LPASS_PLATFORM_PERIODS,
+ .periods_max = LPASS_PLATFORM_PERIODS,
+ .fifo_size = 0,
+};
+
+static const struct snd_pcm_hardware lpass_platform_va_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16 |
+ SNDRV_PCM_FMTBIT_S24 |
+ SNDRV_PCM_FMTBIT_S32,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 8,
+ .buffer_bytes_max = LPSAS_VA_CDC_DMA_LPM_BUFF_SIZE,
+ .period_bytes_max = LPSAS_VA_CDC_DMA_LPM_BUFF_SIZE /
+ LPASS_PLATFORM_PERIODS,
+ .period_bytes_min = LPSAS_VA_CDC_DMA_LPM_BUFF_SIZE /
+ LPASS_PLATFORM_PERIODS,
+ .periods_min = LPASS_PLATFORM_PERIODS,
+ .periods_max = LPASS_PLATFORM_PERIODS,
+ .fifo_size = 0,
+};
+
+static int lpass_platform_alloc_rxtx_dmactl_fields(struct device *dev,
+ struct regmap *map)
+{
+ struct lpass_data *drvdata = dev_get_drvdata(dev);
+ struct lpass_variant *v = drvdata->variant;
+ struct lpaif_dmactl *rd_dmactl, *wr_dmactl;
+ int rval;
+
+ drvdata->rxtx_rd_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
+ GFP_KERNEL);
+ if (drvdata->rxtx_rd_dmactl == NULL)
+ return -ENOMEM;
+
+ drvdata->rxtx_wr_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
+ GFP_KERNEL);
+ if (drvdata->rxtx_wr_dmactl == NULL)
+ return -ENOMEM;
+
+ rd_dmactl = drvdata->rxtx_rd_dmactl;
+ wr_dmactl = drvdata->rxtx_wr_dmactl;
+
+ rval = devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->intf,
+ &v->rxtx_rdma_intf, 15);
+ if (rval)
+ return rval;
+
+ return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,
+ &v->rxtx_wrdma_intf, 15);
+}
+
+static int lpass_platform_alloc_va_dmactl_fields(struct device *dev,
+ struct regmap *map)
+{
+ struct lpass_data *drvdata = dev_get_drvdata(dev);
+ struct lpass_variant *v = drvdata->variant;
+ struct lpaif_dmactl *wr_dmactl;
+
+ drvdata->va_wr_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
+ GFP_KERNEL);
+ if (drvdata->va_wr_dmactl == NULL)
+ return -ENOMEM;
+
+ wr_dmactl = drvdata->va_wr_dmactl;
+
+ return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,
+ &v->va_wrdma_intf, 15);
+}
+
+
static int lpass_platform_alloc_dmactl_fields(struct device *dev,
struct regmap *map)
{
@@ -126,22 +226,43 @@ static int lpass_platform_pcmops_open(struct snd_soc_component *component,
if (cpu_dai->driver->id == LPASS_DP_RX) {
map = drvdata->hdmiif_map;
drvdata->hdmi_substream[dma_ch] = substream;
+ } else if (dai_id == LPASS_CDC_DMA_RX0 || dai_id == LPASS_CDC_DMA_TX3) {
+ map = drvdata->rxtx_lpaif_map;
+ drvdata->rxtx_substream[dma_ch] = substream;
+ } else if (dai_id == LPASS_CDC_DMA_VA_TX0) {
+ map = drvdata->va_lpaif_map;
+ drvdata->va_substream[dma_ch] = substream;
} else {
map = drvdata->lpaif_map;
drvdata->substream[dma_ch] = substream;
}
data->dma_ch = dma_ch;
- ret = regmap_write(map,
- LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0);
- if (ret) {
- dev_err(soc_runtime->dev,
- "error writing to rdmactl reg: %d\n", ret);
- return ret;
+ if (!(dai_id == LPASS_CDC_DMA_RX0 ||
+ dai_id == LPASS_CDC_DMA_TX3 ||
+ dai_id == LPASS_CDC_DMA_VA_TX0)) {
+ ret = regmap_write(map, LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0);
+ if (ret) {
+ dev_err(soc_runtime->dev,
+ "error writing to rdmactl reg: %d\n", ret);
+ return ret;
+ }
}
- snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
-
- runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;

+ switch (dai_id) {
+ case LPASS_CDC_DMA_RX0:
+ case LPASS_CDC_DMA_TX3:
+ snd_soc_set_runtime_hwparams(substream, &lpass_platform_rxtx_hardware);
+ runtime->dma_bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
+ break;
+ case LPASS_CDC_DMA_VA_TX0:
+ snd_soc_set_runtime_hwparams(substream, &lpass_platform_va_hardware);
+ runtime->dma_bytes = lpass_platform_va_hardware.buffer_bytes_max;
+ break;
+ default:
+ snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
+ runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
+ break;
+ }
ret = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0) {
@@ -168,6 +289,10 @@ static int lpass_platform_pcmops_close(struct snd_soc_component *component,
data = runtime->private_data;
if (dai_id == LPASS_DP_RX)
drvdata->hdmi_substream[data->dma_ch] = NULL;
+ else if (dai_id == LPASS_CDC_DMA_RX0 || dai_id == LPASS_CDC_DMA_TX3)
+ drvdata->rxtx_substream[data->dma_ch] = NULL;
+ else if (dai_id == LPASS_CDC_DMA_VA_TX0)
+ drvdata->va_substream[data->dma_ch] = NULL;
else
drvdata->substream[data->dma_ch] = NULL;
if (v->free_dma_channel)
@@ -198,14 +323,27 @@ static void __get_lpaif_handle(struct snd_pcm_substream *substream,
if (dai_id == LPASS_DP_RX) {
l_dmactl = drvdata->hdmi_rd_dmactl;
l_map = drvdata->hdmiif_map;
+ } else if (dai_id == LPASS_CDC_DMA_RX0) {
+ l_map = drvdata->rxtx_lpaif_map;
+ l_dmactl = drvdata->rxtx_rd_dmactl;
} else {
l_dmactl = drvdata->rd_dmactl;
l_map = drvdata->lpaif_map;
}
} else {
- l_dmactl = drvdata->wr_dmactl;
- l_id = pcm_data->dma_ch - v->wrdma_channel_start;
- l_map = drvdata->lpaif_map;
+ if (dai_id == LPASS_CDC_DMA_TX3) {
+ l_dmactl = drvdata->rxtx_wr_dmactl;
+ l_map = drvdata->rxtx_lpaif_map;
+ l_id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start;
+ } else if (dai_id == LPASS_CDC_DMA_VA_TX0) {
+ l_dmactl = drvdata->va_wr_dmactl;
+ l_map = drvdata->va_lpaif_map;
+ l_id = pcm_data->dma_ch - v->va_wrdma_channel_start;
+ } else {
+ l_dmactl = drvdata->wr_dmactl;
+ l_id = pcm_data->dma_ch - v->wrdma_channel_start;
+ l_map = drvdata->lpaif_map;
+ }
}
if (dmactl)
*dmactl = l_dmactl;
@@ -256,6 +394,10 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
}

switch (dai_id) {
+ case LPASS_CDC_DMA_RX0:
+ case LPASS_CDC_DMA_TX3:
+ case LPASS_CDC_DMA_VA_TX0:
+ break;
case LPASS_DP_RX:
ret = regmap_fields_write(dmactl->burst8, id,
LPAIF_DMACTL_BURSTEN_INCR4);
@@ -380,6 +522,10 @@ static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component,

if (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)
+ return 0;
else
map = drvdata->lpaif_map;

@@ -434,6 +580,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",
@@ -476,6 +632,22 @@ 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);
+ if (ret) {
+ dev_err(soc_runtime->dev,
+ "error writing to rdmactl reg field: %d\n", ret);
+ return ret;
+ }
+ 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);
@@ -540,6 +712,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_OFF);
+ if (ret) {
+ dev_err(soc_runtime->dev,
+ "error writing to rdmactl reg field: %d\n", ret);
+ return ret;
+ }
+
+ 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);
@@ -619,6 +809,38 @@ 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;
+
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ size = vma->vm_end - vma->vm_start;
+ offset = vma->vm_pgoff << PAGE_SHIFT;
+ return io_remap_pfn_range(vma, vma->vm_start,
+ (runtime->dma_addr + offset) >> PAGE_SHIFT,
+ size, vma->vm_page_prot);
+
+}
+
+static int lpass_platform_pcmops_mmap(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ 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) {
+ return lpass_platform_cdc_dma_mmap(component, substream, vma);
+ }
+ return 0;
+}
+
static irqreturn_t lpass_dma_interrupt_handler(
struct snd_pcm_substream *substream,
struct lpass_data *drvdata,
@@ -635,6 +857,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);
@@ -758,18 +988,112 @@ 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_soc_component *component,
+ struct snd_pcm *pcm, int dai_id)
+{
+ struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
+ struct snd_pcm_substream *substream;
+ struct snd_dma_buffer *buf;
+ int ret;
+
+ if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
+ substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ else
+ substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+
+ ret = dma_coerce_mask_and_coherent(pcm->card->dev, DMA_BIT_MASK(64));
+ if (ret)
+ return ret;
+
+ buf = &substream->dma_buffer;
+ 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 = drvdata->rxtx_cdc_dma_lpm_buf;
+ } else if (dai_id == LPASS_CDC_DMA_TX3) {
+ buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
+ buf->addr = drvdata->rxtx_cdc_dma_lpm_buf + 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 = drvdata->va_cdc_dma_lpm_buf;
+ }
+
+ 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_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;

- return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
- component->dev, size);
+ if (is_cdc_dma_port(dai_id))
+ return lpass_platform_prealloc_cdc_dma_buffer(component, pcm, dai_id);
+ else
+ return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
+ component->dev, size);
}

static int lpass_platform_pcmops_suspend(struct snd_soc_component *component)
@@ -804,6 +1128,22 @@ static int lpass_platform_pcmops_resume(struct snd_soc_component *component)
return regcache_sync(map);
}

+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;
+
+ 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;
+}

static const struct snd_soc_component_driver lpass_component_driver = {
.name = DRV_NAME,
@@ -814,9 +1154,11 @@ static const struct snd_soc_component_driver lpass_component_driver = {
.prepare = lpass_platform_pcmops_prepare,
.trigger = lpass_platform_pcmops_trigger,
.pointer = lpass_platform_pcmops_pointer,
+ .mmap = lpass_platform_pcmops_mmap,
.pcm_construct = lpass_platform_pcm_new,
.suspend = lpass_platform_pcmops_suspend,
.resume = lpass_platform_pcmops_resume,
+ .copy_user = lpass_platform_copy,

};

@@ -854,6 +1196,60 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
return ret;
}

+ if (drvdata->codec_dma_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)
--
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.

2021-10-23 09:56:53

by Srinivasa Rao Mandadapu

[permalink] [raw]
Subject: [PATCH v3 03/10] ASoC: qcom: Add register definition for codec rddma and wrdma

This patch adds register definitions for codec read dma and write dma
lpass interface.

Signed-off-by: Srinivasa Rao Mandadapu <[email protected]>
Co-developed-by: Venkata Prasad Potturu <[email protected]>
Signed-off-by: Venkata Prasad Potturu <[email protected]>
---
sound/soc/qcom/lpass-lpaif-reg.h | 103 ++++++++++++++++++++++++++++++++++++---
1 file changed, 97 insertions(+), 6 deletions(-)

diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h
index 2eb03ad..697a11f 100644
--- a/sound/soc/qcom/lpass-lpaif-reg.h
+++ b/sound/soc/qcom/lpass-lpaif-reg.h
@@ -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
--
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.

2021-10-23 09:56:53

by Srinivasa Rao Mandadapu

[permalink] [raw]
Subject: [PATCH v3 08/10] ASoC: dt-bindings: Add SC7280 sound card bindings

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: Srinivasa Rao Mandadapu <[email protected]>
Co-developed-by: Venkata Prasad Potturu <[email protected]>
Signed-off-by: Venkata Prasad Potturu <[email protected]>
---
.../devicetree/bindings/sound/qcom,lpass-cpu.yaml | 69 +++++++++++++++++++---
1 file changed, 61 insertions(+), 8 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
index 1e23c0e..0f5a57c 100644
--- a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
@@ -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
+ - const: lpass-irq-vaif
+ - const: lpass-irq-rxtxif
+ - const: lpass-irq-hdmi
+
+ required:
+ - iommus
+ - power-domains
+
examples:
- |
#include <dt-bindings/sound/sc7180-lpass.h>
--
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.

2021-10-23 09:57:22

by Srinivasa Rao Mandadapu

[permalink] [raw]
Subject: [PATCH v3 10/10] ASoC: qcom: SC7280: Update config for building codec dma drivers

Add configuration for building SC7280 audio codec dma drivers.

Signed-off-by: Srinivasa Rao Mandadapu <[email protected]>
Co-developed-by: Venkata Prasad Potturu <[email protected]>
Signed-off-by: Venkata Prasad Potturu <[email protected]>
---
sound/soc/qcom/Kconfig | 13 +++++++++++++
sound/soc/qcom/Makefile | 4 ++++
2 files changed, 17 insertions(+)

diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index d9ffcb7..2b98ad9 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -20,6 +20,10 @@ config SND_SOC_LPASS_PLATFORM
tristate
select REGMAP_MMIO

+config SND_SOC_LPASS_CDC_DMA
+ tristate
+ select REGMAP_MMIO
+
config SND_SOC_LPASS_IPQ806X
tristate
select SND_SOC_LPASS_CPU
@@ -36,6 +40,13 @@ config SND_SOC_LPASS_SC7180
select SND_SOC_LPASS_PLATFORM
select SND_SOC_LPASS_HDMI

+config SND_SOC_LPASS_SC7280
+ tristate
+ select SND_SOC_LPASS_CPU
+ select SND_SOC_LPASS_PLATFORM
+ select SND_SOC_LPASS_HDMI
+ select SND_SOC_LPASS_CDC_DMA
+
config SND_SOC_STORM
tristate "ASoC I2S support for Storm boards"
select SND_SOC_LPASS_IPQ806X
@@ -156,7 +167,9 @@ config SND_SOC_SC7280
tristate "SoC Machine driver for SC7280 boards"
depends on I2C && SOUNDWIRE
select SND_SOC_QCOM_COMMON
+ select SND_SOC_LPASS_SC7280
select SND_SOC_MAX98357A
+ select SND_SOC_WCD938X
select SND_SOC_LPASS_RX_MACRO
select SND_SOC_LPASS_TX_MACRO
help
diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
index 625aec6..8b7b876 100644
--- a/sound/soc/qcom/Makefile
+++ b/sound/soc/qcom/Makefile
@@ -1,18 +1,22 @@
# SPDX-License-Identifier: GPL-2.0
# Platform
snd-soc-lpass-cpu-objs := lpass-cpu.o
+snd-soc-lpass-cdc-dma-objs := lpass-cdc-dma.o
snd-soc-lpass-hdmi-objs := lpass-hdmi.o
snd-soc-lpass-platform-objs := lpass-platform.o
snd-soc-lpass-ipq806x-objs := lpass-ipq806x.o
snd-soc-lpass-apq8016-objs := lpass-apq8016.o
snd-soc-lpass-sc7180-objs := lpass-sc7180.o
+snd-soc-lpass-sc7280-objs := lpass-sc7280.o

obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o
+obj-$(CONFIG_SND_SOC_LPASS_CDC_DMA) += snd-soc-lpass-cdc-dma.o
obj-$(CONFIG_SND_SOC_LPASS_HDMI) += snd-soc-lpass-hdmi.o
obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o
obj-$(CONFIG_SND_SOC_LPASS_IPQ806X) += snd-soc-lpass-ipq806x.o
obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o
obj-$(CONFIG_SND_SOC_LPASS_SC7180) += snd-soc-lpass-sc7180.o
+obj-$(CONFIG_SND_SOC_LPASS_SC7280) += snd-soc-lpass-sc7280.o

# Machine
snd-soc-storm-objs := storm.o
--
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.

2021-10-23 09:57:27

by Srinivasa Rao Mandadapu

[permalink] [raw]
Subject: [PATCH v3 05/10] ASoC: qcom: Add helper function to get dma control and lpaif handle

Add support function to get dma control and lpaif handle to avoid
repeated code in platform driver

Signed-off-by: Srinivasa Rao Mandadapu <[email protected]>
Co-developed-by: Venkata Prasad Potturu <[email protected]>
Signed-off-by: Venkata Prasad Potturu <[email protected]>
---
sound/soc/qcom/lpass-platform.c | 90 ++++++++++++++++++++---------------------
1 file changed, 43 insertions(+), 47 deletions(-)

diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index a44162c..59c0884 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -177,6 +177,44 @@ static int lpass_platform_pcmops_close(struct snd_soc_component *component,
return 0;
}

+static void __get_lpaif_handle(struct snd_pcm_substream *substream,
+ struct snd_soc_component *component,
+ struct lpaif_dmactl **dmactl, int *id, struct regmap **map)
+{
+ 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_component_get_drvdata(component);
+ 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;
+ unsigned int dai_id = cpu_dai->driver->id;
+ struct lpaif_dmactl *l_dmactl;
+ struct regmap *l_map;
+ int l_id;
+
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+ l_id = pcm_data->dma_ch;
+ if (dai_id == LPASS_DP_RX) {
+ l_dmactl = drvdata->hdmi_rd_dmactl;
+ l_map = drvdata->hdmiif_map;
+ } else {
+ l_dmactl = drvdata->rd_dmactl;
+ l_map = drvdata->lpaif_map;
+ }
+ } else {
+ l_dmactl = drvdata->wr_dmactl;
+ l_id = pcm_data->dma_ch - v->wrdma_channel_start;
+ l_map = drvdata->lpaif_map;
+ }
+ if (dmactl)
+ *dmactl = l_dmactl;
+ if (id)
+ *id = l_id;
+ if (map)
+ *map = l_map;
+}
+
static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
@@ -191,22 +229,12 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
unsigned int channels = params_channels(params);
unsigned int regval;
struct lpaif_dmactl *dmactl;
- int id, dir = substream->stream;
+ int id;
int bitwidth;
int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start;
unsigned int dai_id = cpu_dai->driver->id;

- if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
- id = pcm_data->dma_ch;
- if (dai_id == LPASS_DP_RX)
- dmactl = drvdata->hdmi_rd_dmactl;
- else
- dmactl = drvdata->rd_dmactl;
-
- } else {
- dmactl = drvdata->wr_dmactl;
- id = pcm_data->dma_ch - v->wrdma_channel_start;
- }
+ __get_lpaif_handle(substream, component, &dmactl, &id, NULL);

bitwidth = snd_pcm_format_width(format);
if (bitwidth < 0) {
@@ -379,24 +407,9 @@ static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
int ret, id, ch, dir = substream->stream;
unsigned int dai_id = cpu_dai->driver->id;

-
ch = pcm_data->dma_ch;
- if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
- if (dai_id == LPASS_DP_RX) {
- dmactl = drvdata->hdmi_rd_dmactl;
- map = drvdata->hdmiif_map;
- } else {
- dmactl = drvdata->rd_dmactl;
- map = drvdata->lpaif_map;
- }
-
- id = pcm_data->dma_ch;
- } else {
- dmactl = drvdata->wr_dmactl;
- id = pcm_data->dma_ch - v->wrdma_channel_start;
- map = drvdata->lpaif_map;
- }

+ __get_lpaif_handle(substream, component, &dmactl, &id, &map);
ret = regmap_write(map, LPAIF_DMABASE_REG(v, ch, dir, dai_id),
runtime->dma_addr);
if (ret) {
@@ -444,26 +457,12 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
struct lpaif_dmactl *dmactl;
struct regmap *map;
int ret, ch, id;
- int dir = substream->stream;
unsigned int reg_irqclr = 0, val_irqclr = 0;
unsigned int reg_irqen = 0, val_irqen = 0, val_mask = 0;
unsigned int dai_id = cpu_dai->driver->id;

ch = pcm_data->dma_ch;
- if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
- id = pcm_data->dma_ch;
- if (dai_id == LPASS_DP_RX) {
- dmactl = drvdata->hdmi_rd_dmactl;
- map = drvdata->hdmiif_map;
- } 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;
- }
+ __get_lpaif_handle(substream, component, &dmactl, &id, &map);

switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -597,10 +596,7 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
struct regmap *map;
unsigned int dai_id = cpu_dai->driver->id;

- if (dai_id == LPASS_DP_RX)
- map = drvdata->hdmiif_map;
- else
- map = drvdata->lpaif_map;
+ __get_lpaif_handle(substream, component, NULL, NULL, &map);

ch = pcm_data->dma_ch;

--
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.

2021-10-23 09:58:35

by Srinivasa Rao Mandadapu

[permalink] [raw]
Subject: [PATCH v3 09/10] ASoC: qcom: lpass-sc7280: Add platform driver for lpass audio

Add 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.

Signed-off-by: Srinivasa Rao Mandadapu <[email protected]>
Co-developed-by: Venkata Prasad Potturu <[email protected]>
Signed-off-by: Venkata Prasad Potturu <[email protected]>
---
sound/soc/qcom/lpass-sc7280.c | 599 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 599 insertions(+)
create mode 100644 sound/soc/qcom/lpass-sc7280.c

diff --git a/sound/soc/qcom/lpass-sc7280.c b/sound/soc/qcom/lpass-sc7280.c
new file mode 100644
index 0000000..f73d374
--- /dev/null
+++ b/sound/soc/qcom/lpass-sc7280.c
@@ -0,0 +1,599 @@
+// 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");
--
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.

2021-10-23 09:59:43

by Srinivasa Rao Mandadapu

[permalink] [raw]
Subject: [PATCH v3 07/10] ASoC: qcom: Add regmap config support for codec dma driver

Update regmap configuration for supporting headset playback and
capture and DMIC capture using codec dma interface

Signed-off-by: Srinivasa Rao Mandadapu <[email protected]>
Co-developed-by: Venkata Prasad Potturu <[email protected]>
Signed-off-by: Venkata Prasad Potturu <[email protected]>
---
sound/soc/qcom/lpass-cpu.c | 185 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 185 insertions(+)

diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 9e6656c..ea1542d 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -29,6 +29,8 @@
#define LPASS_CPU_I2S_SD2_3_MASK GENMASK(3, 2)
#define LPASS_CPU_I2S_SD0_1_2_MASK GENMASK(2, 0)
#define LPASS_CPU_I2S_SD0_1_2_3_MASK GENMASK(3, 0)
+#define LPASS_REG_READ 1
+#define LPASS_REG_WRITE 0

/*
* Channel maps for Quad channel playbacks on MI2S Secondary
@@ -799,6 +801,189 @@ static struct regmap_config lpass_hdmi_regmap_config = {
.cache_type = REGCACHE_FLAT,
};

+static bool __lpass_rxtx_regmap_accessible(struct device *dev, unsigned int reg, bool rw)
+{
+ 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 (rw == LPASS_REG_READ) {
+ 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 (rw == LPASS_REG_READ) {
+ if (reg == LPAIF_CDC_WRDMACURR_REG(v, i, LPASS_CDC_DMA_RX0))
+ 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_writeable(struct device *dev, unsigned int reg)
+{
+ return __lpass_rxtx_regmap_accessible(dev, reg, LPASS_REG_WRITE);
+}
+
+static bool lpass_rxtx_regmap_readable(struct device *dev, unsigned int reg)
+{
+ return __lpass_rxtx_regmap_accessible(dev, reg, LPASS_REG_READ);
+}
+
+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_accessible(struct device *dev, unsigned int reg, bool rw)
+{
+ 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 (rw == LPASS_REG_READ) {
+ 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_writeable(struct device *dev, unsigned int reg)
+{
+ return __lpass_va_regmap_accessible(dev, reg, LPASS_REG_WRITE);
+}
+
+static bool lpass_va_regmap_readable(struct device *dev, unsigned int reg)
+{
+ return __lpass_va_regmap_accessible(dev, reg, LPASS_REG_READ);
+}
+
+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)
--
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.

2021-10-23 15:17:57

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH v3 08/10] ASoC: dt-bindings: Add SC7280 sound card bindings

On Sat, 23 Oct 2021 15:24:00 +0530, Srinivasa Rao Mandadapu wrote:
> 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: Srinivasa Rao Mandadapu <[email protected]>
> Co-developed-by: Venkata Prasad Potturu <[email protected]>
> Signed-off-by: Venkata Prasad Potturu <[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.example.dt.yaml: lpass@62d80000: reg: [[0, 1658351616, 0, 425984], [0, 1659895808, 0, 167936]] is too short
From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.example.dt.yaml: lpass@62d80000: reg-names: ['lpass-hdmiif', 'lpass-lpaif'] is too short
From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.example.dt.yaml: lpass@62d80000: interrupts: [[0, 160, 1], [0, 268, 1]] is too short
From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.example.dt.yaml: lpass@62d80000: interrupt-names: ['lpass-irq-lpaif', 'lpass-irq-hdmi'] is too short
From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.example.dt.yaml: lpass@62d80000: iommus: [[4294967295, 4128, 0], [4294967295, 4146, 0]] is too short
From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/patch/1545178

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.