diff --git a/asoc/codecs/bolero/bolero-cdc.c b/asoc/codecs/bolero/bolero-cdc.c index 63d8d1013a86..066b72eb08ca 100644 --- a/asoc/codecs/bolero/bolero-cdc.c +++ b/asoc/codecs/bolero/bolero-cdc.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include @@ -470,6 +470,129 @@ void bolero_unregister_res_clk(struct device *dev) } EXPORT_SYMBOL(bolero_unregister_res_clk); +static u8 bolero_dmic_clk_div_get(struct snd_soc_component *component, + int mode) +{ + struct bolero_priv* priv = snd_soc_component_get_drvdata(component); + int macro = (mode ? VA_MACRO : TX_MACRO); + int ret = 0; + + if (priv->macro_params[macro].clk_div_get) { + ret = priv->macro_params[macro].clk_div_get(component); + if (ret > 0) + return ret; + } + + return 1; +} + +int bolero_dmic_clk_enable(struct snd_soc_component *component, + u32 dmic, u32 tx_mode, bool enable) +{ + struct bolero_priv* priv = snd_soc_component_get_drvdata(component); + u8 dmic_clk_en = 0x01; + u16 dmic_clk_reg = 0; + s32 *dmic_clk_cnt = NULL; + u8 *dmic_clk_div = NULL; + u8 freq_change_mask = 0; + u8 clk_div = 0; + + dev_dbg(component->dev, "%s: enable: %d, tx_mode:%d, dmic: %d\n", + __func__, enable, tx_mode, dmic); + + switch (dmic) { + case 0: + case 1: + dmic_clk_cnt = &(priv->dmic_0_1_clk_cnt); + dmic_clk_div = &(priv->dmic_0_1_clk_div); + dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL; + freq_change_mask = 0x01; + break; + case 2: + case 3: + dmic_clk_cnt = &(priv->dmic_2_3_clk_cnt); + dmic_clk_div = &(priv->dmic_2_3_clk_div); + dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL; + freq_change_mask = 0x02; + break; + case 4: + case 5: + dmic_clk_cnt = &(priv->dmic_4_5_clk_cnt); + dmic_clk_div = &(priv->dmic_4_5_clk_div); + dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC2_CTL; + freq_change_mask = 0x04; + break; + case 6: + case 7: + dmic_clk_cnt = &(priv->dmic_6_7_clk_cnt); + dmic_clk_div = &(priv->dmic_6_7_clk_div); + dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL; + freq_change_mask = 0x08; + break; + default: + dev_err(component->dev, "%s: Invalid DMIC Selection\n", + __func__); + return -EINVAL; + } + dev_dbg(component->dev, "%s: DMIC%d dmic_clk_cnt %d\n", + __func__, dmic, *dmic_clk_cnt); + if (enable) { + clk_div = bolero_dmic_clk_div_get(component, tx_mode); + (*dmic_clk_cnt)++; + if (*dmic_clk_cnt == 1) { + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_DMIC_CFG, + 0x80, 0x00); + snd_soc_component_update_bits(component, dmic_clk_reg, + 0x0E, clk_div << 0x1); + snd_soc_component_update_bits(component, dmic_clk_reg, + dmic_clk_en, dmic_clk_en); + } else { + if (*dmic_clk_div > clk_div) { + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_DMIC_CFG, + freq_change_mask, freq_change_mask); + snd_soc_component_update_bits(component, dmic_clk_reg, + 0x0E, clk_div << 0x1); + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_DMIC_CFG, + freq_change_mask, 0x00); + } else { + clk_div = *dmic_clk_div; + } + } + *dmic_clk_div = clk_div; + } else { + (*dmic_clk_cnt)--; + if (*dmic_clk_cnt == 0) { + snd_soc_component_update_bits(component, dmic_clk_reg, + dmic_clk_en, 0); + clk_div = 0; + snd_soc_component_update_bits(component, dmic_clk_reg, + 0x0E, clk_div << 0x1); + } else { + clk_div = bolero_dmic_clk_div_get(component, tx_mode); + if (*dmic_clk_div > clk_div) { + clk_div = bolero_dmic_clk_div_get(component, !tx_mode); + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_DMIC_CFG, + freq_change_mask, freq_change_mask); + snd_soc_component_update_bits(component, dmic_clk_reg, + 0x0E, clk_div << 0x1); + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_DMIC_CFG, + freq_change_mask, 0x00); + } else { + clk_div = *dmic_clk_div; + } + } + *dmic_clk_div = clk_div; + } + + return 0; +} +EXPORT_SYMBOL(bolero_dmic_clk_enable); + /** * bolero_register_macro - Registers macro to bolero * @@ -518,6 +641,9 @@ int bolero_register_macro(struct device *dev, u16 macro_id, priv->macro_params[macro_id].reg_evt_listener = ops->reg_evt_listener; } + if (macro_id == TX_MACRO || macro_id == VA_MACRO) + priv->macro_params[macro_id].clk_div_get = ops->clk_div_get; + if (priv->version == BOLERO_VERSION_2_1) { if (macro_id == VA_MACRO) priv->macro_params[macro_id].reg_wake_irq = @@ -588,6 +714,8 @@ void bolero_unregister_macro(struct device *dev, u16 macro_id) priv->macro_params[macro_id].clk_switch = NULL; priv->macro_params[macro_id].reg_evt_listener = NULL; } + if (macro_id == TX_MACRO || macro_id == VA_MACRO) + priv->macro_params[macro_id].clk_div_get = NULL; priv->num_dais -= priv->macro_params[macro_id].num_dais; priv->num_macros_registered--; diff --git a/asoc/codecs/bolero/bolero-cdc.h b/asoc/codecs/bolero/bolero-cdc.h index 2ec4617447bd..dd58eed87c86 100644 --- a/asoc/codecs/bolero/bolero-cdc.h +++ b/asoc/codecs/bolero/bolero-cdc.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef BOLERO_CDC_H @@ -50,6 +50,12 @@ enum { BOLERO_MACRO_EVT_BCS_CLK_OFF }; +enum { + DMIC_TX = 0, + DMIC_VA = 1, + +}; + struct macro_ops { int (*init)(struct snd_soc_component *component); int (*exit)(struct snd_soc_component *component); @@ -63,6 +69,7 @@ struct macro_ops { int (*set_port_map)(struct snd_soc_component *component, u32 uc, u32 size, void *data); int (*clk_switch)(struct snd_soc_component *component); + int (*clk_div_get)(struct snd_soc_component *component); int (*reg_evt_listener)(struct snd_soc_component *component, bool en); char __iomem *io_base; u16 clk_id_req; @@ -93,6 +100,8 @@ int bolero_register_event_listener(struct snd_soc_component *component, void bolero_wsa_pa_on(struct device *dev); bool bolero_check_core_votes(struct device *dev); int bolero_get_version(struct device *dev); +int bolero_dmic_clk_enable(struct snd_soc_component *component, + u32 dmic, u32 tx_mode, bool enable); #else static inline int bolero_register_res_clk(struct device *dev, rsc_clk_cb_t cb) { @@ -177,5 +186,11 @@ static int bolero_get_version(struct device *dev) { return 0; } + +static int bolero_dmic_clk_enable(struct snd_soc_component *component, + u32 dmic, u32 tx_mode, bool enable) +{ + return 0; +} #endif /* CONFIG_SND_SOC_BOLERO */ #endif /* BOLERO_CDC_H */ diff --git a/asoc/codecs/bolero/internal.h b/asoc/codecs/bolero/internal.h index d18568b0eb16..503443158c4a 100644 --- a/asoc/codecs/bolero/internal.h +++ b/asoc/codecs/bolero/internal.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _BOLERO_INTERNAL_H @@ -82,6 +82,14 @@ struct bolero_priv { struct blocking_notifier_head notifier; struct device *clk_dev; rsc_clk_cb_t rsc_clk_cb; + s32 dmic_0_1_clk_cnt; + s32 dmic_2_3_clk_cnt; + s32 dmic_4_5_clk_cnt; + s32 dmic_6_7_clk_cnt; + u8 dmic_0_1_clk_div; + u8 dmic_2_3_clk_div; + u8 dmic_4_5_clk_div; + u8 dmic_6_7_clk_div; }; struct regmap *bolero_regmap_init(struct device *dev, diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c index 80a0ea84acb2..669f9f009ac9 100644 --- a/asoc/codecs/bolero/tx-macro.c +++ b/asoc/codecs/bolero/tx-macro.c @@ -158,10 +158,6 @@ struct tx_macro_priv { struct work_struct tx_macro_add_child_devices_work; struct hpf_work tx_hpf_work[NUM_DECIMATORS]; struct tx_mute_work tx_mute_dwork[NUM_DECIMATORS]; - s32 dmic_0_1_clk_cnt; - s32 dmic_2_3_clk_cnt; - s32 dmic_4_5_clk_cnt; - s32 dmic_6_7_clk_cnt; u16 dmic_clk_div; u32 version; u32 is_used_tx_swr_gpio; @@ -814,17 +810,9 @@ static int tx_macro_enable_dmic(struct snd_soc_dapm_widget *w, { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - u8 dmic_clk_en = 0x01; - u16 dmic_clk_reg = 0; - s32 *dmic_clk_cnt = NULL; unsigned int dmic = 0; int ret = 0; char *wname = NULL; - struct device *tx_dev = NULL; - struct tx_macro_priv *tx_priv = NULL; - - if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) - return -EINVAL; wname = strpbrk(w->name, "01234567"); if (!wname) { @@ -839,54 +827,15 @@ static int tx_macro_enable_dmic(struct snd_soc_dapm_widget *w, return -EINVAL; } - switch (dmic) { - case 0: - case 1: - dmic_clk_cnt = &(tx_priv->dmic_0_1_clk_cnt); - dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL; - break; - case 2: - case 3: - dmic_clk_cnt = &(tx_priv->dmic_2_3_clk_cnt); - dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL; - break; - case 4: - case 5: - dmic_clk_cnt = &(tx_priv->dmic_4_5_clk_cnt); - dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC2_CTL; - break; - case 6: - case 7: - dmic_clk_cnt = &(tx_priv->dmic_6_7_clk_cnt); - dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL; - break; - default: - dev_err(component->dev, "%s: Invalid DMIC Selection\n", - __func__); - return -EINVAL; - } - dev_dbg(component->dev, "%s: event %d DMIC%d dmic_clk_cnt %d\n", - __func__, event, dmic, *dmic_clk_cnt); + dev_dbg(component->dev, "%s: event %d DMIC%d\n", + __func__, event, dmic); switch (event) { case SND_SOC_DAPM_PRE_PMU: - (*dmic_clk_cnt)++; - if (*dmic_clk_cnt == 1) { - snd_soc_component_update_bits(component, - BOLERO_CDC_VA_TOP_CSR_DMIC_CFG, - 0x80, 0x00); - - snd_soc_component_update_bits(component, dmic_clk_reg, - 0x0E, tx_priv->dmic_clk_div << 0x1); - snd_soc_component_update_bits(component, dmic_clk_reg, - dmic_clk_en, dmic_clk_en); - } + bolero_dmic_clk_enable(component, dmic, DMIC_TX, true); break; case SND_SOC_DAPM_POST_PMD: - (*dmic_clk_cnt)--; - if (*dmic_clk_cnt == 0) - snd_soc_component_update_bits(component, dmic_clk_reg, - dmic_clk_en, 0); + bolero_dmic_clk_enable(component, dmic, DMIC_TX, false); break; } @@ -2590,6 +2539,17 @@ exit: return ret; } +static int tx_macro_clk_div_get(struct snd_soc_component *component) +{ + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + return tx_priv->dmic_clk_div; +} + static int tx_macro_clk_switch(struct snd_soc_component *component) { struct device *tx_dev = NULL; @@ -3093,6 +3053,7 @@ static void tx_macro_init_ops(struct macro_ops *ops, ops->event_handler = tx_macro_event_handler; ops->reg_wake_irq = tx_macro_reg_wake_irq; ops->set_port_map = tx_macro_set_port_map; + ops->clk_div_get = tx_macro_clk_div_get; ops->clk_switch = tx_macro_clk_switch; ops->reg_evt_listener = tx_macro_register_event_listener; } diff --git a/asoc/codecs/bolero/va-macro.c b/asoc/codecs/bolero/va-macro.c index 319fc63319e3..116a2dae30c6 100644 --- a/asoc/codecs/bolero/va-macro.c +++ b/asoc/codecs/bolero/va-macro.c @@ -142,10 +142,6 @@ struct va_macro_priv { struct va_mute_work va_mute_dwork[VA_MACRO_NUM_DECIMATORS]; unsigned long active_ch_mask[VA_MACRO_MAX_DAIS]; unsigned long active_ch_cnt[VA_MACRO_MAX_DAIS]; - s32 dmic_0_1_clk_cnt; - s32 dmic_2_3_clk_cnt; - s32 dmic_4_5_clk_cnt; - s32 dmic_6_7_clk_cnt; u16 dmic_clk_div; u16 va_mclk_users; int swr_clk_users; @@ -196,6 +192,17 @@ static bool va_macro_get_data(struct snd_soc_component *component, return true; } +static int va_macro_clk_div_get(struct snd_soc_component *component) +{ + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + return va_priv->dmic_clk_div; +} + static int va_macro_mclk_enable(struct va_macro_priv *va_priv, bool mclk_enable, bool dapm) { @@ -978,81 +985,32 @@ static int va_macro_enable_dmic(struct snd_soc_dapm_widget *w, { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - u8 dmic_clk_en = 0x01; - u16 dmic_clk_reg; - s32 *dmic_clk_cnt; - unsigned int dmic; - int ret; + unsigned int dmic = 0; + int ret = 0; char *wname; - struct device *va_dev = NULL; - struct va_macro_priv *va_priv = NULL; - - if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) - return -EINVAL; wname = strpbrk(w->name, "01234567"); if (!wname) { - dev_err(va_dev, "%s: widget not found\n", __func__); + dev_err(component->dev, "%s: widget not found\n", __func__); return -EINVAL; } ret = kstrtouint(wname, 10, &dmic); if (ret < 0) { - dev_err(va_dev, "%s: Invalid DMIC line on the codec\n", + dev_err(component->dev, "%s: Invalid DMIC line on the codec\n", __func__); return -EINVAL; } - switch (dmic) { - case 0: - case 1: - dmic_clk_cnt = &(va_priv->dmic_0_1_clk_cnt); - dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL; - break; - case 2: - case 3: - dmic_clk_cnt = &(va_priv->dmic_2_3_clk_cnt); - dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL; - break; - case 4: - case 5: - dmic_clk_cnt = &(va_priv->dmic_4_5_clk_cnt); - dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC2_CTL; - break; - case 6: - case 7: - dmic_clk_cnt = &(va_priv->dmic_6_7_clk_cnt); - dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL; - break; - default: - dev_err(va_dev, "%s: Invalid DMIC Selection\n", - __func__); - return -EINVAL; - } - dev_dbg(va_dev, "%s: event %d DMIC%d dmic_clk_cnt %d\n", - __func__, event, dmic, *dmic_clk_cnt); + dev_dbg(component->dev, "%s: event %d DMIC%d\n", + __func__, event, dmic); switch (event) { case SND_SOC_DAPM_PRE_PMU: - (*dmic_clk_cnt)++; - if (*dmic_clk_cnt == 1) { - snd_soc_component_update_bits(component, - BOLERO_CDC_VA_TOP_CSR_DMIC_CFG, - 0x80, 0x00); - snd_soc_component_update_bits(component, dmic_clk_reg, - VA_MACRO_TX_DMIC_CLK_DIV_MASK, - va_priv->dmic_clk_div << - VA_MACRO_TX_DMIC_CLK_DIV_SHFT); - snd_soc_component_update_bits(component, dmic_clk_reg, - dmic_clk_en, dmic_clk_en); - } + bolero_dmic_clk_enable(component, dmic, DMIC_VA, true); break; case SND_SOC_DAPM_POST_PMD: - (*dmic_clk_cnt)--; - if (*dmic_clk_cnt == 0) { - snd_soc_component_update_bits(component, dmic_clk_reg, - dmic_clk_en, 0); - } + bolero_dmic_clk_enable(component, dmic, DMIC_VA, false); break; } @@ -2795,6 +2753,7 @@ static void va_macro_init_ops(struct macro_ops *ops, ops->event_handler = va_macro_event_handler; ops->set_port_map = va_macro_set_port_map; ops->reg_wake_irq = va_macro_reg_wake_irq; + ops->clk_div_get = va_macro_clk_div_get; } static int va_macro_probe(struct platform_device *pdev)