Merge "ASoC: codecs: Add support for LPASS Audio HW vote"

Цей коміт міститься в:
qctecmdr
2019-06-04 17:59:13 -07:00
зафіксовано Gerrit - the friendly Code Review server
джерело 18830e3e89 ba445bfe2d
коміт a3e3e26667
5 змінених файлів з 172 додано та 7 видалено

Переглянути файл

@@ -28,6 +28,7 @@ enum {
AUDIO_EXT_CLK_LPASS7,
AUDIO_EXT_CLK_LPASS_CORE_HW_VOTE,
AUDIO_EXT_CLK_LPASS8,
AUDIO_EXT_CLK_LPASS_AUDIO_HW_VOTE,
AUDIO_EXT_CLK_LPASS_MAX,
AUDIO_EXT_CLK_EXTERNAL_PLL = AUDIO_EXT_CLK_LPASS_MAX,
AUDIO_EXT_CLK_MAX,
@@ -52,6 +53,7 @@ struct audio_ext_clk_priv {
struct audio_ext_clk audio_clk;
const char *clk_name;
uint32_t lpass_core_hwvote_client_handle;
uint32_t lpass_audio_hwvote_client_handle;
};
static inline struct audio_ext_clk_priv *to_audio_clk(struct clk_hw *hw)
@@ -154,6 +156,17 @@ static int lpass_hw_vote_prepare(struct clk_hw *hw)
}
}
if (clk_priv->clk_src == AUDIO_EXT_CLK_LPASS_AUDIO_HW_VOTE) {
ret = afe_vote_lpass_core_hw(AFE_LPASS_CORE_HW_DCODEC_BLOCK,
"LPASS_HW_DCODEC",
&clk_priv->lpass_audio_hwvote_client_handle);
if (ret < 0) {
pr_err("%s lpass audio hw vote failed %d\n",
__func__, ret);
return ret;
}
}
return 0;
}
@@ -171,6 +184,16 @@ static void lpass_hw_vote_unprepare(struct clk_hw *hw)
__func__, ret);
}
}
if (clk_priv->clk_src == AUDIO_EXT_CLK_LPASS_AUDIO_HW_VOTE) {
ret = afe_unvote_lpass_core_hw(
AFE_LPASS_CORE_HW_DCODEC_BLOCK,
clk_priv->lpass_audio_hwvote_client_handle);
if (ret < 0) {
pr_err("%s lpass audio hw unvote failed %d\n",
__func__, ret);
}
}
}
static const struct clk_ops audio_ext_clk_ops = {
@@ -332,6 +355,15 @@ static struct audio_ext_clk audio_clk_array[] = {
},
},
},
{
.pnctrl_info = {NULL},
.fact = {
.hw.init = &(struct clk_init_data){
.name = "lpass_audio_hw_vote_clk",
.ops = &lpass_hw_vote_ops,
},
},
},
{
.pnctrl_info = {NULL},
.fact = {

Переглянути файл

@@ -909,6 +909,7 @@ static int bolero_probe(struct platform_device *pdev)
u32 num_macros = 0;
int ret;
struct clk *lpass_core_hw_vote = NULL;
struct clk *lpass_audio_hw_vote = NULL;
priv = devm_kzalloc(&pdev->dev, sizeof(struct bolero_priv),
GFP_KERNEL);
@@ -968,6 +969,17 @@ static int bolero_probe(struct platform_device *pdev)
}
priv->lpass_core_hw_vote = lpass_core_hw_vote;
/* 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;
}
priv->lpass_audio_hw_vote = lpass_audio_hw_vote;
return 0;
}
@@ -999,6 +1011,16 @@ int bolero_runtime_resume(struct device *dev)
dev_err(dev, "%s:lpass core hw enable failed\n",
__func__);
if (priv->lpass_audio_hw_vote == NULL) {
dev_dbg(dev, "%s: Invalid lpass audio hw node\n", __func__);
return 0;
}
ret = clk_prepare_enable(priv->lpass_audio_hw_vote);
if (ret < 0)
dev_err(dev, "%s:lpass audio hw enable failed\n",
__func__);
pm_runtime_set_autosuspend_delay(priv->dev, BOLERO_AUTO_SUSPEND_DELAY);
return 0;
}
@@ -1013,6 +1035,12 @@ int bolero_runtime_suspend(struct device *dev)
else
dev_dbg(dev, "%s: Invalid lpass core hw node\n",
__func__);
if (priv->lpass_audio_hw_vote != NULL)
clk_disable_unprepare(priv->lpass_audio_hw_vote);
else
dev_dbg(dev, "%s: Invalid lpass audio hw node\n",
__func__);
return 0;
}
EXPORT_SYMBOL(bolero_runtime_suspend);

Переглянути файл

@@ -58,6 +58,7 @@ struct bolero_priv {
struct work_struct bolero_add_child_devices_work;
u32 version;
struct clk *lpass_core_hw_vote;
struct clk *lpass_audio_hw_vote;
/* Entry for version info */
struct snd_info_entry *entry;

Переглянути файл

@@ -40,6 +40,8 @@
#define VA_MACRO_TX_PATH_OFFSET 0x80
#define VA_MACRO_TX_DMIC_CLK_DIV_MASK 0x0E
#define VA_MACRO_TX_DMIC_CLK_DIV_SHFT 0x01
#define VA_MACRO_SWR_MIC_MUX_SEL_MASK 0xF
#define VA_MACRO_ADC_MUX_CFG_OFFSET 0x2
#define BOLERO_CDC_VA_TX_UNMUTE_DELAY_MS 40
#define MAX_RETRY_ATTEMPTS 500
@@ -78,6 +80,11 @@ enum {
VA_MACRO_CLK_DIV_16,
};
enum {
MSM_DMIC,
SWR_MIC,
};
struct va_mute_work {
struct va_macro_priv *va_priv;
u32 decimator;
@@ -95,6 +102,7 @@ struct va_macro_priv {
struct device *dev;
bool dec_active[VA_MACRO_NUM_DECIMATORS];
bool va_without_decimation;
struct clk *lpass_audio_hw_vote;
struct mutex mclk_lock;
struct snd_soc_component *component;
struct hpf_work va_hpf_work[VA_MACRO_NUM_DECIMATORS];
@@ -232,6 +240,41 @@ static int va_macro_event_handler(struct snd_soc_component *component,
return 0;
}
static int va_macro_swr_pwr_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
int ret = 0;
struct device *va_dev = NULL;
struct va_macro_priv *va_priv = NULL;
if (!va_macro_get_data(component, &va_dev, &va_priv, __func__))
return -EINVAL;
dev_dbg(va_dev, "%s: event = %d\n", __func__, event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
if (va_priv->lpass_audio_hw_vote) {
ret = clk_prepare_enable(va_priv->lpass_audio_hw_vote);
if (ret)
dev_err(va_dev,
"%s: lpass audio hw enable failed\n",
__func__);
}
break;
case SND_SOC_DAPM_POST_PMD:
if (va_priv->lpass_audio_hw_vote)
clk_disable_unprepare(va_priv->lpass_audio_hw_vote);
break;
default:
dev_err(va_priv->dev,
"%s: invalid DAPM event %d\n", __func__, event);
ret = -EINVAL;
}
return ret;
}
static int va_macro_mclk_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -254,6 +297,10 @@ static int va_macro_mclk_event(struct snd_soc_dapm_widget *w,
true);
break;
case SND_SOC_DAPM_POST_PMD:
bolero_clk_rsc_request_clock(va_priv->dev,
va_priv->default_clk_id,
TX_CORE_CLK,
false);
va_macro_mclk_enable(va_priv, 0, true);
break;
default:
@@ -272,6 +319,7 @@ static void va_macro_tx_hpf_corner_freq_callback(struct work_struct *work)
struct snd_soc_component *component;
u16 dec_cfg_reg, hpf_gate_reg;
u8 hpf_cut_off_freq;
u16 adc_mux_reg = 0, adc_n = 0, adc_reg = 0;
hpf_delayed_work = to_delayed_work(work);
hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
@@ -287,6 +335,19 @@ static void va_macro_tx_hpf_corner_freq_callback(struct work_struct *work)
dev_dbg(va_priv->dev, "%s: decimator %u hpf_cut_of_freq 0x%x\n",
__func__, hpf_work->decimator, hpf_cut_off_freq);
adc_mux_reg = BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG1 +
VA_MACRO_ADC_MUX_CFG_OFFSET * hpf_work->decimator;
if (snd_soc_component_read32(component, adc_mux_reg) & SWR_MIC) {
adc_reg = BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG0 +
VA_MACRO_ADC_MUX_CFG_OFFSET * hpf_work->decimator;
adc_n = snd_soc_component_read32(component, adc_reg) &
VA_MACRO_SWR_MIC_MUX_SEL_MASK;
if (adc_n >= BOLERO_ADC_MAX)
goto va_hpf_set;
/* analog mic clear TX hold */
bolero_clear_amic_tx_hold(component->dev, adc_n);
}
va_hpf_set:
snd_soc_component_update_bits(component,
dec_cfg_reg, TX_HPF_CUT_OFF_FREQ_MASK,
hpf_cut_off_freq << 5);
@@ -366,10 +427,23 @@ static int va_macro_put_dec_enum(struct snd_kcontrol *kcontrol,
__func__, e->reg);
return -EINVAL;
}
/* DMIC selected */
if (val != 0)
snd_soc_component_update_bits(component, mic_sel_reg,
1 << 7, 1 << 7);
if (strnstr(widget->name, "SMIC", strlen(widget->name))) {
if (val != 0) {
if (val < 5)
snd_soc_component_update_bits(component,
mic_sel_reg,
1 << 7, 0x0 << 7);
else
snd_soc_component_update_bits(component,
mic_sel_reg,
1 << 7, 0x1 << 7);
}
} else {
/* DMIC selected */
if (val != 0)
snd_soc_component_update_bits(component, mic_sel_reg,
1 << 7, 1 << 7);
}
return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
}
@@ -649,6 +723,12 @@ static int va_macro_enable_tx(struct snd_soc_dapm_widget *w,
TX_CORE_CLK,
false);
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);
break;
default:
dev_err(va_priv->dev,
"%s: invalid DAPM event %d\n", __func__, event);
@@ -1036,15 +1116,18 @@ static const struct snd_kcontrol_new va_aif3_cap_mixer[] = {
static const struct snd_soc_dapm_widget va_macro_dapm_widgets[] = {
SND_SOC_DAPM_AIF_OUT_E("VA_AIF1 CAP", "VA_AIF1 Capture", 0,
SND_SOC_NOPM, VA_MACRO_AIF1_CAP, 0,
va_macro_enable_tx, SND_SOC_DAPM_POST_PMU),
va_macro_enable_tx, SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_AIF_OUT_E("VA_AIF2 CAP", "VA_AIF2 Capture", 0,
SND_SOC_NOPM, VA_MACRO_AIF2_CAP, 0,
va_macro_enable_tx, SND_SOC_DAPM_POST_PMU),
va_macro_enable_tx, SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_AIF_OUT_E("VA_AIF3 CAP", "VA_AIF3 Capture", 0,
SND_SOC_NOPM, VA_MACRO_AIF3_CAP, 0,
va_macro_enable_tx, SND_SOC_DAPM_POST_PMU),
va_macro_enable_tx, SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_MIXER("VA_AIF1_CAP Mixer", SND_SOC_NOPM,
VA_MACRO_AIF1_CAP, 0,
@@ -1165,6 +1248,10 @@ static const struct snd_soc_dapm_widget va_macro_dapm_widgets[] = {
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY_S("VA_SWR_PWR", -1, SND_SOC_NOPM, 0, 0,
va_macro_swr_pwr_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY_S("VA_MCLK", -1, SND_SOC_NOPM, 0, 0,
va_macro_mclk_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
@@ -1403,6 +1490,11 @@ static const struct snd_soc_dapm_route va_audio_map[] = {
{"VA SMIC MUX7", "SWR_DMIC5", "VA SWR_MIC5"},
{"VA SMIC MUX7", "SWR_DMIC6", "VA SWR_MIC6"},
{"VA SMIC MUX7", "SWR_DMIC7", "VA SWR_MIC7"},
{"VA SWR_ADC0", NULL, "VA_SWR_PWR"},
{"VA SWR_ADC1", NULL, "VA_SWR_PWR"},
{"VA SWR_ADC2", NULL, "VA_SWR_PWR"},
{"VA SWR_ADC3", NULL, "VA_SWR_PWR"},
};
static const struct snd_kcontrol_new va_macro_snd_controls[] = {
@@ -1621,6 +1713,7 @@ static int va_macro_probe(struct platform_device *pdev)
int ret = 0;
const char *dmic_sample_rate = "qcom,va-dmic-sample-rate";
u32 default_clk_id = 0;
struct clk *lpass_audio_hw_vote = NULL;
va_priv = devm_kzalloc(&pdev->dev, sizeof(struct va_macro_priv),
GFP_KERNEL);
@@ -1659,6 +1752,16 @@ static int va_macro_probe(struct platform_device *pdev)
}
va_priv->va_io_base = va_io_base;
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;
}
va_priv->lpass_audio_hw_vote = lpass_audio_hw_vote;
if (of_parse_phandle(pdev->dev.of_node, micb_supply_str, 0)) {
va_priv->micb_supply = devm_regulator_get(&pdev->dev,
micb_supply_str1);

Переглянути файл

@@ -483,6 +483,7 @@ int afe_get_doa_tracking_mon(u16 port_id,
#define AFE_LPASS_CORE_HW_BLOCK_ID_NONE 0
#define AFE_LPASS_CORE_HW_BLOCK_ID_AVTIMER 2
#define AFE_LPASS_CORE_HW_MACRO_BLOCK 3
#define AFE_LPASS_CORE_HW_DCODEC_BLOCK 4
/* Handles audio-video timer (avtimer) and BTSC vote requests from clients.
*/