Merge "ASoC: wcd938x: Add support for ADC modes"
diff --git a/asoc/bengal.c b/asoc/bengal.c
index f2a2ece..dcdf1ed 100644
--- a/asoc/bengal.c
+++ b/asoc/bengal.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/clk.h>
@@ -156,6 +156,7 @@
struct device_node *hph_en0_gpio_p; /* used by pinctrl API */
bool is_afe_config_done;
struct device_node *fsa_handle;
+ bool va_disable;
};
struct tdm_port {
@@ -261,7 +262,6 @@
};
static struct mi2s_conf mi2s_intf_conf[MI2S_MAX];
-static bool va_disable;
/* Default configuration of TDM channels */
static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
@@ -3815,13 +3815,17 @@
int ret = 0;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
switch (dai_link->id) {
case MSM_BACKEND_DAI_VA_CDC_DMA_TX_0:
case MSM_BACKEND_DAI_VA_CDC_DMA_TX_1:
case MSM_BACKEND_DAI_VA_CDC_DMA_TX_2:
- if (va_disable)
- break;
+ if (pdata->va_disable) {
+ pr_debug("%s: SVA not supported\n", __func__);
+ return -EINVAL;
+ }
ret = bengal_send_island_va_config(dai_link->id);
if (ret)
pr_err("%s: send island va cfg failed, err: %d\n",
@@ -6616,7 +6620,7 @@
}
memcpy(&adsp_var_idx, buf, len);
kfree(buf);
- va_disable = adsp_var_idx;
+ pdata->va_disable = adsp_var_idx;
ret:
return 0;
diff --git a/asoc/codecs/bolero/bolero-cdc.c b/asoc/codecs/bolero/bolero-cdc.c
index 460a725..af22bb2 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 <linux/of_platform.h>
@@ -991,9 +991,11 @@
*
* @component: pointer to codec component instance.
*
+ * @clk_src: 0 for TX_RCG and 1 for VA_RCG
+ *
* Returns 0 on success or -EINVAL on error.
*/
-int bolero_tx_clk_switch(struct snd_soc_component *component)
+int bolero_tx_clk_switch(struct snd_soc_component *component, int clk_src)
{
struct bolero_priv *priv = NULL;
int ret = 0;
@@ -1011,7 +1013,8 @@
}
if (priv->macro_params[TX_MACRO].clk_switch)
- ret = priv->macro_params[TX_MACRO].clk_switch(component);
+ ret = priv->macro_params[TX_MACRO].clk_switch(component,
+ clk_src);
return ret;
}
diff --git a/asoc/codecs/bolero/bolero-cdc.h b/asoc/codecs/bolero/bolero-cdc.h
index 2294594..3144d88 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
@@ -38,6 +38,11 @@
};
enum {
+ CLK_SRC_TX_RCG = 0,
+ CLK_SRC_VA_RCG,
+};
+
+enum {
BOLERO_MACRO_EVT_RX_MUTE = 1, /* for RX mute/unmute */
BOLERO_MACRO_EVT_IMPED_TRUE, /* for imped true */
BOLERO_MACRO_EVT_IMPED_FALSE, /* for imped false */
@@ -80,8 +85,8 @@
int (*reg_wake_irq)(struct snd_soc_component *component, u32 data);
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 (*clk_switch)(struct snd_soc_component *component, int clk_src);
int (*reg_evt_listener)(struct snd_soc_component *component, bool en);
int (*clk_enable)(struct snd_soc_component *c, bool en);
char __iomem *io_base;
@@ -107,7 +112,7 @@
int bolero_runtime_resume(struct device *dev);
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_tx_clk_switch(struct snd_soc_component *component, int clk_src);
int bolero_register_event_listener(struct snd_soc_component *component,
bool enable);
void bolero_wsa_pa_on(struct device *dev);
@@ -175,7 +180,8 @@
return 0;
}
-static inline int bolero_tx_clk_switch(struct snd_soc_component *component)
+static inline int bolero_tx_clk_switch(struct snd_soc_component *component,
+ int clk_src)
{
return 0;
}
diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c
index b2b4753..a9efa30 100644
--- a/asoc/codecs/bolero/tx-macro.c
+++ b/asoc/codecs/bolero/tx-macro.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 <linux/module.h>
@@ -835,6 +835,8 @@
int unmute_delay = TX_MACRO_DMIC_UNMUTE_DELAY_MS;
struct device *tx_dev = NULL;
struct tx_macro_priv *tx_priv = NULL;
+ u16 adc_mux_reg = 0, adc_reg = 0, adc_n = 0;
+ u16 dmic_clk_reg = 0;
if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__))
return -EINVAL;
@@ -855,6 +857,22 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+ adc_mux_reg = BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG1 +
+ TX_MACRO_ADC_MUX_CFG_OFFSET * decimator;
+ if (snd_soc_component_read32(component, adc_mux_reg) & SWR_MIC) {
+ adc_reg = BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0 +
+ TX_MACRO_ADC_MUX_CFG_OFFSET * decimator;
+ adc_n = snd_soc_component_read32(component, adc_reg) &
+ TX_MACRO_SWR_MIC_MUX_SEL_MASK;
+ if (adc_n >= BOLERO_ADC_MAX) {
+ dmic_clk_reg =
+ BOLERO_CDC_TX_TOP_CSR_SWR_DMIC0_CTL +
+ ((adc_n - 5) / 2) * 4;
+ snd_soc_component_update_bits(component,
+ dmic_clk_reg,
+ 0x0E, tx_priv->dmic_clk_div << 0x1);
+ }
+ }
snd_soc_component_update_bits(component,
dec_cfg_reg, 0x06, tx_priv->dec_mode[decimator] <<
TX_MACRO_ADC_MODE_CFG0_SHIFT);
@@ -2509,7 +2527,7 @@
return tx_priv->dmic_clk_div;
}
-static int tx_macro_clk_switch(struct snd_soc_component *component)
+static int tx_macro_clk_switch(struct snd_soc_component *component, int clk_src)
{
struct device *tx_dev = NULL;
struct tx_macro_priv *tx_priv = NULL;
@@ -2533,7 +2551,7 @@
if (tx_priv->swr_ctrl_data) {
ret = swrm_wcd_notify(
tx_priv->swr_ctrl_data[0].tx_swr_pdev,
- SWR_REQ_CLK_SWITCH, NULL);
+ SWR_REQ_CLK_SWITCH, &clk_src);
}
return ret;
diff --git a/asoc/codecs/bolero/va-macro.c b/asoc/codecs/bolero/va-macro.c
index c595cad..3493a65 100644
--- a/asoc/codecs/bolero/va-macro.c
+++ b/asoc/codecs/bolero/va-macro.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 <linux/module.h>
@@ -45,6 +45,7 @@
#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 0x8
+#define VA_MACRO_ADC_MODE_CFG0_SHIFT 1
#define BOLERO_CDC_VA_TX_DMIC_UNMUTE_DELAY_MS 40
#define BOLERO_CDC_VA_TX_AMIC_UNMUTE_DELAY_MS 100
@@ -170,6 +171,7 @@
int tx_clk_status;
bool lpi_enable;
bool register_event_listener;
+ int dec_mode[VA_MACRO_NUM_DECIMATORS];
};
static bool va_macro_get_data(struct snd_soc_component *component,
@@ -400,7 +402,12 @@
if (!va_macro_get_data(component, &va_dev, &va_priv, __func__))
return -EINVAL;
- dev_dbg(va_dev, "%s: event = %d\n", __func__, event);
+ dev_dbg(va_dev, "%s: event = %d, lpi_enable = %d\n",
+ __func__, event, va_priv->lpi_enable);
+
+ if (!va_priv->lpi_enable)
+ return ret;
+
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
if (va_priv->lpass_audio_hw_vote) {
@@ -411,7 +418,7 @@
__func__);
}
if (!ret)
- if (bolero_tx_clk_switch(component))
+ if (bolero_tx_clk_switch(component, CLK_SRC_VA_RCG))
dev_dbg(va_dev, "%s: clock switch failed\n",
__func__);
if (va_priv->lpi_enable) {
@@ -424,7 +431,7 @@
va_priv->register_event_listener = false;
bolero_register_event_listener(component, false);
}
- if (bolero_tx_clk_switch(component))
+ if (bolero_tx_clk_switch(component, CLK_SRC_TX_RCG))
dev_dbg(va_dev, "%s: clock switch failed\n",__func__);
if (va_priv->lpass_audio_hw_vote)
clk_disable_unprepare(va_priv->lpass_audio_hw_vote);
@@ -484,12 +491,14 @@
ret = bolero_tx_mclk_enable(component, 1);
break;
case SND_SOC_DAPM_POST_PMD:
- if (bolero_tx_clk_switch(component))
- dev_dbg(va_dev, "%s: clock switch failed\n",__func__);
- if (va_priv->lpi_enable)
+ if (va_priv->lpi_enable) {
+ if (bolero_tx_clk_switch(component, CLK_SRC_TX_RCG))
+ dev_dbg(va_dev, "%s: clock switch failed\n",
+ __func__);
va_macro_mclk_enable(va_priv, 0, true);
- else
+ } else {
bolero_tx_mclk_enable(component, 0);
+ }
if (va_priv->tx_clk_status > 0) {
bolero_clk_rsc_request_clock(va_priv->dev,
@@ -1058,6 +1067,9 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_update_bits(component,
+ dec_cfg_reg, 0x06, va_priv->dec_mode[decimator] <<
+ VA_MACRO_ADC_MODE_CFG0_SHIFT);
/* Enable TX PGA Mute */
snd_soc_component_update_bits(component,
tx_vol_ctl_reg, 0x10, 0x10);
@@ -1171,8 +1183,6 @@
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- if (bolero_tx_clk_switch(component))
- dev_dbg(va_dev, "%s: clock switch failed\n",__func__);
if (va_priv->tx_clk_status > 0) {
ret = bolero_clk_rsc_request_clock(va_priv->dev,
va_priv->default_clk_id,
@@ -1265,6 +1275,90 @@
return 0;
}
+static inline int va_macro_path_get(const char *wname,
+ unsigned int *path_num)
+{
+ int ret = 0;
+ char *widget_name = NULL;
+ char *w_name = NULL;
+ char *path_num_char = NULL;
+ char *path_name = NULL;
+
+ widget_name = kstrndup(wname, 10, GFP_KERNEL);
+ if (!widget_name)
+ return -EINVAL;
+
+ w_name = widget_name;
+
+ path_name = strsep(&widget_name, " ");
+ if (!path_name) {
+ pr_err("%s: Invalid widget name = %s\n",
+ __func__, widget_name);
+ ret = -EINVAL;
+ goto err;
+ }
+ path_num_char = strpbrk(path_name, "01234567");
+ if (!path_num_char) {
+ pr_err("%s: va path index not found\n",
+ __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ ret = kstrtouint(path_num_char, 10, path_num);
+ if (ret < 0)
+ pr_err("%s: Invalid tx path = %s\n",
+ __func__, w_name);
+
+err:
+ kfree(w_name);
+ return ret;
+}
+
+static int va_macro_dec_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct va_macro_priv *priv = NULL;
+ struct device *va_dev = NULL;
+ int ret = 0;
+ int path = 0;
+
+ if (!va_macro_get_data(component, &va_dev, &priv, __func__))
+ return -EINVAL;
+
+ ret = va_macro_path_get(kcontrol->id.name, &path);
+ if (ret)
+ return ret;
+
+ ucontrol->value.integer.value[0] = priv->dec_mode[path];
+
+ return 0;
+}
+
+static int va_macro_dec_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct va_macro_priv *priv = NULL;
+ struct device *va_dev = NULL;
+ int value = ucontrol->value.integer.value[0];
+ int ret = 0;
+ int path = 0;
+
+ if (!va_macro_get_data(component, &va_dev, &priv, __func__))
+ return -EINVAL;
+
+ ret = va_macro_path_get(kcontrol->id.name, &path);
+ if (ret)
+ return ret;
+
+ priv->dec_mode[path] = value;
+
+ return 0;
+}
+
static int va_macro_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -2313,8 +2407,24 @@
{"VA SWR_ADC1", NULL, "VA_SWR_PWR"},
{"VA SWR_ADC2", NULL, "VA_SWR_PWR"},
{"VA SWR_ADC3", NULL, "VA_SWR_PWR"},
+ {"VA SWR_MIC0", NULL, "VA_SWR_PWR"},
+ {"VA SWR_MIC1", NULL, "VA_SWR_PWR"},
+ {"VA SWR_MIC2", NULL, "VA_SWR_PWR"},
+ {"VA SWR_MIC3", NULL, "VA_SWR_PWR"},
+ {"VA SWR_MIC4", NULL, "VA_SWR_PWR"},
+ {"VA SWR_MIC5", NULL, "VA_SWR_PWR"},
+ {"VA SWR_MIC6", NULL, "VA_SWR_PWR"},
+ {"VA SWR_MIC7", NULL, "VA_SWR_PWR"},
};
+static const char * const dec_mode_mux_text[] = {
+ "ADC_DEFAULT", "ADC_LOW_PWR", "ADC_HIGH_PERF",
+};
+
+static const struct soc_enum dec_mode_mux_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dec_mode_mux_text),
+ dec_mode_mux_text);
+
static const struct snd_kcontrol_new va_macro_snd_controls[] = {
SOC_SINGLE_SX_TLV("VA_DEC0 Volume",
BOLERO_CDC_VA_TX0_TX_VOL_CTL,
@@ -2342,6 +2452,18 @@
0, -84, 40, digital_gain),
SOC_SINGLE_EXT("LPI Enable", 0, 0, 1, 0,
va_macro_lpi_get, va_macro_lpi_put),
+
+ SOC_ENUM_EXT("VA_DEC0 MODE", dec_mode_mux_enum,
+ va_macro_dec_mode_get, va_macro_dec_mode_put),
+
+ SOC_ENUM_EXT("VA_DEC1 MODE", dec_mode_mux_enum,
+ va_macro_dec_mode_get, va_macro_dec_mode_put),
+
+ SOC_ENUM_EXT("VA_DEC2 MODE", dec_mode_mux_enum,
+ va_macro_dec_mode_get, va_macro_dec_mode_put),
+
+ SOC_ENUM_EXT("VA_DEC3 MODE", dec_mode_mux_enum,
+ va_macro_dec_mode_get, va_macro_dec_mode_put),
};
static const struct snd_kcontrol_new va_macro_snd_controls_common[] = {
diff --git a/asoc/msm-pcm-routing-v2.c b/asoc/msm-pcm-routing-v2.c
index 3d7c568..2c7bcba 100644
--- a/asoc/msm-pcm-routing-v2.c
+++ b/asoc/msm-pcm-routing-v2.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/init.h>
@@ -5471,6 +5471,10 @@
*index = 38;
port_id = AFE_PORT_ID_SENARY_MI2S_RX;
break;
+ case 39:
+ *index = 39;
+ port_id = AFE_PORT_ID_SENARY_MI2S_TX;
+ break;
default:
*index = 0; /* NONE */
pr_err("%s: Invalid value %d\n", __func__, value);
@@ -5528,7 +5532,7 @@
"WSA_CDC_DMA_TX_0", "WSA_CDC_DMA_TX_1", "WSA_CDC_DMA_TX_2",
"SLIM_7_RX", "RX_CDC_DMA_RX_0", "RX_CDC_DMA_RX_1", "RX_CDC_DMA_RX_2",
"RX_CDC_DMA_RX_3", "TX_CDC_DMA_TX_0", "TERT_TDM_RX_2", "SEC_TDM_TX_0",
- "DISPLAY_PORT1", "SEN_MI2S_RX",
+ "DISPLAY_PORT1", "SEN_MI2S_RX", "SENARY_MI2S_TX",
};
static const struct soc_enum msm_route_ec_ref_rx_enum[] = {
@@ -5761,7 +5765,7 @@
"SEC_MI2S_TX", "TERT_MI2S_TX",
"QUAT_MI2S_TX", "QUIN_MI2S_TX",
"SLIM_1_TX", "PRI_TDM_TX",
- "SEC_TDM_TX"};
+ "SEC_TDM_TX", "SENARY_MI2S_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),
diff --git a/config/qcs405auto.conf b/config/qcs405auto.conf
index 61620eb..ebd6f70 100644
--- a/config/qcs405auto.conf
+++ b/config/qcs405auto.conf
@@ -36,3 +36,4 @@
CONFIG_MSM_AVTIMER=m
CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=m
CONFIG_SND_SOC_EP92=m
+CONFIG_DOA_PARAMS_ENABLED=m
diff --git a/config/qcs405autoconf.h b/config/qcs405autoconf.h
index 04f1e10..286dd31 100644
--- a/config/qcs405autoconf.h
+++ b/config/qcs405autoconf.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.
*/
#define CONFIG_PINCTRL_LPI 1
@@ -40,3 +40,4 @@
#define CONFIG_MSM_AVTIMER 1
#define CONFIG_SND_SOC_MSM_HDMI_CODEC_RX 1
#define CONFIG_SND_SOC_EP92 1
+#define CONFIG_DOA_PARAMS_ENABLED 1
diff --git a/include/soc/soundwire.h b/include/soc/soundwire.h
index bb71a35..3e61da1 100644
--- a/include/soc/soundwire.h
+++ b/include/soc/soundwire.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _LINUX_SOUNDWIRE_H
@@ -10,6 +10,13 @@
#include <linux/mod_devicetable.h>
#include <linux/irqdomain.h>
+#define SWR_CLK_RATE_0P6MHZ 600000
+#define SWR_CLK_RATE_1P2MHZ 1200000
+#define SWR_CLK_RATE_2P4MHZ 2400000
+#define SWR_CLK_RATE_4P8MHZ 4800000
+#define SWR_CLK_RATE_9P6MHZ 9600000
+#define SWR_CLK_RATE_11P2896MHZ 1128960
+
extern struct bus_type soundwire_type;
/* Soundwire supports max. of 8 channels per port */
diff --git a/include/soc/swr-wcd.h b/include/soc/swr-wcd.h
index 4ec5094..8ed9f0a 100644
--- a/include/soc/swr-wcd.h
+++ b/include/soc/swr-wcd.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (c) 2015, 2017-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015, 2017-2020 The Linux Foundation. All rights reserved.
*/
#ifndef _LINUX_SWR_WCD_H
@@ -32,6 +32,7 @@
};
#define MCLK_FREQ 9600000
+#define MCLK_FREQ_LP 600000
#define MCLK_FREQ_NATIVE 11289600
#if (IS_ENABLED(CONFIG_SOUNDWIRE_WCD_CTRL) || \
diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c
index 2ab1bee..cd3805f 100644
--- a/soc/swr-mstr-ctrl.c
+++ b/soc/swr-mstr-ctrl.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/irq.h>
@@ -25,6 +25,8 @@
#include "swrm_registers.h"
#include "swr-mstr-ctrl.h"
+#define SWR_NUM_PORTS 4 /* TODO - Get this info from DT */
+
#define SWRM_FRAME_SYNC_SEL 4000 /* 4KHz */
#define SWRM_FRAME_SYNC_SEL_NATIVE 3675 /* 3.675KHz */
#define SWRM_SYSTEM_RESUME_TIMEOUT_MS 700
@@ -94,6 +96,42 @@
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 u8 swrm_get_clk_div(int mclk_freq, int bus_clk_freq)
+{
+ int clk_div = 0;
+ u8 div_val = 0;
+
+ if (!mclk_freq || !bus_clk_freq)
+ return 0;
+
+ clk_div = (mclk_freq / bus_clk_freq);
+
+ switch (clk_div) {
+ case 32:
+ div_val = 5;
+ break;
+ case 16:
+ div_val = 4;
+ break;
+ case 8:
+ div_val = 3;
+ break;
+ case 4:
+ div_val = 2;
+ break;
+ case 2:
+ div_val = 1;
+ break;
+ case 1:
+ default:
+ div_val = 0;
+ break;
+ }
+
+ return div_val;
+}
+
static bool swrm_is_msm_variant(int val)
{
return (val == SWRM_VERSION_1_3);
@@ -955,6 +993,49 @@
return is_removed;
}
+int swrm_get_clk_div_rate(int mclk_freq, int bus_clk_freq)
+{
+ if (!bus_clk_freq)
+ return mclk_freq;
+
+ if (mclk_freq == SWR_CLK_RATE_9P6MHZ) {
+ if (bus_clk_freq <= SWR_CLK_RATE_0P6MHZ)
+ bus_clk_freq = SWR_CLK_RATE_0P6MHZ;
+ else if (bus_clk_freq <= SWR_CLK_RATE_1P2MHZ)
+ bus_clk_freq = SWR_CLK_RATE_1P2MHZ;
+ else if (bus_clk_freq <= SWR_CLK_RATE_2P4MHZ)
+ bus_clk_freq = SWR_CLK_RATE_2P4MHZ;
+ else if(bus_clk_freq <= SWR_CLK_RATE_4P8MHZ)
+ bus_clk_freq = SWR_CLK_RATE_4P8MHZ;
+ else if(bus_clk_freq <= SWR_CLK_RATE_9P6MHZ)
+ bus_clk_freq = SWR_CLK_RATE_9P6MHZ;
+ } else if (mclk_freq == SWR_CLK_RATE_11P2896MHZ)
+ bus_clk_freq = SWR_CLK_RATE_11P2896MHZ;
+
+ return bus_clk_freq;
+}
+
+static int swrm_update_bus_clk(struct swr_mstr_ctrl *swrm)
+{
+ int ret = 0;
+ int agg_clk = 0;
+ int i;
+
+ for (i = 0; i < SWR_MSTR_PORT_LEN; i++)
+ agg_clk += swrm->mport_cfg[i].ch_rate;
+
+ if (agg_clk)
+ swrm->bus_clk = swrm_get_clk_div_rate(swrm->mclk_freq,
+ agg_clk);
+ else
+ swrm->bus_clk = swrm->mclk_freq;
+
+ dev_dbg(swrm->dev, "%s: all_port_clk: %d, bus_clk: %d\n",
+ __func__, agg_clk, swrm->bus_clk);
+
+ return ret;
+}
+
static void swrm_disable_ports(struct swr_master *master,
u8 bank)
{
@@ -1221,13 +1302,15 @@
static int swrm_slvdev_datapath_control(struct swr_master *master, bool enable)
{
u8 bank;
- u32 value, n_row, n_col;
+ u32 value = 0, n_row = 0, n_col = 0;
u32 row = 0, col = 0;
+ int bus_clk_div_factor;
int ret;
u8 ssp_period = 0;
struct swr_mstr_ctrl *swrm = swr_get_ctrl_data(master);
int mask = (SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK |
SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK |
+ SWRM_MCP_FRAME_CTRL_BANK_CLK_DIV_VALUE_BMSK |
SWRM_MCP_FRAME_CTRL_BANK_SSP_PERIOD_BMSK);
u8 inactive_bank;
int frame_sync = SWRM_FRAME_SYNC_SEL;
@@ -1288,13 +1371,17 @@
clear_bit(DISABLE_PENDING, &swrm->port_req_pending);
swrm_disable_ports(master, bank);
}
- dev_dbg(swrm->dev, "%s: enable: %d, cfg_devs: %d\n",
- __func__, enable, swrm->num_cfg_devs);
+ dev_dbg(swrm->dev, "%s: enable: %d, cfg_devs: %d freq %d\n",
+ __func__, enable, swrm->num_cfg_devs, swrm->mclk_freq);
if (enable) {
/* set col = 16 */
n_col = SWR_MAX_COL;
col = SWRM_COL_16;
+ if (swrm->bus_clk == MCLK_FREQ_LP) {
+ n_col = SWR_MIN_COL;
+ col = SWRM_COL_02;
+ }
} else {
/*
* Do not change to col = 2 if there are still active ports
@@ -1309,25 +1396,26 @@
}
/* Use default 50 * x, frame shape. Change based on mclk */
if (swrm->mclk_freq == MCLK_FREQ_NATIVE) {
- dev_dbg(swrm->dev, "setting 64 x %d frameshape\n",
- n_col ? 16 : 2);
+ dev_dbg(swrm->dev, "setting 64 x %d frameshape\n", col);
n_row = SWR_ROW_64;
row = SWRM_ROW_64;
frame_sync = SWRM_FRAME_SYNC_SEL_NATIVE;
} else {
- dev_dbg(swrm->dev, "setting 50 x %d frameshape\n",
- n_col ? 16 : 2);
+ dev_dbg(swrm->dev, "setting 50 x %d frameshape\n", col);
n_row = SWR_ROW_50;
row = SWRM_ROW_50;
frame_sync = SWRM_FRAME_SYNC_SEL;
}
ssp_period = swrm_get_ssp_period(swrm, row, col, frame_sync);
- dev_dbg(swrm->dev, "%s: ssp_period: %d\n", __func__, ssp_period);
-
+ bus_clk_div_factor = swrm_get_clk_div(swrm->mclk_freq, swrm->bus_clk);
+ dev_dbg(swrm->dev, "%s: ssp_period: %d, bus_clk_div:%d \n", __func__,
+ ssp_period, bus_clk_div_factor);
value = swr_master_read(swrm, SWRM_MCP_FRAME_CTRL_BANK_ADDR(bank));
value &= (~mask);
value |= ((n_row << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT) |
(n_col << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT) |
+ (bus_clk_div_factor <<
+ SWRM_MCP_FRAME_CTRL_BANK_CLK_DIV_VALUE_SHFT) |
((ssp_period - 1) << SWRM_MCP_FRAME_CTRL_BANK_SSP_PERIOD_SHFT));
swr_master_write(swrm, SWRM_MCP_FRAME_CTRL_BANK_ADDR(bank), value);
@@ -1431,6 +1519,11 @@
mport->port_en = true;
mport->req_ch |= mstr_ch_msk;
master->port_en_mask |= (1 << mstr_port_id);
+ if (swrm->clk_stop_mode0_supp &&
+ (mport->ch_rate < portinfo->ch_rate[i])) {
+ mport->ch_rate = portinfo->ch_rate[i];
+ swrm_update_bus_clk(swrm);
+ }
}
master->num_port += portinfo->num_port;
set_bit(ENABLE_PENDING, &swrm->port_req_pending);
@@ -1493,6 +1586,10 @@
}
port_req->req_ch &= ~portinfo->ch_en[i];
mport->req_ch &= ~mstr_ch_mask;
+ if (swrm->clk_stop_mode0_supp && !mport->req_ch) {
+ mport->ch_rate = 0;
+ swrm_update_bus_clk(swrm);
+ }
}
master->num_port -= portinfo->num_port;
set_bit(DISABLE_PENDING, &swrm->port_req_pending);
@@ -2402,9 +2499,10 @@
dev_dbg(&pdev->dev, "%s: Looking up %s property failed\n",
__func__, "qcom,swr-num-dev");
} else {
- if (swrm->num_dev > SWR_MAX_SLAVE_DEVICES) {
+ if (swrm->num_dev > SWRM_NUM_AUTO_ENUM_SLAVES) {
dev_err(&pdev->dev, "%s: num_dev %d > max limit %d\n",
- __func__, swrm->num_dev, SWR_MAX_SLAVE_DEVICES);
+ __func__, swrm->num_dev,
+ SWRM_NUM_AUTO_ENUM_SLAVES);
ret = -EINVAL;
goto err_pdata_fail;
}
diff --git a/soc/swr-mstr-ctrl.h b/soc/swr-mstr-ctrl.h
index c404fc6..ce0b64d 100644
--- a/soc/swr-mstr-ctrl.h
+++ b/soc/swr-mstr-ctrl.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _SWR_WCD_CTRL_H
@@ -26,6 +26,7 @@
#define SWR_ROW_48 0
#define SWR_ROW_50 1
#define SWR_ROW_64 3
+#define SWR_COL_04 1 /* Cols = 4 */
#define SWR_MAX_COL 7 /* Cols = 16 */
#define SWR_MIN_COL 0 /* Cols = 2 */
@@ -42,7 +43,7 @@
#define SWR_MAX_CH_PER_PORT 8
-#define SWR_MAX_SLAVE_DEVICES 11
+#define SWRM_NUM_AUTO_ENUM_SLAVES 6
enum {
SWR_MSTR_PAUSE,
@@ -81,7 +82,6 @@
bool port_en;
u8 ch_en;
u8 req_ch;
- u8 ch_rate;
u8 offset1;
u8 offset2;
u8 sinterval;
@@ -91,6 +91,7 @@
u8 blk_pack_mode;
u8 word_length;
u8 lane_ctrl;
+ u32 ch_rate;
};
struct swrm_port_type {