Merge "ASoC: msm: Loopback Driver Reg Stream in Prepare Stage"
diff --git a/asoc/codecs/bolero/rx-macro.c b/asoc/codecs/bolero/rx-macro.c
index c6a9d3d..52598ef 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;
@@ -1526,6 +1597,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)
@@ -2245,6 +2357,8 @@
0x20, 0x20);
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)
diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c
index fda01e1..8c32043 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
@@ -163,6 +164,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 +611,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 +846,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 +930,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 +1203,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,6 +1686,30 @@
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),
};
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/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/wcd938x/wcd938x.c b/asoc/codecs/wcd938x/wcd938x.c
index f89a2aa..036f97a 100644
--- a/asoc/codecs/wcd938x/wcd938x.c
+++ b/asoc/codecs/wcd938x/wcd938x.c
@@ -2779,6 +2779,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);
@@ -3026,6 +3060,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 +3211,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/msm-compress-q6-v2.c b/asoc/msm-compress-q6-v2.c
index 75b217f..c4bf720 100644
--- a/asoc/msm-compress-q6-v2.c
+++ b/asoc/msm-compress-q6-v2.c
@@ -978,6 +978,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 +1267,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;
@@ -2193,6 +2214,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 +3306,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));
@@ -3641,6 +3683,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;
diff --git a/asoc/msm-dai-q6-v2.c b/asoc/msm-dai-q6-v2.c
index c6f61e4..ab3445a 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);
@@ -1728,22 +1742,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 +1920,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 = {
@@ -6096,6 +6152,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 +6353,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 +7370,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;
@@ -12175,6 +12936,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 +12992,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 +13013,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-routing-v2.c b/asoc/msm-pcm-routing-v2.c
index ffd09e8..f5e9896 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[] = {
@@ -7138,6 +7158,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,
@@ -21553,6 +21756,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 +23389,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 +23703,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 +24932,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"},
@@ -28209,6 +28482,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 +29085,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..aca00bb 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,
};
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/qcs405.c b/asoc/qcs405.c
index cadcd40..36fbfad 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);
@@ -5996,6 +6205,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 +6506,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 +7947,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 +8298,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 +8554,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 +8662,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 +9237,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 +9489,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 +9572,8 @@
msm_i2s_auxpcm_init(pdev);
+ msm_meta_mi2s_init(pdev);
+
is_initial_boot = true;
return 0;
err:
diff --git a/dsp/q6afe.c b/dsp/q6afe.c
index 20ff039..9709772 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:
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..d27bbac 100644
--- a/dsp/q6lsm.c
+++ b/dsp/q6lsm.c
@@ -372,9 +372,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);
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/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c
index c4deb20..9ad849e 100644
--- a/soc/swr-mstr-ctrl.c
+++ b/soc/swr-mstr-ctrl.c
@@ -144,6 +144,11 @@
i <= SWR_MSTR_MAX_REG_ADDR; i += 4) {
reg_val = dbgswrm->read(dbgswrm->handle, 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)) {
@@ -397,7 +402,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 +568,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 +1416,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));
@@ -2880,6 +2890,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",