diff --git a/asoc/codecs/bolero/bolero-cdc.c b/asoc/codecs/bolero/bolero-cdc.c index 1a6055789bc0..7ccbaa4f2276 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 @@ -476,6 +476,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 * @@ -524,6 +647,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 = @@ -594,6 +720,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 e11f8c715054..c8aa2fb9a0dd 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; } @@ -2665,6 +2614,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; @@ -3168,6 +3128,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 e0a0dd0ee4f4..2dc224909ecc 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; } @@ -2834,6 +2792,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) diff --git a/asoc/sa6155.c b/asoc/sa6155.c index 7335d4fdd23d..3b88c96dd7b7 100644 --- a/asoc/sa6155.c +++ b/asoc/sa6155.c @@ -1,13 +1,4 @@ -/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. +/* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. */ /* * Copyright 2011, The Android Open Source Project @@ -213,7 +204,7 @@ static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = { }, { /* QUAT TDM */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8}, /* RX_0 */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8}, /* RX_1 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */ @@ -222,10 +213,10 @@ static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = { {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */ }, { /* QUIN TDM */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_0 */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_1 */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_2 */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 6}, /* RX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */ @@ -276,9 +267,9 @@ static struct dev_config tdm_tx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = { {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */ }, { /* QUIN TDM */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 6}, /* TX_0 */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 4}, /* TX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* TX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* TX_2 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */ @@ -415,20 +406,20 @@ static unsigned int tdm_rx_slot_offset {0xFFFF}, /* not used */ }, {/* QUAT TDM */ - {0, 4, 8, 12, 16, 20, 24, 28, 0xFFFF},/*AMP OUT*/ + {0, 8, 16, 24, 32, 40, 48, 56, 0xFFFF}, /*8 CH SPKR*/ + {4, 12, 20, 28, 36, 44, 52, 60, 0xFFFF}, /*8 CH SPKR*/ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {28,0xFFFF}, + {60,0xFFFF}, }, {/* QUIN TDM */ - {0, 4, 0xFFFF},/*STEREO SPKR1*/ - {8, 12, 0xFFFF},/*STEREO SPKR2*/ - {16, 20, 0xFFFF},/*STEREO SPKR3*/ - {24, 28, 0xFFFF},/*STEREO SPKR4*/ + {0, 4, 8, 12, 16, 20, 0xFFFF}, + {24, 0xFFFF}, + {28, 0xFFFF}, + {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ @@ -480,14 +471,14 @@ static unsigned int tdm_tx_slot_offset {60,0xFFFF}, }, {/* QUIN TDM */ - {0, 4, 8, 12, 16, 20, 0xFFFF},/*EC/ANC REF*/ + {0, 4, 8, 12, 0xFFFF}, + {16, 20, 0xFFFF}, + {24, 28, 0xFFFF}, {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {20, 0xFFFF}, + {28, 0xFFFF}, } }; diff --git a/asoc/sa8155.c b/asoc/sa8155.c index abd4eb1eafd2..0b409d7aa645 100644 --- a/asoc/sa8155.c +++ b/asoc/sa8155.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. */ /* * Copyright 2011, The Android Open Source Project @@ -205,7 +205,7 @@ static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = { }, { /* QUAT TDM */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8}, /* RX_0 */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8}, /* RX_1 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */ @@ -214,10 +214,10 @@ static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = { {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */ }, { /* QUIN TDM */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_0 */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_1 */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_2 */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 16}, /* RX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */ @@ -268,7 +268,7 @@ static struct dev_config tdm_tx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = { {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */ }, { /* QUIN TDM */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 6}, /* TX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 16}, /* TX_0 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */ @@ -407,24 +407,25 @@ static unsigned int tdm_rx_slot_offset {0xFFFF}, /* not used */ }, {/* QUAT TDM */ - {0, 4, 8, 12, 16, 20, 24, 28, 0xFFFF},/*AMP OUT*/ + {0, 8, 16, 24, 32, 40, 48, 56, 0xFFFF}, /*8 CH SPKR*/ + {4, 12, 20, 28, 36, 44, 52, 60, 0xFFFF}, /*8 CH SPKR*/ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {28,0xFFFF}, + {60,0xFFFF}, }, {/* QUIN TDM */ - {0, 4, 0xFFFF},/*STEREO SPKR1*/ - {8, 12, 0xFFFF},/*STEREO SPKR2*/ - {16, 20, 0xFFFF},/*STEREO SPKR3*/ - {24, 28, 0xFFFF},/*STEREO SPKR4*/ + {0, 8, 16, 24, 32, 40, 48, 56, + 4, 12, 20, 28, 36, 44, 52, 60, 0xFFFF}, /*16 CH SPKR*/ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ - {28, 0xFFFF}, + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {60, 0xFFFF}, } }; @@ -462,7 +463,7 @@ static unsigned int tdm_tx_slot_offset }, {/* QUAT TDM */ {0, 4, 8, 12, 16, 20, 24, 28, - 32, 36, 40, 44, 48, 52, 56, 60, 0xFFFF},/*MIC ARR*/ + 32, 36, 40, 44, 48, 52, 56, 60, 0xFFFF},/*16 CH MIC ARR1*/ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ @@ -472,14 +473,15 @@ static unsigned int tdm_tx_slot_offset {60,0xFFFF}, }, {/* QUIN TDM */ - {0, 4, 8, 12, 16, 20, 0xFFFF},/*EC/ANC REF*/ + {0, 4, 8, 12, 16, 20, 24, 28, + 32, 36, 40, 44, 48, 52, 56, 60, 0xFFFF},/*16 CH MIC ARR2*/ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ - {20, 0xFFFF}, + {60, 0xFFFF}, } }; diff --git a/dsp/q6afe.c b/dsp/q6afe.c index 5db408c9dc96..a355d23833a7 100644 --- a/dsp/q6afe.c +++ b/dsp/q6afe.c @@ -23,6 +23,7 @@ #include "q6afecal-hwdep.h" #define WAKELOCK_TIMEOUT 5000 +#define AFE_CLK_TOKEN 1024 enum { AFE_COMMON_RX_CAL = 0, AFE_COMMON_TX_CAL, @@ -106,8 +107,11 @@ struct afe_ctl { void *apr; atomic_t state; atomic_t status; + atomic_t clk_state; + atomic_t clk_status; wait_queue_head_t wait[AFE_MAX_PORTS]; wait_queue_head_t wait_wakeup; + wait_queue_head_t clk_wait; struct task_struct *task; wait_queue_head_t lpass_core_hw_wait; uint32_t lpass_hw_core_client_hdl[AFE_LPASS_CORE_HW_VOTE_MAX]; @@ -154,6 +158,7 @@ struct afe_ctl { struct aanc_data aanc_info; struct mutex afe_cmd_lock; struct mutex afe_apr_lock; + struct mutex afe_clk_lock; int set_custom_topology; int dev_acdb_id[AFE_MAX_PORTS]; routing_cb rt_cb; @@ -680,8 +685,8 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) if (data->token < AFE_LPASS_CORE_HW_VOTE_MAX) this_afe.lpass_hw_core_client_hdl[data->token] = payload[0]; - atomic_set(&this_afe.state, 0); - atomic_set(&this_afe.status, 0); + atomic_set(&this_afe.clk_state, 0); + atomic_set(&this_afe.clk_status, 0); wake_up(&this_afe.lpass_core_hw_wait); } else if (data->payload_size) { uint32_t *payload; @@ -699,7 +704,10 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) payload[0], payload[1], data->token); /* payload[1] contains the error status for response */ if (payload[1] != 0) { - atomic_set(&this_afe.status, payload[1]); + if(data->token == AFE_CLK_TOKEN) + atomic_set(&this_afe.clk_status, payload[1]); + else + atomic_set(&this_afe.status, payload[1]); pr_err("%s: cmd = 0x%x returned error = 0x%x\n", __func__, payload[0], payload[1]); } @@ -720,11 +728,16 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) case AFE_SVC_CMD_SET_PARAM: case AFE_SVC_CMD_SET_PARAM_V2: case AFE_PORT_CMD_MOD_EVENT_CFG: - atomic_set(&this_afe.state, 0); - if (afe_token_is_valid(data->token)) - wake_up(&this_afe.wait[data->token]); - else - return -EINVAL; + if(data->token == AFE_CLK_TOKEN) { + atomic_set(&this_afe.clk_state, 0); + wake_up(&this_afe.clk_wait); + } else { + atomic_set(&this_afe.state, 0); + if (afe_token_is_valid(data->token)) + wake_up(&this_afe.wait[data->token]); + else + return -EINVAL; + } break; case AFE_SERVICE_CMD_REGISTER_RT_PORT_DRIVER: break; @@ -770,7 +783,9 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) break; case AFE_CMD_REMOTE_LPASS_CORE_HW_VOTE_REQUEST: case AFE_CMD_REMOTE_LPASS_CORE_HW_DEVOTE_REQUEST: - atomic_set(&this_afe.state, 0); + if (payload[1] != 0) + atomic_set(&this_afe.clk_state, + payload[1]); wake_up(&this_afe.lpass_core_hw_wait); break; case AFE_SVC_CMD_EVENT_CFG: @@ -1090,6 +1105,46 @@ static int afe_apr_send_pkt(void *data, wait_queue_head_t *wait) mutex_unlock(&this_afe.afe_apr_lock); return ret; } +/* + * afe_apr_send_clk_pkt : returns 0 on success, negative otherwise. + */ +static int afe_apr_send_clk_pkt(void *data, wait_queue_head_t *wait) +{ + int ret; + + if (wait) + atomic_set(&this_afe.clk_state, 1); + atomic_set(&this_afe.clk_status, 0); + ret = apr_send_pkt(this_afe.apr, data); + if (ret > 0) { + if (wait) { + ret = wait_event_timeout(*wait, + (atomic_read(&this_afe.clk_state) == 0), + msecs_to_jiffies(2 * TIMEOUT_MS)); + if (!ret) { + pr_err("%s: timeout\n", __func__); + ret = -ETIMEDOUT; + } else if (atomic_read(&this_afe.clk_status) > 0) { + pr_err("%s: DSP returned error[%s]\n", __func__, + adsp_err_get_err_str(atomic_read( + &this_afe.clk_status))); + ret = adsp_err_get_lnx_err_code( + atomic_read(&this_afe.clk_status)); + } else { + ret = 0; + } + } else { + ret = 0; + } + } else if (ret == 0) { + pr_err("%s: packet not transmitted\n", __func__); + /* apr_send_pkt can return 0 when nothing is transmitted */ + ret = -EINVAL; + } + + pr_debug("%s: leave %d\n", __func__, ret); + return ret; +} /* This function shouldn't be called directly. Instead call q6afe_set_params. */ static int q6afe_set_params_v2(u16 port_id, int index, @@ -1486,6 +1541,122 @@ done: return rc; } +/* + * This function shouldn't be called directly. Instead call + * q6afe_clk_set_params. + */ +static int q6afe_clk_set_params_v1(int index, struct mem_mapping_hdr *mem_hdr, + u8 *packed_param_data, u32 packed_data_size) +{ + struct afe_svc_cmd_set_param_v1 *svc_set_param = NULL; + uint32_t size = sizeof(struct afe_svc_cmd_set_param_v1); + int rc = 0; + + if (packed_param_data != NULL) + size += packed_data_size; + svc_set_param = kzalloc(size, GFP_KERNEL); + if (svc_set_param == NULL) + return -ENOMEM; + + svc_set_param->apr_hdr.hdr_field = + APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + svc_set_param->apr_hdr.pkt_size = size; + svc_set_param->apr_hdr.src_port = 0; + svc_set_param->apr_hdr.dest_port = 0; + svc_set_param->apr_hdr.token = AFE_CLK_TOKEN; + svc_set_param->apr_hdr.opcode = AFE_SVC_CMD_SET_PARAM; + svc_set_param->payload_size = packed_data_size; + + if (mem_hdr != NULL) { + /* Out of band case. */ + svc_set_param->mem_hdr = *mem_hdr; + } else if (packed_param_data != NULL) { + /* In band case. */ + memcpy(&svc_set_param->param_data, packed_param_data, + packed_data_size); + } else { + pr_err("%s: Both memory header and param data are NULL\n", + __func__); + rc = -EINVAL; + goto done; + } + + rc = afe_apr_send_clk_pkt(svc_set_param, &this_afe.clk_wait); +done: + kfree(svc_set_param); + return rc; +} + +/* + * This function shouldn't be called directly. Instead call + * q6afe_clk_set_params. + */ +static int q6afe_clk_set_params_v2(int index, struct mem_mapping_hdr *mem_hdr, + u8 *packed_param_data, u32 packed_data_size) +{ + struct afe_svc_cmd_set_param_v2 *svc_set_param = NULL; + uint16_t size = sizeof(struct afe_svc_cmd_set_param_v2); + int rc = 0; + + if (packed_param_data != NULL) + size += packed_data_size; + svc_set_param = kzalloc(size, GFP_KERNEL); + if (svc_set_param == NULL) + return -ENOMEM; + + svc_set_param->apr_hdr.hdr_field = + APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + svc_set_param->apr_hdr.pkt_size = size; + svc_set_param->apr_hdr.src_port = 0; + svc_set_param->apr_hdr.dest_port = 0; + svc_set_param->apr_hdr.token = AFE_CLK_TOKEN; + svc_set_param->apr_hdr.opcode = AFE_SVC_CMD_SET_PARAM_V2; + svc_set_param->payload_size = packed_data_size; + + if (mem_hdr != NULL) { + /* Out of band case. */ + svc_set_param->mem_hdr = *mem_hdr; + } else if (packed_param_data != NULL) { + /* In band case. */ + memcpy(&svc_set_param->param_data, packed_param_data, + packed_data_size); + } else { + pr_err("%s: Both memory header and param data are NULL\n", + __func__); + rc = -EINVAL; + goto done; + } + + rc = afe_apr_send_clk_pkt(svc_set_param, &this_afe.clk_wait); +done: + kfree(svc_set_param); + return rc; +} + +static int q6afe_clk_set_params(int index, struct mem_mapping_hdr *mem_hdr, + u8 *packed_param_data, u32 packed_data_size, + bool is_iid_supported) +{ + int ret; + + ret = afe_q6_interface_prepare(); + if (ret != 0) { + pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret); + return ret; + } + + if (is_iid_supported) + return q6afe_clk_set_params_v2(index, mem_hdr, + packed_param_data, + packed_data_size); + else + return q6afe_clk_set_params_v1(index, mem_hdr, + packed_param_data, + packed_data_size); +} + static int q6afe_svc_set_params(int index, struct mem_mapping_hdr *mem_hdr, u8 *packed_param_data, u32 packed_data_size, bool is_iid_supported) @@ -1530,9 +1701,12 @@ static int q6afe_svc_pack_and_set_param_in_band(int index, __func__, ret); goto done; } - - ret = q6afe_svc_set_params(index, NULL, packed_param_data, - packed_data_size, is_iid_supported); + if (param_hdr.module_id == AFE_MODULE_CLOCK_SET) + ret = q6afe_clk_set_params(index, NULL, packed_param_data, + packed_data_size, is_iid_supported); + else + ret = q6afe_svc_set_params(index, NULL, packed_param_data, + packed_data_size, is_iid_supported); done: kfree(packed_param_data); @@ -7655,13 +7829,7 @@ int afe_set_lpass_clk_cfg(int index, struct afe_clk_set *cfg) memset(¶m_hdr, 0, sizeof(param_hdr)); - ret = afe_q6_interface_prepare(); - if (ret != 0) { - pr_err_ratelimited("%s: Q6 interface prepare failed %d\n", __func__, ret); - return ret; - } - - mutex_lock(&this_afe.afe_cmd_lock); + mutex_lock(&this_afe.afe_clk_lock); param_hdr.module_id = AFE_MODULE_CLOCK_SET; param_hdr.instance_id = INSTANCE_ID_0; param_hdr.param_id = AFE_PARAM_ID_CLOCK_SET; @@ -7681,7 +7849,7 @@ int afe_set_lpass_clk_cfg(int index, struct afe_clk_set *cfg) pr_err_ratelimited("%s: AFE clk cfg failed with ret %d\n", __func__, ret); - mutex_unlock(&this_afe.afe_cmd_lock); + mutex_unlock(&this_afe.afe_clk_lock); return ret; } EXPORT_SYMBOL(afe_set_lpass_clk_cfg); @@ -9028,6 +9196,8 @@ int __init afe_init(void) atomic_set(&this_afe.state, 0); atomic_set(&this_afe.status, 0); + atomic_set(&this_afe.clk_state, 0); + atomic_set(&this_afe.clk_status, 0); atomic_set(&this_afe.mem_map_cal_index, -1); this_afe.apr = NULL; this_afe.dtmf_gen_rx_portid = -1; @@ -9041,6 +9211,7 @@ int __init afe_init(void) this_afe.ex_ftm_cfg.mode = MSM_SPKR_PROT_DISABLED; mutex_init(&this_afe.afe_cmd_lock); mutex_init(&this_afe.afe_apr_lock); + mutex_init(&this_afe.afe_clk_lock); for (i = 0; i < AFE_MAX_PORTS; i++) { this_afe.afe_cal_mode[i] = AFE_CAL_MODE_DEFAULT; this_afe.afe_sample_rates[i] = 0; @@ -9052,6 +9223,7 @@ int __init afe_init(void) } init_waitqueue_head(&this_afe.wait_wakeup); init_waitqueue_head(&this_afe.lpass_core_hw_wait); + init_waitqueue_head(&this_afe.clk_wait); wl.ws = wakeup_source_register(NULL, "spkr-prot"); if (!wl.ws) return -ENOMEM; @@ -9101,6 +9273,7 @@ void afe_exit(void) config_debug_fs_exit(); mutex_destroy(&this_afe.afe_cmd_lock); mutex_destroy(&this_afe.afe_apr_lock); + mutex_destroy(&this_afe.afe_clk_lock); wakeup_source_unregister(wl.ws); } @@ -9164,7 +9337,7 @@ int afe_vote_lpass_core_hw(uint32_t hw_block_id, char *client_name, return ret; } - mutex_lock(&this_afe.afe_cmd_lock); + mutex_lock(&this_afe.afe_clk_lock); memset(cmd_ptr, 0, sizeof(hw_vote_cfg)); @@ -9184,15 +9357,15 @@ int afe_vote_lpass_core_hw(uint32_t hw_block_id, char *client_name, __func__, cmd_ptr->hdr.opcode, cmd_ptr->hw_block_id); *client_handle = 0; - ret = afe_apr_send_pkt((uint32_t *) cmd_ptr, - &this_afe.lpass_core_hw_wait); + + ret = afe_apr_send_clk_pkt((uint32_t *)cmd_ptr, + &this_afe.lpass_core_hw_wait); if (ret == 0) { *client_handle = this_afe.lpass_hw_core_client_hdl[hw_block_id]; pr_debug("%s: lpass_hw_core_client_hdl %d\n", __func__, this_afe.lpass_hw_core_client_hdl[hw_block_id]); } - - mutex_unlock(&this_afe.afe_cmd_lock); + mutex_unlock(&this_afe.afe_clk_lock); return ret; } EXPORT_SYMBOL(afe_vote_lpass_core_hw); @@ -9218,7 +9391,7 @@ int afe_unvote_lpass_core_hw(uint32_t hw_block_id, uint32_t client_handle) return ret; } - mutex_lock(&this_afe.afe_cmd_lock); + mutex_lock(&this_afe.afe_clk_lock); if (!this_afe.lpass_hw_core_client_hdl[hw_block_id]) { pr_debug("%s: SSR in progress, return\n", __func__); @@ -9247,10 +9420,10 @@ int afe_unvote_lpass_core_hw(uint32_t hw_block_id, uint32_t client_handle) goto done; } - ret = afe_apr_send_pkt((uint32_t *) cmd_ptr, - &this_afe.lpass_core_hw_wait); + ret = afe_apr_send_clk_pkt((uint32_t *)cmd_ptr, + &this_afe.lpass_core_hw_wait); done: - mutex_unlock(&this_afe.afe_cmd_lock); + mutex_unlock(&this_afe.afe_clk_lock); return ret; } EXPORT_SYMBOL(afe_unvote_lpass_core_hw);