From 8faa268ab780a7379cfe54b882c6f6e0083233f2 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 12 Feb 2016 09:30:17 -0800 Subject: ASoC: qcom: Don't specify LE device endianness This reverts commit 18560a4e3 (ASoC: qcom: Specify LE device endianness). The commit that caused us to specify LE device endianness here, 29bb45f25ff3 (regmap-mmio: Use native endianness for read/write, 2015-10-29), has been reverted in mainline so now when we specify LE it actively breaks big endian kernels because the byte swapping in regmap-mmio is incorrect. Let's revert this change because it will 1) fix the big endian kernels and 2) be redundant to specify LE because that will become the default soon. Signed-off-by: Stephen Boyd Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-cpu.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index 00b6c9d039cf..e5101e0d2d37 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -355,7 +355,6 @@ static struct regmap_config lpass_cpu_regmap_config = { .readable_reg = lpass_cpu_regmap_readable, .volatile_reg = lpass_cpu_regmap_volatile, .cache_type = REGCACHE_FLAT, - .val_format_endian = REGMAP_ENDIAN_LITTLE, }; int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) -- cgit v1.2.3-59-g8ed1b From 144a98835d2b4fc8a732628eaa5c98c573d58baf Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:17:17 +0000 Subject: ASoC: qcom: use snd_dma_alloc/free* apis There is no point in having local allocation functions when the driver can use snd_dma_alloc/free() apis. This patch replaces the local versions of the dma allocation apis with the snd_dma_alloc/free() apis. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-platform.c | 42 ++++++----------------------------------- 1 file changed, 6 insertions(+), 36 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 4aeb8e1a7160..ec2414dc089a 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -439,39 +439,6 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data) return IRQ_HANDLED; } -static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream, - struct snd_soc_pcm_runtime *rt) -{ - struct snd_dma_buffer *buf = &substream->dma_buffer; - size_t size = lpass_platform_pcm_hardware.buffer_bytes_max; - - buf->dev.type = SNDRV_DMA_TYPE_DEV; - buf->dev.dev = rt->platform->dev; - buf->private_data = NULL; - buf->area = dma_alloc_coherent(rt->platform->dev, size, &buf->addr, - GFP_KERNEL); - if (!buf->area) { - dev_err(rt->platform->dev, "%s: Could not allocate DMA buffer\n", - __func__); - return -ENOMEM; - } - buf->bytes = size; - - return 0; -} - -static void lpass_platform_free_buffer(struct snd_pcm_substream *substream, - struct snd_soc_pcm_runtime *rt) -{ - struct snd_dma_buffer *buf = &substream->dma_buffer; - - if (buf->area) { - dma_free_coherent(rt->dev, buf->bytes, buf->area, - buf->addr); - } - buf->area = NULL; -} - static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) { struct snd_pcm *pcm = soc_runtime->pcm; @@ -483,6 +450,7 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) struct lpass_variant *v = drvdata->variant; int ret; struct lpass_pcm_data *data; + size_t size = lpass_platform_pcm_hardware.buffer_bytes_max; data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL); if (!data) @@ -499,7 +467,9 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) snd_soc_pcm_set_drvdata(soc_runtime, data); - ret = lpass_platform_alloc_buffer(substream, soc_runtime); + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, + soc_runtime->platform->dev, + size, &substream->dma_buffer); if (ret) return ret; @@ -514,7 +484,7 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) return 0; err_buf: - lpass_platform_free_buffer(substream, soc_runtime); + snd_dma_free_pages(&substream->dma_buffer); return ret; } @@ -533,7 +503,7 @@ static void lpass_platform_pcm_free(struct snd_pcm *pcm) if (v->free_dma_channel) v->free_dma_channel(drvdata, data->rdma_ch); - lpass_platform_free_buffer(substream, soc_runtime); + snd_dma_free_pages(&substream->dma_buffer); } static struct snd_soc_platform_driver lpass_platform_driver = { -- cgit v1.2.3-59-g8ed1b From ffc1325e1d3bb809dbd8c0b7f9682a22e51a69c3 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:17:23 +0000 Subject: ASoC: qcom: add wrdma register details to lpass_variant This patch adds wrdma related register offsets, wrdma channel start and shifts into lpass variant structure. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index 0b63e2e5bcc9..024a771be4dc 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -71,12 +71,16 @@ struct lpass_variant { u32 rdma_reg_base; u32 rdma_reg_stride; u32 rdma_channels; + u32 wrdma_reg_base; + u32 wrdma_reg_stride; + u32 wrdma_channels; /** * on SOCs like APQ8016 the channel control bits start * at different offset to ipq806x **/ u32 rdmactl_audif_start; + u32 wrdma_channel_start; /* SOC specific intialization like clocks */ int (*init)(struct platform_device *pdev); int (*exit)(struct platform_device *pdev); -- cgit v1.2.3-59-g8ed1b From ec5b82878c36f8c7c6d0d85eacd5185633e6c91b Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:17:30 +0000 Subject: ASoC: qcom: rename rdmactl_audif_start to dmactrl_audif_start This patch renames rdmactl_audif_start to dmactrl_audif_start as this is common for both rdma and wrdma. Without this patch the name would be bit misleading to the readers. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-apq8016.c | 2 +- sound/soc/qcom/lpass-platform.c | 4 ++-- sound/soc/qcom/lpass.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c index 94efc01020c4..6cc7e72b6ff3 100644 --- a/sound/soc/qcom/lpass-apq8016.c +++ b/sound/soc/qcom/lpass-apq8016.c @@ -212,7 +212,7 @@ static struct lpass_variant apq8016_data = { .rdma_reg_base = 0x8400, .rdma_reg_stride = 0x1000, .rdma_channels = 2, - .rdmactl_audif_start = 1, + .dmactl_audif_start = 1, .dai_driver = apq8016_lpass_cpu_dai_driver, .num_dai = ARRAY_SIZE(apq8016_lpass_cpu_dai_driver), .init = apq8016_lpass_init, diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index ec2414dc089a..7245c2ed4e8b 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -91,7 +91,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, unsigned int channels = params_channels(params); unsigned int regval; int bitwidth; - int ret, rdma_port = pcm_data->i2s_port + v->rdmactl_audif_start; + int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start; bitwidth = snd_pcm_format_width(format); if (bitwidth < 0) { @@ -101,7 +101,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, } regval = LPAIF_RDMACTL_BURSTEN_INCR4 | - LPAIF_RDMACTL_AUDINTF(rdma_port) | + LPAIF_RDMACTL_AUDINTF(dma_port) | LPAIF_RDMACTL_FIFOWM_8; switch (bitwidth) { diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index 024a771be4dc..412399acfe3d 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -79,7 +79,7 @@ struct lpass_variant { * on SOCs like APQ8016 the channel control bits start * at different offset to ipq806x **/ - u32 rdmactl_audif_start; + u32 dmactl_audif_start; u32 wrdma_channel_start; /* SOC specific intialization like clocks */ int (*init)(struct platform_device *pdev); -- cgit v1.2.3-59-g8ed1b From 73c847b6d3670e4521cd3f603102332614d0b640 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:17:37 +0000 Subject: ASoC: qcom: pass direction to dma allocation This patch updates the internal dma allocation callbacks to take the stream direction so that it can allocate channels suitable for that stream direction. Before the capture support this was not necessary. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-apq8016.c | 3 ++- sound/soc/qcom/lpass-ipq806x.c | 2 +- sound/soc/qcom/lpass-platform.c | 3 ++- sound/soc/qcom/lpass.h | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c index 6cc7e72b6ff3..99061f42953e 100644 --- a/sound/soc/qcom/lpass-apq8016.c +++ b/sound/soc/qcom/lpass-apq8016.c @@ -133,7 +133,8 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = { }, }; -static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata) +static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata, + int direction) { struct lpass_variant *v = drvdata->variant; int chan = find_first_zero_bit(&drvdata->rdma_ch_bit_map, diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c index 7a4167952711..119048c016ec 100644 --- a/sound/soc/qcom/lpass-ipq806x.c +++ b/sound/soc/qcom/lpass-ipq806x.c @@ -63,7 +63,7 @@ static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = { .ops = &asoc_qcom_lpass_cpu_dai_ops, }; -static int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata) +static int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata, int dir) { return IPQ806X_LPAIF_RDMA_CHAN_MI2S; } diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 7245c2ed4e8b..69c5ad8e2bd7 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -457,7 +457,8 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) return -ENOMEM; if (v->alloc_dma_channel) - data->rdma_ch = v->alloc_dma_channel(drvdata); + data->rdma_ch = v->alloc_dma_channel(drvdata, + SNDRV_PCM_STREAM_PLAYBACK); if (IS_ERR_VALUE(data->rdma_ch)) return data->rdma_ch; diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index 412399acfe3d..8475b609f8ce 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -84,7 +84,7 @@ struct lpass_variant { /* SOC specific intialization like clocks */ int (*init)(struct platform_device *pdev); int (*exit)(struct platform_device *pdev); - int (*alloc_dma_channel)(struct lpass_data *data); + int (*alloc_dma_channel)(struct lpass_data *data, int direction); int (*free_dma_channel)(struct lpass_data *data, int ch); /* SOC specific dais */ -- cgit v1.2.3-59-g8ed1b From 0a536400ad2ea72c80e6257fa71aa78d17bd43e3 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:17:45 +0000 Subject: ASoC: qcom: ipq806x: add error in dma allocation. ipq806x is only ever tested for playback so return error in dma allocation if the stream direction is capture. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-ipq806x.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c index 119048c016ec..29a35296d8da 100644 --- a/sound/soc/qcom/lpass-ipq806x.c +++ b/sound/soc/qcom/lpass-ipq806x.c @@ -65,7 +65,10 @@ static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = { static int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata, int dir) { - return IPQ806X_LPAIF_RDMA_CHAN_MI2S; + if (dir == SNDRV_PCM_STREAM_PLAYBACK) + return IPQ806X_LPAIF_RDMA_CHAN_MI2S; + else /* Capture currently not implemented */ + return -EINVAL; } static int ipq806x_lpass_free_dma_channel(struct lpass_data *drvdata, int chan) -- cgit v1.2.3-59-g8ed1b From 4d809fb12189aef9419f7337bb1767de85699003 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:17:51 +0000 Subject: ASoC: qcom: rename rdma_ch_bit_map to dma_ch_bit_map rdma_ch_bit_map can be reused for wrdma channel allocations as wrdma channel numbering start after rdma channel numbers. With capture support referring rdma_ch_bit_map for wrdma channel allocation is confusing, so renaming rdma_ch_bit_map to dma_ch_bit_map makes sense. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-apq8016.c | 6 +++--- sound/soc/qcom/lpass.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c index 99061f42953e..ca3bbd58c81a 100644 --- a/sound/soc/qcom/lpass-apq8016.c +++ b/sound/soc/qcom/lpass-apq8016.c @@ -137,20 +137,20 @@ static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata, int direction) { struct lpass_variant *v = drvdata->variant; - int chan = find_first_zero_bit(&drvdata->rdma_ch_bit_map, + int chan = find_first_zero_bit(&drvdata->dma_ch_bit_map, v->rdma_channels); if (chan >= v->rdma_channels) return -EBUSY; - set_bit(chan, &drvdata->rdma_ch_bit_map); + set_bit(chan, &drvdata->dma_ch_bit_map); return chan; } static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int chan) { - clear_bit(chan, &drvdata->rdma_ch_bit_map); + clear_bit(chan, &drvdata->dma_ch_bit_map); return 0; } diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index 8475b609f8ce..30714ad1e138 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -50,7 +50,7 @@ struct lpass_data { struct lpass_variant *variant; /* bit map to keep track of static channel allocations */ - unsigned long rdma_ch_bit_map; + unsigned long dma_ch_bit_map; /* used it for handling interrupt per dma channel */ struct snd_pcm_substream *substream[LPASS_MAX_DMA_CHANNELS]; -- cgit v1.2.3-59-g8ed1b From 0a14a1bf2e81a75c5b814a3904f971fb5a53c068 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:17:57 +0000 Subject: ASoC: qcom: ipq806x: add wrdma related register offsets This patch adds wrdma related register offsets to the lpass variant data of ipq806x. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-ipq806x.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c index 29a35296d8da..608c1a92af8a 100644 --- a/sound/soc/qcom/lpass-ipq806x.c +++ b/sound/soc/qcom/lpass-ipq806x.c @@ -86,6 +86,10 @@ static struct lpass_variant ipq806x_data = { .rdma_reg_base = 0x6000, .rdma_reg_stride = 0x1000, .rdma_channels = 4, + .wrdma_reg_base = 0xB000, + .wrdma_reg_stride = 0x1000, + .wrdma_channel_start = 5, + .wrdma_channels = 4, .dai_driver = &ipq806x_lpass_cpu_dai_driver, .num_dai = 1, .alloc_dma_channel = ipq806x_lpass_alloc_dma_channel, -- cgit v1.2.3-59-g8ed1b From 39ad0ecd1e26a4138bf299b98265fceab60553a6 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:18:06 +0000 Subject: ASoC: qcom: add mic related i2s control register defines This patch adds mic related bitmasks and offsets in the i2c control register. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-lpaif-reg.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h index 95e22f131052..65997945cc25 100644 --- a/sound/soc/qcom/lpass-lpaif-reg.h +++ b/sound/soc/qcom/lpass-lpaif-reg.h @@ -47,6 +47,28 @@ #define LPAIF_I2SCTL_SPKMONO_STEREO (0 << LPAIF_I2SCTL_SPKMONO_SHIFT) #define LPAIF_I2SCTL_SPKMONO_MONO (1 << LPAIF_I2SCTL_SPKMONO_SHIFT) +#define LPAIF_I2SCTL_MICEN_MASK GENMASK(8, 8) +#define LPAIF_I2SCTL_MICEN_SHIFT 8 +#define LPAIF_I2SCTL_MICEN_DISABLE (0 << LPAIF_I2SCTL_MICEN_SHIFT) +#define LPAIF_I2SCTL_MICEN_ENABLE (1 << LPAIF_I2SCTL_MICEN_SHIFT) + +#define LPAIF_I2SCTL_MICMODE_MASK GENMASK(7, 4) +#define LPAIF_I2SCTL_MICMODE_SHIFT 4 +#define LPAIF_I2SCTL_MICMODE_NONE (0 << LPAIF_I2SCTL_MICMODE_SHIFT) +#define LPAIF_I2SCTL_MICMODE_SD0 (1 << LPAIF_I2SCTL_MICMODE_SHIFT) +#define LPAIF_I2SCTL_MICMODE_SD1 (2 << LPAIF_I2SCTL_MICMODE_SHIFT) +#define LPAIF_I2SCTL_MICMODE_SD2 (3 << LPAIF_I2SCTL_MICMODE_SHIFT) +#define LPAIF_I2SCTL_MICMODE_SD3 (4 << LPAIF_I2SCTL_MICMODE_SHIFT) +#define LPAIF_I2SCTL_MICMODE_QUAD01 (5 << LPAIF_I2SCTL_MICMODE_SHIFT) +#define LPAIF_I2SCTL_MICMODE_QUAD23 (6 << LPAIF_I2SCTL_MICMODE_SHIFT) +#define LPAIF_I2SCTL_MICMODE_6CH (7 << LPAIF_I2SCTL_MICMODE_SHIFT) +#define LPAIF_I2SCTL_MICMODE_8CH (8 << LPAIF_I2SCTL_MICMODE_SHIFT) + +#define LPAIF_I2SCTL_MIMONO_MASK GENMASK(3, 3) +#define LPAIF_I2SCTL_MICMONO_SHIFT 3 +#define LPAIF_I2SCTL_MICMONO_STEREO (0 << LPAIF_I2SCTL_MICMONO_SHIFT) +#define LPAIF_I2SCTL_MICMONO_MONO (1 << LPAIF_I2SCTL_MICMONO_SHIFT) + #define LPAIF_I2SCTL_WSSRC_MASK 0x0004 #define LPAIF_I2SCTL_WSSRC_SHIFT 2 #define LPAIF_I2SCTL_WSSRC_INTERNAL (0 << LPAIF_I2SCTL_WSSRC_SHIFT) -- cgit v1.2.3-59-g8ed1b From 71aaa600787faffd72a9b674c9e5c9ded7cd9a82 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:18:14 +0000 Subject: ASoC: qcom: add wrdma register definitions This patch adds wrdma registers into the lpaif-reg.h. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-lpaif-reg.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h index 65997945cc25..760d21905f90 100644 --- a/sound/soc/qcom/lpass-lpaif-reg.h +++ b/sound/soc/qcom/lpass-lpaif-reg.h @@ -145,4 +145,15 @@ #define LPAIF_RDMACTL_ENABLE_OFF (0 << LPAIF_RDMACTL_ENABLE_SHIFT) #define LPAIF_RDMACTL_ENABLE_ON (1 << LPAIF_RDMACTL_ENABLE_SHIFT) +#define LPAIF_WRDMA_REG_ADDR(v, addr, chan) \ + (v->wrdma_reg_base + (addr) + \ + v->wrdma_reg_stride * (chan - v->wrdma_channel_start)) + +#define LPAIF_WRDMACTL_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x00, (chan)) +#define LPAIF_WRDMABASE_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x04, (chan)) +#define LPAIF_WRDMABUFF_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x08, (chan)) +#define LPAIF_WRDMACURR_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x0C, (chan)) +#define LPAIF_WRDMAPER_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x10, (chan)) +#define LPAIF_WRDMAPERCNT_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x14, (chan)) + #endif /* __LPASS_LPAIF_REG_H__ */ -- cgit v1.2.3-59-g8ed1b From ec9e0ec84476954f971feb5e0422b48cb25dde58 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:18:20 +0000 Subject: ASoC: qcom: add generic bit masks for RDMA and WRDMA This patch adds generic masks for accessing bits in rdma/wrdma registers. Doing this would simplify the driver and adding capture support would be much simpler. Also there is no point in having same bit masks for bits in both rdma and wrdma registers. This patch also deletes the RDMA specific bit masks and makes the code use the generic bit masks. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-lpaif-reg.h | 83 ++++++++++++++++++++++++---------------- sound/soc/qcom/lpass-platform.c | 54 ++++++++++++++------------ 2 files changed, 79 insertions(+), 58 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h index 760d21905f90..2240bc68e6ec 100644 --- a/sound/soc/qcom/lpass-lpaif-reg.h +++ b/sound/soc/qcom/lpass-lpaif-reg.h @@ -112,39 +112,6 @@ #define LPAIF_RDMAPER_REG(v, chan) LPAIF_RDMA_REG_ADDR(v, 0x10, (chan)) #define LPAIF_RDMAPERCNT_REG(v, chan) LPAIF_RDMA_REG_ADDR(v, 0x14, (chan)) -#define LPAIF_RDMACTL_BURSTEN_MASK 0x800 -#define LPAIF_RDMACTL_BURSTEN_SHIFT 11 -#define LPAIF_RDMACTL_BURSTEN_SINGLE (0 << LPAIF_RDMACTL_BURSTEN_SHIFT) -#define LPAIF_RDMACTL_BURSTEN_INCR4 (1 << LPAIF_RDMACTL_BURSTEN_SHIFT) - -#define LPAIF_RDMACTL_WPSCNT_MASK 0x700 -#define LPAIF_RDMACTL_WPSCNT_SHIFT 8 -#define LPAIF_RDMACTL_WPSCNT_ONE (0 << LPAIF_RDMACTL_WPSCNT_SHIFT) -#define LPAIF_RDMACTL_WPSCNT_TWO (1 << LPAIF_RDMACTL_WPSCNT_SHIFT) -#define LPAIF_RDMACTL_WPSCNT_THREE (2 << LPAIF_RDMACTL_WPSCNT_SHIFT) -#define LPAIF_RDMACTL_WPSCNT_FOUR (3 << LPAIF_RDMACTL_WPSCNT_SHIFT) -#define LPAIF_RDMACTL_WPSCNT_SIX (5 << LPAIF_RDMACTL_WPSCNT_SHIFT) -#define LPAIF_RDMACTL_WPSCNT_EIGHT (7 << LPAIF_RDMACTL_WPSCNT_SHIFT) - -#define LPAIF_RDMACTL_AUDINTF_MASK 0x0F0 -#define LPAIF_RDMACTL_AUDINTF_SHIFT 4 - -#define LPAIF_RDMACTL_FIFOWM_MASK 0x00E -#define LPAIF_RDMACTL_FIFOWM_SHIFT 1 -#define LPAIF_RDMACTL_FIFOWM_1 (0 << LPAIF_RDMACTL_FIFOWM_SHIFT) -#define LPAIF_RDMACTL_FIFOWM_2 (1 << LPAIF_RDMACTL_FIFOWM_SHIFT) -#define LPAIF_RDMACTL_FIFOWM_3 (2 << LPAIF_RDMACTL_FIFOWM_SHIFT) -#define LPAIF_RDMACTL_FIFOWM_4 (3 << LPAIF_RDMACTL_FIFOWM_SHIFT) -#define LPAIF_RDMACTL_FIFOWM_5 (4 << LPAIF_RDMACTL_FIFOWM_SHIFT) -#define LPAIF_RDMACTL_FIFOWM_6 (5 << LPAIF_RDMACTL_FIFOWM_SHIFT) -#define LPAIF_RDMACTL_FIFOWM_7 (6 << LPAIF_RDMACTL_FIFOWM_SHIFT) -#define LPAIF_RDMACTL_FIFOWM_8 (7 << LPAIF_RDMACTL_FIFOWM_SHIFT) - -#define LPAIF_RDMACTL_ENABLE_MASK 0x1 -#define LPAIF_RDMACTL_ENABLE_SHIFT 0 -#define LPAIF_RDMACTL_ENABLE_OFF (0 << LPAIF_RDMACTL_ENABLE_SHIFT) -#define LPAIF_RDMACTL_ENABLE_ON (1 << LPAIF_RDMACTL_ENABLE_SHIFT) - #define LPAIF_WRDMA_REG_ADDR(v, addr, chan) \ (v->wrdma_reg_base + (addr) + \ v->wrdma_reg_stride * (chan - v->wrdma_channel_start)) @@ -156,4 +123,54 @@ #define LPAIF_WRDMAPER_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x10, (chan)) #define LPAIF_WRDMAPERCNT_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x14, (chan)) +#define __LPAIF_DMA_REG(v, chan, dir, reg) \ + (dir == SNDRV_PCM_STREAM_PLAYBACK) ? \ + LPAIF_RDMA##reg##_REG(v, chan) : \ + LPAIF_WRDMA##reg##_REG(v, chan) + +#define LPAIF_DMACTL_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, CTL) +#define LPAIF_DMABASE_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, BASE) +#define LPAIF_DMABUFF_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, BUFF) +#define LPAIF_DMACURR_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, CURR) +#define LPAIF_DMAPER_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, PER) +#define LPAIF_DMAPERCNT_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, PERCNT) + +#define LPAIF_DMACTL_BURSTEN_MASK 0x800 +#define LPAIF_DMACTL_BURSTEN_SHIFT 11 +#define LPAIF_DMACTL_BURSTEN_SINGLE (0 << LPAIF_DMACTL_BURSTEN_SHIFT) +#define LPAIF_DMACTL_BURSTEN_INCR4 (1 << LPAIF_DMACTL_BURSTEN_SHIFT) + +#define LPAIF_DMACTL_WPSCNT_MASK 0x700 +#define LPAIF_DMACTL_WPSCNT_SHIFT 8 +#define LPAIF_DMACTL_WPSCNT_ONE (0 << LPAIF_DMACTL_WPSCNT_SHIFT) +#define LPAIF_DMACTL_WPSCNT_TWO (1 << LPAIF_DMACTL_WPSCNT_SHIFT) +#define LPAIF_DMACTL_WPSCNT_THREE (2 << LPAIF_DMACTL_WPSCNT_SHIFT) +#define LPAIF_DMACTL_WPSCNT_FOUR (3 << LPAIF_DMACTL_WPSCNT_SHIFT) +#define LPAIF_DMACTL_WPSCNT_SIX (5 << LPAIF_DMACTL_WPSCNT_SHIFT) +#define LPAIF_DMACTL_WPSCNT_EIGHT (7 << LPAIF_DMACTL_WPSCNT_SHIFT) + +#define LPAIF_DMACTL_AUDINTF_MASK 0x0F0 +#define LPAIF_DMACTL_AUDINTF_SHIFT 4 +#define LPAIF_DMACTL_AUDINTF(id) (id << LPAIF_DMACTL_AUDINTF_SHIFT) + +#define LPAIF_DMACTL_FIFOWM_MASK 0x00E +#define LPAIF_DMACTL_FIFOWM_SHIFT 1 +#define LPAIF_DMACTL_FIFOWM_1 (0 << LPAIF_DMACTL_FIFOWM_SHIFT) +#define LPAIF_DMACTL_FIFOWM_2 (1 << LPAIF_DMACTL_FIFOWM_SHIFT) +#define LPAIF_DMACTL_FIFOWM_3 (2 << LPAIF_DMACTL_FIFOWM_SHIFT) +#define LPAIF_DMACTL_FIFOWM_4 (3 << LPAIF_DMACTL_FIFOWM_SHIFT) +#define LPAIF_DMACTL_FIFOWM_5 (4 << LPAIF_DMACTL_FIFOWM_SHIFT) +#define LPAIF_DMACTL_FIFOWM_6 (5 << LPAIF_DMACTL_FIFOWM_SHIFT) +#define LPAIF_DMACTL_FIFOWM_7 (6 << LPAIF_DMACTL_FIFOWM_SHIFT) +#define LPAIF_DMACTL_FIFOWM_8 (7 << LPAIF_DMACTL_FIFOWM_SHIFT) + +#define LPAIF_DMACTL_ENABLE_MASK 0x1 +#define LPAIF_DMACTL_ENABLE_SHIFT 0 +#define LPAIF_DMACTL_ENABLE_OFF (0 << LPAIF_DMACTL_ENABLE_SHIFT) +#define LPAIF_DMACTL_ENABLE_ON (1 << LPAIF_DMACTL_ENABLE_SHIFT) + +#define LPAIF_DMACTL_DYNCLK_MASK BIT(12) +#define LPAIF_DMACTL_DYNCLK_SHIFT 12 +#define LPAIF_DMACTL_DYNCLK_OFF (0 << LPAIF_DMACTL_DYNCLK_SHIFT) +#define LPAIF_DMACTL_DYNCLK_ON (1 << LPAIF_DMACTL_DYNCLK_SHIFT) #endif /* __LPASS_LPAIF_REG_H__ */ diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 69c5ad8e2bd7..348e50bc8891 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -90,6 +90,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, snd_pcm_format_t format = params_format(params); unsigned int channels = params_channels(params); unsigned int regval; + int dir = substream->stream; int bitwidth; int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start; @@ -100,25 +101,25 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, return bitwidth; } - regval = LPAIF_RDMACTL_BURSTEN_INCR4 | - LPAIF_RDMACTL_AUDINTF(dma_port) | - LPAIF_RDMACTL_FIFOWM_8; + regval = LPAIF_DMACTL_BURSTEN_INCR4 | + LPAIF_DMACTL_AUDINTF(dma_port) | + LPAIF_DMACTL_FIFOWM_8; switch (bitwidth) { case 16: switch (channels) { case 1: case 2: - regval |= LPAIF_RDMACTL_WPSCNT_ONE; + regval |= LPAIF_DMACTL_WPSCNT_ONE; break; case 4: - regval |= LPAIF_RDMACTL_WPSCNT_TWO; + regval |= LPAIF_DMACTL_WPSCNT_TWO; break; case 6: - regval |= LPAIF_RDMACTL_WPSCNT_THREE; + regval |= LPAIF_DMACTL_WPSCNT_THREE; break; case 8: - regval |= LPAIF_RDMACTL_WPSCNT_FOUR; + regval |= LPAIF_DMACTL_WPSCNT_FOUR; break; default: dev_err(soc_runtime->dev, "%s() invalid PCM config given: bw=%d, ch=%u\n", @@ -130,19 +131,19 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, case 32: switch (channels) { case 1: - regval |= LPAIF_RDMACTL_WPSCNT_ONE; + regval |= LPAIF_DMACTL_WPSCNT_ONE; break; case 2: - regval |= LPAIF_RDMACTL_WPSCNT_TWO; + regval |= LPAIF_DMACTL_WPSCNT_TWO; break; case 4: - regval |= LPAIF_RDMACTL_WPSCNT_FOUR; + regval |= LPAIF_DMACTL_WPSCNT_FOUR; break; case 6: - regval |= LPAIF_RDMACTL_WPSCNT_SIX; + regval |= LPAIF_DMACTL_WPSCNT_SIX; break; case 8: - regval |= LPAIF_RDMACTL_WPSCNT_EIGHT; + regval |= LPAIF_DMACTL_WPSCNT_EIGHT; break; default: dev_err(soc_runtime->dev, "%s() invalid PCM config given: bw=%d, ch=%u\n", @@ -157,7 +158,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, } ret = regmap_write(drvdata->lpaif_map, - LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch), regval); + LPAIF_DMACTL_REG(v, pcm_data->rdma_ch, dir), regval); if (ret) { dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", __func__, ret); @@ -194,6 +195,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream) snd_soc_platform_get_drvdata(soc_runtime->platform); struct lpass_variant *v = drvdata->variant; int ret, ch = pcm_data->rdma_ch; + int dir = substream->stream; ret = regmap_write(drvdata->lpaif_map, LPAIF_RDMABASE_REG(v, ch), @@ -205,7 +207,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream) } ret = regmap_write(drvdata->lpaif_map, - LPAIF_RDMABUFF_REG(v, ch), + LPAIF_DMABUFF_REG(v, ch, dir), (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1); if (ret) { dev_err(soc_runtime->dev, "%s() error writing to rdmabuff reg: %d\n", @@ -214,7 +216,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream) } ret = regmap_write(drvdata->lpaif_map, - LPAIF_RDMAPER_REG(v, ch), + LPAIF_DMAPER_REG(v, ch, dir), (snd_pcm_lib_period_bytes(substream) >> 2) - 1); if (ret) { dev_err(soc_runtime->dev, "%s() error writing to rdmaper reg: %d\n", @@ -223,8 +225,8 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream) } ret = regmap_update_bits(drvdata->lpaif_map, - LPAIF_RDMACTL_REG(v, ch), - LPAIF_RDMACTL_ENABLE_MASK, LPAIF_RDMACTL_ENABLE_ON); + LPAIF_DMACTL_REG(v, ch, dir), + LPAIF_DMACTL_ENABLE_MASK, LPAIF_DMACTL_ENABLE_ON); if (ret) { dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", __func__, ret); @@ -243,6 +245,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream, snd_soc_platform_get_drvdata(soc_runtime->platform); struct lpass_variant *v = drvdata->variant; int ret, ch = pcm_data->rdma_ch; + int dir = substream->stream; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -269,9 +272,9 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream, } ret = regmap_update_bits(drvdata->lpaif_map, - LPAIF_RDMACTL_REG(v, ch), - LPAIF_RDMACTL_ENABLE_MASK, - LPAIF_RDMACTL_ENABLE_ON); + LPAIF_DMACTL_REG(v, ch, dir), + LPAIF_DMACTL_ENABLE_MASK, + LPAIF_DMACTL_ENABLE_ON); if (ret) { dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", __func__, ret); @@ -282,9 +285,9 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ret = regmap_update_bits(drvdata->lpaif_map, - LPAIF_RDMACTL_REG(v, ch), - LPAIF_RDMACTL_ENABLE_MASK, - LPAIF_RDMACTL_ENABLE_OFF); + LPAIF_DMACTL_REG(v, ch, dir), + LPAIF_DMACTL_ENABLE_MASK, + LPAIF_DMACTL_ENABLE_OFF); if (ret) { dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", __func__, ret); @@ -315,9 +318,10 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer( struct lpass_variant *v = drvdata->variant; unsigned int base_addr, curr_addr; int ret, ch = pcm_data->rdma_ch; + int dir = substream->stream; ret = regmap_read(drvdata->lpaif_map, - LPAIF_RDMABASE_REG(v, ch), &base_addr); + LPAIF_DMABASE_REG(v, ch, dir), &base_addr); if (ret) { dev_err(soc_runtime->dev, "%s() error reading from rdmabase reg: %d\n", __func__, ret); @@ -325,7 +329,7 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer( } ret = regmap_read(drvdata->lpaif_map, - LPAIF_RDMACURR_REG(v, ch), &curr_addr); + LPAIF_DMACURR_REG(v, ch, dir), &curr_addr); if (ret) { dev_err(soc_runtime->dev, "%s() error reading from rdmacurr reg: %d\n", __func__, ret); -- cgit v1.2.3-59-g8ed1b From dad8061494d2a2ce6edc2ae5ab530b0d330b2685 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:18:27 +0000 Subject: ASoC: qcom: apq8016: set the correct max register for regmap Now that we are ready to access wrdma registers, set the max register and other regmap related configs to use correct values. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-cpu.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index e5101e0d2d37..91774fc87fcc 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -294,6 +294,17 @@ static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg) return true; } + for (i = 0; i < v->wrdma_channels; ++i) { + if (reg == LPAIF_WRDMACTL_REG(v, i + v->wrdma_channel_start)) + return true; + if (reg == LPAIF_WRDMABASE_REG(v, i + v->wrdma_channel_start)) + return true; + if (reg == LPAIF_WRDMABUFF_REG(v, i + v->wrdma_channel_start)) + return true; + if (reg == LPAIF_WRDMAPER_REG(v, i + v->wrdma_channel_start)) + return true; + } + return false; } @@ -327,6 +338,19 @@ static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg) return true; } + for (i = 0; i < v->wrdma_channels; ++i) { + if (reg == LPAIF_WRDMACTL_REG(v, i + v->wrdma_channel_start)) + return true; + if (reg == LPAIF_WRDMABASE_REG(v, i + v->wrdma_channel_start)) + return true; + if (reg == LPAIF_WRDMABUFF_REG(v, i + v->wrdma_channel_start)) + return true; + if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start)) + return true; + if (reg == LPAIF_WRDMAPER_REG(v, i + v->wrdma_channel_start)) + return true; + } + return false; } @@ -344,6 +368,10 @@ static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg) if (reg == LPAIF_RDMACURR_REG(v, i)) return true; + for (i = 0; i < v->wrdma_channels; ++i) + if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start)) + return true; + return false; } @@ -398,8 +426,9 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) return PTR_ERR((void const __force *)drvdata->lpaif); } - lpass_cpu_regmap_config.max_register = LPAIF_RDMAPER_REG(variant, - variant->rdma_channels); + lpass_cpu_regmap_config.max_register = LPAIF_WRDMAPER_REG(variant, + variant->wrdma_channels + + variant->wrdma_channel_start); drvdata->lpaif_map = devm_regmap_init_mmio(&pdev->dev, drvdata->lpaif, &lpass_cpu_regmap_config); -- cgit v1.2.3-59-g8ed1b From fb5d11524eda5561f6dd8cc03f9dc778027ce907 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:18:33 +0000 Subject: ASoC: qcom: add mic support This patch adds mic support to the lpass driver, most of the driver is reused as it is, only the register level access is changed depending on te direction of the stream. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-cpu.c | 113 +++++++++++++++++++-------- sound/soc/qcom/lpass-platform.c | 167 +++++++++++++++++++++++++++++----------- 2 files changed, 204 insertions(+), 76 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index 91774fc87fcc..3cde9fb977fa 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -120,31 +120,60 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - switch (channels) { - case 1: - regval |= LPAIF_I2SCTL_SPKMODE_SD0; - regval |= LPAIF_I2SCTL_SPKMONO_MONO; - break; - case 2: - regval |= LPAIF_I2SCTL_SPKMODE_SD0; - regval |= LPAIF_I2SCTL_SPKMONO_STEREO; - break; - case 4: - regval |= LPAIF_I2SCTL_SPKMODE_QUAD01; - regval |= LPAIF_I2SCTL_SPKMONO_STEREO; - break; - case 6: - regval |= LPAIF_I2SCTL_SPKMODE_6CH; - regval |= LPAIF_I2SCTL_SPKMONO_STEREO; - break; - case 8: - regval |= LPAIF_I2SCTL_SPKMODE_8CH; - regval |= LPAIF_I2SCTL_SPKMONO_STEREO; - break; - default: - dev_err(dai->dev, "%s() invalid channels given: %u\n", - __func__, channels); - return -EINVAL; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + switch (channels) { + case 1: + regval |= LPAIF_I2SCTL_SPKMODE_SD0; + regval |= LPAIF_I2SCTL_SPKMONO_MONO; + break; + case 2: + regval |= LPAIF_I2SCTL_SPKMODE_SD0; + regval |= LPAIF_I2SCTL_SPKMONO_STEREO; + break; + case 4: + regval |= LPAIF_I2SCTL_SPKMODE_QUAD01; + regval |= LPAIF_I2SCTL_SPKMONO_STEREO; + break; + case 6: + regval |= LPAIF_I2SCTL_SPKMODE_6CH; + regval |= LPAIF_I2SCTL_SPKMONO_STEREO; + break; + case 8: + regval |= LPAIF_I2SCTL_SPKMODE_8CH; + regval |= LPAIF_I2SCTL_SPKMONO_STEREO; + break; + default: + dev_err(dai->dev, "%s() invalid channels given: %u\n", + __func__, channels); + return -EINVAL; + } + } else { + switch (channels) { + case 1: + regval |= LPAIF_I2SCTL_MICMODE_SD0; + regval |= LPAIF_I2SCTL_MICMONO_MONO; + break; + case 2: + regval |= LPAIF_I2SCTL_MICMODE_SD0; + regval |= LPAIF_I2SCTL_MICMONO_STEREO; + break; + case 4: + regval |= LPAIF_I2SCTL_MICMODE_QUAD01; + regval |= LPAIF_I2SCTL_MICMONO_STEREO; + break; + case 6: + regval |= LPAIF_I2SCTL_MICMODE_6CH; + regval |= LPAIF_I2SCTL_MICMONO_STEREO; + break; + case 8: + regval |= LPAIF_I2SCTL_MICMODE_8CH; + regval |= LPAIF_I2SCTL_MICMONO_STEREO; + break; + default: + dev_err(dai->dev, "%s() invalid channels given: %u\n", + __func__, channels); + return -EINVAL; + } } ret = regmap_write(drvdata->lpaif_map, @@ -188,10 +217,19 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream, { struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); int ret; + unsigned int val, mask; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + val = LPAIF_I2SCTL_SPKEN_ENABLE; + mask = LPAIF_I2SCTL_SPKEN_MASK; + } else { + val = LPAIF_I2SCTL_MICEN_ENABLE; + mask = LPAIF_I2SCTL_MICEN_MASK; + } ret = regmap_update_bits(drvdata->lpaif_map, LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), - LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE); + mask, val); if (ret) dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", __func__, ret); @@ -204,16 +242,24 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream, { struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); int ret = -EINVAL; + unsigned int val, mask; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + val = LPAIF_I2SCTL_SPKEN_ENABLE; + mask = LPAIF_I2SCTL_SPKEN_MASK; + } else { + val = LPAIF_I2SCTL_MICEN_ENABLE; + mask = LPAIF_I2SCTL_MICEN_MASK; + } + ret = regmap_update_bits(drvdata->lpaif_map, LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), - LPAIF_I2SCTL_SPKEN_MASK, - LPAIF_I2SCTL_SPKEN_ENABLE); + mask, val); if (ret) dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", __func__, ret); @@ -221,11 +267,18 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + val = LPAIF_I2SCTL_SPKEN_DISABLE; + mask = LPAIF_I2SCTL_SPKEN_MASK; + } else { + val = LPAIF_I2SCTL_MICEN_DISABLE; + mask = LPAIF_I2SCTL_MICEN_MASK; + } + ret = regmap_update_bits(drvdata->lpaif_map, LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), - LPAIF_I2SCTL_SPKEN_MASK, - LPAIF_I2SCTL_SPKEN_DISABLE); + mask, val); if (ret) dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", __func__, ret); diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 348e50bc8891..6e8665430bd5 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -26,6 +26,7 @@ struct lpass_pcm_data { int rdma_ch; + int wrdma_ch; int i2s_port; }; @@ -90,10 +91,15 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, snd_pcm_format_t format = params_format(params); unsigned int channels = params_channels(params); unsigned int regval; - int dir = substream->stream; + int ch, dir = substream->stream; int bitwidth; int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start; + if (dir == SNDRV_PCM_STREAM_PLAYBACK) + ch = pcm_data->rdma_ch; + else + ch = pcm_data->wrdma_ch; + bitwidth = snd_pcm_format_width(format); if (bitwidth < 0) { dev_err(soc_runtime->dev, "%s() invalid bit width given: %d\n", @@ -158,7 +164,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, } ret = regmap_write(drvdata->lpaif_map, - LPAIF_DMACTL_REG(v, pcm_data->rdma_ch, dir), regval); + LPAIF_DMACTL_REG(v, ch, dir), regval); if (ret) { dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", __func__, ret); @@ -175,10 +181,15 @@ static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream) struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); struct lpass_variant *v = drvdata->variant; + unsigned int reg; int ret; - ret = regmap_write(drvdata->lpaif_map, - LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch), 0); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + reg = LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch); + else + reg = LPAIF_WRDMACTL_REG(v, pcm_data->wrdma_ch); + + ret = regmap_write(drvdata->lpaif_map, reg, 0); if (ret) dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", __func__, ret); @@ -194,11 +205,15 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream) struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); struct lpass_variant *v = drvdata->variant; - int ret, ch = pcm_data->rdma_ch; - int dir = substream->stream; + int ret, ch, dir = substream->stream; + + if (dir == SNDRV_PCM_STREAM_PLAYBACK) + ch = pcm_data->rdma_ch; + else + ch = pcm_data->wrdma_ch; ret = regmap_write(drvdata->lpaif_map, - LPAIF_RDMABASE_REG(v, ch), + LPAIF_DMABASE_REG(v, ch, dir), runtime->dma_addr); if (ret) { dev_err(soc_runtime->dev, "%s() error writing to rdmabase reg: %d\n", @@ -244,8 +259,12 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream, struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); struct lpass_variant *v = drvdata->variant; - int ret, ch = pcm_data->rdma_ch; - int dir = substream->stream; + int ret, ch, dir = substream->stream; + + if (dir == SNDRV_PCM_STREAM_PLAYBACK) + ch = pcm_data->rdma_ch; + else + ch = pcm_data->wrdma_ch; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -317,8 +336,12 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer( snd_soc_platform_get_drvdata(soc_runtime->platform); struct lpass_variant *v = drvdata->variant; unsigned int base_addr, curr_addr; - int ret, ch = pcm_data->rdma_ch; - int dir = substream->stream; + int ret, ch, dir = substream->stream; + + if (dir == SNDRV_PCM_STREAM_PLAYBACK) + ch = pcm_data->rdma_ch; + else + ch = pcm_data->wrdma_ch; ret = regmap_read(drvdata->lpaif_map, LPAIF_DMABASE_REG(v, ch, dir), &base_addr); @@ -446,8 +469,7 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data) static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) { struct snd_pcm *pcm = soc_runtime->pcm; - struct snd_pcm_substream *substream = - pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + struct snd_pcm_substream *psubstream, *csubstream; struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai; struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); @@ -460,55 +482,108 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) if (!data) return -ENOMEM; - if (v->alloc_dma_channel) - data->rdma_ch = v->alloc_dma_channel(drvdata, - SNDRV_PCM_STREAM_PLAYBACK); + data->i2s_port = cpu_dai->driver->id; + snd_soc_pcm_set_drvdata(soc_runtime, data); - if (IS_ERR_VALUE(data->rdma_ch)) - return data->rdma_ch; + psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + if (psubstream) { + if (v->alloc_dma_channel) + data->rdma_ch = v->alloc_dma_channel(drvdata, + SNDRV_PCM_STREAM_PLAYBACK); - drvdata->substream[data->rdma_ch] = substream; - data->i2s_port = cpu_dai->driver->id; + if (IS_ERR_VALUE(data->rdma_ch)) + return data->rdma_ch; - snd_soc_pcm_set_drvdata(soc_runtime, data); + drvdata->substream[data->rdma_ch] = psubstream; - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, - soc_runtime->platform->dev, - size, &substream->dma_buffer); - if (ret) - return ret; + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, + soc_runtime->platform->dev, + size, &psubstream->dma_buffer); + if (ret) + goto playback_alloc_err; - ret = regmap_write(drvdata->lpaif_map, + ret = regmap_write(drvdata->lpaif_map, LPAIF_RDMACTL_REG(v, data->rdma_ch), 0); - if (ret) { - dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", + if (ret) { + dev_err(soc_runtime->dev, + "%s() error writing to rdmactl reg: %d\n", __func__, ret); - goto err_buf; + goto capture_alloc_err; + } + } + + csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; + if (csubstream) { + if (v->alloc_dma_channel) + data->wrdma_ch = v->alloc_dma_channel(drvdata, + SNDRV_PCM_STREAM_CAPTURE); + + if (IS_ERR_VALUE(data->wrdma_ch)) + goto capture_alloc_err; + + drvdata->substream[data->wrdma_ch] = csubstream; + + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, + soc_runtime->platform->dev, + size, &csubstream->dma_buffer); + if (ret) + goto capture_alloc_err; + + ret = regmap_write(drvdata->lpaif_map, + LPAIF_WRDMACTL_REG(v, data->wrdma_ch), 0); + if (ret) { + dev_err(soc_runtime->dev, + "%s() error writing to wrdmactl reg: %d\n", + __func__, ret); + goto capture_reg_err; + } } return 0; -err_buf: - snd_dma_free_pages(&substream->dma_buffer); +capture_reg_err: + if (csubstream) + snd_dma_free_pages(&csubstream->dma_buffer); + +capture_alloc_err: + if (psubstream) + snd_dma_free_pages(&psubstream->dma_buffer); + + playback_alloc_err: + dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n"); + return ret; } static void lpass_platform_pcm_free(struct snd_pcm *pcm) { - struct snd_pcm_substream *substream = - pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; - struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct lpass_data *drvdata = - snd_soc_platform_get_drvdata(soc_runtime->platform); - struct lpass_pcm_data *data = snd_soc_pcm_get_drvdata(soc_runtime); - struct lpass_variant *v = drvdata->variant; - - drvdata->substream[data->rdma_ch] = NULL; - - if (v->free_dma_channel) - v->free_dma_channel(drvdata, data->rdma_ch); - - snd_dma_free_pages(&substream->dma_buffer); + struct snd_soc_pcm_runtime *rt; + struct lpass_data *drvdata; + struct lpass_pcm_data *data; + struct lpass_variant *v; + struct snd_pcm_substream *substream; + int ch, i; + + for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) { + substream = pcm->streams[i].substream; + if (substream) { + rt = substream->private_data; + data = snd_soc_pcm_get_drvdata(rt); + drvdata = snd_soc_platform_get_drvdata(rt->platform); + + ch = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + ? data->rdma_ch + : data->wrdma_ch; + v = drvdata->variant; + drvdata->substream[ch] = NULL; + if (v->free_dma_channel) + v->free_dma_channel(drvdata, ch); + + snd_dma_free_pages(&substream->dma_buffer); + substream->dma_buffer.area = NULL; + substream->dma_buffer.addr = 0; + } + } } static struct snd_soc_platform_driver lpass_platform_driver = { -- cgit v1.2.3-59-g8ed1b From bbedefb9e8c350bc7e8e7dc4732ba1974789e3e9 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:18:45 +0000 Subject: ASoC: qcom: apq8016-sbc: add mic support This patch add mic support on apq8016-sbc board aka db410c. Tested it with headset mic. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/apq8016_sbc.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index 1efdf0088ecd..1289543c8fb2 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -30,6 +30,7 @@ struct apq8016_sbc_data { struct snd_soc_dai_link dai_link[]; /* dynamically allocated */ }; +#define MIC_CTRL_TER_WS_SLAVE_SEL BIT(21) #define MIC_CTRL_QUA_WS_SLAVE_SEL_10 BIT(17) #define MIC_CTRL_TLMM_SCLK_EN BIT(1) #define SPKR_CTL_PRI_WS_SLAVE_SEL_11 (BIT(17) | BIT(16)) @@ -53,6 +54,12 @@ static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd) MIC_CTRL_TLMM_SCLK_EN, pdata->mic_iomux); break; + case MI2S_TERTIARY: + writel(readl(pdata->mic_iomux) | MIC_CTRL_TER_WS_SLAVE_SEL | + MIC_CTRL_TLMM_SCLK_EN, + pdata->mic_iomux); + + break; default: dev_err(card->dev, "unsupported cpu dai configuration\n"); @@ -126,9 +133,6 @@ static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card) } link->platform_of_node = link->cpu_of_node; - /* For now we only support playback */ - link->playback_only = true; - ret = of_property_read_string(np, "link-name", &link->name); if (ret) { dev_err(card->dev, "error getting codec dai_link name\n"); -- cgit v1.2.3-59-g8ed1b From 6a9364ca6fa07ec215b0ba7c49d110b8236985d4 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:19:30 +0000 Subject: ASoC: qcom: apq8016: add wrdma support This patch adds wrdma support in lpass-apq8016 by providing the register offsets and adding support in dma channel allocation callback. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-apq8016.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c index ca3bbd58c81a..3eef0c37ba50 100644 --- a/sound/soc/qcom/lpass-apq8016.c +++ b/sound/soc/qcom/lpass-apq8016.c @@ -137,11 +137,23 @@ static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata, int direction) { struct lpass_variant *v = drvdata->variant; - int chan = find_first_zero_bit(&drvdata->dma_ch_bit_map, + int chan = 0; + + 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; + 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); @@ -214,6 +226,10 @@ static struct lpass_variant apq8016_data = { .rdma_reg_stride = 0x1000, .rdma_channels = 2, .dmactl_audif_start = 1, + .wrdma_reg_base = 0xB000, + .wrdma_reg_stride = 0x1000, + .wrdma_channel_start = 5, + .wrdma_channels = 2, .dai_driver = apq8016_lpass_cpu_dai_driver, .num_dai = ARRAY_SIZE(apq8016_lpass_cpu_dai_driver), .init = apq8016_lpass_init, -- cgit v1.2.3-59-g8ed1b From aa3e838869d494c437c693b54d12fe02b96a0aa1 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 25 Feb 2016 23:02:04 +0100 Subject: ASoC: pxa: remove unused variable As pointed out by Zhangfei Gao, the sspa_div variable in brownstone_wm8994_hw_params() is completely unused, so as a cleanup following a prior patch, this removes both the variable and the division. Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- sound/soc/pxa/brownstone.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c index 416ea646c3b1..ec522e94b0e2 100644 --- a/sound/soc/pxa/brownstone.c +++ b/sound/soc/pxa/brownstone.c @@ -52,7 +52,6 @@ static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int freq_out, sspa_mclk, sysclk; - int sspa_div; if (params_rate(params) > 11025) { freq_out = params_rate(params) * 512; @@ -63,7 +62,6 @@ static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream, sysclk = params_rate(params) * 512; sspa_mclk = params_rate(params) * 64; } - sspa_div = freq_out / sspa_mclk; snd_soc_dai_set_sysclk(cpu_dai, MMP_SSPA_CLK_AUDIO, freq_out, 0); snd_soc_dai_set_pll(cpu_dai, MMP_SYSCLK, 0, freq_out, sysclk); -- cgit v1.2.3-59-g8ed1b From 568cecf42f35bf40bdf94107fb638997f82827f7 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 11 Mar 2016 23:42:52 +0530 Subject: ASoC: qcom: fix build error While building m32r allmodconfig the build failed with: ERROR: "bad_dma_ops" [sound/soc/qcom/snd-soc-lpass-platform.ko] undefined! ERROR: "dma_common_mmap" [sound/soc/qcom/snd-soc-lpass-platform.ko] undefined! To satisfy the dependency CONFIG_SND_SOC_LPASS_PLATFORM should depend on HAS_DMA. Some other configs also needs the dependency on HAS_DMA as they are directly or indirectly selecting SND_SOC_LPASS_PLATFORM. Signed-off-by: Sudip Mukherjee Signed-off-by: Mark Brown --- sound/soc/qcom/Kconfig | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 3cc252e55468..8ec9a074b38b 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -11,21 +11,24 @@ config SND_SOC_LPASS_CPU config SND_SOC_LPASS_PLATFORM tristate + depends on HAS_DMA select REGMAP_MMIO config SND_SOC_LPASS_IPQ806X tristate + depends on HAS_DMA select SND_SOC_LPASS_CPU select SND_SOC_LPASS_PLATFORM config SND_SOC_LPASS_APQ8016 tristate + depends on HAS_DMA select SND_SOC_LPASS_CPU select SND_SOC_LPASS_PLATFORM config SND_SOC_STORM tristate "ASoC I2S support for Storm boards" - depends on SND_SOC_QCOM + depends on SND_SOC_QCOM && HAS_DMA select SND_SOC_LPASS_IPQ806X select SND_SOC_MAX98357A help @@ -34,7 +37,7 @@ config SND_SOC_STORM config SND_SOC_APQ8016_SBC tristate "SoC Audio support for APQ8016 SBC platforms" - depends on SND_SOC_QCOM + depends on SND_SOC_QCOM && HAS_DMA select SND_SOC_LPASS_APQ8016 help Support for Qualcomm Technologies LPASS audio block in -- cgit v1.2.3-59-g8ed1b