Merge "asoc: codecs: bolero: Update mixing path and channel mask for RX path"
diff --git a/asoc/codecs/bolero/bolero-cdc.c b/asoc/codecs/bolero/bolero-cdc.c
index 6f81dab..76c9d40 100644
--- a/asoc/codecs/bolero/bolero-cdc.c
+++ b/asoc/codecs/bolero/bolero-cdc.c
@@ -504,6 +504,8 @@
if (macro_id == TX_MACRO) {
priv->macro_params[macro_id].reg_wake_irq = ops->reg_wake_irq;
priv->macro_params[macro_id].clk_switch = ops->clk_switch;
+ priv->macro_params[macro_id].reg_evt_listener =
+ ops->reg_evt_listener;
}
priv->num_dais += ops->num_dais;
@@ -567,6 +569,7 @@
if (macro_id == TX_MACRO) {
priv->macro_params[macro_id].reg_wake_irq = NULL;
priv->macro_params[macro_id].clk_switch = NULL;
+ priv->macro_params[macro_id].reg_evt_listener = NULL;
}
priv->num_dais -= priv->macro_params[macro_id].num_dais;
@@ -578,6 +581,29 @@
}
EXPORT_SYMBOL(bolero_unregister_macro);
+void bolero_wsa_pa_on(struct device *dev)
+{
+ struct bolero_priv *priv;
+
+ if (!dev) {
+ pr_err("%s: dev is null\n", __func__);
+ return;
+ }
+ if (!bolero_is_valid_child_dev(dev)) {
+ dev_err(dev, "%s: not a valid child dev\n",
+ __func__);
+ return;
+ }
+ priv = dev_get_drvdata(dev->parent);
+ if (!priv) {
+ dev_err(dev, "%s: priv is null\n", __func__);
+ return;
+ }
+
+ bolero_cdc_notifier_call(priv, BOLERO_WCD_EVT_PA_ON_POST_FSCLK);
+}
+EXPORT_SYMBOL(bolero_wsa_pa_on);
+
static ssize_t bolero_version_read(struct snd_info_entry *entry,
void *file_private_data,
struct file *file,
@@ -803,6 +829,41 @@
}
EXPORT_SYMBOL(bolero_tx_clk_switch);
+/**
+ * bolero_register_event_listener - Register/Deregister to event listener
+ *
+ * @component: pointer to codec component instance.
+ * @enable: when set to 1 registers to event listener otherwise, derigisters
+ * from the event listener
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int bolero_register_event_listener(struct snd_soc_component *component,
+ bool enable)
+{
+ struct bolero_priv *priv = NULL;
+ int ret = 0;
+
+ if (!component)
+ return -EINVAL;
+
+ priv = snd_soc_component_get_drvdata(component);
+ if (!priv)
+ return -EINVAL;
+
+ if (!bolero_is_valid_codec_dev(priv->dev)) {
+ dev_err(component->dev, "%s: invalid codec\n", __func__);
+ return -EINVAL;
+ }
+
+ if (priv->macro_params[TX_MACRO].reg_evt_listener)
+ ret = priv->macro_params[TX_MACRO].reg_evt_listener(component,
+ enable);
+
+ return ret;
+}
+EXPORT_SYMBOL(bolero_register_event_listener);
+
static int bolero_soc_codec_probe(struct snd_soc_component *component)
{
struct bolero_priv *priv = dev_get_drvdata(component->dev);
diff --git a/asoc/codecs/bolero/bolero-cdc.h b/asoc/codecs/bolero/bolero-cdc.h
index 7e8ec83..957389c 100644
--- a/asoc/codecs/bolero/bolero-cdc.h
+++ b/asoc/codecs/bolero/bolero-cdc.h
@@ -56,6 +56,7 @@
int (*set_port_map)(struct snd_soc_component *component, u32 uc,
u32 size, void *data);
int (*clk_switch)(struct snd_soc_component *component);
+ int (*reg_evt_listener)(struct snd_soc_component *component, bool en);
char __iomem *io_base;
u16 clk_id_req;
u16 default_clk_id;
@@ -80,6 +81,9 @@
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_register_event_listener(struct snd_soc_component *component,
+ bool enable);
+void bolero_wsa_pa_on(struct device *dev);
#else
static inline int bolero_register_res_clk(struct device *dev, rsc_clk_cb_t cb)
{
@@ -144,5 +148,15 @@
return 0;
}
+static inline int bolero_register_event_listener(
+ struct snd_soc_component *component,
+ bool enable)
+{
+ return 0;
+}
+
+static void bolero_wsa_pa_on(struct device *dev)
+{
+}
#endif /* CONFIG_SND_SOC_BOLERO */
#endif /* BOLERO_CDC_H */
diff --git a/asoc/codecs/bolero/internal.h b/asoc/codecs/bolero/internal.h
index d353a2d..d3f6894 100644
--- a/asoc/codecs/bolero/internal.h
+++ b/asoc/codecs/bolero/internal.h
@@ -15,6 +15,7 @@
BOLERO_WCD_EVT_PA_OFF_PRE_SSR,
BOLERO_WCD_EVT_SSR_DOWN,
BOLERO_WCD_EVT_SSR_UP,
+ BOLERO_WCD_EVT_PA_ON_POST_FSCLK,
};
enum {
diff --git a/asoc/codecs/bolero/rx-macro.c b/asoc/codecs/bolero/rx-macro.c
index d3370f0..9af1522 100644
--- a/asoc/codecs/bolero/rx-macro.c
+++ b/asoc/codecs/bolero/rx-macro.c
@@ -77,6 +77,8 @@
#define RX_MACRO_EC_MIX_TX1_MASK 0x0f
#define RX_MACRO_EC_MIX_TX2_MASK 0x0f
+#define COMP_MAX_COEFF 25
+
struct wcd_imped_val {
u32 imped_val;
u8 index;
@@ -95,6 +97,75 @@
{13, 9},
};
+struct comp_coeff_val {
+ u8 lsb;
+ u8 msb;
+};
+
+enum {
+ HPH_ULP,
+ HPH_LOHIFI,
+ HPH_MODE_MAX,
+};
+
+static const struct comp_coeff_val
+ comp_coeff_table [HPH_MODE_MAX][COMP_MAX_COEFF] = {
+ {
+ {0x40, 0x00},
+ {0x4C, 0x00},
+ {0x5A, 0x00},
+ {0x6B, 0x00},
+ {0x7F, 0x00},
+ {0x97, 0x00},
+ {0xB3, 0x00},
+ {0xD5, 0x00},
+ {0xFD, 0x00},
+ {0x2D, 0x01},
+ {0x66, 0x01},
+ {0xA7, 0x01},
+ {0xF8, 0x01},
+ {0x57, 0x02},
+ {0xC7, 0x02},
+ {0x4B, 0x03},
+ {0xE9, 0x03},
+ {0xA3, 0x04},
+ {0x7D, 0x05},
+ {0x90, 0x06},
+ {0xD1, 0x07},
+ {0x49, 0x09},
+ {0x00, 0x0B},
+ {0x01, 0x0D},
+ {0x59, 0x0F},
+ },
+ {
+ {0x40, 0x00},
+ {0x4C, 0x00},
+ {0x5A, 0x00},
+ {0x6B, 0x00},
+ {0x80, 0x00},
+ {0x98, 0x00},
+ {0xB4, 0x00},
+ {0xD5, 0x00},
+ {0xFE, 0x00},
+ {0x2E, 0x01},
+ {0x66, 0x01},
+ {0xA9, 0x01},
+ {0xF8, 0x01},
+ {0x56, 0x02},
+ {0xC4, 0x02},
+ {0x4F, 0x03},
+ {0xF0, 0x03},
+ {0xAE, 0x04},
+ {0x8B, 0x05},
+ {0x8E, 0x06},
+ {0xBC, 0x07},
+ {0x56, 0x09},
+ {0x0F, 0x0B},
+ {0x13, 0x0D},
+ {0x6F, 0x0F},
+ },
+};
+
struct rx_macro_reg_mask_val {
u16 reg;
u8 mask;
@@ -301,6 +372,7 @@
int (*write)(void *handle, int reg, int val);
int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len);
int (*clk)(void *handle, bool enable);
+ int (*core_vote)(void *handle, bool enable);
int (*handle_irq)(void *handle,
irqreturn_t (*swrm_irq_handler)(int irq,
void *data),
@@ -1638,6 +1710,47 @@
return 0;
}
+static int rx_macro_load_compander_coeff(struct snd_soc_component *component,
+ struct rx_macro_priv *rx_priv,
+ int interp_n, int event)
+{
+ int comp = 0;
+ u16 comp_coeff_lsb_reg = 0, comp_coeff_msb_reg = 0;
+ int i = 0;
+ int hph_pwr_mode = HPH_LOHIFI;
+
+ if (!rx_priv->comp_enabled[comp])
+ return 0;
+
+ if (interp_n == INTERP_HPHL) {
+ comp_coeff_lsb_reg = BOLERO_CDC_RX_TOP_HPHL_COMP_WR_LSB;
+ comp_coeff_msb_reg = BOLERO_CDC_RX_TOP_HPHL_COMP_WR_MSB;
+ } else if (interp_n == INTERP_HPHR) {
+ comp_coeff_lsb_reg = BOLERO_CDC_RX_TOP_HPHR_COMP_WR_LSB;
+ comp_coeff_msb_reg = BOLERO_CDC_RX_TOP_HPHR_COMP_WR_MSB;
+ } else {
+ /* compander coefficients are loaded only for hph path */
+ return 0;
+ }
+
+ comp = interp_n;
+ hph_pwr_mode = rx_priv->hph_pwr_mode;
+ dev_dbg(component->dev, "%s: event %d compander %d, enabled %d\n",
+ __func__, event, comp + 1, rx_priv->comp_enabled[comp]);
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ /* Load Compander Coeff */
+ for (i = 0; i < COMP_MAX_COEFF; i++) {
+ snd_soc_component_write(component, comp_coeff_lsb_reg,
+ comp_coeff_table[hph_pwr_mode][i].lsb);
+ snd_soc_component_write(component, comp_coeff_msb_reg,
+ comp_coeff_table[hph_pwr_mode][i].msb);
+ }
+ }
+
+ return 0;
+}
+
static void rx_macro_enable_softclip_clk(struct snd_soc_component *component,
struct rx_macro_priv *rx_priv,
bool enable)
@@ -2354,6 +2467,8 @@
0x01, 0x01);
snd_soc_component_update_bits(component, rx_cfg2_reg,
0x03, 0x03);
+ rx_macro_load_compander_coeff(component, rx_priv,
+ interp_idx, event);
rx_macro_idle_detect_control(component, rx_priv,
interp_idx, event);
if (rx_priv->hph_hd2_mode)
@@ -3370,6 +3485,23 @@
{"RX INT2 MIX2 INP", "SRC1", "SRC1"},
};
+static int rx_macro_core_vote(void *handle, bool enable)
+{
+ struct rx_macro_priv *rx_priv = (struct rx_macro_priv *) handle;
+
+ if (rx_priv == NULL) {
+ pr_err("%s: rx priv data is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (enable) {
+ pm_runtime_get_sync(rx_priv->dev);
+ pm_runtime_put_autosuspend(rx_priv->dev);
+ pm_runtime_mark_last_busy(rx_priv->dev);
+ }
+
+ return 0;
+}
+
static int rx_swrm_clock(void *handle, bool enable)
{
struct rx_macro_priv *rx_priv = (struct rx_macro_priv *) handle;
@@ -3388,8 +3520,16 @@
if (enable) {
pm_runtime_get_sync(rx_priv->dev);
if (rx_priv->swr_clk_users == 0) {
- msm_cdc_pinctrl_select_active_state(
+ ret = msm_cdc_pinctrl_select_active_state(
rx_priv->rx_swr_gpio_p);
+ if (ret < 0) {
+ dev_err(rx_priv->dev,
+ "%s: rx swr pinctrl enable failed\n",
+ __func__);
+ pm_runtime_mark_last_busy(rx_priv->dev);
+ pm_runtime_put_autosuspend(rx_priv->dev);
+ goto exit;
+ }
ret = rx_macro_mclk_enable(rx_priv, 1, true);
if (ret < 0) {
msm_cdc_pinctrl_select_sleep_state(
@@ -3397,6 +3537,8 @@
dev_err(rx_priv->dev,
"%s: rx request clock enable failed\n",
__func__);
+ pm_runtime_mark_last_busy(rx_priv->dev);
+ pm_runtime_put_autosuspend(rx_priv->dev);
goto exit;
}
if (rx_priv->reset_swr)
@@ -3429,8 +3571,14 @@
BOLERO_CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
0x01, 0x00);
rx_macro_mclk_enable(rx_priv, 0, true);
- msm_cdc_pinctrl_select_sleep_state(
+ ret = msm_cdc_pinctrl_select_sleep_state(
rx_priv->rx_swr_gpio_p);
+ if (ret < 0) {
+ dev_err(rx_priv->dev,
+ "%s: rx swr pinctrl disable failed\n",
+ __func__);
+ goto exit;
+ }
}
}
dev_dbg(rx_priv->dev, "%s: swrm clock users %d\n",
@@ -3440,6 +3588,15 @@
return ret;
}
+static const struct rx_macro_reg_mask_val rx_macro_reg_init[] = {
+ {BOLERO_CDC_RX_RX0_RX_PATH_SEC7, 0x07, 0x02},
+ {BOLERO_CDC_RX_RX1_RX_PATH_SEC7, 0x07, 0x02},
+ {BOLERO_CDC_RX_RX2_RX_PATH_SEC7, 0x07, 0x02},
+ {BOLERO_CDC_RX_RX0_RX_PATH_CFG3, 0x03, 0x02},
+ {BOLERO_CDC_RX_RX1_RX_PATH_CFG3, 0x03, 0x02},
+ {BOLERO_CDC_RX_RX2_RX_PATH_CFG3, 0x03, 0x02},
+};
+
static void rx_macro_init_bcl_pmic_reg(struct snd_soc_component *component)
{
struct device *rx_dev = NULL;
@@ -3494,6 +3651,7 @@
int ret = 0;
struct device *rx_dev = NULL;
struct rx_macro_priv *rx_priv = NULL;
+ int i;
rx_dev = bolero_get_device_ptr(component->dev, RX_MACRO);
if (!rx_dev) {
@@ -3545,18 +3703,11 @@
snd_soc_dapm_ignore_suspend(dapm, "RX_TX DEC3_INP");
snd_soc_dapm_sync(dapm);
- snd_soc_component_update_bits(component, BOLERO_CDC_RX_RX0_RX_PATH_SEC7,
- 0x07, 0x02);
- snd_soc_component_update_bits(component, BOLERO_CDC_RX_RX1_RX_PATH_SEC7,
- 0x07, 0x02);
- snd_soc_component_update_bits(component, BOLERO_CDC_RX_RX2_RX_PATH_SEC7,
- 0x07, 0x02);
- snd_soc_component_update_bits(component, BOLERO_CDC_RX_RX0_RX_PATH_CFG3,
- 0x03, 0x02);
- snd_soc_component_update_bits(component, BOLERO_CDC_RX_RX1_RX_PATH_CFG3,
- 0x03, 0x02);
- snd_soc_component_update_bits(component, BOLERO_CDC_RX_RX2_RX_PATH_CFG3,
- 0x03, 0x02);
+ for (i = 0; i < ARRAY_SIZE(rx_macro_reg_init); i++)
+ snd_soc_component_update_bits(component,
+ rx_macro_reg_init[i].reg,
+ rx_macro_reg_init[i].mask,
+ rx_macro_reg_init[i].val);
rx_priv->component = component;
rx_macro_init_bcl_pmic_reg(component);
@@ -3781,6 +3932,7 @@
rx_priv->swr_plat_data.write = NULL;
rx_priv->swr_plat_data.bulk_write = NULL;
rx_priv->swr_plat_data.clk = rx_swrm_clock;
+ rx_priv->swr_plat_data.core_vote = rx_macro_core_vote;
rx_priv->swr_plat_data.handle_irq = NULL;
ret = of_property_read_u8_array(pdev->dev.of_node,
diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c
index fda01e1..45e0a80 100644
--- a/asoc/codecs/bolero/tx-macro.c
+++ b/asoc/codecs/bolero/tx-macro.c
@@ -41,6 +41,7 @@
#define TX_MACRO_TX_PATH_OFFSET 0x80
#define TX_MACRO_SWR_MIC_MUX_SEL_MASK 0xF
#define TX_MACRO_ADC_MUX_CFG_OFFSET 0x2
+#define TX_MACRO_ADC_MODE_CFG0_SHIFT 1
#define TX_MACRO_TX_UNMUTE_DELAY_MS 40
@@ -71,6 +72,7 @@
int (*write)(void *handle, int reg, int val);
int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len);
int (*clk)(void *handle, bool enable);
+ int (*core_vote)(void *handle, bool enable);
int (*handle_irq)(void *handle,
irqreturn_t (*swrm_irq_handler)(int irq,
void *data),
@@ -118,6 +120,12 @@
VA_MCLK,
};
+struct tx_macro_reg_mask_val {
+ u16 reg;
+ u8 mask;
+ u8 val;
+};
+
struct tx_mute_work {
struct tx_macro_priv *tx_priv;
u32 decimator;
@@ -163,6 +171,7 @@
int va_clk_status;
int tx_clk_status;
bool bcs_enable;
+ int dec_mode[NUM_DECIMATORS];
};
static bool tx_macro_get_data(struct snd_soc_component *component,
@@ -609,6 +618,91 @@
return 0;
}
+
+static inline int tx_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: tx 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 tx_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 tx_macro_priv *tx_priv = NULL;
+ struct device *tx_dev = NULL;
+ int ret = 0;
+ int path = 0;
+
+ if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__))
+ return -EINVAL;
+
+ ret = tx_macro_path_get(kcontrol->id.name, &path);
+ if (ret)
+ return ret;
+
+ ucontrol->value.integer.value[0] = tx_priv->dec_mode[path];
+
+ return 0;
+}
+
+static int tx_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 tx_macro_priv *tx_priv = NULL;
+ struct device *tx_dev = NULL;
+ int value = ucontrol->value.integer.value[0];
+ int ret = 0;
+ int path = 0;
+
+ if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__))
+ return -EINVAL;
+
+ ret = tx_macro_path_get(kcontrol->id.name, &path);
+ if (ret)
+ return ret;
+
+ tx_priv->dec_mode[path] = value;
+
+ return 0;
+}
+
static int tx_macro_get_bcs(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -759,6 +853,9 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_update_bits(component,
+ dec_cfg_reg, 0x06, tx_priv->dec_mode[decimator] <<
+ TX_MACRO_ADC_MODE_CFG0_SHIFT);
/* Enable TX PGA Mute */
snd_soc_component_update_bits(component,
tx_vol_ctl_reg, 0x10, 0x10);
@@ -840,6 +937,8 @@
case SND_SOC_DAPM_POST_PMD:
snd_soc_component_update_bits(component, tx_vol_ctl_reg,
0x20, 0x00);
+ snd_soc_component_update_bits(component,
+ dec_cfg_reg, 0x06, 0x00);
snd_soc_component_update_bits(component, tx_vol_ctl_reg,
0x10, 0x00);
if (tx_priv->bcs_enable) {
@@ -1111,6 +1210,14 @@
0, smic_mux_text, snd_soc_dapm_get_enum_double,
tx_macro_put_dec_enum);
+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 tx_aif1_cap_mixer[] = {
SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, TX_MACRO_DEC0, 1, 0,
tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
@@ -1586,10 +1693,75 @@
BOLERO_CDC_TX7_TX_VOL_CTL,
0, -84, 40, digital_gain),
+ SOC_ENUM_EXT("DEC0 MODE", dec_mode_mux_enum,
+ tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+ SOC_ENUM_EXT("DEC1 MODE", dec_mode_mux_enum,
+ tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+ SOC_ENUM_EXT("DEC2 MODE", dec_mode_mux_enum,
+ tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+ SOC_ENUM_EXT("DEC3 MODE", dec_mode_mux_enum,
+ tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+ SOC_ENUM_EXT("DEC4 MODE", dec_mode_mux_enum,
+ tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+ SOC_ENUM_EXT("DEC5 MODE", dec_mode_mux_enum,
+ tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+ SOC_ENUM_EXT("DEC6 MODE", dec_mode_mux_enum,
+ tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+ SOC_ENUM_EXT("DEC7 MODE", dec_mode_mux_enum,
+ tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
SOC_SINGLE_EXT("DEC0_BCS Switch", SND_SOC_NOPM, 0, 1, 0,
tx_macro_get_bcs, tx_macro_set_bcs),
};
+static int tx_macro_register_event_listener(struct snd_soc_component *component,
+ bool enable)
+{
+ struct device *tx_dev = NULL;
+ struct tx_macro_priv *tx_priv = NULL;
+ int ret = 0;
+
+ if (!component)
+ return -EINVAL;
+
+ tx_dev = bolero_get_device_ptr(component->dev, TX_MACRO);
+ if (!tx_dev) {
+ dev_err(component->dev,
+ "%s: null device for macro!\n", __func__);
+ return -EINVAL;
+ }
+ tx_priv = dev_get_drvdata(tx_dev);
+ if (!tx_priv) {
+ dev_err(component->dev,
+ "%s: priv is null for macro!\n", __func__);
+ return -EINVAL;
+ }
+ if (tx_priv->swr_ctrl_data) {
+ if (enable) {
+ ret = swrm_wcd_notify(
+ tx_priv->swr_ctrl_data[0].tx_swr_pdev,
+ SWR_REGISTER_WAKEUP, NULL);
+ msm_cdc_pinctrl_set_wakeup_capable(
+ tx_priv->tx_swr_gpio_p, false);
+ } else {
+ msm_cdc_pinctrl_set_wakeup_capable(
+ tx_priv->tx_swr_gpio_p, true);
+ ret = swrm_wcd_notify(
+ tx_priv->swr_ctrl_data[0].tx_swr_pdev,
+ SWR_DEREGISTER_WAKEUP, NULL);
+ }
+ }
+
+ return ret;
+}
+
static int tx_macro_tx_va_mclk_enable(struct tx_macro_priv *tx_priv,
struct regmap *regmap, int clk_type,
bool enable)
@@ -1602,9 +1774,16 @@
(enable ? "enable" : "disable"), tx_priv->tx_mclk_users);
if (enable) {
- if (tx_priv->swr_clk_users == 0)
- msm_cdc_pinctrl_select_active_state(
+ if (tx_priv->swr_clk_users == 0) {
+ ret = msm_cdc_pinctrl_select_active_state(
tx_priv->tx_swr_gpio_p);
+ if (ret < 0) {
+ dev_err_ratelimited(tx_priv->dev,
+ "%s: tx swr pinctrl enable failed\n",
+ __func__);
+ goto exit;
+ }
+ }
clk_tx_ret = bolero_clk_rsc_request_clock(tx_priv->dev,
TX_CORE_CLK,
@@ -1717,9 +1896,16 @@
TX_CORE_CLK,
TX_CORE_CLK,
false);
- if (tx_priv->swr_clk_users == 0)
- msm_cdc_pinctrl_select_sleep_state(
+ if (tx_priv->swr_clk_users == 0) {
+ ret = msm_cdc_pinctrl_select_sleep_state(
tx_priv->tx_swr_gpio_p);
+ if (ret < 0) {
+ dev_err_ratelimited(tx_priv->dev,
+ "%s: tx swr pinctrl disable failed\n",
+ __func__);
+ goto exit;
+ }
+ }
}
return 0;
@@ -1729,6 +1915,7 @@
TX_CORE_CLK,
TX_CORE_CLK,
false);
+exit:
return ret;
}
@@ -1762,6 +1949,24 @@
return ret;
}
+static int tx_macro_core_vote(void *handle, bool enable)
+{
+ struct tx_macro_priv *tx_priv = (struct tx_macro_priv *) handle;
+ int ret = 0;
+
+ if (tx_priv == NULL) {
+ pr_err("%s: tx priv data is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (enable) {
+ pm_runtime_get_sync(tx_priv->dev);
+ pm_runtime_put_autosuspend(tx_priv->dev);
+ pm_runtime_mark_last_busy(tx_priv->dev);
+ }
+
+ return ret;
+}
+
static int tx_macro_swrm_clock(void *handle, bool enable)
{
struct tx_macro_priv *tx_priv = (struct tx_macro_priv *) handle;
@@ -1784,14 +1989,20 @@
if (tx_priv->va_swr_clk_cnt && !tx_priv->tx_swr_clk_cnt) {
ret = tx_macro_tx_va_mclk_enable(tx_priv, regmap,
VA_MCLK, enable);
- if (ret)
+ if (ret) {
+ pm_runtime_mark_last_busy(tx_priv->dev);
+ pm_runtime_put_autosuspend(tx_priv->dev);
goto done;
+ }
tx_priv->va_clk_status++;
} else {
ret = tx_macro_tx_va_mclk_enable(tx_priv, regmap,
TX_MCLK, enable);
- if (ret)
+ if (ret) {
+ pm_runtime_mark_last_busy(tx_priv->dev);
+ pm_runtime_put_autosuspend(tx_priv->dev);
goto done;
+ }
tx_priv->tx_clk_status++;
}
pm_runtime_mark_last_busy(tx_priv->dev);
@@ -1889,6 +2100,10 @@
return dmic_sample_rate;
}
+static const struct tx_macro_reg_mask_val tx_macro_reg_init[] = {
+ {BOLERO_CDC_TX0_TX_PATH_SEC7, 0x3F, 0x02},
+};
+
static int tx_macro_init(struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm =
@@ -1968,8 +2183,12 @@
}
tx_priv->component = component;
- snd_soc_component_update_bits(component,
- BOLERO_CDC_TX0_TX_PATH_SEC7, 0x3F, 0x0E);
+ for (i = 0; i < ARRAY_SIZE(tx_macro_reg_init); i++)
+ snd_soc_component_update_bits(component,
+ tx_macro_reg_init[i].reg,
+ tx_macro_reg_init[i].mask,
+ tx_macro_reg_init[i].val);
+
return 0;
}
@@ -2129,6 +2348,7 @@
ops->reg_wake_irq = tx_macro_reg_wake_irq;
ops->set_port_map = tx_macro_set_port_map;
ops->clk_switch = tx_macro_clk_switch;
+ ops->reg_evt_listener = tx_macro_register_event_listener;
}
static int tx_macro_probe(struct platform_device *pdev)
@@ -2208,6 +2428,7 @@
tx_priv->swr_plat_data.write = NULL;
tx_priv->swr_plat_data.bulk_write = NULL;
tx_priv->swr_plat_data.clk = tx_macro_swrm_clock;
+ tx_priv->swr_plat_data.core_vote = tx_macro_core_vote;
tx_priv->swr_plat_data.handle_irq = NULL;
mutex_init(&tx_priv->mclk_lock);
diff --git a/asoc/codecs/bolero/va-macro.c b/asoc/codecs/bolero/va-macro.c
index 4c16319..b7d6fe0 100644
--- a/asoc/codecs/bolero/va-macro.c
+++ b/asoc/codecs/bolero/va-macro.c
@@ -124,6 +124,7 @@
int micb_users;
u16 default_clk_id;
u16 clk_id;
+ int tx_clk_status;
};
static bool va_macro_get_data(struct snd_soc_component *component,
@@ -294,8 +295,10 @@
if (bolero_tx_clk_switch(component))
dev_dbg(va_dev, "%s: clock switch failed\n",
__func__);
+ bolero_register_event_listener(component, true);
break;
case SND_SOC_DAPM_POST_PMD:
+ bolero_register_event_listener(component, false);
if (bolero_tx_clk_switch(component))
dev_dbg(va_dev, "%s: clock switch failed\n",__func__);
if (va_priv->lpass_audio_hw_vote)
@@ -328,14 +331,19 @@
va_priv->default_clk_id,
TX_CORE_CLK,
true);
+ if (!ret)
+ va_priv->tx_clk_status++;
ret = va_macro_mclk_enable(va_priv, 1, true);
break;
case SND_SOC_DAPM_POST_PMD:
va_macro_mclk_enable(va_priv, 0, true);
- bolero_clk_rsc_request_clock(va_priv->dev,
+ if (va_priv->tx_clk_status > 0) {
+ bolero_clk_rsc_request_clock(va_priv->dev,
va_priv->default_clk_id,
TX_CORE_CLK,
false);
+ va_priv->tx_clk_status--;
+ }
break;
default:
dev_err(va_priv->dev,
@@ -767,16 +775,21 @@
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- ret = bolero_clk_rsc_request_clock(va_priv->dev,
+ if (va_priv->tx_clk_status > 0) {
+ ret = bolero_clk_rsc_request_clock(va_priv->dev,
va_priv->default_clk_id,
TX_CORE_CLK,
false);
+ va_priv->tx_clk_status--;
+ }
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);
+ if (!ret)
+ va_priv->tx_clk_status++;
break;
default:
dev_err(va_priv->dev,
diff --git a/asoc/codecs/bolero/wsa-macro.c b/asoc/codecs/bolero/wsa-macro.c
index 39f331b..dfca968 100644
--- a/asoc/codecs/bolero/wsa-macro.c
+++ b/asoc/codecs/bolero/wsa-macro.c
@@ -160,6 +160,7 @@
int (*write)(void *handle, int reg, int val);
int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len);
int (*clk)(void *handle, bool enable);
+ int (*core_vote)(void *handle, bool enable);
int (*handle_irq)(void *handle,
irqreturn_t (*swrm_irq_handler)(int irq,
void *data),
@@ -868,6 +869,7 @@
}
}
}
+ bolero_wsa_pa_on(wsa_dev);
break;
default:
break;
@@ -1442,14 +1444,22 @@
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
u16 reg = 0;
+ struct device *wsa_dev = NULL;
+ struct wsa_macro_priv *wsa_priv = NULL;
+
+ if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__))
+ return -EINVAL;
+
reg = BOLERO_CDC_WSA_RX0_RX_PATH_CTL +
WSA_MACRO_RX_PATH_OFFSET * w->shift;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- if (wsa_macro_adie_lb(component, w->shift))
+ if (wsa_macro_adie_lb(component, w->shift)) {
snd_soc_component_update_bits(component,
reg, 0x20, 0x20);
+ bolero_wsa_pa_on(wsa_dev);
+ }
break;
default:
break;
@@ -2789,6 +2799,24 @@
wsa_macro_init_bcl_pmic_reg(component);
}
+static int wsa_macro_core_vote(void *handle, bool enable)
+{
+ struct wsa_macro_priv *wsa_priv = (struct wsa_macro_priv *) handle;
+ int ret = 0;
+
+ if (wsa_priv == NULL) {
+ pr_err("%s: wsa priv data is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (enable) {
+ pm_runtime_get_sync(wsa_priv->dev);
+ pm_runtime_put_autosuspend(wsa_priv->dev);
+ pm_runtime_mark_last_busy(wsa_priv->dev);
+ }
+
+ return ret;
+}
+
static int wsa_swrm_clock(void *handle, bool enable)
{
struct wsa_macro_priv *wsa_priv = (struct wsa_macro_priv *) handle;
@@ -2807,8 +2835,16 @@
if (enable) {
pm_runtime_get_sync(wsa_priv->dev);
if (wsa_priv->swr_clk_users == 0) {
- msm_cdc_pinctrl_select_active_state(
+ ret = msm_cdc_pinctrl_select_active_state(
wsa_priv->wsa_swr_gpio_p);
+ if (ret < 0) {
+ dev_err_ratelimited(wsa_priv->dev,
+ "%s: wsa swr pinctrl enable failed\n",
+ __func__);
+ pm_runtime_mark_last_busy(wsa_priv->dev);
+ pm_runtime_put_autosuspend(wsa_priv->dev);
+ goto exit;
+ }
ret = wsa_macro_mclk_enable(wsa_priv, 1, true);
if (ret < 0) {
msm_cdc_pinctrl_select_sleep_state(
@@ -2816,6 +2852,8 @@
dev_err_ratelimited(wsa_priv->dev,
"%s: wsa request clock enable failed\n",
__func__);
+ pm_runtime_mark_last_busy(wsa_priv->dev);
+ pm_runtime_put_autosuspend(wsa_priv->dev);
goto exit;
}
if (wsa_priv->reset_swr)
@@ -2831,9 +2869,9 @@
0x02, 0x00);
wsa_priv->reset_swr = false;
}
+ wsa_priv->swr_clk_users++;
pm_runtime_mark_last_busy(wsa_priv->dev);
pm_runtime_put_autosuspend(wsa_priv->dev);
- wsa_priv->swr_clk_users++;
} else {
if (wsa_priv->swr_clk_users <= 0) {
dev_err(wsa_priv->dev, "%s: clock already disabled\n",
@@ -2847,8 +2885,14 @@
BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
0x01, 0x00);
wsa_macro_mclk_enable(wsa_priv, 0, true);
- msm_cdc_pinctrl_select_sleep_state(
+ ret = msm_cdc_pinctrl_select_sleep_state(
wsa_priv->wsa_swr_gpio_p);
+ if (ret < 0) {
+ dev_err_ratelimited(wsa_priv->dev,
+ "%s: wsa swr pinctrl disable failed\n",
+ __func__);
+ goto exit;
+ }
}
}
dev_dbg(wsa_priv->dev, "%s: swrm clock users %d\n",
@@ -3115,6 +3159,7 @@
wsa_priv->swr_plat_data.write = NULL;
wsa_priv->swr_plat_data.bulk_write = NULL;
wsa_priv->swr_plat_data.clk = wsa_swrm_clock;
+ wsa_priv->swr_plat_data.core_vote = wsa_macro_core_vote;
wsa_priv->swr_plat_data.handle_irq = NULL;
ret = of_property_read_u32(pdev->dev.of_node, "qcom,default-clk-id",
diff --git a/asoc/codecs/ep92/ep92.c b/asoc/codecs/ep92/ep92.c
index 06d29ff..6077070 100644
--- a/asoc/codecs/ep92/ep92.c
+++ b/asoc/codecs/ep92/ep92.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/
#include <linux/init.h>
@@ -25,6 +25,7 @@
#define EP92_POLL_INTERVAL_OFF_MSEC 200
#define EP92_POLL_INTERVAL_ON_MSEC 20
+#define EP92_POLL_RUNOUT_MSEC 5000
#define EP92_SYSFS_ENTRY_MAX_LEN 64
#define EP92_HYST_CNT 5
@@ -68,6 +69,9 @@
struct timer_list timer;
struct work_struct read_status_worker;
int irq;
+ int poll_trig;
+ int poll_rem;
+ int force_inactive;
int hyst_tx_plug;
int hyst_link_on0;
@@ -560,15 +564,23 @@
send_uevent = true;
}
+ old = ep92->ai.cs[0];
+ ep92->ai.cs[0] = snd_soc_component_read32(component,
+ EP92_AUDIO_INFO_CHANNEL_STATUS_0);
+ if (ep92->ai.cs[0] == 0xff) {
+ dev_dbg(component->dev, "ep92 EP92_AUDIO_INFO_CHANNEL_STATUS_0 read 0xff\n");
+ ep92->ai.cs[0] = old;
+ }
+ change = ep92->ai.cs[0] ^ old;
+ if (change & EP92_AI_PREEMPH_MASK) {
+ dev_dbg(component->dev, "ep92 preemph changed to %d\n",
+ (ep92->ai.cs[0] & EP92_AI_PREEMPH_MASK) >>
+ EP92_AI_PREEMPH_SHIFT);
+ send_uevent = true;
+ }
+
new_mode = ep92->old_mode;
if (ep92->ai.audio_status & EP92_AI_STD_ADO_MASK) {
- old = ep92->ai.cs[0];
- ep92->ai.cs[0] = snd_soc_component_read32(component,
- EP92_AUDIO_INFO_CHANNEL_STATUS_0);
- if (ep92->ai.cs[0] == 0xff) {
- dev_dbg(component->dev, "ep92 EP92_AUDIO_INFO_CHANNEL_STATUS_0 read 0xff\n");
- ep92->ai.cs[0] = old;
- }
if (ep92->ai.cs[0] & EP92_AI_NPCM_MASK)
new_mode = 1; /* Compr */
else
@@ -648,10 +660,8 @@
ep92_init(component, ep92);
/* start polling when codec is registered */
- if (ep92->irq == 0) {
- mod_timer(&ep92->timer, jiffies +
- msecs_to_jiffies(EP92_POLL_INTERVAL_OFF_MSEC));
- }
+ mod_timer(&ep92->timer, jiffies +
+ msecs_to_jiffies(EP92_POLL_INTERVAL_OFF_MSEC));
return 0;
}
@@ -690,6 +700,9 @@
if (component == NULL)
return;
+ if (ep92->force_inactive)
+ return;
+
/* check ADO_CHF that is set when audio format has changed */
val = snd_soc_component_read32(component, EP92_BI_GENERAL_INFO_1);
if (val == 0xff) {
@@ -724,6 +737,10 @@
dev_dbg(component->dev, "ep92_interrupt\n");
+ ep92->poll_trig = 1;
+ mod_timer(&ep92->timer, jiffies +
+ msecs_to_jiffies(EP92_POLL_INTERVAL_ON_MSEC));
+
schedule_work(&ep92->read_status_worker);
return IRQ_HANDLED;
@@ -732,14 +749,45 @@
void ep92_poll_status(struct timer_list *t)
{
struct ep92_pdata *ep92 = from_timer(ep92, t, timer);
- u32 poll_msec;
+ struct snd_soc_component *component = ep92->component;
- if ((ep92->gc.ctl & EP92_GC_POWER_MASK) == 0)
- poll_msec = EP92_POLL_INTERVAL_OFF_MSEC;
- else
- poll_msec = EP92_POLL_INTERVAL_ON_MSEC;
+ if (ep92->force_inactive)
+ return;
- mod_timer(&ep92->timer, jiffies + msecs_to_jiffies(poll_msec));
+ /* if no IRQ is configured, always keep on polling */
+ if (ep92->irq == 0)
+ ep92->poll_rem = EP92_POLL_RUNOUT_MSEC;
+
+ /* on interrupt, start polling for some time */
+ if (ep92->poll_trig) {
+ if (ep92->poll_rem == 0)
+ dev_info(component->dev, "status checking activated\n");
+
+ ep92->poll_trig = 0;
+ ep92->poll_rem = EP92_POLL_RUNOUT_MSEC;
+ }
+
+ /*
+ * If power_on == 0, poll only until poll_rem reaches zero and stop.
+ * This allows to system to go to low power sleep mode.
+ * Otherwise (power_on == 1) always re-arm timer to keep on polling.
+ */
+ if ((ep92->gc.ctl & EP92_GC_POWER_MASK) == 0) {
+ if (ep92->poll_rem) {
+ mod_timer(&ep92->timer, jiffies +
+ msecs_to_jiffies(EP92_POLL_INTERVAL_OFF_MSEC));
+ if (ep92->poll_rem > EP92_POLL_INTERVAL_OFF_MSEC) {
+ ep92->poll_rem -= EP92_POLL_INTERVAL_OFF_MSEC;
+ } else {
+ dev_info(component->dev, "status checking stopped\n");
+ ep92->poll_rem = 0;
+ }
+ }
+ } else {
+ ep92->poll_rem = EP92_POLL_RUNOUT_MSEC;
+ mod_timer(&ep92->timer, jiffies +
+ msecs_to_jiffies(EP92_POLL_INTERVAL_ON_MSEC));
+ }
schedule_work(&ep92->read_status_worker);
}
@@ -933,7 +981,7 @@
return ret;
}
-static ssize_t ep92_sysfs_rda_avmute(struct device *dev,
+static ssize_t ep92_sysfs_rda_audio_preemph(struct device *dev,
struct device_attribute *attr, char *buf)
{
ssize_t ret;
@@ -945,6 +993,26 @@
return -ENODEV;
}
+ val = (ep92->ai.cs[0] & EP92_AI_PREEMPH_MASK) >>
+ EP92_AI_PREEMPH_SHIFT;
+
+ ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val);
+ dev_dbg(dev, "%s: '%d'\n", __func__, val);
+
+ return ret;
+}
+
+static ssize_t ep92_sysfs_rda_avmute(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret;
+ int val;
+ struct ep92_pdata *ep92 = dev_get_drvdata(dev);
+
+ if (!ep92 || !ep92->component) {
+ dev_err(dev, "%s: device error\n", __func__);
+ return -ENODEV;
+ }
val = (ep92->ai.system_status_0 >> EP92_AI_AVMUTE_SHIFT) &
EP92_2CHOICE_MASK;
@@ -1162,6 +1230,11 @@
ep92->gc.ctl &= ~EP92_GC_POWER_MASK;
ep92->gc.ctl |= (val << EP92_GC_POWER_SHIFT) & EP92_GC_POWER_MASK;
+ if (val == 1) {
+ ep92->poll_trig = 1;
+ mod_timer(&ep92->timer, jiffies +
+ msecs_to_jiffies(EP92_POLL_INTERVAL_ON_MSEC));
+ }
rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN);
end:
return rc;
@@ -1321,12 +1394,12 @@
}
reg = snd_soc_component_read32(ep92->component, EP92_GENERAL_CONTROL_0);
- reg &= ~EP92_GC_AUDIO_PATH_MASK;
- reg |= (val << EP92_GC_AUDIO_PATH_SHIFT) & EP92_GC_AUDIO_PATH_MASK;
+ reg &= ~EP92_GC_ARC_EN_MASK;
+ reg |= (val << EP92_GC_ARC_EN_SHIFT) & EP92_GC_ARC_EN_MASK;
snd_soc_component_write(ep92->component, EP92_GENERAL_CONTROL_0, reg);
- ep92->gc.ctl &= ~EP92_GC_AUDIO_PATH_MASK;
- ep92->gc.ctl |= (val << EP92_GC_AUDIO_PATH_SHIFT) &
- EP92_GC_AUDIO_PATH_MASK;
+ ep92->gc.ctl &= ~EP92_GC_ARC_EN_MASK;
+ ep92->gc.ctl |= (val << EP92_GC_ARC_EN_SHIFT) &
+ EP92_GC_ARC_EN_MASK;
rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN);
end:
@@ -1440,6 +1513,83 @@
return rc;
}
+static ssize_t ep92_sysfs_rda_runout(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret;
+ int val;
+ struct ep92_pdata *ep92 = dev_get_drvdata(dev);
+
+ if (!ep92 || !ep92->component) {
+ dev_err(dev, "%s: device error\n", __func__);
+ return -ENODEV;
+ }
+
+ val = ep92->poll_rem;
+
+ ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val);
+ dev_dbg(dev, "%s: '%d'\n", __func__, val);
+
+ return ret;
+}
+
+static ssize_t ep92_sysfs_rda_force_inactive(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret;
+ int val;
+ struct ep92_pdata *ep92 = dev_get_drvdata(dev);
+
+ if (!ep92 || !ep92->component) {
+ dev_err(dev, "%s: device error\n", __func__);
+ return -ENODEV;
+ }
+
+ val = ep92->force_inactive;
+
+ ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val);
+ dev_dbg(dev, "%s: '%d'\n", __func__, val);
+
+ return ret;
+}
+
+static ssize_t ep92_sysfs_wta_force_inactive(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int val, rc;
+ struct ep92_pdata *ep92 = dev_get_drvdata(dev);
+
+ if (!ep92 || !ep92->component) {
+ dev_err(dev, "%s: device error\n", __func__);
+ return -ENODEV;
+ }
+
+ rc = kstrtoint(buf, 10, &val);
+ if (rc) {
+ dev_err(dev, "%s: kstrtoint failed. rc=%d\n", __func__, rc);
+ goto end;
+ }
+ if ((val < 0) || (val > 1)) {
+ dev_err(dev, "%s: value out of range.\n", __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (val == 0) {
+ ep92->force_inactive = 0;
+ ep92->poll_trig = 1;
+ mod_timer(&ep92->timer, jiffies +
+ msecs_to_jiffies(EP92_POLL_INTERVAL_ON_MSEC));
+ } else {
+ ep92->force_inactive = 1;
+ ep92->poll_rem = 0;
+ }
+
+ rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN);
+end:
+ return rc;
+}
+
static DEVICE_ATTR(chipid, 0444, ep92_sysfs_rda_chipid, NULL);
static DEVICE_ATTR(version, 0444, ep92_sysfs_rda_version, NULL);
static DEVICE_ATTR(audio_state, 0444, ep92_sysfs_rda_audio_state, NULL);
@@ -1448,6 +1598,7 @@
static DEVICE_ATTR(audio_layout, 0444, ep92_sysfs_rda_audio_layout, NULL);
static DEVICE_ATTR(audio_ch_count, 0444, ep92_sysfs_rda_audio_ch_count, NULL);
static DEVICE_ATTR(audio_ch_alloc, 0444, ep92_sysfs_rda_audio_ch_alloc, NULL);
+static DEVICE_ATTR(audio_preemph, 0444, ep92_sysfs_rda_audio_preemph, NULL);
static DEVICE_ATTR(audio_avmute, 0444, ep92_sysfs_rda_avmute, NULL);
static DEVICE_ATTR(link_on0, 0444, ep92_sysfs_rda_link_on0, NULL);
static DEVICE_ATTR(link_on1, 0444, ep92_sysfs_rda_link_on1, NULL);
@@ -1467,6 +1618,9 @@
ep92_sysfs_wta_cec_mute);
static DEVICE_ATTR(cec_volume, 0644, ep92_sysfs_rda_cec_volume,
ep92_sysfs_wta_cec_volume);
+static DEVICE_ATTR(runout, 0444, ep92_sysfs_rda_runout, NULL);
+static DEVICE_ATTR(force_inactive, 0644, ep92_sysfs_rda_force_inactive,
+ ep92_sysfs_wta_force_inactive);
static struct attribute *ep92_fs_attrs[] = {
&dev_attr_chipid.attr,
@@ -1477,6 +1631,7 @@
&dev_attr_audio_layout.attr,
&dev_attr_audio_ch_count.attr,
&dev_attr_audio_ch_alloc.attr,
+ &dev_attr_audio_preemph.attr,
&dev_attr_audio_avmute.attr,
&dev_attr_link_on0.attr,
&dev_attr_link_on1.attr,
@@ -1490,6 +1645,8 @@
&dev_attr_arc_enable.attr,
&dev_attr_cec_mute.attr,
&dev_attr_cec_volume.attr,
+ &dev_attr_runout.attr,
+ &dev_attr_force_inactive.attr,
NULL,
};
@@ -1552,9 +1709,9 @@
ep92->irq = 0;
}
}
- /* poll status if IRQ is not configured */
- if (ep92->irq == 0)
- timer_setup(&ep92->timer, ep92_poll_status, 0);
+ /* prepare timer */
+ timer_setup(&ep92->timer, ep92_poll_status, 0);
+ ep92->poll_rem = EP92_POLL_RUNOUT_MSEC;
#if IS_ENABLED(CONFIG_DEBUG_FS)
/* debugfs interface */
@@ -1610,8 +1767,7 @@
err_sysfs:
snd_soc_unregister_component(&client->dev);
err_reg:
- if (ep92->irq == 0)
- del_timer(&ep92->timer);
+ del_timer(&ep92->timer);
return ret;
}
@@ -1622,8 +1778,7 @@
ep92 = i2c_get_clientdata(client);
if (ep92) {
- if (ep92->irq == 0)
- del_timer(&ep92->timer);
+ del_timer(&ep92->timer);
#if IS_ENABLED(CONFIG_DEBUG_FS)
debugfs_remove_recursive(ep92->debugfs_dir);
diff --git a/asoc/codecs/ep92/ep92.h b/asoc/codecs/ep92/ep92.h
index bfc8d80..18cb010 100644
--- a/asoc/codecs/ep92/ep92.h
+++ b/asoc/codecs/ep92/ep92.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/
#ifndef __EP92_H__
@@ -171,6 +171,8 @@
#define EP92_AI_STD_ADO_MASK 0x08
#define EP92_AI_RATE_MASK 0x07
#define EP92_AI_NPCM_MASK 0x02
+#define EP92_AI_PREEMPH_SHIFT 3
+#define EP92_AI_PREEMPH_MASK 0x38
#define EP92_AI_CH_COUNT_MASK 0x07
#define EP92_AI_CH_ALLOC_MASK 0xff
diff --git a/asoc/codecs/msm-cdc-pinctrl.c b/asoc/codecs/msm-cdc-pinctrl.c
index c611345..a10a681 100644
--- a/asoc/codecs/msm-cdc-pinctrl.c
+++ b/asoc/codecs/msm-cdc-pinctrl.c
@@ -14,13 +14,16 @@
#include <linux/pinctrl/qcom-pinctrl.h>
#include <asoc/msm-cdc-pinctrl.h>
+#define MAX_GPIOS 16
+
struct msm_cdc_pinctrl_info {
struct pinctrl *pinctrl;
struct pinctrl_state *pinctrl_active;
struct pinctrl_state *pinctrl_sleep;
int gpio;
bool state;
- u32 tlmm_gpio;
+ u32 tlmm_gpio[MAX_GPIOS];
+ u32 count;
bool wakeup_capable;
};
@@ -151,14 +154,21 @@
{
struct msm_cdc_pinctrl_info *gpio_data;
int ret = 0;
+ u32 i = 0;
gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
if (!gpio_data)
return -EINVAL;
- if (gpio_data->wakeup_capable)
- ret = msm_gpio_mpm_wake_set(gpio_data->tlmm_gpio, enable);
-
+ if (gpio_data->wakeup_capable) {
+ for (i = 0; i < gpio_data->count; i++) {
+ ret = msm_gpio_mpm_wake_set(gpio_data->tlmm_gpio[i],
+ enable);
+ if (ret < 0)
+ goto exit;
+ }
+ }
+exit:
return ret;
}
EXPORT_SYMBOL(msm_cdc_pinctrl_set_wakeup_capable);
@@ -167,7 +177,9 @@
{
int ret = 0;
struct msm_cdc_pinctrl_info *gpio_data;
- u32 tlmm_gpio = 0;
+ u32 tlmm_gpio[MAX_GPIOS] = {0};
+ u32 i = 0;
+ int count = 0;
gpio_data = devm_kzalloc(&pdev->dev,
sizeof(struct msm_cdc_pinctrl_info),
@@ -210,12 +222,19 @@
__func__, ret);
}
- if (!of_property_read_u32(pdev->dev.of_node, "qcom,tlmm-gpio",
- &tlmm_gpio)) {
+
+ count = of_property_count_u32_elems(pdev->dev.of_node, "qcom,tlmm-gpio");
+ if (count <= 0)
+ goto cdc_rst;
+ if (!of_property_read_u32_array(pdev->dev.of_node, "qcom,tlmm-gpio",
+ tlmm_gpio, count)) {
gpio_data->wakeup_capable = true;
- gpio_data->tlmm_gpio = tlmm_gpio;
+ for (i = 0; i < count; i++)
+ gpio_data->tlmm_gpio[i] = tlmm_gpio[i];
+ gpio_data->count = count;
}
+cdc_rst:
gpio_data->gpio = of_get_named_gpio(pdev->dev.of_node,
"qcom,cdc-rst-n-gpio", 0);
if (gpio_is_valid(gpio_data->gpio)) {
diff --git a/asoc/codecs/msm_hdmi_codec_rx.c b/asoc/codecs/msm_hdmi_codec_rx.c
index 8d2507e..5144b92 100644
--- a/asoc/codecs/msm_hdmi_codec_rx.c
+++ b/asoc/codecs/msm_hdmi_codec_rx.c
@@ -100,7 +100,7 @@
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
uinfo->count = 0;
mutex_unlock(&codec_data->dp_ops_lock);
- return -EINVAL;
+ return 0;
}
rc = codec_data->ext_disp_ops.get_audio_edid_blk(
diff --git a/asoc/codecs/wcd-irq.c b/asoc/codecs/wcd-irq.c
index 3c8e777..d4890a6 100644
--- a/asoc/codecs/wcd-irq.c
+++ b/asoc/codecs/wcd-irq.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/
#include <linux/kernel.h>
@@ -178,7 +178,8 @@
return -EINVAL;
}
- regmap_del_irq_chip(irq_find_mapping(virq, 0), irq_info->irq_chip);
+ devm_regmap_del_irq_chip(irq_info->dev, irq_find_mapping(virq, 0),
+ irq_info->irq_chip);
return 0;
}
diff --git a/asoc/codecs/wcd-mbhc-v2.c b/asoc/codecs/wcd-mbhc-v2.c
index 624b59a..01544aa 100644
--- a/asoc/codecs/wcd-mbhc-v2.c
+++ b/asoc/codecs/wcd-mbhc-v2.c
@@ -691,10 +691,8 @@
&mbhc->zl, &mbhc->zr);
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN,
fsm_en);
- if ((mbhc->zl > mbhc->mbhc_cfg->linein_th &&
- mbhc->zl < MAX_IMPED) &&
- (mbhc->zr > mbhc->mbhc_cfg->linein_th &&
- mbhc->zr < MAX_IMPED) &&
+ if ((mbhc->zl > mbhc->mbhc_cfg->linein_th) &&
+ (mbhc->zr > mbhc->mbhc_cfg->linein_th) &&
(jack_type == SND_JACK_HEADPHONE)) {
jack_type = SND_JACK_LINEOUT;
mbhc->force_linein = true;
diff --git a/asoc/codecs/wcd937x/wcd937x.c b/asoc/codecs/wcd937x/wcd937x.c
index fe0c65c..7a618c5 100644
--- a/asoc/codecs/wcd937x/wcd937x.c
+++ b/asoc/codecs/wcd937x/wcd937x.c
@@ -1349,13 +1349,17 @@
snd_soc_component_update_bits(component,
WCD937X_ANA_TX_CH2, 0x40, 0x40);
snd_soc_component_update_bits(component,
- WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x30, 0x30);
+ WCD937X_ANA_TX_CH3_HPF, 0x40, 0x40);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x70, 0x70);
snd_soc_component_update_bits(component,
WCD937X_ANA_TX_CH1, 0x80, 0x80);
snd_soc_component_update_bits(component,
WCD937X_ANA_TX_CH2, 0x40, 0x00);
snd_soc_component_update_bits(component,
WCD937X_ANA_TX_CH2, 0x80, 0x80);
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_TX_CH3, 0x80, 0x80);
break;
case SND_SOC_DAPM_POST_PMD:
snd_soc_component_update_bits(component,
@@ -1363,6 +1367,8 @@
snd_soc_component_update_bits(component,
WCD937X_ANA_TX_CH2, 0x80, 0x00);
snd_soc_component_update_bits(component,
+ WCD937X_ANA_TX_CH3, 0x80, 0x00);
+ snd_soc_component_update_bits(component,
WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x10, 0x00);
mutex_lock(&wcd937x->ana_tx_clk_lock);
wcd937x->ana_clk_count--;
@@ -2316,7 +2322,8 @@
"variant",
priv->entry);
if (!variant_entry) {
- dev_dbg(codec->dev, "%s: failed to create wcd937x variant entry\n",
+ dev_dbg(component->dev,
+ "%s: failed to create wcd937x variant entry\n",
__func__);
return -ENOMEM;
}
diff --git a/asoc/codecs/wcd938x/internal.h b/asoc/codecs/wcd938x/internal.h
index 2c67ff8..098a60d 100644
--- a/asoc/codecs/wcd938x/internal.h
+++ b/asoc/codecs/wcd938x/internal.h
@@ -11,6 +11,8 @@
#include <asoc/wcd-clsh.h>
#include "wcd938x-mbhc.h"
+#define SWR_SCP_CONTROL 0x44
+#define SWR_SCP_HOST_CLK_DIV2_CTL_BANK 0xE0
#define WCD938X_MAX_MICBIAS 4
/* Convert from vout ctl to micbias voltage in mV */
@@ -97,6 +99,7 @@
struct snd_info_entry *variant_entry;
int flyback_cur_det_disable;
int ear_rx_path;
+ bool dev_up;
};
struct wcd938x_micbias_setting {
diff --git a/asoc/codecs/wcd938x/wcd938x-slave.c b/asoc/codecs/wcd938x/wcd938x-slave.c
index ec42b0d..d56cebb 100644
--- a/asoc/codecs/wcd938x/wcd938x-slave.c
+++ b/asoc/codecs/wcd938x/wcd938x-slave.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -11,10 +11,267 @@
#include <linux/component.h>
#include <soc/soundwire.h>
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#define SWR_SLV_MAX_REG_ADDR 0x2009
+#define SWR_SLV_START_REG_ADDR 0x40
+#define SWR_SLV_MAX_BUF_LEN 20
+#define BYTES_PER_LINE 12
+#define SWR_SLV_RD_BUF_LEN 8
+#define SWR_SLV_WR_BUF_LEN 32
+#define SWR_SLV_MAX_DEVICES 2
+#endif /* CONFIG_DEBUG_FS */
+
struct wcd938x_slave_priv {
struct swr_device *swr_slave;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_wcd938x_dent;
+ struct dentry *debugfs_peek;
+ struct dentry *debugfs_poke;
+ struct dentry *debugfs_reg_dump;
+ unsigned int read_data;
+#endif
};
+#ifdef CONFIG_DEBUG_FS
+static int codec_debug_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static int get_parameters(char *buf, u32 *param1, int num_of_par)
+{
+ char *token = NULL;
+ int base = 0, cnt = 0;
+
+ token = strsep(&buf, " ");
+ for (cnt = 0; cnt < num_of_par; cnt++) {
+ if (token) {
+ if ((token[1] == 'x') || (token[1] == 'X'))
+ base = 16;
+ else
+ base = 10;
+
+ if (kstrtou32(token, base, ¶m1[cnt]) != 0)
+ return -EINVAL;
+
+ token = strsep(&buf, " ");
+ } else {
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static bool is_swr_slv_reg_readable(int reg)
+{
+ int ret = true;
+
+ if (((reg > 0x46) && (reg < 0x4A)) ||
+ ((reg > 0x4A) && (reg < 0x50)) ||
+ ((reg > 0x55) && (reg < 0xD0)) ||
+ ((reg > 0xD0) && (reg < 0xE0)) ||
+ ((reg > 0xE0) && (reg < 0xF0)) ||
+ ((reg > 0xF0) && (reg < 0x100)) ||
+ ((reg > 0x105) && (reg < 0x120)) ||
+ ((reg > 0x205) && (reg < 0x220)) ||
+ ((reg > 0x305) && (reg < 0x320)) ||
+ ((reg > 0x405) && (reg < 0x420)) ||
+ ((reg > 0x128) && (reg < 0x130)) ||
+ ((reg > 0x228) && (reg < 0x230)) ||
+ ((reg > 0x328) && (reg < 0x330)) ||
+ ((reg > 0x428) && (reg < 0x430)) ||
+ ((reg > 0x138) && (reg < 0x205)) ||
+ ((reg > 0x238) && (reg < 0x305)) ||
+ ((reg > 0x338) && (reg < 0x405)) ||
+ ((reg > 0x405) && (reg < 0xF00)) ||
+ ((reg > 0xF05) && (reg < 0xF20)) ||
+ ((reg > 0xF25) && (reg < 0xF30)) ||
+ ((reg > 0xF35) && (reg < 0x2000)))
+ ret = false;
+
+ return ret;
+}
+
+static ssize_t wcd938x_swrslave_reg_show(struct swr_device *pdev,
+ char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ int i, reg_val, len;
+ ssize_t total = 0;
+ char tmp_buf[SWR_SLV_MAX_BUF_LEN];
+
+ if (!ubuf || !ppos)
+ return 0;
+
+ for (i = (((int) *ppos/BYTES_PER_LINE) + SWR_SLV_START_REG_ADDR);
+ i <= SWR_SLV_MAX_REG_ADDR; i++) {
+ if (!is_swr_slv_reg_readable(i))
+ continue;
+ swr_read(pdev, pdev->dev_num, i, ®_val, 1);
+ len = snprintf(tmp_buf, 25, "0x%.3x: 0x%.2x\n", i,
+ (reg_val & 0xFF));
+ if ((total + len) >= count - 1)
+ break;
+ if (copy_to_user((ubuf + total), tmp_buf, len)) {
+ pr_err("%s: fail to copy reg dump\n", __func__);
+ total = -EFAULT;
+ goto copy_err;
+ }
+ total += len;
+ *ppos += len;
+ }
+
+copy_err:
+ *ppos = SWR_SLV_MAX_REG_ADDR * BYTES_PER_LINE;
+ return total;
+}
+
+static ssize_t codec_debug_dump(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct swr_device *pdev;
+
+ if (!count || !file || !ppos || !ubuf)
+ return -EINVAL;
+
+ pdev = file->private_data;
+ if (!pdev)
+ return -EINVAL;
+
+ if (*ppos < 0)
+ return -EINVAL;
+
+ return wcd938x_swrslave_reg_show(pdev, ubuf, count, ppos);
+}
+
+static ssize_t codec_debug_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ char lbuf[SWR_SLV_RD_BUF_LEN];
+ struct swr_device *pdev = NULL;
+ struct wcd938x_slave_priv *wcd938x_slave = NULL;
+
+ if (!count || !file || !ppos || !ubuf)
+ return -EINVAL;
+
+ pdev = file->private_data;
+ if (!pdev)
+ return -EINVAL;
+
+ wcd938x_slave = swr_get_dev_data(pdev);
+ if (!wcd938x_slave)
+ return -EINVAL;
+
+ if (*ppos < 0)
+ return -EINVAL;
+
+ snprintf(lbuf, sizeof(lbuf), "0x%x\n",
+ (wcd938x_slave->read_data & 0xFF));
+
+ return simple_read_from_buffer(ubuf, count, ppos, lbuf,
+ strnlen(lbuf, 7));
+}
+
+static ssize_t codec_debug_peek_write(struct file *file,
+ const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+ char lbuf[SWR_SLV_WR_BUF_LEN];
+ int rc = 0;
+ u32 param[5];
+ struct swr_device *pdev = NULL;
+ struct wcd938x_slave_priv *wcd938x_slave = NULL;
+
+ if (!cnt || !file || !ppos || !ubuf)
+ return -EINVAL;
+
+ pdev = file->private_data;
+ if (!pdev)
+ return -EINVAL;
+
+ wcd938x_slave = swr_get_dev_data(pdev);
+ if (!wcd938x_slave)
+ return -EINVAL;
+
+ if (*ppos < 0)
+ return -EINVAL;
+
+ if (cnt > sizeof(lbuf) - 1)
+ return -EINVAL;
+
+ rc = copy_from_user(lbuf, ubuf, cnt);
+ if (rc)
+ return -EFAULT;
+
+ lbuf[cnt] = '\0';
+ rc = get_parameters(lbuf, param, 1);
+ if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) && (rc == 0)))
+ return -EINVAL;
+ swr_read(pdev, pdev->dev_num, param[0], &wcd938x_slave->read_data, 1);
+ if (rc == 0)
+ rc = cnt;
+ else
+ pr_err("%s: rc = %d\n", __func__, rc);
+
+ return rc;
+}
+
+static ssize_t codec_debug_write(struct file *file,
+ const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+ char lbuf[SWR_SLV_WR_BUF_LEN];
+ int rc = 0;
+ u32 param[5];
+ struct swr_device *pdev;
+
+ if (!file || !ppos || !ubuf)
+ return -EINVAL;
+
+ pdev = file->private_data;
+ if (!pdev)
+ return -EINVAL;
+
+ if (cnt > sizeof(lbuf) - 1)
+ return -EINVAL;
+
+ rc = copy_from_user(lbuf, ubuf, cnt);
+ if (rc)
+ return -EFAULT;
+
+ lbuf[cnt] = '\0';
+ rc = get_parameters(lbuf, param, 2);
+ if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) &&
+ (param[1] <= 0xFF) && (rc == 0)))
+ return -EINVAL;
+ swr_write(pdev, pdev->dev_num, param[0], ¶m[1]);
+ if (rc == 0)
+ rc = cnt;
+ else
+ pr_err("%s: rc = %d\n", __func__, rc);
+
+ return rc;
+}
+
+static const struct file_operations codec_debug_write_ops = {
+ .open = codec_debug_open,
+ .write = codec_debug_write,
+};
+
+static const struct file_operations codec_debug_read_ops = {
+ .open = codec_debug_open,
+ .read = codec_debug_read,
+ .write = codec_debug_peek_write,
+};
+
+static const struct file_operations codec_debug_dump_ops = {
+ .open = codec_debug_open,
+ .read = codec_debug_dump,
+};
+#endif
+
static int wcd938x_slave_bind(struct device *dev,
struct device *master, void *data)
{
@@ -82,11 +339,49 @@
wcd938x_slave->swr_slave = pdev;
+#ifdef CONFIG_DEBUG_FS
+ if (!wcd938x_slave->debugfs_wcd938x_dent) {
+ wcd938x_slave->debugfs_wcd938x_dent = debugfs_create_dir(
+ dev_name(&pdev->dev), 0);
+ if (!IS_ERR(wcd938x_slave->debugfs_wcd938x_dent)) {
+ wcd938x_slave->debugfs_peek =
+ debugfs_create_file("swrslave_peek",
+ S_IFREG | 0444,
+ wcd938x_slave->debugfs_wcd938x_dent,
+ (void *) pdev,
+ &codec_debug_read_ops);
+
+ wcd938x_slave->debugfs_poke =
+ debugfs_create_file("swrslave_poke",
+ S_IFREG | 0444,
+ wcd938x_slave->debugfs_wcd938x_dent,
+ (void *) pdev,
+ &codec_debug_write_ops);
+
+ wcd938x_slave->debugfs_reg_dump =
+ debugfs_create_file(
+ "swrslave_reg_dump",
+ S_IFREG | 0444,
+ wcd938x_slave->debugfs_wcd938x_dent,
+ (void *) pdev,
+ &codec_debug_dump_ops);
+ }
+ }
+#endif
+
return component_add(&pdev->dev, &wcd938x_slave_comp_ops);
}
static int wcd938x_swr_remove(struct swr_device *pdev)
{
+#ifdef CONFIG_DEBUG_FS
+ struct wcd938x_slave_priv *wcd938x_slave = swr_get_dev_data(pdev);
+
+ if (wcd938x_slave) {
+ debugfs_remove_recursive(wcd938x_slave->debugfs_wcd938x_dent);
+ wcd938x_slave->debugfs_wcd938x_dent = NULL;
+ }
+#endif
component_del(&pdev->dev, &wcd938x_slave_comp_ops);
swr_set_dev_data(pdev, NULL);
swr_remove_device(pdev);
diff --git a/asoc/codecs/wcd938x/wcd938x.c b/asoc/codecs/wcd938x/wcd938x.c
index f89a2aa..2980c37 100644
--- a/asoc/codecs/wcd938x/wcd938x.c
+++ b/asoc/codecs/wcd938x/wcd938x.c
@@ -25,6 +25,7 @@
#include "wcd938x-registers.h"
#include "wcd938x.h"
+
#define WCD938X_DRV_NAME "wcd938x_codec"
#define NUM_SWRS_DT_PARAMS 5
#define WCD938X_VARIANT_ENTRY_SIZE 32
@@ -126,6 +127,45 @@
return IRQ_HANDLED;
}
+static int wcd938x_swr_slv_get_current_bank(struct swr_device *dev, u8 devnum)
+{
+ int ret = 0;
+ int bank = 0;
+
+ ret = swr_read(dev, devnum, SWR_SCP_CONTROL, &bank, 1);
+ if (ret)
+ return -EINVAL;
+
+ return ((bank & 0x40) ? 1: 0);
+}
+
+static int wcd938x_swr_slv_set_host_clk_div2(struct swr_device *dev,
+ u8 devnum, int bank)
+{
+ u8 val = (bank ? 1 : 0);
+
+ return (swr_write(dev, devnum,
+ (SWR_SCP_HOST_CLK_DIV2_CTL_BANK + (0x10 * bank)), &val));
+}
+
+static int wcd938x_set_swr_clk_rate(struct snd_soc_component *component,
+ int mode, int bank)
+{
+ u8 mask = (bank ? 0xF0 : 0x0F);
+ u8 val = 0;
+
+ if ((mode == ADC_MODE_ULP1) || (mode == ADC_MODE_ULP2))
+ val = (bank ? 0x60 : 0x06);
+ else
+ val = 0x00;
+
+ snd_soc_component_update_bits(component,
+ WCD938X_DIGITAL_SWR_TX_CLK_RATE,
+ mask, val);
+
+ return 0;
+}
+
static int wcd938x_init_reg(struct snd_soc_component *component)
{
snd_soc_component_update_bits(component, WCD938X_SLEEP_CTL, 0x0E, 0x0E);
@@ -181,6 +221,8 @@
WCD938X_MICB3_TEST_CTL_1, 0xE0, 0xE0);
snd_soc_component_update_bits(component,
WCD938X_MICB4_TEST_CTL_1, 0xE0, 0xE0);
+ snd_soc_component_update_bits(component,
+ WCD938X_TX_3_4_TEST_BLK_EN2, 0x01, 0x00);
return 0;
}
@@ -548,12 +590,26 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
wcd938x_rx_clk_enable(component);
- snd_soc_component_update_bits(component,
+ wcd938x->ear_rx_path =
+ snd_soc_component_read32(
+ component, WCD938X_DIGITAL_CDC_EAR_PATH_CTL);
+ if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) {
+ snd_soc_component_update_bits(component,
+ WCD938X_EAR_EAR_DAC_CON, 0x80, 0x00);
+ snd_soc_component_update_bits(component,
+ WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, 0x01, 0x01);
+ snd_soc_component_update_bits(component,
+ WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x04, 0x04);
+ snd_soc_component_update_bits(component,
+ WCD938X_ANA_EAR_COMPANDER_CTL, 0x80, 0x80);
+ } else {
+ snd_soc_component_update_bits(component,
WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, 0x04, 0x04);
- snd_soc_component_update_bits(component,
+ snd_soc_component_update_bits(component,
WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x01);
- snd_soc_component_update_bits(component,
+ snd_soc_component_update_bits(component,
WCD938X_DIGITAL_CDC_COMP_CTL_0, 0x02, 0x02);
+ }
/* 5 msec delay as per HW requirement */
usleep_range(5000, 5010);
if (wcd938x->flyback_cur_det_disable == 0)
@@ -567,6 +623,14 @@
wcd938x->hph_mode);
break;
case SND_SOC_DAPM_POST_PMD:
+ if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) {
+ snd_soc_component_update_bits(component,
+ WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, 0x01, 0x00);
+ }
+ snd_soc_component_update_bits(component,
+ WCD938X_ANA_EAR_COMPANDER_CTL, 0x80, 0x00);
+ snd_soc_component_update_bits(component,
+ WCD938X_EAR_EAR_DAC_CON, 0x80, 0x80);
break;
};
return 0;
@@ -967,16 +1031,21 @@
snd_soc_component_update_bits(component,
WCD938X_ANA_RX_SUPPLIES,
0x02, 0x02);
- if (wcd938x->update_wcd_event)
- wcd938x->update_wcd_event(wcd938x->handle,
+ if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) {
+ if (wcd938x->update_wcd_event)
+ wcd938x->update_wcd_event(wcd938x->handle,
WCD_BOLERO_EVT_RX_MUTE,
- (WCD_RX1 << 0x10));
- if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX)
+ (WCD_RX3 << 0x10));
wcd_enable_irq(&wcd938x->irq_info,
WCD938X_IRQ_AUX_PDM_WD_INT);
- else
+ } else {
+ if (wcd938x->update_wcd_event)
+ wcd938x->update_wcd_event(wcd938x->handle,
+ WCD_BOLERO_EVT_RX_MUTE,
+ (WCD_RX1 << 0x10));
wcd_enable_irq(&wcd938x->irq_info,
WCD938X_IRQ_HPHL_PDM_WD_INT);
+ }
break;
case SND_SOC_DAPM_PRE_PMD:
if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX)
@@ -1335,17 +1404,33 @@
snd_soc_dapm_to_component(w->dapm);
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
int ret = 0;
+ int bank = 0;
+ int mode = 0;
+ bank = wcd938x_swr_slv_get_current_bank(wcd938x->tx_swr_dev,
+ wcd938x->tx_swr_dev->dev_num);
+ wcd938x_swr_slv_set_host_clk_div2(wcd938x->tx_swr_dev,
+ wcd938x->tx_swr_dev->dev_num, bank);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev,
wcd938x->tx_swr_dev->dev_num,
true);
+ if (test_bit(WCD_ADC1, &wcd938x->status_mask))
+ mode |= wcd938x->tx_mode[WCD_ADC1];
+ if (test_bit(WCD_ADC2, &wcd938x->status_mask))
+ mode |= wcd938x->tx_mode[WCD_ADC2];
+ if (test_bit(WCD_ADC3, &wcd938x->status_mask))
+ mode |= wcd938x->tx_mode[WCD_ADC3];
+ if (test_bit(WCD_ADC4, &wcd938x->status_mask))
+ mode |= wcd938x->tx_mode[WCD_ADC4];
+ wcd938x_set_swr_clk_rate(component, mode, bank);
break;
case SND_SOC_DAPM_POST_PMD:
ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev,
wcd938x->tx_swr_dev->dev_num,
false);
+ wcd938x_set_swr_clk_rate(component, ADC_MODE_INVALID, bank);
break;
};
@@ -1565,6 +1650,7 @@
int pre_off_event = 0, post_off_event = 0;
int post_on_event = 0, post_dapm_off = 0;
int post_dapm_on = 0;
+ int ret = 0;
if ((micb_index < 0) || (micb_index > WCD938X_MAX_MICBIAS - 1)) {
dev_err(component->dev,
@@ -1606,6 +1692,12 @@
switch (req) {
case MICB_PULLUP_ENABLE:
+ if (!wcd938x->dev_up) {
+ dev_dbg(component->dev, "%s: enable req %d wcd device down\n",
+ __func__, req);
+ ret = -ENODEV;
+ goto done;
+ }
wcd938x->pullup_ref[micb_index]++;
if ((wcd938x->pullup_ref[micb_index] == 1) &&
(wcd938x->micb_ref[micb_index] == 0))
@@ -1615,12 +1707,24 @@
case MICB_PULLUP_DISABLE:
if (wcd938x->pullup_ref[micb_index] > 0)
wcd938x->pullup_ref[micb_index]--;
+ if (!wcd938x->dev_up) {
+ dev_dbg(component->dev, "%s: enable req %d wcd device down\n",
+ __func__, req);
+ ret = -ENODEV;
+ goto done;
+ }
if ((wcd938x->pullup_ref[micb_index] == 0) &&
(wcd938x->micb_ref[micb_index] == 0))
snd_soc_component_update_bits(component, micb_reg,
0xC0, 0x00);
break;
case MICB_ENABLE:
+ if (!wcd938x->dev_up) {
+ dev_dbg(component->dev, "%s: enable req %d wcd device down\n",
+ __func__, req);
+ ret = -ENODEV;
+ goto done;
+ }
wcd938x->micb_ref[micb_index]++;
if (wcd938x->micb_ref[micb_index] == 1) {
snd_soc_component_update_bits(component,
@@ -1653,6 +1757,12 @@
case MICB_DISABLE:
if (wcd938x->micb_ref[micb_index] > 0)
wcd938x->micb_ref[micb_index]--;
+ if (!wcd938x->dev_up) {
+ dev_dbg(component->dev, "%s: enable req %d wcd device down\n",
+ __func__, req);
+ ret = -ENODEV;
+ goto done;
+ }
if ((wcd938x->micb_ref[micb_index] == 0) &&
(wcd938x->pullup_ref[micb_index] > 0))
snd_soc_component_update_bits(component, micb_reg,
@@ -1683,9 +1793,10 @@
"%s: micb_num:%d, micb_ref: %d, pullup_ref: %d\n",
__func__, micb_num, wcd938x->micb_ref[micb_index],
wcd938x->pullup_ref[micb_index]);
- mutex_unlock(&wcd938x->micb_lock);
- return 0;
+done:
+ mutex_unlock(&wcd938x->micb_lock);
+ return ret;
}
EXPORT_SYMBOL(wcd938x_micbias_control);
@@ -1748,6 +1859,7 @@
0x80, 0x00);
break;
case BOLERO_WCD_EVT_SSR_DOWN:
+ wcd938x->dev_up = false;
mbhc = &wcd938x->mbhc->wcd_mbhc;
wcd938x_mbhc_ssr_down(wcd938x->mbhc, component);
wcd938x_reset_low(wcd938x->dev);
@@ -1768,6 +1880,7 @@
} else {
wcd938x_mbhc_hs_detect(component, mbhc->mbhc_cfg);
}
+ wcd938x->dev_up = true;
break;
case BOLERO_WCD_EVT_CLK_NOTIFY:
snd_soc_component_update_bits(component,
@@ -2779,6 +2892,40 @@
}
EXPORT_SYMBOL(wcd938x_info_create_codec_entry);
+static int wcd938x_set_micbias_data(struct wcd938x_priv *wcd938x,
+ struct wcd938x_pdata *pdata)
+{
+ int vout_ctl_1 = 0, vout_ctl_2 = 0, vout_ctl_3 = 0, vout_ctl_4 = 0;
+ int rc = 0;
+
+ if (!pdata) {
+ dev_err(wcd938x->dev, "%s: NULL pdata\n", __func__);
+ return -ENODEV;
+ }
+
+ /* set micbias voltage */
+ vout_ctl_1 = wcd938x_get_micb_vout_ctl_val(pdata->micbias.micb1_mv);
+ vout_ctl_2 = wcd938x_get_micb_vout_ctl_val(pdata->micbias.micb2_mv);
+ vout_ctl_3 = wcd938x_get_micb_vout_ctl_val(pdata->micbias.micb3_mv);
+ vout_ctl_4 = wcd938x_get_micb_vout_ctl_val(pdata->micbias.micb4_mv);
+ if (vout_ctl_1 < 0 || vout_ctl_2 < 0 || vout_ctl_3 < 0 ||
+ vout_ctl_4 < 0) {
+ rc = -EINVAL;
+ goto done;
+ }
+ regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB1, 0x3F,
+ vout_ctl_1);
+ regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB2, 0x3F,
+ vout_ctl_2);
+ regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB3, 0x3F,
+ vout_ctl_3);
+ regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB4, 0x3F,
+ vout_ctl_4);
+
+done:
+ return rc;
+}
+
static int wcd938x_soc_codec_probe(struct snd_soc_component *component)
{
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
@@ -2889,6 +3036,7 @@
return ret;
}
}
+ wcd938x->dev_up = true;
return ret;
err_hwdep:
@@ -3026,6 +3174,19 @@
dev_info(dev, "%s: Micbias3 DT property not found\n",
__func__);
}
+
+ /* MB4 */
+ if (of_find_property(dev->of_node, "qcom,cdc-micbias4-mv",
+ NULL)) {
+ rc = wcd938x_read_of_property_u32(dev,
+ "qcom,cdc-micbias4-mv",
+ &prop_val);
+ if (!rc)
+ mb->micb4_mv = prop_val;
+ } else {
+ dev_info(dev, "%s: Micbias4 DT property not found\n",
+ __func__);
+ }
}
static int wcd938x_reset_low(struct device *dev)
@@ -3164,6 +3325,12 @@
}
wcd938x->tx_swr_dev->slave_irq = wcd938x->virq;
+ ret = wcd938x_set_micbias_data(wcd938x, pdata);
+ if (ret < 0) {
+ dev_err(dev, "%s: bad micbias pdata\n", __func__);
+ goto err_irq;
+ }
+
/* Request for watchdog interrupt */
wcd_request_irq(&wcd938x->irq_info, WCD938X_IRQ_HPHR_PDM_WD_INT,
"HPHR PDM WD INT", wcd938x_wd_handle_irq, NULL);
diff --git a/asoc/codecs/wsa881x.c b/asoc/codecs/wsa881x.c
index 2871ad3..966fa8a 100644
--- a/asoc/codecs/wsa881x.c
+++ b/asoc/codecs/wsa881x.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -16,6 +16,7 @@
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
#include <linux/regmap.h>
#include <linux/debugfs.h>
#include <soc/soundwire.h>
@@ -101,6 +102,30 @@
struct delayed_work ocp_ctl_work;
struct device_node *wsa_rst_np;
int pa_mute;
+ struct device_node *bolero_np;
+ struct platform_device* bolero_dev;
+ struct notifier_block bolero_nblock;
+ void *handle;
+ int (*register_notifier)(void *handle,
+ struct notifier_block *nblock,
+ bool enable);
+};
+
+/* from bolero to WSA events */
+enum {
+ BOLERO_WSA_EVT_TX_CH_HOLD_CLEAR = 1,
+ BOLERO_WSA_EVT_PA_OFF_PRE_SSR,
+ BOLERO_WSA_EVT_SSR_DOWN,
+ BOLERO_WSA_EVT_SSR_UP,
+ BOLERO_WSA_EVT_PA_ON_POST_FSCLK,
+};
+
+struct wsa_ctrl_platform_data {
+ void *handle;
+ int (*update_wsa_event)(void *handle, u16 event, u32 data);
+ int (*register_notifier)(void *handle,
+ struct notifier_block *nblock,
+ bool enable);
};
#define SWR_SLV_MAX_REG_ADDR 0x390
@@ -1006,6 +1031,10 @@
break;
case SND_SOC_DAPM_POST_PMU:
+ if (!wsa881x->bolero_dev)
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_DRV_EN,
+ 0x80, 0x80);
if (!wsa881x->comp_enable) {
max_gain = wsa881x->pa_gain;
/*
@@ -1039,6 +1068,9 @@
wsa881x->swr_slave->dev_num);
break;
case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_DRV_EN,
+ 0x80, 0x00);
if (wsa881x->visense_enable) {
wsa881x_visense_adc_ctrl(component, DISABLE);
wsa881x_visense_txfe_ctrl(component, DISABLE,
@@ -1064,7 +1096,7 @@
wsa881x_rdac_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_PGA_E("SPKR PGA", WSA881X_SPKR_DRV_EN, 7, 0, NULL, 0,
+ SND_SOC_DAPM_PGA_E("SPKR PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
wsa881x_spkr_pa_event, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -1338,12 +1370,45 @@
return ret;
}
+static int wsa881x_event_notify(struct notifier_block *nb,
+ unsigned long val, void *ptr)
+{
+ u16 event = (val & 0xffff);
+ struct wsa881x_priv *wsa881x = container_of(nb, struct wsa881x_priv,
+ bolero_nblock);
+
+ if (!wsa881x)
+ return -EINVAL;
+
+ switch (event) {
+ case BOLERO_WSA_EVT_PA_OFF_PRE_SSR:
+ snd_soc_component_update_bits(wsa881x->component,
+ WSA881X_SPKR_DRV_GAIN,
+ 0xF0, 0xC0);
+ snd_soc_component_update_bits(wsa881x->component,
+ WSA881X_SPKR_DRV_EN,
+ 0x80, 0x00);
+ break;
+ case BOLERO_WSA_EVT_PA_ON_POST_FSCLK:
+ if ((snd_soc_component_read32(wsa881x->component,
+ WSA881X_SPKR_DAC_CTL) & 0x80) == 0x80)
+ snd_soc_component_update_bits(wsa881x->component,
+ WSA881X_SPKR_DRV_EN,
+ 0x80, 0x80);
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static int wsa881x_swr_probe(struct swr_device *pdev)
{
int ret = 0;
struct wsa881x_priv *wsa881x;
u8 devnum = 0;
bool pin_state_current = false;
+ struct wsa_ctrl_platform_data *plat_data = NULL;
wsa881x = devm_kzalloc(&pdev->dev, sizeof(struct wsa881x_priv),
GFP_KERNEL);
@@ -1435,6 +1500,37 @@
__func__);
goto dev_err;
}
+
+ wsa881x->bolero_np = of_parse_phandle(pdev->dev.of_node,
+ "qcom,bolero-handle", 0);
+ if (wsa881x->bolero_np) {
+ wsa881x->bolero_dev =
+ of_find_device_by_node(wsa881x->bolero_np);
+ if (wsa881x->bolero_dev) {
+ plat_data = dev_get_platdata(&wsa881x->bolero_dev->dev);
+ if (plat_data) {
+ wsa881x->bolero_nblock.notifier_call =
+ wsa881x_event_notify;
+ if (plat_data->register_notifier)
+ plat_data->register_notifier(
+ plat_data->handle,
+ &wsa881x->bolero_nblock,
+ true);
+ wsa881x->register_notifier =
+ plat_data->register_notifier;
+ wsa881x->handle = plat_data->handle;
+ } else {
+ dev_err(&pdev->dev, "%s: plat data not found\n",
+ __func__);
+ }
+ } else {
+ dev_err(&pdev->dev, "%s: bolero dev not found\n",
+ __func__);
+ }
+ } else {
+ dev_info(&pdev->dev, "%s: bolero node not found\n", __func__);
+ }
+
mutex_init(&wsa881x->res_lock);
mutex_init(&wsa881x->temp_lock);
@@ -1457,6 +1553,10 @@
dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
return -EINVAL;
}
+
+ if (wsa881x->register_notifier)
+ wsa881x->register_notifier(wsa881x->handle,
+ &wsa881x->bolero_nblock, false);
debugfs_remove_recursive(debugfs_wsa881x_dent);
debugfs_wsa881x_dent = NULL;
mutex_destroy(&wsa881x->res_lock);
diff --git a/asoc/kona-port-config.h b/asoc/kona-port-config.h
index 0f73791..723c94a 100644
--- a/asoc/kona-port-config.h
+++ b/asoc/kona-port-config.h
@@ -50,6 +50,15 @@
{3, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1}, /* TX4 */
};
+/* TX UC1: TX1: 1ch, TX2: 2chs, TX3: 1ch(MBHC) */
+static struct port_params tx_frame_params_v2[SWR_MSTR_PORT_LEN] = {
+ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},/* PCM OUT */
+ {1, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1}, /* TX1 */
+ {1, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2}, /* TX2 */
+ {3, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0}, /* TX3 */
+ {3, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2}, /* TX4 */
+};
+
static struct swr_mstr_port_map sm_port_map[] = {
{TX_MACRO, SWR_UC0, tx_frame_params_default},
{RX_MACRO, SWR_UC0, rx_frame_params_default},
@@ -57,4 +66,11 @@
{WSA_MACRO, SWR_UC0, wsa_frame_params_default},
};
+static struct swr_mstr_port_map sm_port_map_v2[] = {
+ {TX_MACRO, SWR_UC0, tx_frame_params_v2},
+ {RX_MACRO, SWR_UC0, rx_frame_params_default},
+ {RX_MACRO, SWR_UC1, rx_frame_params_dsd},
+ {WSA_MACRO, SWR_UC0, wsa_frame_params_default},
+};
+
#endif /* _KONA_PORT_CONFIG */
diff --git a/asoc/kona.c b/asoc/kona.c
index d91627b..c98de7a 100644
--- a/asoc/kona.c
+++ b/asoc/kona.c
@@ -76,6 +76,12 @@
#define WCN_CDC_SLIM_TX_CH_MAX_LITO 3
enum {
+ RX_PATH = 0,
+ TX_PATH,
+ MAX_PATH,
+};
+
+enum {
TDM_0 = 0,
TDM_1,
TDM_2,
@@ -87,6 +93,9 @@
TDM_PORT_MAX,
};
+#define TDM_MAX_SLOTS 8
+#define TDM_SLOT_WIDTH_BITS 32
+
enum {
TDM_PRI = 0,
TDM_SEC,
@@ -158,6 +167,7 @@
struct msm_asoc_mach_data {
struct snd_info_entry *codec_root;
int usbc_en2_gpio; /* used by gpio driver API */
+ int lito_v2_enabled;
struct device_node *dmic01_gpio_p; /* used by pinctrl API */
struct device_node *dmic23_gpio_p; /* used by pinctrl API */
struct device_node *dmic45_gpio_p; /* used by pinctrl API */
@@ -176,6 +186,10 @@
u32 channel;
};
+struct tdm_dev_config {
+ unsigned int tdm_slot_offset[TDM_MAX_SLOTS];
+};
+
enum {
EXT_DISP_RX_IDX_DP = 0,
EXT_DISP_RX_IDX_DP1,
@@ -462,6 +476,153 @@
[SEN_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
};
+static struct tdm_dev_config pri_tdm_dev_config[MAX_PATH][TDM_PORT_MAX] = {
+ { /* PRI TDM */
+ { {0, 4, 0xFFFF} }, /* RX_0 */
+ { {8, 12, 0xFFFF} }, /* RX_1 */
+ { {16, 20, 0xFFFF} }, /* RX_2 */
+ { {24, 28, 0xFFFF} }, /* RX_3 */
+ { {0xFFFF} }, /* RX_4 */
+ { {0xFFFF} }, /* RX_5 */
+ { {0xFFFF} }, /* RX_6 */
+ { {0xFFFF} }, /* RX_7 */
+ },
+ {
+ { {0, 4, 8, 12, 0xFFFF} }, /* TX_0 */
+ { {8, 12, 0xFFFF} }, /* TX_1 */
+ { {16, 20, 0xFFFF} }, /* TX_2 */
+ { {24, 28, 0xFFFF} }, /* TX_3 */
+ { {0xFFFF} }, /* TX_4 */
+ { {0xFFFF} }, /* TX_5 */
+ { {0xFFFF} }, /* TX_6 */
+ { {0xFFFF} }, /* TX_7 */
+ },
+};
+
+static struct tdm_dev_config sec_tdm_dev_config[MAX_PATH][TDM_PORT_MAX] = {
+ { /* SEC TDM */
+ { {0, 4, 0xFFFF} }, /* RX_0 */
+ { {8, 12, 0xFFFF} }, /* RX_1 */
+ { {16, 20, 0xFFFF} }, /* RX_2 */
+ { {24, 28, 0xFFFF} }, /* RX_3 */
+ { {0xFFFF} }, /* RX_4 */
+ { {0xFFFF} }, /* RX_5 */
+ { {0xFFFF} }, /* RX_6 */
+ { {0xFFFF} }, /* RX_7 */
+ },
+ {
+ { {0, 4, 0xFFFF} }, /* TX_0 */
+ { {8, 12, 0xFFFF} }, /* TX_1 */
+ { {16, 20, 0xFFFF} }, /* TX_2 */
+ { {24, 28, 0xFFFF} }, /* TX_3 */
+ { {0xFFFF} }, /* TX_4 */
+ { {0xFFFF} }, /* TX_5 */
+ { {0xFFFF} }, /* TX_6 */
+ { {0xFFFF} }, /* TX_7 */
+ },
+};
+
+static struct tdm_dev_config tert_tdm_dev_config[MAX_PATH][TDM_PORT_MAX] = {
+ { /* TERT TDM */
+ { {0, 4, 0xFFFF} }, /* RX_0 */
+ { {8, 12, 0xFFFF} }, /* RX_1 */
+ { {16, 20, 0xFFFF} }, /* RX_2 */
+ { {24, 28, 0xFFFF} }, /* RX_3 */
+ { {0xFFFF} }, /* RX_4 */
+ { {0xFFFF} }, /* RX_5 */
+ { {0xFFFF} }, /* RX_6 */
+ { {0xFFFF} }, /* RX_7 */
+ },
+ {
+ { {0, 4, 0xFFFF} }, /* TX_0 */
+ { {8, 12, 0xFFFF} }, /* TX_1 */
+ { {16, 20, 0xFFFF} }, /* TX_2 */
+ { {24, 28, 0xFFFF} }, /* TX_3 */
+ { {0xFFFF} }, /* TX_4 */
+ { {0xFFFF} }, /* TX_5 */
+ { {0xFFFF} }, /* TX_6 */
+ { {0xFFFF} }, /* TX_7 */
+ },
+};
+
+static struct tdm_dev_config quat_tdm_dev_config[MAX_PATH][TDM_PORT_MAX] = {
+ { /* QUAT TDM */
+ { {0, 4, 0xFFFF} }, /* RX_0 */
+ { {8, 12, 0xFFFF} }, /* RX_1 */
+ { {16, 20, 0xFFFF} }, /* RX_2 */
+ { {24, 28, 0xFFFF} }, /* RX_3 */
+ { {0xFFFF} }, /* RX_4 */
+ { {0xFFFF} }, /* RX_5 */
+ { {0xFFFF} }, /* RX_6 */
+ { {0xFFFF} }, /* RX_7 */
+ },
+ {
+ { {0, 4, 0xFFFF} }, /* TX_0 */
+ { {8, 12, 0xFFFF} }, /* TX_1 */
+ { {16, 20, 0xFFFF} }, /* TX_2 */
+ { {24, 28, 0xFFFF} }, /* TX_3 */
+ { {0xFFFF} }, /* TX_4 */
+ { {0xFFFF} }, /* TX_5 */
+ { {0xFFFF} }, /* TX_6 */
+ { {0xFFFF} }, /* TX_7 */
+ },
+};
+
+static struct tdm_dev_config quin_tdm_dev_config[MAX_PATH][TDM_PORT_MAX] = {
+ { /* QUIN TDM */
+ { {0, 4, 0xFFFF} }, /* RX_0 */
+ { {8, 12, 0xFFFF} }, /* RX_1 */
+ { {16, 20, 0xFFFF} }, /* RX_2 */
+ { {24, 28, 0xFFFF} }, /* RX_3 */
+ { {0xFFFF} }, /* RX_4 */
+ { {0xFFFF} }, /* RX_5 */
+ { {0xFFFF} }, /* RX_6 */
+ { {0xFFFF} }, /* RX_7 */
+ },
+ {
+ { {0, 4, 0xFFFF} }, /* TX_0 */
+ { {8, 12, 0xFFFF} }, /* TX_1 */
+ { {16, 20, 0xFFFF} }, /* TX_2 */
+ { {24, 28, 0xFFFF} }, /* TX_3 */
+ { {0xFFFF} }, /* TX_4 */
+ { {0xFFFF} }, /* TX_5 */
+ { {0xFFFF} }, /* TX_6 */
+ { {0xFFFF} }, /* TX_7 */
+ },
+};
+
+static struct tdm_dev_config sen_tdm_dev_config[MAX_PATH][TDM_PORT_MAX] = {
+ { /* SEN TDM */
+ { {0, 4, 0xFFFF} }, /* RX_0 */
+ { {8, 12, 0xFFFF} }, /* RX_1 */
+ { {16, 20, 0xFFFF} }, /* RX_2 */
+ { {24, 28, 0xFFFF} }, /* RX_3 */
+ { {0xFFFF} }, /* RX_4 */
+ { {0xFFFF} }, /* RX_5 */
+ { {0xFFFF} }, /* RX_6 */
+ { {0xFFFF} }, /* RX_7 */
+ },
+ {
+ { {0, 4, 0xFFFF} }, /* TX_0 */
+ { {8, 12, 0xFFFF} }, /* TX_1 */
+ { {16, 20, 0xFFFF} }, /* TX_2 */
+ { {24, 28, 0xFFFF} }, /* TX_3 */
+ { {0xFFFF} }, /* TX_4 */
+ { {0xFFFF} }, /* TX_5 */
+ { {0xFFFF} }, /* TX_6 */
+ { {0xFFFF} }, /* TX_7 */
+ },
+};
+
+static void *tdm_cfg[TDM_INTERFACE_MAX] = {
+ pri_tdm_dev_config,
+ sec_tdm_dev_config,
+ tert_tdm_dev_config,
+ quat_tdm_dev_config,
+ quin_tdm_dev_config,
+ sen_tdm_dev_config,
+};
+
/* Default configuration of Codec DMA Interface RX */
static struct dev_config cdc_dma_rx_cfg[] = {
[WSA_CDC_DMA_RX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
@@ -1789,6 +1950,45 @@
return ret;
}
+static int tdm_slot_map_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int slot_index = 0;
+ int interface = ucontrol->value.integer.value[0];
+ int channel = ucontrol->value.integer.value[1];
+ unsigned int offset_val = 0;
+ unsigned int *slot_offset = NULL;
+ struct tdm_dev_config *config = NULL;
+
+ if (interface < 0 || interface >= (TDM_INTERFACE_MAX * MAX_PATH)) {
+ pr_err("%s: incorrect interface = %d\n", __func__, interface);
+ return -EINVAL;
+ }
+ if (channel < 0 || channel >= TDM_PORT_MAX) {
+ pr_err("%s: incorrect channel = %d\n", __func__, channel);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: interface = %d, channel = %d\n", __func__,
+ interface, channel);
+
+ config = ((struct tdm_dev_config *) tdm_cfg[interface / MAX_PATH]) +
+ ((interface % MAX_PATH) * TDM_PORT_MAX) + channel;
+ slot_offset = config->tdm_slot_offset;
+
+ for (slot_index = 0; slot_index < TDM_MAX_SLOTS; slot_index++) {
+ offset_val = ucontrol->value.integer.value[MAX_PATH +
+ slot_index];
+ /* Offset value can only be 0, 4, 8, ..28 */
+ if (offset_val % 4 == 0 && offset_val <= 28)
+ slot_offset[slot_index] = offset_val;
+ pr_debug("%s: slot offset[%d] = %d\n", __func__,
+ slot_index, slot_offset[slot_index]);
+ }
+
+ return 0;
+}
+
static int aux_pcm_get_port_idx(struct snd_kcontrol *kcontrol)
{
int idx = 0;
@@ -3744,6 +3944,8 @@
afe_loopback_tx_ch_get, afe_loopback_tx_ch_put),
SOC_ENUM_EXT("VI_FEED_TX Channels", vi_feed_tx_chs,
msm_vi_feed_tx_ch_get, msm_vi_feed_tx_ch_put),
+ SOC_SINGLE_MULTI_EXT("TDM Slot Map", SND_SOC_NOPM, 0, 255, 0,
+ TDM_MAX_SLOTS + MAX_PATH, NULL, tdm_slot_map_put),
};
static const struct snd_kcontrol_new msm_snd_controls[] = {
@@ -3813,8 +4015,9 @@
SNDRV_PCM_HW_PARAM_CHANNELS);
int idx = 0, rc = 0;
- pr_debug("%s: format = %d, rate = %d\n",
- __func__, params_format(params), params_rate(params));
+ pr_debug("%s: dai_id= %d, format = %d, rate = %d\n",
+ __func__, dai_link->id, params_format(params),
+ params_rate(params));
switch (dai_link->id) {
case MSM_BACKEND_DAI_USB_RX:
@@ -4280,65 +4483,51 @@
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret = 0;
- int slot_width = 32;
- int channels, slots;
+ int slot_width = TDM_SLOT_WIDTH_BITS;
+ int channels, slots = TDM_MAX_SLOTS;
unsigned int slot_mask, rate, clk_freq;
- unsigned int slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
+ unsigned int *slot_offset;
+ struct tdm_dev_config *config;
+ unsigned int path_dir = 0, interface = 0, channel_interface = 0;
pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id);
- /* currently only supporting TDM_RX_0 and TDM_TX_0 */
- switch (cpu_dai->id) {
- case AFE_PORT_ID_PRIMARY_TDM_RX:
- slots = tdm_rx_cfg[TDM_PRI][TDM_0].channels;
- break;
- case AFE_PORT_ID_SECONDARY_TDM_RX:
- slots = tdm_rx_cfg[TDM_SEC][TDM_0].channels;
- break;
- case AFE_PORT_ID_TERTIARY_TDM_RX:
- slots = tdm_rx_cfg[TDM_TERT][TDM_0].channels;
- break;
- case AFE_PORT_ID_QUATERNARY_TDM_RX:
- slots = tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
- break;
- case AFE_PORT_ID_QUINARY_TDM_RX:
- slots = tdm_rx_cfg[TDM_QUIN][TDM_0].channels;
- break;
- case AFE_PORT_ID_SENARY_TDM_RX:
- slots = tdm_rx_cfg[TDM_SEN][TDM_0].channels;
- break;
- case AFE_PORT_ID_PRIMARY_TDM_TX:
- slots = tdm_tx_cfg[TDM_PRI][TDM_0].channels;
- break;
- case AFE_PORT_ID_SECONDARY_TDM_TX:
- slots = tdm_tx_cfg[TDM_SEC][TDM_0].channels;
- break;
- case AFE_PORT_ID_TERTIARY_TDM_TX:
- slots = tdm_tx_cfg[TDM_TERT][TDM_0].channels;
- break;
- case AFE_PORT_ID_QUATERNARY_TDM_TX:
- slots = tdm_tx_cfg[TDM_QUAT][TDM_0].channels;
- break;
- case AFE_PORT_ID_QUINARY_TDM_TX:
- slots = tdm_tx_cfg[TDM_QUIN][TDM_0].channels;
- break;
- case AFE_PORT_ID_SENARY_TDM_TX:
- slots = tdm_tx_cfg[TDM_SEN][TDM_0].channels;
- break;
-
- default:
+ if (cpu_dai->id < AFE_PORT_ID_TDM_PORT_RANGE_START) {
pr_err("%s: dai id 0x%x not supported\n",
__func__, cpu_dai->id);
return -EINVAL;
}
+ /* RX or TX */
+ path_dir = cpu_dai->id % MAX_PATH;
+
+ /* PRI, SEC, TERT, QUAT, QUIN, ... */
+ interface = (cpu_dai->id - AFE_PORT_ID_TDM_PORT_RANGE_START)
+ / (MAX_PATH * TDM_PORT_MAX);
+
+ /* 0, 1, 2, .. 7 */
+ channel_interface =
+ ((cpu_dai->id - AFE_PORT_ID_TDM_PORT_RANGE_START) / MAX_PATH)
+ % TDM_PORT_MAX;
+
+ pr_debug("%s: path dir: %u, interface %u, channel interface %u\n",
+ __func__, path_dir, interface, channel_interface);
+
+ config = ((struct tdm_dev_config *) tdm_cfg[interface]) +
+ (path_dir * TDM_PORT_MAX) + channel_interface;
+ slot_offset = config->tdm_slot_offset;
+
+ if (path_dir)
+ channels = tdm_tx_cfg[interface][channel_interface].channels;
+ else
+ channels = tdm_rx_cfg[interface][channel_interface].channels;
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
/*2 slot config - bits 0 and 1 set for the first two slots */
slot_mask = 0x0000FFFF >> (16 - slots);
- channels = slots;
- pr_debug("%s: tdm rx slot_width %d slots %d\n",
- __func__, slot_width, slots);
+ pr_debug("%s: tdm rx slot_width %d slots %d slot_mask %x\n",
+ __func__, slot_width, slots, slot_mask);
ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask,
slots, slot_width);
@@ -4348,6 +4537,8 @@
goto end;
}
+ pr_debug("%s: tdm rx channels: %d\n", __func__, channels);
+
ret = snd_soc_dai_set_channel_map(cpu_dai,
0, NULL, channels, slot_offset);
if (ret < 0) {
@@ -4358,10 +4549,9 @@
} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
/*2 slot config - bits 0 and 1 set for the first two slots */
slot_mask = 0x0000FFFF >> (16 - slots);
- channels = slots;
- pr_debug("%s: tdm tx slot_width %d slots %d\n",
- __func__, slot_width, slots);
+ pr_debug("%s: tdm tx slot_width %d slots %d slot_mask %x\n",
+ __func__, slot_width, slots, slot_mask);
ret = snd_soc_dai_set_tdm_slot(cpu_dai, slot_mask, 0,
slots, slot_width);
@@ -4371,6 +4561,8 @@
goto end;
}
+ pr_debug("%s: tdm tx channels: %d\n", __func__, channels);
+
ret = snd_soc_dai_set_channel_map(cpu_dai,
channels, slot_offset, 0, NULL);
if (ret < 0) {
@@ -5097,8 +5289,17 @@
WSA_MACRO_GAIN_OFFSET_M1P5_DB);
}
}
- bolero_set_port_map(component, ARRAY_SIZE(sm_port_map),
- sm_port_map);
+ if (pdata->lito_v2_enabled) {
+ /*
+ * Enable tx data line3 for saipan version v2 amd
+ * write corresponding lpi register.
+ */
+ bolero_set_port_map(component, ARRAY_SIZE(sm_port_map_v2),
+ sm_port_map_v2);
+ } else {
+ bolero_set_port_map(component, ARRAY_SIZE(sm_port_map),
+ sm_port_map);
+ }
}
card = rtd->card->snd_card;
if (!pdata->codec_root) {
@@ -7707,6 +7908,10 @@
if (!pdata)
return -ENOMEM;
+ of_property_read_u32(pdev->dev.of_node,
+ "qcom,lito-is-v2-enabled",
+ &pdata->lito_v2_enabled);
+
card = populate_snd_card_dailinks(&pdev->dev);
if (!card) {
dev_err(&pdev->dev, "%s: Card uninitialized\n", __func__);
@@ -7828,6 +8033,10 @@
pdata->dmic45_gpio_p = of_parse_phandle(pdev->dev.of_node,
"qcom,cdc-dmic45-gpios",
0);
+ if (pdata->dmic01_gpio_p)
+ msm_cdc_pinctrl_set_wakeup_capable(pdata->dmic01_gpio_p, false);
+ if (pdata->dmic23_gpio_p)
+ msm_cdc_pinctrl_set_wakeup_capable(pdata->dmic23_gpio_p, false);
if (pdata->dmic45_gpio_p)
msm_cdc_pinctrl_set_wakeup_capable(pdata->dmic45_gpio_p, false);
diff --git a/asoc/msm-compress-q6-v2.c b/asoc/msm-compress-q6-v2.c
index 75b217f..4347bec 100644
--- a/asoc/msm-compress-q6-v2.c
+++ b/asoc/msm-compress-q6-v2.c
@@ -10,6 +10,7 @@
#include <linux/time.h>
#include <linux/math64.h>
#include <linux/wait.h>
+#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <sound/core.h>
@@ -106,6 +107,7 @@
struct msm_compr_ch_map *ch_map[MSM_FRONTEND_DAI_MAX];
bool is_in_use[MSM_FRONTEND_DAI_MAX];
struct msm_pcm_channel_mixer *chmixer_pspd[MSM_FRONTEND_DAI_MM_SIZE];
+ struct mutex lock;
};
struct msm_compr_audio {
@@ -978,6 +980,7 @@
struct asm_ape_cfg ape_cfg;
struct asm_dsd_cfg dsd_cfg;
struct aptx_dec_bt_addr_cfg aptx_cfg;
+ struct asm_amrwbplus_cfg amrwbplus_cfg;
union snd_codec_options *codec_options;
int ret = 0;
@@ -1266,6 +1269,26 @@
__func__, ret);
}
break;
+ case FORMAT_AMRNB:
+ pr_debug("SND_AUDIOCODEC_AMR\n");
+ /* no media format block needed */
+ break;
+ case FORMAT_AMRWB:
+ pr_debug("SND_AUDIOCODEC_AMRWB\n");
+ /* no media format block needed */
+ break;
+ case FORMAT_AMR_WB_PLUS:
+ pr_debug("SND_AUDIOCODEC_AMRWBPLUS\n");
+ memset(&amrwbplus_cfg, 0x0, sizeof(struct asm_amrwbplus_cfg));
+ amrwbplus_cfg.amr_frame_fmt =
+ codec_options->amrwbplus.bit_stream_fmt;
+ ret = q6asm_media_format_block_amrwbplus(
+ prtd->audio_client,
+ &amrwbplus_cfg);
+ if (ret < 0)
+ pr_err("%s: CMD AMRWBPLUS Format block failed ret %d\n",
+ __func__, ret);
+ break;
default:
pr_debug("%s, unsupported format, skip", __func__);
break;
@@ -1640,6 +1663,7 @@
struct snd_soc_component *component = NULL;
struct msm_compr_audio *prtd = NULL;
struct msm_compr_pdata *pdata = NULL;
+ enum apr_subsys_state subsys_state;
pr_debug("%s\n", __func__);
component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
@@ -1653,6 +1677,13 @@
__func__, rtd->dai_link->cpu_dai_name, -EBUSY);
return -EBUSY;
}
+
+ subsys_state = apr_get_subsys_state();
+ if (subsys_state == APR_SUBSYS_DOWN) {
+ pr_debug("%s: adsp is down\n", __func__);
+ return -ENETRESET;
+ }
+
prtd = kzalloc(sizeof(struct msm_compr_audio), GFP_KERNEL);
if (prtd == NULL) {
pr_err("Failed to allocate memory for msm_compr_audio\n");
@@ -1747,6 +1778,7 @@
struct snd_soc_component *component = NULL;
struct msm_compr_audio *prtd;
struct msm_compr_pdata *pdata = NULL;
+ enum apr_subsys_state subsys_state;
pr_debug("%s\n", __func__);
component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
@@ -1759,6 +1791,12 @@
pr_err("%s: pdata is NULL\n", __func__);
return -EINVAL;
}
+
+ subsys_state = apr_get_subsys_state();
+ if (subsys_state == APR_SUBSYS_DOWN) {
+ pr_debug("%s: adsp is down\n", __func__);
+ return -ENETRESET;
+ }
prtd = kzalloc(sizeof(struct msm_compr_audio), GFP_KERNEL);
if (!prtd) {
pr_err("Failed to allocate memory for msm_compr_audio\n");
@@ -1905,6 +1943,7 @@
}
spin_unlock_irqrestore(&prtd->lock, flags);
+ mutex_lock(&pdata->lock);
pdata->cstream[soc_prtd->dai_link->id] = NULL;
if (cstream->direction == SND_COMPRESS_PLAYBACK) {
msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
@@ -1926,6 +1965,7 @@
pdata->is_in_use[soc_prtd->dai_link->id] = false;
kfree(prtd);
runtime->private_data = NULL;
+ mutex_unlock(&pdata->lock);
return 0;
}
@@ -1982,6 +2022,7 @@
}
spin_unlock_irqrestore(&prtd->lock, flags);
+ mutex_lock(&pdata->lock);
pdata->cstream[soc_prtd->dai_link->id] = NULL;
msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
SNDRV_PCM_STREAM_CAPTURE);
@@ -1992,6 +2033,7 @@
kfree(prtd);
runtime->private_data = NULL;
+ mutex_unlock(&pdata->lock);
return 0;
}
@@ -2193,6 +2235,24 @@
break;
}
+ case SND_AUDIOCODEC_AMR: {
+ pr_debug("%s:SND_AUDIOCODEC_AMR\n", __func__);
+ prtd->codec = FORMAT_AMRNB;
+ break;
+ }
+
+ case SND_AUDIOCODEC_AMRWB: {
+ pr_debug("%s:SND_AUDIOCODEC_AMRWB\n", __func__);
+ prtd->codec = FORMAT_AMRWB;
+ break;
+ }
+
+ case SND_AUDIOCODEC_AMRWBPLUS: {
+ pr_debug("%s:SND_AUDIOCODEC_AMRWBPLUS\n", __func__);
+ prtd->codec = FORMAT_AMR_WB_PLUS;
+ break;
+ }
+
default:
pr_err("codec not supported, id =%d\n", params->codec.id);
return -EINVAL;
@@ -3267,6 +3327,9 @@
case FORMAT_VORBIS:
case FORMAT_ALAC:
case FORMAT_APE:
+ case FORMAT_AMRNB:
+ case FORMAT_AMRWB:
+ case FORMAT_AMR_WB_PLUS:
memcpy(&(prtd->gapless_state.codec_options),
codec_options,
sizeof(union snd_codec_options));
@@ -3349,6 +3412,7 @@
struct snd_compr_stream *cstream = NULL;
struct msm_compr_audio *prtd = NULL;
long *values = &(ucontrol->value.integer.value[0]);
+ int ret = 0;
int effects_module;
pr_debug("%s\n", __func__);
@@ -3357,21 +3421,25 @@
__func__, fe_id);
return -EINVAL;
}
+
+ mutex_lock(&pdata->lock);
cstream = pdata->cstream[fe_id];
audio_effects = pdata->audio_effects[fe_id];
if (!cstream || !audio_effects) {
pr_err("%s: stream or effects inactive\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
+ goto done;
}
prtd = cstream->runtime->private_data;
if (!prtd) {
pr_err("%s: cannot set audio effects\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
+ goto done;
}
if (prtd->compr_passthr != LEGACY_PCM) {
pr_debug("%s: No effects for compr_type[%d]\n",
__func__, prtd->compr_passthr);
- return 0;
+ goto done;
}
pr_debug("%s: Effects supported for compr_type[%d]\n",
__func__, prtd->compr_passthr);
@@ -3432,9 +3500,11 @@
break;
default:
pr_err("%s Invalid effects config module\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
}
- return 0;
+done:
+ mutex_unlock(&pdata->lock);
+ return ret;
}
static int msm_compr_audio_effects_config_get(struct snd_kcontrol *kcontrol,
@@ -3446,6 +3516,7 @@
snd_soc_component_get_drvdata(comp);
struct msm_compr_audio_effects *audio_effects = NULL;
struct snd_compr_stream *cstream = NULL;
+ int ret = 0;
struct msm_compr_audio *prtd = NULL;
pr_debug("%s\n", __func__);
@@ -3454,19 +3525,23 @@
__func__, fe_id);
return -EINVAL;
}
+
+ mutex_lock(&pdata->lock);
cstream = pdata->cstream[fe_id];
audio_effects = pdata->audio_effects[fe_id];
if (!cstream || !audio_effects) {
pr_debug("%s: stream or effects inactive\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
+ goto done;
}
prtd = cstream->runtime->private_data;
if (!prtd) {
pr_err("%s: cannot set audio effects\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
}
-
- return 0;
+done:
+ mutex_unlock(&pdata->lock);
+ return ret;
}
static int msm_compr_query_audio_effect_put(struct snd_kcontrol *kcontrol,
@@ -3479,6 +3554,7 @@
struct msm_compr_audio_effects *audio_effects = NULL;
struct snd_compr_stream *cstream = NULL;
struct msm_compr_audio *prtd = NULL;
+ int ret = 0;
long *values = &(ucontrol->value.integer.value[0]);
if (fe_id >= MSM_FRONTEND_DAI_MAX) {
@@ -3486,28 +3562,37 @@
__func__, fe_id);
return -EINVAL;
}
+
+ mutex_lock(&pdata->lock);
+
cstream = pdata->cstream[fe_id];
audio_effects = pdata->audio_effects[fe_id];
if (!cstream || !audio_effects) {
pr_err("%s: stream or effects inactive\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
+ goto done;
}
prtd = cstream->runtime->private_data;
if (!prtd) {
pr_err("%s: cannot set audio effects\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
+ goto done;
}
if (prtd->compr_passthr != LEGACY_PCM) {
pr_err("%s: No effects for compr_type[%d]\n",
__func__, prtd->compr_passthr);
- return -EPERM;
+ ret = -EPERM;
+ goto done;
}
audio_effects->query.mod_id = (u32)*values++;
audio_effects->query.parm_id = (u32)*values++;
audio_effects->query.size = (u32)*values++;
audio_effects->query.offset = (u32)*values++;
audio_effects->query.device = (u32)*values++;
- return 0;
+
+done:
+ mutex_unlock(&pdata->lock);
+ return ret;
}
static int msm_compr_query_audio_effect_get(struct snd_kcontrol *kcontrol,
@@ -3520,6 +3605,7 @@
struct msm_compr_audio_effects *audio_effects = NULL;
struct snd_compr_stream *cstream = NULL;
struct msm_compr_audio *prtd = NULL;
+ int ret = 0;
long *values = &(ucontrol->value.integer.value[0]);
if (fe_id >= MSM_FRONTEND_DAI_MAX) {
@@ -3527,23 +3613,29 @@
__func__, fe_id);
return -EINVAL;
}
+
+ mutex_lock(&pdata->lock);
cstream = pdata->cstream[fe_id];
audio_effects = pdata->audio_effects[fe_id];
if (!cstream || !audio_effects) {
pr_debug("%s: stream or effects inactive\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
+ goto done;
}
prtd = cstream->runtime->private_data;
if (!prtd) {
pr_err("%s: cannot set audio effects\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
+ goto done;
}
values[0] = (long)audio_effects->query.mod_id;
values[1] = (long)audio_effects->query.parm_id;
values[2] = (long)audio_effects->query.size;
values[3] = (long)audio_effects->query.offset;
values[4] = (long)audio_effects->query.device;
- return 0;
+done:
+ mutex_unlock(&pdata->lock);
+ return ret;
}
static int msm_compr_send_dec_params(struct snd_compr_stream *cstream,
@@ -3629,6 +3721,7 @@
goto end;
}
+ mutex_lock(&pdata->lock);
switch (prtd->codec) {
case FORMAT_MP3:
case FORMAT_MPEG4_AAC:
@@ -3641,6 +3734,9 @@
case FORMAT_TRUEHD:
case FORMAT_IEC61937:
case FORMAT_APTX:
+ case FORMAT_AMRNB:
+ case FORMAT_AMRWB:
+ case FORMAT_AMR_WB_PLUS:
pr_debug("%s: no runtime parameters for codec: %d\n", __func__,
prtd->codec);
break;
@@ -3677,6 +3773,7 @@
}
end:
pr_debug("%s: ret %d\n", __func__, rc);
+ mutex_unlock(&pdata->lock);
return rc;
}
@@ -3896,6 +3993,7 @@
goto done;
}
+ mutex_lock(&pdata->lock);
if (prtd->audio_client == NULL) {
pr_err("%s: audio_client is null\n", __func__);
ret = -EINVAL;
@@ -3924,6 +4022,7 @@
pr_err("%s: failed to send stream event cmd, err = %d\n",
__func__, ret);
done:
+ mutex_unlock(&pdata->lock);
return ret;
}
@@ -3960,6 +4059,7 @@
goto done;
}
+ mutex_lock(&pdata->lock);
if (prtd->audio_client == NULL) {
pr_err("%s: audio_client is null\n", __func__);
ret = -EINVAL;
@@ -3971,6 +4071,7 @@
if (ret < 0)
pr_err("%s: failed to register ion fd\n", __func__);
done:
+ mutex_unlock(&pdata->lock);
return ret;
}
@@ -3993,6 +4094,7 @@
goto done;
}
+ mutex_lock(&pdata->lock);
cstream = pdata->cstream[fe_id];
if (cstream == NULL) {
pr_err("%s cstream is null\n", __func__);
@@ -4030,6 +4132,7 @@
pr_err("%s: failed to send rtic event ack, err = %d\n",
__func__, ret);
done:
+ mutex_unlock(&pdata->lock);
return ret;
}
@@ -5409,6 +5512,7 @@
kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
+ mutex_init(&pdata->lock);
dev_set_drvdata(&pdev->dev, pdata);
return snd_soc_register_component(&pdev->dev,
@@ -5425,6 +5529,7 @@
for (i = 0; i < MSM_FRONTEND_DAI_MM_SIZE; i++)
kfree(pdata->chmixer_pspd[i]);
}
+ mutex_destroy(&pdata->lock);
kfree(pdata);
snd_soc_unregister_component(&pdev->dev);
diff --git a/asoc/msm-dai-q6-v2.c b/asoc/msm-dai-q6-v2.c
index c6f61e4..1b15444 100644
--- a/asoc/msm-dai-q6-v2.c
+++ b/asoc/msm-dai-q6-v2.c
@@ -35,6 +35,9 @@
#define CHANNEL_STATUS_SIZE 24
#define CHANNEL_STATUS_MASK_INIT 0x0
#define CHANNEL_STATUS_MASK 0x4
+#define PREEMPH_MASK 0x38
+#define PREEMPH_SHIFT 3
+#define GET_PREEMPH(b) ((b & PREEMPH_MASK) >> PREEMPH_SHIFT)
#define AFE_API_VERSION_CLOCK_SET 1
#define MSM_DAI_SYSFS_ENTRY_MAX_LEN 64
@@ -261,6 +264,17 @@
struct msm_dai_q6_mi2s_dai_config rx_dai;
};
+struct msm_dai_q6_meta_mi2s_dai_data {
+ DECLARE_BITMAP(status_mask, STATUS_MAX);
+ u16 num_member_ports;
+ u16 member_port_id[MAX_NUM_I2S_META_PORT_MEMBER_PORTS];
+ u16 channel_mode[MAX_NUM_I2S_META_PORT_MEMBER_PORTS];
+ u32 rate;
+ u32 channels;
+ u32 bitwidth;
+ union afe_port_config port_config;
+};
+
struct msm_dai_q6_cdc_dma_dai_data {
DECLARE_BITMAP(status_mask, STATUS_MAX);
DECLARE_BITMAP(hwfree_status, STATUS_MAX);
@@ -268,6 +282,7 @@
u32 channels;
u32 bitwidth;
u32 is_island_dai;
+ u32 xt_logging_disable;
union afe_port_config port_config;
};
@@ -1728,22 +1743,41 @@
{
struct msm_dai_q6_spdif_event_msg *evt;
struct msm_dai_q6_spdif_dai_data *dai_data;
+ int preemph_old = 0;
+ int preemph_new = 0;
evt = (struct msm_dai_q6_spdif_event_msg *)payload;
dai_data = (struct msm_dai_q6_spdif_dai_data *)private_data;
- pr_debug("%s: old state %d, fmt %d, rate %d\n",
+ preemph_old = GET_PREEMPH(dai_data->fmt_event.channel_status[0]);
+ preemph_new = GET_PREEMPH(evt->fmt_event.channel_status[0]);
+
+ pr_debug("%s: old state %d, fmt %d, rate %d, preemph %d\n",
__func__, dai_data->fmt_event.status,
dai_data->fmt_event.data_format,
- dai_data->fmt_event.sample_rate);
- pr_debug("%s: new state %d, fmt %d, rate %d\n",
+ dai_data->fmt_event.sample_rate,
+ preemph_old);
+ pr_debug("%s: new state %d, fmt %d, rate %d, preemph %d\n",
__func__, evt->fmt_event.status,
evt->fmt_event.data_format,
- evt->fmt_event.sample_rate);
+ evt->fmt_event.sample_rate,
+ preemph_new);
dai_data->fmt_event.status = evt->fmt_event.status;
dai_data->fmt_event.data_format = evt->fmt_event.data_format;
dai_data->fmt_event.sample_rate = evt->fmt_event.sample_rate;
+ dai_data->fmt_event.channel_status[0] =
+ evt->fmt_event.channel_status[0];
+ dai_data->fmt_event.channel_status[1] =
+ evt->fmt_event.channel_status[1];
+ dai_data->fmt_event.channel_status[2] =
+ evt->fmt_event.channel_status[2];
+ dai_data->fmt_event.channel_status[3] =
+ evt->fmt_event.channel_status[3];
+ dai_data->fmt_event.channel_status[4] =
+ evt->fmt_event.channel_status[4];
+ dai_data->fmt_event.channel_status[5] =
+ evt->fmt_event.channel_status[5];
}
static int msm_dai_q6_spdif_hw_params(struct snd_pcm_substream *substream,
@@ -1887,17 +1921,40 @@
return ret;
}
+static ssize_t msm_dai_q6_spdif_sysfs_rda_audio_preemph(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret;
+ struct msm_dai_q6_spdif_dai_data *dai_data = dev_get_drvdata(dev);
+ int preemph = 0;
+
+ if (!dai_data) {
+ pr_err("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ preemph = GET_PREEMPH(dai_data->fmt_event.channel_status[0]);
+
+ ret = snprintf(buf, MSM_DAI_SYSFS_ENTRY_MAX_LEN, "%d\n", preemph);
+ pr_debug("%s: '%d'\n", __func__, preemph);
+
+ return ret;
+}
+
static DEVICE_ATTR(audio_state, 0444, msm_dai_q6_spdif_sysfs_rda_audio_state,
NULL);
static DEVICE_ATTR(audio_format, 0444, msm_dai_q6_spdif_sysfs_rda_audio_format,
NULL);
static DEVICE_ATTR(audio_rate, 0444, msm_dai_q6_spdif_sysfs_rda_audio_rate,
NULL);
+static DEVICE_ATTR(audio_preemph, 0444,
+ msm_dai_q6_spdif_sysfs_rda_audio_preemph, NULL);
static struct attribute *msm_dai_q6_spdif_fs_attrs[] = {
&dev_attr_audio_state.attr,
&dev_attr_audio_format.attr,
&dev_attr_audio_rate.attr,
+ &dev_attr_audio_preemph.attr,
NULL,
};
static struct attribute_group msm_dai_q6_spdif_fs_attrs_group = {
@@ -2788,24 +2845,54 @@
return 0;
}
-static int msm_dai_q6_xt_logging_disable_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int msm_dai_q6_cdc_dma_xt_logging_disable_put(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
- struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+ struct msm_dai_q6_cdc_dma_dai_data *dai_data = kcontrol->private_data;
- dai_data->xt_logging_disable = ucontrol->value.integer.value[0];
- pr_debug("%s: setting xt logging disable to %d\n",
- __func__, dai_data->xt_logging_disable);
+ if (dai_data) {
+ dai_data->xt_logging_disable = ucontrol->value.integer.value[0];
+ pr_debug("%s: setting xt logging disable to %d\n",
+ __func__, dai_data->xt_logging_disable);
+ }
return 0;
}
-static int msm_dai_q6_xt_logging_disable_get(struct snd_kcontrol *kcontrol,
+static int msm_dai_q6_cdc_dma_xt_logging_disable_get(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_cdc_dma_dai_data *dai_data = kcontrol->private_data;
+
+ if (dai_data)
+ ucontrol->value.integer.value[0] = dai_data->xt_logging_disable;
+ return 0;
+}
+
+static int msm_dai_q6_sb_xt_logging_disable_put(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+
+ if (dai_data) {
+ dai_data->xt_logging_disable = ucontrol->value.integer.value[0];
+ pr_debug("%s: setting xt logging disable to %d\n",
+ __func__, dai_data->xt_logging_disable);
+ }
+
+ return 0;
+}
+
+static int msm_dai_q6_sb_xt_logging_disable_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
- ucontrol->value.integer.value[0] = dai_data->xt_logging_disable;
+ if (dai_data)
+ ucontrol->value.integer.value[0] = dai_data->xt_logging_disable;
return 0;
}
@@ -3670,8 +3757,8 @@
msm_dai_q6_sb_format_get,
msm_dai_q6_sb_format_put),
SOC_ENUM_EXT("SLIM_0_RX XTLoggingDisable", xt_logging_disable_enum[0],
- msm_dai_q6_xt_logging_disable_get,
- msm_dai_q6_xt_logging_disable_put),
+ msm_dai_q6_sb_xt_logging_disable_get,
+ msm_dai_q6_sb_xt_logging_disable_put),
};
static const struct snd_kcontrol_new rt_proxy_config_controls[] = {
@@ -6096,6 +6183,42 @@
return -EINVAL;
}
+static u16 msm_dai_q6_mi2s_get_num_channels(u16 config)
+{
+ switch (config) {
+ case AFE_PORT_I2S_SD0:
+ case AFE_PORT_I2S_SD1:
+ case AFE_PORT_I2S_SD2:
+ case AFE_PORT_I2S_SD3:
+ case AFE_PORT_I2S_SD4:
+ case AFE_PORT_I2S_SD5:
+ case AFE_PORT_I2S_SD6:
+ case AFE_PORT_I2S_SD7:
+ return 2;
+ case AFE_PORT_I2S_QUAD01:
+ case AFE_PORT_I2S_QUAD23:
+ case AFE_PORT_I2S_QUAD45:
+ case AFE_PORT_I2S_QUAD67:
+ return 4;
+ case AFE_PORT_I2S_6CHS:
+ return 6;
+ case AFE_PORT_I2S_8CHS:
+ case AFE_PORT_I2S_8CHS_2:
+ return 8;
+ case AFE_PORT_I2S_10CHS:
+ return 10;
+ case AFE_PORT_I2S_12CHS:
+ return 12;
+ case AFE_PORT_I2S_14CHS:
+ return 14;
+ case AFE_PORT_I2S_16CHS:
+ return 16;
+ default:
+ pr_err("%s: invalid config\n", __func__);
+ return 0;
+ }
+}
+
static int msm_dai_q6_mi2s_platform_data_validation(
struct platform_device *pdev, struct snd_soc_dai_driver *dai_driver)
{
@@ -6261,6 +6384,657 @@
return 0;
}
+static int msm_dai_q6_dai_meta_mi2s_probe(struct snd_soc_dai *dai)
+{
+ struct msm_meta_mi2s_pdata *meta_mi2s_pdata =
+ (struct msm_meta_mi2s_pdata *) dai->dev->platform_data;
+ int rc = 0;
+
+ dai->id = meta_mi2s_pdata->intf_id;
+ rc = msm_dai_q6_dai_add_route(dai);
+ return rc;
+}
+
+static int msm_dai_q6_dai_meta_mi2s_remove(struct snd_soc_dai *dai)
+{
+ return 0;
+}
+
+static int msm_dai_q6_meta_mi2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ return 0;
+}
+
+static int msm_meta_mi2s_get_port_id(u32 mi2s_id, int stream, u16 *port_id)
+{
+ int ret = 0;
+
+ switch (stream) {
+ case SNDRV_PCM_STREAM_PLAYBACK:
+ switch (mi2s_id) {
+ case MSM_PRIM_META_MI2S:
+ *port_id = AFE_PORT_ID_PRIMARY_META_MI2S_RX;
+ break;
+ case MSM_SEC_META_MI2S:
+ *port_id = AFE_PORT_ID_SECONDARY_META_MI2S_RX;
+ break;
+ default:
+ pr_err("%s: playback err id 0x%x\n",
+ __func__, mi2s_id);
+ ret = -1;
+ break;
+ }
+ break;
+
+ case SNDRV_PCM_STREAM_CAPTURE:
+ switch (mi2s_id) {
+ default:
+ pr_err("%s: capture err id 0x%x\n", __func__, mi2s_id);
+ ret = -1;
+ break;
+ }
+ break;
+
+ default:
+ pr_err("%s: default err %d\n", __func__, stream);
+ ret = -1;
+ break;
+ }
+ pr_debug("%s: port_id = 0x%x\n", __func__, *port_id);
+ return ret;
+}
+
+static int msm_dai_q6_meta_mi2s_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_meta_mi2s_dai_data *dai_data =
+ dev_get_drvdata(dai->dev);
+ u16 port_id = 0;
+ int rc = 0;
+
+ if (msm_meta_mi2s_get_port_id(dai->id, substream->stream,
+ &port_id) != 0) {
+ dev_err(dai->dev, "%s: Invalid Port ID 0x%x\n",
+ __func__, port_id);
+ return -EINVAL;
+ }
+
+ dev_dbg(dai->dev, "%s: dai id %d, afe port id = 0x%x\n"
+ "dai_data->channels = %u sample_rate = %u\n", __func__,
+ dai->id, port_id, dai_data->channels, dai_data->rate);
+
+ if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ /* PORT START should be set if prepare called
+ * in active state.
+ */
+ rc = afe_port_start(port_id, &dai_data->port_config,
+ dai_data->rate);
+ if (rc < 0)
+ dev_err(dai->dev, "fail to open AFE port 0x%x\n",
+ dai->id);
+ else
+ set_bit(STATUS_PORT_STARTED,
+ dai_data->status_mask);
+ }
+
+ return rc;
+}
+
+static int msm_dai_q6_meta_mi2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_meta_mi2s_dai_data *dai_data =
+ dev_get_drvdata(dai->dev);
+ struct afe_param_id_meta_i2s_cfg *port_cfg =
+ &dai_data->port_config.meta_i2s;
+ int idx = 0;
+ u16 port_channels = 0;
+ u16 channels_left = 0;
+
+ dai_data->channels = params_channels(params);
+ channels_left = dai_data->channels;
+
+ /* map requested channels to channels that member ports provide */
+ for (idx = 0; idx < dai_data->num_member_ports; idx++) {
+ port_channels = msm_dai_q6_mi2s_get_num_channels(
+ dai_data->channel_mode[idx]);
+
+ if (channels_left >= port_channels) {
+ port_cfg->member_port_id[idx] =
+ dai_data->member_port_id[idx];
+ port_cfg->member_port_channel_mode[idx] =
+ dai_data->channel_mode[idx];
+ channels_left -= port_channels;
+ } else {
+ switch (channels_left) {
+ case 15:
+ case 16:
+ switch (dai_data->channel_mode[idx]) {
+ case AFE_PORT_I2S_16CHS:
+ port_cfg->member_port_channel_mode[idx]
+ = AFE_PORT_I2S_16CHS;
+ break;
+ default:
+ goto error_invalid_data;
+ };
+ break;
+ case 13:
+ case 14:
+ switch (dai_data->channel_mode[idx]) {
+ case AFE_PORT_I2S_14CHS:
+ case AFE_PORT_I2S_16CHS:
+ port_cfg->member_port_channel_mode[idx]
+ = AFE_PORT_I2S_14CHS;
+ break;
+ default:
+ goto error_invalid_data;
+ };
+ break;
+ case 11:
+ case 12:
+ switch (dai_data->channel_mode[idx]) {
+ case AFE_PORT_I2S_12CHS:
+ case AFE_PORT_I2S_14CHS:
+ case AFE_PORT_I2S_16CHS:
+ port_cfg->member_port_channel_mode[idx]
+ = AFE_PORT_I2S_12CHS;
+ break;
+ default:
+ goto error_invalid_data;
+ };
+ break;
+ case 9:
+ case 10:
+ switch (dai_data->channel_mode[idx]) {
+ case AFE_PORT_I2S_10CHS:
+ case AFE_PORT_I2S_12CHS:
+ case AFE_PORT_I2S_14CHS:
+ case AFE_PORT_I2S_16CHS:
+ port_cfg->member_port_channel_mode[idx]
+ = AFE_PORT_I2S_10CHS;
+ break;
+ default:
+ goto error_invalid_data;
+ };
+ break;
+ case 8:
+ case 7:
+ switch (dai_data->channel_mode[idx]) {
+ case AFE_PORT_I2S_8CHS:
+ case AFE_PORT_I2S_10CHS:
+ case AFE_PORT_I2S_12CHS:
+ case AFE_PORT_I2S_14CHS:
+ case AFE_PORT_I2S_16CHS:
+ port_cfg->member_port_channel_mode[idx]
+ = AFE_PORT_I2S_8CHS;
+ break;
+ case AFE_PORT_I2S_8CHS_2:
+ port_cfg->member_port_channel_mode[idx]
+ = AFE_PORT_I2S_8CHS_2;
+ break;
+ default:
+ goto error_invalid_data;
+ };
+ break;
+ case 6:
+ case 5:
+ switch (dai_data->channel_mode[idx]) {
+ case AFE_PORT_I2S_6CHS:
+ case AFE_PORT_I2S_8CHS:
+ case AFE_PORT_I2S_10CHS:
+ case AFE_PORT_I2S_12CHS:
+ case AFE_PORT_I2S_14CHS:
+ case AFE_PORT_I2S_16CHS:
+ port_cfg->member_port_channel_mode[idx]
+ = AFE_PORT_I2S_6CHS;
+ break;
+ default:
+ goto error_invalid_data;
+ };
+ break;
+ case 4:
+ case 3:
+ switch (dai_data->channel_mode[idx]) {
+ case AFE_PORT_I2S_SD0:
+ case AFE_PORT_I2S_SD1:
+ case AFE_PORT_I2S_SD2:
+ case AFE_PORT_I2S_SD3:
+ case AFE_PORT_I2S_SD4:
+ case AFE_PORT_I2S_SD5:
+ case AFE_PORT_I2S_SD6:
+ case AFE_PORT_I2S_SD7:
+ goto error_invalid_data;
+ case AFE_PORT_I2S_QUAD01:
+ case AFE_PORT_I2S_QUAD23:
+ case AFE_PORT_I2S_QUAD45:
+ case AFE_PORT_I2S_QUAD67:
+ port_cfg->member_port_channel_mode[idx]
+ = dai_data->channel_mode[idx];
+ break;
+ case AFE_PORT_I2S_8CHS_2:
+ port_cfg->member_port_channel_mode[idx]
+ = AFE_PORT_I2S_QUAD45;
+ break;
+ default:
+ port_cfg->member_port_channel_mode[idx]
+ = AFE_PORT_I2S_QUAD01;
+ };
+ break;
+ case 2:
+ case 1:
+ if (dai_data->channel_mode[idx] <
+ AFE_PORT_I2S_SD0)
+ goto error_invalid_data;
+ switch (dai_data->channel_mode[idx]) {
+ case AFE_PORT_I2S_SD0:
+ case AFE_PORT_I2S_SD1:
+ case AFE_PORT_I2S_SD2:
+ case AFE_PORT_I2S_SD3:
+ case AFE_PORT_I2S_SD4:
+ case AFE_PORT_I2S_SD5:
+ case AFE_PORT_I2S_SD6:
+ case AFE_PORT_I2S_SD7:
+ port_cfg->member_port_channel_mode[idx]
+ = dai_data->channel_mode[idx];
+ break;
+ case AFE_PORT_I2S_QUAD01:
+ case AFE_PORT_I2S_6CHS:
+ case AFE_PORT_I2S_8CHS:
+ case AFE_PORT_I2S_10CHS:
+ case AFE_PORT_I2S_12CHS:
+ case AFE_PORT_I2S_14CHS:
+ case AFE_PORT_I2S_16CHS:
+ port_cfg->member_port_channel_mode[idx]
+ = AFE_PORT_I2S_SD0;
+ break;
+ case AFE_PORT_I2S_QUAD23:
+ port_cfg->member_port_channel_mode[idx]
+ = AFE_PORT_I2S_SD2;
+ break;
+ case AFE_PORT_I2S_QUAD45:
+ case AFE_PORT_I2S_8CHS_2:
+ port_cfg->member_port_channel_mode[idx]
+ = AFE_PORT_I2S_SD4;
+ break;
+ case AFE_PORT_I2S_QUAD67:
+ port_cfg->member_port_channel_mode[idx]
+ = AFE_PORT_I2S_SD6;
+ break;
+ }
+ break;
+ case 0:
+ port_cfg->member_port_channel_mode[idx] = 0;
+ }
+ if (port_cfg->member_port_channel_mode[idx] == 0) {
+ port_cfg->member_port_id[idx] =
+ AFE_PORT_ID_INVALID;
+ } else {
+ port_cfg->member_port_id[idx] =
+ dai_data->member_port_id[idx];
+ channels_left -=
+ msm_dai_q6_mi2s_get_num_channels(
+ port_cfg->member_port_channel_mode[idx]);
+ }
+ }
+ }
+
+ if (channels_left > 0) {
+ pr_err("%s: too many channels %d\n",
+ __func__, dai_data->channels);
+ return -EINVAL;
+ }
+
+ dai_data->rate = params_rate(params);
+ port_cfg->sample_rate = dai_data->rate;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ case SNDRV_PCM_FORMAT_SPECIAL:
+ port_cfg->bit_width = 16;
+ dai_data->bitwidth = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ port_cfg->bit_width = 24;
+ dai_data->bitwidth = 24;
+ break;
+ default:
+ pr_err("%s: format %d\n",
+ __func__, params_format(params));
+ return -EINVAL;
+ }
+
+ port_cfg->minor_version = AFE_API_VERSION_META_I2S_CONFIG;
+ port_cfg->data_format = AFE_LINEAR_PCM_DATA;
+
+ dev_dbg(dai->dev, "%s: dai id %d dai_data->channels = %d\n"
+ "bit_width = %hu ws_src = 0x%x sample_rate = %u\n"
+ "member_ports 0x%x 0x%x 0x%x 0x%x\n"
+ "sd_lines 0x%x 0x%x 0x%x 0x%x\n",
+ __func__, dai->id, dai_data->channels,
+ port_cfg->bit_width, port_cfg->ws_src, port_cfg->sample_rate,
+ port_cfg->member_port_id[0],
+ port_cfg->member_port_id[1],
+ port_cfg->member_port_id[2],
+ port_cfg->member_port_id[3],
+ port_cfg->member_port_channel_mode[0],
+ port_cfg->member_port_channel_mode[1],
+ port_cfg->member_port_channel_mode[2],
+ port_cfg->member_port_channel_mode[3]);
+ return 0;
+
+error_invalid_data:
+ pr_err("%s: error when assigning member port %d channels (channels_left %d)\n",
+ __func__, idx, channels_left);
+ return -EINVAL;
+}
+
+static int msm_dai_q6_meta_mi2s_set_fmt(struct snd_soc_dai *dai,
+ unsigned int fmt)
+{
+ struct msm_dai_q6_meta_mi2s_dai_data *dai_data =
+ dev_get_drvdata(dai->dev);
+
+ if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ dev_err(dai->dev, "%s: err chg meta i2s mode while dai running",
+ __func__);
+ return -EPERM;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ dai_data->port_config.meta_i2s.ws_src = 1;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ dai_data->port_config.meta_i2s.ws_src = 0;
+ break;
+ default:
+ pr_err("%s: fmt %d\n",
+ __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void msm_dai_q6_meta_mi2s_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_meta_mi2s_dai_data *dai_data =
+ dev_get_drvdata(dai->dev);
+ u16 port_id = 0;
+ int rc = 0;
+
+ if (msm_meta_mi2s_get_port_id(dai->id, substream->stream,
+ &port_id) != 0) {
+ dev_err(dai->dev, "%s: Invalid Port ID 0x%x\n",
+ __func__, port_id);
+ }
+
+ dev_dbg(dai->dev, "%s: closing afe port id = 0x%x\n",
+ __func__, port_id);
+
+ if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ rc = afe_close(port_id);
+ if (rc < 0)
+ dev_err(dai->dev, "fail to close AFE port\n");
+ clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
+ }
+}
+
+static struct snd_soc_dai_ops msm_dai_q6_meta_mi2s_ops = {
+ .startup = msm_dai_q6_meta_mi2s_startup,
+ .prepare = msm_dai_q6_meta_mi2s_prepare,
+ .hw_params = msm_dai_q6_meta_mi2s_hw_params,
+ .set_fmt = msm_dai_q6_meta_mi2s_set_fmt,
+ .shutdown = msm_dai_q6_meta_mi2s_shutdown,
+};
+
+/* Channel min and max are initialized base on platform data */
+static struct snd_soc_dai_driver msm_dai_q6_meta_mi2s_dai[] = {
+ {
+ .playback = {
+ .stream_name = "Primary META MI2S Playback",
+ .aif_name = "PRI_META_MI2S_RX",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_352800 |
+ SNDRV_PCM_RATE_384000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .ops = &msm_dai_q6_meta_mi2s_ops,
+ .name = "Primary META MI2S",
+ .id = AFE_PORT_ID_PRIMARY_META_MI2S_RX,
+ .probe = msm_dai_q6_dai_meta_mi2s_probe,
+ .remove = msm_dai_q6_dai_meta_mi2s_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "Secondary META MI2S Playback",
+ .aif_name = "SEC_META_MI2S_RX",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .ops = &msm_dai_q6_meta_mi2s_ops,
+ .name = "Secondary META MI2S",
+ .id = AFE_PORT_ID_SECONDARY_META_MI2S_RX,
+ .probe = msm_dai_q6_dai_meta_mi2s_probe,
+ .remove = msm_dai_q6_dai_meta_mi2s_remove,
+ },
+};
+
+static int msm_dai_q6_meta_mi2s_platform_data_validation(
+ struct platform_device *pdev, struct snd_soc_dai_driver *dai_driver)
+{
+ struct msm_dai_q6_meta_mi2s_dai_data *dai_data =
+ dev_get_drvdata(&pdev->dev);
+ struct msm_meta_mi2s_pdata *meta_mi2s_pdata =
+ (struct msm_meta_mi2s_pdata *) pdev->dev.platform_data;
+ int rc = 0;
+ int idx = 0;
+ u16 channel_mode = 0;
+ unsigned int ch_cnt = 0;
+ unsigned int ch_cnt_sum = 0;
+ struct afe_param_id_meta_i2s_cfg *port_cfg =
+ &dai_data->port_config.meta_i2s;
+
+ if (meta_mi2s_pdata == NULL) {
+ pr_err("%s: meta_mi2s_pdata NULL", __func__);
+ return -EINVAL;
+ }
+
+ dai_data->num_member_ports = meta_mi2s_pdata->num_member_ports;
+ for (idx = 0; idx < meta_mi2s_pdata->num_member_ports; idx++) {
+ rc = msm_dai_q6_mi2s_get_lineconfig(
+ meta_mi2s_pdata->sd_lines[idx],
+ &channel_mode,
+ &ch_cnt);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "invalid META MI2S RX sd line config\n");
+ goto rtn;
+ }
+ if (ch_cnt) {
+ msm_mi2s_get_port_id(meta_mi2s_pdata->member_port[idx],
+ SNDRV_PCM_STREAM_PLAYBACK,
+ &dai_data->member_port_id[idx]);
+ dai_data->channel_mode[idx] = channel_mode;
+ port_cfg->member_port_id[idx] =
+ dai_data->member_port_id[idx];
+ port_cfg->member_port_channel_mode[idx] = channel_mode;
+ }
+ ch_cnt_sum += ch_cnt;
+ }
+
+ if (ch_cnt_sum) {
+ dai_driver->playback.channels_min = 1;
+ dai_driver->playback.channels_max = ch_cnt_sum << 1;
+ } else {
+ dai_driver->playback.channels_min = 0;
+ dai_driver->playback.channels_max = 0;
+ }
+
+ dev_dbg(&pdev->dev, "%s: sdline 0x%x 0x%x 0x%x 0x%x\n", __func__,
+ dai_data->channel_mode[0], dai_data->channel_mode[1],
+ dai_data->channel_mode[2], dai_data->channel_mode[3]);
+ dev_dbg(&pdev->dev, "%s: playback ch_max %d\n",
+ __func__, dai_driver->playback.channels_max);
+rtn:
+ return rc;
+}
+
+static const struct snd_soc_component_driver msm_q6_meta_mi2s_dai_component = {
+ .name = "msm-dai-q6-meta-mi2s",
+};
+
+static int msm_dai_q6_meta_mi2s_dev_probe(struct platform_device *pdev)
+{
+ struct msm_dai_q6_meta_mi2s_dai_data *dai_data;
+ const char *q6_meta_mi2s_dev_id = "qcom,msm-dai-q6-meta-mi2s-dev-id";
+ u32 dev_id = 0;
+ u32 meta_mi2s_intf = 0;
+ struct msm_meta_mi2s_pdata *meta_mi2s_pdata;
+ int rc;
+
+ rc = of_property_read_u32(pdev->dev.of_node, q6_meta_mi2s_dev_id,
+ &dev_id);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "%s: missing %s in dt node\n", __func__,
+ q6_meta_mi2s_dev_id);
+ goto rtn;
+ }
+
+ dev_dbg(&pdev->dev, "dev name %s dev id 0x%x\n", dev_name(&pdev->dev),
+ dev_id);
+
+ switch (dev_id) {
+ case AFE_PORT_ID_PRIMARY_META_MI2S_RX:
+ meta_mi2s_intf = 0;
+ break;
+ case AFE_PORT_ID_SECONDARY_META_MI2S_RX:
+ meta_mi2s_intf = 1;
+ break;
+ default:
+ dev_err(&pdev->dev,
+ "%s: Invalid META MI2S ID 0x%x from Device Tree\n",
+ __func__, dev_id);
+ rc = -ENXIO;
+ goto rtn;
+ }
+
+ pdev->id = dev_id;
+
+ meta_mi2s_pdata = kzalloc(sizeof(struct msm_meta_mi2s_pdata),
+ GFP_KERNEL);
+ if (!meta_mi2s_pdata) {
+ rc = -ENOMEM;
+ goto rtn;
+ }
+
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,msm-mi2s-num-members",
+ &meta_mi2s_pdata->num_member_ports);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: invalid num from DT file %s\n",
+ __func__, "qcom,msm-mi2s-num-members");
+ goto free_pdata;
+ }
+
+ if (meta_mi2s_pdata->num_member_ports >
+ MAX_NUM_I2S_META_PORT_MEMBER_PORTS) {
+ dev_err(&pdev->dev, "%s: num-members %d too large from DT file\n",
+ __func__, meta_mi2s_pdata->num_member_ports);
+ goto free_pdata;
+ }
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-mi2s-member-id",
+ meta_mi2s_pdata->member_port,
+ meta_mi2s_pdata->num_member_ports);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: member-id from DT file %s\n",
+ __func__, "qcom,msm-mi2s-member-id");
+ goto free_pdata;
+ }
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-mi2s-rx-lines",
+ meta_mi2s_pdata->sd_lines,
+ meta_mi2s_pdata->num_member_ports);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: Rx line from DT file %s\n",
+ __func__, "qcom,msm-mi2s-rx-lines");
+ goto free_pdata;
+ }
+
+ dev_dbg(&pdev->dev, "dev name %s num-members=%d\n",
+ dev_name(&pdev->dev), meta_mi2s_pdata->num_member_ports);
+ dev_dbg(&pdev->dev, "member array (%d, %d, %d, %d)\n",
+ meta_mi2s_pdata->member_port[0],
+ meta_mi2s_pdata->member_port[1],
+ meta_mi2s_pdata->member_port[2],
+ meta_mi2s_pdata->member_port[3]);
+ dev_dbg(&pdev->dev, "sd-lines array (0x%x, 0x%x, 0x%x, 0x%x)\n",
+ meta_mi2s_pdata->sd_lines[0],
+ meta_mi2s_pdata->sd_lines[1],
+ meta_mi2s_pdata->sd_lines[2],
+ meta_mi2s_pdata->sd_lines[3]);
+
+ meta_mi2s_pdata->intf_id = meta_mi2s_intf;
+
+ dai_data = kzalloc(sizeof(struct msm_dai_q6_meta_mi2s_dai_data),
+ GFP_KERNEL);
+ if (!dai_data) {
+ rc = -ENOMEM;
+ goto free_pdata;
+ } else
+ dev_set_drvdata(&pdev->dev, dai_data);
+
+ pdev->dev.platform_data = meta_mi2s_pdata;
+
+ rc = msm_dai_q6_meta_mi2s_platform_data_validation(pdev,
+ &msm_dai_q6_meta_mi2s_dai[meta_mi2s_intf]);
+ if (rc < 0)
+ goto free_dai_data;
+
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_q6_meta_mi2s_dai_component,
+ &msm_dai_q6_meta_mi2s_dai[meta_mi2s_intf], 1);
+ if (rc < 0)
+ goto err_register;
+ return 0;
+
+err_register:
+ dev_err(&pdev->dev, "fail to %s\n", __func__);
+free_dai_data:
+ kfree(dai_data);
+free_pdata:
+ kfree(meta_mi2s_pdata);
+rtn:
+ return rc;
+}
+
+static int msm_dai_q6_meta_mi2s_dev_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_component(&pdev->dev);
+ return 0;
+}
+
static const struct snd_soc_component_driver msm_dai_q6_component = {
.name = "msm-dai-q6-dev",
};
@@ -6627,6 +7401,24 @@
},
};
+static const struct of_device_id msm_dai_q6_meta_mi2s_dev_dt_match[] = {
+ { .compatible = "qcom,msm-dai-q6-meta-mi2s", },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, msm_dai_q6_meta_mi2s_dev_dt_match);
+
+static struct platform_driver msm_dai_q6_meta_mi2s_driver = {
+ .probe = msm_dai_q6_meta_mi2s_dev_probe,
+ .remove = msm_dai_q6_meta_mi2s_dev_remove,
+ .driver = {
+ .name = "msm-dai-q6-meta-mi2s",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_dai_q6_meta_mi2s_dev_dt_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
static int msm_dai_q6_spdif_dev_probe(struct platform_device *pdev)
{
int rc, id;
@@ -8540,6 +9332,42 @@
return rc;
}
+static unsigned int tdm_param_set_slot_mask(u16 *slot_offset, int slot_width,
+ int slots_per_frame)
+{
+ unsigned int i = 0;
+ unsigned int slot_index = 0;
+ unsigned long slot_mask = 0;
+ unsigned int slot_width_bytes = slot_width / 8;
+ unsigned int channel_count = AFE_PORT_MAX_AUDIO_CHAN_CNT;
+
+ if (q6core_get_avcs_api_version_per_service(
+ APRV2_IDS_SERVICE_ID_ADSP_AFE_V) >= AFE_API_VERSION_V3)
+ channel_count = AFE_PORT_MAX_AUDIO_CHAN_CNT_V2;
+
+ if (slot_width_bytes == 0) {
+ pr_err("%s: slot width is zero\n", __func__);
+ return slot_mask;
+ }
+
+ for (i = 0; i < channel_count; i++) {
+ if (slot_offset[i] != AFE_SLOT_MAPPING_OFFSET_INVALID) {
+ slot_index = slot_offset[i] / slot_width_bytes;
+ if (slot_index < slots_per_frame)
+ set_bit(slot_index, &slot_mask);
+ else {
+ pr_err("%s: invalid slot map setting\n",
+ __func__);
+ return 0;
+ }
+ } else {
+ break;
+ }
+ }
+
+ return slot_mask;
+}
+
static int msm_dai_q6_tdm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -8644,7 +9472,16 @@
*/
tdm->nslots_per_frame = tdm_group->nslots_per_frame;
tdm->slot_width = tdm_group->slot_width;
- tdm->slot_mask = tdm_group->slot_mask;
+ if (q6core_get_avcs_api_version_per_service(
+ APRV2_IDS_SERVICE_ID_ADSP_AFE_V) >= AFE_API_VERSION_V3)
+ tdm->slot_mask = tdm_param_set_slot_mask(
+ slot_mapping_v2->offset,
+ tdm_group->slot_width,
+ tdm_group->nslots_per_frame);
+ else
+ tdm->slot_mask = tdm_param_set_slot_mask(slot_mapping->offset,
+ tdm_group->slot_width,
+ tdm_group->nslots_per_frame);
pr_debug("%s: TDM:\n"
"num_channels=%d sample_rate=%d bit_width=%d\n"
@@ -11234,8 +12071,8 @@
msm_dai_q6_cdc_dma_format_put),
SOC_ENUM_EXT("WSA_CDC_DMA_0 RX XTLoggingDisable",
xt_logging_disable_enum[0],
- msm_dai_q6_xt_logging_disable_get,
- msm_dai_q6_xt_logging_disable_put),
+ msm_dai_q6_cdc_dma_xt_logging_disable_get,
+ msm_dai_q6_cdc_dma_xt_logging_disable_put),
};
/* SOC probe for codec DMA interface */
@@ -12175,6 +13012,13 @@
goto dai_q6_mi2s_drv_fail;
}
+ rc = platform_driver_register(&msm_dai_q6_meta_mi2s_driver);
+ if (rc) {
+ pr_err("%s: fail to register dai META MI2S dev drv\n",
+ __func__);
+ goto dai_q6_meta_mi2s_drv_fail;
+ }
+
rc = platform_driver_register(&msm_dai_mi2s_q6);
if (rc) {
pr_err("%s: fail to register dai MI2S\n", __func__);
@@ -12224,6 +13068,8 @@
dai_spdif_q6_fail:
platform_driver_unregister(&msm_dai_mi2s_q6);
dai_mi2s_q6_fail:
+ platform_driver_unregister(&msm_dai_q6_meta_mi2s_driver);
+dai_q6_meta_mi2s_drv_fail:
platform_driver_unregister(&msm_dai_q6_mi2s_driver);
dai_q6_mi2s_drv_fail:
platform_driver_unregister(&msm_dai_q6_dev);
@@ -12243,6 +13089,7 @@
platform_driver_unregister(&msm_dai_q6_tdm_driver);
platform_driver_unregister(&msm_dai_q6_spdif_driver);
platform_driver_unregister(&msm_dai_mi2s_q6);
+ platform_driver_unregister(&msm_dai_q6_meta_mi2s_driver);
platform_driver_unregister(&msm_dai_q6_mi2s_driver);
platform_driver_unregister(&msm_dai_q6_dev);
platform_driver_unregister(&msm_dai_q6);
diff --git a/asoc/msm-dai-q6-v2.h b/asoc/msm-dai-q6-v2.h
index b65e4e1..3ad049d 100644
--- a/asoc/msm-dai-q6-v2.h
+++ b/asoc/msm-dai-q6-v2.h
@@ -23,8 +23,8 @@
#define MSM_TERT_MI2S 2
#define MSM_QUAT_MI2S 3
#define MSM_QUIN_MI2S 4
-#define MSM_SEC_MI2S_SD1 5
-#define MSM_SENARY_MI2S 6
+#define MSM_SENARY_MI2S 5
+#define MSM_SEC_MI2S_SD1 6
#define MSM_INT0_MI2S 7
#define MSM_INT1_MI2S 8
#define MSM_INT2_MI2S 9
@@ -38,6 +38,11 @@
#define MSM_DISPLAY_PORT 0
#define MSM_DISPLAY_PORT1 1
+#define MSM_PRIM_META_MI2S 0
+#define MSM_SEC_META_MI2S 1
+#define MSM_META_MI2S_MIN MSM_PRIM_META_MI2S
+#define MSM_META_MI2S_MAX MSM_SEC_META_MI2S
+
struct msm_dai_auxpcm_config {
u16 mode;
u16 sync;
@@ -60,6 +65,13 @@
u16 intf_id;
};
+struct msm_meta_mi2s_pdata {
+ u32 num_member_ports;
+ u32 member_port[MAX_NUM_I2S_META_PORT_MEMBER_PORTS];
+ u32 sd_lines[MAX_NUM_I2S_META_PORT_MEMBER_PORTS];
+ u16 intf_id;
+};
+
struct msm_i2s_data {
u32 capability; /* RX or TX */
u16 sd_lines;
diff --git a/asoc/msm-pcm-loopback-v2.c b/asoc/msm-pcm-loopback-v2.c
index 07cf20b..70c94e4 100644
--- a/asoc/msm-pcm-loopback-v2.c
+++ b/asoc/msm-pcm-loopback-v2.c
@@ -252,7 +252,6 @@
struct msm_pcm_loopback *pcm = NULL;
int ret = 0;
uint16_t bits_per_sample = 16;
- struct msm_pcm_routing_evt event;
struct asm_session_mtmx_strtr_param_window_v2_t asm_mtmx_strtr_window;
uint32_t param_id;
struct msm_pcm_pdata *pdata;
@@ -279,10 +278,6 @@
dev_dbg(component->dev, "%s: pcm out open: %d,%d\n", __func__,
pcm->instance, substream->stream);
if (pcm->instance == 2) {
- struct snd_soc_pcm_runtime *soc_pcm_rx =
- pcm->playback_substream->private_data;
- struct snd_soc_pcm_runtime *soc_pcm_tx =
- pcm->capture_substream->private_data;
if (pcm->audio_client != NULL)
stop_pcm(pcm);
@@ -314,15 +309,6 @@
mutex_unlock(&pcm->lock);
return -ENOMEM;
}
- event.event_func = msm_pcm_route_event_handler;
- event.priv_data = (void *) pcm;
- msm_pcm_routing_reg_phy_stream(soc_pcm_tx->dai_link->id,
- pcm->audio_client->perf_mode,
- pcm->session_id, pcm->capture_substream->stream);
- msm_pcm_routing_reg_phy_stream_v2(soc_pcm_rx->dai_link->id,
- pcm->audio_client->perf_mode,
- pcm->session_id, pcm->playback_substream->stream,
- event);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
pcm->playback_substream = substream;
ret = pcm_loopback_set_volume(pcm, pcm->volume);
@@ -442,7 +428,9 @@
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
struct snd_soc_component *component =
snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+ struct msm_pcm_routing_evt event;
+ memset(&event, 0, sizeof(event));
if (!component) {
pr_err("%s: component is NULL\n", __func__);
return -EINVAL;
@@ -452,6 +440,12 @@
dev_dbg(component->dev, "%s: ASM loopback stream:%d\n",
__func__, substream->stream);
+
+ if (pcm->playback_start && pcm->capture_start) {
+ mutex_unlock(&pcm->lock);
+ return ret;
+ }
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (!pcm->playback_start)
pcm->playback_start = 1;
@@ -459,6 +453,23 @@
if (!pcm->capture_start)
pcm->capture_start = 1;
}
+
+ if (pcm->playback_start && pcm->capture_start) {
+ struct snd_soc_pcm_runtime *soc_pcm_rx =
+ pcm->playback_substream->private_data;
+ struct snd_soc_pcm_runtime *soc_pcm_tx =
+ pcm->capture_substream->private_data;
+ event.event_func = msm_pcm_route_event_handler;
+ event.priv_data = (void *) pcm;
+ msm_pcm_routing_reg_phy_stream(soc_pcm_tx->dai_link->id,
+ pcm->audio_client->perf_mode,
+ pcm->session_id, pcm->capture_substream->stream);
+ msm_pcm_routing_reg_phy_stream_v2(soc_pcm_rx->dai_link->id,
+ pcm->audio_client->perf_mode,
+ pcm->session_id, pcm->playback_substream->stream,
+ event);
+ }
+
mutex_unlock(&pcm->lock);
return ret;
diff --git a/asoc/msm-pcm-q6-noirq.c b/asoc/msm-pcm-q6-noirq.c
index 6d1d30d..cd69d77 100644
--- a/asoc/msm-pcm-q6-noirq.c
+++ b/asoc/msm-pcm-q6-noirq.c
@@ -181,7 +181,13 @@
struct snd_pcm_runtime *runtime = substream->runtime;
struct msm_audio *prtd;
int ret = 0;
+ enum apr_subsys_state subsys_state;
+ subsys_state = apr_get_subsys_state();
+ if (subsys_state == APR_SUBSYS_DOWN) {
+ pr_debug("%s: adsp is down\n", __func__);
+ return -ENETRESET;
+ }
prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
if (prtd == NULL)
diff --git a/asoc/msm-pcm-q6-v2.c b/asoc/msm-pcm-q6-v2.c
index 88ce6bb..7197ad6 100644
--- a/asoc/msm-pcm-q6-v2.c
+++ b/asoc/msm-pcm-q6-v2.c
@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/time.h>
+#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -676,6 +677,7 @@
snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
struct msm_audio *prtd;
struct msm_plat_data *pdata;
+ enum apr_subsys_state subsys_state;
int ret = 0;
if (!component) {
@@ -689,6 +691,13 @@
pr_err("%s: platform data not populated\n", __func__);
return -EINVAL;
}
+
+ subsys_state = apr_get_subsys_state();
+ if (subsys_state == APR_SUBSYS_DOWN) {
+ pr_debug("%s: adsp is down\n", __func__);
+ return -ENETRESET;
+ }
+
prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
if (prtd == NULL)
return -ENOMEM;
@@ -889,19 +898,25 @@
pr_debug("%s: cmd_pending 0x%lx\n", __func__, prtd->cmd_pending);
+ if (!component) {
+ pr_err("%s: component is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ pdata = (struct msm_plat_data *) dev_get_drvdata(component->dev);
+ if (!pdata) {
+ pr_err("%s: platform data is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&pdata->lock);
if (prtd->audio_client) {
dir = IN;
- if (!component) {
- pr_err("%s: component is NULL\n", __func__);
- return -EINVAL;
- }
/*
* Unvote to downgrade the Rx thread priority from
* RT Thread for Low-Latency use case.
*/
- pdata = (struct msm_plat_data *)
- dev_get_drvdata(component->dev);
if (pdata) {
if (pdata->perf_mode == LOW_LATENCY_PCM_MODE)
apr_end_rx_rt(prtd->audio_client->apr);
@@ -935,7 +950,7 @@
msm_adsp_clean_mixer_ctl_pp_event_queue(soc_prtd);
kfree(prtd);
runtime->private_data = NULL;
-
+ mutex_unlock(&pdata->lock);
return 0;
}
@@ -1027,9 +1042,25 @@
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
struct msm_audio *prtd = runtime->private_data;
+ struct snd_soc_component *component =
+ snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
+ struct msm_plat_data *pdata;
int dir = OUT;
pr_debug("%s\n", __func__);
+
+ if (!component) {
+ pr_err("%s: component is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ pdata = (struct msm_plat_data *) dev_get_drvdata(component->dev);
+ if (!pdata) {
+ pr_err("%s: platform data is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&pdata->lock);
if (prtd->audio_client) {
q6asm_cmd(prtd->audio_client, CMD_CLOSE);
q6asm_audio_client_buf_free_contiguous(dir,
@@ -1041,7 +1072,7 @@
SNDRV_PCM_STREAM_CAPTURE);
kfree(prtd);
runtime->private_data = NULL;
-
+ mutex_unlock(&pdata->lock);
return 0;
}
@@ -1308,6 +1339,7 @@
goto done;
}
+ mutex_lock(&pdata->lock);
event_data = (struct msm_adsp_event_data *)ucontrol->value.bytes.data;
if ((event_data->event_type < ADSP_STREAM_PP_EVENT) ||
(event_data->event_type >= ADSP_STREAM_EVENT_MAX)) {
@@ -1330,6 +1362,7 @@
pr_err("%s: failed to send stream event cmd, err = %d\n",
__func__, ret);
done:
+ mutex_unlock(&pdata->lock);
return ret;
}
@@ -1505,25 +1538,46 @@
{
int rc = 0;
struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
+ struct msm_plat_data *pdata = NULL;
struct snd_pcm_substream *substream =
vol->pcm->streams[vol->stream].substream;
+ struct snd_soc_pcm_runtime *soc_prtd = NULL;
+ struct snd_soc_component *component = NULL;
struct msm_audio *prtd;
int volume = ucontrol->value.integer.value[0];
pr_debug("%s: volume : 0x%x\n", __func__, volume);
if (!substream) {
- pr_err("%s substream not found\n", __func__);
+ pr_err("%s: substream not found\n", __func__);
return -ENODEV;
}
- if (!substream->runtime) {
- pr_err("%s substream runtime not found\n", __func__);
+
+ soc_prtd = substream->private_data;
+ if (!substream->runtime || !soc_prtd) {
+ pr_err("%s: substream runtime or private_data not found\n",
+ __func__);
return 0;
}
+
+ component = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
+ if (!component) {
+ pr_err("%s: component is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ pdata = (struct msm_plat_data *) dev_get_drvdata(component->dev);
+ if (!pdata) {
+ pr_err("%s: pdata not found\n", __func__);
+ return -ENODEV;
+ }
+
+ mutex_lock(&pdata->lock);
prtd = substream->runtime->private_data;
if (prtd) {
rc = msm_pcm_set_volume(prtd, volume);
prtd->volume = volume;
}
+ mutex_unlock(&pdata->lock);
return rc;
}
@@ -1703,9 +1757,27 @@
substream = snd_pcm_chmap_substream(info, idx);
if (!substream)
return -ENODEV;
- if (!substream->runtime)
+
+ rtd = substream->private_data;
+ if (rtd) {
+ component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+ if (component) {
+ pdata = (struct msm_plat_data *)
+ dev_get_drvdata(component->dev);
+ if (!pdata) {
+ pr_err("%s: pdata not found\n", __func__);
+ return -ENODEV;
+ }
+ } else {
+ pr_err("%s: component is NULL\n", __func__);
+ return -EINVAL;
+ }
+ }
+
+ if (!substream->runtime || !rtd)
return 0;
+ mutex_lock(&pdata->lock);
prtd = substream->runtime->private_data;
if (prtd) {
prtd->set_channel_map = true;
@@ -1714,13 +1786,9 @@
(char)(ucontrol->value.integer.value[i]);
/* update chmixer_pspd chmap cached with routing driver as well */
- rtd = substream->private_data;
if (rtd) {
- component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
if (component) {
fe_id = rtd->dai_link->id;
- pdata = (struct msm_plat_data *)
- dev_get_drvdata(component->dev);
chmixer_pspd = pdata ?
pdata->chmixer_pspd[fe_id][SESSION_TYPE_RX] : NULL;
@@ -1734,6 +1802,7 @@
}
}
}
+ mutex_unlock(&pdata->lock);
return 0;
}
@@ -1745,16 +1814,37 @@
unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
struct snd_pcm_substream *substream;
struct msm_audio *prtd;
+ struct snd_soc_pcm_runtime *rtd = NULL;
+ struct msm_plat_data *pdata = NULL;
+ struct snd_soc_component *component = NULL;
pr_debug("%s", __func__);
substream = snd_pcm_chmap_substream(info, idx);
if (!substream)
return -ENODEV;
+
+ rtd = substream->private_data;
+ if (rtd) {
+ component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+ if (component) {
+ pdata = (struct msm_plat_data *)
+ dev_get_drvdata(component->dev);
+ if (!pdata) {
+ pr_err("%s: pdata not found\n", __func__);
+ return -ENODEV;
+ }
+ } else {
+ pr_err("%s: component is NULL\n", __func__);
+ return -EINVAL;
+ }
+ }
+
memset(ucontrol->value.integer.value, 0,
sizeof(ucontrol->value.integer.value));
- if (!substream->runtime)
+ if (!substream->runtime || !rtd)
return 0; /* no channels set */
+ mutex_lock(&pdata->lock);
prtd = substream->runtime->private_data;
if (prtd && prtd->set_channel_map == true) {
@@ -1766,6 +1856,7 @@
ucontrol->value.integer.value[i] = 0;
}
+ mutex_unlock(&pdata->lock);
return 0;
}
@@ -2035,6 +2126,7 @@
return -EINVAL;
}
+ mutex_lock(&pdata->lock);
prtd = substream->runtime ? substream->runtime->private_data : NULL;
if (chmixer_pspd->enable && prtd) {
if (session_type == SESSION_TYPE_RX &&
@@ -2087,6 +2179,7 @@
if (reset_override_in_ch_map)
chmixer_pspd->override_in_ch_map = false;
+ mutex_unlock(&pdata->lock);
return ret;
}
@@ -2748,7 +2841,7 @@
} else {
pdata->perf_mode = LEGACY_PCM_MODE;
}
-
+ mutex_init(&pdata->lock);
dev_set_drvdata(&pdev->dev, pdata);
@@ -2771,6 +2864,7 @@
kfree(pdata->chmixer_pspd[i][SESSION_TYPE_TX]);
}
}
+ mutex_destroy(&pdata->lock);
kfree(pdata);
snd_soc_unregister_component(&pdev->dev);
return 0;
diff --git a/asoc/msm-pcm-q6-v2.h b/asoc/msm-pcm-q6-v2.h
index 62fcebd..6498f07 100644
--- a/asoc/msm-pcm-q6-v2.h
+++ b/asoc/msm-pcm-q6-v2.h
@@ -117,6 +117,7 @@
struct msm_pcm_ch_map *ch_map[MSM_FRONTEND_DAI_MAX];
struct snd_pcm *pcm_device[MSM_FRONTEND_DAI_MM_SIZE];
struct msm_pcm_channel_mixer *chmixer_pspd[MSM_FRONTEND_DAI_MM_SIZE][2];
+ struct mutex lock;
};
struct msm_pcm_ch_map {
diff --git a/asoc/msm-pcm-routing-v2.c b/asoc/msm-pcm-routing-v2.c
index ffd09e8..921bca2 100644
--- a/asoc/msm-pcm-routing-v2.c
+++ b/asoc/msm-pcm-routing-v2.c
@@ -80,6 +80,7 @@
static bool is_custom_stereo_on;
static bool is_ds2_on;
static bool swap_ch;
+static bool hifi_filter_enabled;
static int aanc_level;
static int num_app_cfg_types;
static int msm_ec_ref_port_id;
@@ -689,6 +690,10 @@
{ SLIMBUS_9_RX, 0, {0}, {0}, 0, 0, 0, 0, LPASS_BE_SLIMBUS_9_RX},
{ SLIMBUS_9_TX, 0, {0}, {0}, 0, 0, 0, 0, LPASS_BE_SLIMBUS_9_TX},
{ AFE_LOOPBACK_TX, 0, {0}, {0}, 0, 0, 0, 0, LPASS_BE_AFE_LOOPBACK_TX},
+ { AFE_PORT_ID_PRIMARY_META_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0,
+ LPASS_BE_PRI_META_MI2S_RX},
+ { AFE_PORT_ID_SECONDARY_META_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0,
+ LPASS_BE_SEC_META_MI2S_RX},
};
/* Track ASM playback & capture sessions of DAI
@@ -1520,6 +1525,9 @@
topology = COMPRESSED_PASSTHROUGH_NONE_TOPOLOGY;
pr_debug("%s: Before adm open topology %d\n", __func__,
topology);
+ if (hifi_filter_enabled)
+ bit_width = msm_routing_get_bit_width(
+ SNDRV_PCM_FORMAT_S32_LE);
copp_idx =
adm_open(port_id, path_type, sample_rate,
@@ -1865,6 +1873,9 @@
topology = msm_routing_get_adm_topology(fedai_id,
session_type,
i);
+ if (hifi_filter_enabled)
+ bits_per_sample = msm_routing_get_bit_width(
+ SNDRV_PCM_FORMAT_S32_LE);
copp_idx = adm_open(port_id, path_type,
sample_rate, channels, topology,
perf_mode, bits_per_sample,
@@ -2132,6 +2143,9 @@
reg);
acdb_dev_id =
fe_dai_app_type_cfg[val][session_type][reg].acdb_dev_id;
+ if (hifi_filter_enabled)
+ bits_per_sample = msm_routing_get_bit_width(
+ SNDRV_PCM_FORMAT_S32_LE);
copp_idx = adm_open(port_id, path_type,
sample_rate, channels, topology,
fdai->perf_mode, bits_per_sample,
@@ -3435,7 +3449,8 @@
"RX_CDC_DMA_RX_4", "TX_CDC_DMA_TX_4", "RX_CDC_DMA_RX_5", "TX_CDC_DMA_TX_5",
"RX_CDC_DMA_RX_6", "RX_CDC_DMA_RX_7",
"PRI_SPDIF_TX", "SEC_SPDIF_RX", "SEC_SPDIF_TX",
-"SLIM_9_RX", "SLIM_9_TX", "AFE_LOOPBACK_TX"
+"SLIM_9_RX", "SLIM_9_TX", "AFE_LOOPBACK_TX", "PRI_META_MI2S_RX",
+"SEC_META_MI2S_RX"
};
static SOC_ENUM_SINGLE_DECL(mm1_channel_mux,
@@ -5410,6 +5425,10 @@
*index = 36;
port_id = AFE_PORT_ID_SECONDARY_TDM_TX;
break;
+ case 37:
+ *index = 37;
+ port_id = AFE_PORT_ID_HDMI_OVER_DP_RX;
+ break;
default:
*index = 0; /* NONE */
pr_err("%s: Invalid value %d\n", __func__, value);
@@ -5450,9 +5469,10 @@
"32000", "44100", "48000", "96000", "192000", "384000"};
static const struct soc_enum msm_route_ec_ref_params_enum[] = {
- SOC_ENUM_SINGLE_EXT(17, ec_ref_ch_text),
- SOC_ENUM_SINGLE_EXT(3, ec_ref_bit_format_text),
- SOC_ENUM_SINGLE_EXT(9, ec_ref_rate_text),
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ec_ref_ch_text), ec_ref_ch_text),
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ec_ref_bit_format_text),
+ ec_ref_bit_format_text),
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ec_ref_rate_text), ec_ref_rate_text),
};
static const char *const ec_ref_rx[] = { "None", "SLIM_RX", "I2S_RX",
@@ -5462,11 +5482,11 @@
"QUAT_TDM_RX_0", "QUAT_TDM_RX_1", "QUAT_TDM_RX_2", "SLIM_6_RX",
"TERT_MI2S_RX", "QUAT_MI2S_RX", "TERT_TDM_TX_0", "USB_AUDIO_RX",
"INT0_MI2S_RX", "INT4_MI2S_RX", "INT3_MI2S_TX", "DISPLAY_PORT",
- "DISPLAY_PORT1",
"WSA_CDC_DMA_RX_0", "WSA_CDC_DMA_RX_1",
"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",
};
static const struct soc_enum msm_route_ec_ref_rx_enum[] = {
@@ -5662,6 +5682,9 @@
case EXT_EC_REF_SLIM_1_TX:
ext_ec_ref_port_id = SLIMBUS_1_TX;
break;
+ case EXT_EC_REF_PRI_TDM_TX:
+ ext_ec_ref_port_id = AFE_PORT_ID_PRIMARY_TDM_TX;
+ break;
case EXT_EC_REF_SEC_TDM_TX:
ext_ec_ref_port_id = AFE_PORT_ID_SECONDARY_TDM_TX;
break;
@@ -5689,7 +5712,8 @@
static const char * const ext_ec_ref_rx[] = {"NONE", "PRI_MI2S_TX",
"SEC_MI2S_TX", "TERT_MI2S_TX",
"QUAT_MI2S_TX", "QUIN_MI2S_TX",
- "SLIM_1_TX", "SEC_TDM_TX"};
+ "SLIM_1_TX", "PRI_TDM_TX",
+ "SEC_TDM_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),
@@ -7138,6 +7162,189 @@
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new pri_meta_mi2s_rx_mixer_controls[] = {
+ SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+
+};
+
+static const struct snd_kcontrol_new sec_meta_mi2s_rx_mixer_controls[] = {
+ SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM,
MSM_BACKEND_DAI_HDMI_RX,
@@ -21496,16 +21703,16 @@
kcontrol->private_value)->shift;
int i = 0, j;
- num_app_cfg_types = ucontrol->value.integer.value[i++];
- memset(lsm_app_type_cfg, 0, MAX_APP_TYPES*
- sizeof(struct msm_pcm_routing_app_type_data));
-
- if (num_app_cfg_types > MAX_APP_TYPES) {
+ if (ucontrol->value.integer.value[0] > MAX_APP_TYPES) {
pr_err("%s: number of app types exceed the max supported\n",
__func__);
return -EINVAL;
}
+ num_app_cfg_types = ucontrol->value.integer.value[i++];
+ memset(lsm_app_type_cfg, 0, MAX_APP_TYPES*
+ sizeof(struct msm_pcm_routing_app_type_data));
+
for (j = 0; j < num_app_cfg_types; j++) {
lsm_app_type_cfg[j].app_type =
ucontrol->value.integer.value[i++];
@@ -21553,6 +21760,28 @@
msm_routing_put_use_ds1_or_ds2_control),
};
+static int msm_routing_get_hifi_filter_control(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = hifi_filter_enabled;
+ return 0;
+}
+
+static int msm_routing_put_hifi_filter_control(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ hifi_filter_enabled = ucontrol->value.integer.value[0];
+ return 0;
+}
+
+static const struct snd_kcontrol_new hifi_filter_controls[] = {
+ SOC_SINGLE_EXT("HiFi Filter", SND_SOC_NOPM, 0,
+ 1, 0, msm_routing_get_hifi_filter_control,
+ msm_routing_put_hifi_filter_control),
+};
+
int msm_routing_get_rms_value_control(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) {
int rc = 0;
@@ -23164,6 +23393,10 @@
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SEN_TDM_TX_7", "Senary TDM7 Capture",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRI_META_MI2S_RX", "Primary META MI2S Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_META_MI2S_RX", "Secondary META MI2S Playback",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("WSA_CDC_DMA_RX_0", "WSA CDC DMA0 Playback",
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("WSA_CDC_DMA_TX_0", "WSA CDC DMA0 Capture",
@@ -23474,6 +23707,12 @@
SND_SOC_DAPM_MIXER("SEN_TDM_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
sen_tdm_rx_3_mixer_controls,
ARRAY_SIZE(sen_tdm_rx_3_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PRI_META_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ pri_meta_mi2s_rx_mixer_controls,
+ ARRAY_SIZE(pri_meta_mi2s_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_META_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ sec_meta_mi2s_rx_mixer_controls,
+ ARRAY_SIZE(sec_meta_mi2s_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("WSA_CDC_DMA_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
wsa_cdc_dma_rx_0_mixer_controls,
ARRAY_SIZE(wsa_cdc_dma_rx_0_mixer_controls)),
@@ -24697,6 +24936,44 @@
{"SEN_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
{"SEN_MI2S_RX", NULL, "SEN_MI2S_RX Audio Mixer"},
+ {"PRI_META_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"PRI_META_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"PRI_META_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"PRI_META_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"PRI_META_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"PRI_META_MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"PRI_META_MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"PRI_META_MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"PRI_META_MI2S_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"PRI_META_MI2S_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"PRI_META_MI2S_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"PRI_META_MI2S_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"PRI_META_MI2S_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"PRI_META_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"PRI_META_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"PRI_META_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"PRI_META_MI2S_RX Audio Mixer", "MultiMedia26", "MM_DL26"},
+ {"PRI_META_MI2S_RX", NULL, "PRI_META_MI2S_RX Audio Mixer"},
+
+ {"SEC_META_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SEC_META_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"SEC_META_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"SEC_META_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SEC_META_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SEC_META_MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SEC_META_MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SEC_META_MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SEC_META_MI2S_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"SEC_META_MI2S_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"SEC_META_MI2S_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"SEC_META_MI2S_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"SEC_META_MI2S_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"SEC_META_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"SEC_META_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"SEC_META_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"SEC_META_MI2S_RX Audio Mixer", "MultiMedia26", "MM_DL26"},
+ {"SEC_META_MI2S_RX", NULL, "SEC_META_MI2S_RX Audio Mixer"},
+
{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
@@ -26436,6 +26713,7 @@
{"VOC_EXT_EC MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
{"VOC_EXT_EC MUX", "QUIN_MI2S_TX", "QUIN_MI2S_TX"},
{"VOC_EXT_EC MUX", "SLIM_1_TX", "SLIMBUS_1_TX"},
+ {"VOC_EXT_EC MUX", "PRI_TDM_TX", "PRI_TDM_TX_0"},
{"VOC_EXT_EC MUX", "SEC_TDM_TX", "SEC_TDM_TX_0"},
{"VOIP_UL", NULL, "VOC_EXT_EC MUX"},
{"VOICEMMODE1_UL", NULL, "VOC_EXT_EC MUX"},
@@ -28209,6 +28487,9 @@
|| (fdai->passthr_mode == COMPRESSED_PASSTHROUGH_IEC61937))
topology = COMPRESSED_PASSTHROUGH_NONE_TOPOLOGY;
+ if (hifi_filter_enabled)
+ bits_per_sample = msm_routing_get_bit_width(
+ SNDRV_PCM_FORMAT_S32_LE);
copp_idx = adm_open(port_id, path_type,
sample_rate, channels, topology,
fdai->perf_mode, bits_per_sample,
@@ -28809,6 +29090,10 @@
ARRAY_SIZE(use_ds1_or_ds2_controls));
snd_soc_add_component_controls(component,
+ hifi_filter_controls,
+ ARRAY_SIZE(hifi_filter_controls));
+
+ snd_soc_add_component_controls(component,
device_pp_params_mixer_controls,
ARRAY_SIZE(device_pp_params_mixer_controls));
diff --git a/asoc/msm-pcm-routing-v2.h b/asoc/msm-pcm-routing-v2.h
index c9544cb..8003d91 100644
--- a/asoc/msm-pcm-routing-v2.h
+++ b/asoc/msm-pcm-routing-v2.h
@@ -81,6 +81,9 @@
#define LPASS_BE_SENARY_MI2S_TX "SENARY_MI2S_TX"
#define LPASS_BE_SENARY_MI2S_RX "SENARY_MI2S_RX"
+#define LPASS_BE_PRI_META_MI2S_RX "PRI_META_MI2S_RX"
+#define LPASS_BE_SEC_META_MI2S_RX "SEC_META_MI2S_RX"
+
#define LPASS_BE_PRI_TDM_RX_0 "PRI_TDM_RX_0"
#define LPASS_BE_PRI_TDM_TX_0 "PRI_TDM_TX_0"
#define LPASS_BE_PRI_TDM_RX_1 "PRI_TDM_RX_1"
@@ -494,6 +497,8 @@
MSM_BACKEND_DAI_SLIMBUS_9_RX,
MSM_BACKEND_DAI_SLIMBUS_9_TX,
MSM_BACKEND_DAI_AFE_LOOPBACK_TX,
+ MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ MSM_BACKEND_DAI_SEC_META_MI2S_RX,
MSM_BACKEND_DAI_MAX,
};
@@ -511,6 +516,7 @@
EXT_EC_REF_QUAT_MI2S_TX,
EXT_EC_REF_QUIN_MI2S_TX,
EXT_EC_REF_SLIM_1_TX,
+ EXT_EC_REF_PRI_TDM_TX,
EXT_EC_REF_SEC_TDM_TX,
};
diff --git a/asoc/msm-qti-pp-config.c b/asoc/msm-qti-pp-config.c
index d2da56e..89386c4 100644
--- a/asoc/msm-qti-pp-config.c
+++ b/asoc/msm-qti-pp-config.c
@@ -1484,14 +1484,16 @@
};
static const struct snd_kcontrol_new multi_ch_channel_map_mixer_controls[] = {
- SOC_SINGLE_MULTI_EXT("Playback Device Channel Map", SND_SOC_NOPM, 0, 47,
- 0, PCM_FORMAT_MAX_NUM_CHANNEL_V8, msm_qti_pp_get_channel_map_mixer,
+ SOC_SINGLE_MULTI_EXT("Playback Device Channel Map", SND_SOC_NOPM,
+ 0, PCM_MAX_CHMAP_ID, 0, PCM_FORMAT_MAX_NUM_CHANNEL_V8,
+ msm_qti_pp_get_channel_map_mixer,
msm_qti_pp_put_channel_map_mixer),
};
static const struct snd_kcontrol_new multi_ch_channel_map_capture_controls[] = {
- SOC_SINGLE_MULTI_EXT("Capture Device Channel Map", SND_SOC_NOPM, 0, 47,
- 0, PCM_FORMAT_MAX_NUM_CHANNEL_V8, msm_qti_pp_get_channel_map_capture,
+ SOC_SINGLE_MULTI_EXT("Capture Device Channel Map", SND_SOC_NOPM,
+ 0, PCM_MAX_CHMAP_ID, 0, PCM_FORMAT_MAX_NUM_CHANNEL_V8,
+ msm_qti_pp_get_channel_map_capture,
msm_qti_pp_put_channel_map_capture),
};
diff --git a/asoc/msm-transcode-loopback-q6-v2.c b/asoc/msm-transcode-loopback-q6-v2.c
index 5d572f1..df48f5a 100644
--- a/asoc/msm-transcode-loopback-q6-v2.c
+++ b/asoc/msm-transcode-loopback-q6-v2.c
@@ -426,12 +426,19 @@
struct trans_loopback_pdata *pdata;
uint32_t bit_width = 16;
int ret = 0;
+ enum apr_subsys_state subsys_state;
if (trans == NULL) {
pr_err("%s: Invalid param\n", __func__);
return -EINVAL;
}
+ subsys_state = apr_get_subsys_state();
+ if (subsys_state == APR_SUBSYS_DOWN) {
+ pr_debug("%s: adsp is down\n", __func__);
+ return -ENETRESET;
+ }
+
mutex_lock(&trans->lock);
rtd = snd_pcm_substream_chip(cstream);
diff --git a/asoc/qcs405.c b/asoc/qcs405.c
index cadcd40..18dfb82 100644
--- a/asoc/qcs405.c
+++ b/asoc/qcs405.c
@@ -106,6 +106,12 @@
};
enum {
+ PRIM_META_MI2S = 0,
+ SEC_META_MI2S,
+ META_MI2S_MAX,
+};
+
+enum {
PRIM_AUX_PCM = 0,
SEC_AUX_PCM,
TERT_AUX_PCM,
@@ -157,6 +163,12 @@
Q6AFE_LPASS_CLK_ID_SEN_MI2S_EBIT
};
+struct meta_mi2s_conf {
+ u32 num_member_ports;
+ u32 member_port[MAX_NUM_I2S_META_PORT_MEMBER_PORTS];
+ bool clk_enable[MAX_NUM_I2S_META_PORT_MEMBER_PORTS];
+};
+
struct dev_config {
u32 sample_rate;
u32 bit_format;
@@ -402,6 +414,11 @@
[SEN_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
};
+static struct dev_config meta_mi2s_rx_cfg[] = {
+ [PRIM_META_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [SEC_META_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+};
+
/* Default configuration of SPDIF channels */
static struct dev_config spdif_rx_cfg[] = {
[PRIM_SPDIF_RX] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
@@ -487,6 +504,14 @@
"Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen",
"Fourteen", "Fifteen", "Sixteen"
};
+static const char *const meta_mi2s_ch_text[] = {
+ "One", "Two", "Three", "Four", "Five", "Six", "Seven",
+ "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen",
+ "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen",
+ "Nineteen", "Twenty", "TwentyOne", "TwentyTwo", "TwentyThree",
+ "TwentyFour", "TwentyFive", "TwentySix", "TwentySeven",
+ "TwentyEight", "TwentyNine", "Thirty", "ThirtyOne", "ThirtyTwo"
+};
static const char *const qos_text[] = {"Disable", "Enable"};
static const char *const cdc_dma_rx_ch_text[] = {"One", "Two"};
@@ -576,6 +601,12 @@
static SOC_ENUM_SINGLE_EXT_DECL(mi2s_tx_format, bit_format_text);
static SOC_ENUM_SINGLE_EXT_DECL(aux_pcm_rx_format, bit_format_text);
static SOC_ENUM_SINGLE_EXT_DECL(aux_pcm_tx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_meta_mi2s_rx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_meta_mi2s_rx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_meta_mi2s_rx_chs, meta_mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_meta_mi2s_rx_chs, meta_mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_meta_mi2s_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_meta_mi2s_rx_format, bit_format_text);
static SOC_ENUM_SINGLE_EXT_DECL(wsa_cdc_dma_rx_0_chs, cdc_dma_rx_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(wsa_cdc_dma_rx_1_chs, cdc_dma_rx_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(wsa_cdc_dma_tx_0_chs, cdc_dma_tx_ch_text);
@@ -689,6 +720,8 @@
static struct mi2s_conf mi2s_intf_conf[MI2S_MAX];
+static struct meta_mi2s_conf meta_mi2s_intf_conf[META_MI2S_MAX];
+
static int msm_island_vad_get_portid_from_beid(int32_t be_id, int *port_id)
{
*port_id = 0xFFFF;
@@ -3070,6 +3103,143 @@
return 0;
}
+static int msm_meta_mi2s_get_port_idx(struct snd_kcontrol *kcontrol)
+{
+ int idx = 0;
+
+ if (strnstr(kcontrol->id.name, "PRIM_META_MI2S_RX",
+ sizeof("PRIM_META_MI2S_RX"))) {
+ idx = PRIM_META_MI2S;
+ } else if (strnstr(kcontrol->id.name, "SEC_META_MI2S_RX",
+ sizeof("SEC_META_MI2S_RX"))) {
+ idx = SEC_META_MI2S;
+ } else {
+ pr_err("%s: unsupported port: %s",
+ __func__, kcontrol->id.name);
+ idx = -EINVAL;
+ }
+
+ return idx;
+}
+
+static int msm_meta_mi2s_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = msm_meta_mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ mi2s_get_sample_rate_val(meta_mi2s_rx_cfg[idx].sample_rate);
+
+ pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ idx, meta_mi2s_rx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int msm_meta_mi2s_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = msm_meta_mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ meta_mi2s_rx_cfg[idx].sample_rate =
+ mi2s_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ idx, meta_mi2s_rx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int msm_meta_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = msm_meta_mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] = meta_mi2s_rx_cfg[idx].channels - 1;
+
+ pr_debug("%s: meta_mi2s_[%d]_rx_ch = %d\n", __func__,
+ idx, meta_mi2s_rx_cfg[idx].channels);
+
+ return 0;
+}
+
+static int msm_meta_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = msm_meta_mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ meta_mi2s_rx_cfg[idx].channels = ucontrol->value.enumerated.item[0] + 1;
+
+ pr_debug("%s: meta_mi2s_[%d]_rx_ch = %d\n", __func__,
+ idx, meta_mi2s_rx_cfg[idx].channels);
+
+ return 1;
+}
+
+static int msm_meta_mi2s_rx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = msm_meta_mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ mi2s_auxpcm_get_format_value(meta_mi2s_rx_cfg[idx].bit_format);
+
+ pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__,
+ idx, meta_mi2s_rx_cfg[idx].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int msm_meta_mi2s_rx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_asoc_mach_data *pdata = NULL;
+ struct snd_soc_card *card = NULL;
+ int idx = msm_meta_mi2s_get_port_idx(kcontrol);
+
+ card = kcontrol->private_data;
+ pdata = snd_soc_card_get_drvdata(card);
+
+ if (idx < 0)
+ return idx;
+
+ /* check for PRIM_META_MI2S and CSRAx to allow 24bit BE config only */
+ if ((idx == PRIM_META_MI2S) && pdata->codec_is_csra) {
+ meta_mi2s_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ pr_debug("%s: Keeping default format idx[%d]_rx_format = %d, item = %d\n",
+ __func__, idx, meta_mi2s_rx_cfg[idx].bit_format,
+ ucontrol->value.enumerated.item[0]);
+ } else {
+ meta_mi2s_rx_cfg[idx].bit_format =
+ mi2s_auxpcm_get_format(
+ ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__,
+ idx, meta_mi2s_rx_cfg[idx].bit_format,
+ ucontrol->value.enumerated.item[0]);
+ }
+
+ return 0;
+}
+
static int msm_aux_pcm_rx_format_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -3979,6 +4149,26 @@
msm_mi2s_rx_format_get, msm_mi2s_rx_format_put),
SOC_ENUM_EXT("SEN_MI2S_TX Format", mi2s_tx_format,
msm_mi2s_tx_format_get, msm_mi2s_tx_format_put),
+ SOC_ENUM_EXT("PRIM_META_MI2S_RX SampleRate",
+ prim_meta_mi2s_rx_sample_rate,
+ msm_meta_mi2s_rx_sample_rate_get,
+ msm_meta_mi2s_rx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_META_MI2S_RX SampleRate",
+ sec_meta_mi2s_rx_sample_rate,
+ msm_meta_mi2s_rx_sample_rate_get,
+ msm_meta_mi2s_rx_sample_rate_put),
+ SOC_ENUM_EXT("PRIM_META_MI2S_RX Channels", prim_meta_mi2s_rx_chs,
+ msm_meta_mi2s_rx_ch_get,
+ msm_meta_mi2s_rx_ch_put),
+ SOC_ENUM_EXT("SEC_META_MI2S_RX Channels", sec_meta_mi2s_rx_chs,
+ msm_meta_mi2s_rx_ch_get,
+ msm_meta_mi2s_rx_ch_put),
+ SOC_ENUM_EXT("PRIM_META_MI2S_RX Format", mi2s_rx_format,
+ msm_meta_mi2s_rx_format_get,
+ msm_meta_mi2s_rx_format_put),
+ SOC_ENUM_EXT("SEC_META_MI2S_RX Format", mi2s_rx_format,
+ msm_meta_mi2s_rx_format_get,
+ msm_meta_mi2s_rx_format_put),
SOC_ENUM_EXT("PRIM_AUX_PCM_RX Format", aux_pcm_rx_format,
msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put),
SOC_ENUM_EXT("PRIM_AUX_PCM_TX Format", aux_pcm_tx_format,
@@ -4761,6 +4951,25 @@
channels->min = channels->max =
mi2s_tx_cfg[SEN_MI2S].channels;
break;
+
+ case MSM_BACKEND_DAI_PRI_META_MI2S_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ meta_mi2s_rx_cfg[PRIM_META_MI2S].bit_format);
+ rate->min = rate->max =
+ meta_mi2s_rx_cfg[PRIM_META_MI2S].sample_rate;
+ channels->min = channels->max =
+ meta_mi2s_rx_cfg[PRIM_META_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SEC_META_MI2S_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ meta_mi2s_rx_cfg[SEC_META_MI2S].bit_format);
+ rate->min = rate->max =
+ meta_mi2s_rx_cfg[SEC_META_MI2S].sample_rate;
+ channels->min = channels->max =
+ meta_mi2s_rx_cfg[SEC_META_MI2S].channels;
+ break;
+
case MSM_BACKEND_DAI_WSA_CDC_DMA_RX_0:
case MSM_BACKEND_DAI_WSA_CDC_DMA_RX_1:
idx = msm_cdc_dma_get_idx_from_beid(dai_link->id);
@@ -5063,6 +5272,7 @@
snd_soc_dapm_ignore_suspend(dapm, "LINEOUT2");
snd_soc_dapm_ignore_suspend(dapm, "Analog Mic3");
snd_soc_dapm_ignore_suspend(dapm, "Analog Mic4");
+ snd_soc_dapm_ignore_suspend(dapm, "lineout booster");
snd_soc_dapm_sync(dapm);
@@ -5996,6 +6206,172 @@
mutex_unlock(&mi2s_intf_conf[index].lock);
}
+static int msm_meta_mi2s_set_sclk(struct snd_pcm_substream *substream,
+ int member_id, bool enable)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int be_id = 0;
+ int port_id = 0;
+ int index = cpu_dai->id;
+ u32 bit_per_sample = 0;
+
+ switch (member_id) {
+ case PRIM_MI2S:
+ be_id = MSM_BACKEND_DAI_PRI_MI2S_RX;
+ break;
+ case SEC_MI2S:
+ be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX;
+ break;
+ case TERT_MI2S:
+ be_id = MSM_BACKEND_DAI_TERTIARY_MI2S_RX;
+ break;
+ case QUAT_MI2S:
+ be_id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX;
+ break;
+ default:
+ dev_err(rtd->card->dev, "%s: Invalid member_id\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ port_id = msm_get_port_id(be_id);
+ if (port_id < 0) {
+ dev_err(rtd->card->dev, "%s: Invalid port_id\n", __func__);
+ ret = port_id;
+ goto err;
+ }
+
+ if (enable) {
+ bit_per_sample =
+ get_mi2s_bits_per_sample(
+ meta_mi2s_rx_cfg[index].bit_format);
+ mi2s_clk[member_id].clk_freq_in_hz =
+ meta_mi2s_rx_cfg[index].sample_rate * 2 *
+ bit_per_sample;
+
+ dev_dbg(rtd->card->dev, "%s: clock rate %ul\n", __func__,
+ mi2s_clk[member_id].clk_freq_in_hz);
+ }
+
+ mi2s_clk[member_id].enable = enable;
+ ret = afe_set_lpass_clock_v2(port_id, &mi2s_clk[member_id]);
+ if (ret < 0) {
+ dev_err(rtd->card->dev,
+ "%s: afe lpass clock failed for port 0x%x , err:%d\n",
+ __func__, port_id, ret);
+ goto err;
+ }
+
+err:
+ return ret;
+}
+
+static int msm_meta_mi2s_snd_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ int i = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int index = cpu_dai->id;
+ int member_port = 0;
+ unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+
+ dev_dbg(rtd->card->dev,
+ "%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
+ __func__, substream->name, substream->stream,
+ cpu_dai->name, cpu_dai->id);
+
+ if (index < PRIM_META_MI2S || index >= META_MI2S_MAX) {
+ ret = -EINVAL;
+ dev_err(rtd->card->dev,
+ "%s: CPU DAI id (%d) out of range\n",
+ __func__, cpu_dai->id);
+ goto err;
+ }
+
+ for (i = 0; i < meta_mi2s_intf_conf[index].num_member_ports; i++) {
+ member_port = meta_mi2s_intf_conf[index].member_port[i];
+
+ if (!mi2s_intf_conf[member_port].msm_is_mi2s_master) {
+ mi2s_clk[member_port].clk_id =
+ mi2s_ebit_clk[member_port];
+ fmt = SND_SOC_DAIFMT_CBM_CFM;
+ }
+
+ ret = msm_meta_mi2s_set_sclk(substream, member_port, true);
+ if (ret < 0) {
+ dev_err(rtd->card->dev,
+ "%s: afe lpass clock failed to enable MI2S clock, err:%d\n",
+ __func__, ret);
+ goto clk_off;
+ }
+ meta_mi2s_intf_conf[index].clk_enable[i] = true;
+
+ if (i == 0) {
+ ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+ if (ret < 0) {
+ pr_err("%s: set fmt cpu dai failed for META_MI2S (%d), err:%d\n",
+ __func__, index, ret);
+ goto clk_off;
+ }
+ }
+ if (pdata->mi2s_gpio_p[member_port])
+ msm_cdc_pinctrl_select_active_state(
+ pdata->mi2s_gpio_p[member_port]);
+ }
+ return 0;
+
+clk_off:
+ for (i = 0; i < meta_mi2s_intf_conf[index].num_member_ports; i++) {
+ member_port = meta_mi2s_intf_conf[index].member_port[i];
+ if (pdata->mi2s_gpio_p[member_port])
+ msm_cdc_pinctrl_select_sleep_state(
+ pdata->mi2s_gpio_p[member_port]);
+
+ if (meta_mi2s_intf_conf[index].clk_enable[i]) {
+ msm_meta_mi2s_set_sclk(substream, member_port, false);
+ meta_mi2s_intf_conf[index].clk_enable[i] = false;
+ }
+ }
+err:
+ return ret;
+}
+
+static void msm_meta_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ int i = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int index = rtd->cpu_dai->id;
+ int member_port = 0;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+ if (index < PRIM_MI2S || index >= MI2S_MAX) {
+ pr_err("%s:invalid MI2S DAI(%d)\n", __func__, index);
+ return;
+ }
+
+ for (i = 0; i < meta_mi2s_intf_conf[index].num_member_ports; i++) {
+ member_port = meta_mi2s_intf_conf[index].member_port[i];
+
+ if (pdata->mi2s_gpio_p[member_port])
+ msm_cdc_pinctrl_select_sleep_state(
+ pdata->mi2s_gpio_p[member_port]);
+
+ ret = msm_meta_mi2s_set_sclk(substream, member_port, false);
+ if (ret < 0)
+ pr_err("%s:clock disable failed for META MI2S (%d); ret=%d\n",
+ __func__, index, ret);
+ }
+}
+
static int msm_spdif_set_clk(struct snd_pcm_substream *substream, bool enable)
{
int ret = 0;
@@ -6131,6 +6507,11 @@
.shutdown = msm_mi2s_snd_shutdown,
};
+static struct snd_soc_ops msm_meta_mi2s_be_ops = {
+ .startup = msm_meta_mi2s_snd_startup,
+ .shutdown = msm_meta_mi2s_snd_shutdown,
+};
+
static struct snd_soc_ops msm_auxpcm_be_ops = {
.startup = msm_snd_auxpcm_startup,
};
@@ -7567,6 +7948,39 @@
};
+static struct snd_soc_dai_link msm_meta_mi2s_be_dai_links[] = {
+ {
+ .name = LPASS_BE_PRI_META_MI2S_RX,
+ .stream_name = "Primary META MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-meta-mi2s.4864",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .id = MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_meta_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_META_MI2S_RX,
+ .stream_name = "Secondary META MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-meta-mi2s.4866",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .id = MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_meta_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+};
+
static struct snd_soc_dai_link msm_auxpcm_be_dai_links[] = {
/* Primary AUX PCM Backend DAI Links */
{
@@ -7885,6 +8299,7 @@
ARRAY_SIZE(msm_tasha_be_dai_links) +
ARRAY_SIZE(msm_wcn_be_dai_links) +
ARRAY_SIZE(msm_mi2s_be_dai_links) +
+ ARRAY_SIZE(msm_meta_mi2s_be_dai_links) +
ARRAY_SIZE(msm_auxpcm_be_dai_links) +
ARRAY_SIZE(msm_va_cdc_dma_be_dai_links) +
ARRAY_SIZE(msm_wsa_cdc_dma_be_dai_links) +
@@ -8140,7 +8555,7 @@
uint32_t tasha_codec = 0, auxpcm_audio_intf = 0;
uint32_t va_bolero_codec = 0, wsa_bolero_codec = 0, mi2s_audio_intf = 0;
uint32_t spdif_audio_intf = 0, wcn_audio_intf = 0;
- uint32_t afe_loopback_intf = 0;
+ uint32_t afe_loopback_intf = 0, meta_mi2s_intf = 0;
const struct of_device_id *match;
char __iomem *spdif_cfg, *spdif_pin_ctl;
int rc = 0;
@@ -8248,6 +8663,22 @@
ARRAY_SIZE(msm_mi2s_be_dai_links);
}
}
+
+ rc = of_property_read_u32(dev->of_node, "qcom,meta-mi2s-intf",
+ &meta_mi2s_intf);
+ if (rc) {
+ dev_dbg(dev, "%s: No DT match META-MI2S interface\n",
+ __func__);
+ } else {
+ if (meta_mi2s_intf) {
+ memcpy(msm_qcs405_dai_links + total_links,
+ msm_meta_mi2s_be_dai_links,
+ sizeof(msm_meta_mi2s_be_dai_links));
+ total_links +=
+ ARRAY_SIZE(msm_meta_mi2s_be_dai_links);
+ }
+ }
+
rc = of_property_read_u32(dev->of_node,
"qcom,auxpcm-audio-intf",
&auxpcm_audio_intf);
@@ -8807,6 +9238,81 @@
}
}
+static void msm_meta_mi2s_init(struct platform_device *pdev)
+{
+ int rc = 0;
+ int i = 0;
+ int index = 0;
+ bool parse_of = false;
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct snd_soc_dai_link *dai_link = card->dai_link;
+
+ dev_dbg(&pdev->dev, "%s: read from DT\n", __func__);
+
+ for (index = 0; index < META_MI2S_MAX; index++) {
+ meta_mi2s_intf_conf[index].num_member_ports = 0;
+ meta_mi2s_intf_conf[index].member_port[0] = 0;
+ meta_mi2s_intf_conf[index].member_port[1] = 0;
+ meta_mi2s_intf_conf[index].member_port[2] = 0;
+ meta_mi2s_intf_conf[index].member_port[3] = 0;
+ meta_mi2s_intf_conf[index].clk_enable[0] = false;
+ meta_mi2s_intf_conf[index].clk_enable[1] = false;
+ meta_mi2s_intf_conf[index].clk_enable[2] = false;
+ meta_mi2s_intf_conf[index].clk_enable[3] = false;
+ }
+
+ /* get member port info to set matching clocks for involved ports */
+ for (i = 0; i < card->num_links; i++) {
+ if (dai_link[i].id == MSM_BACKEND_DAI_PRI_META_MI2S_RX) {
+ parse_of = true;
+ index = PRIM_META_MI2S;
+ } else if (dai_link[i].id == MSM_BACKEND_DAI_SEC_META_MI2S_RX) {
+ parse_of = true;
+ index = SEC_META_MI2S;
+ } else {
+ parse_of = false;
+ }
+ if (parse_of && dai_link[i].cpu_of_node) {
+ rc = of_property_read_u32(dai_link[i].cpu_of_node,
+ "qcom,msm-mi2s-num-members",
+ &meta_mi2s_intf_conf[index].num_member_ports);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: invalid num from DT file %s\n",
+ __func__, "qcom,msm-mi2s-num-members");
+ }
+
+ if (meta_mi2s_intf_conf[index].num_member_ports >
+ MAX_NUM_I2S_META_PORT_MEMBER_PORTS) {
+ dev_err(&pdev->dev, "%s: num-members %d too large from DT file\n",
+ __func__,
+ meta_mi2s_intf_conf[index].num_member_ports);
+ }
+
+ if (meta_mi2s_intf_conf[index].num_member_ports > 0) {
+ rc = of_property_read_u32_array(
+ dai_link[i].cpu_of_node,
+ "qcom,msm-mi2s-member-id",
+ meta_mi2s_intf_conf[index].member_port,
+ meta_mi2s_intf_conf[index].num_member_ports);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: member-id from DT file %s\n",
+ __func__,
+ "qcom,msm-mi2s-member-id");
+ }
+ }
+
+ dev_dbg(&pdev->dev, "dev name %s num-members=%d\n",
+ dev_name(&pdev->dev),
+ meta_mi2s_intf_conf[index].num_member_ports);
+ dev_dbg(&pdev->dev, "member array (%d, %d, %d, %d)\n",
+ meta_mi2s_intf_conf[index].member_port[0],
+ meta_mi2s_intf_conf[index].member_port[1],
+ meta_mi2s_intf_conf[index].member_port[2],
+ meta_mi2s_intf_conf[index].member_port[3]);
+ }
+ }
+}
+
static int msm_scan_i2c_addr(struct platform_device *pdev,
uint32_t busnum, uint32_t addr)
{
@@ -8984,6 +9490,8 @@
if (val) {
pdata->codec_is_csra = true;
mi2s_rx_cfg[PRIM_MI2S].bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ meta_mi2s_rx_cfg[PRIM_META_MI2S].bit_format =
+ SNDRV_PCM_FORMAT_S24_LE;
ret = msm_init_csra_dev(pdev, card);
if (ret)
goto err;
@@ -9065,6 +9573,8 @@
msm_i2s_auxpcm_init(pdev);
+ msm_meta_mi2s_init(pdev);
+
is_initial_boot = true;
return 0;
err:
diff --git a/dsp/avtimer.c b/dsp/avtimer.c
index 8d9402c..ad5e13a 100644
--- a/dsp/avtimer.c
+++ b/dsp/avtimer.c
@@ -89,6 +89,13 @@
}
payload1 = data->payload;
+
+ if (data->payload_size < 2 * sizeof(uint32_t)) {
+ pr_err("%s: payload has invalid size %d\n",
+ __func__, data->payload_size);
+ return -EINVAL;
+ }
+
switch (payload1[0]) {
case AVCS_CMD_REMOTE_AVTIMER_RELEASE_REQUEST:
pr_debug("%s: Cmd = TIMER RELEASE status[0x%x]\n",
@@ -114,6 +121,11 @@
}
case AVCS_CMD_RSP_REMOTE_AVTIMER_VOTE_REQUEST:
+ if (data->payload_size < sizeof(uint32_t)) {
+ pr_err("%s: payload has invalid size %d\n",
+ __func__, data->payload_size);
+ return -EINVAL;
+ }
payload1 = data->payload;
pr_debug("%s: RSP_REMOTE_AVTIMER_VOTE_REQUEST handle %x\n",
__func__, payload1[0]);
@@ -323,6 +335,11 @@
uint64_t avtimer_tick_temp, avtimer_tick, sys_time = 0;
struct timespec ts;
+ if (!atomic_read(&avtimer.adsp_ready)) {
+ pr_debug("%s:In SSR, return\n", __func__);
+ return -ENETRESET;
+ }
+
if ((avtimer.p_avtimer_lsw == NULL) ||
(avtimer.p_avtimer_msw == NULL)) {
return -EINVAL;
diff --git a/dsp/q6adm.c b/dsp/q6adm.c
index 6dbbbc0..b161df9 100644
--- a/dsp/q6adm.c
+++ b/dsp/q6adm.c
@@ -3044,14 +3044,19 @@
}
if ((topology == VPM_TX_SM_ECNS_V2_COPP_TOPOLOGY) ||
- (topology == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY) ||
- (topology == VPM_TX_DM_RFECNS_COPP_TOPOLOGY)||
(topology == VPM_TX_DM_FLUENCE_EF_COPP_TOPOLOGY)) {
if ((rate != ADM_CMD_COPP_OPEN_SAMPLE_RATE_8K) &&
(rate != ADM_CMD_COPP_OPEN_SAMPLE_RATE_16K) &&
(rate != ADM_CMD_COPP_OPEN_SAMPLE_RATE_32K) &&
(rate != ADM_CMD_COPP_OPEN_SAMPLE_RATE_48K))
- rate = 16000;
+ rate = 16000;
+ }
+ if ((topology == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY) ||
+ (topology == VPM_TX_DM_RFECNS_COPP_TOPOLOGY)) {
+ if ((rate != ADM_CMD_COPP_OPEN_SAMPLE_RATE_8K) &&
+ (rate != ADM_CMD_COPP_OPEN_SAMPLE_RATE_16K) &&
+ (rate != ADM_CMD_COPP_OPEN_SAMPLE_RATE_32K))
+ rate = 16000;
}
if (topology == FFECNS_TOPOLOGY) {
diff --git a/dsp/q6afe.c b/dsp/q6afe.c
index 20ff039..8120536 100644
--- a/dsp/q6afe.c
+++ b/dsp/q6afe.c
@@ -915,6 +915,10 @@
case AFE_PORT_ID_SENARY_MI2S_TX:
ret_size = SIZEOF_CFG_CMD(afe_param_id_i2s_cfg);
break;
+ case AFE_PORT_ID_PRIMARY_META_MI2S_RX:
+ case AFE_PORT_ID_SECONDARY_META_MI2S_RX:
+ ret_size = SIZEOF_CFG_CMD(afe_param_id_meta_i2s_cfg);
+ break;
case HDMI_RX:
case DISPLAY_PORT_RX:
ret_size =
@@ -4556,6 +4560,10 @@
case AFE_PORT_ID_INT6_MI2S_TX:
cfg_type = AFE_PARAM_ID_I2S_CONFIG;
break;
+ case AFE_PORT_ID_PRIMARY_META_MI2S_RX:
+ case AFE_PORT_ID_SECONDARY_META_MI2S_RX:
+ cfg_type = AFE_PARAM_ID_META_I2S_CONFIG;
+ break;
case HDMI_RX:
case DISPLAY_PORT_RX:
cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
@@ -5091,6 +5099,10 @@
return IDX_AFE_PORT_ID_INT6_MI2S_RX;
case AFE_PORT_ID_INT6_MI2S_TX:
return IDX_AFE_PORT_ID_INT6_MI2S_TX;
+ case AFE_PORT_ID_PRIMARY_META_MI2S_RX:
+ return IDX_AFE_PORT_ID_PRIMARY_META_MI2S_RX;
+ case AFE_PORT_ID_SECONDARY_META_MI2S_RX:
+ return IDX_AFE_PORT_ID_SECONDARY_META_MI2S_RX;
case AFE_PORT_ID_VA_CODEC_DMA_TX_0:
return IDX_AFE_PORT_ID_VA_CODEC_DMA_TX_0;
case AFE_PORT_ID_VA_CODEC_DMA_TX_1:
@@ -5254,6 +5266,10 @@
case AFE_PORT_ID_SENARY_MI2S_TX:
cfg_type = AFE_PARAM_ID_I2S_CONFIG;
break;
+ case AFE_PORT_ID_PRIMARY_META_MI2S_RX:
+ case AFE_PORT_ID_SECONDARY_META_MI2S_RX:
+ cfg_type = AFE_PARAM_ID_META_I2S_CONFIG;
+ break;
case HDMI_RX:
case DISPLAY_PORT_RX:
cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
@@ -7231,6 +7247,8 @@
case AFE_PORT_ID_QUINARY_MI2S_TX:
case AFE_PORT_ID_SENARY_MI2S_RX:
case AFE_PORT_ID_SENARY_MI2S_TX:
+ case AFE_PORT_ID_PRIMARY_META_MI2S_RX:
+ case AFE_PORT_ID_SECONDARY_META_MI2S_RX:
case AFE_PORT_ID_PRIMARY_TDM_RX:
case AFE_PORT_ID_PRIMARY_TDM_TX:
case AFE_PORT_ID_PRIMARY_TDM_RX_1:
@@ -8503,7 +8521,7 @@
uint32_t mode;
if (cal_data == NULL ||
- data_size != sizeof(*cal_data) ||
+ data_size > sizeof(*cal_data) ||
this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL)
goto done;
@@ -8647,7 +8665,7 @@
int ret = 0;
if (cal_data == NULL ||
- data_size != sizeof(*cal_data) ||
+ data_size > sizeof(*cal_data) ||
this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL)
return 0;
diff --git a/dsp/q6asm.c b/dsp/q6asm.c
index 37ea0d0..11b307a 100644
--- a/dsp/q6asm.c
+++ b/dsp/q6asm.c
@@ -3542,6 +3542,15 @@
case FORMAT_WMA_V10PRO:
open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V10PRO_V2;
break;
+ case FORMAT_AMRNB:
+ open.dec_fmt_id = ASM_MEDIA_FMT_AMRNB_FS;
+ break;
+ case FORMAT_AMRWB:
+ open.dec_fmt_id = ASM_MEDIA_FMT_AMRWB_FS;
+ break;
+ case FORMAT_AMR_WB_PLUS:
+ open.dec_fmt_id = ASM_MEDIA_FMT_AMR_WB_PLUS_V2;
+ break;
case FORMAT_MP3:
open.dec_fmt_id = ASM_MEDIA_FMT_MP3;
break;
diff --git a/dsp/q6audio-v2.c b/dsp/q6audio-v2.c
index 8de6060..68b3736 100644
--- a/dsp/q6audio-v2.c
+++ b/dsp/q6audio-v2.c
@@ -337,6 +337,10 @@
return IDX_AFE_PORT_ID_INT6_MI2S_RX;
case AFE_PORT_ID_INT6_MI2S_TX:
return IDX_AFE_PORT_ID_INT6_MI2S_TX;
+ case AFE_PORT_ID_PRIMARY_META_MI2S_RX:
+ return IDX_AFE_PORT_ID_PRIMARY_META_MI2S_RX;
+ case AFE_PORT_ID_SECONDARY_META_MI2S_RX:
+ return IDX_AFE_PORT_ID_SECONDARY_META_MI2S_RX;
case AFE_PORT_ID_WSA_CODEC_DMA_RX_0:
return IDX_AFE_PORT_ID_WSA_CODEC_DMA_RX_0;
case AFE_PORT_ID_WSA_CODEC_DMA_TX_0:
@@ -487,6 +491,10 @@
return AUDIO_PORT_ID_I2S_RX;
case AFE_PORT_ID_SECONDARY_MI2S_RX_SD1:
return AFE_PORT_ID_SECONDARY_MI2S_RX_SD1;
+ case AFE_PORT_ID_PRIMARY_META_MI2S_RX:
+ return AFE_PORT_ID_PRIMARY_META_MI2S_RX;
+ case AFE_PORT_ID_SECONDARY_META_MI2S_RX:
+ return AFE_PORT_ID_SECONDARY_META_MI2S_RX;
case AFE_PORT_ID_PRIMARY_TDM_RX:
return AFE_PORT_ID_PRIMARY_TDM_RX;
case AFE_PORT_ID_PRIMARY_TDM_TX:
@@ -820,6 +828,8 @@
case AFE_PORT_ID_SECONDARY_MI2S_TX:
case AUDIO_PORT_ID_I2S_RX:
case AFE_PORT_ID_SECONDARY_MI2S_RX_SD1:
+ case AFE_PORT_ID_PRIMARY_META_MI2S_RX:
+ case AFE_PORT_ID_SECONDARY_META_MI2S_RX:
case AFE_PORT_ID_PRIMARY_TDM_RX:
case AFE_PORT_ID_PRIMARY_TDM_TX:
case AFE_PORT_ID_PRIMARY_TDM_RX_1:
@@ -1048,6 +1058,8 @@
case AFE_PORT_ID_QUINARY_MI2S_RX:
case AFE_PORT_ID_QUINARY_MI2S_TX:
case AFE_PORT_ID_SECONDARY_MI2S_RX_SD1:
+ case AFE_PORT_ID_PRIMARY_META_MI2S_RX:
+ case AFE_PORT_ID_SECONDARY_META_MI2S_RX:
case AFE_PORT_ID_PRIMARY_TDM_RX:
case AFE_PORT_ID_PRIMARY_TDM_TX:
case AFE_PORT_ID_PRIMARY_TDM_RX_1:
diff --git a/dsp/q6lsm.c b/dsp/q6lsm.c
index d55dfc3..9c5bf3d 100644
--- a/dsp/q6lsm.c
+++ b/dsp/q6lsm.c
@@ -285,12 +285,15 @@
static int q6lsm_mmap_apr_dereg(void)
{
- if (atomic_read(&lsm_common.apr_users) <= 0) {
- WARN("%s: APR common port already closed\n", __func__);
- } else {
- if (atomic_dec_return(&lsm_common.apr_users) == 0) {
- apr_deregister(lsm_common.apr);
- pr_debug("%s: APR De-Register common port\n", __func__);
+ if (lsm_common.apr) {
+ if (atomic_read(&lsm_common.apr_users) <= 0) {
+ WARN("%s: APR common port already closed\n", __func__);
+ } else {
+ if (atomic_dec_return(&lsm_common.apr_users) == 0) {
+ apr_deregister(lsm_common.apr);
+ pr_debug("%s: APR De-Register common port\n",
+ __func__);
+ }
}
}
return 0;
@@ -372,9 +375,9 @@
pr_err("%s: Invalid Session %d\n", __func__, client->session);
return;
}
- mutex_lock(&session_lock);
apr_deregister(client->apr);
client->mmap_apr = NULL;
+ mutex_lock(&session_lock);
q6lsm_session_free(client);
q6lsm_mmap_apr_dereg();
mutex_destroy(&client->cmd_lock);
@@ -446,6 +449,8 @@
if (wait)
mutex_unlock(&lsm_common.apr_lock);
+ if (mmap_p && *mmap_p == 0)
+ ret = -ENOMEM;
pr_debug("%s: leave ret %d\n", __func__, ret);
return ret;
}
diff --git a/include/asoc/wcd-mbhc-v2.h b/include/asoc/wcd-mbhc-v2.h
index 9341e3d..1f9d64e 100644
--- a/include/asoc/wcd-mbhc-v2.h
+++ b/include/asoc/wcd-mbhc-v2.h
@@ -140,7 +140,6 @@
#define FW_READ_ATTEMPTS 15
#define FW_READ_TIMEOUT 4000000
#define FAKE_REM_RETRY_ATTEMPTS 3
-#define MAX_IMPED 60000
#define WCD_MBHC_BTN_PRESS_COMPL_TIMEOUT_MS 50
#define ANC_DETECT_RETRY_CNT 7
diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h
index a9a552e..0fcc76a 100644
--- a/include/dsp/apr_audio-v2.h
+++ b/include/dsp/apr_audio-v2.h
@@ -1505,6 +1505,9 @@
/* ID of the senary auxiliary PCM Tx port. */
#define AFE_PORT_ID_SENARY_PCM_TX 0x103F
+#define AFE_PORT_ID_PRIMARY_META_MI2S_RX 0x1300
+#define AFE_PORT_ID_SECONDARY_META_MI2S_RX 0x1302
+
#define AFE_PORT_ID_PRIMARY_SPDIF_RX 0x5000
#define AFE_PORT_ID_PRIMARY_SPDIF_TX 0x5001
#define AFE_PORT_ID_SECONDARY_SPDIF_RX 0x5002
@@ -2650,6 +2653,98 @@
/* This field must be set to zero. */
} __packed;
+/* This param id is used to configure META I2S interface */
+#define AFE_PARAM_ID_META_I2S_CONFIG 0x000102C5
+#define AFE_API_VERSION_META_I2S_CONFIG 0x1
+#define MAX_NUM_I2S_META_PORT_MEMBER_PORTS 4
+
+/* Payload of the #AFE_PARAM_ID_META_I2S_CONFIG
+ * command's (I2S configuration
+ * parameter).
+ */
+struct afe_param_id_meta_i2s_cfg {
+ u32 minor_version;
+/* Minor version used for tracking the version of the I2S
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_META_I2S_CONFIG
+ */
+
+ u16 bit_width;
+/* Bit width of the sample.
+ * Supported values: 16, 24
+ */
+
+ u16 ws_src;
+/* Word select source: internal or external.
+ * Supported values:
+ * - #AFE_PORT_CONFIG_I2S_WS_SRC_EXTERNAL
+ * - #AFE_PORT_CONFIG_I2S_WS_SRC_INTERNAL
+ */
+
+ u32 sample_rate;
+/* Sampling rate of the port.
+ * Supported values:
+ * - #AFE_PORT_SAMPLE_RATE_8K
+ * - #AFE_PORT_SAMPLE_RATE_16K
+ * - #AFE_PORT_SAMPLE_RATE_48K
+ * - #AFE_PORT_SAMPLE_RATE_96K
+ * - #AFE_PORT_SAMPLE_RATE_192K
+ */
+
+ u16 member_port_id[MAX_NUM_I2S_META_PORT_MEMBER_PORTS];
+/* Array of member port IDs in this meta device.
+ * Supported values:
+ * - #AFE_PORT_ID_PRIMARY_MI2S_RX
+ * - #AFE_PORT_ID_SECONDARY_MI2S_RX
+ * - #AFE_PORT_ID_TERTIARY_MI2S_RX
+ * - #AFE_PORT_ID_QUATERNY_MI2S_RX
+ * - #AFE_PORT_ID_INVALID
+ *
+ * Fill these values from index 0. Set unused index to AFE_PORT_ID_INVALID.
+ *
+ * Note:
+ * the first member port will act as WS master in case
+ * meta port ws_src is configured as AFE_PORT_CONFIG_I2S_WS_SRC_INTERNAL.
+ * In all other cases member ports will act as slave.
+ * This must be considered when HLOS enables the interface clocks
+ */
+
+ u16 member_port_channel_mode[MAX_NUM_I2S_META_PORT_MEMBER_PORTS];
+/* I2S lines and multichannel operation per member port.
+ * The sequence matches the sequence in member_port_id,
+ * value will be ignored if member port is set to AFE_PORT_ID_INVALID
+ *
+ * Supported values:
+ * - #AFE_PORT_I2S_SD0
+ * - #AFE_PORT_I2S_SD1
+ * - #AFE_PORT_I2S_SD2
+ * - #AFE_PORT_I2S_SD3
+ * - #AFE_PORT_I2S_QUAD01
+ * - #AFE_PORT_I2S_QUAD23
+ * - #AFE_PORT_I2S_6CHS
+ * - #AFE_PORT_I2S_8CHS
+ * - #AFE_PORT_I2S_10CHS
+ * - #AFE_PORT_I2S_12CHS
+ * - #AFE_PORT_I2S_14CHS
+ * - #AFE_PORT_I2S_16CHS
+ * - #AFE_PORT_I2S_SD4
+ * - #AFE_PORT_I2S_SD5
+ * - #AFE_PORT_I2S_SD6
+ * - #AFE_PORT_I2S_SD7
+ * - #AFE_PORT_I2S_QUAD45
+ * - #AFE_PORT_I2S_QUAD67
+ * - #AFE_PORT_I2S_8CHS_2
+ */
+
+ u16 data_format;
+/* data format
+ * Supported values:
+ * - #LINEAR_PCM_DATA
+ */
+ u16 reserved;
+ /* This field must be set to zero. */
+} __packed;
+
/*
* This param id is used to configure PCM interface
*/
@@ -4846,6 +4941,7 @@
union afe_port_config {
struct afe_param_id_pcm_cfg pcm;
struct afe_param_id_i2s_cfg i2s;
+ struct afe_param_id_meta_i2s_cfg meta_i2s;
struct afe_param_id_hdmi_multi_chan_audio_cfg hdmi_multi_ch;
struct afe_param_id_slimbus_cfg slim_sch;
struct afe_param_id_rt_proxy_port_cfg rtproxy;
@@ -5663,9 +5759,7 @@
/* Left side direct channel. */
#define PCM_CHANNEL_LSD 33
-/* Right side direct channel. Update PCM_MAX_CHMAP_ID when
- * this list is extended.
- */
+/* Right side direct channel. */
#define PCM_CHANNEL_RSD 34
/* Mark unused channel. */
@@ -5690,7 +5784,7 @@
#define PCM_MAX_CHANNEL_MAP 63
/* Max valid channel map index */
-#define PCM_MAX_CHMAP_ID PCM_CHANNEL_RSD
+#define PCM_MAX_CHMAP_ID PCM_MAX_CHANNEL_MAP
#define PCM_FORMAT_MAX_NUM_CHANNEL 8
#define PCM_FORMAT_MAX_CHANNELS_9 9
diff --git a/include/dsp/q6afe-v2.h b/include/dsp/q6afe-v2.h
index 9504ad6..d1b4f3c 100644
--- a/include/dsp/q6afe-v2.h
+++ b/include/dsp/q6afe-v2.h
@@ -281,6 +281,9 @@
IDX_AFE_PORT_ID_SENARY_TDM_TX_6,
IDX_AFE_PORT_ID_SENARY_TDM_RX_7,
IDX_AFE_PORT_ID_SENARY_TDM_TX_7,
+ /* IDX 208-> 209 */
+ IDX_AFE_PORT_ID_PRIMARY_META_MI2S_RX,
+ IDX_AFE_PORT_ID_SECONDARY_META_MI2S_RX,
AFE_MAX_PORTS
};
diff --git a/include/soc/swr-wcd.h b/include/soc/swr-wcd.h
index 25c5339..4ec5094 100644
--- a/include/soc/swr-wcd.h
+++ b/include/soc/swr-wcd.h
@@ -22,6 +22,8 @@
SWR_REGISTER_WAKE_IRQ,
SWR_SET_PORT_MAP,
SWR_REQ_CLK_SWITCH,
+ SWR_REGISTER_WAKEUP,
+ SWR_DEREGISTER_WAKEUP,
};
struct swr_mstr_port {
diff --git a/soc/pinctrl-lpi.c b/soc/pinctrl-lpi.c
index 157e2c5..3aff320 100644
--- a/soc/pinctrl-lpi.c
+++ b/soc/pinctrl-lpi.c
@@ -23,6 +23,7 @@
#include "pinctrl-utils.h"
#define LPI_AUTO_SUSPEND_DELAY 100 /* delay in msec */
+#define LPI_AUTO_SUSPEND_DELAY_ERROR 1 /* delay in msec */
#define LPI_ADDRESS_SIZE 0x20000
#define LPI_SLEW_ADDRESS_SIZE 0x1000
@@ -824,13 +825,19 @@
mutex_lock(&state->core_hw_vote_lock);
ret = clk_prepare_enable(state->lpass_core_hw_vote);
- if (ret < 0)
+ if (ret < 0) {
+ pm_runtime_set_autosuspend_delay(dev,
+ LPI_AUTO_SUSPEND_DELAY_ERROR);
dev_err(dev, "%s:lpass core hw island enable failed\n",
__func__);
- else
+ goto exit;
+ } else {
state->core_hw_vote_status = true;
+ }
pm_runtime_set_autosuspend_delay(dev, LPI_AUTO_SUSPEND_DELAY);
+
+exit:
mutex_unlock(&state->core_hw_vote_lock);
return 0;
}
diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c
index c4deb20..44d245d 100644
--- a/soc/swr-mstr-ctrl.c
+++ b/soc/swr-mstr-ctrl.c
@@ -18,8 +18,6 @@
#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
#include <soc/soundwire.h>
#include <soc/swr-common.h>
#include <linux/regmap.h>
@@ -42,6 +40,8 @@
#define SWR_HSTOP_MAX_VAL 0xF
#define SWR_HSTART_MIN_VAL 0x0
+#define ERR_AUTO_SUSPEND_TIMER_VAL 0x1
+
#define SWRM_INTERRUPT_STATUS_MASK 0x1FDFD
/* pm runtime auto suspend timer in msecs */
static int auto_suspend_timer = SWR_AUTO_SUSPEND_DELAY * 1000;
@@ -77,30 +77,19 @@
#define SWRM_MAX_PORT_REG 120
#define SWRM_MAX_INIT_REG 11
-#define SWR_MSTR_MAX_REG_ADDR 0x1740
-#define SWR_MSTR_START_REG_ADDR 0x00
-#define SWR_MSTR_MAX_BUF_LEN 32
-#define BYTES_PER_LINE 12
-#define SWR_MSTR_RD_BUF_LEN 8
-#define SWR_MSTR_WR_BUF_LEN 32
-
#define MAX_FIFO_RD_FAIL_RETRY 3
-static struct swr_mstr_ctrl *dbgswrm;
-static struct dentry *debugfs_swrm_dent;
-static struct dentry *debugfs_peek;
-static struct dentry *debugfs_poke;
-static struct dentry *debugfs_reg_dump;
-static unsigned int read_data;
-
static bool swrm_lock_sleep(struct swr_mstr_ctrl *swrm);
static void swrm_unlock_sleep(struct swr_mstr_ctrl *swrm);
+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 bool swrm_is_msm_variant(int val)
{
return (val == SWRM_VERSION_1_3);
}
+#ifdef CONFIG_DEBUG_FS
static int swrm_debug_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
@@ -130,20 +119,32 @@
return 0;
}
-static ssize_t swrm_reg_show(char __user *ubuf, size_t count,
- loff_t *ppos)
+static ssize_t swrm_reg_show(struct swr_mstr_ctrl *swrm, char __user *ubuf,
+ size_t count, loff_t *ppos)
{
int i, reg_val, len;
ssize_t total = 0;
char tmp_buf[SWR_MSTR_MAX_BUF_LEN];
+ int rem = 0;
if (!ubuf || !ppos)
return 0;
- for (i = (((int) *ppos / BYTES_PER_LINE) + SWR_MSTR_START_REG_ADDR);
- i <= SWR_MSTR_MAX_REG_ADDR; i += 4) {
- reg_val = dbgswrm->read(dbgswrm->handle, i);
+ i = ((int) *ppos + SWR_MSTR_START_REG_ADDR);
+ rem = i%4;
+
+ if (rem)
+ i = (i - rem);
+
+ for (; i <= SWR_MSTR_MAX_REG_ADDR; i += 4) {
+ usleep_range(100, 150);
+ reg_val = swr_master_read(swrm, i);
len = snprintf(tmp_buf, 25, "0x%.3x: 0x%.2x\n", i, reg_val);
+ if (len < 0) {
+ pr_err("%s: fail to fill the buffer\n", __func__);
+ total = -EFAULT;
+ goto copy_err;
+ }
if ((total + len) >= count - 1)
break;
if (copy_to_user((ubuf + total), tmp_buf, len)) {
@@ -159,85 +160,142 @@
return total;
}
-static ssize_t swrm_debug_read(struct file *file, char __user *ubuf,
+static ssize_t swrm_debug_reg_dump(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
- char lbuf[SWR_MSTR_RD_BUF_LEN];
- char *access_str;
- ssize_t ret_cnt;
+ struct swr_mstr_ctrl *swrm;
if (!count || !file || !ppos || !ubuf)
return -EINVAL;
- access_str = file->private_data;
+ swrm = file->private_data;
+ if (!swrm)
+ return -EINVAL;
+
if (*ppos < 0)
return -EINVAL;
- if (!strcmp(access_str, "swrm_peek")) {
- snprintf(lbuf, sizeof(lbuf), "0x%x\n", read_data);
- ret_cnt = simple_read_from_buffer(ubuf, count, ppos, lbuf,
- strnlen(lbuf, 7));
- } else if (!strcmp(access_str, "swrm_reg_dump")) {
- ret_cnt = swrm_reg_show(ubuf, count, ppos);
- } else {
- pr_err("%s: %s not permitted to read\n", __func__, access_str);
- ret_cnt = -EPERM;
- }
- return ret_cnt;
+ return swrm_reg_show(swrm, ubuf, count, ppos);
}
-static ssize_t swrm_debug_write(struct file *filp,
- const char __user *ubuf, size_t cnt, loff_t *ppos)
+static ssize_t swrm_debug_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ char lbuf[SWR_MSTR_RD_BUF_LEN];
+ struct swr_mstr_ctrl *swrm = NULL;
+
+ if (!count || !file || !ppos || !ubuf)
+ return -EINVAL;
+
+ swrm = file->private_data;
+ if (!swrm)
+ return -EINVAL;
+
+ if (*ppos < 0)
+ return -EINVAL;
+
+ snprintf(lbuf, sizeof(lbuf), "0x%x\n", swrm->read_data);
+
+ return simple_read_from_buffer(ubuf, count, ppos, lbuf,
+ strnlen(lbuf, 7));
+}
+
+static ssize_t swrm_debug_peek_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ char lbuf[SWR_MSTR_RD_BUF_LEN];
+ int rc;
+ u32 param[5];
+ struct swr_mstr_ctrl *swrm = NULL;
+
+ if (!count || !file || !ppos || !ubuf)
+ return -EINVAL;
+
+ swrm = file->private_data;
+ if (!swrm)
+ return -EINVAL;
+
+ if (*ppos < 0)
+ return -EINVAL;
+
+ if (count > sizeof(lbuf) - 1)
+ return -EINVAL;
+
+ rc = copy_from_user(lbuf, ubuf, count);
+ if (rc)
+ return -EFAULT;
+
+ lbuf[count] = '\0';
+ rc = get_parameters(lbuf, param, 1);
+ if ((param[0] <= SWR_MSTR_MAX_REG_ADDR) && (rc == 0))
+ swrm->read_data = swr_master_read(swrm, param[0]);
+ else
+ rc = -EINVAL;
+
+ if (rc == 0)
+ rc = count;
+ else
+ dev_err(swrm->dev, "%s: rc = %d\n", __func__, rc);
+
+ return rc;
+}
+
+static ssize_t swrm_debug_write(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
{
char lbuf[SWR_MSTR_WR_BUF_LEN];
int rc;
u32 param[5];
- char *access_str;
+ struct swr_mstr_ctrl *swrm;
- if (!filp || !ppos || !ubuf)
+ if (!file || !ppos || !ubuf)
return -EINVAL;
- access_str = filp->private_data;
- if (cnt > sizeof(lbuf) - 1)
+ swrm = file->private_data;
+ if (!swrm)
return -EINVAL;
- rc = copy_from_user(lbuf, ubuf, cnt);
+ if (count > sizeof(lbuf) - 1)
+ return -EINVAL;
+
+ rc = copy_from_user(lbuf, ubuf, count);
if (rc)
return -EFAULT;
- lbuf[cnt] = '\0';
- if (!strcmp(access_str, "swrm_poke")) {
- /* write */
- rc = get_parameters(lbuf, param, 2);
- if ((param[0] <= SWR_MSTR_MAX_REG_ADDR) &&
- (param[1] <= 0xFFFFFFFF) &&
- (rc == 0))
- rc = dbgswrm->write(dbgswrm->handle, param[0],
- param[1]);
- else
- rc = -EINVAL;
- } else if (!strcmp(access_str, "swrm_peek")) {
- /* read */
- rc = get_parameters(lbuf, param, 1);
- if ((param[0] <= SWR_MSTR_MAX_REG_ADDR) && (rc == 0))
- read_data = dbgswrm->read(dbgswrm->handle, param[0]);
- else
- rc = -EINVAL;
- }
+ lbuf[count] = '\0';
+ rc = get_parameters(lbuf, param, 2);
+ if ((param[0] <= SWR_MSTR_MAX_REG_ADDR) &&
+ (param[1] <= 0xFFFFFFFF) &&
+ (rc == 0))
+ swr_master_write(swrm, param[0], param[1]);
+ else
+ rc = -EINVAL;
+
if (rc == 0)
- rc = cnt;
+ rc = count;
else
pr_err("%s: rc = %d\n", __func__, rc);
return rc;
}
-static const struct file_operations swrm_debug_ops = {
+static const struct file_operations swrm_debug_read_ops = {
.open = swrm_debug_open,
- .write = swrm_debug_write,
+ .write = swrm_debug_peek_write,
.read = swrm_debug_read,
};
+static const struct file_operations swrm_debug_write_ops = {
+ .open = swrm_debug_open,
+ .write = swrm_debug_write,
+};
+
+static const struct file_operations swrm_debug_dump_ops = {
+ .open = swrm_debug_open,
+ .read = swrm_debug_reg_dump,
+};
+#endif
+
static void swrm_reg_dump(struct swr_mstr_ctrl *swrm,
u32 *reg, u32 *val, int len, const char* func)
{
@@ -296,6 +354,15 @@
ret = -ENODEV;
goto exit;
}
+ if (swrm->core_vote) {
+ ret = swrm->core_vote(swrm->handle, true);
+ if (ret) {
+ dev_err_ratelimited(swrm->dev,
+ "%s: clock enable req failed",
+ __func__);
+ goto exit;
+ }
+ }
swrm->clk_ref_count++;
if (swrm->clk_ref_count == 1) {
ret = swrm->clk(swrm->handle, true);
@@ -397,7 +464,11 @@
mutex_lock(&swrm->iolock);
for (i = 0; i < length; i++) {
/* wait for FIFO WR command to complete to avoid overflow */
- usleep_range(100, 105);
+ /*
+ * Reduce sleep from 100us to 10us to meet KPIs
+ * This still meets the hardware spec
+ */
+ usleep_range(10, 12);
swr_master_write(swrm, reg_addr[i], val[i]);
}
mutex_unlock(&swrm->iolock);
@@ -559,7 +630,7 @@
* skip delay if write is handled in platform driver.
*/
if(!swrm->write)
- usleep_range(250, 255);
+ usleep_range(150, 155);
if (cmd_id == 0xF) {
/*
* sleep for 10ms for MSM soundwire variant to allow broadcast
@@ -1407,6 +1478,7 @@
continue;
if (swr_dev->slave_irq) {
do {
+ swr_dev->slave_irq_pending = 0;
handle_nested_irq(
irq_find_mapping(
swr_dev->slave_irq, 0));
@@ -1535,6 +1607,12 @@
struct swr_device *swr_dev;
struct swr_master *mstr = &swrm->master;
+ if (!swrm->dev_up || swrm->state == SWR_MSTR_SSR) {
+ complete(&swrm->broadcast);
+ dev_dbg(swrm->dev, "%s swrm is not up\n", __func__);
+ return IRQ_NONE;
+ }
+
if (unlikely(swrm_lock_sleep(swrm) == false)) {
dev_err(swrm->dev, "%s Failed to hold suspend\n", __func__);
return IRQ_NONE;
@@ -1549,7 +1627,12 @@
ret = IRQ_NONE;
goto err_audio_hw_vote;
}
- swrm_clk_request(swrm, true);
+ ret = swrm_clk_request(swrm, true);
+ if (ret) {
+ dev_err(dev, "%s: swrm clk failed\n", __func__);
+ ret = IRQ_NONE;
+ goto err_audio_core_vote;
+ }
mutex_unlock(&swrm->reslock);
intr_sts = swr_master_read(swrm, SWRM_INTERRUPT_STATUS);
@@ -1725,6 +1808,7 @@
mutex_lock(&swrm->reslock);
swrm_clk_request(swrm, false);
+err_audio_core_vote:
swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, false);
err_audio_hw_vote:
@@ -2113,6 +2197,7 @@
swrm->swrm_base_reg, SWRM_MAX_REGISTER);
}
+ swrm->core_vote = pdata->core_vote;
swrm->clk = pdata->clk;
if (!swrm->clk) {
dev_err(&pdev->dev, "%s: swrm->clk is NULL\n",
@@ -2320,23 +2405,23 @@
if (pdev->dev.of_node)
of_register_swr_devices(&swrm->master);
- dbgswrm = swrm;
- debugfs_swrm_dent = debugfs_create_dir(dev_name(&pdev->dev), 0);
- if (!IS_ERR(debugfs_swrm_dent)) {
- debugfs_peek = debugfs_create_file("swrm_peek",
- S_IFREG | 0444, debugfs_swrm_dent,
- (void *) "swrm_peek", &swrm_debug_ops);
+#ifdef CONFIG_DEBUG_FS
+ swrm->debugfs_swrm_dent = debugfs_create_dir(dev_name(&pdev->dev), 0);
+ if (!IS_ERR(swrm->debugfs_swrm_dent)) {
+ swrm->debugfs_peek = debugfs_create_file("swrm_peek",
+ S_IFREG | 0444, swrm->debugfs_swrm_dent,
+ (void *) swrm, &swrm_debug_read_ops);
- debugfs_poke = debugfs_create_file("swrm_poke",
- S_IFREG | 0444, debugfs_swrm_dent,
- (void *) "swrm_poke", &swrm_debug_ops);
+ swrm->debugfs_poke = debugfs_create_file("swrm_poke",
+ S_IFREG | 0444, swrm->debugfs_swrm_dent,
+ (void *) swrm, &swrm_debug_write_ops);
- debugfs_reg_dump = debugfs_create_file("swrm_reg_dump",
- S_IFREG | 0444, debugfs_swrm_dent,
- (void *) "swrm_reg_dump",
- &swrm_debug_ops);
+ swrm->debugfs_reg_dump = debugfs_create_file("swrm_reg_dump",
+ S_IFREG | 0444, swrm->debugfs_swrm_dent,
+ (void *) swrm,
+ &swrm_debug_dump_ops);
}
-
+#endif
ret = device_init_wakeup(swrm->dev, true);
if (ret) {
dev_err(swrm->dev, "Device wakeup init failed: %d\n", ret);
@@ -2425,6 +2510,7 @@
struct platform_device *pdev = to_platform_device(dev);
struct swr_mstr_ctrl *swrm = platform_get_drvdata(pdev);
int ret = 0;
+ bool swrm_clk_req_err = false;
bool hw_core_err = false;
bool aud_core_err = false;
struct swr_master *mstr = &swrm->master;
@@ -2458,7 +2544,7 @@
* Set autosuspend timer to 1 for
* master to enter into suspend.
*/
- auto_suspend_timer = 1;
+ swrm_clk_req_err = true;
goto exit;
}
if (!swrm->clk_stop_mode0_supp || swrm->state == SWR_MSTR_SSR) {
@@ -2501,8 +2587,12 @@
swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, false);
if (!hw_core_err)
swrm_request_hw_vote(swrm, LPASS_HW_CORE, false);
- pm_runtime_set_autosuspend_delay(&pdev->dev, auto_suspend_timer);
- auto_suspend_timer = SWR_AUTO_SUSPEND_DELAY * 1000;
+ if (swrm_clk_req_err)
+ pm_runtime_set_autosuspend_delay(&pdev->dev,
+ ERR_AUTO_SUSPEND_TIMER_VAL);
+ else
+ pm_runtime_set_autosuspend_delay(&pdev->dev,
+ auto_suspend_timer);
mutex_unlock(&swrm->reslock);
return ret;
@@ -2574,7 +2664,12 @@
mutex_lock(&swrm->reslock);
usleep_range(100, 105);
}
- swrm_clk_request(swrm, false);
+ ret = swrm_clk_request(swrm, false);
+ if (ret) {
+ dev_err(dev, "%s: swrmn clk failed\n", __func__);
+ ret = 0;
+ goto exit;
+ }
if (swrm->clk_stop_mode0_supp) {
if (swrm->wake_irq > 0) {
@@ -2880,6 +2975,14 @@
mutex_unlock(&swrm->mlock);
}
break;
+ case SWR_REGISTER_WAKEUP:
+ msm_aud_evt_blocking_notifier_call_chain(
+ SWR_WAKE_IRQ_REGISTER, (void *)swrm);
+ break;
+ case SWR_DEREGISTER_WAKEUP:
+ msm_aud_evt_blocking_notifier_call_chain(
+ SWR_WAKE_IRQ_DEREGISTER, (void *)swrm);
+ break;
case SWR_SET_PORT_MAP:
if (!data) {
dev_err(swrm->dev, "%s: data is NULL for id=%d\n",
diff --git a/soc/swr-mstr-ctrl.h b/soc/swr-mstr-ctrl.h
index e05ede2..321e84f 100644
--- a/soc/swr-mstr-ctrl.h
+++ b/soc/swr-mstr-ctrl.h
@@ -11,6 +11,18 @@
#include <soc/qcom/pm.h>
#include <soc/swr-common.h>
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#define SWR_MSTR_MAX_REG_ADDR 0x1740
+#define SWR_MSTR_START_REG_ADDR 0x00
+#define SWR_MSTR_MAX_BUF_LEN 32
+#define BYTES_PER_LINE 12
+#define SWR_MSTR_RD_BUF_LEN 8
+#define SWR_MSTR_WR_BUF_LEN 32
+#endif
+
#define SWR_ROW_48 0
#define SWR_ROW_50 1
#define SWR_ROW_64 2
@@ -91,6 +103,7 @@
int (*write)(void *handle, int reg, int val);
int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len);
int (*clk)(void *handle, bool enable);
+ int (*core_vote)(void *handle, bool enable);
int (*reg_irq)(void *handle, irqreturn_t(*irq_handler)(int irq,
void *data), void *swr_handle, int type);
};
@@ -120,6 +133,7 @@
int (*write)(void *handle, int reg, int val);
int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len);
int (*clk)(void *handle, bool enable);
+ int (*core_vote)(void *handle, bool enable);
int (*reg_irq)(void *handle, irqreturn_t(*irq_handler)(int irq,
void *data), void *swr_handle, int type);
int irq;
@@ -160,6 +174,13 @@
u32 swr_irq_wakeup_capable;
int hw_core_clk_en;
int aud_core_clk_en;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_swrm_dent;
+ struct dentry *debugfs_peek;
+ struct dentry *debugfs_poke;
+ struct dentry *debugfs_reg_dump;
+ unsigned int read_data;
+#endif
};
#endif /* _SWR_WCD_CTRL_H */