Merge "asoc: codecs: bolero: Add support to disable aux hpf"
diff --git a/asoc/codecs/bolero/bolero-cdc.c b/asoc/codecs/bolero/bolero-cdc.c
index 6f81dab..76c9d40 100644
--- a/asoc/codecs/bolero/bolero-cdc.c
+++ b/asoc/codecs/bolero/bolero-cdc.c
@@ -504,6 +504,8 @@
if (macro_id == TX_MACRO) {
priv->macro_params[macro_id].reg_wake_irq = ops->reg_wake_irq;
priv->macro_params[macro_id].clk_switch = ops->clk_switch;
+ priv->macro_params[macro_id].reg_evt_listener =
+ ops->reg_evt_listener;
}
priv->num_dais += ops->num_dais;
@@ -567,6 +569,7 @@
if (macro_id == TX_MACRO) {
priv->macro_params[macro_id].reg_wake_irq = NULL;
priv->macro_params[macro_id].clk_switch = NULL;
+ priv->macro_params[macro_id].reg_evt_listener = NULL;
}
priv->num_dais -= priv->macro_params[macro_id].num_dais;
@@ -578,6 +581,29 @@
}
EXPORT_SYMBOL(bolero_unregister_macro);
+void bolero_wsa_pa_on(struct device *dev)
+{
+ struct bolero_priv *priv;
+
+ if (!dev) {
+ pr_err("%s: dev is null\n", __func__);
+ return;
+ }
+ if (!bolero_is_valid_child_dev(dev)) {
+ dev_err(dev, "%s: not a valid child dev\n",
+ __func__);
+ return;
+ }
+ priv = dev_get_drvdata(dev->parent);
+ if (!priv) {
+ dev_err(dev, "%s: priv is null\n", __func__);
+ return;
+ }
+
+ bolero_cdc_notifier_call(priv, BOLERO_WCD_EVT_PA_ON_POST_FSCLK);
+}
+EXPORT_SYMBOL(bolero_wsa_pa_on);
+
static ssize_t bolero_version_read(struct snd_info_entry *entry,
void *file_private_data,
struct file *file,
@@ -803,6 +829,41 @@
}
EXPORT_SYMBOL(bolero_tx_clk_switch);
+/**
+ * bolero_register_event_listener - Register/Deregister to event listener
+ *
+ * @component: pointer to codec component instance.
+ * @enable: when set to 1 registers to event listener otherwise, derigisters
+ * from the event listener
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int bolero_register_event_listener(struct snd_soc_component *component,
+ bool enable)
+{
+ struct bolero_priv *priv = NULL;
+ int ret = 0;
+
+ if (!component)
+ return -EINVAL;
+
+ priv = snd_soc_component_get_drvdata(component);
+ if (!priv)
+ return -EINVAL;
+
+ if (!bolero_is_valid_codec_dev(priv->dev)) {
+ dev_err(component->dev, "%s: invalid codec\n", __func__);
+ return -EINVAL;
+ }
+
+ if (priv->macro_params[TX_MACRO].reg_evt_listener)
+ ret = priv->macro_params[TX_MACRO].reg_evt_listener(component,
+ enable);
+
+ return ret;
+}
+EXPORT_SYMBOL(bolero_register_event_listener);
+
static int bolero_soc_codec_probe(struct snd_soc_component *component)
{
struct bolero_priv *priv = dev_get_drvdata(component->dev);
diff --git a/asoc/codecs/bolero/bolero-cdc.h b/asoc/codecs/bolero/bolero-cdc.h
index 7e8ec83..957389c 100644
--- a/asoc/codecs/bolero/bolero-cdc.h
+++ b/asoc/codecs/bolero/bolero-cdc.h
@@ -56,6 +56,7 @@
int (*set_port_map)(struct snd_soc_component *component, u32 uc,
u32 size, void *data);
int (*clk_switch)(struct snd_soc_component *component);
+ int (*reg_evt_listener)(struct snd_soc_component *component, bool en);
char __iomem *io_base;
u16 clk_id_req;
u16 default_clk_id;
@@ -80,6 +81,9 @@
int bolero_runtime_suspend(struct device *dev);
int bolero_set_port_map(struct snd_soc_component *component, u32 size, void *data);
int bolero_tx_clk_switch(struct snd_soc_component *component);
+int bolero_register_event_listener(struct snd_soc_component *component,
+ bool enable);
+void bolero_wsa_pa_on(struct device *dev);
#else
static inline int bolero_register_res_clk(struct device *dev, rsc_clk_cb_t cb)
{
@@ -144,5 +148,15 @@
return 0;
}
+static inline int bolero_register_event_listener(
+ struct snd_soc_component *component,
+ bool enable)
+{
+ return 0;
+}
+
+static void bolero_wsa_pa_on(struct device *dev)
+{
+}
#endif /* CONFIG_SND_SOC_BOLERO */
#endif /* BOLERO_CDC_H */
diff --git a/asoc/codecs/bolero/internal.h b/asoc/codecs/bolero/internal.h
index d353a2d..d3f6894 100644
--- a/asoc/codecs/bolero/internal.h
+++ b/asoc/codecs/bolero/internal.h
@@ -15,6 +15,7 @@
BOLERO_WCD_EVT_PA_OFF_PRE_SSR,
BOLERO_WCD_EVT_SSR_DOWN,
BOLERO_WCD_EVT_SSR_UP,
+ BOLERO_WCD_EVT_PA_ON_POST_FSCLK,
};
enum {
diff --git a/asoc/codecs/bolero/rx-macro.c b/asoc/codecs/bolero/rx-macro.c
index 9a226c3..924771a 100644
--- a/asoc/codecs/bolero/rx-macro.c
+++ b/asoc/codecs/bolero/rx-macro.c
@@ -372,6 +372,7 @@
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),
@@ -921,9 +922,9 @@
inp0_sel = int_mux_cfg0_val & 0x0F;
inp1_sel = (int_mux_cfg0_val >> 4) & 0x0F;
inp2_sel = (int_mux_cfg1_val >> 4) & 0x0F;
- if ((inp0_sel == int_1_mix1_inp) ||
- (inp1_sel == int_1_mix1_inp) ||
- (inp2_sel == int_1_mix1_inp)) {
+ 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_RX_RX0_RX_PATH_CTL +
0x80 * j;
pr_debug("%s: AIF_PB DAI(%d) connected to INT%u_1\n",
@@ -972,7 +973,8 @@
int_mux_cfg1_val = snd_soc_component_read32(
component, int_mux_cfg1) &
0x0F;
- if (int_mux_cfg1_val == int_2_inp) {
+ if (int_mux_cfg1_val == int_2_inp +
+ INTn_2_INP_SEL_RX0) {
int_fs_reg = BOLERO_CDC_RX_RX0_RX_PATH_MIX_CTL +
0x80 * j;
pr_debug("%s: AIF_PB DAI(%d) connected to INT%u_2\n",
@@ -1100,8 +1102,26 @@
if (++i == RX_MACRO_MAX_DMA_CH_PER_PORT)
break;
}
+ /*
+ * CDC_DMA_RX_0 port drives RX0/RX1 -- ch_mask 0x1/0x2/0x3
+ * CDC_DMA_RX_1 port drives RX2/RX3 -- ch_mask 0x1/0x2/0x3
+ * CDC_DMA_RX_2 port drives RX4 -- ch_mask 0x1
+ * CDC_DMA_RX_3 port drives RX5 -- ch_mask 0x1
+ * AIFn can pair to any CDC_DMA_RX_n port.
+ * In general, below convention is used::
+ * CDC_DMA_RX_0(AIF1)/CDC_DMA_RX_1(AIF2)/
+ * CDC_DMA_RX_2(AIF3)/CDC_DMA_RX_3(AIF4)
+ * Above is reflected in machine driver BE dailink
+ */
+ if (ch_mask & 0x0C)
+ ch_mask = ch_mask >> 2;
+ if ((ch_mask & 0x10) || (ch_mask & 0x20))
+ ch_mask = 0x1;
*rx_slot = ch_mask;
*rx_num = rx_priv->active_ch_cnt[dai->id];
+ dev_dbg(rx_priv->dev,
+ "%s: dai->id:%d, ch_mask:0x%x, active_ch_cnt:%d active_mask: 0x%x\n",
+ __func__, dai->id, *rx_slot, *rx_num, rx_priv->active_ch_mask[dai->id]);
break;
case RX_MACRO_AIF_ECHO:
val = snd_soc_component_read32(component,
@@ -1169,9 +1189,12 @@
if (int_mux_cfg0_val || (int_mux_cfg1_val & 0xF0))
snd_soc_component_update_bits(component,
reg, 0x20, 0x20);
- if (int_mux_cfg1_val & 0x0F)
+ if (int_mux_cfg1_val & 0x0F) {
+ snd_soc_component_update_bits(component,
+ reg, 0x20, 0x20);
snd_soc_component_update_bits(component,
mix_reg, 0x20, 0x20);
+ }
}
}
break;
@@ -3535,6 +3558,23 @@
{"RX INT2 MIX2 INP", "SRC1", "SRC1"},
};
+static int rx_macro_core_vote(void *handle, bool enable)
+{
+ struct rx_macro_priv *rx_priv = (struct rx_macro_priv *) handle;
+
+ if (rx_priv == NULL) {
+ pr_err("%s: rx priv data is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (enable) {
+ pm_runtime_get_sync(rx_priv->dev);
+ pm_runtime_put_autosuspend(rx_priv->dev);
+ pm_runtime_mark_last_busy(rx_priv->dev);
+ }
+
+ return 0;
+}
+
static int rx_swrm_clock(void *handle, bool enable)
{
struct rx_macro_priv *rx_priv = (struct rx_macro_priv *) handle;
@@ -3553,8 +3593,16 @@
if (enable) {
pm_runtime_get_sync(rx_priv->dev);
if (rx_priv->swr_clk_users == 0) {
- msm_cdc_pinctrl_select_active_state(
+ ret = msm_cdc_pinctrl_select_active_state(
rx_priv->rx_swr_gpio_p);
+ if (ret < 0) {
+ dev_err(rx_priv->dev,
+ "%s: rx swr pinctrl enable failed\n",
+ __func__);
+ pm_runtime_mark_last_busy(rx_priv->dev);
+ pm_runtime_put_autosuspend(rx_priv->dev);
+ goto exit;
+ }
ret = rx_macro_mclk_enable(rx_priv, 1, true);
if (ret < 0) {
msm_cdc_pinctrl_select_sleep_state(
@@ -3562,6 +3610,8 @@
dev_err(rx_priv->dev,
"%s: rx request clock enable failed\n",
__func__);
+ pm_runtime_mark_last_busy(rx_priv->dev);
+ pm_runtime_put_autosuspend(rx_priv->dev);
goto exit;
}
if (rx_priv->reset_swr)
@@ -3594,8 +3644,14 @@
BOLERO_CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
0x01, 0x00);
rx_macro_mclk_enable(rx_priv, 0, true);
- msm_cdc_pinctrl_select_sleep_state(
+ ret = msm_cdc_pinctrl_select_sleep_state(
rx_priv->rx_swr_gpio_p);
+ if (ret < 0) {
+ dev_err(rx_priv->dev,
+ "%s: rx swr pinctrl disable failed\n",
+ __func__);
+ goto exit;
+ }
}
}
dev_dbg(rx_priv->dev, "%s: swrm clock users %d\n",
@@ -3605,6 +3661,15 @@
return ret;
}
+static const struct rx_macro_reg_mask_val rx_macro_reg_init[] = {
+ {BOLERO_CDC_RX_RX0_RX_PATH_SEC7, 0x07, 0x02},
+ {BOLERO_CDC_RX_RX1_RX_PATH_SEC7, 0x07, 0x02},
+ {BOLERO_CDC_RX_RX2_RX_PATH_SEC7, 0x07, 0x02},
+ {BOLERO_CDC_RX_RX0_RX_PATH_CFG3, 0x03, 0x02},
+ {BOLERO_CDC_RX_RX1_RX_PATH_CFG3, 0x03, 0x02},
+ {BOLERO_CDC_RX_RX2_RX_PATH_CFG3, 0x03, 0x02},
+};
+
static void rx_macro_init_bcl_pmic_reg(struct snd_soc_component *component)
{
struct device *rx_dev = NULL;
@@ -3659,6 +3724,7 @@
int ret = 0;
struct device *rx_dev = NULL;
struct rx_macro_priv *rx_priv = NULL;
+ int i;
rx_dev = bolero_get_device_ptr(component->dev, RX_MACRO);
if (!rx_dev) {
@@ -3710,18 +3776,11 @@
snd_soc_dapm_ignore_suspend(dapm, "RX_TX DEC3_INP");
snd_soc_dapm_sync(dapm);
- snd_soc_component_update_bits(component, BOLERO_CDC_RX_RX0_RX_PATH_SEC7,
- 0x07, 0x02);
- snd_soc_component_update_bits(component, BOLERO_CDC_RX_RX1_RX_PATH_SEC7,
- 0x07, 0x02);
- snd_soc_component_update_bits(component, BOLERO_CDC_RX_RX2_RX_PATH_SEC7,
- 0x07, 0x02);
- snd_soc_component_update_bits(component, BOLERO_CDC_RX_RX0_RX_PATH_CFG3,
- 0x03, 0x02);
- snd_soc_component_update_bits(component, BOLERO_CDC_RX_RX1_RX_PATH_CFG3,
- 0x03, 0x02);
- snd_soc_component_update_bits(component, BOLERO_CDC_RX_RX2_RX_PATH_CFG3,
- 0x03, 0x02);
+ for (i = 0; i < ARRAY_SIZE(rx_macro_reg_init); i++)
+ snd_soc_component_update_bits(component,
+ rx_macro_reg_init[i].reg,
+ rx_macro_reg_init[i].mask,
+ rx_macro_reg_init[i].val);
rx_priv->component = component;
rx_macro_init_bcl_pmic_reg(component);
@@ -3918,7 +3977,8 @@
__func__);
return -EINVAL;
}
- if (msm_cdc_pinctrl_get_state(rx_priv->rx_swr_gpio_p) < 0) {
+ if (msm_cdc_pinctrl_get_state(rx_priv->rx_swr_gpio_p) < 0 &&
+ is_used_rx_swr_gpio) {
dev_err(&pdev->dev, "%s: failed to get swr pin state\n",
__func__);
return -EPROBE_DEFER;
@@ -3946,6 +4006,7 @@
rx_priv->swr_plat_data.write = NULL;
rx_priv->swr_plat_data.bulk_write = NULL;
rx_priv->swr_plat_data.clk = rx_swrm_clock;
+ rx_priv->swr_plat_data.core_vote = rx_macro_core_vote;
rx_priv->swr_plat_data.handle_irq = NULL;
ret = of_property_read_u8_array(pdev->dev.of_node,
diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c
index 8c32043..97d9f7e 100644
--- a/asoc/codecs/bolero/tx-macro.c
+++ b/asoc/codecs/bolero/tx-macro.c
@@ -72,6 +72,7 @@
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),
@@ -119,6 +120,12 @@
VA_MCLK,
};
+struct tx_macro_reg_mask_val {
+ u16 reg;
+ u8 mask;
+ u8 val;
+};
+
struct tx_mute_work {
struct tx_macro_priv *tx_priv;
u32 decimator;
@@ -1714,6 +1721,47 @@
tx_macro_get_bcs, tx_macro_set_bcs),
};
+static int tx_macro_register_event_listener(struct snd_soc_component *component,
+ bool enable)
+{
+ struct device *tx_dev = NULL;
+ struct tx_macro_priv *tx_priv = NULL;
+ int ret = 0;
+
+ if (!component)
+ return -EINVAL;
+
+ tx_dev = bolero_get_device_ptr(component->dev, TX_MACRO);
+ if (!tx_dev) {
+ dev_err(component->dev,
+ "%s: null device for macro!\n", __func__);
+ return -EINVAL;
+ }
+ tx_priv = dev_get_drvdata(tx_dev);
+ if (!tx_priv) {
+ dev_err(component->dev,
+ "%s: priv is null for macro!\n", __func__);
+ return -EINVAL;
+ }
+ if (tx_priv->swr_ctrl_data) {
+ if (enable) {
+ ret = swrm_wcd_notify(
+ tx_priv->swr_ctrl_data[0].tx_swr_pdev,
+ SWR_REGISTER_WAKEUP, NULL);
+ msm_cdc_pinctrl_set_wakeup_capable(
+ tx_priv->tx_swr_gpio_p, false);
+ } else {
+ msm_cdc_pinctrl_set_wakeup_capable(
+ tx_priv->tx_swr_gpio_p, true);
+ ret = swrm_wcd_notify(
+ tx_priv->swr_ctrl_data[0].tx_swr_pdev,
+ SWR_DEREGISTER_WAKEUP, NULL);
+ }
+ }
+
+ return ret;
+}
+
static int tx_macro_tx_va_mclk_enable(struct tx_macro_priv *tx_priv,
struct regmap *regmap, int clk_type,
bool enable)
@@ -1726,9 +1774,16 @@
(enable ? "enable" : "disable"), tx_priv->tx_mclk_users);
if (enable) {
- if (tx_priv->swr_clk_users == 0)
- msm_cdc_pinctrl_select_active_state(
+ if (tx_priv->swr_clk_users == 0) {
+ ret = msm_cdc_pinctrl_select_active_state(
tx_priv->tx_swr_gpio_p);
+ if (ret < 0) {
+ dev_err_ratelimited(tx_priv->dev,
+ "%s: tx swr pinctrl enable failed\n",
+ __func__);
+ goto exit;
+ }
+ }
clk_tx_ret = bolero_clk_rsc_request_clock(tx_priv->dev,
TX_CORE_CLK,
@@ -1841,9 +1896,16 @@
TX_CORE_CLK,
TX_CORE_CLK,
false);
- if (tx_priv->swr_clk_users == 0)
- msm_cdc_pinctrl_select_sleep_state(
+ if (tx_priv->swr_clk_users == 0) {
+ ret = msm_cdc_pinctrl_select_sleep_state(
tx_priv->tx_swr_gpio_p);
+ if (ret < 0) {
+ dev_err_ratelimited(tx_priv->dev,
+ "%s: tx swr pinctrl disable failed\n",
+ __func__);
+ goto exit;
+ }
+ }
}
return 0;
@@ -1853,6 +1915,7 @@
TX_CORE_CLK,
TX_CORE_CLK,
false);
+exit:
return ret;
}
@@ -1886,6 +1949,24 @@
return ret;
}
+static int tx_macro_core_vote(void *handle, bool enable)
+{
+ struct tx_macro_priv *tx_priv = (struct tx_macro_priv *) handle;
+ int ret = 0;
+
+ if (tx_priv == NULL) {
+ pr_err("%s: tx priv data is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (enable) {
+ pm_runtime_get_sync(tx_priv->dev);
+ pm_runtime_put_autosuspend(tx_priv->dev);
+ pm_runtime_mark_last_busy(tx_priv->dev);
+ }
+
+ return ret;
+}
+
static int tx_macro_swrm_clock(void *handle, bool enable)
{
struct tx_macro_priv *tx_priv = (struct tx_macro_priv *) handle;
@@ -1908,14 +1989,20 @@
if (tx_priv->va_swr_clk_cnt && !tx_priv->tx_swr_clk_cnt) {
ret = tx_macro_tx_va_mclk_enable(tx_priv, regmap,
VA_MCLK, enable);
- if (ret)
+ if (ret) {
+ pm_runtime_mark_last_busy(tx_priv->dev);
+ pm_runtime_put_autosuspend(tx_priv->dev);
goto done;
+ }
tx_priv->va_clk_status++;
} else {
ret = tx_macro_tx_va_mclk_enable(tx_priv, regmap,
TX_MCLK, enable);
- if (ret)
+ if (ret) {
+ pm_runtime_mark_last_busy(tx_priv->dev);
+ pm_runtime_put_autosuspend(tx_priv->dev);
goto done;
+ }
tx_priv->tx_clk_status++;
}
pm_runtime_mark_last_busy(tx_priv->dev);
@@ -2013,6 +2100,10 @@
return dmic_sample_rate;
}
+static const struct tx_macro_reg_mask_val tx_macro_reg_init[] = {
+ {BOLERO_CDC_TX0_TX_PATH_SEC7, 0x3F, 0x02},
+};
+
static int tx_macro_init(struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm =
@@ -2092,8 +2183,12 @@
}
tx_priv->component = component;
- snd_soc_component_update_bits(component,
- BOLERO_CDC_TX0_TX_PATH_SEC7, 0x3F, 0x0E);
+ for (i = 0; i < ARRAY_SIZE(tx_macro_reg_init); i++)
+ snd_soc_component_update_bits(component,
+ tx_macro_reg_init[i].reg,
+ tx_macro_reg_init[i].mask,
+ tx_macro_reg_init[i].val);
+
return 0;
}
@@ -2253,6 +2348,7 @@
ops->reg_wake_irq = tx_macro_reg_wake_irq;
ops->set_port_map = tx_macro_set_port_map;
ops->clk_switch = tx_macro_clk_switch;
+ ops->reg_evt_listener = tx_macro_register_event_listener;
}
static int tx_macro_probe(struct platform_device *pdev)
@@ -2299,7 +2395,8 @@
__func__);
return -EINVAL;
}
- if (msm_cdc_pinctrl_get_state(tx_priv->tx_swr_gpio_p) < 0) {
+ if (msm_cdc_pinctrl_get_state(tx_priv->tx_swr_gpio_p) < 0 &&
+ is_used_tx_swr_gpio) {
dev_err(&pdev->dev, "%s: failed to get swr pin state\n",
__func__);
return -EPROBE_DEFER;
@@ -2332,6 +2429,7 @@
tx_priv->swr_plat_data.write = NULL;
tx_priv->swr_plat_data.bulk_write = NULL;
tx_priv->swr_plat_data.clk = tx_macro_swrm_clock;
+ tx_priv->swr_plat_data.core_vote = tx_macro_core_vote;
tx_priv->swr_plat_data.handle_irq = NULL;
mutex_init(&tx_priv->mclk_lock);
diff --git a/asoc/codecs/bolero/va-macro.c b/asoc/codecs/bolero/va-macro.c
index 4c16319..b7d6fe0 100644
--- a/asoc/codecs/bolero/va-macro.c
+++ b/asoc/codecs/bolero/va-macro.c
@@ -124,6 +124,7 @@
int micb_users;
u16 default_clk_id;
u16 clk_id;
+ int tx_clk_status;
};
static bool va_macro_get_data(struct snd_soc_component *component,
@@ -294,8 +295,10 @@
if (bolero_tx_clk_switch(component))
dev_dbg(va_dev, "%s: clock switch failed\n",
__func__);
+ bolero_register_event_listener(component, true);
break;
case SND_SOC_DAPM_POST_PMD:
+ bolero_register_event_listener(component, false);
if (bolero_tx_clk_switch(component))
dev_dbg(va_dev, "%s: clock switch failed\n",__func__);
if (va_priv->lpass_audio_hw_vote)
@@ -328,14 +331,19 @@
va_priv->default_clk_id,
TX_CORE_CLK,
true);
+ if (!ret)
+ va_priv->tx_clk_status++;
ret = va_macro_mclk_enable(va_priv, 1, true);
break;
case SND_SOC_DAPM_POST_PMD:
va_macro_mclk_enable(va_priv, 0, true);
- bolero_clk_rsc_request_clock(va_priv->dev,
+ if (va_priv->tx_clk_status > 0) {
+ bolero_clk_rsc_request_clock(va_priv->dev,
va_priv->default_clk_id,
TX_CORE_CLK,
false);
+ va_priv->tx_clk_status--;
+ }
break;
default:
dev_err(va_priv->dev,
@@ -767,16 +775,21 @@
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- ret = bolero_clk_rsc_request_clock(va_priv->dev,
+ if (va_priv->tx_clk_status > 0) {
+ ret = bolero_clk_rsc_request_clock(va_priv->dev,
va_priv->default_clk_id,
TX_CORE_CLK,
false);
+ va_priv->tx_clk_status--;
+ }
break;
case SND_SOC_DAPM_PRE_PMD:
ret = bolero_clk_rsc_request_clock(va_priv->dev,
va_priv->default_clk_id,
TX_CORE_CLK,
true);
+ if (!ret)
+ va_priv->tx_clk_status++;
break;
default:
dev_err(va_priv->dev,
diff --git a/asoc/codecs/bolero/wsa-macro.c b/asoc/codecs/bolero/wsa-macro.c
index 623b64b..623af37 100644
--- a/asoc/codecs/bolero/wsa-macro.c
+++ b/asoc/codecs/bolero/wsa-macro.c
@@ -54,6 +54,7 @@
#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,
@@ -98,6 +99,14 @@
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;
@@ -151,6 +160,7 @@
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),
@@ -614,9 +624,9 @@
inp2_sel = (int_mux_cfg1_val >>
WSA_MACRO_MUX_INP_SHFT) &
WSA_MACRO_MUX_INP_MASK2;
- if ((inp0_sel == int_1_mix1_inp) ||
- (inp1_sel == int_1_mix1_inp) ||
- (inp2_sel == int_1_mix1_inp)) {
+ 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(wsa_dev,
@@ -670,7 +680,8 @@
int_mux_cfg1_val = snd_soc_component_read32(component,
int_mux_cfg1) &
WSA_MACRO_MUX_INP_MASK1;
- if (int_mux_cfg1_val == int_2_inp) {
+ 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;
@@ -766,7 +777,7 @@
struct snd_soc_component *component = dai->component;
struct device *wsa_dev = NULL;
struct wsa_macro_priv *wsa_priv = NULL;
- u16 val = 0, mask = 0, cnt = 0;
+ u16 val = 0, mask = 0, cnt = 0, temp = 0;
if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__))
return -EINVAL;
@@ -782,8 +793,16 @@
break;
case WSA_MACRO_AIF1_PB:
case WSA_MACRO_AIF_MIX1_PB:
- *rx_slot = wsa_priv->active_ch_mask[dai->id];
- *rx_num = wsa_priv->active_ch_cnt[dai->id];
+ 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_read32(component,
@@ -842,11 +861,15 @@
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)
+ 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(wsa_dev);
break;
default:
break;
@@ -1421,14 +1444,22 @@
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
u16 reg = 0;
+ struct device *wsa_dev = NULL;
+ struct wsa_macro_priv *wsa_priv = NULL;
+
+ if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__))
+ return -EINVAL;
+
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))
+ if (wsa_macro_adie_lb(component, w->shift)) {
snd_soc_component_update_bits(component,
reg, 0x20, 0x20);
+ bolero_wsa_pa_on(wsa_dev);
+ }
break;
default:
break;
@@ -2179,8 +2210,6 @@
wsa_priv->rx_port_value[widget->shift] = rx_port_value;
bit_input = widget->shift;
- if (widget->shift >= WSA_MACRO_RX_MIX)
- bit_input %= WSA_MACRO_RX_MIX;
dev_dbg(wsa_dev,
"%s: mux input: %d, mux output: %d, bit: %d\n",
@@ -2770,6 +2799,24 @@
wsa_macro_init_bcl_pmic_reg(component);
}
+static int wsa_macro_core_vote(void *handle, bool enable)
+{
+ struct wsa_macro_priv *wsa_priv = (struct wsa_macro_priv *) handle;
+ int ret = 0;
+
+ if (wsa_priv == NULL) {
+ pr_err("%s: wsa priv data is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (enable) {
+ pm_runtime_get_sync(wsa_priv->dev);
+ pm_runtime_put_autosuspend(wsa_priv->dev);
+ pm_runtime_mark_last_busy(wsa_priv->dev);
+ }
+
+ return ret;
+}
+
static int wsa_swrm_clock(void *handle, bool enable)
{
struct wsa_macro_priv *wsa_priv = (struct wsa_macro_priv *) handle;
@@ -2788,8 +2835,16 @@
if (enable) {
pm_runtime_get_sync(wsa_priv->dev);
if (wsa_priv->swr_clk_users == 0) {
- msm_cdc_pinctrl_select_active_state(
+ ret = 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(
@@ -2797,6 +2852,8 @@
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)
@@ -2812,9 +2869,9 @@
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);
- wsa_priv->swr_clk_users++;
} else {
if (wsa_priv->swr_clk_users <= 0) {
dev_err(wsa_priv->dev, "%s: clock already disabled\n",
@@ -2828,8 +2885,14 @@
BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
0x01, 0x00);
wsa_macro_mclk_enable(wsa_priv, 0, true);
- msm_cdc_pinctrl_select_sleep_state(
+ ret = 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;
+ }
}
}
dev_dbg(wsa_priv->dev, "%s: swrm clock users %d\n",
@@ -3075,7 +3138,8 @@
__func__);
return -EINVAL;
}
- if (msm_cdc_pinctrl_get_state(wsa_priv->wsa_swr_gpio_p) < 0) {
+ if (msm_cdc_pinctrl_get_state(wsa_priv->wsa_swr_gpio_p) < 0 &&
+ is_used_wsa_swr_gpio) {
dev_err(&pdev->dev, "%s: failed to get swr pin state\n",
__func__);
return -EPROBE_DEFER;
@@ -3096,6 +3160,7 @@
wsa_priv->swr_plat_data.write = NULL;
wsa_priv->swr_plat_data.bulk_write = NULL;
wsa_priv->swr_plat_data.clk = wsa_swrm_clock;
+ wsa_priv->swr_plat_data.core_vote = wsa_macro_core_vote;
wsa_priv->swr_plat_data.handle_irq = NULL;
ret = of_property_read_u32(pdev->dev.of_node, "qcom,default-clk-id",
diff --git a/asoc/codecs/msm-cdc-pinctrl.c b/asoc/codecs/msm-cdc-pinctrl.c
index c611345..a10a681 100644
--- a/asoc/codecs/msm-cdc-pinctrl.c
+++ b/asoc/codecs/msm-cdc-pinctrl.c
@@ -14,13 +14,16 @@
#include <linux/pinctrl/qcom-pinctrl.h>
#include <asoc/msm-cdc-pinctrl.h>
+#define MAX_GPIOS 16
+
struct msm_cdc_pinctrl_info {
struct pinctrl *pinctrl;
struct pinctrl_state *pinctrl_active;
struct pinctrl_state *pinctrl_sleep;
int gpio;
bool state;
- u32 tlmm_gpio;
+ u32 tlmm_gpio[MAX_GPIOS];
+ u32 count;
bool wakeup_capable;
};
@@ -151,14 +154,21 @@
{
struct msm_cdc_pinctrl_info *gpio_data;
int ret = 0;
+ u32 i = 0;
gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
if (!gpio_data)
return -EINVAL;
- if (gpio_data->wakeup_capable)
- ret = msm_gpio_mpm_wake_set(gpio_data->tlmm_gpio, enable);
-
+ if (gpio_data->wakeup_capable) {
+ for (i = 0; i < gpio_data->count; i++) {
+ ret = msm_gpio_mpm_wake_set(gpio_data->tlmm_gpio[i],
+ enable);
+ if (ret < 0)
+ goto exit;
+ }
+ }
+exit:
return ret;
}
EXPORT_SYMBOL(msm_cdc_pinctrl_set_wakeup_capable);
@@ -167,7 +177,9 @@
{
int ret = 0;
struct msm_cdc_pinctrl_info *gpio_data;
- u32 tlmm_gpio = 0;
+ u32 tlmm_gpio[MAX_GPIOS] = {0};
+ u32 i = 0;
+ int count = 0;
gpio_data = devm_kzalloc(&pdev->dev,
sizeof(struct msm_cdc_pinctrl_info),
@@ -210,12 +222,19 @@
__func__, ret);
}
- if (!of_property_read_u32(pdev->dev.of_node, "qcom,tlmm-gpio",
- &tlmm_gpio)) {
+
+ count = of_property_count_u32_elems(pdev->dev.of_node, "qcom,tlmm-gpio");
+ if (count <= 0)
+ goto cdc_rst;
+ if (!of_property_read_u32_array(pdev->dev.of_node, "qcom,tlmm-gpio",
+ tlmm_gpio, count)) {
gpio_data->wakeup_capable = true;
- gpio_data->tlmm_gpio = tlmm_gpio;
+ for (i = 0; i < count; i++)
+ gpio_data->tlmm_gpio[i] = tlmm_gpio[i];
+ gpio_data->count = count;
}
+cdc_rst:
gpio_data->gpio = of_get_named_gpio(pdev->dev.of_node,
"qcom,cdc-rst-n-gpio", 0);
if (gpio_is_valid(gpio_data->gpio)) {
diff --git a/asoc/codecs/msm_hdmi_codec_rx.c b/asoc/codecs/msm_hdmi_codec_rx.c
index 8d2507e..5144b92 100644
--- a/asoc/codecs/msm_hdmi_codec_rx.c
+++ b/asoc/codecs/msm_hdmi_codec_rx.c
@@ -100,7 +100,7 @@
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
uinfo->count = 0;
mutex_unlock(&codec_data->dp_ops_lock);
- return -EINVAL;
+ return 0;
}
rc = codec_data->ext_disp_ops.get_audio_edid_blk(
diff --git a/asoc/codecs/wcd-clsh.c b/asoc/codecs/wcd-clsh.c
index 8306fa5..73dc1f8 100644
--- a/asoc/codecs/wcd-clsh.c
+++ b/asoc/codecs/wcd-clsh.c
@@ -482,6 +482,9 @@
case WCD_CLSH_STATE_HPHR_AUX:
case WCD_CLSH_STATE_HPH_ST_AUX:
case WCD_CLSH_STATE_EAR_AUX:
+ case WCD_CLSH_STATE_HPHL_EAR:
+ case WCD_CLSH_STATE_HPHR_EAR:
+ case WCD_CLSH_STATE_HPH_ST_EAR:
return true;
default:
return false;
diff --git a/asoc/codecs/wcd-mbhc-v2.c b/asoc/codecs/wcd-mbhc-v2.c
index 624b59a..01544aa 100644
--- a/asoc/codecs/wcd-mbhc-v2.c
+++ b/asoc/codecs/wcd-mbhc-v2.c
@@ -691,10 +691,8 @@
&mbhc->zl, &mbhc->zr);
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN,
fsm_en);
- if ((mbhc->zl > mbhc->mbhc_cfg->linein_th &&
- mbhc->zl < MAX_IMPED) &&
- (mbhc->zr > mbhc->mbhc_cfg->linein_th &&
- mbhc->zr < MAX_IMPED) &&
+ if ((mbhc->zl > mbhc->mbhc_cfg->linein_th) &&
+ (mbhc->zr > mbhc->mbhc_cfg->linein_th) &&
(jack_type == SND_JACK_HEADPHONE)) {
jack_type = SND_JACK_LINEOUT;
mbhc->force_linein = true;
diff --git a/asoc/codecs/wcd937x/wcd937x.c b/asoc/codecs/wcd937x/wcd937x.c
index 2a7857a..1799599 100644
--- a/asoc/codecs/wcd937x/wcd937x.c
+++ b/asoc/codecs/wcd937x/wcd937x.c
@@ -88,6 +88,7 @@
.mask_base = WCD937X_DIGITAL_INTR_MASK_0,
.ack_base = WCD937X_DIGITAL_INTR_CLEAR_0,
.use_ack = 1,
+ .clear_ack = 1,
.type_base = WCD937X_DIGITAL_INTR_LEVEL_0,
.runtime_pm = false,
.handle_post_irq = wcd937x_handle_post_irq,
@@ -2322,7 +2323,8 @@
"variant",
priv->entry);
if (!variant_entry) {
- dev_dbg(codec->dev, "%s: failed to create wcd937x variant entry\n",
+ dev_dbg(component->dev,
+ "%s: failed to create wcd937x variant entry\n",
__func__);
return -ENOMEM;
}
diff --git a/asoc/codecs/wcd938x/internal.h b/asoc/codecs/wcd938x/internal.h
index 2c67ff8..098a60d 100644
--- a/asoc/codecs/wcd938x/internal.h
+++ b/asoc/codecs/wcd938x/internal.h
@@ -11,6 +11,8 @@
#include <asoc/wcd-clsh.h>
#include "wcd938x-mbhc.h"
+#define SWR_SCP_CONTROL 0x44
+#define SWR_SCP_HOST_CLK_DIV2_CTL_BANK 0xE0
#define WCD938X_MAX_MICBIAS 4
/* Convert from vout ctl to micbias voltage in mV */
@@ -97,6 +99,7 @@
struct snd_info_entry *variant_entry;
int flyback_cur_det_disable;
int ear_rx_path;
+ bool dev_up;
};
struct wcd938x_micbias_setting {
diff --git a/asoc/codecs/wcd938x/wcd938x-slave.c b/asoc/codecs/wcd938x/wcd938x-slave.c
index ec42b0d..75cc783 100644
--- a/asoc/codecs/wcd938x/wcd938x-slave.c
+++ b/asoc/codecs/wcd938x/wcd938x-slave.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -11,10 +11,267 @@
#include <linux/component.h>
#include <soc/soundwire.h>
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#define SWR_SLV_MAX_REG_ADDR 0x2009
+#define SWR_SLV_START_REG_ADDR 0x40
+#define SWR_SLV_MAX_BUF_LEN 20
+#define BYTES_PER_LINE 12
+#define SWR_SLV_RD_BUF_LEN 8
+#define SWR_SLV_WR_BUF_LEN 32
+#define SWR_SLV_MAX_DEVICES 2
+#endif /* CONFIG_DEBUG_FS */
+
struct wcd938x_slave_priv {
struct swr_device *swr_slave;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_wcd938x_dent;
+ struct dentry *debugfs_peek;
+ struct dentry *debugfs_poke;
+ struct dentry *debugfs_reg_dump;
+ unsigned int read_data;
+#endif
};
+#ifdef CONFIG_DEBUG_FS
+static int codec_debug_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static int get_parameters(char *buf, u32 *param1, int num_of_par)
+{
+ char *token = NULL;
+ int base = 0, cnt = 0;
+
+ token = strsep(&buf, " ");
+ for (cnt = 0; cnt < num_of_par; cnt++) {
+ if (token) {
+ if ((token[1] == 'x') || (token[1] == 'X'))
+ base = 16;
+ else
+ base = 10;
+
+ if (kstrtou32(token, base, ¶m1[cnt]) != 0)
+ return -EINVAL;
+
+ token = strsep(&buf, " ");
+ } else {
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static bool is_swr_slv_reg_readable(int reg)
+{
+ int ret = true;
+
+ if (((reg > 0x46) && (reg < 0x4A)) ||
+ ((reg > 0x4A) && (reg < 0x50)) ||
+ ((reg > 0x55) && (reg < 0xD0)) ||
+ ((reg > 0xD0) && (reg < 0xE0)) ||
+ ((reg > 0xE0) && (reg < 0xF0)) ||
+ ((reg > 0xF0) && (reg < 0x100)) ||
+ ((reg > 0x105) && (reg < 0x120)) ||
+ ((reg > 0x205) && (reg < 0x220)) ||
+ ((reg > 0x305) && (reg < 0x320)) ||
+ ((reg > 0x405) && (reg < 0x420)) ||
+ ((reg > 0x128) && (reg < 0x130)) ||
+ ((reg > 0x228) && (reg < 0x230)) ||
+ ((reg > 0x328) && (reg < 0x330)) ||
+ ((reg > 0x428) && (reg < 0x430)) ||
+ ((reg > 0x138) && (reg < 0x205)) ||
+ ((reg > 0x238) && (reg < 0x305)) ||
+ ((reg > 0x338) && (reg < 0x405)) ||
+ ((reg > 0x405) && (reg < 0xF00)) ||
+ ((reg > 0xF05) && (reg < 0xF20)) ||
+ ((reg > 0xF25) && (reg < 0xF30)) ||
+ ((reg > 0xF35) && (reg < 0x2000)))
+ ret = false;
+
+ return ret;
+}
+
+static ssize_t wcd938x_swrslave_reg_show(struct swr_device *pdev,
+ char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ int i, reg_val, len;
+ ssize_t total = 0;
+ char tmp_buf[SWR_SLV_MAX_BUF_LEN];
+
+ if (!ubuf || !ppos)
+ return 0;
+
+ for (i = (((int) *ppos/BYTES_PER_LINE) + SWR_SLV_START_REG_ADDR);
+ i <= SWR_SLV_MAX_REG_ADDR; i++) {
+ if (!is_swr_slv_reg_readable(i))
+ continue;
+ swr_read(pdev, pdev->dev_num, i, ®_val, 1);
+ len = snprintf(tmp_buf, sizeof(tmp_buf), "0x%.3x: 0x%.2x\n", i,
+ (reg_val & 0xFF));
+ if (((total + len) >= count - 1) || (len < 0))
+ break;
+ if (copy_to_user((ubuf + total), tmp_buf, len)) {
+ pr_err("%s: fail to copy reg dump\n", __func__);
+ total = -EFAULT;
+ goto copy_err;
+ }
+ total += len;
+ *ppos += len;
+ }
+
+copy_err:
+ *ppos = SWR_SLV_MAX_REG_ADDR * BYTES_PER_LINE;
+ return total;
+}
+
+static ssize_t codec_debug_dump(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct swr_device *pdev;
+
+ if (!count || !file || !ppos || !ubuf)
+ return -EINVAL;
+
+ pdev = file->private_data;
+ if (!pdev)
+ return -EINVAL;
+
+ if (*ppos < 0)
+ return -EINVAL;
+
+ return wcd938x_swrslave_reg_show(pdev, ubuf, count, ppos);
+}
+
+static ssize_t codec_debug_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ char lbuf[SWR_SLV_RD_BUF_LEN];
+ struct swr_device *pdev = NULL;
+ struct wcd938x_slave_priv *wcd938x_slave = NULL;
+
+ if (!count || !file || !ppos || !ubuf)
+ return -EINVAL;
+
+ pdev = file->private_data;
+ if (!pdev)
+ return -EINVAL;
+
+ wcd938x_slave = swr_get_dev_data(pdev);
+ if (!wcd938x_slave)
+ return -EINVAL;
+
+ if (*ppos < 0)
+ return -EINVAL;
+
+ snprintf(lbuf, sizeof(lbuf), "0x%x\n",
+ (wcd938x_slave->read_data & 0xFF));
+
+ return simple_read_from_buffer(ubuf, count, ppos, lbuf,
+ strnlen(lbuf, 7));
+}
+
+static ssize_t codec_debug_peek_write(struct file *file,
+ const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+ char lbuf[SWR_SLV_WR_BUF_LEN];
+ int rc = 0;
+ u32 param[5];
+ struct swr_device *pdev = NULL;
+ struct wcd938x_slave_priv *wcd938x_slave = NULL;
+
+ if (!cnt || !file || !ppos || !ubuf)
+ return -EINVAL;
+
+ pdev = file->private_data;
+ if (!pdev)
+ return -EINVAL;
+
+ wcd938x_slave = swr_get_dev_data(pdev);
+ if (!wcd938x_slave)
+ return -EINVAL;
+
+ if (*ppos < 0)
+ return -EINVAL;
+
+ if (cnt > sizeof(lbuf) - 1)
+ return -EINVAL;
+
+ rc = copy_from_user(lbuf, ubuf, cnt);
+ if (rc)
+ return -EFAULT;
+
+ lbuf[cnt] = '\0';
+ rc = get_parameters(lbuf, param, 1);
+ if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) && (rc == 0)))
+ return -EINVAL;
+ swr_read(pdev, pdev->dev_num, param[0], &wcd938x_slave->read_data, 1);
+ if (rc == 0)
+ rc = cnt;
+ else
+ pr_err("%s: rc = %d\n", __func__, rc);
+
+ return rc;
+}
+
+static ssize_t codec_debug_write(struct file *file,
+ const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+ char lbuf[SWR_SLV_WR_BUF_LEN];
+ int rc = 0;
+ u32 param[5];
+ struct swr_device *pdev;
+
+ if (!file || !ppos || !ubuf)
+ return -EINVAL;
+
+ pdev = file->private_data;
+ if (!pdev)
+ return -EINVAL;
+
+ if (cnt > sizeof(lbuf) - 1)
+ return -EINVAL;
+
+ rc = copy_from_user(lbuf, ubuf, cnt);
+ if (rc)
+ return -EFAULT;
+
+ lbuf[cnt] = '\0';
+ rc = get_parameters(lbuf, param, 2);
+ if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) &&
+ (param[1] <= 0xFF) && (rc == 0)))
+ return -EINVAL;
+ swr_write(pdev, pdev->dev_num, param[0], ¶m[1]);
+ if (rc == 0)
+ rc = cnt;
+ else
+ pr_err("%s: rc = %d\n", __func__, rc);
+
+ return rc;
+}
+
+static const struct file_operations codec_debug_write_ops = {
+ .open = codec_debug_open,
+ .write = codec_debug_write,
+};
+
+static const struct file_operations codec_debug_read_ops = {
+ .open = codec_debug_open,
+ .read = codec_debug_read,
+ .write = codec_debug_peek_write,
+};
+
+static const struct file_operations codec_debug_dump_ops = {
+ .open = codec_debug_open,
+ .read = codec_debug_dump,
+};
+#endif
+
static int wcd938x_slave_bind(struct device *dev,
struct device *master, void *data)
{
@@ -82,11 +339,49 @@
wcd938x_slave->swr_slave = pdev;
+#ifdef CONFIG_DEBUG_FS
+ if (!wcd938x_slave->debugfs_wcd938x_dent) {
+ wcd938x_slave->debugfs_wcd938x_dent = debugfs_create_dir(
+ dev_name(&pdev->dev), 0);
+ if (!IS_ERR(wcd938x_slave->debugfs_wcd938x_dent)) {
+ wcd938x_slave->debugfs_peek =
+ debugfs_create_file("swrslave_peek",
+ S_IFREG | 0444,
+ wcd938x_slave->debugfs_wcd938x_dent,
+ (void *) pdev,
+ &codec_debug_read_ops);
+
+ wcd938x_slave->debugfs_poke =
+ debugfs_create_file("swrslave_poke",
+ S_IFREG | 0444,
+ wcd938x_slave->debugfs_wcd938x_dent,
+ (void *) pdev,
+ &codec_debug_write_ops);
+
+ wcd938x_slave->debugfs_reg_dump =
+ debugfs_create_file(
+ "swrslave_reg_dump",
+ S_IFREG | 0444,
+ wcd938x_slave->debugfs_wcd938x_dent,
+ (void *) pdev,
+ &codec_debug_dump_ops);
+ }
+ }
+#endif
+
return component_add(&pdev->dev, &wcd938x_slave_comp_ops);
}
static int wcd938x_swr_remove(struct swr_device *pdev)
{
+#ifdef CONFIG_DEBUG_FS
+ struct wcd938x_slave_priv *wcd938x_slave = swr_get_dev_data(pdev);
+
+ if (wcd938x_slave) {
+ debugfs_remove_recursive(wcd938x_slave->debugfs_wcd938x_dent);
+ wcd938x_slave->debugfs_wcd938x_dent = NULL;
+ }
+#endif
component_del(&pdev->dev, &wcd938x_slave_comp_ops);
swr_set_dev_data(pdev, NULL);
swr_remove_device(pdev);
diff --git a/asoc/codecs/wcd938x/wcd938x.c b/asoc/codecs/wcd938x/wcd938x.c
index 036f97a..9bc75a0 100644
--- a/asoc/codecs/wcd938x/wcd938x.c
+++ b/asoc/codecs/wcd938x/wcd938x.c
@@ -25,6 +25,7 @@
#include "wcd938x-registers.h"
#include "wcd938x.h"
+
#define WCD938X_DRV_NAME "wcd938x_codec"
#define NUM_SWRS_DT_PARAMS 5
#define WCD938X_VARIANT_ENTRY_SIZE 32
@@ -126,6 +127,45 @@
return IRQ_HANDLED;
}
+static int wcd938x_swr_slv_get_current_bank(struct swr_device *dev, u8 devnum)
+{
+ int ret = 0;
+ int bank = 0;
+
+ ret = swr_read(dev, devnum, SWR_SCP_CONTROL, &bank, 1);
+ if (ret)
+ return -EINVAL;
+
+ return ((bank & 0x40) ? 1: 0);
+}
+
+static int wcd938x_swr_slv_set_host_clk_div2(struct swr_device *dev,
+ u8 devnum, int bank)
+{
+ u8 val = (bank ? 1 : 0);
+
+ return (swr_write(dev, devnum,
+ (SWR_SCP_HOST_CLK_DIV2_CTL_BANK + (0x10 * bank)), &val));
+}
+
+static int wcd938x_set_swr_clk_rate(struct snd_soc_component *component,
+ int mode, int bank)
+{
+ u8 mask = (bank ? 0xF0 : 0x0F);
+ u8 val = 0;
+
+ if ((mode == ADC_MODE_ULP1) || (mode == ADC_MODE_ULP2))
+ val = (bank ? 0x60 : 0x06);
+ else
+ val = 0x00;
+
+ snd_soc_component_update_bits(component,
+ WCD938X_DIGITAL_SWR_TX_CLK_RATE,
+ mask, val);
+
+ return 0;
+}
+
static int wcd938x_init_reg(struct snd_soc_component *component)
{
snd_soc_component_update_bits(component, WCD938X_SLEEP_CTL, 0x0E, 0x0E);
@@ -181,6 +221,8 @@
WCD938X_MICB3_TEST_CTL_1, 0xE0, 0xE0);
snd_soc_component_update_bits(component,
WCD938X_MICB4_TEST_CTL_1, 0xE0, 0xE0);
+ snd_soc_component_update_bits(component,
+ WCD938X_TX_3_4_TEST_BLK_EN2, 0x01, 0x00);
return 0;
}
@@ -548,12 +590,26 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
wcd938x_rx_clk_enable(component);
- snd_soc_component_update_bits(component,
+ wcd938x->ear_rx_path =
+ snd_soc_component_read32(
+ component, WCD938X_DIGITAL_CDC_EAR_PATH_CTL);
+ if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) {
+ snd_soc_component_update_bits(component,
+ WCD938X_EAR_EAR_DAC_CON, 0x80, 0x00);
+ snd_soc_component_update_bits(component,
+ WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, 0x01, 0x01);
+ snd_soc_component_update_bits(component,
+ WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x04, 0x04);
+ snd_soc_component_update_bits(component,
+ WCD938X_ANA_EAR_COMPANDER_CTL, 0x80, 0x80);
+ } else {
+ snd_soc_component_update_bits(component,
WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, 0x04, 0x04);
- snd_soc_component_update_bits(component,
+ snd_soc_component_update_bits(component,
WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x01);
- snd_soc_component_update_bits(component,
+ snd_soc_component_update_bits(component,
WCD938X_DIGITAL_CDC_COMP_CTL_0, 0x02, 0x02);
+ }
/* 5 msec delay as per HW requirement */
usleep_range(5000, 5010);
if (wcd938x->flyback_cur_det_disable == 0)
@@ -567,6 +623,14 @@
wcd938x->hph_mode);
break;
case SND_SOC_DAPM_POST_PMD:
+ if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) {
+ snd_soc_component_update_bits(component,
+ WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, 0x01, 0x00);
+ }
+ snd_soc_component_update_bits(component,
+ WCD938X_ANA_EAR_COMPANDER_CTL, 0x80, 0x00);
+ snd_soc_component_update_bits(component,
+ WCD938X_EAR_EAR_DAC_CON, 0x80, 0x80);
break;
};
return 0;
@@ -967,28 +1031,38 @@
snd_soc_component_update_bits(component,
WCD938X_ANA_RX_SUPPLIES,
0x02, 0x02);
- if (wcd938x->update_wcd_event)
- wcd938x->update_wcd_event(wcd938x->handle,
+ if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) {
+ if (wcd938x->update_wcd_event)
+ wcd938x->update_wcd_event(wcd938x->handle,
+ WCD_BOLERO_EVT_RX_MUTE,
+ (WCD_RX3 << 0x10));
+ wcd_enable_irq(&wcd938x->irq_info,
+ WCD938X_IRQ_AUX_PDM_WD_INT);
+ } else {
+ if (wcd938x->update_wcd_event)
+ wcd938x->update_wcd_event(wcd938x->handle,
WCD_BOLERO_EVT_RX_MUTE,
(WCD_RX1 << 0x10));
- if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX)
- wcd_enable_irq(&wcd938x->irq_info,
- WCD938X_IRQ_AUX_PDM_WD_INT);
- else
wcd_enable_irq(&wcd938x->irq_info,
WCD938X_IRQ_HPHL_PDM_WD_INT);
+ }
break;
case SND_SOC_DAPM_PRE_PMD:
- if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX)
+ if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) {
wcd_disable_irq(&wcd938x->irq_info,
WCD938X_IRQ_AUX_PDM_WD_INT);
- else
+ if (wcd938x->update_wcd_event)
+ wcd938x->update_wcd_event(wcd938x->handle,
+ WCD_BOLERO_EVT_RX_MUTE,
+ (WCD_RX3 << 0x10 | 0x1));
+ } else {
wcd_disable_irq(&wcd938x->irq_info,
WCD938X_IRQ_HPHL_PDM_WD_INT);
- if (wcd938x->update_wcd_event)
- wcd938x->update_wcd_event(wcd938x->handle,
+ if (wcd938x->update_wcd_event)
+ wcd938x->update_wcd_event(wcd938x->handle,
WCD_BOLERO_EVT_RX_MUTE,
(WCD_RX1 << 0x10 | 0x1));
+ }
break;
case SND_SOC_DAPM_POST_PMD:
/* 7 msec delay as per HW requirement */
@@ -1335,17 +1409,33 @@
snd_soc_dapm_to_component(w->dapm);
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
int ret = 0;
+ int bank = 0;
+ int mode = 0;
+ bank = wcd938x_swr_slv_get_current_bank(wcd938x->tx_swr_dev,
+ wcd938x->tx_swr_dev->dev_num);
+ wcd938x_swr_slv_set_host_clk_div2(wcd938x->tx_swr_dev,
+ wcd938x->tx_swr_dev->dev_num, bank);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev,
wcd938x->tx_swr_dev->dev_num,
true);
+ if (test_bit(WCD_ADC1, &wcd938x->status_mask))
+ mode |= wcd938x->tx_mode[WCD_ADC1];
+ if (test_bit(WCD_ADC2, &wcd938x->status_mask))
+ mode |= wcd938x->tx_mode[WCD_ADC2];
+ if (test_bit(WCD_ADC3, &wcd938x->status_mask))
+ mode |= wcd938x->tx_mode[WCD_ADC3];
+ if (test_bit(WCD_ADC4, &wcd938x->status_mask))
+ mode |= wcd938x->tx_mode[WCD_ADC4];
+ wcd938x_set_swr_clk_rate(component, mode, bank);
break;
case SND_SOC_DAPM_POST_PMD:
ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev,
wcd938x->tx_swr_dev->dev_num,
false);
+ wcd938x_set_swr_clk_rate(component, ADC_MODE_INVALID, bank);
break;
};
@@ -1565,6 +1655,7 @@
int pre_off_event = 0, post_off_event = 0;
int post_on_event = 0, post_dapm_off = 0;
int post_dapm_on = 0;
+ int ret = 0;
if ((micb_index < 0) || (micb_index > WCD938X_MAX_MICBIAS - 1)) {
dev_err(component->dev,
@@ -1606,6 +1697,12 @@
switch (req) {
case MICB_PULLUP_ENABLE:
+ if (!wcd938x->dev_up) {
+ dev_dbg(component->dev, "%s: enable req %d wcd device down\n",
+ __func__, req);
+ ret = -ENODEV;
+ goto done;
+ }
wcd938x->pullup_ref[micb_index]++;
if ((wcd938x->pullup_ref[micb_index] == 1) &&
(wcd938x->micb_ref[micb_index] == 0))
@@ -1615,12 +1712,24 @@
case MICB_PULLUP_DISABLE:
if (wcd938x->pullup_ref[micb_index] > 0)
wcd938x->pullup_ref[micb_index]--;
+ if (!wcd938x->dev_up) {
+ dev_dbg(component->dev, "%s: enable req %d wcd device down\n",
+ __func__, req);
+ ret = -ENODEV;
+ goto done;
+ }
if ((wcd938x->pullup_ref[micb_index] == 0) &&
(wcd938x->micb_ref[micb_index] == 0))
snd_soc_component_update_bits(component, micb_reg,
0xC0, 0x00);
break;
case MICB_ENABLE:
+ if (!wcd938x->dev_up) {
+ dev_dbg(component->dev, "%s: enable req %d wcd device down\n",
+ __func__, req);
+ ret = -ENODEV;
+ goto done;
+ }
wcd938x->micb_ref[micb_index]++;
if (wcd938x->micb_ref[micb_index] == 1) {
snd_soc_component_update_bits(component,
@@ -1653,6 +1762,12 @@
case MICB_DISABLE:
if (wcd938x->micb_ref[micb_index] > 0)
wcd938x->micb_ref[micb_index]--;
+ if (!wcd938x->dev_up) {
+ dev_dbg(component->dev, "%s: enable req %d wcd device down\n",
+ __func__, req);
+ ret = -ENODEV;
+ goto done;
+ }
if ((wcd938x->micb_ref[micb_index] == 0) &&
(wcd938x->pullup_ref[micb_index] > 0))
snd_soc_component_update_bits(component, micb_reg,
@@ -1683,9 +1798,10 @@
"%s: micb_num:%d, micb_ref: %d, pullup_ref: %d\n",
__func__, micb_num, wcd938x->micb_ref[micb_index],
wcd938x->pullup_ref[micb_index]);
- mutex_unlock(&wcd938x->micb_lock);
- return 0;
+done:
+ mutex_unlock(&wcd938x->micb_lock);
+ return ret;
}
EXPORT_SYMBOL(wcd938x_micbias_control);
@@ -1748,6 +1864,7 @@
0x80, 0x00);
break;
case BOLERO_WCD_EVT_SSR_DOWN:
+ wcd938x->dev_up = false;
mbhc = &wcd938x->mbhc->wcd_mbhc;
wcd938x_mbhc_ssr_down(wcd938x->mbhc, component);
wcd938x_reset_low(wcd938x->dev);
@@ -1768,6 +1885,7 @@
} else {
wcd938x_mbhc_hs_detect(component, mbhc->mbhc_cfg);
}
+ wcd938x->dev_up = true;
break;
case BOLERO_WCD_EVT_CLK_NOTIFY:
snd_soc_component_update_bits(component,
@@ -2923,6 +3041,7 @@
return ret;
}
}
+ wcd938x->dev_up = true;
return ret;
err_hwdep:
diff --git a/asoc/codecs/wsa881x.c b/asoc/codecs/wsa881x.c
index 2871ad3..966fa8a 100644
--- a/asoc/codecs/wsa881x.c
+++ b/asoc/codecs/wsa881x.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -16,6 +16,7 @@
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
#include <linux/regmap.h>
#include <linux/debugfs.h>
#include <soc/soundwire.h>
@@ -101,6 +102,30 @@
struct delayed_work ocp_ctl_work;
struct device_node *wsa_rst_np;
int pa_mute;
+ struct device_node *bolero_np;
+ struct platform_device* bolero_dev;
+ struct notifier_block bolero_nblock;
+ void *handle;
+ int (*register_notifier)(void *handle,
+ struct notifier_block *nblock,
+ bool enable);
+};
+
+/* from bolero to WSA events */
+enum {
+ BOLERO_WSA_EVT_TX_CH_HOLD_CLEAR = 1,
+ BOLERO_WSA_EVT_PA_OFF_PRE_SSR,
+ BOLERO_WSA_EVT_SSR_DOWN,
+ BOLERO_WSA_EVT_SSR_UP,
+ BOLERO_WSA_EVT_PA_ON_POST_FSCLK,
+};
+
+struct wsa_ctrl_platform_data {
+ void *handle;
+ int (*update_wsa_event)(void *handle, u16 event, u32 data);
+ int (*register_notifier)(void *handle,
+ struct notifier_block *nblock,
+ bool enable);
};
#define SWR_SLV_MAX_REG_ADDR 0x390
@@ -1006,6 +1031,10 @@
break;
case SND_SOC_DAPM_POST_PMU:
+ if (!wsa881x->bolero_dev)
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_DRV_EN,
+ 0x80, 0x80);
if (!wsa881x->comp_enable) {
max_gain = wsa881x->pa_gain;
/*
@@ -1039,6 +1068,9 @@
wsa881x->swr_slave->dev_num);
break;
case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_DRV_EN,
+ 0x80, 0x00);
if (wsa881x->visense_enable) {
wsa881x_visense_adc_ctrl(component, DISABLE);
wsa881x_visense_txfe_ctrl(component, DISABLE,
@@ -1064,7 +1096,7 @@
wsa881x_rdac_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_PGA_E("SPKR PGA", WSA881X_SPKR_DRV_EN, 7, 0, NULL, 0,
+ SND_SOC_DAPM_PGA_E("SPKR PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
wsa881x_spkr_pa_event, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -1338,12 +1370,45 @@
return ret;
}
+static int wsa881x_event_notify(struct notifier_block *nb,
+ unsigned long val, void *ptr)
+{
+ u16 event = (val & 0xffff);
+ struct wsa881x_priv *wsa881x = container_of(nb, struct wsa881x_priv,
+ bolero_nblock);
+
+ if (!wsa881x)
+ return -EINVAL;
+
+ switch (event) {
+ case BOLERO_WSA_EVT_PA_OFF_PRE_SSR:
+ snd_soc_component_update_bits(wsa881x->component,
+ WSA881X_SPKR_DRV_GAIN,
+ 0xF0, 0xC0);
+ snd_soc_component_update_bits(wsa881x->component,
+ WSA881X_SPKR_DRV_EN,
+ 0x80, 0x00);
+ break;
+ case BOLERO_WSA_EVT_PA_ON_POST_FSCLK:
+ if ((snd_soc_component_read32(wsa881x->component,
+ WSA881X_SPKR_DAC_CTL) & 0x80) == 0x80)
+ snd_soc_component_update_bits(wsa881x->component,
+ WSA881X_SPKR_DRV_EN,
+ 0x80, 0x80);
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static int wsa881x_swr_probe(struct swr_device *pdev)
{
int ret = 0;
struct wsa881x_priv *wsa881x;
u8 devnum = 0;
bool pin_state_current = false;
+ struct wsa_ctrl_platform_data *plat_data = NULL;
wsa881x = devm_kzalloc(&pdev->dev, sizeof(struct wsa881x_priv),
GFP_KERNEL);
@@ -1435,6 +1500,37 @@
__func__);
goto dev_err;
}
+
+ wsa881x->bolero_np = of_parse_phandle(pdev->dev.of_node,
+ "qcom,bolero-handle", 0);
+ if (wsa881x->bolero_np) {
+ wsa881x->bolero_dev =
+ of_find_device_by_node(wsa881x->bolero_np);
+ if (wsa881x->bolero_dev) {
+ plat_data = dev_get_platdata(&wsa881x->bolero_dev->dev);
+ if (plat_data) {
+ wsa881x->bolero_nblock.notifier_call =
+ wsa881x_event_notify;
+ if (plat_data->register_notifier)
+ plat_data->register_notifier(
+ plat_data->handle,
+ &wsa881x->bolero_nblock,
+ true);
+ wsa881x->register_notifier =
+ plat_data->register_notifier;
+ wsa881x->handle = plat_data->handle;
+ } else {
+ dev_err(&pdev->dev, "%s: plat data not found\n",
+ __func__);
+ }
+ } else {
+ dev_err(&pdev->dev, "%s: bolero dev not found\n",
+ __func__);
+ }
+ } else {
+ dev_info(&pdev->dev, "%s: bolero node not found\n", __func__);
+ }
+
mutex_init(&wsa881x->res_lock);
mutex_init(&wsa881x->temp_lock);
@@ -1457,6 +1553,10 @@
dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
return -EINVAL;
}
+
+ if (wsa881x->register_notifier)
+ wsa881x->register_notifier(wsa881x->handle,
+ &wsa881x->bolero_nblock, false);
debugfs_remove_recursive(debugfs_wsa881x_dent);
debugfs_wsa881x_dent = NULL;
mutex_destroy(&wsa881x->res_lock);
diff --git a/asoc/kona-port-config.h b/asoc/kona-port-config.h
index 0f73791..723c94a 100644
--- a/asoc/kona-port-config.h
+++ b/asoc/kona-port-config.h
@@ -50,6 +50,15 @@
{3, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1}, /* TX4 */
};
+/* TX UC1: TX1: 1ch, TX2: 2chs, TX3: 1ch(MBHC) */
+static struct port_params tx_frame_params_v2[SWR_MSTR_PORT_LEN] = {
+ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},/* PCM OUT */
+ {1, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1}, /* TX1 */
+ {1, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2}, /* TX2 */
+ {3, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0}, /* TX3 */
+ {3, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2}, /* TX4 */
+};
+
static struct swr_mstr_port_map sm_port_map[] = {
{TX_MACRO, SWR_UC0, tx_frame_params_default},
{RX_MACRO, SWR_UC0, rx_frame_params_default},
@@ -57,4 +66,11 @@
{WSA_MACRO, SWR_UC0, wsa_frame_params_default},
};
+static struct swr_mstr_port_map sm_port_map_v2[] = {
+ {TX_MACRO, SWR_UC0, tx_frame_params_v2},
+ {RX_MACRO, SWR_UC0, rx_frame_params_default},
+ {RX_MACRO, SWR_UC1, rx_frame_params_dsd},
+ {WSA_MACRO, SWR_UC0, wsa_frame_params_default},
+};
+
#endif /* _KONA_PORT_CONFIG */
diff --git a/asoc/kona.c b/asoc/kona.c
index 41a4ac6..1df6d34 100644
--- a/asoc/kona.c
+++ b/asoc/kona.c
@@ -55,6 +55,14 @@
#define SAMPLING_RATE_352P8KHZ 352800
#define SAMPLING_RATE_384KHZ 384000
+#define IS_FRACTIONAL(x) \
+((x == SAMPLING_RATE_11P025KHZ) || (x == SAMPLING_RATE_22P05KHZ) || \
+(x == SAMPLING_RATE_44P1KHZ) || (x == SAMPLING_RATE_88P2KHZ) || \
+(x == SAMPLING_RATE_176P4KHZ) || (x == SAMPLING_RATE_352P8KHZ))
+
+#define IS_MSM_INTERFACE_MI2S(x) \
+((x == PRIM_MI2S) || (x == SEC_MI2S) || (x == TERT_MI2S))
+
#define WCD9XXX_MBHC_DEF_RLOADS 5
#define WCD9XXX_MBHC_DEF_BUTTONS 8
#define CODEC_EXT_CLK_RATE 9600000
@@ -167,6 +175,7 @@
struct msm_asoc_mach_data {
struct snd_info_entry *codec_root;
int usbc_en2_gpio; /* used by gpio driver API */
+ int lito_v2_enabled;
struct device_node *dmic01_gpio_p; /* used by pinctrl API */
struct device_node *dmic23_gpio_p; /* used by pinctrl API */
struct device_node *dmic45_gpio_p; /* used by pinctrl API */
@@ -178,6 +187,8 @@
struct device_node *hph_en0_gpio_p; /* used by pinctrl API */
bool is_afe_config_done;
struct device_node *fsa_handle;
+ struct clk *lpass_audio_hw_vote;
+ int core_audio_vote_count;
};
struct tdm_port {
@@ -674,7 +685,9 @@
static const char *const auxpcm_rate_text[] = {"KHZ_8", "KHZ_16"};
static char const *mi2s_rate_text[] = {"KHZ_8", "KHZ_11P025", "KHZ_16",
"KHZ_22P05", "KHZ_32", "KHZ_44P1",
- "KHZ_48", "KHZ_96", "KHZ_192"};
+ "KHZ_48", "KHZ_88P2", "KHZ_96",
+ "KHZ_176P4", "KHZ_192","KHZ_352P8",
+ "KHZ_384"};
static const char *const mi2s_ch_text[] = {"One", "Two", "Three", "Four",
"Five", "Six", "Seven",
"Eight"};
@@ -2319,11 +2332,23 @@
sample_rate = SAMPLING_RATE_48KHZ;
break;
case 7:
- sample_rate = SAMPLING_RATE_96KHZ;
+ sample_rate = SAMPLING_RATE_88P2KHZ;
break;
case 8:
+ sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 9:
+ sample_rate = SAMPLING_RATE_176P4KHZ;
+ break;
+ case 10:
sample_rate = SAMPLING_RATE_192KHZ;
break;
+ case 11:
+ sample_rate = SAMPLING_RATE_352P8KHZ;
+ break;
+ case 12:
+ sample_rate = SAMPLING_RATE_384KHZ;
+ break;
default:
sample_rate = SAMPLING_RATE_48KHZ;
break;
@@ -2357,12 +2382,24 @@
case SAMPLING_RATE_48KHZ:
sample_rate_val = 6;
break;
- case SAMPLING_RATE_96KHZ:
+ case SAMPLING_RATE_88P2KHZ:
sample_rate_val = 7;
break;
- case SAMPLING_RATE_192KHZ:
+ case SAMPLING_RATE_96KHZ:
sample_rate_val = 8;
break;
+ case SAMPLING_RATE_176P4KHZ:
+ sample_rate_val = 9;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 10;
+ break;
+ case SAMPLING_RATE_352P8KHZ:
+ sample_rate_val = 11;
+ break;
+ case SAMPLING_RATE_384KHZ:
+ sample_rate_val = 12;
+ break;
default:
sample_rate_val = 6;
break;
@@ -4875,6 +4912,39 @@
return 0;
}
+void mi2s_disable_audio_vote(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int index = cpu_dai->id;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ int sample_rate = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ sample_rate = mi2s_rx_cfg[index].sample_rate;
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ sample_rate = mi2s_tx_cfg[index].sample_rate;
+ } else {
+ pr_err("%s: invalid stream %d\n", __func__, substream->stream);
+ return;
+ }
+
+ if (IS_MSM_INTERFACE_MI2S(index) && IS_FRACTIONAL(sample_rate)) {
+ if (pdata->lpass_audio_hw_vote != NULL) {
+ if (--pdata->core_audio_vote_count == 0) {
+ clk_disable_unprepare(
+ pdata->lpass_audio_hw_vote);
+ } else if (pdata->core_audio_vote_count < 0) {
+ pr_err("%s: audio vote mismatch\n", __func__);
+ pdata->core_audio_vote_count = 0;
+ }
+ } else {
+ pr_err("%s: Invalid lpass audio hw node\n", __func__);
+ }
+ }
+}
+
static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
{
int ret = 0;
@@ -4884,6 +4954,7 @@
unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
struct snd_soc_card *card = rtd->card;
struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ int sample_rate = 0;
dev_dbg(rtd->card->dev,
"%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
@@ -4903,6 +4974,34 @@
* that the same clock won't be enable twice.
*/
mutex_lock(&mi2s_intf_conf[index].lock);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ sample_rate = mi2s_rx_cfg[index].sample_rate;
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ sample_rate = mi2s_tx_cfg[index].sample_rate;
+ } else {
+ pr_err("%s: invalid stream %d\n", __func__, substream->stream);
+ ret = -EINVAL;
+ goto vote_err;
+ }
+
+ if (IS_MSM_INTERFACE_MI2S(index) && IS_FRACTIONAL(sample_rate)) {
+ if (pdata->lpass_audio_hw_vote == NULL) {
+ dev_err(rtd->card->dev, "%s: Invalid lpass audio hw node\n",
+ __func__);
+ ret = -EINVAL;
+ goto vote_err;
+ }
+ if (pdata->core_audio_vote_count == 0) {
+ ret = clk_prepare_enable(pdata->lpass_audio_hw_vote);
+ if (ret < 0) {
+ dev_err(rtd->card->dev, "%s: audio vote error\n",
+ __func__);
+ goto vote_err;
+ }
+ }
+ pdata->core_audio_vote_count++;
+ }
+
if (++mi2s_intf_conf[index].ref_cnt == 1) {
/* Check if msm needs to provide the clock to the interface */
if (!mi2s_intf_conf[index].msm_is_mi2s_master) {
@@ -4941,8 +5040,11 @@
if (ret < 0)
msm_mi2s_set_sclk(substream, false);
clean_up:
- if (ret < 0)
+ if (ret < 0) {
mi2s_intf_conf[index].ref_cnt--;
+ mi2s_disable_audio_vote(substream);
+ }
+vote_err:
mutex_unlock(&mi2s_intf_conf[index].lock);
err:
return ret;
@@ -4982,6 +5084,7 @@
pr_err("%s:clock disable failed for MI2S (%d); ret=%d\n",
__func__, index, ret);
}
+ mi2s_disable_audio_vote(substream);
mutex_unlock(&mi2s_intf_conf[index].lock);
}
@@ -5288,8 +5391,17 @@
WSA_MACRO_GAIN_OFFSET_M1P5_DB);
}
}
- bolero_set_port_map(component, ARRAY_SIZE(sm_port_map),
- sm_port_map);
+ if (pdata->lito_v2_enabled) {
+ /*
+ * Enable tx data line3 for saipan version v2 amd
+ * write corresponding lpi register.
+ */
+ bolero_set_port_map(component, ARRAY_SIZE(sm_port_map_v2),
+ sm_port_map_v2);
+ } else {
+ bolero_set_port_map(component, ARRAY_SIZE(sm_port_map),
+ sm_port_map);
+ }
}
card = rtd->card->snd_card;
if (!pdata->codec_root) {
@@ -7887,6 +7999,7 @@
const char *mbhc_audio_jack_type = NULL;
int ret = 0;
uint index = 0;
+ struct clk *lpass_audio_hw_vote = NULL;
if (!pdev->dev.of_node) {
dev_err(&pdev->dev, "%s: No platform supplied from device tree\n", __func__);
@@ -7898,6 +8011,10 @@
if (!pdata)
return -ENOMEM;
+ of_property_read_u32(pdev->dev.of_node,
+ "qcom,lito-is-v2-enabled",
+ &pdata->lito_v2_enabled);
+
card = populate_snd_card_dailinks(&pdev->dev);
if (!card) {
dev_err(&pdev->dev, "%s: Card uninitialized\n", __func__);
@@ -8019,6 +8136,10 @@
pdata->dmic45_gpio_p = of_parse_phandle(pdev->dev.of_node,
"qcom,cdc-dmic45-gpios",
0);
+ if (pdata->dmic01_gpio_p)
+ msm_cdc_pinctrl_set_wakeup_capable(pdata->dmic01_gpio_p, false);
+ if (pdata->dmic23_gpio_p)
+ msm_cdc_pinctrl_set_wakeup_capable(pdata->dmic23_gpio_p, false);
if (pdata->dmic45_gpio_p)
msm_cdc_pinctrl_set_wakeup_capable(pdata->dmic45_gpio_p, false);
@@ -8037,6 +8158,18 @@
for (index = PRIM_MI2S; index < MI2S_MAX; index++)
atomic_set(&(pdata->mi2s_gpio_ref_count[index]), 0);
+ /* Register LPASS audio hw vote */
+ lpass_audio_hw_vote = devm_clk_get(&pdev->dev, "lpass_audio_hw_vote");
+ if (IS_ERR(lpass_audio_hw_vote)) {
+ ret = PTR_ERR(lpass_audio_hw_vote);
+ dev_dbg(&pdev->dev, "%s: clk get %s failed %d\n",
+ __func__, "lpass_audio_hw_vote", ret);
+ lpass_audio_hw_vote = NULL;
+ ret = 0;
+ }
+ pdata->lpass_audio_hw_vote = lpass_audio_hw_vote;
+ pdata->core_audio_vote_count = 0;
+
ret = msm_audio_ssr_register(&pdev->dev);
if (ret)
pr_err("%s: Registration with SND event FWK failed ret = %d\n",
diff --git a/asoc/msm-compress-q6-v2.c b/asoc/msm-compress-q6-v2.c
index 8933dbd..4347bec 100644
--- a/asoc/msm-compress-q6-v2.c
+++ b/asoc/msm-compress-q6-v2.c
@@ -10,6 +10,7 @@
#include <linux/time.h>
#include <linux/math64.h>
#include <linux/wait.h>
+#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <sound/core.h>
@@ -106,6 +107,7 @@
struct msm_compr_ch_map *ch_map[MSM_FRONTEND_DAI_MAX];
bool is_in_use[MSM_FRONTEND_DAI_MAX];
struct msm_pcm_channel_mixer *chmixer_pspd[MSM_FRONTEND_DAI_MM_SIZE];
+ struct mutex lock;
};
struct msm_compr_audio {
@@ -1941,6 +1943,7 @@
}
spin_unlock_irqrestore(&prtd->lock, flags);
+ mutex_lock(&pdata->lock);
pdata->cstream[soc_prtd->dai_link->id] = NULL;
if (cstream->direction == SND_COMPRESS_PLAYBACK) {
msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
@@ -1962,6 +1965,7 @@
pdata->is_in_use[soc_prtd->dai_link->id] = false;
kfree(prtd);
runtime->private_data = NULL;
+ mutex_unlock(&pdata->lock);
return 0;
}
@@ -2018,6 +2022,7 @@
}
spin_unlock_irqrestore(&prtd->lock, flags);
+ mutex_lock(&pdata->lock);
pdata->cstream[soc_prtd->dai_link->id] = NULL;
msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
SNDRV_PCM_STREAM_CAPTURE);
@@ -2028,6 +2033,7 @@
kfree(prtd);
runtime->private_data = NULL;
+ mutex_unlock(&pdata->lock);
return 0;
}
@@ -3406,6 +3412,7 @@
struct snd_compr_stream *cstream = NULL;
struct msm_compr_audio *prtd = NULL;
long *values = &(ucontrol->value.integer.value[0]);
+ int ret = 0;
int effects_module;
pr_debug("%s\n", __func__);
@@ -3414,21 +3421,25 @@
__func__, fe_id);
return -EINVAL;
}
+
+ mutex_lock(&pdata->lock);
cstream = pdata->cstream[fe_id];
audio_effects = pdata->audio_effects[fe_id];
if (!cstream || !audio_effects) {
pr_err("%s: stream or effects inactive\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
+ goto done;
}
prtd = cstream->runtime->private_data;
if (!prtd) {
pr_err("%s: cannot set audio effects\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
+ goto done;
}
if (prtd->compr_passthr != LEGACY_PCM) {
pr_debug("%s: No effects for compr_type[%d]\n",
__func__, prtd->compr_passthr);
- return 0;
+ goto done;
}
pr_debug("%s: Effects supported for compr_type[%d]\n",
__func__, prtd->compr_passthr);
@@ -3489,9 +3500,11 @@
break;
default:
pr_err("%s Invalid effects config module\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
}
- return 0;
+done:
+ mutex_unlock(&pdata->lock);
+ return ret;
}
static int msm_compr_audio_effects_config_get(struct snd_kcontrol *kcontrol,
@@ -3503,6 +3516,7 @@
snd_soc_component_get_drvdata(comp);
struct msm_compr_audio_effects *audio_effects = NULL;
struct snd_compr_stream *cstream = NULL;
+ int ret = 0;
struct msm_compr_audio *prtd = NULL;
pr_debug("%s\n", __func__);
@@ -3511,19 +3525,23 @@
__func__, fe_id);
return -EINVAL;
}
+
+ mutex_lock(&pdata->lock);
cstream = pdata->cstream[fe_id];
audio_effects = pdata->audio_effects[fe_id];
if (!cstream || !audio_effects) {
pr_debug("%s: stream or effects inactive\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
+ goto done;
}
prtd = cstream->runtime->private_data;
if (!prtd) {
pr_err("%s: cannot set audio effects\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
}
-
- return 0;
+done:
+ mutex_unlock(&pdata->lock);
+ return ret;
}
static int msm_compr_query_audio_effect_put(struct snd_kcontrol *kcontrol,
@@ -3536,6 +3554,7 @@
struct msm_compr_audio_effects *audio_effects = NULL;
struct snd_compr_stream *cstream = NULL;
struct msm_compr_audio *prtd = NULL;
+ int ret = 0;
long *values = &(ucontrol->value.integer.value[0]);
if (fe_id >= MSM_FRONTEND_DAI_MAX) {
@@ -3543,28 +3562,37 @@
__func__, fe_id);
return -EINVAL;
}
+
+ mutex_lock(&pdata->lock);
+
cstream = pdata->cstream[fe_id];
audio_effects = pdata->audio_effects[fe_id];
if (!cstream || !audio_effects) {
pr_err("%s: stream or effects inactive\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
+ goto done;
}
prtd = cstream->runtime->private_data;
if (!prtd) {
pr_err("%s: cannot set audio effects\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
+ goto done;
}
if (prtd->compr_passthr != LEGACY_PCM) {
pr_err("%s: No effects for compr_type[%d]\n",
__func__, prtd->compr_passthr);
- return -EPERM;
+ ret = -EPERM;
+ goto done;
}
audio_effects->query.mod_id = (u32)*values++;
audio_effects->query.parm_id = (u32)*values++;
audio_effects->query.size = (u32)*values++;
audio_effects->query.offset = (u32)*values++;
audio_effects->query.device = (u32)*values++;
- return 0;
+
+done:
+ mutex_unlock(&pdata->lock);
+ return ret;
}
static int msm_compr_query_audio_effect_get(struct snd_kcontrol *kcontrol,
@@ -3577,6 +3605,7 @@
struct msm_compr_audio_effects *audio_effects = NULL;
struct snd_compr_stream *cstream = NULL;
struct msm_compr_audio *prtd = NULL;
+ int ret = 0;
long *values = &(ucontrol->value.integer.value[0]);
if (fe_id >= MSM_FRONTEND_DAI_MAX) {
@@ -3584,23 +3613,29 @@
__func__, fe_id);
return -EINVAL;
}
+
+ mutex_lock(&pdata->lock);
cstream = pdata->cstream[fe_id];
audio_effects = pdata->audio_effects[fe_id];
if (!cstream || !audio_effects) {
pr_debug("%s: stream or effects inactive\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
+ goto done;
}
prtd = cstream->runtime->private_data;
if (!prtd) {
pr_err("%s: cannot set audio effects\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
+ goto done;
}
values[0] = (long)audio_effects->query.mod_id;
values[1] = (long)audio_effects->query.parm_id;
values[2] = (long)audio_effects->query.size;
values[3] = (long)audio_effects->query.offset;
values[4] = (long)audio_effects->query.device;
- return 0;
+done:
+ mutex_unlock(&pdata->lock);
+ return ret;
}
static int msm_compr_send_dec_params(struct snd_compr_stream *cstream,
@@ -3686,6 +3721,7 @@
goto end;
}
+ mutex_lock(&pdata->lock);
switch (prtd->codec) {
case FORMAT_MP3:
case FORMAT_MPEG4_AAC:
@@ -3737,6 +3773,7 @@
}
end:
pr_debug("%s: ret %d\n", __func__, rc);
+ mutex_unlock(&pdata->lock);
return rc;
}
@@ -3956,6 +3993,7 @@
goto done;
}
+ mutex_lock(&pdata->lock);
if (prtd->audio_client == NULL) {
pr_err("%s: audio_client is null\n", __func__);
ret = -EINVAL;
@@ -3984,6 +4022,7 @@
pr_err("%s: failed to send stream event cmd, err = %d\n",
__func__, ret);
done:
+ mutex_unlock(&pdata->lock);
return ret;
}
@@ -4020,6 +4059,7 @@
goto done;
}
+ mutex_lock(&pdata->lock);
if (prtd->audio_client == NULL) {
pr_err("%s: audio_client is null\n", __func__);
ret = -EINVAL;
@@ -4031,6 +4071,7 @@
if (ret < 0)
pr_err("%s: failed to register ion fd\n", __func__);
done:
+ mutex_unlock(&pdata->lock);
return ret;
}
@@ -4053,6 +4094,7 @@
goto done;
}
+ mutex_lock(&pdata->lock);
cstream = pdata->cstream[fe_id];
if (cstream == NULL) {
pr_err("%s cstream is null\n", __func__);
@@ -4090,6 +4132,7 @@
pr_err("%s: failed to send rtic event ack, err = %d\n",
__func__, ret);
done:
+ mutex_unlock(&pdata->lock);
return ret;
}
@@ -5469,6 +5512,7 @@
kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
+ mutex_init(&pdata->lock);
dev_set_drvdata(&pdev->dev, pdata);
return snd_soc_register_component(&pdev->dev,
@@ -5485,6 +5529,7 @@
for (i = 0; i < MSM_FRONTEND_DAI_MM_SIZE; i++)
kfree(pdata->chmixer_pspd[i]);
}
+ mutex_destroy(&pdata->lock);
kfree(pdata);
snd_soc_unregister_component(&pdev->dev);
diff --git a/asoc/msm-dai-q6-v2.c b/asoc/msm-dai-q6-v2.c
index 73582cb..1b15444 100644
--- a/asoc/msm-dai-q6-v2.c
+++ b/asoc/msm-dai-q6-v2.c
@@ -9333,19 +9333,24 @@
}
static unsigned int tdm_param_set_slot_mask(u16 *slot_offset, int slot_width,
- int slots_per_frame)
+ int slots_per_frame)
{
unsigned int i = 0;
unsigned int slot_index = 0;
unsigned long slot_mask = 0;
unsigned int slot_width_bytes = slot_width / 8;
+ unsigned int channel_count = AFE_PORT_MAX_AUDIO_CHAN_CNT;
+
+ if (q6core_get_avcs_api_version_per_service(
+ APRV2_IDS_SERVICE_ID_ADSP_AFE_V) >= AFE_API_VERSION_V3)
+ channel_count = AFE_PORT_MAX_AUDIO_CHAN_CNT_V2;
if (slot_width_bytes == 0) {
pr_err("%s: slot width is zero\n", __func__);
return slot_mask;
}
- for (i = 0; i < AFE_PORT_MAX_AUDIO_CHAN_CNT; i++) {
+ for (i = 0; i < channel_count; i++) {
if (slot_offset[i] != AFE_SLOT_MAPPING_OFFSET_INVALID) {
slot_index = slot_offset[i] / slot_width_bytes;
if (slot_index < slots_per_frame)
@@ -9467,9 +9472,16 @@
*/
tdm->nslots_per_frame = tdm_group->nslots_per_frame;
tdm->slot_width = tdm_group->slot_width;
- tdm->slot_mask = tdm_param_set_slot_mask(slot_mapping->offset,
- tdm_group->slot_width,
- tdm_group->nslots_per_frame);
+ if (q6core_get_avcs_api_version_per_service(
+ APRV2_IDS_SERVICE_ID_ADSP_AFE_V) >= AFE_API_VERSION_V3)
+ tdm->slot_mask = tdm_param_set_slot_mask(
+ slot_mapping_v2->offset,
+ tdm_group->slot_width,
+ tdm_group->nslots_per_frame);
+ else
+ tdm->slot_mask = tdm_param_set_slot_mask(slot_mapping->offset,
+ tdm_group->slot_width,
+ tdm_group->nslots_per_frame);
pr_debug("%s: TDM:\n"
"num_channels=%d sample_rate=%d bit_width=%d\n"
diff --git a/asoc/msm-pcm-q6-v2.c b/asoc/msm-pcm-q6-v2.c
index 6525dd0..7197ad6 100644
--- a/asoc/msm-pcm-q6-v2.c
+++ b/asoc/msm-pcm-q6-v2.c
@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/time.h>
+#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -897,19 +898,25 @@
pr_debug("%s: cmd_pending 0x%lx\n", __func__, prtd->cmd_pending);
+ if (!component) {
+ pr_err("%s: component is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ pdata = (struct msm_plat_data *) dev_get_drvdata(component->dev);
+ if (!pdata) {
+ pr_err("%s: platform data is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&pdata->lock);
if (prtd->audio_client) {
dir = IN;
- if (!component) {
- pr_err("%s: component is NULL\n", __func__);
- return -EINVAL;
- }
/*
* Unvote to downgrade the Rx thread priority from
* RT Thread for Low-Latency use case.
*/
- pdata = (struct msm_plat_data *)
- dev_get_drvdata(component->dev);
if (pdata) {
if (pdata->perf_mode == LOW_LATENCY_PCM_MODE)
apr_end_rx_rt(prtd->audio_client->apr);
@@ -943,7 +950,7 @@
msm_adsp_clean_mixer_ctl_pp_event_queue(soc_prtd);
kfree(prtd);
runtime->private_data = NULL;
-
+ mutex_unlock(&pdata->lock);
return 0;
}
@@ -1035,9 +1042,25 @@
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
struct msm_audio *prtd = runtime->private_data;
+ struct snd_soc_component *component =
+ snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
+ struct msm_plat_data *pdata;
int dir = OUT;
pr_debug("%s\n", __func__);
+
+ if (!component) {
+ pr_err("%s: component is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ pdata = (struct msm_plat_data *) dev_get_drvdata(component->dev);
+ if (!pdata) {
+ pr_err("%s: platform data is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&pdata->lock);
if (prtd->audio_client) {
q6asm_cmd(prtd->audio_client, CMD_CLOSE);
q6asm_audio_client_buf_free_contiguous(dir,
@@ -1049,7 +1072,7 @@
SNDRV_PCM_STREAM_CAPTURE);
kfree(prtd);
runtime->private_data = NULL;
-
+ mutex_unlock(&pdata->lock);
return 0;
}
@@ -1316,6 +1339,7 @@
goto done;
}
+ mutex_lock(&pdata->lock);
event_data = (struct msm_adsp_event_data *)ucontrol->value.bytes.data;
if ((event_data->event_type < ADSP_STREAM_PP_EVENT) ||
(event_data->event_type >= ADSP_STREAM_EVENT_MAX)) {
@@ -1338,6 +1362,7 @@
pr_err("%s: failed to send stream event cmd, err = %d\n",
__func__, ret);
done:
+ mutex_unlock(&pdata->lock);
return ret;
}
@@ -1513,25 +1538,46 @@
{
int rc = 0;
struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
+ struct msm_plat_data *pdata = NULL;
struct snd_pcm_substream *substream =
vol->pcm->streams[vol->stream].substream;
+ struct snd_soc_pcm_runtime *soc_prtd = NULL;
+ struct snd_soc_component *component = NULL;
struct msm_audio *prtd;
int volume = ucontrol->value.integer.value[0];
pr_debug("%s: volume : 0x%x\n", __func__, volume);
if (!substream) {
- pr_err("%s substream not found\n", __func__);
+ pr_err("%s: substream not found\n", __func__);
return -ENODEV;
}
- if (!substream->runtime) {
- pr_err("%s substream runtime not found\n", __func__);
+
+ soc_prtd = substream->private_data;
+ if (!substream->runtime || !soc_prtd) {
+ pr_err("%s: substream runtime or private_data not found\n",
+ __func__);
return 0;
}
+
+ component = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
+ if (!component) {
+ pr_err("%s: component is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ pdata = (struct msm_plat_data *) dev_get_drvdata(component->dev);
+ if (!pdata) {
+ pr_err("%s: pdata not found\n", __func__);
+ return -ENODEV;
+ }
+
+ mutex_lock(&pdata->lock);
prtd = substream->runtime->private_data;
if (prtd) {
rc = msm_pcm_set_volume(prtd, volume);
prtd->volume = volume;
}
+ mutex_unlock(&pdata->lock);
return rc;
}
@@ -1711,9 +1757,27 @@
substream = snd_pcm_chmap_substream(info, idx);
if (!substream)
return -ENODEV;
- if (!substream->runtime)
+
+ rtd = substream->private_data;
+ if (rtd) {
+ component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+ if (component) {
+ pdata = (struct msm_plat_data *)
+ dev_get_drvdata(component->dev);
+ if (!pdata) {
+ pr_err("%s: pdata not found\n", __func__);
+ return -ENODEV;
+ }
+ } else {
+ pr_err("%s: component is NULL\n", __func__);
+ return -EINVAL;
+ }
+ }
+
+ if (!substream->runtime || !rtd)
return 0;
+ mutex_lock(&pdata->lock);
prtd = substream->runtime->private_data;
if (prtd) {
prtd->set_channel_map = true;
@@ -1722,13 +1786,9 @@
(char)(ucontrol->value.integer.value[i]);
/* update chmixer_pspd chmap cached with routing driver as well */
- rtd = substream->private_data;
if (rtd) {
- component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
if (component) {
fe_id = rtd->dai_link->id;
- pdata = (struct msm_plat_data *)
- dev_get_drvdata(component->dev);
chmixer_pspd = pdata ?
pdata->chmixer_pspd[fe_id][SESSION_TYPE_RX] : NULL;
@@ -1742,6 +1802,7 @@
}
}
}
+ mutex_unlock(&pdata->lock);
return 0;
}
@@ -1753,16 +1814,37 @@
unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
struct snd_pcm_substream *substream;
struct msm_audio *prtd;
+ struct snd_soc_pcm_runtime *rtd = NULL;
+ struct msm_plat_data *pdata = NULL;
+ struct snd_soc_component *component = NULL;
pr_debug("%s", __func__);
substream = snd_pcm_chmap_substream(info, idx);
if (!substream)
return -ENODEV;
+
+ rtd = substream->private_data;
+ if (rtd) {
+ component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+ if (component) {
+ pdata = (struct msm_plat_data *)
+ dev_get_drvdata(component->dev);
+ if (!pdata) {
+ pr_err("%s: pdata not found\n", __func__);
+ return -ENODEV;
+ }
+ } else {
+ pr_err("%s: component is NULL\n", __func__);
+ return -EINVAL;
+ }
+ }
+
memset(ucontrol->value.integer.value, 0,
sizeof(ucontrol->value.integer.value));
- if (!substream->runtime)
+ if (!substream->runtime || !rtd)
return 0; /* no channels set */
+ mutex_lock(&pdata->lock);
prtd = substream->runtime->private_data;
if (prtd && prtd->set_channel_map == true) {
@@ -1774,6 +1856,7 @@
ucontrol->value.integer.value[i] = 0;
}
+ mutex_unlock(&pdata->lock);
return 0;
}
@@ -2043,6 +2126,7 @@
return -EINVAL;
}
+ mutex_lock(&pdata->lock);
prtd = substream->runtime ? substream->runtime->private_data : NULL;
if (chmixer_pspd->enable && prtd) {
if (session_type == SESSION_TYPE_RX &&
@@ -2095,6 +2179,7 @@
if (reset_override_in_ch_map)
chmixer_pspd->override_in_ch_map = false;
+ mutex_unlock(&pdata->lock);
return ret;
}
@@ -2756,7 +2841,7 @@
} else {
pdata->perf_mode = LEGACY_PCM_MODE;
}
-
+ mutex_init(&pdata->lock);
dev_set_drvdata(&pdev->dev, pdata);
@@ -2779,6 +2864,7 @@
kfree(pdata->chmixer_pspd[i][SESSION_TYPE_TX]);
}
}
+ mutex_destroy(&pdata->lock);
kfree(pdata);
snd_soc_unregister_component(&pdev->dev);
return 0;
diff --git a/asoc/msm-pcm-q6-v2.h b/asoc/msm-pcm-q6-v2.h
index 62fcebd..6498f07 100644
--- a/asoc/msm-pcm-q6-v2.h
+++ b/asoc/msm-pcm-q6-v2.h
@@ -117,6 +117,7 @@
struct msm_pcm_ch_map *ch_map[MSM_FRONTEND_DAI_MAX];
struct snd_pcm *pcm_device[MSM_FRONTEND_DAI_MM_SIZE];
struct msm_pcm_channel_mixer *chmixer_pspd[MSM_FRONTEND_DAI_MM_SIZE][2];
+ struct mutex lock;
};
struct msm_pcm_ch_map {
diff --git a/asoc/msm-pcm-routing-v2.c b/asoc/msm-pcm-routing-v2.c
index f5e9896..0563d8c 100644
--- a/asoc/msm-pcm-routing-v2.c
+++ b/asoc/msm-pcm-routing-v2.c
@@ -1423,7 +1423,7 @@
int num_copps = 0;
struct route_payload payload;
u32 channels, sample_rate;
- u16 bit_width = 16;
+ u16 bit_width = 16, be_bit_width;
bool is_lsm;
pr_debug("%s:fe_id[%d] perf_mode[%d] id[%d] stream_type[%d] passt[%d]",
@@ -1525,7 +1525,12 @@
topology = COMPRESSED_PASSTHROUGH_NONE_TOPOLOGY;
pr_debug("%s: Before adm open topology %d\n", __func__,
topology);
- if (hifi_filter_enabled)
+
+ be_bit_width = msm_routing_get_bit_width(
+ msm_bedais[i].format);
+ if (hifi_filter_enabled && (msm_bedais[i].sample_rate
+ == 384000 || msm_bedais[i].sample_rate ==
+ 352800) && be_bit_width == 32)
bit_width = msm_routing_get_bit_width(
SNDRV_PCM_FORMAT_S32_LE);
@@ -1805,7 +1810,7 @@
int i, j, session_type, path_type, port_type, topology, num_copps = 0;
struct route_payload payload;
u32 channels, sample_rate;
- uint16_t bits_per_sample = 16;
+ uint16_t bits_per_sample = 16, be_bit_width;
uint32_t passthr_mode = LEGACY_PCM;
int ret = 0;
@@ -1873,7 +1878,12 @@
topology = msm_routing_get_adm_topology(fedai_id,
session_type,
i);
- if (hifi_filter_enabled)
+ be_bit_width = msm_routing_get_bit_width(
+ msm_bedais[i].format);
+
+ if (hifi_filter_enabled && (msm_bedais[i].sample_rate ==
+ 384000 ||msm_bedais[i].sample_rate == 352800)
+ && be_bit_width == 32)
bits_per_sample = msm_routing_get_bit_width(
SNDRV_PCM_FORMAT_S32_LE);
copp_idx = adm_open(port_id, path_type,
@@ -2039,7 +2049,7 @@
{
int session_type, path_type, topology;
u32 channels, sample_rate;
- uint16_t bits_per_sample = 16;
+ uint16_t bits_per_sample = 16, be_bit_width;
struct msm_pcm_routing_fdai_data *fdai;
uint32_t passthr_mode;
bool is_lsm;
@@ -2143,7 +2153,12 @@
reg);
acdb_dev_id =
fe_dai_app_type_cfg[val][session_type][reg].acdb_dev_id;
- if (hifi_filter_enabled)
+
+ be_bit_width = msm_routing_get_bit_width(
+ msm_bedais[reg].format);
+ if (hifi_filter_enabled && (msm_bedais[reg].sample_rate
+ == 384000 ||msm_bedais[reg].sample_rate ==
+ 352800) && be_bit_width == 32)
bits_per_sample = msm_routing_get_bit_width(
SNDRV_PCM_FORMAT_S32_LE);
copp_idx = adm_open(port_id, path_type,
@@ -5682,6 +5697,9 @@
case EXT_EC_REF_SLIM_1_TX:
ext_ec_ref_port_id = SLIMBUS_1_TX;
break;
+ case EXT_EC_REF_PRI_TDM_TX:
+ ext_ec_ref_port_id = AFE_PORT_ID_PRIMARY_TDM_TX;
+ break;
case EXT_EC_REF_SEC_TDM_TX:
ext_ec_ref_port_id = AFE_PORT_ID_SECONDARY_TDM_TX;
break;
@@ -5709,7 +5727,8 @@
static const char * const ext_ec_ref_rx[] = {"NONE", "PRI_MI2S_TX",
"SEC_MI2S_TX", "TERT_MI2S_TX",
"QUAT_MI2S_TX", "QUIN_MI2S_TX",
- "SLIM_1_TX", "SEC_TDM_TX"};
+ "SLIM_1_TX", "PRI_TDM_TX",
+ "SEC_TDM_TX"};
static const struct soc_enum msm_route_ext_ec_ref_rx_enum[] = {
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ext_ec_ref_rx), ext_ec_ref_rx),
@@ -21699,16 +21718,16 @@
kcontrol->private_value)->shift;
int i = 0, j;
- num_app_cfg_types = ucontrol->value.integer.value[i++];
- memset(lsm_app_type_cfg, 0, MAX_APP_TYPES*
- sizeof(struct msm_pcm_routing_app_type_data));
-
- if (num_app_cfg_types > MAX_APP_TYPES) {
+ if (ucontrol->value.integer.value[0] > MAX_APP_TYPES) {
pr_err("%s: number of app types exceed the max supported\n",
__func__);
return -EINVAL;
}
+ num_app_cfg_types = ucontrol->value.integer.value[i++];
+ memset(lsm_app_type_cfg, 0, MAX_APP_TYPES*
+ sizeof(struct msm_pcm_routing_app_type_data));
+
for (j = 0; j < num_app_cfg_types; j++) {
lsm_app_type_cfg[j].app_type =
ucontrol->value.integer.value[i++];
@@ -26709,6 +26728,7 @@
{"VOC_EXT_EC MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
{"VOC_EXT_EC MUX", "QUIN_MI2S_TX", "QUIN_MI2S_TX"},
{"VOC_EXT_EC MUX", "SLIM_1_TX", "SLIMBUS_1_TX"},
+ {"VOC_EXT_EC MUX", "PRI_TDM_TX", "PRI_TDM_TX_0"},
{"VOC_EXT_EC MUX", "SEC_TDM_TX", "SEC_TDM_TX_0"},
{"VOIP_UL", NULL, "VOC_EXT_EC MUX"},
{"VOICEMMODE1_UL", NULL, "VOC_EXT_EC MUX"},
@@ -28374,7 +28394,7 @@
int session_type = INVALID_SESSION;
struct msm_pcm_routing_bdai_data *bedai;
u32 channels, sample_rate;
- uint16_t bits_per_sample = 16, voc_path_type;
+ uint16_t bits_per_sample = 16, voc_path_type, be_bit_width;
struct msm_pcm_routing_fdai_data *fdai;
u32 session_id;
struct media_format_info voc_be_media_format;
@@ -28482,7 +28502,12 @@
|| (fdai->passthr_mode == COMPRESSED_PASSTHROUGH_IEC61937))
topology = COMPRESSED_PASSTHROUGH_NONE_TOPOLOGY;
- if (hifi_filter_enabled)
+ be_bit_width = msm_routing_get_bit_width(
+ bedai->format);
+
+ if (hifi_filter_enabled && (bedai->sample_rate == 384000
+ || bedai->sample_rate == 352800) &&
+ be_bit_width == 32)
bits_per_sample = msm_routing_get_bit_width(
SNDRV_PCM_FORMAT_S32_LE);
copp_idx = adm_open(port_id, path_type,
diff --git a/asoc/msm-pcm-routing-v2.h b/asoc/msm-pcm-routing-v2.h
index aca00bb..8003d91 100644
--- a/asoc/msm-pcm-routing-v2.h
+++ b/asoc/msm-pcm-routing-v2.h
@@ -516,6 +516,7 @@
EXT_EC_REF_QUAT_MI2S_TX,
EXT_EC_REF_QUIN_MI2S_TX,
EXT_EC_REF_SLIM_1_TX,
+ EXT_EC_REF_PRI_TDM_TX,
EXT_EC_REF_SEC_TDM_TX,
};
diff --git a/asoc/qcs405.c b/asoc/qcs405.c
index 36fbfad..18dfb82 100644
--- a/asoc/qcs405.c
+++ b/asoc/qcs405.c
@@ -5272,6 +5272,7 @@
snd_soc_dapm_ignore_suspend(dapm, "LINEOUT2");
snd_soc_dapm_ignore_suspend(dapm, "Analog Mic3");
snd_soc_dapm_ignore_suspend(dapm, "Analog Mic4");
+ snd_soc_dapm_ignore_suspend(dapm, "lineout booster");
snd_soc_dapm_sync(dapm);
diff --git a/dsp/adsp-loader.c b/dsp/adsp-loader.c
index ef9d92d..aec90f5 100644
--- a/dsp/adsp-loader.c
+++ b/dsp/adsp-loader.c
@@ -7,6 +7,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/err.h>
+#include <linux/string.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <ipc/apr.h>
@@ -22,7 +23,6 @@
#define SSR_RESET_CMD 1
#define IMAGE_UNLOAD_CMD 0
#define MAX_FW_IMAGES 4
-#define ADSP_FW_NAME_MAX_LENGTH 5
static ssize_t adsp_boot_store(struct kobject *kobj,
struct kobj_attribute *attr,
@@ -330,6 +330,7 @@
int adsp_fw_cnt;
u32* adsp_fw_bit_values = NULL;
int i;
+ int fw_name_size;
u32 adsp_var_idx;
int ret = 0;
@@ -398,12 +399,14 @@
for (i = 0; i < adsp_fw_cnt; i++) {
if (adsp_fw_bit_values[i] == adsp_var_idx) {
+ fw_name_size = strlen(adsp_fw_name_array[i]) + 1;
priv->adsp_fw_name = devm_kzalloc(&pdev->dev,
- ADSP_FW_NAME_MAX_LENGTH, GFP_KERNEL);
+ fw_name_size,
+ GFP_KERNEL);
if (!priv->adsp_fw_name)
goto wqueue;
strlcpy(priv->adsp_fw_name, adsp_fw_name_array[i],
- sizeof(priv->adsp_fw_name));
+ fw_name_size);
break;
}
}
diff --git a/dsp/avtimer.c b/dsp/avtimer.c
index 39b5268..ad5e13a 100644
--- a/dsp/avtimer.c
+++ b/dsp/avtimer.c
@@ -335,6 +335,11 @@
uint64_t avtimer_tick_temp, avtimer_tick, sys_time = 0;
struct timespec ts;
+ if (!atomic_read(&avtimer.adsp_ready)) {
+ pr_debug("%s:In SSR, return\n", __func__);
+ return -ENETRESET;
+ }
+
if ((avtimer.p_avtimer_lsw == NULL) ||
(avtimer.p_avtimer_msw == NULL)) {
return -EINVAL;
diff --git a/dsp/q6adm.c b/dsp/q6adm.c
index 6dbbbc0..b161df9 100644
--- a/dsp/q6adm.c
+++ b/dsp/q6adm.c
@@ -3044,14 +3044,19 @@
}
if ((topology == VPM_TX_SM_ECNS_V2_COPP_TOPOLOGY) ||
- (topology == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY) ||
- (topology == VPM_TX_DM_RFECNS_COPP_TOPOLOGY)||
(topology == VPM_TX_DM_FLUENCE_EF_COPP_TOPOLOGY)) {
if ((rate != ADM_CMD_COPP_OPEN_SAMPLE_RATE_8K) &&
(rate != ADM_CMD_COPP_OPEN_SAMPLE_RATE_16K) &&
(rate != ADM_CMD_COPP_OPEN_SAMPLE_RATE_32K) &&
(rate != ADM_CMD_COPP_OPEN_SAMPLE_RATE_48K))
- rate = 16000;
+ rate = 16000;
+ }
+ if ((topology == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY) ||
+ (topology == VPM_TX_DM_RFECNS_COPP_TOPOLOGY)) {
+ if ((rate != ADM_CMD_COPP_OPEN_SAMPLE_RATE_8K) &&
+ (rate != ADM_CMD_COPP_OPEN_SAMPLE_RATE_16K) &&
+ (rate != ADM_CMD_COPP_OPEN_SAMPLE_RATE_32K))
+ rate = 16000;
}
if (topology == FFECNS_TOPOLOGY) {
diff --git a/dsp/q6afe.c b/dsp/q6afe.c
index 9709772..c30415a 100644
--- a/dsp/q6afe.c
+++ b/dsp/q6afe.c
@@ -596,6 +596,11 @@
rtac_set_afe_handle(this_afe.apr);
}
+ /* Reset the core client handle in SSR/PDR use cases */
+ mutex_lock(&this_afe.afe_cmd_lock);
+ this_afe.lpass_hw_core_client_hdl = 0;
+ mutex_unlock(&this_afe.afe_cmd_lock);
+
/*
* Pass reset events to proxy driver, if cb is registered
*/
@@ -8521,7 +8526,7 @@
uint32_t mode;
if (cal_data == NULL ||
- data_size != sizeof(*cal_data) ||
+ data_size > sizeof(*cal_data) ||
this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL)
goto done;
@@ -8665,7 +8670,7 @@
int ret = 0;
if (cal_data == NULL ||
- data_size != sizeof(*cal_data) ||
+ data_size > sizeof(*cal_data) ||
this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL)
return 0;
@@ -9058,6 +9063,7 @@
this_afe.mmap_handle = 0;
this_afe.vi_tx_port = -1;
this_afe.vi_rx_port = -1;
+ this_afe.lpass_hw_core_client_hdl = 0;
this_afe.prot_cfg.mode = MSM_SPKR_PROT_DISABLED;
this_afe.th_ftm_cfg.mode = MSM_SPKR_PROT_DISABLED;
this_afe.ex_ftm_cfg.mode = MSM_SPKR_PROT_DISABLED;
@@ -9262,6 +9268,11 @@
mutex_lock(&this_afe.afe_cmd_lock);
+ if (!this_afe.lpass_hw_core_client_hdl) {
+ pr_debug("%s: SSR in progress, return\n", __func__);
+ goto done;
+ }
+
memset(cmd_ptr, 0, sizeof(hw_vote_cfg));
cmd_ptr->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -9278,6 +9289,12 @@
pr_debug("%s: lpass core hw unvote opcode[0x%x] hw id[0x%x]\n",
__func__, cmd_ptr->hdr.opcode, cmd_ptr->hw_block_id);
+ if (cmd_ptr->client_handle <= 0) {
+ pr_err("%s: invalid client handle\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
atomic_set(&this_afe.status, 0);
atomic_set(&this_afe.state, 1);
ret = apr_send_pkt(this_afe.apr, (uint32_t *) cmd_ptr);
diff --git a/dsp/q6lsm.c b/dsp/q6lsm.c
index 2a497b1..9c5bf3d 100644
--- a/dsp/q6lsm.c
+++ b/dsp/q6lsm.c
@@ -285,12 +285,15 @@
static int q6lsm_mmap_apr_dereg(void)
{
- if (atomic_read(&lsm_common.apr_users) <= 0) {
- WARN("%s: APR common port already closed\n", __func__);
- } else {
- if (atomic_dec_return(&lsm_common.apr_users) == 0) {
- apr_deregister(lsm_common.apr);
- pr_debug("%s: APR De-Register common port\n", __func__);
+ if (lsm_common.apr) {
+ if (atomic_read(&lsm_common.apr_users) <= 0) {
+ WARN("%s: APR common port already closed\n", __func__);
+ } else {
+ if (atomic_dec_return(&lsm_common.apr_users) == 0) {
+ apr_deregister(lsm_common.apr);
+ pr_debug("%s: APR De-Register common port\n",
+ __func__);
+ }
}
}
return 0;
diff --git a/include/asoc/wcd-mbhc-v2.h b/include/asoc/wcd-mbhc-v2.h
index 9341e3d..1f9d64e 100644
--- a/include/asoc/wcd-mbhc-v2.h
+++ b/include/asoc/wcd-mbhc-v2.h
@@ -140,7 +140,6 @@
#define FW_READ_ATTEMPTS 15
#define FW_READ_TIMEOUT 4000000
#define FAKE_REM_RETRY_ATTEMPTS 3
-#define MAX_IMPED 60000
#define WCD_MBHC_BTN_PRESS_COMPL_TIMEOUT_MS 50
#define ANC_DETECT_RETRY_CNT 7
diff --git a/soc/pinctrl-lpi.c b/soc/pinctrl-lpi.c
index 157e2c5..ba39129 100644
--- a/soc/pinctrl-lpi.c
+++ b/soc/pinctrl-lpi.c
@@ -23,6 +23,7 @@
#include "pinctrl-utils.h"
#define LPI_AUTO_SUSPEND_DELAY 100 /* delay in msec */
+#define LPI_AUTO_SUSPEND_DELAY_ERROR 1 /* delay in msec */
#define LPI_ADDRESS_SIZE 0x20000
#define LPI_SLEW_ADDRESS_SIZE 0x1000
@@ -85,6 +86,7 @@
* @base: stores one of gpio_base or slew_base at a given time.
* @gpio_base: Address base of LPI GPIO PAD.
* @slew_base: Address base of LPI SLEW PAD.
+ * @lpi_slew_reg: Address for lpi slew reg.
* @pullup: Constant current which flow through GPIO output buffer.
* @strength: No, Low, Medium, High
* @function: See lpi_gpio_functions[]
@@ -98,6 +100,7 @@
char __iomem *base;
char __iomem *gpio_base;
char __iomem *slew_base;
+ char __iomem *lpi_slew_reg;
unsigned int pullup;
unsigned int strength;
unsigned int function;
@@ -125,6 +128,7 @@
#define LPI_TLMM_MAX_PINS 100
static u32 lpi_offset[LPI_TLMM_MAX_PINS];
static u32 lpi_slew_offset[LPI_TLMM_MAX_PINS];
+static u32 lpi_slew_base[LPI_TLMM_MAX_PINS];
static const char *const lpi_gpio_functions[] = {
[LPI_GPIO_FUNC_INDEX_GPIO] = LPI_GPIO_FUNC_GPIO,
@@ -365,6 +369,12 @@
pad->base = pad->slew_base;
pad->offset = 0;
mutex_lock(&state->slew_access_lock);
+ if (pad->lpi_slew_reg != NULL) {
+ pad->base = pad->lpi_slew_reg;
+ lpi_gpio_write(pad, LPI_SLEW_REG_VAL_CTL, arg);
+ pad->base = pad->slew_base;
+ goto slew_exit;
+ }
val = lpi_gpio_read(pad, LPI_SLEW_REG_VAL_CTL);
pad->offset = pad->slew_offset;
for (i = 0; i < LPI_SLEW_BITS_SIZE; i++) {
@@ -377,6 +387,7 @@
}
pad->offset = 0;
lpi_gpio_write(pad, LPI_SLEW_REG_VAL_CTL, val);
+slew_exit:
mutex_unlock(&state->slew_access_lock);
break;
default:
@@ -645,6 +656,16 @@
__func__, ret);
}
+ ret = of_property_read_u32_array(dev->of_node,
+ "qcom,lpi-slew-base-tbl",
+ lpi_slew_base, npins);
+ if (ret < 0) {
+ for (i = 0; i < npins; i++)
+ lpi_slew_base[i] = LPI_SLEW_OFFSET_INVALID;
+ dev_dbg(dev, "%s: error in reading lpi slew table: %d\n",
+ __func__, ret);
+ }
+
state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
@@ -711,6 +732,11 @@
pad->gpio_offset = lpi_offset[i];
pad->slew_offset = lpi_slew_offset[i];
pad->offset = pad->gpio_offset;
+ pad->lpi_slew_reg = NULL;
+ if ((lpi_slew_base[i] != LPI_SLEW_OFFSET_INVALID) &&
+ lpi_slew_base[i])
+ pad->lpi_slew_reg = devm_ioremap(dev,
+ lpi_slew_base[i], 0x4);
}
state->chip = lpi_gpio_template;
@@ -824,13 +850,19 @@
mutex_lock(&state->core_hw_vote_lock);
ret = clk_prepare_enable(state->lpass_core_hw_vote);
- if (ret < 0)
+ if (ret < 0) {
+ pm_runtime_set_autosuspend_delay(dev,
+ LPI_AUTO_SUSPEND_DELAY_ERROR);
dev_err(dev, "%s:lpass core hw island enable failed\n",
__func__);
- else
+ goto exit;
+ } else {
state->core_hw_vote_status = true;
+ }
pm_runtime_set_autosuspend_delay(dev, LPI_AUTO_SUSPEND_DELAY);
+
+exit:
mutex_unlock(&state->core_hw_vote_lock);
return 0;
}
diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c
index 9ad849e..44d245d 100644
--- a/soc/swr-mstr-ctrl.c
+++ b/soc/swr-mstr-ctrl.c
@@ -18,8 +18,6 @@
#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
#include <soc/soundwire.h>
#include <soc/swr-common.h>
#include <linux/regmap.h>
@@ -42,6 +40,8 @@
#define SWR_HSTOP_MAX_VAL 0xF
#define SWR_HSTART_MIN_VAL 0x0
+#define ERR_AUTO_SUSPEND_TIMER_VAL 0x1
+
#define SWRM_INTERRUPT_STATUS_MASK 0x1FDFD
/* pm runtime auto suspend timer in msecs */
static int auto_suspend_timer = SWR_AUTO_SUSPEND_DELAY * 1000;
@@ -77,30 +77,19 @@
#define SWRM_MAX_PORT_REG 120
#define SWRM_MAX_INIT_REG 11
-#define SWR_MSTR_MAX_REG_ADDR 0x1740
-#define SWR_MSTR_START_REG_ADDR 0x00
-#define SWR_MSTR_MAX_BUF_LEN 32
-#define BYTES_PER_LINE 12
-#define SWR_MSTR_RD_BUF_LEN 8
-#define SWR_MSTR_WR_BUF_LEN 32
-
#define MAX_FIFO_RD_FAIL_RETRY 3
-static struct swr_mstr_ctrl *dbgswrm;
-static struct dentry *debugfs_swrm_dent;
-static struct dentry *debugfs_peek;
-static struct dentry *debugfs_poke;
-static struct dentry *debugfs_reg_dump;
-static unsigned int read_data;
-
static bool swrm_lock_sleep(struct swr_mstr_ctrl *swrm);
static void swrm_unlock_sleep(struct swr_mstr_ctrl *swrm);
+static u32 swr_master_read(struct swr_mstr_ctrl *swrm, unsigned int reg_addr);
+static void swr_master_write(struct swr_mstr_ctrl *swrm, u16 reg_addr, u32 val);
static bool swrm_is_msm_variant(int val)
{
return (val == SWRM_VERSION_1_3);
}
+#ifdef CONFIG_DEBUG_FS
static int swrm_debug_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
@@ -130,19 +119,26 @@
return 0;
}
-static ssize_t swrm_reg_show(char __user *ubuf, size_t count,
- loff_t *ppos)
+static ssize_t swrm_reg_show(struct swr_mstr_ctrl *swrm, char __user *ubuf,
+ size_t count, loff_t *ppos)
{
int i, reg_val, len;
ssize_t total = 0;
char tmp_buf[SWR_MSTR_MAX_BUF_LEN];
+ int rem = 0;
if (!ubuf || !ppos)
return 0;
- for (i = (((int) *ppos / BYTES_PER_LINE) + SWR_MSTR_START_REG_ADDR);
- i <= SWR_MSTR_MAX_REG_ADDR; i += 4) {
- reg_val = dbgswrm->read(dbgswrm->handle, i);
+ i = ((int) *ppos + SWR_MSTR_START_REG_ADDR);
+ rem = i%4;
+
+ if (rem)
+ i = (i - rem);
+
+ for (; i <= SWR_MSTR_MAX_REG_ADDR; i += 4) {
+ usleep_range(100, 150);
+ reg_val = swr_master_read(swrm, i);
len = snprintf(tmp_buf, 25, "0x%.3x: 0x%.2x\n", i, reg_val);
if (len < 0) {
pr_err("%s: fail to fill the buffer\n", __func__);
@@ -164,85 +160,142 @@
return total;
}
-static ssize_t swrm_debug_read(struct file *file, char __user *ubuf,
+static ssize_t swrm_debug_reg_dump(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
- char lbuf[SWR_MSTR_RD_BUF_LEN];
- char *access_str;
- ssize_t ret_cnt;
+ struct swr_mstr_ctrl *swrm;
if (!count || !file || !ppos || !ubuf)
return -EINVAL;
- access_str = file->private_data;
+ swrm = file->private_data;
+ if (!swrm)
+ return -EINVAL;
+
if (*ppos < 0)
return -EINVAL;
- if (!strcmp(access_str, "swrm_peek")) {
- snprintf(lbuf, sizeof(lbuf), "0x%x\n", read_data);
- ret_cnt = simple_read_from_buffer(ubuf, count, ppos, lbuf,
- strnlen(lbuf, 7));
- } else if (!strcmp(access_str, "swrm_reg_dump")) {
- ret_cnt = swrm_reg_show(ubuf, count, ppos);
- } else {
- pr_err("%s: %s not permitted to read\n", __func__, access_str);
- ret_cnt = -EPERM;
- }
- return ret_cnt;
+ return swrm_reg_show(swrm, ubuf, count, ppos);
}
-static ssize_t swrm_debug_write(struct file *filp,
- const char __user *ubuf, size_t cnt, loff_t *ppos)
+static ssize_t swrm_debug_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ char lbuf[SWR_MSTR_RD_BUF_LEN];
+ struct swr_mstr_ctrl *swrm = NULL;
+
+ if (!count || !file || !ppos || !ubuf)
+ return -EINVAL;
+
+ swrm = file->private_data;
+ if (!swrm)
+ return -EINVAL;
+
+ if (*ppos < 0)
+ return -EINVAL;
+
+ snprintf(lbuf, sizeof(lbuf), "0x%x\n", swrm->read_data);
+
+ return simple_read_from_buffer(ubuf, count, ppos, lbuf,
+ strnlen(lbuf, 7));
+}
+
+static ssize_t swrm_debug_peek_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ char lbuf[SWR_MSTR_RD_BUF_LEN];
+ int rc;
+ u32 param[5];
+ struct swr_mstr_ctrl *swrm = NULL;
+
+ if (!count || !file || !ppos || !ubuf)
+ return -EINVAL;
+
+ swrm = file->private_data;
+ if (!swrm)
+ return -EINVAL;
+
+ if (*ppos < 0)
+ return -EINVAL;
+
+ if (count > sizeof(lbuf) - 1)
+ return -EINVAL;
+
+ rc = copy_from_user(lbuf, ubuf, count);
+ if (rc)
+ return -EFAULT;
+
+ lbuf[count] = '\0';
+ rc = get_parameters(lbuf, param, 1);
+ if ((param[0] <= SWR_MSTR_MAX_REG_ADDR) && (rc == 0))
+ swrm->read_data = swr_master_read(swrm, param[0]);
+ else
+ rc = -EINVAL;
+
+ if (rc == 0)
+ rc = count;
+ else
+ dev_err(swrm->dev, "%s: rc = %d\n", __func__, rc);
+
+ return rc;
+}
+
+static ssize_t swrm_debug_write(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
{
char lbuf[SWR_MSTR_WR_BUF_LEN];
int rc;
u32 param[5];
- char *access_str;
+ struct swr_mstr_ctrl *swrm;
- if (!filp || !ppos || !ubuf)
+ if (!file || !ppos || !ubuf)
return -EINVAL;
- access_str = filp->private_data;
- if (cnt > sizeof(lbuf) - 1)
+ swrm = file->private_data;
+ if (!swrm)
return -EINVAL;
- rc = copy_from_user(lbuf, ubuf, cnt);
+ if (count > sizeof(lbuf) - 1)
+ return -EINVAL;
+
+ rc = copy_from_user(lbuf, ubuf, count);
if (rc)
return -EFAULT;
- lbuf[cnt] = '\0';
- if (!strcmp(access_str, "swrm_poke")) {
- /* write */
- rc = get_parameters(lbuf, param, 2);
- if ((param[0] <= SWR_MSTR_MAX_REG_ADDR) &&
- (param[1] <= 0xFFFFFFFF) &&
- (rc == 0))
- rc = dbgswrm->write(dbgswrm->handle, param[0],
- param[1]);
- else
- rc = -EINVAL;
- } else if (!strcmp(access_str, "swrm_peek")) {
- /* read */
- rc = get_parameters(lbuf, param, 1);
- if ((param[0] <= SWR_MSTR_MAX_REG_ADDR) && (rc == 0))
- read_data = dbgswrm->read(dbgswrm->handle, param[0]);
- else
- rc = -EINVAL;
- }
+ lbuf[count] = '\0';
+ rc = get_parameters(lbuf, param, 2);
+ if ((param[0] <= SWR_MSTR_MAX_REG_ADDR) &&
+ (param[1] <= 0xFFFFFFFF) &&
+ (rc == 0))
+ swr_master_write(swrm, param[0], param[1]);
+ else
+ rc = -EINVAL;
+
if (rc == 0)
- rc = cnt;
+ rc = count;
else
pr_err("%s: rc = %d\n", __func__, rc);
return rc;
}
-static const struct file_operations swrm_debug_ops = {
+static const struct file_operations swrm_debug_read_ops = {
.open = swrm_debug_open,
- .write = swrm_debug_write,
+ .write = swrm_debug_peek_write,
.read = swrm_debug_read,
};
+static const struct file_operations swrm_debug_write_ops = {
+ .open = swrm_debug_open,
+ .write = swrm_debug_write,
+};
+
+static const struct file_operations swrm_debug_dump_ops = {
+ .open = swrm_debug_open,
+ .read = swrm_debug_reg_dump,
+};
+#endif
+
static void swrm_reg_dump(struct swr_mstr_ctrl *swrm,
u32 *reg, u32 *val, int len, const char* func)
{
@@ -301,6 +354,15 @@
ret = -ENODEV;
goto exit;
}
+ if (swrm->core_vote) {
+ ret = swrm->core_vote(swrm->handle, true);
+ if (ret) {
+ dev_err_ratelimited(swrm->dev,
+ "%s: clock enable req failed",
+ __func__);
+ goto exit;
+ }
+ }
swrm->clk_ref_count++;
if (swrm->clk_ref_count == 1) {
ret = swrm->clk(swrm->handle, true);
@@ -1545,6 +1607,12 @@
struct swr_device *swr_dev;
struct swr_master *mstr = &swrm->master;
+ if (!swrm->dev_up || swrm->state == SWR_MSTR_SSR) {
+ complete(&swrm->broadcast);
+ dev_dbg(swrm->dev, "%s swrm is not up\n", __func__);
+ return IRQ_NONE;
+ }
+
if (unlikely(swrm_lock_sleep(swrm) == false)) {
dev_err(swrm->dev, "%s Failed to hold suspend\n", __func__);
return IRQ_NONE;
@@ -1559,7 +1627,12 @@
ret = IRQ_NONE;
goto err_audio_hw_vote;
}
- swrm_clk_request(swrm, true);
+ ret = swrm_clk_request(swrm, true);
+ if (ret) {
+ dev_err(dev, "%s: swrm clk failed\n", __func__);
+ ret = IRQ_NONE;
+ goto err_audio_core_vote;
+ }
mutex_unlock(&swrm->reslock);
intr_sts = swr_master_read(swrm, SWRM_INTERRUPT_STATUS);
@@ -1735,6 +1808,7 @@
mutex_lock(&swrm->reslock);
swrm_clk_request(swrm, false);
+err_audio_core_vote:
swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, false);
err_audio_hw_vote:
@@ -2123,6 +2197,7 @@
swrm->swrm_base_reg, SWRM_MAX_REGISTER);
}
+ swrm->core_vote = pdata->core_vote;
swrm->clk = pdata->clk;
if (!swrm->clk) {
dev_err(&pdev->dev, "%s: swrm->clk is NULL\n",
@@ -2330,23 +2405,23 @@
if (pdev->dev.of_node)
of_register_swr_devices(&swrm->master);
- dbgswrm = swrm;
- debugfs_swrm_dent = debugfs_create_dir(dev_name(&pdev->dev), 0);
- if (!IS_ERR(debugfs_swrm_dent)) {
- debugfs_peek = debugfs_create_file("swrm_peek",
- S_IFREG | 0444, debugfs_swrm_dent,
- (void *) "swrm_peek", &swrm_debug_ops);
+#ifdef CONFIG_DEBUG_FS
+ swrm->debugfs_swrm_dent = debugfs_create_dir(dev_name(&pdev->dev), 0);
+ if (!IS_ERR(swrm->debugfs_swrm_dent)) {
+ swrm->debugfs_peek = debugfs_create_file("swrm_peek",
+ S_IFREG | 0444, swrm->debugfs_swrm_dent,
+ (void *) swrm, &swrm_debug_read_ops);
- debugfs_poke = debugfs_create_file("swrm_poke",
- S_IFREG | 0444, debugfs_swrm_dent,
- (void *) "swrm_poke", &swrm_debug_ops);
+ swrm->debugfs_poke = debugfs_create_file("swrm_poke",
+ S_IFREG | 0444, swrm->debugfs_swrm_dent,
+ (void *) swrm, &swrm_debug_write_ops);
- debugfs_reg_dump = debugfs_create_file("swrm_reg_dump",
- S_IFREG | 0444, debugfs_swrm_dent,
- (void *) "swrm_reg_dump",
- &swrm_debug_ops);
+ swrm->debugfs_reg_dump = debugfs_create_file("swrm_reg_dump",
+ S_IFREG | 0444, swrm->debugfs_swrm_dent,
+ (void *) swrm,
+ &swrm_debug_dump_ops);
}
-
+#endif
ret = device_init_wakeup(swrm->dev, true);
if (ret) {
dev_err(swrm->dev, "Device wakeup init failed: %d\n", ret);
@@ -2435,6 +2510,7 @@
struct platform_device *pdev = to_platform_device(dev);
struct swr_mstr_ctrl *swrm = platform_get_drvdata(pdev);
int ret = 0;
+ bool swrm_clk_req_err = false;
bool hw_core_err = false;
bool aud_core_err = false;
struct swr_master *mstr = &swrm->master;
@@ -2468,7 +2544,7 @@
* Set autosuspend timer to 1 for
* master to enter into suspend.
*/
- auto_suspend_timer = 1;
+ swrm_clk_req_err = true;
goto exit;
}
if (!swrm->clk_stop_mode0_supp || swrm->state == SWR_MSTR_SSR) {
@@ -2511,8 +2587,12 @@
swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, false);
if (!hw_core_err)
swrm_request_hw_vote(swrm, LPASS_HW_CORE, false);
- pm_runtime_set_autosuspend_delay(&pdev->dev, auto_suspend_timer);
- auto_suspend_timer = SWR_AUTO_SUSPEND_DELAY * 1000;
+ if (swrm_clk_req_err)
+ pm_runtime_set_autosuspend_delay(&pdev->dev,
+ ERR_AUTO_SUSPEND_TIMER_VAL);
+ else
+ pm_runtime_set_autosuspend_delay(&pdev->dev,
+ auto_suspend_timer);
mutex_unlock(&swrm->reslock);
return ret;
@@ -2584,7 +2664,12 @@
mutex_lock(&swrm->reslock);
usleep_range(100, 105);
}
- swrm_clk_request(swrm, false);
+ ret = swrm_clk_request(swrm, false);
+ if (ret) {
+ dev_err(dev, "%s: swrmn clk failed\n", __func__);
+ ret = 0;
+ goto exit;
+ }
if (swrm->clk_stop_mode0_supp) {
if (swrm->wake_irq > 0) {
diff --git a/soc/swr-mstr-ctrl.h b/soc/swr-mstr-ctrl.h
index e05ede2..321e84f 100644
--- a/soc/swr-mstr-ctrl.h
+++ b/soc/swr-mstr-ctrl.h
@@ -11,6 +11,18 @@
#include <soc/qcom/pm.h>
#include <soc/swr-common.h>
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#define SWR_MSTR_MAX_REG_ADDR 0x1740
+#define SWR_MSTR_START_REG_ADDR 0x00
+#define SWR_MSTR_MAX_BUF_LEN 32
+#define BYTES_PER_LINE 12
+#define SWR_MSTR_RD_BUF_LEN 8
+#define SWR_MSTR_WR_BUF_LEN 32
+#endif
+
#define SWR_ROW_48 0
#define SWR_ROW_50 1
#define SWR_ROW_64 2
@@ -91,6 +103,7 @@
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 (*reg_irq)(void *handle, irqreturn_t(*irq_handler)(int irq,
void *data), void *swr_handle, int type);
};
@@ -120,6 +133,7 @@
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 (*reg_irq)(void *handle, irqreturn_t(*irq_handler)(int irq,
void *data), void *swr_handle, int type);
int irq;
@@ -160,6 +174,13 @@
u32 swr_irq_wakeup_capable;
int hw_core_clk_en;
int aud_core_clk_en;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_swrm_dent;
+ struct dentry *debugfs_peek;
+ struct dentry *debugfs_poke;
+ struct dentry *debugfs_reg_dump;
+ unsigned int read_data;
+#endif
};
#endif /* _SWR_WCD_CTRL_H */