aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinaro CI <ci_notify@linaro.org>2020-09-11 11:16:14 +0000
committerLinaro CI <ci_notify@linaro.org>2020-09-11 11:16:14 +0000
commit9b3f3942f95371439e742658300bdfedfc680621 (patch)
tree6b77f00a038ced71151000cbc465588bb4b228e8
parent9e683e94b7354014451a8b5b826fec4fee2f7c8a (diff)
parent981d64631aaca39e3b597b2411f58c601fde6c30 (diff)
Merge remote-tracking branch 'audio/tracking-qcomlt-audio' into integration-linux-qcomlt
-rw-r--r--Documentation/devicetree/bindings/slimbus/slim-ngd-qcom-ctrl.txt1
-rw-r--r--drivers/clk/qcom/Kconfig8
-rw-r--r--drivers/clk/qcom/Makefile1
-rw-r--r--drivers/clk/qcom/lpasscc-sm8250.c276
-rw-r--r--drivers/pinctrl/qcom/Kconfig8
-rw-r--r--drivers/pinctrl/qcom/Makefile1
-rw-r--r--drivers/pinctrl/qcom/pinctrl-lpass.c627
-rw-r--r--drivers/slimbus/qcom-ngd-ctrl.c3
-rw-r--r--drivers/soundwire/Kconfig1
-rw-r--r--drivers/soundwire/qcom.c108
-rw-r--r--drivers/soundwire/stream.c24
-rw-r--r--include/dt-bindings/clock/qcom,audiocc-sm8250.h17
-rw-r--r--include/dt-bindings/sound/qcom,q6afe.h96
-rw-r--r--sound/soc/codecs/Kconfig3
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/lpass-wsa-macro.c3069
-rw-r--r--sound/soc/codecs/lpass-wsa-macro.h623
-rw-r--r--sound/soc/qcom/Kconfig22
-rw-r--r--sound/soc/qcom/Makefile2
-rw-r--r--sound/soc/qcom/apq8096.c48
-rw-r--r--sound/soc/qcom/qdsp6/Makefile1
-rw-r--r--sound/soc/qcom/qdsp6/q6afe-clocks.c295
-rw-r--r--sound/soc/qcom/qdsp6/q6afe-dai.c229
-rw-r--r--sound/soc/qcom/qdsp6/q6afe.c308
-rw-r--r--sound/soc/qcom/qdsp6/q6afe.h33
-rw-r--r--sound/soc/qcom/qdsp6/q6asm-dai.c414
-rw-r--r--sound/soc/qcom/qdsp6/q6asm.c169
-rw-r--r--sound/soc/qcom/qdsp6/q6asm.h49
-rw-r--r--sound/soc/qcom/qdsp6/q6routing.c121
-rw-r--r--sound/soc/qcom/sm8250.c199
30 files changed, 6538 insertions, 220 deletions
diff --git a/Documentation/devicetree/bindings/slimbus/slim-ngd-qcom-ctrl.txt b/Documentation/devicetree/bindings/slimbus/slim-ngd-qcom-ctrl.txt
index e94a2ad3a710..1c615b622d07 100644
--- a/Documentation/devicetree/bindings/slimbus/slim-ngd-qcom-ctrl.txt
+++ b/Documentation/devicetree/bindings/slimbus/slim-ngd-qcom-ctrl.txt
@@ -14,6 +14,7 @@ Please refer to slimbus/bus.txt for details of the common SLIMBus bindings.
must be one of the following.
"qcom,slim-ngd-v1.5.0" for MSM8996
"qcom,slim-ngd-v2.1.0" for SDM845
+ "qcom,slim-ngd-v2.2.0" for SM8250
- reg:
Usage: required
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 058327310c25..21784c9395b2 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -475,4 +475,12 @@ config KRAITCC
Support for the Krait CPU clocks on Qualcomm devices.
Say Y if you want to support CPU frequency scaling.
+config CLK_GFM_LPASS
+ tristate "GFM LPASS Clocks"
+ depends on SND_SOC_QDSP6_COMMON
+ help
+ Support for the GFM Glitch Free Mux LPASS clock. Say Y
+ if you want to support GFM Clocks on LPASS for devices such
+ as SM8250 etc.
+
endif
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 9677e769e7e9..d918b4716d27 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -72,3 +72,4 @@ obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o
obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o
obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
obj-$(CONFIG_KRAITCC) += krait-cc.o
+obj-$(CONFIG_CLK_GFM_LPASS) += lpasscc-sm8250.o
diff --git a/drivers/clk/qcom/lpasscc-sm8250.c b/drivers/clk/qcom/lpasscc-sm8250.c
new file mode 100644
index 000000000000..3c434b1e385e
--- /dev/null
+++ b/drivers/clk/qcom/lpasscc-sm8250.c
@@ -0,0 +1,276 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <dt-bindings/clock/qcom,audiocc-sm8250.h>
+
+struct lpasscc_sm8250 {
+ struct device *dev;
+ void __iomem *audiocc;
+ void __iomem *aocc;
+};
+
+struct clk_gfm {
+ int id;
+ unsigned int mux_reg;
+ unsigned int mux_mask;
+ struct clk_hw hw;
+ struct lpasscc_sm8250 *priv;
+ void __iomem *gfm_mux;
+};
+
+#define GFM_MASK BIT(1)
+#define to_clk_gfm(_hw) container_of(_hw, struct clk_gfm, hw)
+
+static u8 clk_gfm_get_parent(struct clk_hw *hw)
+{
+ struct clk_gfm *clk = to_clk_gfm(hw);
+
+ return readl(clk->gfm_mux) & GFM_MASK;
+}
+
+static int clk_gfm_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_gfm *clk = to_clk_gfm(hw);
+ unsigned int val;
+
+ val = readl(clk->gfm_mux);
+
+ if (index)
+ val |= GFM_MASK;
+ else
+ val &= ~GFM_MASK;
+
+ writel(val, clk->gfm_mux);
+
+ return 0;
+}
+
+static const struct clk_ops clk_gfm_ops = {
+ .get_parent = clk_gfm_get_parent,
+ .set_parent = clk_gfm_set_parent,
+ .determine_rate = __clk_mux_determine_rate,
+};
+
+static struct clk_gfm lpass_gfm_va_mclk = {
+ .mux_reg = 0x20000,
+ .mux_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "VA_MCLK",
+ .ops = &clk_gfm_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ .parent_names = (const char *[]) {
+ "LPASS_CLK_ID_TX_CORE_MCLK",
+ "LPASS_CLK_ID_VA_CORE_MCLK",
+ },
+ .num_parents = 2,
+ .parent_data = (const struct clk_parent_data[]){
+ { .index = 0 },
+ { .index = 1 },
+ },
+ },
+};
+
+static struct clk_gfm lpass_gfm_tx_npl = {
+ .mux_reg = 0x20000,
+ .mux_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "TX_NPL",
+ .ops = &clk_gfm_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ .parent_names = (const char *[]){
+ "LPASS_CLK_ID_TX_CORE_NPL_MCLK",
+ "LPASS_CLK_ID_VA_CORE_2X_MCLK",
+ },
+ .parent_data = (const struct clk_parent_data[]){
+ { .index = 0 },
+ { .index = 1 },
+ },
+ .num_parents = 2,
+ },
+};
+
+static struct clk_gfm lpass_gfm_wsa_mclk = {
+ .mux_reg = 0x220d8,
+ .mux_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "WSA_MCLK",
+ .ops = &clk_gfm_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ .parent_names = (const char *[]){
+ "LPASS_CLK_ID_TX_CORE_MCLK",
+ "LPASS_CLK_ID_WSA_CORE_MCLK",
+ },
+ .parent_data = (const struct clk_parent_data[]){
+ { .index = 0 },
+ { .index = 1 },
+ },
+ .num_parents = 2,
+ },
+};
+
+static struct clk_gfm lpass_gfm_wsa_npl = {
+ .mux_reg = 0x220d8,
+ .mux_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "WSA_NPL",
+ .ops = &clk_gfm_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ .parent_names = (const char *[]){
+ "LPASS_CLK_ID_TX_CORE_NPL_MCLK",
+ "LPASS_CLK_ID_WSA_CORE_NPL_MCLK",
+ },
+ .parent_data = (const struct clk_parent_data[]){
+ { .index = 0 },
+ { .index = 1 },
+ },
+ .num_parents = 2,
+ },
+};
+
+static struct clk_gfm lpass_gfm_rx_mclk_mclk2 = {
+ .mux_reg = 0x240d8,
+ .mux_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "RX_MCLK_MCLK2",
+ .ops = &clk_gfm_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ .parent_names = (const char *[]){
+ "LPASS_CLK_ID_TX_CORE_MCLK",
+ "LPASS_CLK_ID_RX_CORE_MCLK",
+ },
+ .parent_data = (const struct clk_parent_data[]){
+ { .index = 0 },
+ { .index = 1 },
+ },
+ .num_parents = 2,
+ },
+};
+
+static struct clk_gfm lpass_gfm_rx_npl = {
+ .mux_reg = 0x240d8,
+ .mux_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "RX_NPL",
+ .ops = &clk_gfm_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ .parent_names = (const char *[]){
+ "LPASS_CLK_ID_TX_CORE_NPL_MCLK",
+ "LPASS_CLK_ID_RX_CORE_NPL_MCLK",
+ },
+ .parent_data = (const struct clk_parent_data[]){
+ { .index = 0 },
+ { .index = 1 },
+ },
+ .num_parents = 2,
+ },
+};
+
+static struct clk_gfm *lpass_gfm_clks[] = {
+ [LPASS_CDC_VA_MCLK] = &lpass_gfm_va_mclk,
+ [LPASS_CDC_TX_NPL] = &lpass_gfm_tx_npl,
+// [LPASS_CDC_TX_MCLK] = &lpass_gfm_tx_mclk
+ [LPASS_CDC_WSA_NPL] = &lpass_gfm_wsa_npl,
+ [LPASS_CDC_WSA_MCLK] = &lpass_gfm_wsa_mclk,
+// [LPASS_CDC_RX_MCLK] = &lpass_gfm_rx_mclk_mclk2,
+ [LPASS_CDC_RX_NPL] = &lpass_gfm_rx_npl,
+ [LPASS_CDC_RX_MCLK_MCLK2] = &lpass_gfm_rx_mclk_mclk2,
+};
+
+static struct clk_hw_onecell_data lpasscc_hw_onecell_data = {
+ .hws = {
+ [LPASS_CDC_VA_MCLK] = &lpass_gfm_va_mclk.hw,
+ [LPASS_CDC_TX_NPL] = &lpass_gfm_tx_npl.hw,
+// [LPASS_CDC_TX_MCLK] = &lpass_gfm_tx_mclk.hw,
+ [LPASS_CDC_WSA_NPL] = &lpass_gfm_wsa_npl.hw,
+ [LPASS_CDC_WSA_MCLK] = &lpass_gfm_wsa_mclk.hw,
+// [LPASS_CDC_RX_MCLK] = &lpass_gfm_rx_mclk_mclk2.hw
+ [LPASS_CDC_RX_NPL] = &lpass_gfm_rx_npl.hw,
+ [LPASS_CDC_RX_MCLK_MCLK2] = &lpass_gfm_rx_mclk_mclk2.hw,
+ },
+ .num = ARRAY_SIZE(lpass_gfm_clks),
+};
+
+extern bool q6core_is_adsp_ready(void);
+
+static int lpasscc_sm8250_clk_driver_probe(struct platform_device *pdev)
+{
+ struct lpasscc_sm8250 *lpasscc;
+ struct device *dev = &pdev->dev;
+ struct clk_gfm *gfm;
+ struct resource *res;
+ struct clk *lpass_core_hw_vote = NULL;
+ int err, i;
+
+ if (!q6core_is_adsp_ready())
+ return -EPROBE_DEFER;
+
+ lpass_core_hw_vote = devm_clk_get(&pdev->dev, "core");
+ if (IS_ERR(lpass_core_hw_vote)) {
+ dev_dbg(&pdev->dev, "%s: clk get %s failed\n",
+ __func__, "lpass_core_hw_vote");
+ return PTR_ERR(lpass_core_hw_vote);
+ }
+
+ clk_prepare_enable(lpass_core_hw_vote);
+
+ lpasscc = devm_kzalloc(dev, sizeof(*lpasscc), GFP_KERNEL);
+ if (!lpasscc)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ lpasscc->audiocc = devm_ioremap_resource(dev, res);
+ if (IS_ERR(lpasscc->audiocc))
+ return PTR_ERR(lpasscc->audiocc);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ lpasscc->aocc = devm_ioremap_resource(dev, res);
+ if (IS_ERR(lpasscc->aocc))
+ return PTR_ERR(lpasscc->aocc);
+
+ for (i = 0; i < ARRAY_SIZE(lpass_gfm_clks); i++) {
+ if (!lpass_gfm_clks[i])
+ continue;
+
+ gfm = lpass_gfm_clks[i];
+ gfm->priv = lpasscc;
+
+ if (i >= LPASS_CDC_WSA_NPL)
+ gfm->gfm_mux = lpasscc->audiocc;
+ else
+ gfm->gfm_mux = lpasscc->aocc;
+
+ gfm->gfm_mux = gfm->gfm_mux + lpass_gfm_clks[i]->mux_reg;
+
+ gfm->id = i;
+ err = devm_clk_hw_register(dev, &lpass_gfm_clks[i]->hw);
+ if (err)
+ return err;
+
+ }
+
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+ &lpasscc_hw_onecell_data);
+}
+
+static const struct of_device_id lpasscc_sm8250_clk_match_table[] = {
+ { .compatible = "qcom,sm8250-audiocc" },
+ { }
+};
+
+static struct platform_driver lpasscc_sm8250_clk_driver = {
+ .probe = lpasscc_sm8250_clk_driver_probe,
+ .driver = {
+ .name = "lpass-gfm-clk",
+ .of_match_table = lpasscc_sm8250_clk_match_table,
+ },
+};
+builtin_platform_driver(lpasscc_sm8250_clk_driver);
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index f8ff30cdafa6..d58633d38303 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -227,4 +227,12 @@ config PINCTRL_SM8250
Qualcomm Technologies Inc TLMM block found on the Qualcomm
Technologies Inc SM8250 platform.
+config PINCTRL_LPASS
+ tristate "Qualcomm Technologies Inc LPASS pin controller driver"
+ depends on GPIOLIB && OF
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm Technologies Inc LPASS (Low Power Audio SubSystem) found
+ on the Qualcomm Technologies Inc SoCs.
+
endif
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index 061ec9fb659b..3a6473ad2b19 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -27,3 +27,4 @@ obj-$(CONFIG_PINCTRL_SDM660) += pinctrl-sdm660.o
obj-$(CONFIG_PINCTRL_SDM845) += pinctrl-sdm845.o
obj-$(CONFIG_PINCTRL_SM8150) += pinctrl-sm8150.o
obj-$(CONFIG_PINCTRL_SM8250) += pinctrl-sm8250.o
+obj-$(CONFIG_PINCTRL_LPASS) += pinctrl-lpass.o
diff --git a/drivers/pinctrl/qcom/pinctrl-lpass.c b/drivers/pinctrl/qcom/pinctrl-lpass.c
new file mode 100644
index 000000000000..0ba9cc570b76
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-lpass.c
@@ -0,0 +1,627 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/bitops.h>
+
+#include "../core.h"
+#include "../pinctrl-utils.h"
+
+#define LPI_GPIO_REG_VAL_CTL 0x00
+#define LPI_GPIO_REG_DIR_CTL 0x04
+
+#define LPI_SLEW_REG_VAL_CTL 0x00
+#define LPI_SLEW_RATE_MAX 0x03
+#define LPI_SLEW_BITS_SIZE 0x02
+#define LPI_SLEW_OFFSET_INVALID 0xFFFFFFFF
+
+#define LPI_GPIO_REG_PULL_SHIFT 0x0
+#define LPI_GPIO_REG_PULL_MASK 0x3
+
+#define LPI_GPIO_REG_FUNCTION_SHIFT 0x2
+#define LPI_GPIO_REG_FUNCTION_MASK 0x3C
+
+#define LPI_GPIO_REG_OUT_STRENGTH_SHIFT 0x6
+#define LPI_GPIO_REG_OUT_STRENGTH_MASK 0x1C0
+
+#define LPI_GPIO_REG_OE_SHIFT 0x9
+#define LPI_GPIO_REG_OE_MASK 0x200
+
+#define LPI_GPIO_REG_DIR_SHIFT 0x1
+#define LPI_GPIO_REG_DIR_MASK 0x2
+
+#define LPI_GPIO_BIAS_DISABLE 0x0
+#define LPI_GPIO_PULL_DOWN 0x1
+#define LPI_GPIO_KEEPER 0x2
+#define LPI_GPIO_PULL_UP 0x3
+
+#define LPI_GPIO_FUNC_GPIO "gpio"
+#define LPI_GPIO_FUNC_FUNC1 "func1"
+#define LPI_GPIO_FUNC_FUNC2 "func2"
+#define LPI_GPIO_FUNC_FUNC3 "func3"
+#define LPI_GPIO_FUNC_FUNC4 "func4"
+#define LPI_GPIO_FUNC_FUNC5 "func5"
+
+/* The index of each function in lpass_gpio_functions[] array */
+enum lpass_gpio_func_index {
+ LPI_GPIO_FUNC_INDEX_GPIO = 0x00,
+ LPI_GPIO_FUNC_INDEX_FUNC1 = 0x01,
+ LPI_GPIO_FUNC_INDEX_FUNC2 = 0x02,
+ LPI_GPIO_FUNC_INDEX_FUNC3 = 0x03,
+ LPI_GPIO_FUNC_INDEX_FUNC4 = 0x04,
+ LPI_GPIO_FUNC_INDEX_FUNC5 = 0x05,
+};
+
+struct lpass_pinctrl_variant_data {
+ int tlmm_reg_offset;
+ const struct pinctrl_pin_desc *pins;
+ int npins;
+ const char *const *groups;
+ int ngroups;
+ int *slew_reg_pin_offsets;
+};
+
+struct lpass_pinctrl {
+ struct device *dev;
+ struct pinctrl_dev *ctrl;
+ struct gpio_chip chip;
+ struct pinctrl_desc desc;
+ char __iomem *tlmm_base;
+ char __iomem *slew_base;
+
+// char __iomem *base;
+ struct clk *lpass_core_hw_vote;
+ struct clk *lpass_audio_hw_vote;
+ struct mutex slew_access_lock;
+// bool core_hw_vote_status;
+// struct mutex core_hw_vote_lock;
+ const struct lpass_pinctrl_variant_data *data;
+};
+
+/* sm8250 variant specific data */
+#define SM8250_LPASS_PINS 14
+static const char *const sm8250_gpio_groups[SM8250_LPASS_PINS] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4",
+ "gpio5", "gpio6", "gpio7", "gpio8", "gpio9",
+ "gpio10", "gpio11", "gpio12", "gpio13"
+};
+
+static const struct pinctrl_pin_desc sm8250_lpass_pins[] = {
+ PINCTRL_PIN(0, "gpio0"),
+ PINCTRL_PIN(1, "gpio1"),
+ PINCTRL_PIN(2, "gpio2"),
+ PINCTRL_PIN(3, "gpio3"),
+ PINCTRL_PIN(4, "gpio4"),
+ PINCTRL_PIN(5, "gpio5"),
+ PINCTRL_PIN(6, "gpio6"),
+ PINCTRL_PIN(7, "gpio7"),
+ PINCTRL_PIN(8, "gpio8"),
+ PINCTRL_PIN(9, "gpio9"),
+ PINCTRL_PIN(10, "gpio10"),
+ PINCTRL_PIN(11, "gpio11"),
+ PINCTRL_PIN(12, "gpio12"),
+ PINCTRL_PIN(13, "gpio13"),
+};
+
+static int sm8250_slew_reg_offsets[] = {
+ 0x0, 0x2, 0x4, 0x8, 0xa,
+ 0xc, 0x0, 0x0, 0x0, 0x10,
+ 0x12, 0x0, 0x0, 0x0
+};
+
+static struct lpass_pinctrl_variant_data sm8250_lpass_data = {
+ .tlmm_reg_offset = 0x1000,
+ .pins = sm8250_lpass_pins,
+ .npins = ARRAY_SIZE(sm8250_lpass_pins),
+ .slew_reg_pin_offsets = sm8250_slew_reg_offsets,
+ .groups = sm8250_gpio_groups,
+ .ngroups = ARRAY_SIZE(sm8250_gpio_groups),
+};
+
+static const char *const lpass_gpio_functions[] = {
+ [LPI_GPIO_FUNC_INDEX_GPIO] = LPI_GPIO_FUNC_GPIO,
+ [LPI_GPIO_FUNC_INDEX_FUNC1] = LPI_GPIO_FUNC_FUNC1,
+ [LPI_GPIO_FUNC_INDEX_FUNC2] = LPI_GPIO_FUNC_FUNC2,
+ [LPI_GPIO_FUNC_INDEX_FUNC3] = LPI_GPIO_FUNC_FUNC3,
+ [LPI_GPIO_FUNC_INDEX_FUNC4] = LPI_GPIO_FUNC_FUNC4,
+ [LPI_GPIO_FUNC_INDEX_FUNC5] = LPI_GPIO_FUNC_FUNC5,
+};
+
+static int lpass_gpio_read(struct lpass_pinctrl *state, unsigned int pin,
+ unsigned int addr)
+{
+ return ioread32(state->tlmm_base +
+ state->data->tlmm_reg_offset * pin + addr);
+}
+
+static int lpass_gpio_write(struct lpass_pinctrl *state, unsigned int pin,
+ unsigned int addr, unsigned int val)
+{
+ iowrite32(val, state->tlmm_base +
+ state->data->tlmm_reg_offset * pin + addr);
+ return 0;
+}
+
+static int lpass_gpio_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ /* Every PIN is a group */
+ return pctldev->desc->npins;
+}
+
+static const char *lpass_gpio_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned int pin)
+{
+ struct lpass_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctrl->data->groups[pin];
+}
+
+static int lpass_gpio_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned int pin,
+ const unsigned int **pins,
+ unsigned int *num_pins)
+{
+ *pins = &pctldev->desc->pins[pin].number;
+ *num_pins = 1;
+
+ return 0;
+}
+
+static const struct pinctrl_ops lpass_gpio_pinctrl_ops = {
+ .get_groups_count = lpass_gpio_get_groups_count,
+ .get_group_name = lpass_gpio_get_group_name,
+ .get_group_pins = lpass_gpio_get_group_pins,
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_group,
+ .dt_free_map = pinctrl_utils_free_map,
+};
+
+static int lpass_gpio_get_functions_count(struct pinctrl_dev *pctldev)
+{
+ return ARRAY_SIZE(lpass_gpio_functions);
+}
+
+static const char *lpass_gpio_get_function_name(struct pinctrl_dev *pctldev,
+ unsigned int function)
+{
+ return lpass_gpio_functions[function];
+}
+
+static int lpass_gpio_get_function_groups(struct pinctrl_dev *pctldev,
+ unsigned int function,
+ const char *const **groups,
+ unsigned *const num_qgroups)
+{
+ struct lpass_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = pctrl->data->groups;
+ *num_qgroups = pctrl->data->ngroups;
+
+ return 0;
+}
+
+static int lpass_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
+ unsigned int pin)
+{
+ struct lpass_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ unsigned int val;
+
+ val = lpass_gpio_read(pctrl, pin, LPI_GPIO_REG_VAL_CTL);
+ val &= ~(LPI_GPIO_REG_FUNCTION_MASK);
+ val |= function << LPI_GPIO_REG_FUNCTION_SHIFT;
+ lpass_gpio_write(pctrl, pin, LPI_GPIO_REG_VAL_CTL, val);
+
+ return 0;
+}
+
+static const struct pinmux_ops lpass_gpio_pinmux_ops = {
+ .get_functions_count = lpass_gpio_get_functions_count,
+ .get_function_name = lpass_gpio_get_function_name,
+ .get_function_groups = lpass_gpio_get_function_groups,
+ .set_mux = lpass_gpio_set_mux,
+};
+
+static int lpass_config_get(struct pinctrl_dev *pctldev,
+ unsigned int pin, unsigned long *config)
+{
+ unsigned int param = pinconf_to_config_param(*config);
+ struct lpass_pinctrl *state = dev_get_drvdata(pctldev->dev);
+ unsigned int arg = 0;
+ int is_out;
+ int pull;
+ u32 ctl_reg;
+
+ ctl_reg = lpass_gpio_read(state, pin, LPI_GPIO_REG_DIR_CTL);
+
+ is_out = (ctl_reg & LPI_GPIO_REG_DIR_MASK) >> LPI_GPIO_REG_DIR_SHIFT;
+
+ ctl_reg = lpass_gpio_read(state, pin, LPI_GPIO_REG_VAL_CTL);
+
+ pull = (ctl_reg & LPI_GPIO_REG_PULL_MASK) >> LPI_GPIO_REG_PULL_SHIFT;
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ if (pull == LPI_GPIO_BIAS_DISABLE)
+ arg = 1;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ if (pull == LPI_GPIO_PULL_DOWN)
+ arg = 1;
+ break;
+ case PIN_CONFIG_BIAS_BUS_HOLD:
+ if (pull == LPI_GPIO_KEEPER)
+ arg = 1;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (pull == LPI_GPIO_PULL_UP)
+ arg = 1;
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ case PIN_CONFIG_OUTPUT:
+ if (is_out)
+ arg = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *config = pinconf_to_config_packed(param, arg);
+ return 0;
+}
+
+static unsigned int lpass_drive_to_regval(u32 arg)
+{
+ return (arg/2 - 1);
+}
+
+static int lpass_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned long *configs, unsigned int nconfs)
+{
+ unsigned int param, arg;
+ int i, ret = 0;
+ volatile unsigned long val;
+ struct lpass_pinctrl *state = dev_get_drvdata(pctldev->dev);
+ bool output_enabled;
+ unsigned int pullup;
+ unsigned int strength;
+ unsigned int offset;
+ bool value;
+
+ for (i = 0; i < nconfs; i++) {
+ param = pinconf_to_config_param(configs[i]);
+ arg = pinconf_to_config_argument(configs[i]);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ pullup = LPI_GPIO_BIAS_DISABLE;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ pullup = LPI_GPIO_PULL_DOWN;
+ break;
+ case PIN_CONFIG_BIAS_BUS_HOLD:
+ pullup = LPI_GPIO_KEEPER;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ pullup = LPI_GPIO_PULL_UP;
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ output_enabled = false;
+ break;
+ case PIN_CONFIG_OUTPUT:
+ output_enabled = true;
+ lpass_gpio_write(state, pin, LPI_GPIO_REG_DIR_CTL,
+ output_enabled << LPI_GPIO_REG_DIR_SHIFT);
+ value = arg;
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ strength = arg;
+ break;
+ case PIN_CONFIG_SLEW_RATE:
+ if (arg > LPI_SLEW_RATE_MAX) {
+ dev_err(pctldev->dev, "%s: invalid slew rate %u for pin: %d\n",
+ __func__, arg, pin);
+ goto set_gpio;
+ }
+
+ mutex_lock(&state->slew_access_lock);
+
+ val = lpass_gpio_read(state, pin, LPI_SLEW_REG_VAL_CTL);
+
+ offset = state->data->slew_reg_pin_offsets[pin];//pad->slew_offset;
+ for (i = 0; i < LPI_SLEW_BITS_SIZE; i++) {
+ if (arg & 0x01)
+ set_bit(offset, &val);
+ else
+ clear_bit(offset, &val);
+ offset++;
+ arg = arg >> 1;
+ }
+ lpass_gpio_write(state, pin, LPI_SLEW_REG_VAL_CTL, val);
+
+ mutex_unlock(&state->slew_access_lock);
+ break;
+ default:
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+set_gpio:
+
+ val = lpass_gpio_read(state, pin, LPI_GPIO_REG_VAL_CTL);
+ val &= ~(LPI_GPIO_REG_PULL_MASK | LPI_GPIO_REG_OUT_STRENGTH_MASK |
+ LPI_GPIO_REG_OE_MASK);
+ val |= pullup << LPI_GPIO_REG_PULL_SHIFT;
+ val |= lpass_drive_to_regval(strength) << LPI_GPIO_REG_OUT_STRENGTH_SHIFT;
+ if (output_enabled)
+ val |= value << LPI_GPIO_REG_OE_SHIFT;
+
+ lpass_gpio_write(state, pin, LPI_GPIO_REG_VAL_CTL, val);
+ lpass_gpio_write(state, pin, LPI_GPIO_REG_DIR_CTL,
+ output_enabled << LPI_GPIO_REG_DIR_SHIFT);
+done:
+ return ret;
+}
+
+static const struct pinconf_ops lpass_gpio_pinconf_ops = {
+ .is_generic = true,
+ .pin_config_group_get = lpass_config_get,
+ .pin_config_group_set = lpass_config_set,
+};
+
+static int lpass_gpio_direction_input(struct gpio_chip *chip, unsigned int pin)
+{
+ struct lpass_pinctrl *state = gpiochip_get_data(chip);
+ unsigned long config;
+
+ config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1);
+
+ return lpass_config_set(state->ctrl, pin, &config, 1);
+}
+
+static int lpass_gpio_direction_output(struct gpio_chip *chip,
+ unsigned int pin, int val)
+{
+ struct lpass_pinctrl *state = gpiochip_get_data(chip);
+ unsigned long config;
+
+ config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val);
+
+ return lpass_config_set(state->ctrl, pin, &config, 1);
+}
+
+static int lpass_gpio_get(struct gpio_chip *chip, unsigned int pin)
+{
+ struct lpass_pinctrl *state = gpiochip_get_data(chip);
+ int value;
+
+ value = lpass_gpio_read(state, pin, LPI_GPIO_REG_VAL_CTL);
+ return value;
+}
+
+static void lpass_gpio_set(struct gpio_chip *chip, unsigned int pin, int value)
+{
+ struct lpass_pinctrl *state = gpiochip_get_data(chip);
+ unsigned long config;
+
+ config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value);
+
+ lpass_config_set(state->ctrl, pin, &config, 1);
+}
+#ifdef CONFIG_DEBUG_FS
+#include <linux/seq_file.h>
+
+static unsigned int lpass_regval_to_drive(u32 val)
+{
+ return (val + 1) * 2;
+}
+
+static void lpass_gpio_dbg_show_one(struct seq_file *s,
+ struct pinctrl_dev *pctldev,
+ struct gpio_chip *chip,
+ unsigned int offset,
+ unsigned int gpio)
+{
+ struct lpass_pinctrl *state = gpiochip_get_data(chip);
+ struct pinctrl_pin_desc pindesc;
+ unsigned int func;
+ int is_out;
+ int drive;
+ int pull;
+ u32 ctl_reg;
+
+ static const char * const pulls[] = {
+ "no pull",
+ "pull down",
+ "keeper",
+ "pull up"
+ };
+
+ pctldev = pctldev ? : state->ctrl;
+ pindesc = pctldev->desc->pins[offset];
+ ctl_reg = lpass_gpio_read(state, offset, LPI_GPIO_REG_DIR_CTL);
+ is_out = (ctl_reg & LPI_GPIO_REG_DIR_MASK) >> LPI_GPIO_REG_DIR_SHIFT;
+ ctl_reg = lpass_gpio_read(state, offset, LPI_GPIO_REG_VAL_CTL);
+
+ func = (ctl_reg & LPI_GPIO_REG_FUNCTION_MASK) >>
+ LPI_GPIO_REG_FUNCTION_SHIFT;
+ drive = (ctl_reg & LPI_GPIO_REG_OUT_STRENGTH_MASK) >>
+ LPI_GPIO_REG_OUT_STRENGTH_SHIFT;
+ pull = (ctl_reg & LPI_GPIO_REG_PULL_MASK) >> LPI_GPIO_REG_PULL_SHIFT;
+
+ seq_printf(s, " %-8s: %-3s %d",
+ pindesc.name, is_out ? "out" : "in", func);
+ seq_printf(s, " %dmA", lpass_regval_to_drive(drive));
+ seq_printf(s, " %s", pulls[pull]);
+}
+
+static void lpass_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+ unsigned int gpio = chip->base;
+ unsigned int i;
+
+ for (i = 0; i < chip->ngpio; i++, gpio++) {
+ lpass_gpio_dbg_show_one(s, NULL, chip, i, gpio);
+ seq_puts(s, "\n");
+ }
+}
+
+#else
+#define lpass_gpio_dbg_show NULL
+#endif
+
+static const struct gpio_chip lpass_gpio_template = {
+ .direction_input = lpass_gpio_direction_input,
+ .direction_output = lpass_gpio_direction_output,
+ .get = lpass_gpio_get,
+ .set = lpass_gpio_set,
+ .request = gpiochip_generic_request,
+ .free = gpiochip_generic_free,
+ .dbg_show = lpass_gpio_dbg_show,
+};
+
+static int lpass_pinctrl_probe(struct platform_device *pdev)
+{
+ int ret, npins;
+ struct clk *lpass_core_hw_vote = NULL;
+ struct clk *lpass_audio_hw_vote = NULL;
+
+ struct lpass_pinctrl *pctrl;
+ const struct lpass_pinctrl_variant_data *data;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+
+ pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL);
+ if (!pctrl)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, pctrl);
+
+ data = of_device_get_match_data(dev);
+ pctrl->data = data;
+ pctrl->dev = &pdev->dev;
+ npins = data->npins;
+
+ /* Register LPASS core hw vote */
+ lpass_core_hw_vote = devm_clk_get(&pdev->dev, "core");
+ if (IS_ERR(lpass_core_hw_vote)) {
+ dev_dbg(&pdev->dev, "%s: clk get %s failed %d\n",
+ __func__, "lpass_core_hw_vote", ret);
+ return PTR_ERR(lpass_core_hw_vote);
+ }
+ pctrl->lpass_core_hw_vote = lpass_core_hw_vote;
+
+ /* Register LPASS audio hw vote */
+ lpass_audio_hw_vote = devm_clk_get(&pdev->dev, "audio");
+ if (IS_ERR(lpass_audio_hw_vote)) {
+ dev_dbg(&pdev->dev, "%s: clk get %s failed %d\n",
+ __func__, "lpass_audio_hw_vote", ret);
+ return PTR_ERR(lpass_audio_hw_vote);
+ }
+
+ pctrl->lpass_audio_hw_vote = lpass_audio_hw_vote;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pctrl->tlmm_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pctrl->tlmm_base))
+ return PTR_ERR(pctrl->tlmm_base);
+
+ clk_prepare_enable(pctrl->lpass_core_hw_vote);
+ clk_prepare_enable(pctrl->lpass_audio_hw_vote);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ pctrl->slew_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pctrl->slew_base))
+ return PTR_ERR(pctrl->slew_base);
+
+ pctrl->desc.pctlops = &lpass_gpio_pinctrl_ops;
+ pctrl->desc.pmxops = &lpass_gpio_pinmux_ops;
+ pctrl->desc.confops = &lpass_gpio_pinconf_ops;
+
+ pctrl->desc.owner = THIS_MODULE;
+ pctrl->desc.name = dev_name(dev);
+ pctrl->desc.pins = data->pins;
+ pctrl->desc.npins = data->npins;
+
+ pctrl->chip = lpass_gpio_template;
+ pctrl->chip.parent = dev;
+ pctrl->chip.base = -1;
+ pctrl->chip.ngpio = npins;
+ pctrl->chip.label = dev_name(dev);
+ pctrl->chip.of_gpio_n_cells = 2;
+ pctrl->chip.can_sleep = false;
+
+ mutex_init(&pctrl->slew_access_lock);
+// mutex_init(&pctrl->core_hw_vote_lock);
+
+ pctrl->ctrl = devm_pinctrl_register(dev, &pctrl->desc, pctrl);
+ if (IS_ERR(pctrl->ctrl))
+ return PTR_ERR(pctrl->ctrl);
+
+ ret = gpiochip_add_data(&pctrl->chip, pctrl);
+ if (ret) {
+ dev_err(pctrl->dev, "can't add gpio chip\n");
+ goto err_chip;
+ }
+
+ ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(dev), 0, 0, npins);
+ if (ret) {
+ dev_err(dev, "failed to add pin range\n");
+ goto err_range;
+ }
+
+ return 0;
+
+err_range:
+ gpiochip_remove(&pctrl->chip);
+err_chip:
+// mutex_destroy(&pctrl->core_hw_vote_lock);
+ mutex_destroy(&pctrl->slew_access_lock);
+ return ret;
+}
+
+static int lpass_pinctrl_remove(struct platform_device *pdev)
+{
+ struct lpass_pinctrl *state = platform_get_drvdata(pdev);
+
+ gpiochip_remove(&state->chip);
+// mutex_destroy(&state->core_hw_vote_lock);
+ mutex_destroy(&state->slew_access_lock);
+
+ return 0;
+}
+
+static const struct of_device_id lpass_pinctrl_of_match[] = {
+ {
+ .compatible = "qcom,sm8250-lpass-pinctrl",
+ .data = &sm8250_lpass_data,
+ },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, lpass_pinctrl_of_match);
+
+static struct platform_driver lpass_pinctrl_driver = {
+ .driver = {
+ .name = "qcom-lpass-pinctrl",
+ .of_match_table = lpass_pinctrl_of_match,
+ },
+ .probe = lpass_pinctrl_probe,
+ .remove = lpass_pinctrl_remove,
+};
+
+module_platform_driver(lpass_pinctrl_driver);
+
+MODULE_DESCRIPTION("QTI LPI GPIO pin control driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c
index 743ee7b4e63f..e643338678a6 100644
--- a/drivers/slimbus/qcom-ngd-ctrl.c
+++ b/drivers/slimbus/qcom-ngd-ctrl.c
@@ -1323,6 +1323,9 @@ static const struct of_device_id qcom_slim_ngd_dt_match[] = {
},{
.compatible = "qcom,slim-ngd-v2.1.0",
.data = &ngd_v1_5_offset_info,
+ },{
+ .compatible = "qcom,slim-ngd-v2.2.0",
+ .data = &ngd_v1_5_offset_info,
},
{}
};
diff --git a/drivers/soundwire/Kconfig b/drivers/soundwire/Kconfig
index fa2b4ab92ed9..d121cf739090 100644
--- a/drivers/soundwire/Kconfig
+++ b/drivers/soundwire/Kconfig
@@ -33,7 +33,6 @@ config SOUNDWIRE_INTEL
config SOUNDWIRE_QCOM
tristate "Qualcomm SoundWire Master driver"
- depends on SLIMBUS
depends on SND_SOC
help
SoundWire Qualcomm Master driver.
diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 915c2cf0c274..03c5bc05fc6e 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -34,6 +34,7 @@
#define SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED BIT(10)
#define SWRM_INTERRUPT_MASK_ADDR 0x204
#define SWRM_INTERRUPT_CLEAR 0x208
+#define SWRM_INTERRUPT_CPU_EN 0x210
#define SWRM_CMD_FIFO_WR_CMD 0x300
#define SWRM_CMD_FIFO_RD_CMD 0x304
#define SWRM_CMD_FIFO_CMD 0x308
@@ -56,6 +57,7 @@
#define SWRM_MCP_SLV_STATUS 0x1090
#define SWRM_MCP_SLV_STATUS_MASK GENMASK(1, 0)
#define SWRM_DP_PORT_CTRL_BANK(n, m) (0x1124 + 0x100 * (n - 1) + 0x40 * m)
+#define SWRM_DP_BLOCK_CTRL3_BANK(n, m) (0x1138 + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DP_PORT_CTRL_EN_CHAN_SHFT 0x18
#define SWRM_DP_PORT_CTRL_OFFSET2_SHFT 0x10
#define SWRM_DP_PORT_CTRL_OFFSET1_SHFT 0x08
@@ -67,11 +69,6 @@
#define SWRM_REG_VAL_PACK(data, dev, id, reg) \
((reg) | ((id) << 16) | ((dev) << 20) | ((data) << 24))
-#define SWRM_MAX_ROW_VAL 0 /* Rows = 48 */
-#define SWRM_DEFAULT_ROWS 48
-#define SWRM_MIN_COL_VAL 0 /* Cols = 2 */
-#define SWRM_DEFAULT_COL 16
-#define SWRM_MAX_COL_VAL 7
#define SWRM_SPECIAL_CMD_ID 0xF
#define MAX_FREQ_NUM 1
#define TIMEOUT_MS (2 * HZ)
@@ -84,12 +81,14 @@ struct qcom_swrm_port_config {
u8 si;
u8 off1;
u8 off2;
+ u8 bp_mode;
};
struct qcom_swrm_ctrl {
struct sdw_bus bus;
struct device *dev;
struct regmap *regmap;
+ void __iomem *mmio;
struct completion *comp;
struct work_struct slave_work;
/* read/write lock */
@@ -103,6 +102,8 @@ struct qcom_swrm_ctrl {
unsigned int version;
int num_din_ports;
int num_dout_ports;
+ int cols_index;
+ int rows_index;
unsigned long dout_port_mask;
unsigned long din_port_mask;
struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS];
@@ -112,9 +113,24 @@ struct qcom_swrm_ctrl {
int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val);
};
+struct qcom_swrm_data {
+ int default_cols;
+ int default_rows;
+};
+
+static struct qcom_swrm_data swrm_v1_3_data = {
+ .default_rows = 48,
+ .default_cols = 16,
+};
+
+static struct qcom_swrm_data swrm_v1_5_data = {
+ .default_rows = 50,
+ .default_cols = 16,
+};
+
#define to_qcom_sdw(b) container_of(b, struct qcom_swrm_ctrl, bus)
-static int qcom_swrm_abh_reg_read(struct qcom_swrm_ctrl *ctrl, int reg,
+static int qcom_swrm_ahb_reg_read(struct qcom_swrm_ctrl *ctrl, int reg,
u32 *val)
{
struct regmap *wcd_regmap = ctrl->regmap;
@@ -154,6 +170,20 @@ static int qcom_swrm_ahb_reg_write(struct qcom_swrm_ctrl *ctrl,
return SDW_CMD_OK;
}
+static int qcom_swrm_cpu_reg_read(struct qcom_swrm_ctrl *ctrl, int reg,
+ u32 *val)
+{
+ *val = readl(ctrl->mmio + reg);
+ return SDW_CMD_OK;
+}
+
+static int qcom_swrm_cpu_reg_write(struct qcom_swrm_ctrl *ctrl, int reg,
+ int val)
+{
+ writel(val, ctrl->mmio + reg);
+ return SDW_CMD_OK;
+}
+
static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl *ctrl, u8 cmd_data,
u8 dev_addr, u16 reg_addr)
{
@@ -284,8 +314,8 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
u32 val;
/* Clear Rows and Cols */
- val = (SWRM_MAX_ROW_VAL << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT |
- SWRM_MIN_COL_VAL << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT);
+ val = ctrl->rows_index << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT |
+ ctrl->cols_index << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT;
ctrl->reg_write(ctrl, SWRM_MCP_FRAME_CTRL_BANK_ADDR(0), val);
@@ -310,6 +340,12 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
ctrl->reg_write(ctrl, SWRM_COMP_CFG_ADDR,
SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK |
SWRM_COMP_CFG_ENABLE_MSK);
+
+ /* enable CPU IRQs */
+ if (ctrl->mmio) {
+ ctrl->reg_write(ctrl, SWRM_INTERRUPT_CPU_EN,
+ SWRM_INTERRUPT_STATUS_RMSK);
+ }
return 0;
}
@@ -358,8 +394,8 @@ static int qcom_swrm_pre_bank_switch(struct sdw_bus *bus)
val &= ~SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK;
val &= ~SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK;
- val |= (SWRM_MAX_ROW_VAL << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT |
- SWRM_MAX_COL_VAL << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT);
+ val |= ctrl->rows_index << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT |
+ ctrl->cols_index << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT;
return ctrl->reg_write(ctrl, reg, val);
}
@@ -378,14 +414,22 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
{
struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
u32 value;
+ int reg = SWRM_DP_PORT_CTRL_BANK((params->port_num), bank);
+ int ret;
value = params->offset1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT;
value |= params->offset2 << SWRM_DP_PORT_CTRL_OFFSET2_SHFT;
value |= params->sample_interval - 1;
- return ctrl->reg_write(ctrl,
- SWRM_DP_PORT_CTRL_BANK((params->port_num), bank),
- value);
+ ret = ctrl->reg_write(ctrl, reg, value);
+
+ if (!ret && params->blk_pkg_mode) {
+ reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank);
+
+ ret = ctrl->reg_write(ctrl, reg, 1);
+ }
+
+ return ret;
}
static int qcom_swrm_port_enable(struct sdw_bus *bus,
@@ -433,6 +477,7 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus)
p_rt->transport_params.sample_interval = pcfg->si + 1;
p_rt->transport_params.offset1 = pcfg->off1;
p_rt->transport_params.offset2 = pcfg->off2;
+ p_rt->transport_params.blk_pkg_mode = pcfg->bp_mode;
}
list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
@@ -443,6 +488,7 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus)
pcfg->si + 1;
p_rt->transport_params.offset1 = pcfg->off1;
p_rt->transport_params.offset2 = pcfg->off2;
+ p_rt->transport_params.blk_pkg_mode = pcfg->bp_mode;
i++;
}
}
@@ -689,6 +735,7 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl)
u8 off1[QCOM_SDW_MAX_PORTS];
u8 off2[QCOM_SDW_MAX_PORTS];
u8 si[QCOM_SDW_MAX_PORTS];
+ u8 bp_mode[QCOM_SDW_MAX_PORTS] = { 0, };
int i, ret, nports, val;
ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val);
@@ -731,10 +778,13 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl)
if (ret)
return ret;
+ ret = of_property_read_u8_array(np, "qcom,ports-block-pack-mode",
+ bp_mode, nports);
for (i = 0; i < nports; i++) {
ctrl->pconfig[i].si = si[i];
ctrl->pconfig[i].off1 = off1[i];
ctrl->pconfig[i].off2 = off2[i];
+ ctrl->pconfig[i].bp_mode = bp_mode[i];
}
return 0;
@@ -746,6 +796,8 @@ static int qcom_swrm_probe(struct platform_device *pdev)
struct sdw_master_prop *prop;
struct sdw_bus_params *params;
struct qcom_swrm_ctrl *ctrl;
+ const struct qcom_swrm_data *data;
+ struct resource *res;
int ret;
u32 val;
@@ -753,15 +805,28 @@ static int qcom_swrm_probe(struct platform_device *pdev)
if (!ctrl)
return -ENOMEM;
+ data = of_device_get_match_data(dev);
+ ctrl->rows_index = sdw_find_row_index(data->default_rows);
+ ctrl->cols_index = sdw_find_col_index(data->default_cols);
+#ifdef CONFIG_SLIMBUS
if (dev->parent->bus == &slimbus_bus) {
- ctrl->reg_read = qcom_swrm_abh_reg_read;
+#else
+ if (false) {
+#endif
+ ctrl->reg_read = qcom_swrm_ahb_reg_read;
ctrl->reg_write = qcom_swrm_ahb_reg_write;
ctrl->regmap = dev_get_regmap(dev->parent, NULL);
if (!ctrl->regmap)
return -EINVAL;
} else {
- /* Only WCD based SoundWire controller is supported */
- return -ENOTSUPP;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ ctrl->reg_read = qcom_swrm_cpu_reg_read;
+ ctrl->reg_write = qcom_swrm_cpu_reg_write;
+ ctrl->mmio = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ctrl->mmio))
+ return PTR_ERR(ctrl->mmio);
}
ctrl->irq = of_irq_get(dev->of_node, 0);
@@ -795,8 +860,8 @@ static int qcom_swrm_probe(struct platform_device *pdev)
params = &ctrl->bus.params;
params->max_dr_freq = DEFAULT_CLK_FREQ;
params->curr_dr_freq = DEFAULT_CLK_FREQ;
- params->col = SWRM_DEFAULT_COL;
- params->row = SWRM_DEFAULT_ROWS;
+ params->col = data->default_cols;
+ params->row = data->default_rows;
ctrl->reg_read(ctrl, SWRM_MCP_STATUS, &val);
params->curr_bank = val & SWRM_MCP_STATUS_BANK_NUM_MASK;
params->next_bank = !params->curr_bank;
@@ -806,8 +871,8 @@ static int qcom_swrm_probe(struct platform_device *pdev)
prop->num_clk_gears = 0;
prop->num_clk_freq = MAX_FREQ_NUM;
prop->clk_freq = &qcom_swrm_freq_tbl[0];
- prop->default_col = SWRM_DEFAULT_COL;
- prop->default_row = SWRM_DEFAULT_ROWS;
+ prop->default_col = data->default_cols;
+ prop->default_row = data->default_rows;
ctrl->reg_read(ctrl, SWRM_COMP_HW_VERSION, &ctrl->version);
@@ -858,7 +923,8 @@ static int qcom_swrm_remove(struct platform_device *pdev)
}
static const struct of_device_id qcom_swrm_of_match[] = {
- { .compatible = "qcom,soundwire-v1.3.0", },
+ { .compatible = "qcom,soundwire-v1.3.0", .data = &swrm_v1_3_data },
+ { .compatible = "qcom,soundwire-v1.5.1", .data = &swrm_v1_5_data },
{/* sentinel */},
};
diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
index 37290a799023..56e87137c1dd 100644
--- a/drivers/soundwire/stream.c
+++ b/drivers/soundwire/stream.c
@@ -704,9 +704,12 @@ static int sdw_bank_switch(struct sdw_bus *bus, int m_rt_count)
}
if (!multi_link) {
- kfree(wr_msg);
- kfree(wbuf);
- bus->defer_msg.msg = NULL;
+ if (bus->defer_msg.msg) {
+ kfree(bus->defer_msg.msg->buf);
+ kfree(bus->defer_msg.msg);
+ bus->defer_msg.msg = NULL;
+ }
+
bus->params.curr_bank = !bus->params.curr_bank;
bus->params.next_bank = !bus->params.next_bank;
}
@@ -716,7 +719,11 @@ static int sdw_bank_switch(struct sdw_bus *bus, int m_rt_count)
error:
kfree(wbuf);
error_1:
- kfree(wr_msg);
+ if (bus->defer_msg.msg) {
+ kfree(bus->defer_msg.msg);
+ bus->defer_msg.msg = NULL;
+ }
+
return ret;
}
@@ -749,6 +756,7 @@ static int sdw_ml_sync_bank_switch(struct sdw_bus *bus)
if (bus->defer_msg.msg) {
kfree(bus->defer_msg.msg->buf);
kfree(bus->defer_msg.msg);
+ bus->defer_msg.msg = NULL;
}
return 0;
@@ -840,9 +848,11 @@ static int do_bank_switch(struct sdw_stream_runtime *stream)
error:
list_for_each_entry(m_rt, &stream->master_list, stream_node) {
bus = m_rt->bus;
-
- kfree(bus->defer_msg.msg->buf);
- kfree(bus->defer_msg.msg);
+ if (bus->defer_msg.msg) {
+ kfree(bus->defer_msg.msg->buf);
+ kfree(bus->defer_msg.msg);
+ bus->defer_msg.msg = NULL;
+ }
}
msg_unlock:
diff --git a/include/dt-bindings/clock/qcom,audiocc-sm8250.h b/include/dt-bindings/clock/qcom,audiocc-sm8250.h
new file mode 100644
index 000000000000..5a8918e84351
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,audiocc-sm8250.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _DT_BINDINGS_CLK_LPASS_SM8250_H
+#define _DT_BINDINGS_CLK_LPASS_SM8250_H
+
+/* from AOCC */
+#define LPASS_CDC_VA_MCLK 0
+#define LPASS_CDC_TX_NPL 1
+#define LPASS_CDC_TX_MCLK 2
+/* From AudioCC */
+#define LPASS_CDC_WSA_NPL 3
+#define LPASS_CDC_WSA_MCLK 4
+#define LPASS_CDC_RX_MCLK 5
+#define LPASS_CDC_RX_NPL 6
+#define LPASS_CDC_RX_MCLK_MCLK2 7
+
+#endif /* _DT_BINDINGS_CLK_LPASS_SM8250_H */
diff --git a/include/dt-bindings/sound/qcom,q6afe.h b/include/dt-bindings/sound/qcom,q6afe.h
index 1df06f8ad5c3..f64b5d2e6efd 100644
--- a/include/dt-bindings/sound/qcom,q6afe.h
+++ b/include/dt-bindings/sound/qcom,q6afe.h
@@ -107,6 +107,100 @@
#define QUINARY_TDM_RX_7 102
#define QUINARY_TDM_TX_7 103
#define DISPLAY_PORT_RX 104
+#define WSA_CODEC_DMA_RX_0 105
+#define WSA_CODEC_DMA_TX_0 106
+#define WSA_CODEC_DMA_RX_1 107
+#define WSA_CODEC_DMA_TX_1 108
+#define WSA_CODEC_DMA_TX_2 109
+#define VA_CODEC_DMA_TX_0 110
+#define VA_CODEC_DMA_TX_1 111
+#define VA_CODEC_DMA_TX_2 112
+#define RX_CODEC_DMA_RX_0 113
+#define TX_CODEC_DMA_TX_0 114
+#define RX_CODEC_DMA_RX_1 115
+#define TX_CODEC_DMA_TX_1 116
+#define RX_CODEC_DMA_RX_2 117
+#define TX_CODEC_DMA_TX_2 118
+#define RX_CODEC_DMA_RX_3 119
+#define TX_CODEC_DMA_TX_3 120
+#define RX_CODEC_DMA_RX_4 121
+#define TX_CODEC_DMA_TX_4 122
+#define RX_CODEC_DMA_RX_5 123
+#define TX_CODEC_DMA_TX_5 124
+#define RX_CODEC_DMA_RX_6 125
+#define RX_CODEC_DMA_RX_7 126
-#endif /* __DT_BINDINGS_Q6_AFE_H__ */
+#define LPASS_CLK_ID_PRI_MI2S_IBIT 1
+#define LPASS_CLK_ID_PRI_MI2S_EBIT 2
+#define LPASS_CLK_ID_SEC_MI2S_IBIT 3
+#define LPASS_CLK_ID_SEC_MI2S_EBIT 4
+#define LPASS_CLK_ID_TER_MI2S_IBIT 5
+#define LPASS_CLK_ID_TER_MI2S_EBIT 6
+#define LPASS_CLK_ID_QUAD_MI2S_IBIT 7
+#define LPASS_CLK_ID_QUAD_MI2S_EBIT 8
+#define LPASS_CLK_ID_SPEAKER_I2S_IBIT 9
+#define LPASS_CLK_ID_SPEAKER_I2S_EBIT 10
+#define LPASS_CLK_ID_SPEAKER_I2S_OSR 11
+#define LPASS_CLK_ID_QUI_MI2S_IBIT 12
+#define LPASS_CLK_ID_QUI_MI2S_EBIT 13
+#define LPASS_CLK_ID_SEN_MI2S_IBIT 14
+#define LPASS_CLK_ID_SEN_MI2S_EBIT 15
+#define LPASS_CLK_ID_INT0_MI2S_IBIT 16
+#define LPASS_CLK_ID_INT1_MI2S_IBIT 17
+#define LPASS_CLK_ID_INT2_MI2S_IBIT 18
+#define LPASS_CLK_ID_INT3_MI2S_IBIT 19
+#define LPASS_CLK_ID_INT4_MI2S_IBIT 20
+#define LPASS_CLK_ID_INT5_MI2S_IBIT 21
+#define LPASS_CLK_ID_INT6_MI2S_IBIT 22
+#define LPASS_CLK_ID_QUI_MI2S_OSR 23
+#define LPASS_CLK_ID_PRI_PCM_IBIT 24
+#define LPASS_CLK_ID_PRI_PCM_EBIT 25
+#define LPASS_CLK_ID_SEC_PCM_IBIT 26
+#define LPASS_CLK_ID_SEC_PCM_EBIT 27
+#define LPASS_CLK_ID_TER_PCM_IBIT 28
+#define LPASS_CLK_ID_TER_PCM_EBIT 29
+#define LPASS_CLK_ID_QUAD_PCM_IBIT 30
+#define LPASS_CLK_ID_QUAD_PCM_EBIT 31
+#define LPASS_CLK_ID_QUIN_PCM_IBIT 32
+#define LPASS_CLK_ID_QUIN_PCM_EBIT 33
+#define LPASS_CLK_ID_QUI_PCM_OSR 34
+#define LPASS_CLK_ID_PRI_TDM_IBIT 35
+#define LPASS_CLK_ID_PRI_TDM_EBIT 36
+#define LPASS_CLK_ID_SEC_TDM_IBIT 37
+#define LPASS_CLK_ID_SEC_TDM_EBIT 38
+#define LPASS_CLK_ID_TER_TDM_IBIT 39
+#define LPASS_CLK_ID_TER_TDM_EBIT 40
+#define LPASS_CLK_ID_QUAD_TDM_IBIT 41
+#define LPASS_CLK_ID_QUAD_TDM_EBIT 42
+#define LPASS_CLK_ID_QUIN_TDM_IBIT 43
+#define LPASS_CLK_ID_QUIN_TDM_EBIT 44
+#define LPASS_CLK_ID_QUIN_TDM_OSR 45
+#define LPASS_CLK_ID_MCLK_1 46
+#define LPASS_CLK_ID_MCLK_2 47
+#define LPASS_CLK_ID_MCLK_3 48
+#define LPASS_CLK_ID_MCLK_4 49
+#define LPASS_CLK_ID_INTERNAL_DIGITAL_CODEC_CORE 50
+#define LPASS_CLK_ID_INT_MCLK_0 51
+#define LPASS_CLK_ID_INT_MCLK_1 52
+#define LPASS_CLK_ID_MCLK_5 53
+#define LPASS_CLK_ID_WSA_CORE_MCLK 54
+#define LPASS_CLK_ID_WSA_CORE_NPL_MCLK 55
+#define LPASS_CLK_ID_VA_CORE_MCLK 56
+#define LPASS_CLK_ID_TX_CORE_MCLK 57
+#define LPASS_CLK_ID_TX_CORE_NPL_MCLK 58
+#define LPASS_CLK_ID_RX_CORE_MCLK 59
+#define LPASS_CLK_ID_RX_CORE_NPL_MCLK 60
+#define LPASS_CLK_ID_VA_CORE_2X_MCLK 61
+
+#define LPASS_HW_AVTIMER_VOTE 101
+#define LPASS_HW_MACRO_VOTE 102
+#define LPASS_HW_DCODEC_VOTE 103
+
+#define Q6AFE_MAX_CLK_ID 104
+#define LPASS_CLK_ATTRIBUTE_INVALID 0x0
+#define LPASS_CLK_ATTRIBUTE_COUPLE_NO 0x1
+#define LPASS_CLK_ATTRIBUTE_COUPLE_DIVIDEND 0x2
+#define LPASS_CLK_ATTRIBUTE_COUPLE_DIVISOR 0x3
+
+#endif /* __DT_BINDINGS_Q6_AFE_H__ */
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 946a70210f49..86e576d091e6 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -1757,4 +1757,7 @@ config SND_SOC_TPA6130A2
tristate "Texas Instruments TPA6130A2 headphone amplifier"
depends on I2C
+config SND_SOC_LPASS_WSA_MACRO
+ tristate "Qualcomm WSA Macro in LPASS(Low Power Audio SubSystem)"
+
endmenu
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 0140c60db695..0e0f8079a94a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -102,6 +102,7 @@ snd-soc-l3-objs := l3.o
snd-soc-lm4857-objs := lm4857.o
snd-soc-lm49453-objs := lm49453.o
snd-soc-lochnagar-sc-objs := lochnagar-sc.o
+snd-soc-lpass-wsa-macro-objs := lpass-wsa-macro.o
snd-soc-madera-objs := madera.o
snd-soc-max9759-objs := max9759.o
snd-soc-max9768-objs := max9768.o
@@ -605,3 +606,4 @@ obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o
obj-$(CONFIG_SND_SOC_MAX98504) += snd-soc-max98504.o
obj-$(CONFIG_SND_SOC_SIMPLE_AMPLIFIER) += snd-soc-simple-amplifier.o
obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o
+obj-$(CONFIG_SND_SOC_LPASS_WSA_MACRO) += snd-soc-lpass-wsa-macro.o
diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c
new file mode 100644
index 000000000000..97af0122db8e
--- /dev/null
+++ b/sound/soc/codecs/lpass-wsa-macro.c
@@ -0,0 +1,3069 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of_clk.h>
+#include <linux/clk-provider.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <linux/of_platform.h>
+#include <sound/tlv.h>
+#include <linux/pinctrl/consumer.h>
+
+#include "lpass-wsa-macro.h"
+
+#define AUTO_SUSPEND_DELAY 50 /* delay in msec */
+#define WSA_MACRO_MAX_OFFSET 0x1000
+
+#define WSA_MACRO_RX_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define WSA_MACRO_RX_MIX_RATES (SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define WSA_MACRO_RX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+#define WSA_MACRO_ECHO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_48000)
+#define WSA_MACRO_ECHO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S24_3LE)
+
+#define NUM_INTERPOLATORS 2
+
+#define WSA_MACRO_MUX_INP_SHFT 0x3
+#define WSA_MACRO_MUX_INP_MASK1 0x07
+#define WSA_MACRO_MUX_INP_MASK2 0x38
+#define WSA_MACRO_MUX_CFG_OFFSET 0x8
+#define WSA_MACRO_MUX_CFG1_OFFSET 0x4
+#define WSA_MACRO_RX_COMP_OFFSET 0x40
+#define WSA_MACRO_RX_SOFTCLIP_OFFSET 0x40
+#define WSA_MACRO_RX_PATH_OFFSET 0x80
+#define WSA_MACRO_RX_PATH_CFG3_OFFSET 0x10
+#define WSA_MACRO_RX_PATH_DSMDEM_OFFSET 0x4C
+#define WSA_MACRO_FS_RATE_MASK 0x0F
+#define WSA_MACRO_EC_MIX_TX0_MASK 0x03
+#define WSA_MACRO_EC_MIX_TX1_MASK 0x18
+
+#define WSA_MACRO_MAX_DMA_CH_PER_PORT 0x2
+
+enum {
+ WSA_MACRO_RX0 = 0,
+ WSA_MACRO_RX1,
+ WSA_MACRO_RX_MIX,
+ WSA_MACRO_RX_MIX0 = WSA_MACRO_RX_MIX,
+ WSA_MACRO_RX_MIX1,
+ WSA_MACRO_RX_MAX,
+};
+
+enum {
+ WSA_MACRO_TX0 = 0,
+ WSA_MACRO_TX1,
+ WSA_MACRO_TX_MAX,
+};
+
+enum {
+ WSA_MACRO_EC0_MUX = 0,
+ WSA_MACRO_EC1_MUX,
+ WSA_MACRO_EC_MUX_MAX,
+};
+
+enum {
+ WSA_MACRO_COMP1, /* SPK_L */
+ WSA_MACRO_COMP2, /* SPK_R */
+ WSA_MACRO_COMP_MAX
+};
+
+enum {
+ WSA_MACRO_SOFTCLIP0, /* RX0 */
+ WSA_MACRO_SOFTCLIP1, /* RX1 */
+ WSA_MACRO_SOFTCLIP_MAX
+};
+
+enum {
+ INTn_1_INP_SEL_ZERO = 0,
+ INTn_1_INP_SEL_RX0,
+ INTn_1_INP_SEL_RX1,
+ INTn_1_INP_SEL_RX2,
+ INTn_1_INP_SEL_RX3,
+ INTn_1_INP_SEL_DEC0,
+ INTn_1_INP_SEL_DEC1,
+};
+
+enum {
+ INTn_2_INP_SEL_ZERO = 0,
+ INTn_2_INP_SEL_RX0,
+ INTn_2_INP_SEL_RX1,
+ INTn_2_INP_SEL_RX2,
+ INTn_2_INP_SEL_RX3,
+};
+
+struct interp_sample_rate {
+ int sample_rate;
+ int rate_val;
+};
+
+/*
+ * Structure used to update codec
+ * register defaults after reset
+ */
+struct wsa_macro_reg_mask_val {
+ u16 reg;
+ u8 mask;
+ u8 val;
+};
+
+static struct interp_sample_rate int_prim_sample_rate_val[] = {
+ {8000, 0x0}, /* 8K */
+ {16000, 0x1}, /* 16K */
+ {24000, -EINVAL},/* 24K */
+ {32000, 0x3}, /* 32K */
+ {48000, 0x4}, /* 48K */
+ {96000, 0x5}, /* 96K */
+ {192000, 0x6}, /* 192K */
+ {384000, 0x7}, /* 384K */
+ {44100, 0x8}, /* 44.1K */
+};
+
+static struct interp_sample_rate int_mix_sample_rate_val[] = {
+ {48000, 0x4}, /* 48K */
+ {96000, 0x5}, /* 96K */
+ {192000, 0x6}, /* 192K */
+};
+
+#define WSA_MACRO_SWR_STRING_LEN 80
+
+static int wsa_macro_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai);
+static int wsa_macro_get_channel_map(struct snd_soc_dai *dai,
+ unsigned int *tx_num, unsigned int *tx_slot,
+ unsigned int *rx_num, unsigned int *rx_slot);
+static int wsa_macro_digital_mute(struct snd_soc_dai *dai, int mute, int
+ stream);
+/* Hold instance to soundwire platform device */
+struct wsa_macro_swr_ctrl_data {
+ struct platform_device *wsa_swr_pdev;
+};
+
+struct wsa_macro_swr_ctrl_platform_data {
+ void *handle; /* holds codec private data */
+ int (*read)(void *handle, int reg);
+ int (*write)(void *handle, int reg, int val);
+ int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len);
+ int (*clk)(void *handle, bool enable);
+ int (*core_vote)(void *handle, bool enable);
+ int (*handle_irq)(void *handle,
+ irqreturn_t (*swrm_irq_handler)(int irq,
+ void *data),
+ void *swrm_handle,
+ int action);
+};
+
+struct wsa_macro_bcl_pmic_params {
+ u8 id;
+ u8 sid;
+ u8 ppid;
+};
+
+enum {
+ WSA_MACRO_AIF_INVALID = 0,
+ WSA_MACRO_AIF1_PB,
+ WSA_MACRO_AIF_MIX1_PB,
+ WSA_MACRO_AIF_VI,
+ WSA_MACRO_AIF_ECHO,
+ WSA_MACRO_MAX_DAIS,
+};
+
+#define WSA_MACRO_CHILD_DEVICES_MAX 3
+
+/*
+ * @dev: wsa macro device pointer
+ * @comp_enabled: compander enable mixer value set
+ * @ec_hq: echo HQ enable mixer value set
+ * @prim_int_users: Users of interpolator
+ * @wsa_mclk_users: WSA MCLK users count
+ * @swr_clk_users: SWR clk users count
+ * @vi_feed_value: VI sense mask
+ * @mclk_lock: to lock mclk operations
+ * @swr_clk_lock: to lock swr master clock operations
+ * @swr_ctrl_data: SoundWire data structure
+ * @swr_plat_data: Soundwire platform data
+ * @wsa_macro_add_child_devices_work: work for adding child devices
+ * @wsa_swr_gpio_p: used by pinctrl API
+ * @component: codec handle
+ * @rx_0_count: RX0 interpolation users
+ * @rx_1_count: RX1 interpolation users
+ * @active_ch_mask: channel mask for all AIF DAIs
+ * @active_ch_cnt: channel count of all AIF DAIs
+ * @rx_port_value: mixer ctl value of WSA RX MUXes
+ */
+struct wsa_macro_priv {
+ struct device *dev;
+ int comp_enabled[WSA_MACRO_COMP_MAX];
+ int ec_hq[WSA_MACRO_RX1 + 1];
+ u16 prim_int_users[WSA_MACRO_RX1 + 1];
+ u16 wsa_mclk_users;
+ u16 swr_clk_users;
+ bool dapm_mclk_enable;
+ bool reset_swr;
+ unsigned int vi_feed_value;
+ struct mutex mclk_lock;
+ struct mutex swr_clk_lock;
+ //struct wsa_macro_swr_ctrl_data *swr_ctrl_data;
+ //struct wsa_macro_swr_ctrl_platform_data swr_plat_data;
+ //struct work_struct wsa_macro_add_child_devices_work;
+ // struct device_node *wsa_swr_gpio_p;
+ //struct snd_soc_component *component;
+ int rx_0_count;
+ int rx_1_count;
+ unsigned long active_ch_mask[WSA_MACRO_MAX_DAIS];
+ unsigned long active_ch_cnt[WSA_MACRO_MAX_DAIS];
+ int rx_port_value[WSA_MACRO_RX_MAX];
+ //struct platform_device *pdev_child_devices
+ // [WSA_MACRO_CHILD_DEVICES_MAX];
+ //int child_count;
+ int ear_spkr_gain;
+ int spkr_gain_offset;
+ int spkr_mode;
+ int is_softclip_on[WSA_MACRO_SOFTCLIP_MAX];
+ int softclip_clk_users[WSA_MACRO_SOFTCLIP_MAX];
+ struct wsa_macro_bcl_pmic_params bcl_pmic_params;
+ // char __iomem *mclk_mode_muxsel;
+ // u16 default_clk_id;
+ int wsa_digital_mute_status[WSA_MACRO_RX_MAX];
+
+ struct regmap *regmap;
+ struct regmap *va_regmap;
+ struct clk *hw_vote;
+ struct clk *dcodec_vote;
+ struct clk *clk;
+ struct clk *npl_clk;
+ struct clk_hw hw;
+};
+#define to_wsa_macro(_hw) container_of(_hw, struct wsa_macro_priv, hw)
+
+static int wsa_macro_config_ear_spkr_gain(struct snd_soc_component *component,
+ struct wsa_macro_priv *wsa_priv,
+ int event, int gain_reg);
+static struct snd_soc_dai_driver wsa_macro_dai[];
+static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
+
+static const char *const rx_text[] = {
+ "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "DEC0", "DEC1"
+};
+
+static const char *const rx_mix_text[] = {
+ "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1"
+};
+
+static const char *const rx_mix_ec_text[] = {
+ "ZERO", "RX_MIX_TX0", "RX_MIX_TX1"
+};
+
+static const char *const rx_mux_text[] = {
+ "ZERO", "AIF1_PB", "AIF_MIX1_PB"
+};
+
+static const char *const rx_sidetone_mix_text[] = {
+ "ZERO", "SRC0"
+};
+
+static const char * const wsa_macro_ear_spkr_pa_gain_text[] = {
+ "G_DEFAULT", "G_0_DB", "G_1_DB", "G_2_DB", "G_3_DB",
+ "G_4_DB", "G_5_DB", "G_6_DB"
+};
+
+static const char * const wsa_macro_speaker_boost_stage_text[] = {
+ "NO_MAX_STATE", "MAX_STATE_1", "MAX_STATE_2"
+};
+
+static const char * const wsa_macro_vbat_bcl_gsm_mode_text[] = {
+ "OFF", "ON"
+};
+
+static const struct snd_kcontrol_new wsa_int0_vbat_mix_switch[] = {
+ SOC_DAPM_SINGLE("WSA RX0 VBAT Enable", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new wsa_int1_vbat_mix_switch[] = {
+ SOC_DAPM_SINGLE("WSA RX1 VBAT Enable", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(wsa_macro_ear_spkr_pa_gain_enum,
+ wsa_macro_ear_spkr_pa_gain_text);
+static SOC_ENUM_SINGLE_EXT_DECL(wsa_macro_spkr_boost_stage_enum,
+ wsa_macro_speaker_boost_stage_text);
+static SOC_ENUM_SINGLE_EXT_DECL(wsa_macro_vbat_bcl_gsm_mode_enum,
+ wsa_macro_vbat_bcl_gsm_mode_text);
+
+/* RX INT0 */
+static const struct soc_enum rx0_prim_inp0_chain_enum =
+ SOC_ENUM_SINGLE(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0,
+ 0, 7, rx_text);
+
+static const struct soc_enum rx0_prim_inp1_chain_enum =
+ SOC_ENUM_SINGLE(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0,
+ 3, 7, rx_text);
+
+static const struct soc_enum rx0_prim_inp2_chain_enum =
+ SOC_ENUM_SINGLE(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG1,
+ 3, 7, rx_text);
+
+static const struct soc_enum rx0_mix_chain_enum =
+ SOC_ENUM_SINGLE(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG1,
+ 0, 5, rx_mix_text);
+
+static const struct soc_enum rx0_sidetone_mix_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_sidetone_mix_text);
+
+static const struct snd_kcontrol_new rx0_prim_inp0_mux =
+ SOC_DAPM_ENUM("WSA_RX0 INP0 Mux", rx0_prim_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx0_prim_inp1_mux =
+ SOC_DAPM_ENUM("WSA_RX0 INP1 Mux", rx0_prim_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx0_prim_inp2_mux =
+ SOC_DAPM_ENUM("WSA_RX0 INP2 Mux", rx0_prim_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx0_mix_mux =
+ SOC_DAPM_ENUM("WSA_RX0 MIX Mux", rx0_mix_chain_enum);
+
+static const struct snd_kcontrol_new rx0_sidetone_mix_mux =
+ SOC_DAPM_ENUM("WSA_RX0 SIDETONE MIX Mux", rx0_sidetone_mix_enum);
+
+/* RX INT1 */
+static const struct soc_enum rx1_prim_inp0_chain_enum =
+ SOC_ENUM_SINGLE(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT1_CFG0,
+ 0, 7, rx_text);
+
+static const struct soc_enum rx1_prim_inp1_chain_enum =
+ SOC_ENUM_SINGLE(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT1_CFG0,
+ 3, 7, rx_text);
+
+static const struct soc_enum rx1_prim_inp2_chain_enum =
+ SOC_ENUM_SINGLE(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT1_CFG1,
+ 3, 7, rx_text);
+
+static const struct soc_enum rx1_mix_chain_enum =
+ SOC_ENUM_SINGLE(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT1_CFG1,
+ 0, 5, rx_mix_text);
+
+static const struct snd_kcontrol_new rx1_prim_inp0_mux =
+ SOC_DAPM_ENUM("WSA_RX1 INP0 Mux", rx1_prim_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx1_prim_inp1_mux =
+ SOC_DAPM_ENUM("WSA_RX1 INP1 Mux", rx1_prim_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx1_prim_inp2_mux =
+ SOC_DAPM_ENUM("WSA_RX1 INP2 Mux", rx1_prim_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx1_mix_mux =
+ SOC_DAPM_ENUM("WSA_RX1 MIX Mux", rx1_mix_chain_enum);
+
+static const struct soc_enum rx_mix_ec0_enum =
+ SOC_ENUM_SINGLE(BOLERO_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0,
+ 0, 3, rx_mix_ec_text);
+
+static const struct soc_enum rx_mix_ec1_enum =
+ SOC_ENUM_SINGLE(BOLERO_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0,
+ 3, 3, rx_mix_ec_text);
+
+static const struct snd_kcontrol_new rx_mix_ec0_mux =
+ SOC_DAPM_ENUM("WSA RX_MIX EC0_Mux", rx_mix_ec0_enum);
+
+static const struct snd_kcontrol_new rx_mix_ec1_mux =
+ SOC_DAPM_ENUM("WSA RX_MIX EC1_Mux", rx_mix_ec1_enum);
+
+static struct snd_soc_dai_ops wsa_macro_dai_ops = {
+ .hw_params = wsa_macro_hw_params,
+ .get_channel_map = wsa_macro_get_channel_map,
+ .mute_stream = wsa_macro_digital_mute,
+};
+
+static struct snd_soc_dai_driver wsa_macro_dai[] = {
+ {
+ .name = "wsa_macro_rx1",
+ .id = WSA_MACRO_AIF1_PB,
+ .playback = {
+ .stream_name = "WSA_AIF1 Playback",
+ .rates = WSA_MACRO_RX_RATES,
+ .formats = WSA_MACRO_RX_FORMATS,
+ .rate_max = 384000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &wsa_macro_dai_ops,
+ },
+ {
+ .name = "wsa_macro_rx_mix",
+ .id = WSA_MACRO_AIF_MIX1_PB,
+ .playback = {
+ .stream_name = "WSA_AIF_MIX1 Playback",
+ .rates = WSA_MACRO_RX_MIX_RATES,
+ .formats = WSA_MACRO_RX_FORMATS,
+ .rate_max = 192000,
+ .rate_min = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &wsa_macro_dai_ops,
+ },
+ {
+ .name = "wsa_macro_vifeedback",
+ .id = WSA_MACRO_AIF_VI,
+ .capture = {
+ .stream_name = "WSA_AIF_VI Capture",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000,
+ .formats = WSA_MACRO_RX_FORMATS,
+ .rate_max = 48000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &wsa_macro_dai_ops,
+ },
+ {
+ .name = "wsa_macro_echo",
+ .id = WSA_MACRO_AIF_ECHO,
+ .capture = {
+ .stream_name = "WSA_AIF_ECHO Capture",
+ .rates = WSA_MACRO_ECHO_RATES,
+ .formats = WSA_MACRO_ECHO_FORMATS,
+ .rate_max = 48000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &wsa_macro_dai_ops,
+ },
+};
+
+static const struct wsa_macro_reg_mask_val wsa_macro_spkr_default[] = {
+ {BOLERO_CDC_WSA_COMPANDER0_CTL3, 0x80, 0x80},
+ {BOLERO_CDC_WSA_COMPANDER1_CTL3, 0x80, 0x80},
+ {BOLERO_CDC_WSA_COMPANDER0_CTL7, 0x01, 0x01},
+ {BOLERO_CDC_WSA_COMPANDER1_CTL7, 0x01, 0x01},
+ {BOLERO_CDC_WSA_BOOST0_BOOST_CTL, 0x7C, 0x58},
+ {BOLERO_CDC_WSA_BOOST1_BOOST_CTL, 0x7C, 0x58},
+};
+
+static const struct wsa_macro_reg_mask_val wsa_macro_spkr_mode1[] = {
+ {BOLERO_CDC_WSA_COMPANDER0_CTL3, 0x80, 0x00},
+ {BOLERO_CDC_WSA_COMPANDER1_CTL3, 0x80, 0x00},
+ {BOLERO_CDC_WSA_COMPANDER0_CTL7, 0x01, 0x00},
+ {BOLERO_CDC_WSA_COMPANDER1_CTL7, 0x01, 0x00},
+ {BOLERO_CDC_WSA_BOOST0_BOOST_CTL, 0x7C, 0x44},
+ {BOLERO_CDC_WSA_BOOST1_BOOST_CTL, 0x7C, 0x44},
+};
+
+/**
+ * wsa_macro_set_spkr_mode - Configures speaker compander and smartboost
+ * settings based on speaker mode.
+ *
+ * @component: codec instance
+ * @mode: Indicates speaker configuration mode.
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int wsa_macro_set_spkr_mode(struct snd_soc_component *component, int mode)
+{
+ int i;
+ const struct wsa_macro_reg_mask_val *regs;
+ int size;
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+
+ switch (mode) {
+ case WSA_MACRO_SPKR_MODE_1:
+ regs = wsa_macro_spkr_mode1;
+ size = ARRAY_SIZE(wsa_macro_spkr_mode1);
+ break;
+ default:
+ regs = wsa_macro_spkr_default;
+ size = ARRAY_SIZE(wsa_macro_spkr_default);
+ break;
+ }
+
+ wsa_priv->spkr_mode = mode;
+ for (i = 0; i < size; i++)
+ snd_soc_component_update_bits(component, regs[i].reg,
+ regs[i].mask, regs[i].val);
+ return 0;
+}
+EXPORT_SYMBOL(wsa_macro_set_spkr_mode);
+
+static int wsa_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai,
+ u8 int_prim_fs_rate_reg_val,
+ u32 sample_rate)
+{
+ u8 int_1_mix1_inp;
+ u32 j, port;
+ u16 int_mux_cfg0, int_mux_cfg1;
+ u16 int_fs_reg;
+ u8 int_mux_cfg0_val, int_mux_cfg1_val;
+ u8 inp0_sel, inp1_sel, inp2_sel;
+ struct snd_soc_component *component = dai->component;
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+
+ for_each_set_bit(port, &wsa_priv->active_ch_mask[dai->id],
+ WSA_MACRO_RX_MAX) {
+ int_1_mix1_inp = port;
+ if ((int_1_mix1_inp < WSA_MACRO_RX0) ||
+ (int_1_mix1_inp > WSA_MACRO_RX_MIX1)) {
+ dev_err(component->dev,
+ "%s: Invalid RX port, Dai ID is %d\n",
+ __func__, dai->id);
+ return -EINVAL;
+ }
+
+ int_mux_cfg0 = BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0;
+
+ /*
+ * Loop through all interpolator MUX inputs and find out
+ * to which interpolator input, the cdc_dma rx port
+ * is connected
+ */
+ for (j = 0; j < NUM_INTERPOLATORS; j++) {
+ int_mux_cfg1 = int_mux_cfg0 + WSA_MACRO_MUX_CFG1_OFFSET;
+
+ int_mux_cfg0_val = snd_soc_component_read(component,
+ int_mux_cfg0);
+ int_mux_cfg1_val = snd_soc_component_read(component,
+ int_mux_cfg1);
+ inp0_sel = int_mux_cfg0_val & WSA_MACRO_MUX_INP_MASK1;
+ inp1_sel = (int_mux_cfg0_val >>
+ WSA_MACRO_MUX_INP_SHFT) &
+ WSA_MACRO_MUX_INP_MASK1;
+ inp2_sel = (int_mux_cfg1_val >>
+ WSA_MACRO_MUX_INP_SHFT) &
+ WSA_MACRO_MUX_INP_MASK1;
+ if ((inp0_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) ||
+ (inp1_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) ||
+ (inp2_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0)) {
+ int_fs_reg = BOLERO_CDC_WSA_RX0_RX_PATH_CTL +
+ WSA_MACRO_RX_PATH_OFFSET * j;
+ dev_dbg(component->dev,
+ "%s: AIF_PB DAI(%d) connected to INT%u_1\n",
+ __func__, dai->id, j);
+ dev_dbg(component->dev,
+ "%s: set INT%u_1 sample rate to %u\n",
+ __func__, j, sample_rate);
+ /* sample_rate is in Hz */
+ snd_soc_component_update_bits(component,
+ int_fs_reg,
+ WSA_MACRO_FS_RATE_MASK,
+ int_prim_fs_rate_reg_val);
+ }
+ int_mux_cfg0 += WSA_MACRO_MUX_CFG_OFFSET;
+ }
+ }
+
+ return 0;
+}
+
+static int wsa_macro_set_mix_interpolator_rate(struct snd_soc_dai *dai,
+ u8 int_mix_fs_rate_reg_val,
+ u32 sample_rate)
+{
+ u8 int_2_inp;
+ u32 j, port;
+ u16 int_mux_cfg1, int_fs_reg;
+ u8 int_mux_cfg1_val;
+ struct snd_soc_component *component = dai->component;
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+
+ for_each_set_bit(port, &wsa_priv->active_ch_mask[dai->id],
+ WSA_MACRO_RX_MAX) {
+ int_2_inp = port;
+ if ((int_2_inp < WSA_MACRO_RX0) ||
+ (int_2_inp > WSA_MACRO_RX_MIX1)) {
+ dev_err(component->dev,
+ "%s: Invalid RX port, Dai ID is %d\n",
+ __func__, dai->id);
+ return -EINVAL;
+ }
+
+ int_mux_cfg1 = BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG1;
+ for (j = 0; j < NUM_INTERPOLATORS; j++) {
+ int_mux_cfg1_val = snd_soc_component_read(component,
+ int_mux_cfg1) &
+ WSA_MACRO_MUX_INP_MASK1;
+ if (int_mux_cfg1_val == int_2_inp +
+ INTn_2_INP_SEL_RX0) {
+ int_fs_reg =
+ BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL +
+ WSA_MACRO_RX_PATH_OFFSET * j;
+
+ dev_dbg(component->dev,
+ "%s: AIF_PB DAI(%d) connected to INT%u_2\n",
+ __func__, dai->id, j);
+ dev_dbg(component->dev,
+ "%s: set INT%u_2 sample rate to %u\n",
+ __func__, j, sample_rate);
+ snd_soc_component_update_bits(component,
+ int_fs_reg,
+ WSA_MACRO_FS_RATE_MASK,
+ int_mix_fs_rate_reg_val);
+ }
+ int_mux_cfg1 += WSA_MACRO_MUX_CFG_OFFSET;
+ }
+ }
+ return 0;
+}
+
+static int wsa_macro_set_interpolator_rate(struct snd_soc_dai *dai,
+ u32 sample_rate)
+{
+ int rate_val = 0;
+ int i, ret;
+
+ /* set mixing path rate */
+ for (i = 0; i < ARRAY_SIZE(int_mix_sample_rate_val); i++) {
+ if (sample_rate ==
+ int_mix_sample_rate_val[i].sample_rate) {
+ rate_val =
+ int_mix_sample_rate_val[i].rate_val;
+ break;
+ }
+ }
+ if ((i == ARRAY_SIZE(int_mix_sample_rate_val)) ||
+ (rate_val < 0))
+ goto prim_rate;
+ ret = wsa_macro_set_mix_interpolator_rate(dai,
+ (u8) rate_val, sample_rate);
+prim_rate:
+ /* set primary path sample rate */
+ for (i = 0; i < ARRAY_SIZE(int_prim_sample_rate_val); i++) {
+ if (sample_rate ==
+ int_prim_sample_rate_val[i].sample_rate) {
+ rate_val =
+ int_prim_sample_rate_val[i].rate_val;
+ break;
+ }
+ }
+ if ((i == ARRAY_SIZE(int_prim_sample_rate_val)) ||
+ (rate_val < 0))
+ return -EINVAL;
+ ret = wsa_macro_set_prim_interpolator_rate(dai,
+ (u8) rate_val, sample_rate);
+ return ret;
+}
+
+static int wsa_macro_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ int ret;
+
+ dev_dbg(component->dev,
+ "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__,
+ dai->name, dai->id, params_rate(params),
+ params_channels(params));
+
+ switch (substream->stream) {
+ case SNDRV_PCM_STREAM_PLAYBACK:
+ ret = wsa_macro_set_interpolator_rate(dai, params_rate(params));
+ if (ret) {
+ dev_err(component->dev,
+ "%s: cannot set sample rate: %u\n",
+ __func__, params_rate(params));
+ return ret;
+ }
+ break;
+ case SNDRV_PCM_STREAM_CAPTURE:
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int wsa_macro_get_channel_map(struct snd_soc_dai *dai,
+ unsigned int *tx_num, unsigned int *tx_slot,
+ unsigned int *rx_num, unsigned int *rx_slot)
+{
+ struct snd_soc_component *component = dai->component;
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+ u16 val = 0, mask = 0, cnt = 0, temp = 0;
+
+ wsa_priv = dev_get_drvdata(component->dev);
+ if (!wsa_priv)
+ return -EINVAL;
+
+ switch (dai->id) {
+ case WSA_MACRO_AIF_VI:
+ *tx_slot = wsa_priv->active_ch_mask[dai->id];
+ *tx_num = wsa_priv->active_ch_cnt[dai->id];
+ break;
+ case WSA_MACRO_AIF1_PB:
+ case WSA_MACRO_AIF_MIX1_PB:
+ for_each_set_bit(temp, &wsa_priv->active_ch_mask[dai->id],
+ WSA_MACRO_RX_MAX) {
+ mask |= (1 << temp);
+ if (++cnt == WSA_MACRO_MAX_DMA_CH_PER_PORT)
+ break;
+ }
+ if (mask & 0x0C)
+ mask = mask >> 0x2;
+ *rx_slot = mask;
+ *rx_num = cnt;
+ break;
+ case WSA_MACRO_AIF_ECHO:
+ val = snd_soc_component_read(component,
+ BOLERO_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0);
+ if (val & WSA_MACRO_EC_MIX_TX1_MASK) {
+ mask |= 0x2;
+ cnt++;
+ }
+ if (val & WSA_MACRO_EC_MIX_TX0_MASK) {
+ mask |= 0x1;
+ cnt++;
+ }
+ *tx_slot = mask;
+ *tx_num = cnt;
+ break;
+ default:
+ dev_err(component->dev, "%s: Invalid AIF\n", __func__);
+ break;
+ }
+ return 0;
+}
+
+static int wsa_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+ struct snd_soc_component *component = dai->component;
+ uint16_t j = 0, reg = 0, mix_reg = 0, dsm_reg = 0;
+ u16 int_mux_cfg0 = 0, int_mux_cfg1 = 0;
+ u8 int_mux_cfg0_val = 0, int_mux_cfg1_val = 0;
+
+ if (mute)
+ return 0;
+
+ switch (dai->id) {
+ case WSA_MACRO_AIF1_PB:
+ case WSA_MACRO_AIF_MIX1_PB:
+ for (j = 0; j < NUM_INTERPOLATORS; j++) {
+ reg = BOLERO_CDC_WSA_RX0_RX_PATH_CTL +
+ (j * WSA_MACRO_RX_PATH_OFFSET);
+ mix_reg = BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL +
+ (j * WSA_MACRO_RX_PATH_OFFSET);
+ dsm_reg = BOLERO_CDC_WSA_RX0_RX_PATH_CTL +
+ (j * WSA_MACRO_RX_PATH_OFFSET) +
+ WSA_MACRO_RX_PATH_DSMDEM_OFFSET;
+ int_mux_cfg0 = BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0 + j * 8;
+ int_mux_cfg1 = int_mux_cfg0 + 4;
+ int_mux_cfg0_val = snd_soc_component_read(component,
+ int_mux_cfg0);
+ int_mux_cfg1_val = snd_soc_component_read(component,
+ int_mux_cfg1);
+ if (snd_soc_component_read(component, dsm_reg) & 0x01) {
+ if (int_mux_cfg0_val || (int_mux_cfg1_val & 0x38))
+ snd_soc_component_update_bits(component, reg,
+ 0x20, 0x20);
+ if (int_mux_cfg1_val & 0x07) {
+ snd_soc_component_update_bits(component, reg,
+ 0x20, 0x20);
+ snd_soc_component_update_bits(component,
+ mix_reg, 0x20, 0x20);
+ }
+ }
+ }
+ //bolero_wsa_pa_on(component->dev);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+static int bolero_clk_rsc_fs_gen_request(struct wsa_macro_priv *wsa_priv)
+{
+ struct regmap *regmap = wsa_priv->va_regmap;
+
+ pr_err("DEBUG: %s: %d: \n", __func__, __LINE__);
+
+ regmap_update_bits(regmap, 0x0, 0x1, 0x1);
+ regmap_update_bits(regmap, 0x4, 0x1, 0x1);
+ regmap_update_bits(regmap, 0x80, 0x2, 0x2);
+
+ return 0;
+}
+
+static int wsa_macro_mclk_enable(struct wsa_macro_priv *wsa_priv,
+ bool mclk_enable, bool dapm)
+{
+ struct regmap *regmap = wsa_priv->regmap;
+ int ret = 0;
+
+ if (regmap == NULL) {
+ dev_err(wsa_priv->dev, "%s: regmap is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ dev_err(wsa_priv->dev, "%s: mclk_enable = %u, dapm = %d clk_users= %d\n",
+ __func__, mclk_enable, dapm, wsa_priv->wsa_mclk_users);
+
+ mutex_lock(&wsa_priv->mclk_lock);
+ if (mclk_enable) {
+ if (wsa_priv->wsa_mclk_users == 0) {
+#if 0
+ ret = bolero_clk_rsc_request_clock(wsa_priv->dev,
+ wsa_priv->default_clk_id,
+ wsa_priv->default_clk_id,
+ true);
+ if (ret < 0) {
+ dev_err_ratelimited(wsa_priv->dev,
+ "%s: wsa request clock enable failed\n",
+ __func__);
+ goto exit;
+ }
+#endif
+ pr_err("DEBUG: %s: %d: \n", __func__, __LINE__);
+ bolero_clk_rsc_fs_gen_request(wsa_priv);
+ pr_err("DEBUG: %s: %d: \n", __func__, __LINE__);
+ regcache_mark_dirty(regmap);
+ regcache_sync_region(regmap,
+ WSA_START_OFFSET,
+ WSA_MAX_OFFSET);
+ pr_err("DEBUG: %s: %d: \n", __func__, __LINE__);
+ /* 9.6MHz MCLK, set value 0x00 if other frequency */
+ regmap_update_bits(regmap,
+ BOLERO_CDC_WSA_TOP_FREQ_MCLK, 0x01, 0x01);
+ regmap_update_bits(regmap,
+ BOLERO_CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL,
+ 0x01, 0x01);
+ pr_err("DEBUG: %s: %d: \n", __func__, __LINE__);
+ regmap_update_bits(regmap,
+ BOLERO_CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL,
+ 0x01, 0x01);
+ pr_err("DEBUG: %s: %d: \n", __func__, __LINE__);
+ }
+ wsa_priv->wsa_mclk_users++;
+ } else {
+ if (wsa_priv->wsa_mclk_users <= 0) {
+ dev_err(wsa_priv->dev, "%s: clock already disabled\n",
+ __func__);
+ wsa_priv->wsa_mclk_users = 0;
+ goto exit;
+ }
+ wsa_priv->wsa_mclk_users--;
+ if (wsa_priv->wsa_mclk_users == 0) {
+ regmap_update_bits(regmap,
+ BOLERO_CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL,
+ 0x01, 0x00);
+ regmap_update_bits(regmap,
+ BOLERO_CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL,
+ 0x01, 0x00);
+#if 0
+ bolero_clk_rsc_fs_gen_request(wsa_priv->dev,
+ false);
+
+ bolero_clk_rsc_request_clock(wsa_priv->dev,
+ wsa_priv->default_clk_id,
+ wsa_priv->default_clk_id,
+ false);
+#endif
+ }
+ }
+exit:
+ mutex_unlock(&wsa_priv->mclk_lock);
+ return ret;
+}
+
+static int wsa_macro_mclk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ int ret = 0;
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s: event = %d\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = wsa_macro_mclk_enable(wsa_priv, 1, true);
+ if (ret)
+ wsa_priv->dapm_mclk_enable = false;
+ else
+ wsa_priv->dapm_mclk_enable = true;
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (wsa_priv->dapm_mclk_enable)
+ wsa_macro_mclk_enable(wsa_priv, 0, true);
+ break;
+ default:
+ dev_err(wsa_priv->dev,
+ "%s: invalid DAPM event %d\n", __func__, event);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static int wsa_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ if (test_bit(WSA_MACRO_TX0,
+ &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI])) {
+ dev_dbg(component->dev, "%s: spkr1 enabled\n", __func__);
+ /* Enable V&I sensing */
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CTL,
+ 0x20, 0x20);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CTL,
+ 0x20, 0x20);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CTL,
+ 0x0F, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CTL,
+ 0x0F, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CTL,
+ 0x10, 0x10);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CTL,
+ 0x10, 0x10);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CTL,
+ 0x20, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CTL,
+ 0x20, 0x00);
+ }
+ if (test_bit(WSA_MACRO_TX1,
+ &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI])) {
+ dev_dbg(component->dev, "%s: spkr2 enabled\n", __func__);
+ /* Enable V&I sensing */
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CTL,
+ 0x20, 0x20);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CTL,
+ 0x20, 0x20);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CTL,
+ 0x0F, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CTL,
+ 0x0F, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CTL,
+ 0x10, 0x10);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CTL,
+ 0x10, 0x10);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CTL,
+ 0x20, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CTL,
+ 0x20, 0x00);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (test_bit(WSA_MACRO_TX0,
+ &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI])) {
+ /* Disable V&I sensing */
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CTL,
+ 0x20, 0x20);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CTL,
+ 0x20, 0x20);
+ dev_dbg(component->dev, "%s: spkr1 disabled\n", __func__);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CTL,
+ 0x10, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CTL,
+ 0x10, 0x00);
+ }
+ if (test_bit(WSA_MACRO_TX1,
+ &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI])) {
+ /* Disable V&I sensing */
+ dev_dbg(component->dev, "%s: spkr2 disabled\n", __func__);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CTL,
+ 0x20, 0x20);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CTL,
+ 0x20, 0x20);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CTL,
+ 0x10, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CTL,
+ 0x10, 0x00);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static int wsa_macro_enable_mix_path(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ u16 gain_reg;
+ int offset_val = 0;
+ int val = 0;
+
+ dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name);
+
+ switch (w->reg) {
+ case BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL:
+ gain_reg = BOLERO_CDC_WSA_RX0_RX_VOL_MIX_CTL;
+ break;
+ case BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CTL:
+ gain_reg = BOLERO_CDC_WSA_RX1_RX_VOL_MIX_CTL;
+ break;
+ default:
+ dev_err(component->dev, "%s: No gain register avail for %s\n",
+ __func__, w->name);
+ return 0;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ val = snd_soc_component_read(component, gain_reg);
+ val += offset_val;
+ snd_soc_component_write(component, gain_reg, val);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component,
+ w->reg, 0x20, 0x00);
+ break;
+ }
+
+ return 0;
+}
+
+static void wsa_macro_hd2_control(struct snd_soc_component *component,
+ u16 reg, int event)
+{
+ u16 hd2_scale_reg;
+ u16 hd2_enable_reg = 0;
+
+ if (reg == BOLERO_CDC_WSA_RX0_RX_PATH_CTL) {
+ hd2_scale_reg = BOLERO_CDC_WSA_RX0_RX_PATH_SEC3;
+ hd2_enable_reg = BOLERO_CDC_WSA_RX0_RX_PATH_CFG0;
+ }
+ if (reg == BOLERO_CDC_WSA_RX1_RX_PATH_CTL) {
+ hd2_scale_reg = BOLERO_CDC_WSA_RX1_RX_PATH_SEC3;
+ hd2_enable_reg = BOLERO_CDC_WSA_RX1_RX_PATH_CFG0;
+ }
+
+ if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) {
+ snd_soc_component_update_bits(component, hd2_scale_reg,
+ 0x3C, 0x10);
+ snd_soc_component_update_bits(component, hd2_scale_reg,
+ 0x03, 0x01);
+ snd_soc_component_update_bits(component, hd2_enable_reg,
+ 0x04, 0x04);
+ }
+
+ if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) {
+ snd_soc_component_update_bits(component, hd2_enable_reg,
+ 0x04, 0x00);
+ snd_soc_component_update_bits(component, hd2_scale_reg,
+ 0x03, 0x00);
+ snd_soc_component_update_bits(component, hd2_scale_reg,
+ 0x3C, 0x00);
+ }
+}
+
+static int wsa_macro_enable_swr(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ int ch_cnt;
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (!(strnstr(w->name, "RX0", sizeof("WSA_RX0"))) &&
+ !wsa_priv->rx_0_count)
+ wsa_priv->rx_0_count++;
+ if (!(strnstr(w->name, "RX1", sizeof("WSA_RX1"))) &&
+ !wsa_priv->rx_1_count)
+ wsa_priv->rx_1_count++;
+ ch_cnt = wsa_priv->rx_0_count + wsa_priv->rx_1_count;
+
+#if 0
+ if (wsa_priv->swr_ctrl_data) {
+ swrm_wcd_notify(
+ wsa_priv->swr_ctrl_data[0].wsa_swr_pdev,
+ SWR_DEVICE_UP, NULL);
+ swrm_wcd_notify(
+ wsa_priv->swr_ctrl_data[0].wsa_swr_pdev,
+ SWR_SET_NUM_RX_CH, &ch_cnt);
+ }
+#endif
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (!(strnstr(w->name, "RX0", sizeof("WSA_RX0"))) &&
+ wsa_priv->rx_0_count)
+ wsa_priv->rx_0_count--;
+ if (!(strnstr(w->name, "RX1", sizeof("WSA_RX1"))) &&
+ wsa_priv->rx_1_count)
+ wsa_priv->rx_1_count--;
+ ch_cnt = wsa_priv->rx_0_count + wsa_priv->rx_1_count;
+
+#if 0
+ if (wsa_priv->swr_ctrl_data)
+ swrm_wcd_notify(
+ wsa_priv->swr_ctrl_data[0].wsa_swr_pdev,
+ SWR_SET_NUM_RX_CH, &ch_cnt);
+#endif
+ break;
+ }
+ dev_dbg(wsa_priv->dev, "%s: current swr ch cnt: %d\n",
+ __func__, wsa_priv->rx_0_count + wsa_priv->rx_1_count);
+
+ return 0;
+}
+
+static int wsa_macro_config_compander(struct snd_soc_component *component,
+ int comp, int event)
+{
+ u16 comp_ctl0_reg, rx_path_cfg0_reg;
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s: event %d compander %d, enabled %d\n",
+ __func__, event, comp + 1, wsa_priv->comp_enabled[comp]);
+
+ if (!wsa_priv->comp_enabled[comp])
+ return 0;
+
+ comp_ctl0_reg = BOLERO_CDC_WSA_COMPANDER0_CTL0 +
+ (comp * WSA_MACRO_RX_COMP_OFFSET);
+ rx_path_cfg0_reg = BOLERO_CDC_WSA_RX0_RX_PATH_CFG0 +
+ (comp * WSA_MACRO_RX_PATH_OFFSET);
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ /* Enable Compander Clock */
+ snd_soc_component_update_bits(component, comp_ctl0_reg,
+ 0x01, 0x01);
+ snd_soc_component_update_bits(component, comp_ctl0_reg,
+ 0x02, 0x02);
+ snd_soc_component_update_bits(component, comp_ctl0_reg,
+ 0x02, 0x00);
+ snd_soc_component_update_bits(component, rx_path_cfg0_reg,
+ 0x02, 0x02);
+ }
+
+ if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ snd_soc_component_update_bits(component, comp_ctl0_reg,
+ 0x04, 0x04);
+ snd_soc_component_update_bits(component, rx_path_cfg0_reg,
+ 0x02, 0x00);
+ snd_soc_component_update_bits(component, comp_ctl0_reg,
+ 0x02, 0x02);
+ snd_soc_component_update_bits(component, comp_ctl0_reg,
+ 0x02, 0x00);
+ snd_soc_component_update_bits(component, comp_ctl0_reg,
+ 0x01, 0x00);
+ snd_soc_component_update_bits(component, comp_ctl0_reg,
+ 0x04, 0x00);
+ }
+
+ return 0;
+}
+
+static void wsa_macro_enable_softclip_clk(struct snd_soc_component *component,
+ struct wsa_macro_priv *wsa_priv,
+ int path,
+ bool enable)
+{
+ u16 softclip_clk_reg = BOLERO_CDC_WSA_SOFTCLIP0_CRC +
+ (path * WSA_MACRO_RX_SOFTCLIP_OFFSET);
+ u8 softclip_mux_mask = (1 << path);
+ u8 softclip_mux_value = (1 << path);
+
+ dev_dbg(component->dev, "%s: path %d, enable %d\n",
+ __func__, path, enable);
+ if (enable) {
+ if (wsa_priv->softclip_clk_users[path] == 0) {
+ snd_soc_component_update_bits(component,
+ softclip_clk_reg, 0x01, 0x01);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0,
+ softclip_mux_mask, softclip_mux_value);
+ }
+ wsa_priv->softclip_clk_users[path]++;
+ } else {
+ wsa_priv->softclip_clk_users[path]--;
+ if (wsa_priv->softclip_clk_users[path] == 0) {
+ snd_soc_component_update_bits(component,
+ softclip_clk_reg, 0x01, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0,
+ softclip_mux_mask, 0x00);
+ }
+ }
+}
+
+static int wsa_macro_config_softclip(struct snd_soc_component *component,
+ int path, int event)
+{
+ u16 softclip_ctrl_reg = 0;
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+ int softclip_path = 0;
+
+ if (path == WSA_MACRO_COMP1)
+ softclip_path = WSA_MACRO_SOFTCLIP0;
+ else if (path == WSA_MACRO_COMP2)
+ softclip_path = WSA_MACRO_SOFTCLIP1;
+
+ dev_dbg(component->dev, "%s: event %d path %d, enabled %d\n",
+ __func__, event, softclip_path,
+ wsa_priv->is_softclip_on[softclip_path]);
+
+ if (!wsa_priv->is_softclip_on[softclip_path])
+ return 0;
+
+ softclip_ctrl_reg = BOLERO_CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL +
+ (softclip_path * WSA_MACRO_RX_SOFTCLIP_OFFSET);
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ /* Enable Softclip clock and mux */
+ wsa_macro_enable_softclip_clk(component, wsa_priv,
+ softclip_path, true);
+ /* Enable Softclip control */
+ snd_soc_component_update_bits(component, softclip_ctrl_reg,
+ 0x01, 0x01);
+ }
+
+ if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ snd_soc_component_update_bits(component, softclip_ctrl_reg,
+ 0x01, 0x00);
+ wsa_macro_enable_softclip_clk(component, wsa_priv,
+ softclip_path, false);
+ }
+
+ return 0;
+}
+
+static bool wsa_macro_adie_lb(struct snd_soc_component *component,
+ int interp_idx)
+{
+ u16 int_mux_cfg0 = 0, int_mux_cfg1 = 0;
+ u8 int_mux_cfg0_val = 0, int_mux_cfg1_val = 0;
+ u8 int_n_inp0 = 0, int_n_inp1 = 0, int_n_inp2 = 0;
+
+ int_mux_cfg0 = BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0 + interp_idx * 8;
+ int_mux_cfg1 = int_mux_cfg0 + 4;
+ int_mux_cfg0_val = snd_soc_component_read(component, int_mux_cfg0);
+ int_mux_cfg1_val = snd_soc_component_read(component, int_mux_cfg1);
+
+ int_n_inp0 = int_mux_cfg0_val & 0x0F;
+ if (int_n_inp0 == INTn_1_INP_SEL_DEC0 ||
+ int_n_inp0 == INTn_1_INP_SEL_DEC1)
+ return true;
+
+ int_n_inp1 = int_mux_cfg0_val >> 4;
+ if (int_n_inp1 == INTn_1_INP_SEL_DEC0 ||
+ int_n_inp1 == INTn_1_INP_SEL_DEC1)
+ return true;
+
+ int_n_inp2 = int_mux_cfg1_val >> 4;
+ if (int_n_inp2 == INTn_1_INP_SEL_DEC0 ||
+ int_n_inp2 == INTn_1_INP_SEL_DEC1)
+ return true;
+
+ return false;
+}
+
+static int wsa_macro_enable_main_path(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ u16 reg = 0;
+
+
+ reg = BOLERO_CDC_WSA_RX0_RX_PATH_CTL +
+ WSA_MACRO_RX_PATH_OFFSET * w->shift;
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (wsa_macro_adie_lb(component, w->shift)) {
+ snd_soc_component_update_bits(component,
+ reg, 0x20, 0x20);
+ //bolero_wsa_pa_on(component->dev);
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int wsa_macro_interp_get_primary_reg(u16 reg, u16 *ind)
+{
+ u16 prim_int_reg = 0;
+
+ switch (reg) {
+ case BOLERO_CDC_WSA_RX0_RX_PATH_CTL:
+ case BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL:
+ prim_int_reg = BOLERO_CDC_WSA_RX0_RX_PATH_CTL;
+ *ind = 0;
+ break;
+ case BOLERO_CDC_WSA_RX1_RX_PATH_CTL:
+ case BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CTL:
+ prim_int_reg = BOLERO_CDC_WSA_RX1_RX_PATH_CTL;
+ *ind = 1;
+ break;
+ }
+
+ return prim_int_reg;
+}
+
+static int wsa_macro_enable_prim_interpolator(
+ struct snd_soc_component *component,
+ u16 reg, int event)
+{
+ u16 prim_int_reg;
+ u16 ind = 0;
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);;
+
+ prim_int_reg = wsa_macro_interp_get_primary_reg(reg, &ind);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wsa_priv->prim_int_users[ind]++;
+ if (wsa_priv->prim_int_users[ind] == 1) {
+ snd_soc_component_update_bits(component,
+ prim_int_reg + WSA_MACRO_RX_PATH_CFG3_OFFSET,
+ 0x03, 0x03);
+ snd_soc_component_update_bits(component, prim_int_reg,
+ 0x10, 0x10);
+ wsa_macro_hd2_control(component, prim_int_reg, event);
+ snd_soc_component_update_bits(component,
+ prim_int_reg + WSA_MACRO_RX_PATH_DSMDEM_OFFSET,
+ 0x1, 0x1);
+ }
+ if ((reg != prim_int_reg) &&
+ ((snd_soc_component_read(
+ component, prim_int_reg)) & 0x10))
+ snd_soc_component_update_bits(component, reg,
+ 0x10, 0x10);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ wsa_priv->prim_int_users[ind]--;
+ if (wsa_priv->prim_int_users[ind] == 0) {
+ snd_soc_component_update_bits(component, prim_int_reg,
+ 1 << 0x5, 0 << 0x5);
+ snd_soc_component_update_bits(component,
+ prim_int_reg + WSA_MACRO_RX_PATH_DSMDEM_OFFSET,
+ 0x1, 0x0);
+ snd_soc_component_update_bits(component, prim_int_reg,
+ 0x40, 0x40);
+ snd_soc_component_update_bits(component, prim_int_reg,
+ 0x40, 0x00);
+ wsa_macro_hd2_control(component, prim_int_reg, event);
+ }
+ break;
+ }
+
+ dev_dbg(component->dev, "%s: primary interpolator: INT%d, users: %d\n",
+ __func__, ind, wsa_priv->prim_int_users[ind]);
+ return 0;
+}
+
+static int wsa_macro_enable_interpolator(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ u16 gain_reg;
+ u16 reg;
+ int val;
+ int offset_val = 0;
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name);
+
+ if (!(strcmp(w->name, "WSA_RX INT0 INTERP"))) {
+ reg = BOLERO_CDC_WSA_RX0_RX_PATH_CTL;
+ gain_reg = BOLERO_CDC_WSA_RX0_RX_VOL_CTL;
+ } else if (!(strcmp(w->name, "WSA_RX INT1 INTERP"))) {
+ reg = BOLERO_CDC_WSA_RX1_RX_PATH_CTL;
+ gain_reg = BOLERO_CDC_WSA_RX1_RX_VOL_CTL;
+ } else {
+ dev_err(component->dev, "%s: Interpolator reg not found\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Reset if needed */
+ wsa_macro_enable_prim_interpolator(component, reg, event);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ wsa_macro_config_compander(component, w->shift, event);
+ wsa_macro_config_softclip(component, w->shift, event);
+ /* apply gain after int clk is enabled */
+ if ((wsa_priv->spkr_gain_offset ==
+ WSA_MACRO_GAIN_OFFSET_M1P5_DB) &&
+ (wsa_priv->comp_enabled[WSA_MACRO_COMP1] ||
+ wsa_priv->comp_enabled[WSA_MACRO_COMP2]) &&
+ (gain_reg == BOLERO_CDC_WSA_RX0_RX_VOL_CTL ||
+ gain_reg == BOLERO_CDC_WSA_RX1_RX_VOL_CTL)) {
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_RX0_RX_PATH_SEC1,
+ 0x01, 0x01);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_RX0_RX_PATH_MIX_SEC0,
+ 0x01, 0x01);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_RX1_RX_PATH_SEC1,
+ 0x01, 0x01);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_RX1_RX_PATH_MIX_SEC0,
+ 0x01, 0x01);
+ offset_val = -2;
+ }
+ val = snd_soc_component_read(component, gain_reg);
+ val += offset_val;
+ snd_soc_component_write(component, gain_reg, val);
+ wsa_macro_config_ear_spkr_gain(component, wsa_priv,
+ event, gain_reg);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ wsa_macro_config_compander(component, w->shift, event);
+ wsa_macro_config_softclip(component, w->shift, event);
+ wsa_macro_enable_prim_interpolator(component, reg, event);
+ if ((wsa_priv->spkr_gain_offset ==
+ WSA_MACRO_GAIN_OFFSET_M1P5_DB) &&
+ (wsa_priv->comp_enabled[WSA_MACRO_COMP1] ||
+ wsa_priv->comp_enabled[WSA_MACRO_COMP2]) &&
+ (gain_reg == BOLERO_CDC_WSA_RX0_RX_VOL_CTL ||
+ gain_reg == BOLERO_CDC_WSA_RX1_RX_VOL_CTL)) {
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_RX0_RX_PATH_SEC1,
+ 0x01, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_RX0_RX_PATH_MIX_SEC0,
+ 0x01, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_RX1_RX_PATH_SEC1,
+ 0x01, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_RX1_RX_PATH_MIX_SEC0,
+ 0x01, 0x00);
+ offset_val = 2;
+ val = snd_soc_component_read(component, gain_reg);
+ val += offset_val;
+ snd_soc_component_write(component, gain_reg, val);
+ }
+ wsa_macro_config_ear_spkr_gain(component, wsa_priv,
+ event, gain_reg);
+ break;
+ }
+
+ return 0;
+}
+
+static int wsa_macro_config_ear_spkr_gain(struct snd_soc_component *component,
+ struct wsa_macro_priv *wsa_priv,
+ int event, int gain_reg)
+{
+ int comp_gain_offset, val;
+
+ switch (wsa_priv->spkr_mode) {
+ /* Compander gain in WSA_MACRO_SPKR_MODE1 case is 12 dB */
+ case WSA_MACRO_SPKR_MODE_1:
+ comp_gain_offset = -12;
+ break;
+ /* Default case compander gain is 15 dB */
+ default:
+ comp_gain_offset = -15;
+ break;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* Apply ear spkr gain only if compander is enabled */
+ if (wsa_priv->comp_enabled[WSA_MACRO_COMP1] &&
+ (gain_reg == BOLERO_CDC_WSA_RX0_RX_VOL_CTL) &&
+ (wsa_priv->ear_spkr_gain != 0)) {
+ /* For example, val is -8(-12+5-1) for 4dB of gain */
+ val = comp_gain_offset + wsa_priv->ear_spkr_gain - 1;
+ snd_soc_component_write(component, gain_reg, val);
+
+ dev_dbg(wsa_priv->dev, "%s: RX0 Volume %d dB\n",
+ __func__, val);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /*
+ * Reset RX0 volume to 0 dB if compander is enabled and
+ * ear_spkr_gain is non-zero.
+ */
+ if (wsa_priv->comp_enabled[WSA_MACRO_COMP1] &&
+ (gain_reg == BOLERO_CDC_WSA_RX0_RX_VOL_CTL) &&
+ (wsa_priv->ear_spkr_gain != 0)) {
+ snd_soc_component_write(component, gain_reg, 0x0);
+
+ dev_dbg(wsa_priv->dev, "%s: Reset RX0 Volume to 0 dB\n",
+ __func__);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static int wsa_macro_spk_boost_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ u16 boost_path_ctl, boost_path_cfg1;
+ u16 reg, reg_mix;
+
+ dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event);
+
+ if (!strcmp(w->name, "WSA_RX INT0 CHAIN")) {
+ boost_path_ctl = BOLERO_CDC_WSA_BOOST0_BOOST_PATH_CTL;
+ boost_path_cfg1 = BOLERO_CDC_WSA_RX0_RX_PATH_CFG1;
+ reg = BOLERO_CDC_WSA_RX0_RX_PATH_CTL;
+ reg_mix = BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL;
+ } else if (!strcmp(w->name, "WSA_RX INT1 CHAIN")) {
+ boost_path_ctl = BOLERO_CDC_WSA_BOOST1_BOOST_PATH_CTL;
+ boost_path_cfg1 = BOLERO_CDC_WSA_RX1_RX_PATH_CFG1;
+ reg = BOLERO_CDC_WSA_RX1_RX_PATH_CTL;
+ reg_mix = BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CTL;
+ } else {
+ dev_err(component->dev, "%s: unknown widget: %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_update_bits(component, boost_path_cfg1,
+ 0x01, 0x01);
+ snd_soc_component_update_bits(component, boost_path_ctl,
+ 0x10, 0x10);
+ if ((snd_soc_component_read(component, reg_mix)) & 0x10)
+ snd_soc_component_update_bits(component, reg_mix,
+ 0x10, 0x00);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_component_update_bits(component, reg, 0x10, 0x00);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component, boost_path_ctl,
+ 0x10, 0x00);
+ snd_soc_component_update_bits(component, boost_path_cfg1,
+ 0x01, 0x00);
+ break;
+ }
+
+ return 0;
+}
+
+
+static int wsa_macro_enable_vbat(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+ u16 vbat_path_cfg = 0;
+ int softclip_path = 0;
+
+ dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event);
+ if (!strcmp(w->name, "WSA_RX INT0 VBAT")) {
+ vbat_path_cfg = BOLERO_CDC_WSA_RX0_RX_PATH_CFG1;
+ softclip_path = WSA_MACRO_SOFTCLIP0;
+ } else if (!strcmp(w->name, "WSA_RX INT1 VBAT")) {
+ vbat_path_cfg = BOLERO_CDC_WSA_RX1_RX_PATH_CFG1;
+ softclip_path = WSA_MACRO_SOFTCLIP1;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Enable clock for VBAT block */
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_PATH_CTL, 0x10, 0x10);
+ /* Enable VBAT block */
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_CFG, 0x01, 0x01);
+ /* Update interpolator with 384K path */
+ snd_soc_component_update_bits(component, vbat_path_cfg,
+ 0x80, 0x80);
+ /* Use attenuation mode */
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_CFG, 0x02, 0x00);
+ /*
+ * BCL block needs softclip clock and mux config to be enabled
+ */
+ wsa_macro_enable_softclip_clk(component, wsa_priv,
+ softclip_path, true);
+ /* Enable VBAT at channel level */
+ snd_soc_component_update_bits(component, vbat_path_cfg,
+ 0x02, 0x02);
+ /* Set the ATTK1 gain */
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD1,
+ 0xFF, 0xFF);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD2,
+ 0xFF, 0x03);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD3,
+ 0xFF, 0x00);
+ /* Set the ATTK2 gain */
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD4,
+ 0xFF, 0xFF);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD5,
+ 0xFF, 0x03);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD6,
+ 0xFF, 0x00);
+ /* Set the ATTK3 gain */
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD7,
+ 0xFF, 0xFF);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD8,
+ 0xFF, 0x03);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD9,
+ 0xFF, 0x00);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component, vbat_path_cfg,
+ 0x80, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_CFG,
+ 0x02, 0x02);
+ snd_soc_component_update_bits(component, vbat_path_cfg,
+ 0x02, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD1,
+ 0xFF, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD2,
+ 0xFF, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD3,
+ 0xFF, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD4,
+ 0xFF, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD5,
+ 0xFF, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD6,
+ 0xFF, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD7,
+ 0xFF, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD8,
+ 0xFF, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD9,
+ 0xFF, 0x00);
+ wsa_macro_enable_softclip_clk(component, wsa_priv,
+ softclip_path, false);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_CFG, 0x01, 0x00);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_PATH_CTL, 0x10, 0x00);
+ break;
+ default:
+ dev_err(component->dev, "%s: Invalid event %d\n", __func__, event);
+ break;
+ }
+ return 0;
+}
+
+static int wsa_macro_enable_echo(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+ u16 val, ec_tx = 0, ec_hq_reg;
+
+ dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name);
+
+ val = snd_soc_component_read(component,
+ BOLERO_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0);
+ if (!(strcmp(w->name, "WSA RX_MIX EC0_MUX")))
+ ec_tx = (val & 0x07) - 1;
+ else
+ ec_tx = ((val & 0x38) >> 0x3) - 1;
+
+ if (ec_tx < 0 || ec_tx >= (WSA_MACRO_RX1 + 1)) {
+ dev_err(component->dev, "%s: EC mix control not set correctly\n",
+ __func__);
+ return -EINVAL;
+ }
+ if (wsa_priv->ec_hq[ec_tx]) {
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0,
+ 0x1 << ec_tx, 0x1 << ec_tx);
+ ec_hq_reg = BOLERO_CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL +
+ 0x40 * ec_tx;
+ snd_soc_component_update_bits(component, ec_hq_reg, 0x01, 0x01);
+ ec_hq_reg = BOLERO_CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0 +
+ 0x40 * ec_tx;
+ /* default set to 48k */
+ snd_soc_component_update_bits(component, ec_hq_reg, 0x1E, 0x08);
+ }
+
+ return 0;
+}
+
+static int wsa_macro_get_ec_hq(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ int ec_tx = ((struct soc_mixer_control *)
+ kcontrol->private_value)->shift;
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = wsa_priv->ec_hq[ec_tx];
+ return 0;
+}
+
+static int wsa_macro_set_ec_hq(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ int ec_tx = ((struct soc_mixer_control *)
+ kcontrol->private_value)->shift;
+ int value = ucontrol->value.integer.value[0];
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s: enable current %d, new %d\n",
+ __func__, wsa_priv->ec_hq[ec_tx], value);
+ wsa_priv->ec_hq[ec_tx] = value;
+
+ return 0;
+}
+
+static int wsa_macro_get_rx_mute_status(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+ int wsa_rx_shift = ((struct soc_mixer_control *)
+ kcontrol->private_value)->shift;
+
+ ucontrol->value.integer.value[0] =
+ wsa_priv->wsa_digital_mute_status[wsa_rx_shift];
+ return 0;
+}
+
+static int wsa_macro_set_rx_mute_status(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+ int value = ucontrol->value.integer.value[0];
+ int wsa_rx_shift = ((struct soc_mixer_control *)
+ kcontrol->private_value)->shift;
+
+
+ switch (wsa_rx_shift) {
+ case 0:
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_RX0_RX_PATH_CTL,
+ 0x10, value << 4);
+ break;
+ case 1:
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_RX1_RX_PATH_CTL,
+ 0x10, value << 4);
+ break;
+ case 2:
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL,
+ 0x10, value << 4);
+ break;
+ case 3:
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CTL,
+ 0x10, value << 4);
+ break;
+ default:
+ pr_err("%s: invalid argument rx_shift = %d\n", __func__,
+ wsa_rx_shift);
+ return -EINVAL;
+ }
+
+ dev_dbg(component->dev, "%s: WSA Digital Mute RX %d Enable %d\n",
+ __func__, wsa_rx_shift, value);
+ wsa_priv->wsa_digital_mute_status[wsa_rx_shift] = value;
+ return 0;
+}
+
+static int wsa_macro_get_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ int comp = ((struct soc_mixer_control *)
+ kcontrol->private_value)->shift;
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = wsa_priv->comp_enabled[comp];
+ return 0;
+}
+
+static int wsa_macro_set_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ int comp = ((struct soc_mixer_control *)
+ kcontrol->private_value)->shift;
+ int value = ucontrol->value.integer.value[0];
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+
+
+ dev_dbg(component->dev, "%s: Compander %d enable current %d, new %d\n",
+ __func__, comp + 1, wsa_priv->comp_enabled[comp], value);
+ wsa_priv->comp_enabled[comp] = value;
+
+ return 0;
+}
+
+static int wsa_macro_ear_spkr_pa_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = wsa_priv->ear_spkr_gain;
+
+ dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int wsa_macro_ear_spkr_pa_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+
+ wsa_priv->ear_spkr_gain = ucontrol->value.integer.value[0];
+
+ dev_dbg(component->dev, "%s: gain = %d\n", __func__,
+ wsa_priv->ear_spkr_gain);
+
+ return 0;
+}
+
+static int wsa_macro_spkr_left_boost_stage_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 bst_state_max = 0;
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+
+ bst_state_max = snd_soc_component_read(component,
+ BOLERO_CDC_WSA_BOOST0_BOOST_CTL);
+ bst_state_max = (bst_state_max & 0x0c) >> 2;
+ ucontrol->value.integer.value[0] = bst_state_max;
+ dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int wsa_macro_spkr_left_boost_stage_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 bst_state_max;
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+
+ dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+ bst_state_max = ucontrol->value.integer.value[0] << 2;
+ /* bolero does not need to limit the boost levels */
+
+ return 0;
+}
+
+static int wsa_macro_spkr_right_boost_stage_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 bst_state_max = 0;
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+
+ bst_state_max = snd_soc_component_read(component,
+ BOLERO_CDC_WSA_BOOST1_BOOST_CTL);
+ bst_state_max = (bst_state_max & 0x0c) >> 2;
+ ucontrol->value.integer.value[0] = bst_state_max;
+ dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int wsa_macro_spkr_right_boost_stage_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 bst_state_max;
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+
+ dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+ bst_state_max = ucontrol->value.integer.value[0] << 2;
+ /* bolero does not need to limit the boost levels */
+
+ return 0;
+}
+
+static int wsa_macro_rx_mux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(widget->dapm);
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] =
+ wsa_priv->rx_port_value[widget->shift];
+ return 0;
+}
+
+static int wsa_macro_rx_mux_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(widget->dapm);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ struct snd_soc_dapm_update *update = NULL;
+ u32 rx_port_value = ucontrol->value.integer.value[0];
+ u32 bit_input = 0;
+ u32 aif_rst;
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+
+ aif_rst = wsa_priv->rx_port_value[widget->shift];
+ if (!rx_port_value) {
+ if (aif_rst == 0) {
+ dev_err(component->dev, "%s: AIF reset already\n", __func__);
+ return 0;
+ }
+ if (aif_rst >= WSA_MACRO_RX_MAX) {
+ dev_err(component->dev, "%s: Invalid AIF reset\n", __func__);
+ return 0;
+ }
+ }
+ wsa_priv->rx_port_value[widget->shift] = rx_port_value;
+
+ bit_input = widget->shift;
+
+ dev_dbg(component->dev,
+ "%s: mux input: %d, mux output: %d, bit: %d\n",
+ __func__, rx_port_value, widget->shift, bit_input);
+
+ switch (rx_port_value) {
+ case 0:
+ if (wsa_priv->active_ch_cnt[aif_rst]) {
+ clear_bit(bit_input,
+ &wsa_priv->active_ch_mask[aif_rst]);
+ wsa_priv->active_ch_cnt[aif_rst]--;
+ }
+ break;
+ case 1:
+ case 2:
+ set_bit(bit_input,
+ &wsa_priv->active_ch_mask[rx_port_value]);
+ wsa_priv->active_ch_cnt[rx_port_value]++;
+ break;
+ default:
+ dev_err(component->dev,
+ "%s: Invalid AIF_ID for WSA RX MUX %d\n",
+ __func__, rx_port_value);
+ return -EINVAL;
+ }
+
+ snd_soc_dapm_mux_update_power(widget->dapm, kcontrol,
+ rx_port_value, e, update);
+ return 0;
+}
+
+static int wsa_macro_vbat_bcl_gsm_mode_func_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+
+ ucontrol->value.integer.value[0] =
+ ((snd_soc_component_read(
+ component, BOLERO_CDC_WSA_VBAT_BCL_VBAT_CFG) & 0x04) ?
+ 1 : 0);
+
+ dev_dbg(component->dev, "%s: value: %lu\n", __func__,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int wsa_macro_vbat_bcl_gsm_mode_func_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+
+ dev_dbg(component->dev, "%s: value: %lu\n", __func__,
+ ucontrol->value.integer.value[0]);
+
+ /* Set Vbat register configuration for GSM mode bit based on value */
+ if (ucontrol->value.integer.value[0])
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_CFG,
+ 0x04, 0x04);
+ else
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_CFG,
+ 0x04, 0x00);
+
+ return 0;
+}
+
+static int wsa_macro_soft_clip_enable_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+ int path = ((struct soc_mixer_control *)
+ kcontrol->private_value)->shift;
+
+
+ ucontrol->value.integer.value[0] = wsa_priv->is_softclip_on[path];
+
+ dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int wsa_macro_soft_clip_enable_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+ int path = ((struct soc_mixer_control *)
+ kcontrol->private_value)->shift;
+
+ wsa_priv->is_softclip_on[path] = ucontrol->value.integer.value[0];
+
+ dev_dbg(component->dev, "%s: soft clip enable for %d: %d\n", __func__,
+ path, wsa_priv->is_softclip_on[path]);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new wsa_macro_snd_controls[] = {
+ SOC_ENUM_EXT("EAR SPKR PA Gain", wsa_macro_ear_spkr_pa_gain_enum,
+ wsa_macro_ear_spkr_pa_gain_get,
+ wsa_macro_ear_spkr_pa_gain_put),
+ SOC_ENUM_EXT("SPKR Left Boost Max State",
+ wsa_macro_spkr_boost_stage_enum,
+ wsa_macro_spkr_left_boost_stage_get,
+ wsa_macro_spkr_left_boost_stage_put),
+ SOC_ENUM_EXT("SPKR Right Boost Max State",
+ wsa_macro_spkr_boost_stage_enum,
+ wsa_macro_spkr_right_boost_stage_get,
+ wsa_macro_spkr_right_boost_stage_put),
+ SOC_ENUM_EXT("GSM mode Enable", wsa_macro_vbat_bcl_gsm_mode_enum,
+ wsa_macro_vbat_bcl_gsm_mode_func_get,
+ wsa_macro_vbat_bcl_gsm_mode_func_put),
+ SOC_SINGLE_EXT("WSA_Softclip0 Enable", SND_SOC_NOPM,
+ WSA_MACRO_SOFTCLIP0, 1, 0,
+ wsa_macro_soft_clip_enable_get,
+ wsa_macro_soft_clip_enable_put),
+ SOC_SINGLE_EXT("WSA_Softclip1 Enable", SND_SOC_NOPM,
+ WSA_MACRO_SOFTCLIP1, 1, 0,
+ wsa_macro_soft_clip_enable_get,
+ wsa_macro_soft_clip_enable_put),
+ SOC_SINGLE_SX_TLV("WSA_RX0 Digital Volume",
+ BOLERO_CDC_WSA_RX0_RX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("WSA_RX1 Digital Volume",
+ BOLERO_CDC_WSA_RX1_RX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_EXT("WSA_RX0 Digital Mute", SND_SOC_NOPM, WSA_MACRO_RX0, 1,
+ 0, wsa_macro_get_rx_mute_status,
+ wsa_macro_set_rx_mute_status),
+ SOC_SINGLE_EXT("WSA_RX1 Digital Mute", SND_SOC_NOPM, WSA_MACRO_RX1, 1,
+ 0, wsa_macro_get_rx_mute_status,
+ wsa_macro_set_rx_mute_status),
+ SOC_SINGLE_EXT("WSA_RX0_MIX Digital Mute", SND_SOC_NOPM,
+ WSA_MACRO_RX_MIX0, 1, 0, wsa_macro_get_rx_mute_status,
+ wsa_macro_set_rx_mute_status),
+ SOC_SINGLE_EXT("WSA_RX1_MIX Digital Mute", SND_SOC_NOPM,
+ WSA_MACRO_RX_MIX1, 1, 0, wsa_macro_get_rx_mute_status,
+ wsa_macro_set_rx_mute_status),
+ SOC_SINGLE_EXT("WSA_COMP1 Switch", SND_SOC_NOPM, WSA_MACRO_COMP1, 1, 0,
+ wsa_macro_get_compander, wsa_macro_set_compander),
+ SOC_SINGLE_EXT("WSA_COMP2 Switch", SND_SOC_NOPM, WSA_MACRO_COMP2, 1, 0,
+ wsa_macro_get_compander, wsa_macro_set_compander),
+ SOC_SINGLE_EXT("WSA_RX0 EC_HQ Switch", SND_SOC_NOPM, WSA_MACRO_RX0,
+ 1, 0, wsa_macro_get_ec_hq, wsa_macro_set_ec_hq),
+ SOC_SINGLE_EXT("WSA_RX1 EC_HQ Switch", SND_SOC_NOPM, WSA_MACRO_RX1,
+ 1, 0, wsa_macro_get_ec_hq, wsa_macro_set_ec_hq),
+};
+
+static const struct soc_enum rx_mux_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_mux_text), rx_mux_text);
+
+static const struct snd_kcontrol_new rx_mux[WSA_MACRO_RX_MAX] = {
+ SOC_DAPM_ENUM_EXT("WSA RX0 Mux", rx_mux_enum,
+ wsa_macro_rx_mux_get, wsa_macro_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("WSA RX1 Mux", rx_mux_enum,
+ wsa_macro_rx_mux_get, wsa_macro_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("WSA RX_MIX0 Mux", rx_mux_enum,
+ wsa_macro_rx_mux_get, wsa_macro_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("WSA RX_MIX1 Mux", rx_mux_enum,
+ wsa_macro_rx_mux_get, wsa_macro_rx_mux_put),
+};
+
+static int wsa_macro_vi_feed_mixer_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(widget->dapm);
+ struct soc_mixer_control *mixer =
+ ((struct soc_mixer_control *)kcontrol->private_value);
+ u32 dai_id = widget->shift;
+ u32 spk_tx_id = mixer->shift;
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+
+ if (test_bit(spk_tx_id, &wsa_priv->active_ch_mask[dai_id]))
+ ucontrol->value.integer.value[0] = 1;
+ else
+ ucontrol->value.integer.value[0] = 0;
+
+ return 0;
+}
+
+static int wsa_macro_vi_feed_mixer_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *widget =
+ snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(widget->dapm);
+ struct soc_mixer_control *mixer =
+ ((struct soc_mixer_control *)kcontrol->private_value);
+ u32 spk_tx_id = mixer->shift;
+ u32 enable = ucontrol->value.integer.value[0];
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(component);
+
+ wsa_priv->vi_feed_value = ucontrol->value.integer.value[0];
+
+ if (enable) {
+ if (spk_tx_id == WSA_MACRO_TX0 &&
+ !test_bit(WSA_MACRO_TX0,
+ &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI])) {
+ set_bit(WSA_MACRO_TX0,
+ &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI]);
+ wsa_priv->active_ch_cnt[WSA_MACRO_AIF_VI]++;
+ }
+ if (spk_tx_id == WSA_MACRO_TX1 &&
+ !test_bit(WSA_MACRO_TX1,
+ &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI])) {
+ set_bit(WSA_MACRO_TX1,
+ &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI]);
+ wsa_priv->active_ch_cnt[WSA_MACRO_AIF_VI]++;
+ }
+ } else {
+ if (spk_tx_id == WSA_MACRO_TX0 &&
+ test_bit(WSA_MACRO_TX0,
+ &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI])) {
+ clear_bit(WSA_MACRO_TX0,
+ &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI]);
+ wsa_priv->active_ch_cnt[WSA_MACRO_AIF_VI]--;
+ }
+ if (spk_tx_id == WSA_MACRO_TX1 &&
+ test_bit(WSA_MACRO_TX1,
+ &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI])) {
+ clear_bit(WSA_MACRO_TX1,
+ &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI]);
+ wsa_priv->active_ch_cnt[WSA_MACRO_AIF_VI]--;
+ }
+ }
+ snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, NULL);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new aif_vi_mixer[] = {
+ SOC_SINGLE_EXT("WSA_SPKR_VI_1", SND_SOC_NOPM, WSA_MACRO_TX0, 1, 0,
+ wsa_macro_vi_feed_mixer_get,
+ wsa_macro_vi_feed_mixer_put),
+ SOC_SINGLE_EXT("WSA_SPKR_VI_2", SND_SOC_NOPM, WSA_MACRO_TX1, 1, 0,
+ wsa_macro_vi_feed_mixer_get,
+ wsa_macro_vi_feed_mixer_put),
+};
+
+static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets[] = {
+ SND_SOC_DAPM_AIF_IN("WSA AIF1 PB", "WSA_AIF1 Playback", 0,
+ SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_IN("WSA AIF_MIX1 PB", "WSA_AIF_MIX1 Playback", 0,
+ SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_OUT_E("WSA AIF_VI", "WSA_AIF_VI Capture", 0,
+ SND_SOC_NOPM, WSA_MACRO_AIF_VI, 0,
+ wsa_macro_enable_vi_feedback,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_OUT("WSA AIF_ECHO", "WSA_AIF_ECHO Capture", 0,
+ SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_MIXER("WSA_AIF_VI Mixer", SND_SOC_NOPM, WSA_MACRO_AIF_VI,
+ 0, aif_vi_mixer, ARRAY_SIZE(aif_vi_mixer)),
+ SND_SOC_DAPM_MUX_E("WSA RX_MIX EC0_MUX", SND_SOC_NOPM,
+ WSA_MACRO_EC0_MUX, 0,
+ &rx_mix_ec0_mux, wsa_macro_enable_echo,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("WSA RX_MIX EC1_MUX", SND_SOC_NOPM,
+ WSA_MACRO_EC1_MUX, 0,
+ &rx_mix_ec1_mux, wsa_macro_enable_echo,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("WSA RX0 MUX", SND_SOC_NOPM, WSA_MACRO_RX0, 0,
+ &rx_mux[WSA_MACRO_RX0]),
+ SND_SOC_DAPM_MUX("WSA RX1 MUX", SND_SOC_NOPM, WSA_MACRO_RX1, 0,
+ &rx_mux[WSA_MACRO_RX1]),
+ SND_SOC_DAPM_MUX("WSA RX_MIX0 MUX", SND_SOC_NOPM, WSA_MACRO_RX_MIX0, 0,
+ &rx_mux[WSA_MACRO_RX_MIX0]),
+ SND_SOC_DAPM_MUX("WSA RX_MIX1 MUX", SND_SOC_NOPM, WSA_MACRO_RX_MIX1, 0,
+ &rx_mux[WSA_MACRO_RX_MIX1]),
+
+ SND_SOC_DAPM_MIXER("WSA RX0", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("WSA RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("WSA RX_MIX0", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("WSA RX_MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX_E("WSA_RX0 INP0", SND_SOC_NOPM, 0, 0,
+ &rx0_prim_inp0_mux, wsa_macro_enable_swr,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("WSA_RX0 INP1", SND_SOC_NOPM, 0, 0,
+ &rx0_prim_inp1_mux, wsa_macro_enable_swr,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0,
+ &rx0_prim_inp2_mux, wsa_macro_enable_swr,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL,
+ 0, 0, &rx0_mix_mux, wsa_macro_enable_mix_path,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("WSA_RX1 INP0", SND_SOC_NOPM, 0, 0,
+ &rx1_prim_inp0_mux, wsa_macro_enable_swr,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("WSA_RX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx1_prim_inp1_mux, wsa_macro_enable_swr,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx1_prim_inp2_mux, wsa_macro_enable_swr,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CTL,
+ 0, 0, &rx1_mix_mux, wsa_macro_enable_mix_path,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("WSA_RX INT0 MIX", SND_SOC_NOPM,
+ 0, 0, NULL, 0, wsa_macro_enable_main_path,
+ SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MIXER_E("WSA_RX INT1 MIX", SND_SOC_NOPM,
+ 1, 0, NULL, 0, wsa_macro_enable_main_path,
+ SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MIXER("WSA_RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("WSA_RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX_E("WSA_RX0 INT0 SIDETONE MIX",
+ BOLERO_CDC_WSA_RX0_RX_PATH_CFG1, 4, 0,
+ &rx0_sidetone_mix_mux, wsa_macro_enable_swr,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_INPUT("WSA SRC0_INP"),
+
+ SND_SOC_DAPM_INPUT("WSA_TX DEC0_INP"),
+ SND_SOC_DAPM_INPUT("WSA_TX DEC1_INP"),
+
+ SND_SOC_DAPM_MIXER_E("WSA_RX INT0 INTERP", SND_SOC_NOPM,
+ WSA_MACRO_COMP1, 0, NULL, 0, wsa_macro_enable_interpolator,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("WSA_RX INT1 INTERP", SND_SOC_NOPM,
+ WSA_MACRO_COMP2, 0, NULL, 0, wsa_macro_enable_interpolator,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MIXER_E("WSA_RX INT0 CHAIN", SND_SOC_NOPM, 0, 0,
+ NULL, 0, wsa_macro_spk_boost_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("WSA_RX INT1 CHAIN", SND_SOC_NOPM, 0, 0,
+ NULL, 0, wsa_macro_spk_boost_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MIXER_E("WSA_RX INT0 VBAT", SND_SOC_NOPM,
+ 0, 0, wsa_int0_vbat_mix_switch,
+ ARRAY_SIZE(wsa_int0_vbat_mix_switch),
+ wsa_macro_enable_vbat,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("WSA_RX INT1 VBAT", SND_SOC_NOPM,
+ 0, 0, wsa_int1_vbat_mix_switch,
+ ARRAY_SIZE(wsa_int1_vbat_mix_switch),
+ wsa_macro_enable_vbat,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_INPUT("VIINPUT_WSA"),
+
+ SND_SOC_DAPM_OUTPUT("WSA_SPK1 OUT"),
+ SND_SOC_DAPM_OUTPUT("WSA_SPK2 OUT"),
+
+ SND_SOC_DAPM_SUPPLY_S("WSA_MCLK", 0, SND_SOC_NOPM, 0, 0,
+ wsa_macro_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route wsa_audio_map[] = {
+ /* VI Feedback */
+ {"WSA_AIF_VI Mixer", "WSA_SPKR_VI_1", "VIINPUT_WSA"},
+ {"WSA_AIF_VI Mixer", "WSA_SPKR_VI_2", "VIINPUT_WSA"},
+ {"WSA AIF_VI", NULL, "WSA_AIF_VI Mixer"},
+ {"WSA AIF_VI", NULL, "WSA_MCLK"},
+
+ {"WSA RX_MIX EC0_MUX", "RX_MIX_TX0", "WSA_RX INT0 SEC MIX"},
+ {"WSA RX_MIX EC1_MUX", "RX_MIX_TX0", "WSA_RX INT0 SEC MIX"},
+ {"WSA RX_MIX EC0_MUX", "RX_MIX_TX1", "WSA_RX INT1 SEC MIX"},
+ {"WSA RX_MIX EC1_MUX", "RX_MIX_TX1", "WSA_RX INT1 SEC MIX"},
+ {"WSA AIF_ECHO", NULL, "WSA RX_MIX EC0_MUX"},
+ {"WSA AIF_ECHO", NULL, "WSA RX_MIX EC1_MUX"},
+ {"WSA AIF_ECHO", NULL, "WSA_MCLK"},
+
+ {"WSA AIF1 PB", NULL, "WSA_MCLK"},
+ {"WSA AIF_MIX1 PB", NULL, "WSA_MCLK"},
+
+ {"WSA RX0 MUX", "AIF1_PB", "WSA AIF1 PB"},
+ {"WSA RX1 MUX", "AIF1_PB", "WSA AIF1 PB"},
+ {"WSA RX_MIX0 MUX", "AIF1_PB", "WSA AIF1 PB"},
+ {"WSA RX_MIX1 MUX", "AIF1_PB", "WSA AIF1 PB"},
+
+ {"WSA RX0 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"},
+ {"WSA RX1 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"},
+ {"WSA RX_MIX0 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"},
+ {"WSA RX_MIX1 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"},
+
+ {"WSA RX0", NULL, "WSA RX0 MUX"},
+ {"WSA RX1", NULL, "WSA RX1 MUX"},
+ {"WSA RX_MIX0", NULL, "WSA RX_MIX0 MUX"},
+ {"WSA RX_MIX1", NULL, "WSA RX_MIX1 MUX"},
+
+ {"WSA_RX0 INP0", "RX0", "WSA RX0"},
+ {"WSA_RX0 INP0", "RX1", "WSA RX1"},
+ {"WSA_RX0 INP0", "RX_MIX0", "WSA RX_MIX0"},
+ {"WSA_RX0 INP0", "RX_MIX1", "WSA RX_MIX1"},
+ {"WSA_RX0 INP0", "DEC0", "WSA_TX DEC0_INP"},
+ {"WSA_RX0 INP0", "DEC1", "WSA_TX DEC1_INP"},
+ {"WSA_RX INT0 MIX", NULL, "WSA_RX0 INP0"},
+
+ {"WSA_RX0 INP1", "RX0", "WSA RX0"},
+ {"WSA_RX0 INP1", "RX1", "WSA RX1"},
+ {"WSA_RX0 INP1", "RX_MIX0", "WSA RX_MIX0"},
+ {"WSA_RX0 INP1", "RX_MIX1", "WSA RX_MIX1"},
+ {"WSA_RX0 INP1", "DEC0", "WSA_TX DEC0_INP"},
+ {"WSA_RX0 INP1", "DEC1", "WSA_TX DEC1_INP"},
+ {"WSA_RX INT0 MIX", NULL, "WSA_RX0 INP1"},
+
+ {"WSA_RX0 INP2", "RX0", "WSA RX0"},
+ {"WSA_RX0 INP2", "RX1", "WSA RX1"},
+ {"WSA_RX0 INP2", "RX_MIX0", "WSA RX_MIX0"},
+ {"WSA_RX0 INP2", "RX_MIX1", "WSA RX_MIX1"},
+ {"WSA_RX0 INP2", "DEC0", "WSA_TX DEC0_INP"},
+ {"WSA_RX0 INP2", "DEC1", "WSA_TX DEC1_INP"},
+ {"WSA_RX INT0 MIX", NULL, "WSA_RX0 INP2"},
+
+ {"WSA_RX0 MIX INP", "RX0", "WSA RX0"},
+ {"WSA_RX0 MIX INP", "RX1", "WSA RX1"},
+ {"WSA_RX0 MIX INP", "RX_MIX0", "WSA RX_MIX0"},
+ {"WSA_RX0 MIX INP", "RX_MIX1", "WSA RX_MIX1"},
+ {"WSA_RX INT0 SEC MIX", NULL, "WSA_RX0 MIX INP"},
+
+ {"WSA_RX INT0 SEC MIX", NULL, "WSA_RX INT0 MIX"},
+ {"WSA_RX INT0 INTERP", NULL, "WSA_RX INT0 SEC MIX"},
+ {"WSA_RX0 INT0 SIDETONE MIX", "SRC0", "WSA SRC0_INP"},
+ {"WSA_RX INT0 INTERP", NULL, "WSA_RX0 INT0 SIDETONE MIX"},
+ {"WSA_RX INT0 CHAIN", NULL, "WSA_RX INT0 INTERP"},
+
+ {"WSA_RX INT0 VBAT", "WSA RX0 VBAT Enable", "WSA_RX INT0 INTERP"},
+ {"WSA_RX INT0 CHAIN", NULL, "WSA_RX INT0 VBAT"},
+
+ {"WSA_SPK1 OUT", NULL, "WSA_RX INT0 CHAIN"},
+ {"WSA_SPK1 OUT", NULL, "WSA_MCLK"},
+
+ {"WSA_RX1 INP0", "RX0", "WSA RX0"},
+ {"WSA_RX1 INP0", "RX1", "WSA RX1"},
+ {"WSA_RX1 INP0", "RX_MIX0", "WSA RX_MIX0"},
+ {"WSA_RX1 INP0", "RX_MIX1", "WSA RX_MIX1"},
+ {"WSA_RX1 INP0", "DEC0", "WSA_TX DEC0_INP"},
+ {"WSA_RX1 INP0", "DEC1", "WSA_TX DEC1_INP"},
+ {"WSA_RX INT1 MIX", NULL, "WSA_RX1 INP0"},
+
+ {"WSA_RX1 INP1", "RX0", "WSA RX0"},
+ {"WSA_RX1 INP1", "RX1", "WSA RX1"},
+ {"WSA_RX1 INP1", "RX_MIX0", "WSA RX_MIX0"},
+ {"WSA_RX1 INP1", "RX_MIX1", "WSA RX_MIX1"},
+ {"WSA_RX1 INP1", "DEC0", "WSA_TX DEC0_INP"},
+ {"WSA_RX1 INP1", "DEC1", "WSA_TX DEC1_INP"},
+ {"WSA_RX INT1 MIX", NULL, "WSA_RX1 INP1"},
+
+ {"WSA_RX1 INP2", "RX0", "WSA RX0"},
+ {"WSA_RX1 INP2", "RX1", "WSA RX1"},
+ {"WSA_RX1 INP2", "RX_MIX0", "WSA RX_MIX0"},
+ {"WSA_RX1 INP2", "RX_MIX1", "WSA RX_MIX1"},
+ {"WSA_RX1 INP2", "DEC0", "WSA_TX DEC0_INP"},
+ {"WSA_RX1 INP2", "DEC1", "WSA_TX DEC1_INP"},
+ {"WSA_RX INT1 MIX", NULL, "WSA_RX1 INP2"},
+
+ {"WSA_RX1 MIX INP", "RX0", "WSA RX0"},
+ {"WSA_RX1 MIX INP", "RX1", "WSA RX1"},
+ {"WSA_RX1 MIX INP", "RX_MIX0", "WSA RX_MIX0"},
+ {"WSA_RX1 MIX INP", "RX_MIX1", "WSA RX_MIX1"},
+ {"WSA_RX INT1 SEC MIX", NULL, "WSA_RX1 MIX INP"},
+
+ {"WSA_RX INT1 SEC MIX", NULL, "WSA_RX INT1 MIX"},
+ {"WSA_RX INT1 INTERP", NULL, "WSA_RX INT1 SEC MIX"},
+
+ {"WSA_RX INT1 VBAT", "WSA RX1 VBAT Enable", "WSA_RX INT1 INTERP"},
+ {"WSA_RX INT1 CHAIN", NULL, "WSA_RX INT1 VBAT"},
+
+ {"WSA_RX INT1 CHAIN", NULL, "WSA_RX INT1 INTERP"},
+ {"WSA_SPK2 OUT", NULL, "WSA_RX INT1 CHAIN"},
+ {"WSA_SPK2 OUT", NULL, "WSA_MCLK"},
+};
+
+static const struct wsa_macro_reg_mask_val wsa_macro_reg_init[] = {
+ {BOLERO_CDC_WSA_BOOST0_BOOST_CFG1, 0x3F, 0x12},
+ {BOLERO_CDC_WSA_BOOST0_BOOST_CFG2, 0x1C, 0x08},
+ {BOLERO_CDC_WSA_COMPANDER0_CTL7, 0x1E, 0x18},
+ {BOLERO_CDC_WSA_BOOST1_BOOST_CFG1, 0x3F, 0x12},
+ {BOLERO_CDC_WSA_BOOST1_BOOST_CFG2, 0x1C, 0x08},
+ {BOLERO_CDC_WSA_COMPANDER1_CTL7, 0x1E, 0x18},
+ {BOLERO_CDC_WSA_BOOST0_BOOST_CTL, 0x70, 0x58},
+ {BOLERO_CDC_WSA_BOOST1_BOOST_CTL, 0x70, 0x58},
+ {BOLERO_CDC_WSA_RX0_RX_PATH_CFG1, 0x08, 0x08},
+ {BOLERO_CDC_WSA_RX1_RX_PATH_CFG1, 0x08, 0x08},
+ {BOLERO_CDC_WSA_TOP_TOP_CFG1, 0x02, 0x02},
+ {BOLERO_CDC_WSA_TOP_TOP_CFG1, 0x01, 0x01},
+ {BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+ {BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+ {BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+ {BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+ {BOLERO_CDC_WSA_COMPANDER0_CTL3, 0x80, 0x80},
+ {BOLERO_CDC_WSA_COMPANDER1_CTL3, 0x80, 0x80},
+ {BOLERO_CDC_WSA_COMPANDER0_CTL7, 0x01, 0x01},
+ {BOLERO_CDC_WSA_COMPANDER1_CTL7, 0x01, 0x01},
+ {BOLERO_CDC_WSA_RX0_RX_PATH_CFG0, 0x01, 0x01},
+ {BOLERO_CDC_WSA_RX1_RX_PATH_CFG0, 0x01, 0x01},
+ {BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CFG, 0x01, 0x01},
+ {BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CFG, 0x01, 0x01},
+};
+
+static void wsa_macro_init_bcl_pmic_reg(struct snd_soc_component *component)
+{
+ struct wsa_macro_priv *wsa_priv = NULL;
+
+ if (!component) {
+ pr_err("%s: NULL component pointer!\n", __func__);
+ return;
+ }
+
+ wsa_priv = snd_soc_component_get_drvdata(component);
+
+ switch (wsa_priv->bcl_pmic_params.id) {
+ case 0:
+ /* Enable ID0 to listen to respective PMIC group interrupts */
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CTL1, 0x02, 0x02);
+ /* Update MC_SID0 */
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG1, 0x0F,
+ wsa_priv->bcl_pmic_params.sid);
+ /* Update MC_PPID0 */
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG2, 0xFF,
+ wsa_priv->bcl_pmic_params.ppid);
+ break;
+ case 1:
+ /* Enable ID1 to listen to respective PMIC group interrupts */
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CTL1, 0x01, 0x01);
+ /* Update MC_SID1 */
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG3, 0x0F,
+ wsa_priv->bcl_pmic_params.sid);
+ /* Update MC_PPID1 */
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG4, 0xFF,
+ wsa_priv->bcl_pmic_params.ppid);
+ break;
+ default:
+ dev_err(component->dev, "%s: PMIC ID is invalid %d\n",
+ __func__, wsa_priv->bcl_pmic_params.id);
+ break;
+ }
+}
+
+static void wsa_macro_init_reg(struct snd_soc_component *component)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(wsa_macro_reg_init); i++)
+ snd_soc_component_update_bits(component,
+ wsa_macro_reg_init[i].reg,
+ wsa_macro_reg_init[i].mask,
+ wsa_macro_reg_init[i].val);
+
+ wsa_macro_init_bcl_pmic_reg(component);
+}
+
+static int wsa_swrm_clock(void *handle, bool enable)
+{
+ struct wsa_macro_priv *wsa_priv = (struct wsa_macro_priv *) handle;
+ struct regmap *regmap = wsa_priv->regmap;
+ int ret = 0;
+
+ if (regmap == NULL) {
+ dev_err(wsa_priv->dev, "%s: regmap is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&wsa_priv->swr_clk_lock);
+
+ trace_printk("%s: %s swrm clock %s\n",
+ dev_name(wsa_priv->dev), __func__,
+ (enable ? "enable" : "disable"));
+ dev_dbg(wsa_priv->dev, "%s: swrm clock %s\n",
+ __func__, (enable ? "enable" : "disable"));
+ if (enable) {
+ //pm_runtime_get_sync(wsa_priv->dev);
+ if (wsa_priv->swr_clk_users == 0) {
+ ret = 0;//msm_cdc_pinctrl_select_active_state(
+ // wsa_priv->wsa_swr_gpio_p);
+ if (ret < 0) {
+ dev_err_ratelimited(wsa_priv->dev,
+ "%s: wsa swr pinctrl enable failed\n",
+ __func__);
+ pm_runtime_mark_last_busy(wsa_priv->dev);
+ pm_runtime_put_autosuspend(wsa_priv->dev);
+ goto exit;
+ }
+ ret = wsa_macro_mclk_enable(wsa_priv, 1, true);
+ if (ret < 0) {
+ //msm_cdc_pinctrl_select_sleep_state(
+ // wsa_priv->wsa_swr_gpio_p);
+ dev_err_ratelimited(wsa_priv->dev,
+ "%s: wsa request clock enable failed\n",
+ __func__);
+ pm_runtime_mark_last_busy(wsa_priv->dev);
+ pm_runtime_put_autosuspend(wsa_priv->dev);
+ goto exit;
+ }
+ if (wsa_priv->reset_swr)
+ regmap_update_bits(regmap,
+ BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
+ 0x02, 0x02);
+ regmap_update_bits(regmap,
+ BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
+ 0x01, 0x01);
+ if (wsa_priv->reset_swr)
+ regmap_update_bits(regmap,
+ BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
+ 0x02, 0x00);
+ wsa_priv->reset_swr = false;
+ }
+ wsa_priv->swr_clk_users++;
+ //pm_runtime_mark_last_busy(wsa_priv->dev);
+ //pm_runtime_put_autosuspend(wsa_priv->dev);
+ } else {
+#if 0
+ if (wsa_priv->swr_clk_users <= 0) {
+ dev_err(wsa_priv->dev, "%s: clock already disabled\n",
+ __func__);
+ wsa_priv->swr_clk_users = 0;
+ goto exit;
+ }
+ wsa_priv->swr_clk_users--;
+ if (wsa_priv->swr_clk_users == 0) {
+ regmap_update_bits(regmap,
+ BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
+ 0x01, 0x00);
+ wsa_macro_mclk_enable(wsa_priv, 0, true);
+ ret = 0;//msm_cdc_pinctrl_select_sleep_state(
+ // wsa_priv->wsa_swr_gpio_p);
+ if (ret < 0) {
+ dev_err_ratelimited(wsa_priv->dev,
+ "%s: wsa swr pinctrl disable failed\n",
+ __func__);
+ goto exit;
+ }
+ }
+#endif
+ }
+ trace_printk("%s: %s swrm clock users: %d\n",
+ dev_name(wsa_priv->dev), __func__,
+ wsa_priv->swr_clk_users);
+ dev_dbg(wsa_priv->dev, "%s: swrm clock users %d\n",
+ __func__, wsa_priv->swr_clk_users);
+exit:
+ mutex_unlock(&wsa_priv->swr_clk_lock);
+ return ret;
+}
+
+#if 0
+static void wsa_macro_add_child_devices(struct work_struct *work)
+{
+ struct wsa_macro_priv *wsa_priv;
+ struct platform_device *pdev;
+ struct device_node *node;
+ struct wsa_macro_swr_ctrl_data *swr_ctrl_data = NULL, *temp;
+ int ret;
+ u16 count = 0, ctrl_num = 0;
+ struct wsa_macro_swr_ctrl_platform_data *platdata;
+ char plat_dev_name[WSA_MACRO_SWR_STRING_LEN];
+
+ wsa_priv = container_of(work, struct wsa_macro_priv,
+ wsa_macro_add_child_devices_work);
+ if (!wsa_priv) {
+ pr_err("%s: Memory for wsa_priv does not exist\n",
+ __func__);
+ return;
+ }
+ if (!wsa_priv->dev || !wsa_priv->dev->of_node) {
+ dev_err(wsa_priv->dev,
+ "%s: DT node for wsa_priv does not exist\n", __func__);
+ return;
+ }
+
+ platdata = &wsa_priv->swr_plat_data;
+ wsa_priv->child_count = 0;
+
+ for_each_available_child_of_node(wsa_priv->dev->of_node, node) {
+ if (strnstr(node->name, "wsa_swr_master",
+ strlen("wsa_swr_master")) != NULL)
+ strlcpy(plat_dev_name, "wsa_swr_ctrl",
+ (WSA_MACRO_SWR_STRING_LEN - 1));
+ else if (strnstr(node->name, "msm_cdc_pinctrl",
+ strlen("msm_cdc_pinctrl")) != NULL)
+ strlcpy(plat_dev_name, node->name,
+ (WSA_MACRO_SWR_STRING_LEN - 1));
+ else
+ continue;
+
+ pdev = platform_device_alloc(plat_dev_name, -1);
+ if (!pdev) {
+ dev_err(wsa_priv->dev, "%s: pdev memory alloc failed\n",
+ __func__);
+ ret = -ENOMEM;
+ goto err;
+ }
+ pdev->dev.parent = wsa_priv->dev;
+ pdev->dev.of_node = node;
+
+ if (strnstr(node->name, "wsa_swr_master",
+ strlen("wsa_swr_master")) != NULL) {
+ ret = platform_device_add_data(pdev, platdata,
+ sizeof(*platdata));
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: cannot add plat data ctrl:%d\n",
+ __func__, ctrl_num);
+ goto fail_pdev_add;
+ }
+ }
+
+ ret = platform_device_add(pdev);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: Cannot add platform device\n",
+ __func__);
+ goto fail_pdev_add;
+ }
+
+ if (!strcmp(node->name, "wsa_swr_master")) {
+ temp = krealloc(swr_ctrl_data,
+ (ctrl_num + 1) * sizeof(
+ struct wsa_macro_swr_ctrl_data),
+ GFP_KERNEL);
+ if (!temp) {
+ dev_err(&pdev->dev, "out of memory\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ swr_ctrl_data = temp;
+ swr_ctrl_data[ctrl_num].wsa_swr_pdev = pdev;
+ ctrl_num++;
+ dev_dbg(&pdev->dev,
+ "%s: Added soundwire ctrl device(s)\n",
+ __func__);
+ wsa_priv->swr_ctrl_data = swr_ctrl_data;
+ }
+ if (wsa_priv->child_count < WSA_MACRO_CHILD_DEVICES_MAX)
+ wsa_priv->pdev_child_devices[
+ wsa_priv->child_count++] = pdev;
+ else
+ goto err;
+ }
+
+ return;
+fail_pdev_add:
+ for (count = 0; count < wsa_priv->child_count; count++)
+ platform_device_put(wsa_priv->pdev_child_devices[count]);
+err:
+ return;
+}
+#endif
+
+static int wsa_macro_component_probe(struct snd_soc_component *comp)
+{
+ struct wsa_macro_priv *wsa_priv = snd_soc_component_get_drvdata(comp);
+
+ snd_soc_component_init_regmap(comp, wsa_priv->regmap);
+
+#if 0
+ snd_soc_dapm_ignore_suspend(dapm, "WSA_AIF1 Playback");
+ snd_soc_dapm_ignore_suspend(dapm, "WSA_AIF_MIX1 Playback");
+ snd_soc_dapm_ignore_suspend(dapm, "WSA_AIF_VI Capture");
+ snd_soc_dapm_ignore_suspend(dapm, "WSA_AIF_ECHO Capture");
+ snd_soc_dapm_ignore_suspend(dapm, "WSA_SPK1 OUT");
+ snd_soc_dapm_ignore_suspend(dapm, "WSA_SPK2 OUT");
+ snd_soc_dapm_ignore_suspend(dapm, "VIINPUT_WSA");
+ snd_soc_dapm_ignore_suspend(dapm, "WSA SRC0_INP");
+ snd_soc_dapm_ignore_suspend(dapm, "WSA_TX DEC0_INP");
+ snd_soc_dapm_ignore_suspend(dapm, "WSA_TX DEC1_INP");
+ snd_soc_dapm_sync(dapm);
+#endif
+
+ wsa_priv->spkr_gain_offset = WSA_MACRO_GAIN_OFFSET_0_DB;
+ wsa_macro_init_reg(comp);
+
+ wsa_macro_set_spkr_mode(comp, 0);
+
+ return 0;
+}
+
+static int swclk_gate_enable(struct clk_hw *hw)
+{
+ return wsa_swrm_clock(to_wsa_macro(hw), true);
+}
+
+static void swclk_gate_disable(struct clk_hw *hw)
+{
+ wsa_swrm_clock(to_wsa_macro(hw), false);
+}
+
+static int swclk_gate_is_enabled(struct clk_hw *hw)
+{
+ struct wsa_macro_priv *wsa = to_wsa_macro(hw);
+ int ret, val;
+
+ regmap_read(wsa->regmap, BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, &val);
+ ret = val & BIT(0);
+
+ return ret;
+}
+
+static unsigned long swclk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return parent_rate / 2;
+}
+
+static const struct clk_ops swclk_gate_ops = {
+ .prepare = swclk_gate_enable,
+ .unprepare = swclk_gate_disable,
+ .is_enabled = swclk_gate_is_enabled,
+ .recalc_rate = swclk_recalc_rate,
+
+};
+
+static struct clk *wsa_macro_register_mclk_output(struct wsa_macro_priv *wsa)
+{
+ struct clk *parent = wsa->npl_clk;
+ struct device *dev = wsa->dev;
+ struct device_node *np = dev->of_node;
+ const char *parent_clk_name = NULL;
+ const char *clk_name = "mclk";
+ struct clk_hw *hw;
+ struct clk_init_data init;
+ int rate;
+ int ret;
+
+ if (of_property_read_u32(np, "clock-frequency", &rate))
+ return NULL;
+
+ parent_clk_name = __clk_get_name(parent);
+
+ of_property_read_string(np, "clock-output-names", &clk_name);
+
+ init.name = clk_name;
+ init.ops = &swclk_gate_ops;
+ init.flags = 0;
+ init.parent_names = &parent_clk_name;
+ init.num_parents = 1;
+ wsa->hw.init = &init;
+ hw = &wsa->hw;
+ ret = clk_hw_register(wsa->dev, hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ of_clk_add_provider(np, of_clk_src_simple_get, hw->clk);
+
+ return NULL;
+}
+
+static const struct snd_soc_component_driver wsa_macro_component_drv = {
+ .name = "WSA881x",
+ .probe = wsa_macro_component_probe,
+ .controls = wsa_macro_snd_controls,
+ .num_controls = ARRAY_SIZE(wsa_macro_snd_controls),
+ .dapm_widgets = wsa_macro_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wsa_macro_dapm_widgets),
+ .dapm_routes = wsa_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(wsa_audio_map),
+};
+extern bool q6core_is_adsp_ready(void);
+
+const struct regmap_config bolero_va_regmap_config = {
+ .name = "va_macro",
+ .reg_bits = 16,
+ .val_bits = 32, /* 8 but with 32 bit read/write */
+ .reg_stride = 4,
+// .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_FLAT,
+// .reg_defaults = bolero_defaults,
+// .num_reg_defaults = ARRAY_SIZE(bolero_defaults),
+ .max_register = WSA_MAX_OFFSET,
+// .writeable_reg = bolero_is_writeable_register,
+// .volatile_reg = bolero_is_volatile_register,
+// .readable_reg = bolero_is_readable_register,
+};
+
+static int wsa_macro_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct wsa_macro_priv *wsa_priv;
+ struct resource *res;
+ struct clk *c;
+ int ret;
+
+ if (!q6core_is_adsp_ready())
+ return -EPROBE_DEFER;
+
+ struct pinctrl *pinctrl;
+pr_err("DEBUG: %s: %d \n", __func__, __LINE__);
+
+ pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (IS_ERR(pinctrl))
+ return -EPROBE_DEFER;
+
+
+ pinctrl_select_default_state(dev);
+pr_err("DEBUG: %s: %d \n", __func__, __LINE__);
+ wsa_priv = devm_kzalloc(dev, sizeof(struct wsa_macro_priv),
+ GFP_KERNEL);
+ if (!wsa_priv)
+ return -ENOMEM;
+
+ wsa_priv->hw_vote = devm_clk_get(dev, "macro");
+ if (IS_ERR(wsa_priv->hw_vote))
+ return PTR_ERR(wsa_priv->hw_vote);
+
+ wsa_priv->dcodec_vote = devm_clk_get(dev, "dcodec");
+ if (IS_ERR(wsa_priv->dcodec_vote))
+ return PTR_ERR(wsa_priv->dcodec_vote);
+
+ clk_prepare_enable(wsa_priv->hw_vote);
+ clk_prepare_enable(wsa_priv->dcodec_vote);
+
+ wsa_priv->clk = devm_clk_get(dev, "mclk");
+ if (IS_ERR(wsa_priv->clk))
+ return PTR_ERR(wsa_priv->clk);
+
+ wsa_priv->npl_clk = devm_clk_get(dev, "npl");
+ if (IS_ERR(wsa_priv->npl_clk))
+ return PTR_ERR(wsa_priv->npl_clk);
+
+ clk_set_rate(wsa_priv->clk, 19200000);
+
+ clk_set_rate(wsa_priv->npl_clk, 19200000);
+
+ c = devm_clk_get(dev, "va");
+ if (IS_ERR(c))
+ return PTR_ERR(c);
+ clk_set_rate(c, 19200000);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ wsa_priv->regmap = devm_regmap_init_mmio(dev,
+ devm_ioremap_resource(dev, res),
+ &bolero_regmap_config);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ wsa_priv->va_regmap = devm_regmap_init_mmio(dev,
+ devm_ioremap_resource(dev, res),
+ &bolero_va_regmap_config);
+
+// regmap_update_bits(wsa_priv->va_regmap, 0x0, 0x1, 0x1);
+// regmap_update_bits(wsa_priv->va_regmap, 0x4, 0x1, 0x1);
+// regmap_update_bits(wsa_priv->va_regmap, 0x80, 0x2, 0x2);
+
+ dev_set_drvdata(dev, wsa_priv);
+ mutex_init(&wsa_priv->mclk_lock);
+ mutex_init(&wsa_priv->swr_clk_lock);
+
+ wsa_priv->bcl_pmic_params.id = 0x00;
+ wsa_priv->bcl_pmic_params.sid = 0x04;
+ wsa_priv->bcl_pmic_params.ppid = 0x3E;
+
+ wsa_priv->reset_swr = true;
+ wsa_priv->dev = dev;
+
+ unsigned int val;
+ regmap_read(wsa_priv->regmap,
+ BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, &val);
+ pr_err("DEBUG: %s: %d %x \n", __func__, __LINE__, val);
+ clk_prepare_enable(wsa_priv->clk);
+ clk_prepare_enable(wsa_priv->npl_clk);
+ usleep_range(1000, 1100);
+ usleep_range(1000, 1100);
+ usleep_range(1000, 1100);
+
+ regmap_read(wsa_priv->regmap,
+ BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, &val);
+
+ pr_err("DEBUG: %s: %d %x \n", __func__, __LINE__, val);
+
+ wsa_macro_register_mclk_output(wsa_priv);
+
+ ret = devm_snd_soc_register_component(dev,
+ &wsa_macro_component_drv,
+ wsa_macro_dai,
+ ARRAY_SIZE(wsa_macro_dai));
+ if (ret)
+ return ret;
+
+ regmap_read(wsa_priv->regmap,
+ BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, &val);
+ pr_err("DEBUG: %s: %d %x \n", __func__, __LINE__, val);
+
+ return of_platform_populate(dev->of_node, NULL, NULL, dev);
+}
+
+static int wsa_macro_remove(struct platform_device *pdev)
+{
+ struct wsa_macro_priv *wsa_priv;
+ //u16 count = 0;
+
+ wsa_priv = dev_get_drvdata(&pdev->dev);
+
+ if (!wsa_priv)
+ return -EINVAL;
+
+ //for (count = 0; count < wsa_priv->child_count &&
+ // count < WSA_MACRO_CHILD_DEVICES_MAX; count++)
+ // platform_device_unregister(wsa_priv->pdev_child_devices[count]);
+
+ //pm_runtime_disable(&pdev->dev);
+ //pm_runtime_set_suspended(&pdev->dev);
+ //bolero_unregister_macro(&pdev->dev, WSA_MACRO);
+ mutex_destroy(&wsa_priv->mclk_lock);
+ mutex_destroy(&wsa_priv->swr_clk_lock);
+ return 0;
+}
+
+static const struct of_device_id wsa_macro_dt_match[] = {
+ {.compatible = "qcom,sm8250-lpass-wsa-macro"},
+ {}
+};
+
+#if 0
+static const struct dev_pm_ops bolero_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(
+ pm_runtime_force_suspend,
+ pm_runtime_force_resume
+ )
+ SET_RUNTIME_PM_OPS(
+ bolero_runtime_suspend,
+ bolero_runtime_resume,
+ NULL
+ )
+};
+#endif
+
+static struct platform_driver wsa_macro_driver = {
+ .driver = {
+ .name = "wsa_macro",
+ .owner = THIS_MODULE,
+ //.pm = &bolero_dev_pm_ops,
+ .of_match_table = wsa_macro_dt_match,
+ //.suppress_bind_attrs = true,
+ },
+ .probe = wsa_macro_probe,
+ .remove = wsa_macro_remove,
+};
+
+module_platform_driver(wsa_macro_driver);
+
+MODULE_DESCRIPTION("WSA macro driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/lpass-wsa-macro.h b/sound/soc/codecs/lpass-wsa-macro.h
new file mode 100644
index 000000000000..143433d606cb
--- /dev/null
+++ b/sound/soc/codecs/lpass-wsa-macro.h
@@ -0,0 +1,623 @@
+/*
+ * Selects compander and smart boost settings
+ * for a given speaker mode
+ */
+enum {
+ WSA_MACRO_SPKR_MODE_DEFAULT,
+ WSA_MACRO_SPKR_MODE_1, /* COMP Gain = 12dB, Smartboost Max = 5.5V */
+};
+
+/* Rx path gain offsets */
+enum {
+ WSA_MACRO_GAIN_OFFSET_M1P5_DB,
+ WSA_MACRO_GAIN_OFFSET_0_DB,
+};
+
+/* WSA - macro#2 */
+#define WSA_START_OFFSET 0
+#define BOLERO_CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL \
+ (WSA_START_OFFSET + 0x0000)
+#define BOLERO_CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL \
+ (WSA_START_OFFSET + 0x0004)
+#define BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL (WSA_START_OFFSET + 0x0008)
+#define BOLERO_CDC_WSA_TOP_TOP_CFG0 (WSA_START_OFFSET + 0x0080)
+#define BOLERO_CDC_WSA_TOP_TOP_CFG1 (WSA_START_OFFSET + 0x0084)
+#define BOLERO_CDC_WSA_TOP_FREQ_MCLK (WSA_START_OFFSET + 0x0088)
+#define BOLERO_CDC_WSA_TOP_DEBUG_BUS_SEL (WSA_START_OFFSET + 0x008C)
+#define BOLERO_CDC_WSA_TOP_DEBUG_EN0 (WSA_START_OFFSET + 0x0090)
+#define BOLERO_CDC_WSA_TOP_DEBUG_EN1 (WSA_START_OFFSET + 0x0094)
+#define BOLERO_CDC_WSA_TOP_DEBUG_DSM_LB (WSA_START_OFFSET + 0x0098)
+#define BOLERO_CDC_WSA_TOP_RX_I2S_CTL (WSA_START_OFFSET + 0x009C)
+#define BOLERO_CDC_WSA_TOP_TX_I2S_CTL (WSA_START_OFFSET + 0x00A0)
+#define BOLERO_CDC_WSA_TOP_I2S_CLK (WSA_START_OFFSET + 0x00A4)
+#define BOLERO_CDC_WSA_TOP_I2S_RESET (WSA_START_OFFSET + 0x00A8)
+#define BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0 (WSA_START_OFFSET + 0x0100)
+#define BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG1 (WSA_START_OFFSET + 0x0104)
+#define BOLERO_CDC_WSA_RX_INP_MUX_RX_INT1_CFG0 (WSA_START_OFFSET + 0x0108)
+#define BOLERO_CDC_WSA_RX_INP_MUX_RX_INT1_CFG1 (WSA_START_OFFSET + 0x010C)
+#define BOLERO_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0 (WSA_START_OFFSET + 0x0110)
+#define BOLERO_CDC_WSA_RX_INP_MUX_RX_EC_CFG0 (WSA_START_OFFSET + 0x0114)
+#define BOLERO_CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0 (WSA_START_OFFSET + 0x0118)
+/* VBAT registers */
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_PATH_CTL (WSA_START_OFFSET + 0x0180)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_CFG (WSA_START_OFFSET + 0x0184)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL1 (WSA_START_OFFSET + 0x0188)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL2 (WSA_START_OFFSET + 0x018C)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL3 (WSA_START_OFFSET + 0x0190)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_PK_EST1 (WSA_START_OFFSET + 0x0194)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_PK_EST2 (WSA_START_OFFSET + 0x0198)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_PK_EST3 (WSA_START_OFFSET + 0x019C)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_RF_PROC1 (WSA_START_OFFSET + 0x01A0)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_RF_PROC2 (WSA_START_OFFSET + 0x01A4)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC1 (WSA_START_OFFSET + 0x01A8)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC2 (WSA_START_OFFSET + 0x01AC)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC3 (WSA_START_OFFSET + 0x01B0)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC4 (WSA_START_OFFSET + 0x01B4)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD1 (WSA_START_OFFSET + 0x01B8)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD2 (WSA_START_OFFSET + 0x01BC)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD3 (WSA_START_OFFSET + 0x01C0)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD4 (WSA_START_OFFSET + 0x01C4)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD5 (WSA_START_OFFSET + 0x01C8)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_DEBUG1 (WSA_START_OFFSET + 0x01CC)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD_MON \
+ (WSA_START_OFFSET + 0x01D0)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_MON_VAL \
+ (WSA_START_OFFSET + 0x01D4)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BAN (WSA_START_OFFSET + 0x01D8)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD1 \
+ (WSA_START_OFFSET + 0x01DC)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD2 \
+ (WSA_START_OFFSET + 0x01E0)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD3 \
+ (WSA_START_OFFSET + 0x01E4)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD4 \
+ (WSA_START_OFFSET + 0x01E8)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD5 \
+ (WSA_START_OFFSET + 0x01EC)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD6 \
+ (WSA_START_OFFSET + 0x01F0)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD7 \
+ (WSA_START_OFFSET + 0x01F4)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD8 \
+ (WSA_START_OFFSET + 0x01F8)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD9 \
+ (WSA_START_OFFSET + 0x01FC)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN1 (WSA_START_OFFSET + 0x0200)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN2 (WSA_START_OFFSET + 0x0204)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN3 (WSA_START_OFFSET + 0x0208)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CTL1 \
+ (WSA_START_OFFSET + 0x020C)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CTL2 \
+ (WSA_START_OFFSET + 0x0210)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG1 \
+ (WSA_START_OFFSET + 0x0214)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG2 \
+ (WSA_START_OFFSET + 0x0218)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG3 \
+ (WSA_START_OFFSET + 0x021C)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG4 \
+ (WSA_START_OFFSET + 0x0220)
+#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_ST (WSA_START_OFFSET + 0x0224)
+#define BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CTL (WSA_START_OFFSET + 0x0244)
+#define BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CFG0 (WSA_START_OFFSET + 0x0248)
+#define BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CTL (WSA_START_OFFSET + 0x0264)
+#define BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CFG0 (WSA_START_OFFSET + 0x0268)
+#define BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CTL (WSA_START_OFFSET + 0x0284)
+#define BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CFG0 (WSA_START_OFFSET + 0x0288)
+#define BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CTL (WSA_START_OFFSET + 0x02A4)
+#define BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CFG0 (WSA_START_OFFSET + 0x02A8)
+#define BOLERO_CDC_WSA_INTR_CTRL_CFG (WSA_START_OFFSET + 0x0340)
+#define BOLERO_CDC_WSA_INTR_CTRL_CLR_COMMIT (WSA_START_OFFSET + 0x0344)
+#define BOLERO_CDC_WSA_INTR_CTRL_PIN1_MASK0 (WSA_START_OFFSET + 0x0360)
+#define BOLERO_CDC_WSA_INTR_CTRL_PIN1_STATUS0 (WSA_START_OFFSET + 0x0368)
+#define BOLERO_CDC_WSA_INTR_CTRL_PIN1_CLEAR0 (WSA_START_OFFSET + 0x0370)
+#define BOLERO_CDC_WSA_INTR_CTRL_PIN2_MASK0 (WSA_START_OFFSET + 0x0380)
+#define BOLERO_CDC_WSA_INTR_CTRL_PIN2_STATUS0 (WSA_START_OFFSET + 0x0388)
+#define BOLERO_CDC_WSA_INTR_CTRL_PIN2_CLEAR0 (WSA_START_OFFSET + 0x0390)
+#define BOLERO_CDC_WSA_INTR_CTRL_LEVEL0 (WSA_START_OFFSET + 0x03C0)
+#define BOLERO_CDC_WSA_INTR_CTRL_BYPASS0 (WSA_START_OFFSET + 0x03C8)
+#define BOLERO_CDC_WSA_INTR_CTRL_SET0 (WSA_START_OFFSET + 0x03D0)
+#define BOLERO_CDC_WSA_RX0_RX_PATH_CTL (WSA_START_OFFSET + 0x0400)
+#define BOLERO_CDC_WSA_RX0_RX_PATH_CFG0 (WSA_START_OFFSET + 0x0404)
+#define BOLERO_CDC_WSA_RX0_RX_PATH_CFG1 (WSA_START_OFFSET + 0x0408)
+#define BOLERO_CDC_WSA_RX0_RX_PATH_CFG2 (WSA_START_OFFSET + 0x040C)
+#define BOLERO_CDC_WSA_RX0_RX_PATH_CFG3 (WSA_START_OFFSET + 0x0410)
+#define BOLERO_CDC_WSA_RX0_RX_VOL_CTL (WSA_START_OFFSET + 0x0414)
+#define BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL (WSA_START_OFFSET + 0x0418)
+#define BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CFG (WSA_START_OFFSET + 0x041C)
+#define BOLERO_CDC_WSA_RX0_RX_VOL_MIX_CTL (WSA_START_OFFSET + 0x0420)
+#define BOLERO_CDC_WSA_RX0_RX_PATH_SEC0 (WSA_START_OFFSET + 0x0424)
+#define BOLERO_CDC_WSA_RX0_RX_PATH_SEC1 (WSA_START_OFFSET + 0x0428)
+#define BOLERO_CDC_WSA_RX0_RX_PATH_SEC2 (WSA_START_OFFSET + 0x042C)
+#define BOLERO_CDC_WSA_RX0_RX_PATH_SEC3 (WSA_START_OFFSET + 0x0430)
+#define BOLERO_CDC_WSA_RX0_RX_PATH_SEC5 (WSA_START_OFFSET + 0x0438)
+#define BOLERO_CDC_WSA_RX0_RX_PATH_SEC6 (WSA_START_OFFSET + 0x043C)
+#define BOLERO_CDC_WSA_RX0_RX_PATH_SEC7 (WSA_START_OFFSET + 0x0440)
+#define BOLERO_CDC_WSA_RX0_RX_PATH_MIX_SEC0 (WSA_START_OFFSET + 0x0444)
+#define BOLERO_CDC_WSA_RX0_RX_PATH_MIX_SEC1 (WSA_START_OFFSET + 0x0448)
+#define BOLERO_CDC_WSA_RX0_RX_PATH_DSMDEM_CTL (WSA_START_OFFSET + 0x044C)
+#define BOLERO_CDC_WSA_RX1_RX_PATH_CTL (WSA_START_OFFSET + 0x0480)
+#define BOLERO_CDC_WSA_RX1_RX_PATH_CFG0 (WSA_START_OFFSET + 0x0484)
+#define BOLERO_CDC_WSA_RX1_RX_PATH_CFG1 (WSA_START_OFFSET + 0x0488)
+#define BOLERO_CDC_WSA_RX1_RX_PATH_CFG2 (WSA_START_OFFSET + 0x048C)
+#define BOLERO_CDC_WSA_RX1_RX_PATH_CFG3 (WSA_START_OFFSET + 0x0490)
+#define BOLERO_CDC_WSA_RX1_RX_VOL_CTL (WSA_START_OFFSET + 0x0494)
+#define BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CTL (WSA_START_OFFSET + 0x0498)
+#define BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CFG (WSA_START_OFFSET + 0x049C)
+#define BOLERO_CDC_WSA_RX1_RX_VOL_MIX_CTL (WSA_START_OFFSET + 0x04A0)
+#define BOLERO_CDC_WSA_RX1_RX_PATH_SEC0 (WSA_START_OFFSET + 0x04A4)
+#define BOLERO_CDC_WSA_RX1_RX_PATH_SEC1 (WSA_START_OFFSET + 0x04A8)
+#define BOLERO_CDC_WSA_RX1_RX_PATH_SEC2 (WSA_START_OFFSET + 0x04AC)
+#define BOLERO_CDC_WSA_RX1_RX_PATH_SEC3 (WSA_START_OFFSET + 0x04B0)
+#define BOLERO_CDC_WSA_RX1_RX_PATH_SEC5 (WSA_START_OFFSET + 0x04B8)
+#define BOLERO_CDC_WSA_RX1_RX_PATH_SEC6 (WSA_START_OFFSET + 0x04BC)
+#define BOLERO_CDC_WSA_RX1_RX_PATH_SEC7 (WSA_START_OFFSET + 0x04C0)
+#define BOLERO_CDC_WSA_RX1_RX_PATH_MIX_SEC0 (WSA_START_OFFSET + 0x04C4)
+#define BOLERO_CDC_WSA_RX1_RX_PATH_MIX_SEC1 (WSA_START_OFFSET + 0x04C8)
+#define BOLERO_CDC_WSA_RX1_RX_PATH_DSMDEM_CTL (WSA_START_OFFSET + 0x04CC)
+#define BOLERO_CDC_WSA_BOOST0_BOOST_PATH_CTL (WSA_START_OFFSET + 0x0500)
+#define BOLERO_CDC_WSA_BOOST0_BOOST_CTL (WSA_START_OFFSET + 0x0504)
+#define BOLERO_CDC_WSA_BOOST0_BOOST_CFG1 (WSA_START_OFFSET + 0x0508)
+#define BOLERO_CDC_WSA_BOOST0_BOOST_CFG2 (WSA_START_OFFSET + 0x050C)
+#define BOLERO_CDC_WSA_BOOST1_BOOST_PATH_CTL (WSA_START_OFFSET + 0x0540)
+#define BOLERO_CDC_WSA_BOOST1_BOOST_CTL (WSA_START_OFFSET + 0x0544)
+#define BOLERO_CDC_WSA_BOOST1_BOOST_CFG1 (WSA_START_OFFSET + 0x0548)
+#define BOLERO_CDC_WSA_BOOST1_BOOST_CFG2 (WSA_START_OFFSET + 0x054C)
+#define BOLERO_CDC_WSA_COMPANDER0_CTL0 (WSA_START_OFFSET + 0x0580)
+#define BOLERO_CDC_WSA_COMPANDER0_CTL1 (WSA_START_OFFSET + 0x0584)
+#define BOLERO_CDC_WSA_COMPANDER0_CTL2 (WSA_START_OFFSET + 0x0588)
+#define BOLERO_CDC_WSA_COMPANDER0_CTL3 (WSA_START_OFFSET + 0x058C)
+#define BOLERO_CDC_WSA_COMPANDER0_CTL4 (WSA_START_OFFSET + 0x0590)
+#define BOLERO_CDC_WSA_COMPANDER0_CTL5 (WSA_START_OFFSET + 0x0594)
+#define BOLERO_CDC_WSA_COMPANDER0_CTL6 (WSA_START_OFFSET + 0x0598)
+#define BOLERO_CDC_WSA_COMPANDER0_CTL7 (WSA_START_OFFSET + 0x059C)
+#define BOLERO_CDC_WSA_COMPANDER1_CTL0 (WSA_START_OFFSET + 0x05C0)
+#define BOLERO_CDC_WSA_COMPANDER1_CTL1 (WSA_START_OFFSET + 0x05C4)
+#define BOLERO_CDC_WSA_COMPANDER1_CTL2 (WSA_START_OFFSET + 0x05C8)
+#define BOLERO_CDC_WSA_COMPANDER1_CTL3 (WSA_START_OFFSET + 0x05CC)
+#define BOLERO_CDC_WSA_COMPANDER1_CTL4 (WSA_START_OFFSET + 0x05D0)
+#define BOLERO_CDC_WSA_COMPANDER1_CTL5 (WSA_START_OFFSET + 0x05D4)
+#define BOLERO_CDC_WSA_COMPANDER1_CTL6 (WSA_START_OFFSET + 0x05D8)
+#define BOLERO_CDC_WSA_COMPANDER1_CTL7 (WSA_START_OFFSET + 0x05DC)
+#define BOLERO_CDC_WSA_SOFTCLIP0_CRC (WSA_START_OFFSET + 0x0600)
+#define BOLERO_CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL (WSA_START_OFFSET + 0x0604)
+#define BOLERO_CDC_WSA_SOFTCLIP1_CRC (WSA_START_OFFSET + 0x0640)
+#define BOLERO_CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL (WSA_START_OFFSET + 0x0644)
+#define BOLERO_CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL \
+ (WSA_START_OFFSET + 0x0680)
+#define BOLERO_CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0 (WSA_START_OFFSET + 0x0684)
+#define BOLERO_CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL \
+ (WSA_START_OFFSET + 0x06C0)
+#define BOLERO_CDC_WSA_EC_HQ1_EC_REF_HQ_CFG0 (WSA_START_OFFSET + 0x06C4)
+#define BOLERO_CDC_WSA_SPLINE_ASRC0_CLK_RST_CTL (WSA_START_OFFSET + 0x0700)
+#define BOLERO_CDC_WSA_SPLINE_ASRC0_CTL0 (WSA_START_OFFSET + 0x0704)
+#define BOLERO_CDC_WSA_SPLINE_ASRC0_CTL1 (WSA_START_OFFSET + 0x0708)
+#define BOLERO_CDC_WSA_SPLINE_ASRC0_FIFO_CTL (WSA_START_OFFSET + 0x070C)
+#define BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB \
+ (WSA_START_OFFSET + 0x0710)
+#define BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB \
+ (WSA_START_OFFSET + 0x0714)
+#define BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB \
+ (WSA_START_OFFSET + 0x0718)
+#define BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_MSB \
+ (WSA_START_OFFSET + 0x071C)
+#define BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FIFO (WSA_START_OFFSET + 0x0720)
+#define BOLERO_CDC_WSA_SPLINE_ASRC1_CLK_RST_CTL (WSA_START_OFFSET + 0x0740)
+#define BOLERO_CDC_WSA_SPLINE_ASRC1_CTL0 (WSA_START_OFFSET + 0x0744)
+#define BOLERO_CDC_WSA_SPLINE_ASRC1_CTL1 (WSA_START_OFFSET + 0x0748)
+#define BOLERO_CDC_WSA_SPLINE_ASRC1_FIFO_CTL (WSA_START_OFFSET + 0x074C)
+#define BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_LSB \
+ (WSA_START_OFFSET + 0x0750)
+#define BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_MSB \
+ (WSA_START_OFFSET + 0x0754)
+#define BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_LSB \
+ (WSA_START_OFFSET + 0x0758)
+#define BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_MSB \
+ (WSA_START_OFFSET + 0x075C)
+#define BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FIFO (WSA_START_OFFSET + 0x0760)
+#define WSA_MAX_OFFSET (WSA_START_OFFSET + 0x0760)
+
+#define BOLERO_CDC_WSA_MACRO_MAX 0x1D9 /* 0x760/4 = 0x1D8 + 1 registers */
+
+static const struct reg_default bolero_defaults[] = {
+ /* WSA Macro */
+ { BOLERO_CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL, 0x00},
+ { BOLERO_CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00},
+ { BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, 0x00},
+ { BOLERO_CDC_WSA_TOP_TOP_CFG0, 0x00},
+ { BOLERO_CDC_WSA_TOP_TOP_CFG1, 0x00},
+ { BOLERO_CDC_WSA_TOP_FREQ_MCLK, 0x00},
+ { BOLERO_CDC_WSA_TOP_DEBUG_BUS_SEL, 0x00},
+ { BOLERO_CDC_WSA_TOP_DEBUG_EN0, 0x00},
+ { BOLERO_CDC_WSA_TOP_DEBUG_EN1, 0x00},
+ { BOLERO_CDC_WSA_TOP_DEBUG_DSM_LB, 0x88},
+ { BOLERO_CDC_WSA_TOP_RX_I2S_CTL, 0x0C},
+ { BOLERO_CDC_WSA_TOP_TX_I2S_CTL, 0x0C},
+ { BOLERO_CDC_WSA_TOP_I2S_CLK, 0x02},
+ { BOLERO_CDC_WSA_TOP_I2S_RESET, 0x00},
+ { BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0, 0x00},
+ { BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG1, 0x00},
+ { BOLERO_CDC_WSA_RX_INP_MUX_RX_INT1_CFG0, 0x00},
+ { BOLERO_CDC_WSA_RX_INP_MUX_RX_INT1_CFG1, 0x00},
+ { BOLERO_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0, 0x00},
+ { BOLERO_CDC_WSA_RX_INP_MUX_RX_EC_CFG0, 0x00},
+ { BOLERO_CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0, 0x00},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_PATH_CTL, 0x00},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_CFG, 0x10},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL1, 0x00},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL2, 0x00},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL3, 0x04},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_PK_EST1, 0xE0},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_PK_EST2, 0x01},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_PK_EST3, 0x40},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_RF_PROC1, 0x2A},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_RF_PROC2, 0x00},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC1, 0x00},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC2, 0x18},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC3, 0x18},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC4, 0x03},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD1, 0x01},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD2, 0x00},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD3, 0x00},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD4, 0x64},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD5, 0x01},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_DEBUG1, 0x00},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD_MON, 0x00},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_MON_VAL, 0x00},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BAN, 0x0C},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD1, 0x00},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD2, 0x77},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD3, 0x01},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD4, 0x00},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD5, 0x4B},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD6, 0x00},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD7, 0x01},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD8, 0x00},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD9, 0x00},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN1, 0x04},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN2, 0x08},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN3, 0x0C},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CTL1, 0xE0},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CTL2, 0x00},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG1, 0x00},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG2, 0x00},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG3, 0x00},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG4, 0x00},
+ { BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_ST, 0x00},
+ { BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CTL, 0x02},
+ { BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CFG0, 0x00},
+ { BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CTL, 0x02},
+ { BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CFG0, 0x00},
+ { BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CTL, 0x02},
+ { BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CFG0, 0x00},
+ { BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CTL, 0x02},
+ { BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CFG0, 0x00},
+ { BOLERO_CDC_WSA_INTR_CTRL_CFG, 0x00},
+ { BOLERO_CDC_WSA_INTR_CTRL_CLR_COMMIT, 0x00},
+ { BOLERO_CDC_WSA_INTR_CTRL_PIN1_MASK0, 0xFF},
+ { BOLERO_CDC_WSA_INTR_CTRL_PIN1_STATUS0, 0x00},
+ { BOLERO_CDC_WSA_INTR_CTRL_PIN1_CLEAR0, 0x00},
+ { BOLERO_CDC_WSA_INTR_CTRL_PIN2_MASK0, 0xFF},
+ { BOLERO_CDC_WSA_INTR_CTRL_PIN2_STATUS0, 0x00},
+ { BOLERO_CDC_WSA_INTR_CTRL_PIN2_CLEAR0, 0x00},
+ { BOLERO_CDC_WSA_INTR_CTRL_LEVEL0, 0x00},
+ { BOLERO_CDC_WSA_INTR_CTRL_BYPASS0, 0x00},
+ { BOLERO_CDC_WSA_INTR_CTRL_SET0, 0x00},
+ { BOLERO_CDC_WSA_RX0_RX_PATH_CTL, 0x04},
+ { BOLERO_CDC_WSA_RX0_RX_PATH_CFG0, 0x00},
+ { BOLERO_CDC_WSA_RX0_RX_PATH_CFG1, 0x64},
+ { BOLERO_CDC_WSA_RX0_RX_PATH_CFG2, 0x8F},
+ { BOLERO_CDC_WSA_RX0_RX_PATH_CFG3, 0x00},
+ { BOLERO_CDC_WSA_RX0_RX_VOL_CTL, 0x00},
+ { BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL, 0x04},
+ { BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CFG, 0x7E},
+ { BOLERO_CDC_WSA_RX0_RX_VOL_MIX_CTL, 0x00},
+ { BOLERO_CDC_WSA_RX0_RX_PATH_SEC0, 0x04},
+ { BOLERO_CDC_WSA_RX0_RX_PATH_SEC1, 0x08},
+ { BOLERO_CDC_WSA_RX0_RX_PATH_SEC2, 0x00},
+ { BOLERO_CDC_WSA_RX0_RX_PATH_SEC3, 0x00},
+ { BOLERO_CDC_WSA_RX0_RX_PATH_SEC5, 0x00},
+ { BOLERO_CDC_WSA_RX0_RX_PATH_SEC6, 0x00},
+ { BOLERO_CDC_WSA_RX0_RX_PATH_SEC7, 0x00},
+ { BOLERO_CDC_WSA_RX0_RX_PATH_MIX_SEC0, 0x08},
+ { BOLERO_CDC_WSA_RX0_RX_PATH_MIX_SEC1, 0x00},
+ { BOLERO_CDC_WSA_RX0_RX_PATH_DSMDEM_CTL, 0x00},
+ { BOLERO_CDC_WSA_RX1_RX_PATH_CFG0, 0x00},
+ { BOLERO_CDC_WSA_RX1_RX_PATH_CFG1, 0x64},
+ { BOLERO_CDC_WSA_RX1_RX_PATH_CFG2, 0x8F},
+ { BOLERO_CDC_WSA_RX1_RX_PATH_CFG3, 0x00},
+ { BOLERO_CDC_WSA_RX1_RX_VOL_CTL, 0x00},
+ { BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CTL, 0x04},
+ { BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CFG, 0x7E},
+ { BOLERO_CDC_WSA_RX1_RX_VOL_MIX_CTL, 0x00},
+ { BOLERO_CDC_WSA_RX1_RX_PATH_SEC0, 0x04},
+ { BOLERO_CDC_WSA_RX1_RX_PATH_SEC1, 0x08},
+ { BOLERO_CDC_WSA_RX1_RX_PATH_SEC2, 0x00},
+ { BOLERO_CDC_WSA_RX1_RX_PATH_SEC3, 0x00},
+ { BOLERO_CDC_WSA_RX1_RX_PATH_SEC5, 0x00},
+ { BOLERO_CDC_WSA_RX1_RX_PATH_SEC6, 0x00},
+ { BOLERO_CDC_WSA_RX1_RX_PATH_SEC7, 0x00},
+ { BOLERO_CDC_WSA_RX1_RX_PATH_MIX_SEC0, 0x08},
+ { BOLERO_CDC_WSA_RX1_RX_PATH_MIX_SEC1, 0x00},
+ { BOLERO_CDC_WSA_RX1_RX_PATH_DSMDEM_CTL, 0x00},
+ { BOLERO_CDC_WSA_BOOST0_BOOST_PATH_CTL, 0x00},
+ { BOLERO_CDC_WSA_BOOST0_BOOST_CTL, 0xD0},
+ { BOLERO_CDC_WSA_BOOST0_BOOST_CFG1, 0x89},
+ { BOLERO_CDC_WSA_BOOST0_BOOST_CFG2, 0x04},
+ { BOLERO_CDC_WSA_BOOST1_BOOST_PATH_CTL, 0x00},
+ { BOLERO_CDC_WSA_BOOST1_BOOST_CTL, 0xD0},
+ { BOLERO_CDC_WSA_BOOST1_BOOST_CFG1, 0x89},
+ { BOLERO_CDC_WSA_BOOST1_BOOST_CFG2, 0x04},
+ { BOLERO_CDC_WSA_COMPANDER0_CTL0, 0x60},
+ { BOLERO_CDC_WSA_COMPANDER0_CTL1, 0xDB},
+ { BOLERO_CDC_WSA_COMPANDER0_CTL2, 0xFF},
+ { BOLERO_CDC_WSA_COMPANDER0_CTL3, 0x35},
+ { BOLERO_CDC_WSA_COMPANDER0_CTL4, 0xFF},
+ { BOLERO_CDC_WSA_COMPANDER0_CTL5, 0x00},
+ { BOLERO_CDC_WSA_COMPANDER0_CTL6, 0x01},
+ { BOLERO_CDC_WSA_COMPANDER0_CTL7, 0x28},
+ { BOLERO_CDC_WSA_COMPANDER1_CTL0, 0x60},
+ { BOLERO_CDC_WSA_COMPANDER1_CTL1, 0xDB},
+ { BOLERO_CDC_WSA_COMPANDER1_CTL2, 0xFF},
+ { BOLERO_CDC_WSA_COMPANDER1_CTL3, 0x35},
+ { BOLERO_CDC_WSA_COMPANDER1_CTL4, 0xFF},
+ { BOLERO_CDC_WSA_COMPANDER1_CTL5, 0x00},
+ { BOLERO_CDC_WSA_COMPANDER1_CTL6, 0x01},
+ { BOLERO_CDC_WSA_COMPANDER1_CTL7, 0x28},
+ { BOLERO_CDC_WSA_SOFTCLIP0_CRC, 0x00},
+ { BOLERO_CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL, 0x38},
+ { BOLERO_CDC_WSA_SOFTCLIP1_CRC, 0x00},
+ { BOLERO_CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL, 0x38},
+ { BOLERO_CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL, 0x00},
+ { BOLERO_CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0, 0x01},
+ { BOLERO_CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL, 0x00},
+ { BOLERO_CDC_WSA_EC_HQ1_EC_REF_HQ_CFG0, 0x01},
+ { BOLERO_CDC_WSA_SPLINE_ASRC0_CLK_RST_CTL, 0x00},
+ { BOLERO_CDC_WSA_SPLINE_ASRC0_CTL0, 0x00},
+ { BOLERO_CDC_WSA_SPLINE_ASRC0_CTL1, 0x00},
+ { BOLERO_CDC_WSA_SPLINE_ASRC0_FIFO_CTL, 0xA8},
+ { BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB, 0x00},
+ { BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB, 0x00},
+ { BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB, 0x00},
+ { BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_MSB, 0x00},
+ { BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FIFO, 0x00},
+ { BOLERO_CDC_WSA_SPLINE_ASRC1_CLK_RST_CTL, 0x00},
+ { BOLERO_CDC_WSA_SPLINE_ASRC1_CTL0, 0x00},
+ { BOLERO_CDC_WSA_SPLINE_ASRC1_CTL1, 0x00},
+ { BOLERO_CDC_WSA_SPLINE_ASRC1_FIFO_CTL, 0xA8},
+ { BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_LSB, 0x00},
+ { BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_MSB, 0x00},
+ { BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_LSB, 0x00},
+ { BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_MSB, 0x00},
+ { BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FIFO, 0x00},
+};
+
+#define BOLERO_REG(x) ((x) / 4)
+#define RD_REG 1
+#define WR_REG 2
+#define RD_WR_REG (RD_REG | WR_REG)
+
+u8 bolero_wsa_reg_access[BOLERO_CDC_WSA_MACRO_MAX] = {
+ [BOLERO_REG(BOLERO_CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_TOP_TOP_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_TOP_TOP_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_TOP_FREQ_MCLK)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_TOP_DEBUG_BUS_SEL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_TOP_DEBUG_EN0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_TOP_DEBUG_EN1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_TOP_DEBUG_DSM_LB)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_TOP_RX_I2S_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_TOP_TX_I2S_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_TOP_I2S_CLK)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_TOP_I2S_RESET)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT1_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT1_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX_INP_MUX_RX_EC_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_PATH_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_CFG)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_PK_EST1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_PK_EST2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_PK_EST3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_RF_PROC1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_RF_PROC2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC4)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD4)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD5)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_DEBUG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD_MON)] = WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_MON_VAL)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BAN)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD4)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD5)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD6)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD7)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD8)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD9)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CTL1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CTL2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG4)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_ST)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_INTR_CTRL_CFG)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_INTR_CTRL_CLR_COMMIT)] = WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_INTR_CTRL_PIN1_MASK0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_INTR_CTRL_PIN1_STATUS0)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_INTR_CTRL_PIN1_CLEAR0)] = WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_INTR_CTRL_PIN2_MASK0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_INTR_CTRL_PIN2_STATUS0)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_INTR_CTRL_PIN2_CLEAR0)] = WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_INTR_CTRL_LEVEL0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_INTR_CTRL_BYPASS0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_INTR_CTRL_SET0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_CFG2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_CFG3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_VOL_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CFG)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_VOL_MIX_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_SEC0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_SEC1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_SEC2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_SEC3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_SEC5)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_SEC6)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_SEC7)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_MIX_SEC0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_MIX_SEC1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_DSMDEM_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_CFG2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_CFG3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_VOL_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CFG)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_VOL_MIX_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_SEC0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_SEC1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_SEC2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_SEC3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_SEC5)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_SEC6)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_SEC7)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_MIX_SEC0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_MIX_SEC1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_DSMDEM_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_BOOST0_BOOST_PATH_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_BOOST0_BOOST_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_BOOST0_BOOST_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_BOOST0_BOOST_CFG2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_BOOST1_BOOST_PATH_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_BOOST1_BOOST_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_BOOST1_BOOST_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_BOOST1_BOOST_CFG2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER0_CTL0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER0_CTL1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER0_CTL2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER0_CTL3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER0_CTL4)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER0_CTL5)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER0_CTL6)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER0_CTL7)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER1_CTL0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER1_CTL1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER1_CTL2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER1_CTL3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER1_CTL4)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER1_CTL5)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER1_CTL6)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER1_CTL7)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_SOFTCLIP0_CRC)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_SOFTCLIP1_CRC)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_EC_HQ1_EC_REF_HQ_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC0_CLK_RST_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC0_CTL0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC0_CTL1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC0_FIFO_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_MSB)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FIFO)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC1_CLK_RST_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC1_CTL0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC1_CTL1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC1_FIFO_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_LSB)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_MSB)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_LSB)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_MSB)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FIFO)] = RD_REG,
+};
+
+static bool bolero_is_readable_register(struct device *dev,
+ unsigned int reg)
+{
+ return bolero_wsa_reg_access[BOLERO_REG(reg)] & RD_REG;
+}
+
+static bool bolero_is_writeable_register(struct device *dev,
+ unsigned int reg)
+{
+ return bolero_wsa_reg_access[BOLERO_REG(reg)] & WR_REG;
+}
+
+static bool bolero_is_volatile_register(struct device *dev,
+ unsigned int reg)
+{
+ /* Update volatile list for rx/tx macros */
+ switch (reg) {
+ case BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_MON_VAL:
+ case BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_ST:
+ case BOLERO_CDC_WSA_INTR_CTRL_PIN1_STATUS0:
+ case BOLERO_CDC_WSA_INTR_CTRL_PIN2_STATUS0:
+ case BOLERO_CDC_WSA_COMPANDER0_CTL6:
+ case BOLERO_CDC_WSA_COMPANDER1_CTL6:
+ case BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB:
+ case BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB:
+ case BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB:
+ case BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_MSB:
+ case BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FIFO:
+ case BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_LSB:
+ case BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_MSB:
+ case BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_LSB:
+ case BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_MSB:
+ case BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FIFO:
+ return true;
+ }
+ return false;
+}
+
+const struct regmap_config bolero_regmap_config = {
+ .name = "wsa_macro",
+ .reg_bits = 16,
+ .val_bits = 32, /* 8 but with 32 bit read/write */
+ .reg_stride = 4,
+ .cache_type = REGCACHE_FLAT,
+ .reg_defaults = bolero_defaults,
+ .num_reg_defaults = ARRAY_SIZE(bolero_defaults),
+ .max_register = WSA_MAX_OFFSET,
+ .writeable_reg = bolero_is_writeable_register,
+ .volatile_reg = bolero_is_volatile_register,
+ .readable_reg = bolero_is_readable_register,
+};
diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 5d6b2466a2f2..fbd118e86631 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -1,11 +1,13 @@
# SPDX-License-Identifier: GPL-2.0-only
-config SND_SOC_QCOM
+menuconfig SND_SOC_QCOM
tristate "ASoC support for QCOM platforms"
depends on ARCH_QCOM || COMPILE_TEST
help
Say Y or M if you want to add support to use audio devices
in Qualcomm Technologies SOC-based platforms.
+if SND_SOC_QCOM
+
config SND_SOC_LPASS_CPU
tristate
select REGMAP_MMIO
@@ -26,7 +28,6 @@ config SND_SOC_LPASS_APQ8016
config SND_SOC_STORM
tristate "ASoC I2S support for Storm boards"
- depends on SND_SOC_QCOM
select SND_SOC_LPASS_IPQ806X
select SND_SOC_MAX98357A
help
@@ -35,7 +36,6 @@ config SND_SOC_STORM
config SND_SOC_APQ8016_SBC
tristate "SoC Audio support for APQ8016 SBC platforms"
- depends on SND_SOC_QCOM
select SND_SOC_LPASS_APQ8016
select SND_SOC_QCOM_COMMON
help
@@ -58,6 +58,9 @@ config SND_SOC_QDSP6_AFE
config SND_SOC_QDSP6_AFE_DAI
tristate
+config SND_SOC_QDSP6_AFE_CLOCKS
+ tristate
+
config SND_SOC_QDSP6_ADM
tristate
@@ -78,6 +81,7 @@ config SND_SOC_QDSP6
select SND_SOC_QDSP6_CORE
select SND_SOC_QDSP6_AFE
select SND_SOC_QDSP6_AFE_DAI
+ select SND_SOC_QDSP6_AFE_CLOCKS
select SND_SOC_QDSP6_ADM
select SND_SOC_QDSP6_ROUTING
select SND_SOC_QDSP6_ASM
@@ -110,3 +114,15 @@ config SND_SOC_SDM845
To add support for audio on Qualcomm Technologies Inc.
SDM845 SoC-based systems.
Say Y if you want to use audio device on this SoCs.
+
+config SND_SOC_SM8250
+ tristate "SoC Machine driver for SM8250 boards"
+ depends on QCOM_APR
+ select SND_SOC_QDSP6
+ select SND_SOC_QCOM_COMMON
+ help
+ To add support for audio on Qualcomm Technologies Inc.
+ SM8250 SoC-based systems.
+ Say Y if you want to use audio device on this SoCs.
+
+endif #SND_SOC_QCOM
diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
index 41b2c7a23a4d..8236eed36c22 100644
--- a/sound/soc/qcom/Makefile
+++ b/sound/soc/qcom/Makefile
@@ -15,12 +15,14 @@ snd-soc-storm-objs := storm.o
snd-soc-apq8016-sbc-objs := apq8016_sbc.o
snd-soc-apq8096-objs := apq8096.o
snd-soc-sdm845-objs := sdm845.o
+snd-soc-sm8250-objs := sm8250.o
snd-soc-qcom-common-objs := common.o
obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o
obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o
obj-$(CONFIG_SND_SOC_MSM8996) += snd-soc-apq8096.o
obj-$(CONFIG_SND_SOC_SDM845) += snd-soc-sdm845.o
+obj-$(CONFIG_SND_SOC_SM8250) += snd-soc-sm8250.o
obj-$(CONFIG_SND_SOC_QCOM_COMMON) += snd-soc-qcom-common.o
#DSP lib
diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c
index 253549600c5a..1a55251d90e7 100644
--- a/sound/soc/qcom/apq8096.c
+++ b/sound/soc/qcom/apq8096.c
@@ -5,14 +5,21 @@
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <sound/soc.h>
+#include <sound/jack.h>
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
+#include <uapi/linux/input-event-codes.h>
#include "common.h"
#define SLIM_MAX_TX_PORTS 16
#define SLIM_MAX_RX_PORTS 16
#define WCD9335_DEFAULT_MCLK_RATE 9600000
+struct apq8096_card_data {
+ struct snd_soc_jack jack;
+ bool jack_setup;
+};
+
static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -67,6 +74,7 @@ static struct snd_soc_ops apq8096_ops = {
static int apq8096_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct apq8096_card_data *data = snd_soc_card_get_drvdata(rtd->card);
/*
* Codec SLIMBUS configuration
@@ -79,6 +87,8 @@ static int apq8096_init(struct snd_soc_pcm_runtime *rtd)
unsigned int tx_ch[SLIM_MAX_TX_PORTS] = {128, 129, 130, 131, 132, 133,
134, 135, 136, 137, 138, 139,
140, 141, 142, 143};
+ struct snd_soc_card *card = rtd->card;
+ int rval;
snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
@@ -86,6 +96,38 @@ static int apq8096_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dai_set_sysclk(codec_dai, 0, WCD9335_DEFAULT_MCLK_RATE,
SNDRV_PCM_STREAM_PLAYBACK);
+ if (!data->jack_setup) {
+ struct snd_jack *jack;
+
+ rval = snd_soc_card_jack_new(card, "Headset Jack",
+ SND_JACK_HEADSET |
+ SND_JACK_HEADPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+ SND_JACK_BTN_4,
+ &data->jack, NULL, 0);
+
+ if (rval < 0) {
+ dev_err(card->dev, "Unable to add Headphone Jack\n");
+ return rval;
+ }
+
+ jack = data->jack.jack;
+
+ snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+ data->jack_setup = true;
+ }
+
+ rval = snd_soc_component_set_jack(codec_dai->component,
+ &data->jack, NULL);
+ if (rval != 0 && rval != -ENOTSUPP) {
+ dev_warn(card->dev, "Failed to set jack: %d\n", rval);
+ return rval;
+ }
+
return 0;
}
@@ -105,6 +147,7 @@ static void apq8096_add_be_ops(struct snd_soc_card *card)
static int apq8096_platform_probe(struct platform_device *pdev)
{
+ struct apq8096_card_data *data;
struct snd_soc_card *card;
struct device *dev = &pdev->dev;
int ret;
@@ -113,8 +156,13 @@ static int apq8096_platform_probe(struct platform_device *pdev)
if (!card)
return -ENOMEM;
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
card->dev = dev;
dev_set_drvdata(dev, card);
+ snd_soc_card_set_drvdata(card, data);
ret = qcom_snd_parse_of(card);
if (ret)
return ret;
diff --git a/sound/soc/qcom/qdsp6/Makefile b/sound/soc/qcom/qdsp6/Makefile
index 7e91e96f7ad5..3c1dd9f32f1d 100644
--- a/sound/soc/qcom/qdsp6/Makefile
+++ b/sound/soc/qcom/qdsp6/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_SND_SOC_QDSP6_COMMON) += q6dsp-common.o
obj-$(CONFIG_SND_SOC_QDSP6_CORE) += q6core.o
obj-$(CONFIG_SND_SOC_QDSP6_AFE) += q6afe.o
obj-$(CONFIG_SND_SOC_QDSP6_AFE_DAI) += q6afe-dai.o
+obj-$(CONFIG_SND_SOC_QDSP6_AFE_CLOCKS) += q6afe-clocks.o
obj-$(CONFIG_SND_SOC_QDSP6_ADM) += q6adm.o
obj-$(CONFIG_SND_SOC_QDSP6_ROUTING) += q6routing.o
obj-$(CONFIG_SND_SOC_QDSP6_ASM) += q6asm.o
diff --git a/sound/soc/qcom/qdsp6/q6afe-clocks.c b/sound/soc/qcom/qdsp6/q6afe-clocks.c
new file mode 100644
index 000000000000..8e0ba2c2170e
--- /dev/null
+++ b/sound/soc/qcom/qdsp6/q6afe-clocks.c
@@ -0,0 +1,295 @@
+// SPDX-License-Identifier: GPL-1.0
+// Copyright (c) 2020, Linaro Limited
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include "q6afe.h"
+
+#define Q6AFE_CORE_CLK(id) &(struct q6afe_clk) { \
+ .clk_id = id, \
+ .afe_clk_id = Q6AFE_##id, \
+ .name = #id, \
+ .rate = 19200000, \
+ .hw.init = &(struct clk_init_data) { \
+ .ops = &clk_q6afe_ops, \
+ .name = #id, \
+ }, \
+ }
+
+#define Q6AFE_NPL_CLK(cid, id) &(struct q6afe_clk) { \
+ .clk_id = id, \
+ .afe_clk_id = Q6AFE_##id, \
+ .name = #id, \
+ .rate = 19200000, \
+ .hw.init = &(struct clk_init_data) { \
+ .ops = &clk_q6afe_ops, \
+ .name = #id, \
+ }, \
+ }
+
+#define Q6AFE_CLK(id) &(struct q6afe_clk) { \
+ .clk_id = id, \
+ .afe_clk_id = Q6AFE_##id, \
+ .name = #id, \
+ .hw.init = &(struct clk_init_data) { \
+ .ops = &clk_q6afe_ops, \
+ .name = #id, \
+ }, \
+ }
+
+#define Q6AFE_VOTE_CLK(id, blkid, n) &(struct q6afe_clk) { \
+ .clk_id = id, \
+ .afe_clk_id = blkid, \
+ .name = #n, \
+ .hw.init = &(struct clk_init_data) { \
+ .ops = &clk_vote_q6afe_ops, \
+ .name = #id, \
+ }, \
+ }
+
+struct q6afe_clk {
+ struct device *dev;
+ int clk_id;
+ int afe_clk_id;
+ char *name;
+ int attributes;
+ int rate;
+ uint32_t handle;
+ struct clk_hw hw;
+};
+
+#define to_q6afe_clk(_hw) container_of(_hw, struct q6afe_clk, hw)
+
+struct q6afe_cc {
+ struct device *dev;
+ struct q6afe_clk **clks;
+ int num_clks;
+};
+
+static int clk_q6afe_prepare(struct clk_hw *hw)
+{
+ struct q6afe_clk *clk = to_q6afe_clk(hw);
+
+ return q6afe_set_lpass_clock(clk->dev, clk->afe_clk_id,
+ LPASS_CLK_ATTRIBUTE_COUPLE_NO/*clk->attributes*/,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT, clk->rate);
+}
+
+static void clk_q6afe_unprepare(struct clk_hw *hw)
+{
+ struct q6afe_clk *clk = to_q6afe_clk(hw);
+
+ q6afe_set_lpass_clock(clk->dev, clk->afe_clk_id,
+ LPASS_CLK_ATTRIBUTE_COUPLE_NO/*clk->attributes*/,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT, 0);
+}
+
+static int clk_q6afe_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct q6afe_clk *clk = to_q6afe_clk(hw);
+
+ clk->rate = rate;
+
+ return 0;
+}
+
+static unsigned long clk_q6afe_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct q6afe_clk *clk = to_q6afe_clk(hw);
+
+ return clk->rate;
+}
+
+static long clk_q6afe_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ return rate;
+}
+
+static const struct clk_ops clk_q6afe_ops = {
+ .prepare = clk_q6afe_prepare,
+ .unprepare = clk_q6afe_unprepare,
+ .set_rate = clk_q6afe_set_rate,
+ .round_rate = clk_q6afe_round_rate,
+ .recalc_rate = clk_q6afe_recalc_rate,
+};
+
+static int clk_vote_q6afe_block(struct clk_hw *hw)
+{
+ struct q6afe_clk *clk = to_q6afe_clk(hw);
+
+ return q6afe_vote_lpass_core_hw(clk->dev, clk->afe_clk_id,
+ clk->name, &clk->handle);
+}
+
+static void clk_unvote_q6afe_block(struct clk_hw *hw)
+{
+ struct q6afe_clk *clk = to_q6afe_clk(hw);
+
+ q6afe_unvote_lpass_core_hw(clk->dev, clk->afe_clk_id, clk->handle);
+}
+
+static const struct clk_ops clk_vote_q6afe_ops = {
+ .prepare = clk_vote_q6afe_block,
+ .unprepare = clk_unvote_q6afe_block,
+};
+
+struct q6afe_clk *q6afe_clks[Q6AFE_MAX_CLK_ID] = {
+ [LPASS_CLK_ID_PRI_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_MI2S_IBIT),
+ [LPASS_CLK_ID_PRI_MI2S_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_MI2S_EBIT),
+ [LPASS_CLK_ID_SEC_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEC_MI2S_IBIT),
+ [LPASS_CLK_ID_SEC_MI2S_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEC_MI2S_EBIT),
+ [LPASS_CLK_ID_TER_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_TER_MI2S_IBIT),
+ [LPASS_CLK_ID_TER_MI2S_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_TER_MI2S_EBIT),
+ [LPASS_CLK_ID_QUAD_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUAD_MI2S_IBIT),
+ [LPASS_CLK_ID_QUAD_MI2S_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUAD_MI2S_EBIT),
+ [LPASS_CLK_ID_SPEAKER_I2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_SPEAKER_I2S_IBIT),
+ [LPASS_CLK_ID_SPEAKER_I2S_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_SPEAKER_I2S_EBIT),
+ [LPASS_CLK_ID_SPEAKER_I2S_OSR] = Q6AFE_CLK(LPASS_CLK_ID_SPEAKER_I2S_OSR),
+ [LPASS_CLK_ID_QUI_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUI_MI2S_IBIT),
+ [LPASS_CLK_ID_QUI_MI2S_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUI_MI2S_EBIT),
+ [LPASS_CLK_ID_SEN_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEN_MI2S_IBIT),
+ [LPASS_CLK_ID_SEN_MI2S_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEN_MI2S_EBIT),
+ [LPASS_CLK_ID_INT0_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_INT0_MI2S_IBIT),
+ [LPASS_CLK_ID_INT1_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_INT1_MI2S_IBIT),
+ [LPASS_CLK_ID_INT2_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_INT2_MI2S_IBIT),
+ [LPASS_CLK_ID_INT3_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_INT3_MI2S_IBIT),
+ [LPASS_CLK_ID_INT4_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_INT4_MI2S_IBIT),
+ [LPASS_CLK_ID_INT5_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_INT5_MI2S_IBIT),
+ [LPASS_CLK_ID_INT6_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_INT6_MI2S_IBIT),
+ [LPASS_CLK_ID_QUI_MI2S_OSR] = Q6AFE_CLK(LPASS_CLK_ID_QUI_MI2S_OSR),
+ [LPASS_CLK_ID_PRI_PCM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_PCM_IBIT),
+ [LPASS_CLK_ID_PRI_PCM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_PCM_EBIT),
+ [LPASS_CLK_ID_SEC_PCM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEC_PCM_IBIT),
+ [LPASS_CLK_ID_SEC_PCM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEC_PCM_EBIT),
+ [LPASS_CLK_ID_TER_PCM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_TER_PCM_IBIT),
+ [LPASS_CLK_ID_TER_PCM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_TER_PCM_EBIT),
+ [LPASS_CLK_ID_QUAD_PCM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUAD_PCM_IBIT),
+ [LPASS_CLK_ID_QUAD_PCM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUAD_PCM_EBIT),
+ [LPASS_CLK_ID_QUIN_PCM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUIN_PCM_IBIT),
+ [LPASS_CLK_ID_QUIN_PCM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUIN_PCM_EBIT),
+ [LPASS_CLK_ID_QUI_PCM_OSR] = Q6AFE_CLK(LPASS_CLK_ID_QUI_PCM_OSR),
+ [LPASS_CLK_ID_PRI_TDM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_TDM_IBIT),
+ [LPASS_CLK_ID_PRI_TDM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_TDM_EBIT),
+ [LPASS_CLK_ID_SEC_TDM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEC_TDM_IBIT),
+ [LPASS_CLK_ID_SEC_TDM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEC_TDM_EBIT),
+ [LPASS_CLK_ID_TER_TDM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_TER_TDM_IBIT),
+ [LPASS_CLK_ID_TER_TDM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_TER_TDM_EBIT),
+ [LPASS_CLK_ID_QUAD_TDM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUAD_TDM_IBIT),
+ [LPASS_CLK_ID_QUAD_TDM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUAD_TDM_EBIT),
+ [LPASS_CLK_ID_QUIN_TDM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUIN_TDM_IBIT),
+ [LPASS_CLK_ID_QUIN_TDM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUIN_TDM_EBIT),
+ [LPASS_CLK_ID_QUIN_TDM_OSR] = Q6AFE_CLK(LPASS_CLK_ID_QUIN_TDM_OSR),
+ [LPASS_CLK_ID_MCLK_1] = Q6AFE_CLK(LPASS_CLK_ID_MCLK_1),
+ [LPASS_CLK_ID_MCLK_2] = Q6AFE_CLK(LPASS_CLK_ID_MCLK_2),
+ [LPASS_CLK_ID_MCLK_3] = Q6AFE_CLK(LPASS_CLK_ID_MCLK_3),
+ [LPASS_CLK_ID_MCLK_4] = Q6AFE_CLK(LPASS_CLK_ID_MCLK_4),
+ [LPASS_CLK_ID_INTERNAL_DIGITAL_CODEC_CORE] = Q6AFE_CLK(LPASS_CLK_ID_INTERNAL_DIGITAL_CODEC_CORE),
+ [LPASS_CLK_ID_INT_MCLK_0] = Q6AFE_CLK(LPASS_CLK_ID_INT_MCLK_0),
+ [LPASS_CLK_ID_INT_MCLK_1] = Q6AFE_CLK(LPASS_CLK_ID_INT_MCLK_1),
+ [LPASS_CLK_ID_WSA_CORE_MCLK] = Q6AFE_CORE_CLK(LPASS_CLK_ID_WSA_CORE_MCLK),
+ [LPASS_CLK_ID_WSA_CORE_NPL_MCLK] =
+ Q6AFE_NPL_CLK(LPASS_CLK_ID_WSA_CORE_MCLK,
+ LPASS_CLK_ID_WSA_CORE_NPL_MCLK),
+ [LPASS_CLK_ID_VA_CORE_MCLK] = Q6AFE_CORE_CLK(LPASS_CLK_ID_VA_CORE_MCLK),
+ [LPASS_CLK_ID_TX_CORE_MCLK] = Q6AFE_CORE_CLK(LPASS_CLK_ID_TX_CORE_MCLK),
+ [LPASS_CLK_ID_TX_CORE_NPL_MCLK] =
+ Q6AFE_NPL_CLK(LPASS_CLK_ID_TX_CORE_MCLK,
+ LPASS_CLK_ID_TX_CORE_NPL_MCLK),
+ [LPASS_CLK_ID_RX_CORE_MCLK] = Q6AFE_CORE_CLK(LPASS_CLK_ID_RX_CORE_MCLK),
+ [LPASS_CLK_ID_RX_CORE_NPL_MCLK] =
+ Q6AFE_NPL_CLK(LPASS_CLK_ID_RX_CORE_MCLK,
+ LPASS_CLK_ID_RX_CORE_NPL_MCLK),
+ [LPASS_CLK_ID_VA_CORE_2X_MCLK] =
+ Q6AFE_NPL_CLK(LPASS_CLK_ID_VA_CORE_MCLK,
+ LPASS_CLK_ID_VA_CORE_2X_MCLK),
+ [LPASS_HW_AVTIMER_VOTE] = Q6AFE_VOTE_CLK(LPASS_HW_AVTIMER_VOTE,
+ Q6AFE_LPASS_CORE_AVTIMER_BLOCK,
+ "LPASS_AVTIMER_MACRO"
+ ),
+ [LPASS_HW_MACRO_VOTE] = Q6AFE_VOTE_CLK(LPASS_HW_MACRO_VOTE,
+ Q6AFE_LPASS_CORE_HW_MACRO_BLOCK,
+ "LPASS_HW_MACRO"),
+ [LPASS_HW_DCODEC_VOTE] = Q6AFE_VOTE_CLK(LPASS_HW_DCODEC_VOTE,
+ Q6AFE_LPASS_CORE_HW_DCODEC_BLOCK,
+ "LPASS_HW_DCODEC"),
+};
+
+static struct clk_hw *q6afe_of_clk_hw_get(struct of_phandle_args *clkspec,
+ void *data)
+{
+ struct q6afe_cc *cc = data;
+ unsigned int idx = clkspec->args[0];
+ unsigned int attr = clkspec->args[1];
+
+ if (idx >= cc->num_clks || attr > LPASS_CLK_ATTRIBUTE_COUPLE_DIVISOR) {
+ dev_err(cc->dev, "Invalid clk specifier (%d, %d)\n", idx, attr);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (cc->clks[idx]) {
+ cc->clks[idx]->attributes = attr;
+ return &cc->clks[idx]->hw;
+ }
+
+ return ERR_PTR(-ENOENT);
+}
+
+static int q6afe_clock_dev_probe(struct platform_device *pdev)
+{
+ struct q6afe_cc *cc;
+ struct device *dev = &pdev->dev;
+ int i, ret;
+
+ cc = devm_kzalloc(dev, sizeof(*cc), GFP_KERNEL);
+ if (!cc)
+ return -ENOMEM;
+
+ cc->clks = &q6afe_clks[0];
+
+ cc->num_clks = ARRAY_SIZE(q6afe_clks);
+ for (i = 0; i < ARRAY_SIZE(q6afe_clks); i++) {
+ if (!q6afe_clks[i])
+ continue;
+
+ q6afe_clks[i]->dev = dev;
+
+ ret = devm_clk_hw_register(dev, &q6afe_clks[i]->hw);
+ if (ret)
+ return ret;
+ }
+
+ ret = of_clk_add_hw_provider(dev->of_node, q6afe_of_clk_hw_get, cc);
+ if (ret)
+ return ret;
+
+ dev_set_drvdata(dev, cc);
+
+ return 0;
+}
+
+static const struct of_device_id q6afe_clock_device_id[] = {
+ { .compatible = "qcom,q6afe-clocks" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, q6afe_clock_device_id);
+
+static struct platform_driver q6afe_clock_platform_driver = {
+ .driver = {
+ .name = "q6afe-clock",
+ .of_match_table = of_match_ptr(q6afe_clock_device_id),
+ },
+ .probe = q6afe_clock_dev_probe,
+};
+module_platform_driver(q6afe_clock_platform_driver);
+
+MODULE_DESCRIPTION("Q6 Audio Frontend clock driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c
index 0168af849272..d58b86a98114 100644
--- a/sound/soc/qcom/qdsp6/q6afe-dai.c
+++ b/sound/soc/qcom/qdsp6/q6afe-dai.c
@@ -55,6 +55,48 @@
.remove = msm_dai_q6_dai_remove, \
}
+#define Q6AFE_CDC_DMA_RX_DAI(did) { \
+ .playback = { \
+ .stream_name = #did" Playback", \
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_176400, \
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE, \
+ .channels_min = 1, \
+ .channels_max = 8, \
+ .rate_min = 8000, \
+ .rate_max = 176400, \
+ }, \
+ .name = #did, \
+ .ops = &q6dma_ops, \
+ .id = did, \
+ .probe = msm_dai_q6_dai_probe, \
+ .remove = msm_dai_q6_dai_remove, \
+ }
+
+#define Q6AFE_CDC_DMA_TX_DAI(did) { \
+ .capture = { \
+ .stream_name = #did" Capture", \
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_176400, \
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE, \
+ .channels_min = 1, \
+ .channels_max = 8, \
+ .rate_min = 8000, \
+ .rate_max = 176400, \
+ }, \
+ .name = #did, \
+ .ops = &q6dma_ops, \
+ .id = did, \
+ .probe = msm_dai_q6_dai_probe, \
+ .remove = msm_dai_q6_dai_remove, \
+ }
+
struct q6afe_dai_priv_data {
uint32_t sd_line_mask;
uint32_t sync_mode;
@@ -307,6 +349,90 @@ static int q6tdm_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+
+static int q6dma_set_channel_map(struct snd_soc_dai *dai,
+ unsigned int tx_num, unsigned int *tx_ch_mask,
+ unsigned int rx_num, unsigned int *rx_ch_mask)
+{
+
+ struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ struct q6afe_cdc_dma_cfg *cfg = &dai_data->port_config[dai->id].dma_cfg;
+ int ch_mask;
+ int rc = 0;
+
+ switch (dai->id) {
+ case WSA_CODEC_DMA_TX_0:
+ case WSA_CODEC_DMA_TX_1:
+ case WSA_CODEC_DMA_TX_2:
+ case VA_CODEC_DMA_TX_0:
+ case VA_CODEC_DMA_TX_1:
+ case VA_CODEC_DMA_TX_2:
+ case TX_CODEC_DMA_TX_0:
+ case TX_CODEC_DMA_TX_1:
+ case TX_CODEC_DMA_TX_2:
+ case TX_CODEC_DMA_TX_3:
+ case TX_CODEC_DMA_TX_4:
+ case TX_CODEC_DMA_TX_5:
+ if (!tx_ch_mask) {
+ dev_err(dai->dev, "tx slot not found\n");
+ return -EINVAL;
+ }
+
+ if (tx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
+ dev_err(dai->dev, "invalid tx num %d\n",
+ tx_num);
+ return -EINVAL;
+ }
+ ch_mask = *tx_ch_mask;
+
+ break;
+ case WSA_CODEC_DMA_RX_0:
+ case WSA_CODEC_DMA_RX_1:
+ case RX_CODEC_DMA_RX_0:
+ case RX_CODEC_DMA_RX_1:
+ case RX_CODEC_DMA_RX_2:
+ case RX_CODEC_DMA_RX_3:
+ case RX_CODEC_DMA_RX_4:
+ case RX_CODEC_DMA_RX_5:
+ case RX_CODEC_DMA_RX_6:
+ case RX_CODEC_DMA_RX_7:
+ /* rx */
+ if (!rx_ch_mask) {
+ dev_err(dai->dev, "rx slot not found\n");
+ return -EINVAL;
+ }
+ if (rx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
+ dev_err(dai->dev, "invalid rx num %d\n",
+ rx_num);
+ return -EINVAL;
+ }
+ ch_mask = *rx_ch_mask;
+
+ break;
+ default:
+ dev_err(dai->dev, "%s: invalid dai id 0x%x\n",
+ __func__, dai->id);
+ return -EINVAL;
+ }
+
+ cfg->active_channels_mask = ch_mask;
+
+ return rc;
+}
+
+static int q6dma_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ struct q6afe_cdc_dma_cfg *cfg = &dai_data->port_config[dai->id].dma_cfg;
+
+ cfg->bit_width = params_width(params);
+ cfg->sample_rate = params_rate(params);
+ cfg->num_channels = params_channels(params);
+
+ return 0;
+}
static void q6afe_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -362,6 +488,10 @@ static int q6afe_dai_prepare(struct snd_pcm_substream *substream,
q6afe_tdm_port_prepare(dai_data->port[dai->id],
&dai_data->port_config[dai->id].tdm);
break;
+ case WSA_CODEC_DMA_RX_0 ... RX_CODEC_DMA_RX_7:
+ q6afe_cdc_dma_port_prepare(dai_data->port[dai->id],
+ &dai_data->port_config[dai->id].dma_cfg);
+ break;
default:
return -EINVAL;
}
@@ -430,6 +560,7 @@ static int q6afe_mi2s_set_sysclk(struct snd_soc_dai *dai,
freq, dir);
case Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT ... Q6AFE_LPASS_CLK_ID_QUI_MI2S_OSR:
case Q6AFE_LPASS_CLK_ID_MCLK_1 ... Q6AFE_LPASS_CLK_ID_INT_MCLK_1:
+ case Q6AFE_LPASS_CLK_ID_WSA_CORE_MCLK ... Q6AFE_LPASS_CLK_ID_VA_CORE_2X_MCLK:
return q6afe_port_set_sysclk(port, clk_id,
Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
Q6AFE_LPASS_CLK_ROOT_DEFAULT,
@@ -562,6 +693,29 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = {
{"PRI_MI2S_TX", NULL, "Primary MI2S Capture"},
{"SEC_MI2S_TX", NULL, "Secondary MI2S Capture"},
{"QUAT_MI2S_TX", NULL, "Quaternary MI2S Capture"},
+
+ {"WSA_CODEC_DMA_RX_0 Playback", NULL, "WSA_CODEC_DMA_RX_0"},
+ {"WSA_CODEC_DMA_TX_0", NULL, "WSA_CODEC_DMA_TX_0 Capture"},
+ {"WSA_CODEC_DMA_RX_1 Playback", NULL, "WSA_CODEC_DMA_RX_1"},
+ {"WSA_CODEC_DMA_TX_1", NULL, "WSA_CODEC_DMA_TX_1 Capture"},
+ {"WSA_CODEC_DMA_TX_2", NULL, "WSA_CODEC_DMA_TX_2 Capture"},
+ {"VA_CODEC_DMA_TX_0", NULL, "VA_CODEC_DMA_TX_0 Capture"},
+ {"VA_CODEC_DMA_TX_1", NULL, "VA_CODEC_DMA_TX_1 Capture"},
+ {"VA_CODEC_DMA_TX_2", NULL, "VA_CODEC_DMA_TX_2 Capture"},
+ {"RX_CODEC_DMA_RX_0 Playback", NULL, "RX_CODEC_DMA_RX_0"},
+ {"TX_CODEC_DMA_TX_0", NULL, "TX_CODEC_DMA_TX_0 Capture"},
+ {"RX_CODEC_DMA_RX_1 Playback", NULL, "RX_CODEC_DMA_RX_1"},
+ {"TX_CODEC_DMA_TX_1", NULL, "TX_CODEC_DMA_TX_1 Capture"},
+ {"RX_CODEC_DMA_RX_2 Playback", NULL, "RX_CODEC_DMA_RX_2"},
+ {"TX_CODEC_DMA_TX_2", NULL, "TX_CODEC_DMA_TX_2 Capture"},
+ {"RX_CODEC_DMA_RX_3 Playback", NULL, "RX_CODEC_DMA_RX_3"},
+ {"TX_CODEC_DMA_TX_3", NULL, "TX_CODEC_DMA_TX_3 Capture"},
+ {"RX_CODEC_DMA_RX_4 Playback", NULL, "RX_CODEC_DMA_RX_4"},
+ {"TX_CODEC_DMA_TX_4", NULL, "TX_CODEC_DMA_TX_4 Capture"},
+ {"RX_CODEC_DMA_RX_5 Playback", NULL, "RX_CODEC_DMA_RX_5"},
+ {"TX_CODEC_DMA_TX_5", NULL, "TX_CODEC_DMA_TX_5 Capture"},
+ {"RX_CODEC_DMA_RX_6 Playback", NULL, "RX_CODEC_DMA_RX_6"},
+ {"RX_CODEC_DMA_RX_7 Playback", NULL, "RX_CODEC_DMA_RX_7"},
};
static const struct snd_soc_dai_ops q6hdmi_ops = {
@@ -594,6 +748,14 @@ static const struct snd_soc_dai_ops q6tdm_ops = {
.hw_params = q6tdm_hw_params,
};
+static const struct snd_soc_dai_ops q6dma_ops = {
+ .prepare = q6afe_dai_prepare,
+ .shutdown = q6afe_dai_shutdown,
+ .set_sysclk = q6afe_mi2s_set_sysclk,
+ .set_channel_map = q6dma_set_channel_map,
+ .hw_params = q6dma_hw_params,
+};
+
static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
{
struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
@@ -1128,6 +1290,28 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
.probe = msm_dai_q6_dai_probe,
.remove = msm_dai_q6_dai_remove,
},
+ Q6AFE_CDC_DMA_RX_DAI(WSA_CODEC_DMA_RX_0),
+ Q6AFE_CDC_DMA_TX_DAI(WSA_CODEC_DMA_TX_0),
+ Q6AFE_CDC_DMA_RX_DAI(WSA_CODEC_DMA_RX_1),
+ Q6AFE_CDC_DMA_TX_DAI(WSA_CODEC_DMA_TX_1),
+ Q6AFE_CDC_DMA_TX_DAI(WSA_CODEC_DMA_TX_2),
+ Q6AFE_CDC_DMA_TX_DAI(VA_CODEC_DMA_TX_0),
+ Q6AFE_CDC_DMA_TX_DAI(VA_CODEC_DMA_TX_1),
+ Q6AFE_CDC_DMA_TX_DAI(VA_CODEC_DMA_TX_2),
+ Q6AFE_CDC_DMA_RX_DAI(RX_CODEC_DMA_RX_0),
+ Q6AFE_CDC_DMA_TX_DAI(TX_CODEC_DMA_TX_0),
+ Q6AFE_CDC_DMA_RX_DAI(RX_CODEC_DMA_RX_1),
+ Q6AFE_CDC_DMA_TX_DAI(TX_CODEC_DMA_TX_1),
+ Q6AFE_CDC_DMA_RX_DAI(RX_CODEC_DMA_RX_2),
+ Q6AFE_CDC_DMA_TX_DAI(TX_CODEC_DMA_TX_2),
+ Q6AFE_CDC_DMA_RX_DAI(RX_CODEC_DMA_RX_3),
+ Q6AFE_CDC_DMA_TX_DAI(TX_CODEC_DMA_TX_3),
+ Q6AFE_CDC_DMA_RX_DAI(RX_CODEC_DMA_RX_4),
+ Q6AFE_CDC_DMA_TX_DAI(TX_CODEC_DMA_TX_4),
+ Q6AFE_CDC_DMA_RX_DAI(RX_CODEC_DMA_RX_5),
+ Q6AFE_CDC_DMA_TX_DAI(TX_CODEC_DMA_TX_5),
+ Q6AFE_CDC_DMA_RX_DAI(RX_CODEC_DMA_RX_6),
+ Q6AFE_CDC_DMA_RX_DAI(RX_CODEC_DMA_RX_7),
};
static int q6afe_of_xlate_dai_name(struct snd_soc_component *component,
@@ -1350,6 +1534,51 @@ static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = {
SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_7", NULL,
0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("DISPLAY_PORT_RX", "NULL", 0, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_IN("WSA_CODEC_DMA_RX_0", "NULL",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("WSA_CODEC_DMA_TX_0", "NULL",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("WSA_CODEC_DMA_RX_1", "NULL",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("WSA_CODEC_DMA_TX_1", "NULL",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("WSA_CODEC_DMA_TX_2", "NULL",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("VA_CODEC_DMA_TX_0", "NULL",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("VA_CODEC_DMA_TX_1", "NULL",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("VA_CODEC_DMA_TX_2", "NULL",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_0", "NULL",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_0", "NULL",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_1", "NULL",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_1", "NULL",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_2", "NULL",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_2", "NULL",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_3", "NULL",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_3", "NULL",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_4", "NULL",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_4", "NULL",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_5", "NULL",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_5", "NULL",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_6", "NULL",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_7", "NULL",
+ 0, SND_SOC_NOPM, 0, 0),
};
static const struct snd_soc_component_driver q6afe_dai_component = {
diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c
index e0945f7a58c8..688878a002a4 100644
--- a/sound/soc/qcom/qdsp6/q6afe.c
+++ b/sound/soc/qcom/qdsp6/q6afe.c
@@ -42,6 +42,10 @@
#define AFE_PARAM_ID_I2S_CONFIG 0x0001020D
#define AFE_PARAM_ID_TDM_CONFIG 0x0001029D
#define AFE_PARAM_ID_PORT_SLOT_MAPPING_CONFIG 0x00010297
+#define AFE_PARAM_ID_CODEC_DMA_CONFIG 0x000102B8
+#define AFE_CMD_REMOTE_LPASS_CORE_HW_VOTE_REQUEST 0x000100f4
+#define AFE_CMD_RSP_REMOTE_LPASS_CORE_HW_VOTE_REQUEST 0x000100f5
+#define AFE_CMD_REMOTE_LPASS_CORE_HW_DEVOTE_REQUEST 0x000100f6
/* I2S config specific */
#define AFE_API_VERSION_I2S_CONFIG 0x1
@@ -299,22 +303,71 @@
#define AFE_PORT_ID_QUINARY_TDM_TX_7 \
(AFE_PORT_ID_QUINARY_TDM_TX + 0x0E)
+/* AFE WSA Codec DMA Rx port 0 */
+#define AFE_PORT_ID_WSA_CODEC_DMA_RX_0 0xB000
+/* AFE WSA Codec DMA Tx port 0 */
+#define AFE_PORT_ID_WSA_CODEC_DMA_TX_0 0xB001
+/* AFE WSA Codec DMA Rx port 1 */
+#define AFE_PORT_ID_WSA_CODEC_DMA_RX_1 0xB002
+/* AFE WSA Codec DMA Tx port 1 */
+#define AFE_PORT_ID_WSA_CODEC_DMA_TX_1 0xB003
+/* AFE WSA Codec DMA Tx port 2 */
+#define AFE_PORT_ID_WSA_CODEC_DMA_TX_2 0xB005
+/* AFE VA Codec DMA Tx port 0 */
+#define AFE_PORT_ID_VA_CODEC_DMA_TX_0 0xB021
+/* AFE VA Codec DMA Tx port 1 */
+#define AFE_PORT_ID_VA_CODEC_DMA_TX_1 0xB023
+/* AFE VA Codec DMA Tx port 2 */
+#define AFE_PORT_ID_VA_CODEC_DMA_TX_2 0xB025
+/* AFE Rx Codec DMA Rx port 0 */
+#define AFE_PORT_ID_RX_CODEC_DMA_RX_0 0xB030
+/* AFE Tx Codec DMA Tx port 0 */
+#define AFE_PORT_ID_TX_CODEC_DMA_TX_0 0xB031
+/* AFE Rx Codec DMA Rx port 1 */
+#define AFE_PORT_ID_RX_CODEC_DMA_RX_1 0xB032
+/* AFE Tx Codec DMA Tx port 1 */
+#define AFE_PORT_ID_TX_CODEC_DMA_TX_1 0xB033
+/* AFE Rx Codec DMA Rx port 2 */
+#define AFE_PORT_ID_RX_CODEC_DMA_RX_2 0xB034
+/* AFE Tx Codec DMA Tx port 2 */
+#define AFE_PORT_ID_TX_CODEC_DMA_TX_2 0xB035
+/* AFE Rx Codec DMA Rx port 3 */
+#define AFE_PORT_ID_RX_CODEC_DMA_RX_3 0xB036
+/* AFE Tx Codec DMA Tx port 3 */
+#define AFE_PORT_ID_TX_CODEC_DMA_TX_3 0xB037
+/* AFE Rx Codec DMA Rx port 4 */
+#define AFE_PORT_ID_RX_CODEC_DMA_RX_4 0xB038
+/* AFE Tx Codec DMA Tx port 4 */
+#define AFE_PORT_ID_TX_CODEC_DMA_TX_4 0xB039
+/* AFE Rx Codec DMA Rx port 5 */
+#define AFE_PORT_ID_RX_CODEC_DMA_RX_5 0xB03A
+/* AFE Tx Codec DMA Tx port 5 */
+#define AFE_PORT_ID_TX_CODEC_DMA_TX_5 0xB03B
+/* AFE Rx Codec DMA Rx port 6 */
+#define AFE_PORT_ID_RX_CODEC_DMA_RX_6 0xB03C
+/* AFE Rx Codec DMA Rx port 7 */
+#define AFE_PORT_ID_RX_CODEC_DMA_RX_7 0xB03E
+
#define Q6AFE_LPASS_MODE_CLK1_VALID 1
#define Q6AFE_LPASS_MODE_CLK2_VALID 2
#define Q6AFE_LPASS_CLK_SRC_INTERNAL 1
#define Q6AFE_LPASS_CLK_ROOT_DEFAULT 0
#define AFE_API_VERSION_TDM_CONFIG 1
#define AFE_API_VERSION_SLOT_MAPPING_CONFIG 1
+#define AFE_API_VERSION_CODEC_DMA_CONFIG 1
#define TIMEOUT_MS 1000
#define AFE_CMD_RESP_AVAIL 0
#define AFE_CMD_RESP_NONE 1
+#define AFE_CLK_TOKEN 1024
struct q6afe {
struct apr_device *apr;
struct device *dev;
struct q6core_svc_api_info ainfo;
struct mutex lock;
+ struct aprv2_ibasic_rsp_result_t result;
+ wait_queue_head_t wait;
struct list_head port_list;
spinlock_t port_list_lock;
};
@@ -448,11 +501,21 @@ struct afe_param_id_tdm_cfg {
u32 slot_mask;
} __packed;
+struct afe_param_id_cdc_dma_cfg {
+ u32 cdc_dma_cfg_minor_version;
+ u32 sample_rate;
+ u16 bit_width;
+ u16 data_format;
+ u16 num_channels;
+ u16 active_channels_mask;
+} __packed;
+
union afe_port_config {
struct afe_param_id_hdmi_multi_chan_audio_cfg hdmi_multi_ch;
struct afe_param_id_slimbus_cfg slim_cfg;
struct afe_param_id_i2s_cfg i2s_cfg;
struct afe_param_id_tdm_cfg tdm_cfg;
+ struct afe_param_id_cdc_dma_cfg dma_cfg;
} __packed;
@@ -486,6 +549,18 @@ struct q6afe_port {
struct list_head node;
};
+struct afe_cmd_remote_lpass_core_hw_vote_request {
+ uint32_t hw_block_id;
+ char client_name[8];
+} __packed;
+
+struct afe_cmd_remote_lpass_core_hw_devote_request {
+ uint32_t hw_block_id;
+ uint32_t client_handle;
+} __packed;
+
+
+
struct afe_port_map {
int port_id;
int token;
@@ -707,6 +782,50 @@ static struct afe_port_map port_maps[AFE_PORT_MAX] = {
QUINARY_TDM_TX_7, 0, 1},
[DISPLAY_PORT_RX] = { AFE_PORT_ID_HDMI_OVER_DP_RX,
DISPLAY_PORT_RX, 1, 1},
+ [WSA_CODEC_DMA_RX_0] = { AFE_PORT_ID_WSA_CODEC_DMA_RX_0,
+ WSA_CODEC_DMA_RX_0, 1, 1},
+ [WSA_CODEC_DMA_TX_0] = { AFE_PORT_ID_WSA_CODEC_DMA_TX_0,
+ WSA_CODEC_DMA_TX_0, 0, 1},
+ [WSA_CODEC_DMA_RX_1] = { AFE_PORT_ID_WSA_CODEC_DMA_RX_1,
+ WSA_CODEC_DMA_RX_1, 1, 1},
+ [WSA_CODEC_DMA_TX_1] = { AFE_PORT_ID_WSA_CODEC_DMA_TX_1,
+ WSA_CODEC_DMA_TX_1, 0, 1},
+ [WSA_CODEC_DMA_TX_2] = { AFE_PORT_ID_WSA_CODEC_DMA_TX_2,
+ WSA_CODEC_DMA_TX_2, 0, 1},
+ [VA_CODEC_DMA_TX_0] = { AFE_PORT_ID_VA_CODEC_DMA_TX_0,
+ VA_CODEC_DMA_TX_0, 0, 1},
+ [VA_CODEC_DMA_TX_1] = { AFE_PORT_ID_VA_CODEC_DMA_TX_1,
+ VA_CODEC_DMA_TX_1, 0, 1},
+ [VA_CODEC_DMA_TX_2] = { AFE_PORT_ID_VA_CODEC_DMA_TX_2,
+ VA_CODEC_DMA_TX_2, 0, 1},
+ [RX_CODEC_DMA_RX_0] = { AFE_PORT_ID_RX_CODEC_DMA_RX_0,
+ RX_CODEC_DMA_RX_0, 1, 1},
+ [TX_CODEC_DMA_TX_0] = { AFE_PORT_ID_TX_CODEC_DMA_TX_0,
+ TX_CODEC_DMA_TX_0, 0, 1},
+ [RX_CODEC_DMA_RX_1] = { AFE_PORT_ID_RX_CODEC_DMA_RX_1,
+ RX_CODEC_DMA_RX_1, 1, 1},
+ [TX_CODEC_DMA_TX_1] = { AFE_PORT_ID_TX_CODEC_DMA_TX_1,
+ TX_CODEC_DMA_TX_1, 0, 1},
+ [RX_CODEC_DMA_RX_2] = { AFE_PORT_ID_RX_CODEC_DMA_RX_2,
+ RX_CODEC_DMA_RX_2, 1, 1},
+ [TX_CODEC_DMA_TX_2] = { AFE_PORT_ID_TX_CODEC_DMA_TX_2,
+ TX_CODEC_DMA_TX_2, 0, 1},
+ [RX_CODEC_DMA_RX_3] = { AFE_PORT_ID_RX_CODEC_DMA_RX_3,
+ RX_CODEC_DMA_RX_3, 1, 1},
+ [TX_CODEC_DMA_TX_3] = { AFE_PORT_ID_TX_CODEC_DMA_TX_3,
+ TX_CODEC_DMA_TX_3, 0, 1},
+ [RX_CODEC_DMA_RX_4] = { AFE_PORT_ID_RX_CODEC_DMA_RX_4,
+ RX_CODEC_DMA_RX_4, 1, 1},
+ [TX_CODEC_DMA_TX_4] = { AFE_PORT_ID_TX_CODEC_DMA_TX_4,
+ TX_CODEC_DMA_TX_4, 0, 1},
+ [RX_CODEC_DMA_RX_5] = { AFE_PORT_ID_RX_CODEC_DMA_RX_5,
+ RX_CODEC_DMA_RX_5, 1, 1},
+ [TX_CODEC_DMA_TX_5] = { AFE_PORT_ID_TX_CODEC_DMA_TX_5,
+ TX_CODEC_DMA_TX_5, 0, 1},
+ [RX_CODEC_DMA_RX_6] = { AFE_PORT_ID_RX_CODEC_DMA_RX_6,
+ RX_CODEC_DMA_RX_6, 1, 1},
+ [RX_CODEC_DMA_RX_7] = { AFE_PORT_ID_RX_CODEC_DMA_RX_7,
+ RX_CODEC_DMA_RX_7, 1, 1},
};
static void q6afe_port_free(struct kref *ref)
@@ -769,6 +888,9 @@ static int q6afe_callback(struct apr_device *adev, struct apr_resp_pkt *data)
port->result = *res;
wake_up(&port->wait);
kref_put(&port->refcount, q6afe_port_free);
+ } else if (hdr->token == AFE_CLK_TOKEN) {
+ afe->result = *res;
+ wake_up(&afe->wait);
}
break;
default:
@@ -777,6 +899,11 @@ static int q6afe_callback(struct apr_device *adev, struct apr_resp_pkt *data)
}
}
break;
+ case AFE_CMD_RSP_REMOTE_LPASS_CORE_HW_VOTE_REQUEST:
+ afe->result.opcode = hdr->opcode;
+ afe->result.status = res->status;
+ wake_up(&afe->wait);
+ break;
default:
break;
}
@@ -801,15 +928,23 @@ int q6afe_get_port_id(int index)
EXPORT_SYMBOL_GPL(q6afe_get_port_id);
static int afe_apr_send_pkt(struct q6afe *afe, struct apr_pkt *pkt,
- struct q6afe_port *port)
+ struct q6afe_port *port, uint32_t rsp_opcode)
{
wait_queue_head_t *wait = &port->wait;
- struct apr_hdr *hdr = &pkt->hdr;
+ struct aprv2_ibasic_rsp_result_t *result;
int ret;
mutex_lock(&afe->lock);
- port->result.opcode = 0;
- port->result.status = 0;
+ if (port) {
+ wait = &port->wait;
+ result = &port->result;
+ } else {
+ result = &afe->result;
+ wait = &afe->wait;
+ }
+
+ result->opcode = 0;
+ result->status = 0;
ret = apr_send_pkt(afe->apr, pkt);
if (ret < 0) {
@@ -818,13 +953,13 @@ static int afe_apr_send_pkt(struct q6afe *afe, struct apr_pkt *pkt,
goto err;
}
- ret = wait_event_timeout(*wait, (port->result.opcode == hdr->opcode),
+ ret = wait_event_timeout(*wait, (result->opcode == rsp_opcode),
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
ret = -ETIMEDOUT;
- } else if (port->result.status > 0) {
+ } else if (result->status > 0) {
dev_err(afe->dev, "DSP returned error[%x]\n",
- port->result.status);
+ result->status);
ret = -EINVAL;
} else {
ret = 0;
@@ -836,14 +971,13 @@ err:
return ret;
}
-static int q6afe_port_set_param(struct q6afe_port *port, void *data,
- int param_id, int module_id, int psize)
+static int q6afe_set_param(struct q6afe *afe, struct q6afe_port *port,
+ void *data, int param_id, int module_id, int psize,
+ int token)
{
struct afe_svc_cmd_set_param *param;
struct afe_port_param_data_v2 *pdata;
- struct q6afe *afe = port->afe;
struct apr_pkt *pkt;
- u16 port_id = port->id;
int ret, pkt_size;
void *p, *pl;
@@ -864,7 +998,7 @@ static int q6afe_port_set_param(struct q6afe_port *port, void *data,
pkt->hdr.pkt_size = pkt_size;
pkt->hdr.src_port = 0;
pkt->hdr.dest_port = 0;
- pkt->hdr.token = port->token;
+ pkt->hdr.token = token;
pkt->hdr.opcode = AFE_SVC_CMD_SET_PARAM;
param->payload_size = sizeof(*pdata) + psize;
@@ -875,15 +1009,21 @@ static int q6afe_port_set_param(struct q6afe_port *port, void *data,
pdata->param_id = param_id;
pdata->param_size = psize;
- ret = afe_apr_send_pkt(afe, pkt, port);
+ ret = afe_apr_send_pkt(afe, pkt, port, AFE_SVC_CMD_SET_PARAM);
if (ret)
- dev_err(afe->dev, "AFE enable for port 0x%x failed %d\n",
- port_id, ret);
+ dev_err(afe->dev, "AFE set params failed %d\n", ret);
kfree(pkt);
return ret;
}
+static int q6afe_port_set_param(struct q6afe_port *port, void *data,
+ int param_id, int module_id, int psize)
+{
+ return q6afe_set_param(port->afe, port, data, param_id, module_id,
+ psize, port->token);
+}
+
static int q6afe_port_set_param_v2(struct q6afe_port *port, void *data,
int param_id, int module_id, int psize)
{
@@ -924,7 +1064,7 @@ static int q6afe_port_set_param_v2(struct q6afe_port *port, void *data,
pdata->param_id = param_id;
pdata->param_size = psize;
- ret = afe_apr_send_pkt(afe, pkt, port);
+ ret = afe_apr_send_pkt(afe, pkt, port, AFE_PORT_CMD_SET_PARAM_V2);
if (ret)
dev_err(afe->dev, "AFE enable for port 0x%x failed %d\n",
port_id, ret);
@@ -933,7 +1073,7 @@ static int q6afe_port_set_param_v2(struct q6afe_port *port, void *data,
return ret;
}
-static int q6afe_set_lpass_clock(struct q6afe_port *port,
+static int q6afe_port_set_lpass_clock(struct q6afe_port *port,
struct afe_clk_cfg *cfg)
{
return q6afe_port_set_param_v2(port, cfg,
@@ -958,6 +1098,25 @@ static int q6afe_set_digital_codec_core_clock(struct q6afe_port *port,
sizeof(*cfg));
}
+int q6afe_set_lpass_clock(struct device *dev, int clk_id, int attri,
+ int clk_root, unsigned int freq)
+{
+ struct q6afe *afe = dev_get_drvdata(dev->parent);
+ struct afe_clk_set cset = {0,};
+
+ cset.clk_set_minor_version = AFE_API_VERSION_CLOCK_SET;
+ cset.clk_id = clk_id;
+ cset.clk_freq_in_hz = freq;
+ cset.clk_attri = attri;
+ cset.clk_root = clk_root;
+ cset.enable = !!freq;
+
+ return q6afe_set_param(afe, NULL, &cset, AFE_PARAM_ID_CLOCK_SET,
+ AFE_MODULE_CLOCK_SET, sizeof(cset),
+ AFE_CLK_TOKEN);
+}
+EXPORT_SYMBOL_GPL(q6afe_set_lpass_clock);
+
int q6afe_port_set_sysclk(struct q6afe_port *port, int clk_id,
int clk_src, int clk_root,
unsigned int freq, int dir)
@@ -980,7 +1139,7 @@ int q6afe_port_set_sysclk(struct q6afe_port *port, int clk_id,
ccfg.clk_src = clk_src;
ccfg.clk_root = clk_root;
ccfg.clk_set_mode = Q6AFE_LPASS_MODE_CLK1_VALID;
- ret = q6afe_set_lpass_clock(port, &ccfg);
+ ret = q6afe_port_set_lpass_clock(port, &ccfg);
break;
case LPAIF_OSR_CLK:
@@ -989,11 +1148,12 @@ int q6afe_port_set_sysclk(struct q6afe_port *port, int clk_id,
ccfg.clk_src = clk_src;
ccfg.clk_root = clk_root;
ccfg.clk_set_mode = Q6AFE_LPASS_MODE_CLK2_VALID;
- ret = q6afe_set_lpass_clock(port, &ccfg);
+ ret = q6afe_port_set_lpass_clock(port, &ccfg);
break;
case Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT ... Q6AFE_LPASS_CLK_ID_QUI_MI2S_OSR:
case Q6AFE_LPASS_CLK_ID_MCLK_1 ... Q6AFE_LPASS_CLK_ID_INT_MCLK_1:
case Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT ... Q6AFE_LPASS_CLK_ID_QUIN_TDM_EBIT:
+ case Q6AFE_LPASS_CLK_ID_WSA_CORE_MCLK ... Q6AFE_LPASS_CLK_ID_VA_CORE_2X_MCLK:
cset.clk_set_minor_version = AFE_API_VERSION_CLOCK_SET;
cset.clk_id = clk_id;
cset.clk_freq_in_hz = freq;
@@ -1054,7 +1214,7 @@ int q6afe_port_stop(struct q6afe_port *port)
stop->port_id = port_id;
stop->reserved = 0;
- ret = afe_apr_send_pkt(afe, pkt, port);
+ ret = afe_apr_send_pkt(afe, pkt, port, AFE_PORT_CMD_DEVICE_STOP);
if (ret)
dev_err(afe->dev, "AFE close failed %d\n", ret);
@@ -1289,6 +1449,28 @@ int q6afe_i2s_port_prepare(struct q6afe_port *port, struct q6afe_i2s_cfg *cfg)
EXPORT_SYMBOL_GPL(q6afe_i2s_port_prepare);
/**
+ * q6afe_dam_port_prepare() - Prepare dma afe port.
+ *
+ * @port: Instance of afe port
+ * @cfg: DMA configuration for the afe port
+ *
+ */
+void q6afe_cdc_dma_port_prepare(struct q6afe_port *port,
+ struct q6afe_cdc_dma_cfg *cfg)
+{
+ union afe_port_config *pcfg = &port->port_cfg;
+ struct afe_param_id_cdc_dma_cfg *dma_cfg = &pcfg->dma_cfg;
+
+ dma_cfg->cdc_dma_cfg_minor_version = AFE_API_VERSION_CODEC_DMA_CONFIG;
+ dma_cfg->sample_rate = cfg->sample_rate;
+ dma_cfg->bit_width = cfg->bit_width;
+ dma_cfg->data_format = cfg->data_format;
+ dma_cfg->num_channels = cfg->num_channels;
+ if (!cfg->active_channels_mask)
+ dma_cfg->active_channels_mask = (1 << cfg->num_channels) - 1;
+}
+EXPORT_SYMBOL_GPL(q6afe_cdc_dma_port_prepare);
+/**
* q6afe_port_start() - Start a afe port
*
* @port: Instance of port to start
@@ -1344,7 +1526,7 @@ int q6afe_port_start(struct q6afe_port *port)
start->port_id = port_id;
- ret = afe_apr_send_pkt(afe, pkt, port);
+ ret = afe_apr_send_pkt(afe, pkt, port, AFE_PORT_CMD_DEVICE_START);
if (ret)
dev_err(afe->dev, "AFE enable for port 0x%x failed %d\n",
port_id, ret);
@@ -1420,7 +1602,9 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id)
case AFE_PORT_ID_PRIMARY_TDM_RX ... AFE_PORT_ID_QUINARY_TDM_TX_7:
cfg_type = AFE_PARAM_ID_TDM_CONFIG;
break;
-
+ case AFE_PORT_ID_WSA_CODEC_DMA_RX_0 ... AFE_PORT_ID_RX_CODEC_DMA_RX_7:
+ cfg_type = AFE_PARAM_ID_CODEC_DMA_CONFIG;
+ break;
default:
dev_err(dev, "Invalid port id 0x%x\n", port_id);
return ERR_PTR(-EINVAL);
@@ -1458,6 +1642,85 @@ void q6afe_port_put(struct q6afe_port *port)
}
EXPORT_SYMBOL_GPL(q6afe_port_put);
+int q6afe_unvote_lpass_core_hw(struct device *dev, uint32_t hw_block_id,
+ uint32_t client_handle)
+{
+ struct q6afe *afe = dev_get_drvdata(dev->parent);
+ struct afe_cmd_remote_lpass_core_hw_devote_request *vote_cfg;
+ struct apr_pkt *pkt;
+ int ret = 0;
+ int pkt_size;
+ void *p;
+
+ pkt_size = APR_HDR_SIZE + sizeof(*vote_cfg);
+ p = kzalloc(pkt_size, GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ pkt = p;
+ vote_cfg = p + APR_HDR_SIZE;
+
+ pkt->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ pkt->hdr.pkt_size = pkt_size;
+ pkt->hdr.src_port = 0;
+ pkt->hdr.dest_port = 0;
+ pkt->hdr.token = hw_block_id;
+ pkt->hdr.opcode = AFE_CMD_REMOTE_LPASS_CORE_HW_DEVOTE_REQUEST;
+ vote_cfg->hw_block_id = hw_block_id;
+ vote_cfg->client_handle = client_handle;
+
+ ret = apr_send_pkt(afe->apr, pkt);
+ if (ret < 0)
+ dev_err(afe->dev, "AFE failed to unvote (%d)\n", hw_block_id);
+
+ kfree(pkt);
+ return ret;
+}
+EXPORT_SYMBOL(q6afe_unvote_lpass_core_hw);
+
+int q6afe_vote_lpass_core_hw(struct device *dev, uint32_t hw_block_id,
+ char *client_name, uint32_t *client_handle)
+{
+ struct q6afe *afe = dev_get_drvdata(dev->parent);
+ struct afe_cmd_remote_lpass_core_hw_vote_request *vote_cfg;
+ struct apr_pkt *pkt;
+ int ret = 0;
+ int pkt_size;
+ void *p;
+
+ pkt_size = APR_HDR_SIZE + sizeof(*vote_cfg);
+ p = kzalloc(pkt_size, GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ pkt = p;
+ vote_cfg = p + APR_HDR_SIZE;
+
+ pkt->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ pkt->hdr.pkt_size = pkt_size;
+ pkt->hdr.src_port = 0;
+ pkt->hdr.dest_port = 0;
+ pkt->hdr.token = hw_block_id;
+ pkt->hdr.opcode = AFE_CMD_REMOTE_LPASS_CORE_HW_VOTE_REQUEST;
+ vote_cfg->hw_block_id = hw_block_id;
+ strlcpy(vote_cfg->client_name, client_name,
+ sizeof(vote_cfg->client_name));
+
+ ret = afe_apr_send_pkt(afe, pkt, NULL,
+ AFE_CMD_RSP_REMOTE_LPASS_CORE_HW_VOTE_REQUEST);
+ if (ret)
+ dev_err(afe->dev, "AFE failed to vote (%d)\n", hw_block_id);
+
+
+ kfree(pkt);
+ return ret;
+}
+EXPORT_SYMBOL(q6afe_vote_lpass_core_hw);
+
static int q6afe_probe(struct apr_device *adev)
{
struct q6afe *afe;
@@ -1470,6 +1733,7 @@ static int q6afe_probe(struct apr_device *adev)
q6core_get_svc_api_info(adev->svc_id, &afe->ainfo);
afe->apr = adev;
mutex_init(&afe->lock);
+ init_waitqueue_head(&afe->wait);
afe->dev = dev;
INIT_LIST_HEAD(&afe->port_list);
spin_lock_init(&afe->port_list_lock);
diff --git a/sound/soc/qcom/qdsp6/q6afe.h b/sound/soc/qcom/qdsp6/q6afe.h
index c7ed5422baff..22e10269aa10 100644
--- a/sound/soc/qcom/qdsp6/q6afe.h
+++ b/sound/soc/qcom/qdsp6/q6afe.h
@@ -5,7 +5,7 @@
#include <dt-bindings/sound/qcom,q6afe.h>
-#define AFE_PORT_MAX 105
+#define AFE_PORT_MAX 127
#define MSM_AFE_PORT_TYPE_RX 0
#define MSM_AFE_PORT_TYPE_TX 1
@@ -133,6 +133,19 @@
/* Clock ID for INT MCLK1 */
#define Q6AFE_LPASS_CLK_ID_INT_MCLK_1 0x306
+#define Q6AFE_LPASS_CLK_ID_WSA_CORE_MCLK 0x309
+#define Q6AFE_LPASS_CLK_ID_WSA_CORE_NPL_MCLK 0x30a
+#define Q6AFE_LPASS_CLK_ID_TX_CORE_MCLK 0x30c
+#define Q6AFE_LPASS_CLK_ID_TX_CORE_NPL_MCLK 0x30d
+#define Q6AFE_LPASS_CLK_ID_RX_CORE_MCLK 0x30e
+#define Q6AFE_LPASS_CLK_ID_RX_CORE_NPL_MCLK 0x30f
+#define Q6AFE_LPASS_CLK_ID_VA_CORE_MCLK 0x30b
+#define Q6AFE_LPASS_CLK_ID_VA_CORE_2X_MCLK 0x310
+
+#define Q6AFE_LPASS_CORE_AVTIMER_BLOCK 0x2
+#define Q6AFE_LPASS_CORE_HW_MACRO_BLOCK 0x3
+#define Q6AFE_LPASS_CORE_HW_DCODEC_BLOCK 0x4
+
/* Clock attribute for invalid use (reserved for internal usage) */
#define Q6AFE_LPASS_CLK_ATTRIBUTE_INVALID 0x0
/* Clock attribute for no couple case */
@@ -184,11 +197,21 @@ struct q6afe_tdm_cfg {
u16 ch_mapping[AFE_MAX_CHAN_COUNT];
};
+struct q6afe_cdc_dma_cfg {
+ u16 sample_rate;
+ u16 bit_width;
+ u16 data_format;
+ u16 num_channels;
+ u16 active_channels_mask;
+};
+
+
struct q6afe_port_config {
struct q6afe_hdmi_cfg hdmi;
struct q6afe_slim_cfg slim;
struct q6afe_i2s_cfg i2s_cfg;
struct q6afe_tdm_cfg tdm;
+ struct q6afe_cdc_dma_cfg dma_cfg;
};
struct q6afe_port;
@@ -204,8 +227,16 @@ void q6afe_slim_port_prepare(struct q6afe_port *port,
struct q6afe_slim_cfg *cfg);
int q6afe_i2s_port_prepare(struct q6afe_port *port, struct q6afe_i2s_cfg *cfg);
void q6afe_tdm_port_prepare(struct q6afe_port *port, struct q6afe_tdm_cfg *cfg);
+void q6afe_cdc_dma_port_prepare(struct q6afe_port *port,
+ struct q6afe_cdc_dma_cfg *cfg);
int q6afe_port_set_sysclk(struct q6afe_port *port, int clk_id,
int clk_src, int clk_root,
unsigned int freq, int dir);
+int q6afe_set_lpass_clock(struct device *dev, int clk_id, int clk_src,
+ int clk_root, unsigned int freq);
+int q6afe_vote_lpass_core_hw(struct device *dev, uint32_t hw_block_id,
+ char *client_name, uint32_t *client_handle);
+int q6afe_unvote_lpass_core_hw(struct device *dev, uint32_t hw_block_id,
+ uint32_t client_handle);
#endif /* __Q6AFE_H__ */
diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index 9b7b218f2a20..a1dd31f306ce 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -50,7 +50,7 @@ enum stream_state {
struct q6asm_dai_rtd {
struct snd_pcm_substream *substream;
struct snd_compr_stream *cstream;
- struct snd_compr_params codec_param;
+ struct snd_codec codec;
struct snd_dma_buffer dma_buffer;
spinlock_t lock;
phys_addr_t phys;
@@ -64,8 +64,14 @@ struct q6asm_dai_rtd {
uint16_t bits_per_sample;
uint16_t source; /* Encoding source bit mask */
struct audio_client *audio_client;
+ uint32_t next_track_stream_id;
+ bool next_track;
+ uint32_t stream_id;
uint16_t session_id;
enum stream_state state;
+ uint32_t initial_samples_drop;
+ uint32_t trailing_samples_drop;
+ bool notify_on_drain;
};
struct q6asm_dai_data {
@@ -181,8 +187,8 @@ static void event_handler(uint32_t opcode, uint32_t token,
switch (opcode) {
case ASM_CLIENT_EVENT_CMD_RUN_DONE:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- q6asm_write_async(prtd->audio_client,
- prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+ q6asm_write_async(prtd->audio_client, prtd->stream_id,
+ prtd->pcm_count, 0, 0, 0);
break;
case ASM_CLIENT_EVENT_CMD_EOS_DONE:
prtd->state = Q6ASM_STREAM_STOPPED;
@@ -191,8 +197,8 @@ static void event_handler(uint32_t opcode, uint32_t token,
prtd->pcm_irq_pos += prtd->pcm_count;
snd_pcm_period_elapsed(substream);
if (prtd->state == Q6ASM_STREAM_RUNNING)
- q6asm_write_async(prtd->audio_client,
- prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+ q6asm_write_async(prtd->audio_client, prtd->stream_id,
+ prtd->pcm_count, 0, 0, 0);
break;
}
@@ -200,7 +206,7 @@ static void event_handler(uint32_t opcode, uint32_t token,
prtd->pcm_irq_pos += prtd->pcm_count;
snd_pcm_period_elapsed(substream);
if (prtd->state == Q6ASM_STREAM_RUNNING)
- q6asm_read(prtd->audio_client);
+ q6asm_read(prtd->audio_client, prtd->stream_id);
break;
default:
@@ -233,7 +239,7 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
/* rate and channels are sent to audio driver */
if (prtd->state) {
/* clear the previous setup if any */
- q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+ q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE);
q6asm_unmap_memory_regions(substream->stream,
prtd->audio_client);
q6routing_stream_close(soc_prtd->dai_link->id,
@@ -252,11 +258,13 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM,
- 0, prtd->bits_per_sample);
+ ret = q6asm_open_write(prtd->audio_client, prtd->stream_id,
+ FORMAT_LINEAR_PCM,
+ 0, prtd->bits_per_sample, false);
} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM,
- prtd->bits_per_sample);
+ ret = q6asm_open_read(prtd->audio_client, prtd->stream_id,
+ FORMAT_LINEAR_PCM,
+ prtd->bits_per_sample);
}
if (ret < 0) {
@@ -276,17 +284,19 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
ret = q6asm_media_format_block_multi_ch_pcm(
- prtd->audio_client, runtime->rate,
- runtime->channels, NULL,
+ prtd->audio_client, prtd->stream_id,
+ runtime->rate, runtime->channels, NULL,
prtd->bits_per_sample);
} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
ret = q6asm_enc_cfg_blk_pcm_format_support(prtd->audio_client,
- runtime->rate, runtime->channels,
- prtd->bits_per_sample);
+ prtd->stream_id,
+ runtime->rate,
+ runtime->channels,
+ prtd->bits_per_sample);
/* Queue the buffers */
for (i = 0; i < runtime->periods; i++)
- q6asm_read(prtd->audio_client);
+ q6asm_read(prtd->audio_client, prtd->stream_id);
}
if (ret < 0)
@@ -308,15 +318,18 @@ static int q6asm_dai_trigger(struct snd_soc_component *component,
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+ ret = q6asm_run_nowait(prtd->audio_client, prtd->stream_id,
+ 0, 0, 0);
break;
case SNDRV_PCM_TRIGGER_STOP:
prtd->state = Q6ASM_STREAM_STOPPED;
- ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+ ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
+ CMD_EOS);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+ ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
+ CMD_PAUSE);
break;
default:
ret = -EINVAL;
@@ -361,6 +374,9 @@ static int q6asm_dai_open(struct snd_soc_component *component,
return ret;
}
+ /* DSP expects stream id from 1 */
+ prtd->stream_id = 1;
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
runtime->hw = q6asm_dai_hardware_playback;
else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
@@ -427,7 +443,8 @@ static int q6asm_dai_close(struct snd_soc_component *component,
if (prtd->audio_client) {
if (prtd->state)
- q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+ q6asm_cmd(prtd->audio_client, prtd->stream_id,
+ CMD_CLOSE);
q6asm_unmap_memory_regions(substream->stream,
prtd->audio_client);
@@ -493,14 +510,21 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,
struct q6asm_dai_rtd *prtd = priv;
struct snd_compr_stream *substream = prtd->cstream;
unsigned long flags;
+ u32 wflags = 0;
uint64_t avail;
+ uint32_t bytes_written, bytes_to_write;
+ bool is_last_buffer = false;
switch (opcode) {
case ASM_CLIENT_EVENT_CMD_RUN_DONE:
spin_lock_irqsave(&prtd->lock, flags);
if (!prtd->bytes_sent) {
- q6asm_write_async(prtd->audio_client, prtd->pcm_count,
- 0, 0, NO_TIMESTAMP);
+ q6asm_stream_remove_initial_silence(prtd->audio_client,
+ prtd->stream_id,
+ prtd->initial_samples_drop);
+
+ q6asm_write_async(prtd->audio_client, prtd->stream_id,
+ prtd->pcm_count, 0, 0, 0);
prtd->bytes_sent += prtd->pcm_count;
}
@@ -508,13 +532,37 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,
break;
case ASM_CLIENT_EVENT_CMD_EOS_DONE:
- prtd->state = Q6ASM_STREAM_STOPPED;
+ spin_lock_irqsave(&prtd->lock, flags);
+ if (prtd->notify_on_drain) {
+ if (substream->partial_drain) {
+ /*
+ * Close old stream and make it stale, switch
+ * the active stream now!
+ */
+ q6asm_cmd_nowait(prtd->audio_client,
+ prtd->stream_id,
+ CMD_CLOSE);
+ /*
+ * vaild stream ids start from 1, So we are
+ * toggling this between 1 and 2.
+ */
+ prtd->stream_id = (prtd->stream_id == 1 ? 2 : 1);
+ }
+
+ snd_compr_drain_notify(prtd->cstream);
+ prtd->notify_on_drain = false;
+
+ } else {
+ prtd->state = Q6ASM_STREAM_STOPPED;
+ }
+ spin_unlock_irqrestore(&prtd->lock, flags);
break;
case ASM_CLIENT_EVENT_DATA_WRITE_DONE:
spin_lock_irqsave(&prtd->lock, flags);
- prtd->copied_total += prtd->pcm_count;
+ bytes_written = token >> ASM_WRITE_TOKEN_LEN_SHIFT;
+ prtd->copied_total += bytes_written;
snd_compr_fragment_elapsed(substream);
if (prtd->state != Q6ASM_STREAM_RUNNING) {
@@ -523,13 +571,32 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,
}
avail = prtd->bytes_received - prtd->bytes_sent;
+ if (avail > prtd->pcm_count) {
+ bytes_to_write = prtd->pcm_count;
+ } else {
+ if (substream->partial_drain || prtd->notify_on_drain)
+ is_last_buffer = true;
+ bytes_to_write = avail;
+ }
- if (avail >= prtd->pcm_count) {
- q6asm_write_async(prtd->audio_client,
- prtd->pcm_count, 0, 0, NO_TIMESTAMP);
- prtd->bytes_sent += prtd->pcm_count;
+ if (bytes_to_write) {
+ if (substream->partial_drain && is_last_buffer) {
+ wflags |= ASM_LAST_BUFFER_FLAG;
+ q6asm_stream_remove_trailing_silence(prtd->audio_client,
+ prtd->stream_id,
+ prtd->trailing_samples_drop);
+ }
+
+ q6asm_write_async(prtd->audio_client, prtd->stream_id,
+ bytes_to_write, 0, 0, wflags);
+
+ prtd->bytes_sent += bytes_to_write;
}
+ if (prtd->notify_on_drain && is_last_buffer)
+ q6asm_cmd_nowait(prtd->audio_client,
+ prtd->stream_id, CMD_EOS);
+
spin_unlock_irqrestore(&prtd->lock, flags);
break;
@@ -560,6 +627,9 @@ static int q6asm_dai_compr_open(struct snd_soc_component *component,
if (!prtd)
return -ENOMEM;
+ /* DSP expects stream id from 1 */
+ prtd->stream_id = 1;
+
prtd->cstream = stream;
prtd->audio_client = q6asm_audio_client_alloc(dev,
(q6asm_cb)compress_event_handler,
@@ -606,8 +676,15 @@ static int q6asm_dai_compr_free(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd = stream->private_data;
if (prtd->audio_client) {
- if (prtd->state)
- q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+ if (prtd->state) {
+ q6asm_cmd(prtd->audio_client, prtd->stream_id,
+ CMD_CLOSE);
+ if (prtd->next_track_stream_id) {
+ q6asm_cmd(prtd->audio_client,
+ prtd->next_track_stream_id,
+ CMD_CLOSE);
+ }
+ }
snd_dma_free_pages(&prtd->dma_buffer);
q6asm_unmap_memory_regions(stream->direction,
@@ -621,15 +698,13 @@ static int q6asm_dai_compr_free(struct snd_soc_component *component,
return 0;
}
-static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
- struct snd_compr_stream *stream,
- struct snd_compr_params *params)
+static int __q6asm_dai_compr_set_codec_params(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
+ struct snd_codec *codec,
+ int stream_id)
{
struct snd_compr_runtime *runtime = stream->runtime;
struct q6asm_dai_rtd *prtd = runtime->private_data;
- struct snd_soc_pcm_runtime *rtd = stream->private_data;
- int dir = stream->direction;
- struct q6asm_dai_data *pdata;
struct q6asm_flac_cfg flac_cfg;
struct q6asm_wma_cfg wma_cfg;
struct q6asm_alac_cfg alac_cfg;
@@ -643,52 +718,18 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
struct snd_dec_alac *alac;
struct snd_dec_ape *ape;
- codec_options = &(prtd->codec_param.codec.options);
-
-
- memcpy(&prtd->codec_param, params, sizeof(*params));
-
- pdata = snd_soc_component_get_drvdata(component);
- if (!pdata)
- return -EINVAL;
-
- if (!prtd || !prtd->audio_client) {
- dev_err(dev, "private data null or audio client freed\n");
- return -EINVAL;
- }
-
- prtd->periods = runtime->fragments;
- prtd->pcm_count = runtime->fragment_size;
- prtd->pcm_size = runtime->fragments * runtime->fragment_size;
- prtd->bits_per_sample = 16;
- if (dir == SND_COMPRESS_PLAYBACK) {
- ret = q6asm_open_write(prtd->audio_client, params->codec.id,
- params->codec.profile, prtd->bits_per_sample);
-
- if (ret < 0) {
- dev_err(dev, "q6asm_open_write failed\n");
- q6asm_audio_client_free(prtd->audio_client);
- prtd->audio_client = NULL;
- return ret;
- }
- }
+ codec_options = &(prtd->codec.options);
- prtd->session_id = q6asm_get_session_id(prtd->audio_client);
- ret = q6routing_stream_open(rtd->dai_link->id, LEGACY_PCM_MODE,
- prtd->session_id, dir);
- if (ret) {
- dev_err(dev, "Stream reg failed ret:%d\n", ret);
- return ret;
- }
+ memcpy(&prtd->codec, codec, sizeof(*codec));
- switch (params->codec.id) {
+ switch (codec->id) {
case SND_AUDIOCODEC_FLAC:
memset(&flac_cfg, 0x0, sizeof(struct q6asm_flac_cfg));
flac = &codec_options->flac_d;
- flac_cfg.ch_cfg = params->codec.ch_in;
- flac_cfg.sample_rate = params->codec.sample_rate;
+ flac_cfg.ch_cfg = codec->ch_in;
+ flac_cfg.sample_rate = codec->sample_rate;
flac_cfg.stream_info_present = 1;
flac_cfg.sample_size = flac->sample_size;
flac_cfg.min_blk_size = flac->min_blk_size;
@@ -697,6 +738,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
flac_cfg.min_frame_size = flac->min_frame_size;
ret = q6asm_stream_media_format_block_flac(prtd->audio_client,
+ stream_id,
&flac_cfg);
if (ret < 0) {
dev_err(dev, "FLAC CMD Format block failed:%d\n", ret);
@@ -709,10 +751,10 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
memset(&wma_cfg, 0x0, sizeof(struct q6asm_wma_cfg));
- wma_cfg.sample_rate = params->codec.sample_rate;
- wma_cfg.num_channels = params->codec.ch_in;
- wma_cfg.bytes_per_sec = params->codec.bit_rate / 8;
- wma_cfg.block_align = params->codec.align;
+ wma_cfg.sample_rate = codec->sample_rate;
+ wma_cfg.num_channels = codec->ch_in;
+ wma_cfg.bytes_per_sec = codec->bit_rate / 8;
+ wma_cfg.block_align = codec->align;
wma_cfg.bits_per_sample = prtd->bits_per_sample;
wma_cfg.enc_options = wma->encoder_option;
wma_cfg.adv_enc_options = wma->adv_encoder_option;
@@ -726,7 +768,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
return -EINVAL;
/* check the codec profile */
- switch (params->codec.profile) {
+ switch (codec->profile) {
case SND_AUDIOPROFILE_WMA9:
wma_cfg.fmtag = 0x161;
wma_v9 = 1;
@@ -750,16 +792,18 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
default:
dev_err(dev, "Unknown WMA profile:%x\n",
- params->codec.profile);
+ codec->profile);
return -EIO;
}
if (wma_v9)
ret = q6asm_stream_media_format_block_wma_v9(
- prtd->audio_client, &wma_cfg);
+ prtd->audio_client, stream_id,
+ &wma_cfg);
else
ret = q6asm_stream_media_format_block_wma_v10(
- prtd->audio_client, &wma_cfg);
+ prtd->audio_client, stream_id,
+ &wma_cfg);
if (ret < 0) {
dev_err(dev, "WMA9 CMD failed:%d\n", ret);
return -EIO;
@@ -770,10 +814,10 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
memset(&alac_cfg, 0x0, sizeof(alac_cfg));
alac = &codec_options->alac_d;
- alac_cfg.sample_rate = params->codec.sample_rate;
- alac_cfg.avg_bit_rate = params->codec.bit_rate;
+ alac_cfg.sample_rate = codec->sample_rate;
+ alac_cfg.avg_bit_rate = codec->bit_rate;
alac_cfg.bit_depth = prtd->bits_per_sample;
- alac_cfg.num_channels = params->codec.ch_in;
+ alac_cfg.num_channels = codec->ch_in;
alac_cfg.frame_length = alac->frame_length;
alac_cfg.pb = alac->pb;
@@ -783,7 +827,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
alac_cfg.compatible_version = alac->compatible_version;
alac_cfg.max_frame_bytes = alac->max_frame_bytes;
- switch (params->codec.ch_in) {
+ switch (codec->ch_in) {
case 1:
alac_cfg.channel_layout_tag = ALAC_CH_LAYOUT_MONO;
break;
@@ -792,6 +836,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
break;
}
ret = q6asm_stream_media_format_block_alac(prtd->audio_client,
+ stream_id,
&alac_cfg);
if (ret < 0) {
dev_err(dev, "ALAC CMD Format block failed:%d\n", ret);
@@ -803,8 +848,8 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
memset(&ape_cfg, 0x0, sizeof(ape_cfg));
ape = &codec_options->ape_d;
- ape_cfg.sample_rate = params->codec.sample_rate;
- ape_cfg.num_channels = params->codec.ch_in;
+ ape_cfg.sample_rate = codec->sample_rate;
+ ape_cfg.num_channels = codec->ch_in;
ape_cfg.bits_per_sample = prtd->bits_per_sample;
ape_cfg.compatible_version = ape->compatible_version;
@@ -816,6 +861,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
ape_cfg.seek_table_present = ape->seek_table_present;
ret = q6asm_stream_media_format_block_ape(prtd->audio_client,
+ stream_id,
&ape_cfg);
if (ret < 0) {
dev_err(dev, "APE CMD Format block failed:%d\n", ret);
@@ -827,6 +873,64 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
break;
}
+ return 0;
+}
+
+static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
+ struct snd_compr_params *params)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
+ int dir = stream->direction;
+ struct q6asm_dai_data *pdata;
+ struct device *dev = component->dev;
+ int ret;
+
+ pdata = snd_soc_component_get_drvdata(component);
+ if (!pdata)
+ return -EINVAL;
+
+ if (!prtd || !prtd->audio_client) {
+ dev_err(dev, "private data null or audio client freed\n");
+ return -EINVAL;
+ }
+
+ prtd->periods = runtime->fragments;
+ prtd->pcm_count = runtime->fragment_size;
+ prtd->pcm_size = runtime->fragments * runtime->fragment_size;
+ prtd->bits_per_sample = 16;
+
+ if (dir == SND_COMPRESS_PLAYBACK) {
+ ret = q6asm_open_write(prtd->audio_client, prtd->stream_id, params->codec.id,
+ params->codec.profile, prtd->bits_per_sample,
+ true);
+
+ if (ret < 0) {
+ dev_err(dev, "q6asm_open_write failed\n");
+ q6asm_audio_client_free(prtd->audio_client);
+ prtd->audio_client = NULL;
+ return ret;
+ }
+ }
+
+ prtd->session_id = q6asm_get_session_id(prtd->audio_client);
+ ret = q6routing_stream_open(rtd->dai_link->id, LEGACY_PCM_MODE,
+ prtd->session_id, dir);
+ if (ret) {
+ dev_err(dev, "Stream reg failed ret:%d\n", ret);
+ return ret;
+ }
+
+ ret = __q6asm_dai_compr_set_codec_params(component, stream,
+ &params->codec,
+ prtd->stream_id);
+ if (ret) {
+ dev_err(dev, "codec param setup failed ret:%d\n", ret);
+ return ret;
+ }
+
ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys,
(prtd->pcm_size / prtd->periods),
prtd->periods);
@@ -841,6 +945,55 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
return 0;
}
+static int q6asm_dai_compr_set_metadata(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
+ struct snd_compr_metadata *metadata)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ int ret = 0;
+
+ switch (metadata->key) {
+ case SNDRV_COMPRESS_ENCODER_PADDING:
+ prtd->trailing_samples_drop = metadata->value[0];
+ break;
+ case SNDRV_COMPRESS_ENCODER_DELAY:
+ prtd->initial_samples_drop = metadata->value[0];
+ if (prtd->next_track_stream_id) {
+ ret = q6asm_open_write(prtd->audio_client,
+ prtd->next_track_stream_id,
+ prtd->codec.id,
+ prtd->codec.profile,
+ prtd->bits_per_sample,
+ true);
+ if (ret < 0) {
+ dev_err(component->dev, "q6asm_open_write failed\n");
+ return ret;
+ }
+ ret = __q6asm_dai_compr_set_codec_params(component, stream,
+ &prtd->codec,
+ prtd->next_track_stream_id);
+ if (ret < 0) {
+ dev_err(component->dev, "q6asm_open_write failed\n");
+ return ret;
+ }
+
+ ret = q6asm_stream_remove_initial_silence(prtd->audio_client,
+ prtd->next_track_stream_id,
+ prtd->initial_samples_drop);
+ prtd->next_track_stream_id = 0;
+
+ }
+
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
static int q6asm_dai_compr_trigger(struct snd_soc_component *component,
struct snd_compr_stream *stream, int cmd)
{
@@ -852,15 +1005,26 @@ static int q6asm_dai_compr_trigger(struct snd_soc_component *component,
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+ ret = q6asm_run_nowait(prtd->audio_client, prtd->stream_id,
+ 0, 0, 0);
break;
case SNDRV_PCM_TRIGGER_STOP:
prtd->state = Q6ASM_STREAM_STOPPED;
- ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+ ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
+ CMD_EOS);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+ ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
+ CMD_PAUSE);
+ break;
+ case SND_COMPR_TRIGGER_NEXT_TRACK:
+ prtd->next_track = true;
+ prtd->next_track_stream_id = (prtd->stream_id == 1 ? 2 : 1);
+ break;
+ case SND_COMPR_TRIGGER_DRAIN:
+ case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
+ prtd->notify_on_drain = true;
break;
default:
ret = -EINVAL;
@@ -888,16 +1052,71 @@ static int q6asm_dai_compr_pointer(struct snd_soc_component *component,
return 0;
}
-static int q6asm_dai_compr_ack(struct snd_soc_component *component,
- struct snd_compr_stream *stream,
- size_t count)
+static int q6asm_compr_copy(struct snd_soc_component *component,
+ struct snd_compr_stream *stream, char __user *buf,
+ size_t count)
{
struct snd_compr_runtime *runtime = stream->runtime;
struct q6asm_dai_rtd *prtd = runtime->private_data;
unsigned long flags;
+ u32 wflags = 0;
+ int avail, bytes_in_flight = 0;
+ void *dstn;
+ size_t copy;
+ u32 app_pointer;
+ u32 bytes_received;
+
+ bytes_received = prtd->bytes_received;
+
+ /**
+ * Make sure that next track data pointer is aligned at 32 bit boundary
+ * This is a Mandatory requirement from DSP data buffers alignment
+ */
+ if (prtd->next_track)
+ bytes_received = ALIGN(prtd->bytes_received, prtd->pcm_count);
+
+ app_pointer = bytes_received/prtd->pcm_size;
+ app_pointer = bytes_received - (app_pointer * prtd->pcm_size);
+ dstn = prtd->dma_buffer.area + app_pointer;
+
+ if (count < prtd->pcm_size - app_pointer) {
+ if (copy_from_user(dstn, buf, count))
+ return -EFAULT;
+ } else {
+ copy = prtd->pcm_size - app_pointer;
+ if (copy_from_user(dstn, buf, copy))
+ return -EFAULT;
+ if (copy_from_user(prtd->dma_buffer.area, buf + copy,
+ count - copy))
+ return -EFAULT;
+ }
spin_lock_irqsave(&prtd->lock, flags);
- prtd->bytes_received += count;
+
+ bytes_in_flight = prtd->bytes_received - prtd->copied_total;
+
+ if (prtd->next_track) {
+ prtd->next_track = false;
+ prtd->copied_total = ALIGN(prtd->copied_total, prtd->pcm_count);
+ prtd->bytes_sent = ALIGN(prtd->bytes_sent, prtd->pcm_count);
+ }
+
+ prtd->bytes_received = bytes_received + count;
+
+ /* Kick off the data to dsp if its starving!! */
+ if (prtd->state == Q6ASM_STREAM_RUNNING && (bytes_in_flight == 0)) {
+ uint32_t bytes_to_write = prtd->pcm_count;
+
+ avail = prtd->bytes_received - prtd->bytes_sent;
+
+ if (avail < prtd->pcm_count)
+ bytes_to_write = avail;
+
+ q6asm_write_async(prtd->audio_client, prtd->stream_id,
+ bytes_to_write, 0, 0, wflags);
+ prtd->bytes_sent += bytes_to_write;
+ }
+
spin_unlock_irqrestore(&prtd->lock, flags);
return count;
@@ -954,12 +1173,13 @@ static struct snd_compress_ops q6asm_dai_compress_ops = {
.open = q6asm_dai_compr_open,
.free = q6asm_dai_compr_free,
.set_params = q6asm_dai_compr_set_params,
+ .set_metadata = q6asm_dai_compr_set_metadata,
.pointer = q6asm_dai_compr_pointer,
.trigger = q6asm_dai_compr_trigger,
.get_caps = q6asm_dai_compr_get_caps,
.get_codec_caps = q6asm_dai_compr_get_codec_caps,
.mmap = q6asm_dai_compr_mmap,
- .ack = q6asm_dai_compr_ack,
+ .copy = q6asm_compr_copy,
};
static int q6asm_dai_pcm_new(struct snd_soc_component *component,
diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
index 755062eadcc8..d745a02fcd5f 100644
--- a/sound/soc/qcom/qdsp6/q6asm.c
+++ b/sound/soc/qcom/qdsp6/q6asm.c
@@ -51,6 +51,8 @@
#define ASM_STREAM_CMD_OPEN_READWRITE_V2 0x00010D8D
#define ASM_MEDIA_FMT_ALAC 0x00012f31
#define ASM_MEDIA_FMT_APE 0x00012f32
+#define ASM_DATA_CMD_REMOVE_INITIAL_SILENCE 0x00010D67
+#define ASM_DATA_CMD_REMOVE_TRAILING_SILENCE 0x00010D68
#define ASM_LEGACY_STREAM_SESSION 0
@@ -270,7 +272,6 @@ struct audio_client {
wait_queue_head_t cmd_wait;
struct aprv2_ibasic_rsp_result_t result;
int perf_mode;
- int stream_id;
struct q6asm *q6asm;
struct device *dev;
};
@@ -640,6 +641,8 @@ static int32_t q6asm_stream_callback(struct apr_device *adev,
case ASM_STREAM_CMD_OPEN_READWRITE_V2:
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
+ case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
+ case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:
if (result->status != 0) {
dev_err(ac->dev,
"cmd = 0x%x returned error = 0x%x\n",
@@ -671,6 +674,7 @@ static int32_t q6asm_stream_callback(struct apr_device *adev,
if (ac->io_mode & ASM_SYNC_IO_MODE) {
phys_addr_t phys;
unsigned long flags;
+ int token = hdr->token & ASM_WRITE_TOKEN_MASK;
spin_lock_irqsave(&ac->lock, flags);
@@ -682,12 +686,12 @@ static int32_t q6asm_stream_callback(struct apr_device *adev,
goto done;
}
- phys = port->buf[hdr->token].phys;
+ phys = port->buf[token].phys;
if (lower_32_bits(phys) != result->opcode ||
upper_32_bits(phys) != result->status) {
dev_err(ac->dev, "Expected addr %pa\n",
- &port->buf[hdr->token].phys);
+ &port->buf[token].phys);
spin_unlock_irqrestore(&ac->lock, flags);
ret = -EINVAL;
goto done;
@@ -828,21 +832,21 @@ EXPORT_SYMBOL_GPL(q6asm_get_session_id);
* @dev: Pointer to asm child device.
* @cb: event callback.
* @priv: private data associated with this client.
- * @stream_id: stream id
+ * @session_id: session id
* @perf_mode: performace mode for this client
*
* Return: Will be an error pointer on error or a valid audio client
* on success.
*/
struct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb,
- void *priv, int stream_id,
+ void *priv, int session_id,
int perf_mode)
{
struct q6asm *a = dev_get_drvdata(dev->parent);
struct audio_client *ac;
unsigned long flags;
- ac = q6asm_get_audio_client(a, stream_id + 1);
+ ac = q6asm_get_audio_client(a, session_id + 1);
if (ac) {
dev_err(dev, "Audio Client already active\n");
return ac;
@@ -853,17 +857,15 @@ struct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb,
return ERR_PTR(-ENOMEM);
spin_lock_irqsave(&a->slock, flags);
- a->session[stream_id + 1] = ac;
+ a->session[session_id + 1] = ac;
spin_unlock_irqrestore(&a->slock, flags);
- ac->session = stream_id + 1;
+ ac->session = session_id + 1;
ac->cb = cb;
ac->dev = dev;
ac->q6asm = a;
ac->priv = priv;
ac->io_mode = ASM_SYNC_IO_MODE;
ac->perf_mode = perf_mode;
- /* DSP expects stream id from 1 */
- ac->stream_id = 1;
ac->adev = a->adev;
kref_init(&ac->refcount);
@@ -919,8 +921,9 @@ err:
*
* Return: Will be an negative value on error or zero on success
*/
-int q6asm_open_write(struct audio_client *ac, uint32_t format,
- u32 codec_profile, uint16_t bits_per_sample)
+int q6asm_open_write(struct audio_client *ac, uint32_t stream_id,
+ uint32_t format, u32 codec_profile,
+ uint16_t bits_per_sample, bool is_gapless)
{
struct asm_stream_cmd_open_write_v3 *open;
struct apr_pkt *pkt;
@@ -935,11 +938,13 @@ int q6asm_open_write(struct audio_client *ac, uint32_t format,
pkt = p;
open = p + APR_HDR_SIZE;
- q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+ q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
open->mode_flags = 0x00;
open->mode_flags |= ASM_LEGACY_STREAM_SESSION;
+ if (is_gapless)
+ open->mode_flags |= BIT(ASM_SHIFT_GAPLESS_MODE_FLAG);
/* source endpoint : matrix */
open->sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;
@@ -998,8 +1003,9 @@ err:
}
EXPORT_SYMBOL_GPL(q6asm_open_write);
-static int __q6asm_run(struct audio_client *ac, uint32_t flags,
- uint32_t msw_ts, uint32_t lsw_ts, bool wait)
+static int __q6asm_run(struct audio_client *ac, uint32_t stream_id,
+ uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts,
+ bool wait)
{
struct asm_session_cmd_run_v2 *run;
struct apr_pkt *pkt;
@@ -1014,7 +1020,7 @@ static int __q6asm_run(struct audio_client *ac, uint32_t flags,
pkt = p;
run = p + APR_HDR_SIZE;
- q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+ q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
pkt->hdr.opcode = ASM_SESSION_CMD_RUN_V2;
run->flags = flags;
@@ -1042,10 +1048,10 @@ static int __q6asm_run(struct audio_client *ac, uint32_t flags,
*
* Return: Will be an negative value on error or zero on success
*/
-int q6asm_run(struct audio_client *ac, uint32_t flags,
+int q6asm_run(struct audio_client *ac, uint32_t stream_id, uint32_t flags,
uint32_t msw_ts, uint32_t lsw_ts)
{
- return __q6asm_run(ac, flags, msw_ts, lsw_ts, true);
+ return __q6asm_run(ac, stream_id, flags, msw_ts, lsw_ts, true);
}
EXPORT_SYMBOL_GPL(q6asm_run);
@@ -1053,16 +1059,17 @@ EXPORT_SYMBOL_GPL(q6asm_run);
* q6asm_run_nowait() - start the audio client withou blocking
*
* @ac: audio client pointer
+ * @stream_id: stream id
* @flags: flags associated with write
* @msw_ts: timestamp msw
* @lsw_ts: timestamp lsw
*
* Return: Will be an negative value on error or zero on success
*/
-int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
- uint32_t msw_ts, uint32_t lsw_ts)
+int q6asm_run_nowait(struct audio_client *ac, uint32_t stream_id,
+ uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts)
{
- return __q6asm_run(ac, flags, msw_ts, lsw_ts, false);
+ return __q6asm_run(ac, stream_id, flags, msw_ts, lsw_ts, false);
}
EXPORT_SYMBOL_GPL(q6asm_run_nowait);
@@ -1070,6 +1077,7 @@ EXPORT_SYMBOL_GPL(q6asm_run_nowait);
* q6asm_media_format_block_multi_ch_pcm() - setup pcm configuration
*
* @ac: audio client pointer
+ * @stream_id: stream id
* @rate: audio sample rate
* @channels: number of audio channels.
* @channel_map: channel map pointer
@@ -1078,6 +1086,7 @@ EXPORT_SYMBOL_GPL(q6asm_run_nowait);
* Return: Will be an negative value on error or zero on success
*/
int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
+ uint32_t stream_id,
uint32_t rate, uint32_t channels,
u8 channel_map[PCM_MAX_NUM_CHANNEL],
uint16_t bits_per_sample)
@@ -1096,7 +1105,7 @@ int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
pkt = p;
fmt = p + APR_HDR_SIZE;
- q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+ q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
@@ -1125,8 +1134,8 @@ err:
}
EXPORT_SYMBOL_GPL(q6asm_media_format_block_multi_ch_pcm);
-
int q6asm_stream_media_format_block_flac(struct audio_client *ac,
+ uint32_t stream_id,
struct q6asm_flac_cfg *cfg)
{
struct asm_flac_fmt_blk_v2 *fmt;
@@ -1142,7 +1151,7 @@ int q6asm_stream_media_format_block_flac(struct audio_client *ac,
pkt = p;
fmt = p + APR_HDR_SIZE;
- q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+ q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
@@ -1163,6 +1172,7 @@ int q6asm_stream_media_format_block_flac(struct audio_client *ac,
EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_flac);
int q6asm_stream_media_format_block_wma_v9(struct audio_client *ac,
+ uint32_t stream_id,
struct q6asm_wma_cfg *cfg)
{
struct asm_wmastdv9_fmt_blk_v2 *fmt;
@@ -1178,7 +1188,7 @@ int q6asm_stream_media_format_block_wma_v9(struct audio_client *ac,
pkt = p;
fmt = p + APR_HDR_SIZE;
- q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+ q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
@@ -1200,6 +1210,7 @@ int q6asm_stream_media_format_block_wma_v9(struct audio_client *ac,
EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_wma_v9);
int q6asm_stream_media_format_block_wma_v10(struct audio_client *ac,
+ uint32_t stream_id,
struct q6asm_wma_cfg *cfg)
{
struct asm_wmaprov10_fmt_blk_v2 *fmt;
@@ -1215,7 +1226,7 @@ int q6asm_stream_media_format_block_wma_v10(struct audio_client *ac,
pkt = p;
fmt = p + APR_HDR_SIZE;
- q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+ q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
@@ -1238,6 +1249,7 @@ int q6asm_stream_media_format_block_wma_v10(struct audio_client *ac,
EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_wma_v10);
int q6asm_stream_media_format_block_alac(struct audio_client *ac,
+ uint32_t stream_id,
struct q6asm_alac_cfg *cfg)
{
struct asm_alac_fmt_blk_v2 *fmt;
@@ -1253,7 +1265,7 @@ int q6asm_stream_media_format_block_alac(struct audio_client *ac,
pkt = p;
fmt = p + APR_HDR_SIZE;
- q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+ q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
@@ -1279,6 +1291,7 @@ int q6asm_stream_media_format_block_alac(struct audio_client *ac,
EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_alac);
int q6asm_stream_media_format_block_ape(struct audio_client *ac,
+ uint32_t stream_id,
struct q6asm_ape_cfg *cfg)
{
struct asm_ape_fmt_blk_v2 *fmt;
@@ -1294,7 +1307,7 @@ int q6asm_stream_media_format_block_ape(struct audio_client *ac,
pkt = p;
fmt = p + APR_HDR_SIZE;
- q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+ q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
@@ -1317,10 +1330,60 @@ int q6asm_stream_media_format_block_ape(struct audio_client *ac,
}
EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_ape);
+static int q6asm_stream_remove_silence(struct audio_client *ac, uint32_t stream_id,
+ uint32_t cmd,
+ uint32_t num_samples)
+{
+ uint32_t *samples;
+ struct apr_pkt *pkt;
+ void *p;
+ int rc, pkt_size;
+
+ pkt_size = APR_HDR_SIZE + sizeof(uint32_t);
+ p = kzalloc(pkt_size, GFP_ATOMIC);
+ if (!p)
+ return -ENOMEM;
+
+ pkt = p;
+ samples = p + APR_HDR_SIZE;
+
+ q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
+
+ pkt->hdr.opcode = cmd;
+ *samples = num_samples;
+ rc = apr_send_pkt(ac->adev, pkt);
+ if (rc == pkt_size)
+ rc = 0;
+
+ kfree(pkt);
+
+ return rc;
+}
+
+int q6asm_stream_remove_initial_silence(struct audio_client *ac,
+ uint32_t stream_id,
+ uint32_t initial_samples)
+{
+ return q6asm_stream_remove_silence(ac, stream_id,
+ ASM_DATA_CMD_REMOVE_INITIAL_SILENCE,
+ initial_samples);
+}
+EXPORT_SYMBOL_GPL(q6asm_stream_remove_initial_silence);
+
+int q6asm_stream_remove_trailing_silence(struct audio_client *ac, uint32_t stream_id,
+ uint32_t trailing_samples)
+{
+ return q6asm_stream_remove_silence(ac, stream_id,
+ ASM_DATA_CMD_REMOVE_TRAILING_SILENCE,
+ trailing_samples);
+}
+EXPORT_SYMBOL_GPL(q6asm_stream_remove_trailing_silence);
+
/**
* q6asm_enc_cfg_blk_pcm_format_support() - setup pcm configuration for capture
*
* @ac: audio client pointer
+ * @stream_id: stream id
* @rate: audio sample rate
* @channels: number of audio channels.
* @bits_per_sample: bits per sample
@@ -1328,7 +1391,9 @@ EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_ape);
* Return: Will be an negative value on error or zero on success
*/
int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
- uint32_t rate, uint32_t channels, uint16_t bits_per_sample)
+ uint32_t stream_id, uint32_t rate,
+ uint32_t channels,
+ uint16_t bits_per_sample)
{
struct asm_multi_channel_pcm_enc_cfg_v2 *enc_cfg;
struct apr_pkt *pkt;
@@ -1344,7 +1409,7 @@ int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
pkt = p;
enc_cfg = p + APR_HDR_SIZE;
- q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+ q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
pkt->hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
enc_cfg->encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
@@ -1376,10 +1441,11 @@ EXPORT_SYMBOL_GPL(q6asm_enc_cfg_blk_pcm_format_support);
* q6asm_read() - read data of period size from audio client
*
* @ac: audio client pointer
+ * @stream_id: stream id
*
* Return: Will be an negative value on error or zero on success
*/
-int q6asm_read(struct audio_client *ac)
+int q6asm_read(struct audio_client *ac, uint32_t stream_id)
{
struct asm_data_cmd_read_v2 *read;
struct audio_port_data *port;
@@ -1400,7 +1466,7 @@ int q6asm_read(struct audio_client *ac)
spin_lock_irqsave(&ac->lock, flags);
port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
- q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, ac->stream_id);
+ q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, stream_id);
ab = &port->buf[port->dsp_buf];
pkt->hdr.opcode = ASM_DATA_CMD_READ_V2;
read->buf_addr_lsw = lower_32_bits(ab->phys);
@@ -1428,7 +1494,7 @@ int q6asm_read(struct audio_client *ac)
}
EXPORT_SYMBOL_GPL(q6asm_read);
-static int __q6asm_open_read(struct audio_client *ac,
+static int __q6asm_open_read(struct audio_client *ac, uint32_t stream_id,
uint32_t format, uint16_t bits_per_sample)
{
struct asm_stream_cmd_open_read_v3 *open;
@@ -1444,7 +1510,7 @@ static int __q6asm_open_read(struct audio_client *ac,
pkt = p;
open = p + APR_HDR_SIZE;
- q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+ q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3;
/* Stream prio : High, provide meta info with encoded frames */
open->src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
@@ -1475,15 +1541,16 @@ static int __q6asm_open_read(struct audio_client *ac,
* q6asm_open_read() - Open audio client for reading
*
* @ac: audio client pointer
+ * @stream_id: stream id
* @format: audio sample format
* @bits_per_sample: bits per sample
*
* Return: Will be an negative value on error or zero on success
*/
-int q6asm_open_read(struct audio_client *ac, uint32_t format,
- uint16_t bits_per_sample)
+int q6asm_open_read(struct audio_client *ac, uint32_t stream_id,
+ uint32_t format, uint16_t bits_per_sample)
{
- return __q6asm_open_read(ac, format, bits_per_sample);
+ return __q6asm_open_read(ac, stream_id, format, bits_per_sample);
}
EXPORT_SYMBOL_GPL(q6asm_open_read);
@@ -1491,6 +1558,7 @@ EXPORT_SYMBOL_GPL(q6asm_open_read);
* q6asm_write_async() - non blocking write
*
* @ac: audio client pointer
+ * @stream_id: stream id
* @len: length in bytes
* @msw_ts: timestamp msw
* @lsw_ts: timestamp lsw
@@ -1498,8 +1566,8 @@ EXPORT_SYMBOL_GPL(q6asm_open_read);
*
* Return: Will be an negative value on error or zero on success
*/
-int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
- uint32_t lsw_ts, uint32_t wflags)
+int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len,
+ uint32_t msw_ts, uint32_t lsw_ts, uint32_t wflags)
{
struct asm_data_cmd_write_v2 *write;
struct audio_port_data *port;
@@ -1520,10 +1588,10 @@ int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
spin_lock_irqsave(&ac->lock, flags);
port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
- q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, ac->stream_id);
+ q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, stream_id);
ab = &port->buf[port->dsp_buf];
- pkt->hdr.token = port->dsp_buf;
+ pkt->hdr.token = port->dsp_buf | (len << ASM_WRITE_TOKEN_LEN_SHIFT);
pkt->hdr.opcode = ASM_DATA_CMD_WRITE_V2;
write->buf_addr_lsw = lower_32_bits(ab->phys);
write->buf_addr_msw = upper_32_bits(ab->phys);
@@ -1534,10 +1602,7 @@ int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
write->mem_map_handle =
ac->port[SNDRV_PCM_STREAM_PLAYBACK].mem_map_handle;
- if (wflags == NO_TIMESTAMP)
- write->flags = (wflags & 0x800000FF);
- else
- write->flags = (0x80000000 | wflags);
+ write->flags = wflags;
port->dsp_buf++;
@@ -1567,9 +1632,9 @@ static void q6asm_reset_buf_state(struct audio_client *ac)
spin_unlock_irqrestore(&ac->lock, flags);
}
-static int __q6asm_cmd(struct audio_client *ac, int cmd, bool wait)
+static int __q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd,
+ bool wait)
{
- int stream_id = ac->stream_id;
struct apr_pkt pkt;
int rc;
@@ -1616,13 +1681,14 @@ static int __q6asm_cmd(struct audio_client *ac, int cmd, bool wait)
* q6asm_cmd() - run cmd on audio client
*
* @ac: audio client pointer
+ * @stream_id: stream id
* @cmd: command to run on audio client.
*
* Return: Will be an negative value on error or zero on success
*/
-int q6asm_cmd(struct audio_client *ac, int cmd)
+int q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd)
{
- return __q6asm_cmd(ac, cmd, true);
+ return __q6asm_cmd(ac, stream_id, cmd, true);
}
EXPORT_SYMBOL_GPL(q6asm_cmd);
@@ -1630,13 +1696,14 @@ EXPORT_SYMBOL_GPL(q6asm_cmd);
* q6asm_cmd_nowait() - non blocking, run cmd on audio client
*
* @ac: audio client pointer
+ * @stream_id: stream id
* @cmd: command to run on audio client.
*
* Return: Will be an negative value on error or zero on success
*/
-int q6asm_cmd_nowait(struct audio_client *ac, int cmd)
+int q6asm_cmd_nowait(struct audio_client *ac, uint32_t stream_id, int cmd)
{
- return __q6asm_cmd(ac, cmd, false);
+ return __q6asm_cmd(ac, stream_id, cmd, false);
}
EXPORT_SYMBOL_GPL(q6asm_cmd_nowait);
diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h
index 38a207d6cd95..82e584aa534f 100644
--- a/sound/soc/qcom/qdsp6/q6asm.h
+++ b/sound/soc/qcom/qdsp6/q6asm.h
@@ -20,6 +20,9 @@
#define ASM_CLIENT_EVENT_CMD_RUN_DONE 0x1008
#define ASM_CLIENT_EVENT_DATA_WRITE_DONE 0x1009
#define ASM_CLIENT_EVENT_DATA_READ_DONE 0x100a
+#define ASM_WRITE_TOKEN_MASK GENMASK(15, 0)
+#define ASM_WRITE_TOKEN_LEN_MASK GENMASK(31, 16)
+#define ASM_WRITE_TOKEN_LEN_SHIFT 16
enum {
LEGACY_PCM_MODE = 0,
@@ -29,8 +32,8 @@ enum {
};
#define MAX_SESSIONS 8
-#define NO_TIMESTAMP 0xFF00
#define FORMAT_LINEAR_PCM 0x0000
+#define ASM_LAST_BUFFER_FLAG BIT(30)
struct q6asm_flac_cfg {
u32 sample_rate;
@@ -93,37 +96,53 @@ struct audio_client *q6asm_audio_client_alloc(struct device *dev,
q6asm_cb cb, void *priv,
int session_id, int perf_mode);
void q6asm_audio_client_free(struct audio_client *ac);
-int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
- uint32_t lsw_ts, uint32_t flags);
-int q6asm_open_write(struct audio_client *ac, uint32_t format,
- u32 codec_profile, uint16_t bits_per_sample);
+int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len,
+ uint32_t msw_ts, uint32_t lsw_ts, uint32_t flags);
+int q6asm_open_write(struct audio_client *ac, uint32_t stream_id,
+ uint32_t format, u32 codec_profile,
+ uint16_t bits_per_sample, bool is_gapless);
-int q6asm_open_read(struct audio_client *ac, uint32_t format,
- uint16_t bits_per_sample);
+int q6asm_open_read(struct audio_client *ac, uint32_t stream_id,
+ uint32_t format, uint16_t bits_per_sample);
int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
- uint32_t rate, uint32_t channels, uint16_t bits_per_sample);
-int q6asm_read(struct audio_client *ac);
+ uint32_t stream_id, uint32_t rate,
+ uint32_t channels,
+ uint16_t bits_per_sample);
+
+int q6asm_read(struct audio_client *ac, uint32_t stream_id);
int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
+ uint32_t stream_id,
uint32_t rate, uint32_t channels,
u8 channel_map[PCM_MAX_NUM_CHANNEL],
uint16_t bits_per_sample);
int q6asm_stream_media_format_block_flac(struct audio_client *ac,
+ uint32_t stream_id,
struct q6asm_flac_cfg *cfg);
int q6asm_stream_media_format_block_wma_v9(struct audio_client *ac,
+ uint32_t stream_id,
struct q6asm_wma_cfg *cfg);
int q6asm_stream_media_format_block_wma_v10(struct audio_client *ac,
+ uint32_t stream_id,
struct q6asm_wma_cfg *cfg);
int q6asm_stream_media_format_block_alac(struct audio_client *ac,
+ uint32_t stream_id,
struct q6asm_alac_cfg *cfg);
int q6asm_stream_media_format_block_ape(struct audio_client *ac,
+ uint32_t stream_id,
struct q6asm_ape_cfg *cfg);
-int q6asm_run(struct audio_client *ac, uint32_t flags, uint32_t msw_ts,
- uint32_t lsw_ts);
-int q6asm_run_nowait(struct audio_client *ac, uint32_t flags, uint32_t msw_ts,
- uint32_t lsw_ts);
-int q6asm_cmd(struct audio_client *ac, int cmd);
-int q6asm_cmd_nowait(struct audio_client *ac, int cmd);
+int q6asm_run(struct audio_client *ac, uint32_t stream_id, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts);
+int q6asm_run_nowait(struct audio_client *ac, uint32_t stream_id,
+ uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts);
+int q6asm_stream_remove_initial_silence(struct audio_client *ac,
+ uint32_t stream_id,
+ uint32_t initial_samples);
+int q6asm_stream_remove_trailing_silence(struct audio_client *ac,
+ uint32_t stream_id,
+ uint32_t trailing_samples);
+int q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd);
+int q6asm_cmd_nowait(struct audio_client *ac, uint32_t stream_id, int cmd);
int q6asm_get_session_id(struct audio_client *ac);
int q6asm_map_memory_regions(unsigned int dir,
struct audio_client *ac,
diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c
index 25d23e0266c7..b12539fae6ed 100644
--- a/sound/soc/qcom/qdsp6/q6routing.c
+++ b/sound/soc/qcom/qdsp6/q6routing.c
@@ -113,7 +113,19 @@
{ mix_name, "QUIN_TDM_TX_4", "QUIN_TDM_TX_4"}, \
{ mix_name, "QUIN_TDM_TX_5", "QUIN_TDM_TX_5"}, \
{ mix_name, "QUIN_TDM_TX_6", "QUIN_TDM_TX_6"}, \
- { mix_name, "QUIN_TDM_TX_7", "QUIN_TDM_TX_7"}
+ { mix_name, "QUIN_TDM_TX_7", "QUIN_TDM_TX_7"}, \
+ { mix_name, "WSA_CODEC_DMA_TX_0", "WSA_CODEC_DMA_TX_0"}, \
+ { mix_name, "WSA_CODEC_DMA_TX_1", "WSA_CODEC_DMA_TX_1"}, \
+ { mix_name, "WSA_CODEC_DMA_TX_2", "WSA_CODEC_DMA_TX_2"}, \
+ { mix_name, "VA_CODEC_DMA_TX_0", "VA_CODEC_DMA_TX_0"}, \
+ { mix_name, "VA_CODEC_DMA_TX_1", "VA_CODEC_DMA_TX_1"}, \
+ { mix_name, "VA_CODEC_DMA_TX_2", "VA_CODEC_DMA_TX_2"}, \
+ { mix_name, "TX_CODEC_DMA_TX_0", "TX_CODEC_DMA_TX_0"}, \
+ { mix_name, "TX_CODEC_DMA_TX_1", "TX_CODEC_DMA_TX_1"}, \
+ { mix_name, "TX_CODEC_DMA_TX_2", "TX_CODEC_DMA_TX_2"}, \
+ { mix_name, "TX_CODEC_DMA_TX_3", "TX_CODEC_DMA_TX_3"}, \
+ { mix_name, "TX_CODEC_DMA_TX_4", "TX_CODEC_DMA_TX_4"}, \
+ { mix_name, "TX_CODEC_DMA_TX_5", "TX_CODEC_DMA_TX_5"}
#define Q6ROUTING_TX_MIXERS(id) \
SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX, \
@@ -268,6 +280,42 @@
msm_routing_put_audio_mixer), \
SOC_SINGLE_EXT("QUIN_TDM_TX_7", QUINARY_TDM_TX_7, \
id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("WSA_CODEC_DMA_TX_0", WSA_CODEC_DMA_TX_0, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("WSA_CODEC_DMA_TX_1", WSA_CODEC_DMA_TX_1, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("WSA_CODEC_DMA_TX_2", WSA_CODEC_DMA_TX_2, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("VA_CODEC_DMA_TX_0", VA_CODEC_DMA_TX_0, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("VA_CODEC_DMA_TX_1", VA_CODEC_DMA_TX_1, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("VA_CODEC_DMA_TX_2", VA_CODEC_DMA_TX_2, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("TX_CODEC_DMA_TX_0", TX_CODEC_DMA_TX_0, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("TX_CODEC_DMA_TX_1", TX_CODEC_DMA_TX_1, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("TX_CODEC_DMA_TX_2", TX_CODEC_DMA_TX_2, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("TX_CODEC_DMA_TX_3", TX_CODEC_DMA_TX_3, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("TX_CODEC_DMA_TX_4", TX_CODEC_DMA_TX_4, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("TX_CODEC_DMA_TX_5", TX_CODEC_DMA_TX_5, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
msm_routing_put_audio_mixer),
struct session_data {
@@ -609,6 +657,36 @@ static const struct snd_kcontrol_new quin_tdm_rx_6_mixer_controls[] = {
static const struct snd_kcontrol_new quin_tdm_rx_7_mixer_controls[] = {
Q6ROUTING_RX_MIXERS(QUINARY_TDM_RX_7) };
+static const struct snd_kcontrol_new wsa_codec_dma_rx_0_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(WSA_CODEC_DMA_RX_0) };
+
+static const struct snd_kcontrol_new wsa_codec_dma_rx_1_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(WSA_CODEC_DMA_RX_1) };
+
+static const struct snd_kcontrol_new rx_codec_dma_rx_0_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(RX_CODEC_DMA_RX_0) };
+
+static const struct snd_kcontrol_new rx_codec_dma_rx_1_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(RX_CODEC_DMA_RX_1) };
+
+static const struct snd_kcontrol_new rx_codec_dma_rx_2_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(RX_CODEC_DMA_RX_2) };
+
+static const struct snd_kcontrol_new rx_codec_dma_rx_3_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(RX_CODEC_DMA_RX_3) };
+
+static const struct snd_kcontrol_new rx_codec_dma_rx_4_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(RX_CODEC_DMA_RX_4) };
+
+static const struct snd_kcontrol_new rx_codec_dma_rx_5_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(RX_CODEC_DMA_RX_5) };
+
+static const struct snd_kcontrol_new rxcodec_dma_rx_6_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(RX_CODEC_DMA_RX_6) };
+
+static const struct snd_kcontrol_new rx_codec_dma_rx_7_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(RX_CODEC_DMA_RX_7) };
+
static const struct snd_kcontrol_new mmul1_mixer_controls[] = {
Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA1) };
@@ -819,6 +897,37 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
SND_SOC_DAPM_MIXER("QUIN_TDM_RX_7 Audio Mixer", SND_SOC_NOPM, 0, 0,
quin_tdm_rx_7_mixer_controls,
ARRAY_SIZE(quin_tdm_rx_7_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("WSA_CODEC_DMA_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ wsa_codec_dma_rx_0_mixer_controls,
+ ARRAY_SIZE(wsa_codec_dma_rx_0_mixer_controls)),
+ SND_SOC_DAPM_MIXER("WSA_CODEC_DMA_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ wsa_codec_dma_rx_1_mixer_controls,
+ ARRAY_SIZE(wsa_codec_dma_rx_1_mixer_controls)),
+ SND_SOC_DAPM_MIXER("RX_CODEC_DMA_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ rx_codec_dma_rx_0_mixer_controls,
+ ARRAY_SIZE(rx_codec_dma_rx_0_mixer_controls)),
+ SND_SOC_DAPM_MIXER("RX_CODEC_DMA_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ rx_codec_dma_rx_1_mixer_controls,
+ ARRAY_SIZE(rx_codec_dma_rx_1_mixer_controls)),
+ SND_SOC_DAPM_MIXER("RX_CODEC_DMA_RX_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ rx_codec_dma_rx_2_mixer_controls,
+ ARRAY_SIZE(rx_codec_dma_rx_2_mixer_controls)),
+ SND_SOC_DAPM_MIXER("RX_CODEC_DMA_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ rx_codec_dma_rx_3_mixer_controls,
+ ARRAY_SIZE(rx_codec_dma_rx_3_mixer_controls)),
+ SND_SOC_DAPM_MIXER("RX_CODEC_DMA_RX_4 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ rx_codec_dma_rx_4_mixer_controls,
+ ARRAY_SIZE(rx_codec_dma_rx_4_mixer_controls)),
+ SND_SOC_DAPM_MIXER("RX_CODEC_DMA_RX_5 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ rx_codec_dma_rx_5_mixer_controls,
+ ARRAY_SIZE(rx_codec_dma_rx_5_mixer_controls)),
+ SND_SOC_DAPM_MIXER("RX_CODEC_DMA_RX_6 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ rxcodec_dma_rx_6_mixer_controls,
+ ARRAY_SIZE(rxcodec_dma_rx_6_mixer_controls)),
+ SND_SOC_DAPM_MIXER("RX_CODEC_DMA_RX_7 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ rx_codec_dma_rx_7_mixer_controls,
+ ARRAY_SIZE(rx_codec_dma_rx_7_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia1 Mixer", SND_SOC_NOPM, 0, 0,
mmul1_mixer_controls, ARRAY_SIZE(mmul1_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia2 Mixer", SND_SOC_NOPM, 0, 0,
@@ -901,6 +1010,16 @@ static const struct snd_soc_dapm_route intercon[] = {
Q6ROUTING_RX_DAPM_ROUTE("QUIN_TDM_RX_5 Audio Mixer", "QUIN_TDM_RX_5"),
Q6ROUTING_RX_DAPM_ROUTE("QUIN_TDM_RX_6 Audio Mixer", "QUIN_TDM_RX_6"),
Q6ROUTING_RX_DAPM_ROUTE("QUIN_TDM_RX_7 Audio Mixer", "QUIN_TDM_RX_7"),
+ Q6ROUTING_RX_DAPM_ROUTE("WSA_CODEC_DMA_RX_0 Audio Mixer", "WSA_CODEC_DMA_RX_0"),
+ Q6ROUTING_RX_DAPM_ROUTE("WSA_CODEC_DMA_RX_1 Audio Mixer", "WSA_CODEC_DMA_RX_1"),
+ Q6ROUTING_RX_DAPM_ROUTE("RX_CODEC_DMA_RX_0 Audio Mixer", "RX_CODEC_DMA_RX_0"),
+ Q6ROUTING_RX_DAPM_ROUTE("RX_CODEC_DMA_RX_1 Audio Mixer", "RX_CODEC_DMA_RX_1"),
+ Q6ROUTING_RX_DAPM_ROUTE("RX_CODEC_DMA_RX_2 Audio Mixer", "RX_CODEC_DMA_RX_2"),
+ Q6ROUTING_RX_DAPM_ROUTE("RX_CODEC_DMA_RX_3 Audio Mixer", "RX_CODEC_DMA_RX_3"),
+ Q6ROUTING_RX_DAPM_ROUTE("RX_CODEC_DMA_RX_4 Audio Mixer", "RX_CODEC_DMA_RX_4"),
+ Q6ROUTING_RX_DAPM_ROUTE("RX_CODEC_DMA_RX_5 Audio Mixer", "RX_CODEC_DMA_RX_5"),
+ Q6ROUTING_RX_DAPM_ROUTE("RX_CODEC_DMA_RX_6 Audio Mixer", "RX_CODEC_DMA_RX_6"),
+ Q6ROUTING_RX_DAPM_ROUTE("RX_CODEC_DMA_RX_7 Audio Mixer", "RX_CODEC_DMA_RX_7"),
Q6ROUTING_TX_DAPM_ROUTE("MultiMedia1 Mixer"),
Q6ROUTING_TX_DAPM_ROUTE("MultiMedia2 Mixer"),
Q6ROUTING_TX_DAPM_ROUTE("MultiMedia3 Mixer"),
diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c
new file mode 100644
index 000000000000..d1e4f621a538
--- /dev/null
+++ b/sound/soc/qcom/sm8250.c
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2020, Linaro Limited
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <linux/soundwire/sdw.h>
+#include "qdsp6/q6afe.h"
+#include "common.h"
+
+#define MI2S_BCLK_RATE 1536000
+#define DEFAULT_MCLK_RATE 24576000
+#define MAX_WSA_PORTS 16
+
+struct sm8250_snd_data {
+ bool stream_prepared[MAX_WSA_PORTS];
+ struct snd_soc_card *card;
+ struct sdw_stream_runtime *sruntime[MAX_WSA_PORTS];
+};
+
+static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ return 0;
+}
+
+static int sm8250_snd_startup(struct snd_pcm_substream *substream)
+{
+ unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+
+ switch (cpu_dai->id) {
+ case TERTIARY_MI2S_RX:
+ codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF;
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT,
+ MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+ snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int sm8250_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct sm8250_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);
+ struct sdw_stream_runtime *sruntime;
+ int i;
+
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ sruntime = snd_soc_dai_get_sdw_stream(codec_dai,
+ substream->stream);
+ if (sruntime != ERR_PTR(-ENOTSUPP))
+ pdata->sruntime[cpu_dai->id] = sruntime;
+ }
+
+ return 0;
+
+}
+
+static int sm8250_snd_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
+ struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
+ int ret;
+
+ if (!sruntime)
+ return 0;
+
+ if (data->stream_prepared[cpu_dai->id]) {
+ sdw_disable_stream(sruntime);
+ sdw_deprepare_stream(sruntime);
+ data->stream_prepared[cpu_dai->id] = false;
+ }
+
+ ret = sdw_prepare_stream(sruntime);
+ if (ret)
+ return ret;
+
+ /**
+ * NOTE: there is a strict hw requirement about the ordering of port
+ * enables and actual WSA881x PA enable. PA enable should only happen
+ * after soundwire ports are enabled if not DC on the line is
+ * accumulated resulting in Click/Pop Noise
+ * PA enable/mute are handled as part of codec DAPM and digital mute.
+ */
+
+ ret = sdw_enable_stream(sruntime);
+ if (ret) {
+ sdw_deprepare_stream(sruntime);
+ return ret;
+ }
+ data->stream_prepared[cpu_dai->id] = true;
+
+ return ret;
+}
+
+static int sm8250_snd_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
+
+ if (sruntime && data->stream_prepared[cpu_dai->id]) {
+ sdw_disable_stream(sruntime);
+ sdw_deprepare_stream(sruntime);
+ data->stream_prepared[cpu_dai->id] = false;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_ops sm8250_be_ops = {
+ .startup = sm8250_snd_startup,
+ .hw_params = sm8250_snd_hw_params,
+ .hw_free = sm8250_snd_hw_free,
+ .prepare = sm8250_snd_prepare,
+};
+
+static void sm8250_add_be_ops(struct snd_soc_card *card)
+{
+ struct snd_soc_dai_link *link;
+ int i;
+
+ for_each_card_prelinks(card, i, link) {
+ if (link->no_pcm == 1) {
+ link->be_hw_params_fixup = sm8250_be_hw_params_fixup;
+ link->ops = &sm8250_be_ops;
+ }
+ }
+}
+
+static int sm8250_platform_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card;
+ struct sm8250_snd_data *data;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ /* Allocate the private data */
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ card->dev = dev;
+ dev_set_drvdata(dev, card);
+ snd_soc_card_set_drvdata(card, data);
+ ret = qcom_snd_parse_of(card);
+ if (ret)
+ return ret;
+
+ sm8250_add_be_ops(card);
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static const struct of_device_id snd_sm8250_dt_match[] = {
+ {.compatible = "qcom,sm8250-sndcard"},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, snd_sm8250_dt_match);
+
+static struct platform_driver snd_sm8250_driver = {
+ .probe = sm8250_platform_probe,
+ .driver = {
+ .name = "snd-sm8250",
+ .of_match_table = snd_sm8250_dt_match,
+ },
+};
+module_platform_driver(snd_sm8250_driver);
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
+MODULE_DESCRIPTION("SM8250 ASoC Machine Driver");
+MODULE_LICENSE("GPL v2");