Merge "ASoC: msm: update QUAT/QUIN TDM slot mappings for A2B"

This commit is contained in:
qctecmdr 2020-03-30 01:20:38 -07:00 • committed by Gerrit - the friendly Code Review server
commit b8e5bd2fc8
8 changed files with 432 additions and 195 deletions

View file

@ -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 <linux/of_platform.h>
@ -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--;

View file

@ -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 */

View file

@ -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,

View file

@ -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;
}

View file

@ -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)

View file

@ -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},
}
};

View file

@ -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},
}
};

View file

@ -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(&param_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);