|
@@ -27,13 +27,25 @@
|
|
|
#include <asoc/msm-cdc-pinctrl.h>
|
|
|
#include <asoc/msm-cdc-supply.h>
|
|
|
#include <dt-bindings/sound/audio-codec-port-types.h>
|
|
|
+#include "wcd938x/wcd938x.h"
|
|
|
#include "swr-dmic.h"
|
|
|
|
|
|
-#define itoa(x) ('0' + x)
|
|
|
-#define DAI_NAME_NUM_INDEX 11
|
|
|
-#define AIF_NAME_NUM_INDEX 12
|
|
|
-#define DEFAULT_CODEC_NAME "swr_dmic_tx0"
|
|
|
-#define DEFAULT_AIF_NAME "SWR_DMIC_AIF0 Playback"
|
|
|
+static int swr_master_channel_map[] = {
|
|
|
+ ZERO,
|
|
|
+ SWRM_TX1_CH1,
|
|
|
+ SWRM_TX1_CH2,
|
|
|
+ SWRM_TX1_CH3,
|
|
|
+ SWRM_TX1_CH4,
|
|
|
+ SWRM_TX2_CH1,
|
|
|
+ SWRM_TX2_CH2,
|
|
|
+ SWRM_TX2_CH3,
|
|
|
+ SWRM_TX2_CH4,
|
|
|
+ SWRM_TX3_CH1,
|
|
|
+ SWRM_TX3_CH2,
|
|
|
+ SWRM_TX3_CH3,
|
|
|
+ SWRM_TX3_CH4,
|
|
|
+ SWRM_PCM_IN,
|
|
|
+};
|
|
|
|
|
|
/*
|
|
|
* Private data Structure for swr-dmic. All parameters related to
|
|
@@ -44,12 +56,12 @@ struct swr_dmic_priv {
|
|
|
struct swr_device *swr_slave;
|
|
|
struct snd_soc_component *component;
|
|
|
struct snd_soc_component_driver *driver;
|
|
|
- struct snd_soc_dai_driver *dai_driver;
|
|
|
- const char *supply_name;
|
|
|
+ struct snd_soc_component *supply_component;
|
|
|
+ u32 micb_num;
|
|
|
struct device_node *wcd_handle;
|
|
|
- struct cdc_wcd_supply *cdc_supply;
|
|
|
bool is_wcd_supply;
|
|
|
- int tx_mode;
|
|
|
+ int is_en_supply;
|
|
|
+ int port_type;
|
|
|
u8 tx_master_port_map[SWR_DMIC_MAX_PORTS];
|
|
|
};
|
|
|
|
|
@@ -58,127 +70,34 @@ const char *codec_name_list[] = {
|
|
|
"swr-dmic-02",
|
|
|
"swr-dmic-03",
|
|
|
"swr-dmic-04",
|
|
|
- "swr-dmic-05",
|
|
|
};
|
|
|
|
|
|
-static int get_master_port(int val)
|
|
|
-{
|
|
|
- int master_port = 0;
|
|
|
-
|
|
|
- switch(val) {
|
|
|
- case 0:
|
|
|
- master_port = SWRM_TX1_CH1;
|
|
|
- break;
|
|
|
- case 1:
|
|
|
- master_port = SWRM_TX1_CH2;
|
|
|
- break;
|
|
|
- case 2:
|
|
|
- master_port = SWRM_TX1_CH3;
|
|
|
- break;
|
|
|
- case 3:
|
|
|
- master_port = SWRM_TX1_CH4;
|
|
|
- break;
|
|
|
- case 4:
|
|
|
- master_port = SWRM_TX2_CH1;
|
|
|
- break;
|
|
|
- case 5:
|
|
|
- master_port = SWRM_TX2_CH2;
|
|
|
- break;
|
|
|
- case 6:
|
|
|
- master_port = SWRM_TX2_CH3;
|
|
|
- break;
|
|
|
- case 7:
|
|
|
- master_port = SWRM_TX2_CH4;
|
|
|
- break;
|
|
|
- case 8:
|
|
|
- master_port = SWRM_TX3_CH1;
|
|
|
- break;
|
|
|
- case 9:
|
|
|
- master_port = SWRM_TX3_CH2;
|
|
|
- break;
|
|
|
- case 10:
|
|
|
- master_port = SWRM_TX3_CH3;
|
|
|
- break;
|
|
|
- case 11:
|
|
|
- master_port = SWRM_TX3_CH4;
|
|
|
- break;
|
|
|
- case 12:
|
|
|
- master_port = SWRM_PCM_IN;
|
|
|
- break;
|
|
|
- default:
|
|
|
- master_port = SWRM_TX1_CH1;
|
|
|
- pr_debug("%s: undefined value, fall back to default master_port: %d\n",
|
|
|
- __func__, master_port);
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- pr_debug("%s: master_port: %d\n", __func__, master_port);
|
|
|
- return master_port;
|
|
|
-}
|
|
|
-
|
|
|
-static int get_master_port_val(int master_port)
|
|
|
-{
|
|
|
- int val = 0;
|
|
|
+const char *dai_name_list[] = {
|
|
|
+ "swr_dmic_tx0",
|
|
|
+ "swr_dmic_tx1",
|
|
|
+ "swr_dmic_tx2",
|
|
|
+ "swr_dmic_tx3",
|
|
|
+};
|
|
|
|
|
|
- switch (master_port) {
|
|
|
- case SWRM_TX1_CH1:
|
|
|
- val = 0;
|
|
|
- break;
|
|
|
- case SWRM_TX1_CH2:
|
|
|
- val = 1;
|
|
|
- break;
|
|
|
- case SWRM_TX1_CH3:
|
|
|
- val = 2;
|
|
|
- break;
|
|
|
- case SWRM_TX1_CH4:
|
|
|
- val = 3;
|
|
|
- break;
|
|
|
- case SWRM_TX2_CH1:
|
|
|
- val = 4;
|
|
|
- break;
|
|
|
- case SWRM_TX2_CH2:
|
|
|
- val = 5;
|
|
|
- break;
|
|
|
- case SWRM_TX2_CH3:
|
|
|
- val = 6;
|
|
|
- break;
|
|
|
- case SWRM_TX2_CH4:
|
|
|
- val = 7;
|
|
|
- break;
|
|
|
- case SWRM_TX3_CH1:
|
|
|
- val = 8;
|
|
|
- break;
|
|
|
- case SWRM_TX3_CH2:
|
|
|
- val = 9;
|
|
|
- break;
|
|
|
- case SWRM_TX3_CH3:
|
|
|
- val = 10;
|
|
|
- break;
|
|
|
- case SWRM_TX3_CH4:
|
|
|
- val = 11;
|
|
|
- break;
|
|
|
- case SWRM_PCM_IN:
|
|
|
- val = 12;
|
|
|
- break;
|
|
|
- default:
|
|
|
- val = 0;
|
|
|
- pr_debug("%s: undefined master_port:%d, fallback to default val: %d\n",
|
|
|
- __func__, master_port, val);
|
|
|
- break;
|
|
|
- }
|
|
|
+const char *aif_name_list[] = {
|
|
|
+ "SWR_DMIC_AIF0 Playback",
|
|
|
+ "SWR_DMIC_AIF1 Playback",
|
|
|
+ "SWR_DMIC_AIF2 Playback",
|
|
|
+ "SWR_DMIC_AIF3 Playback",
|
|
|
+};
|
|
|
|
|
|
- pr_debug("%s: master_port:%d val: %d\n", __func__, master_port, val);
|
|
|
- return val;
|
|
|
-}
|
|
|
+static int swr_dmic_reset(struct swr_device *pdev);
|
|
|
+static int swr_dmic_up(struct swr_device *pdev);
|
|
|
+static int swr_dmic_down(struct swr_device *pdev);
|
|
|
|
|
|
static inline int swr_dmic_tx_get_slave_port_type_idx(const char *wname,
|
|
|
unsigned int *port_idx)
|
|
|
{
|
|
|
u8 port_type;
|
|
|
|
|
|
- if (strnstr(wname, "HIFI", sizeof("HIFI")))
|
|
|
+ if (strnstr(wname, "HIFI", strlen(wname)))
|
|
|
port_type = SWR_DMIC_HIFI_PORT;
|
|
|
- else if (strnstr(wname, "LP", sizeof("LP")))
|
|
|
+ else if (strnstr(wname, "LP", strlen(wname)))
|
|
|
port_type = SWR_DMIC_LP_PORT;
|
|
|
else
|
|
|
return -EINVAL;
|
|
@@ -187,6 +106,16 @@ static inline int swr_dmic_tx_get_slave_port_type_idx(const char *wname,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static inline int swr_dmic_get_master_port_val(int port)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < ARRAY_SIZE(swr_master_channel_map); i++)
|
|
|
+ if (port == swr_master_channel_map[i])
|
|
|
+ return i;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int swr_dmic_tx_master_port_get(struct snd_kcontrol *kcontrol,
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
{
|
|
@@ -202,14 +131,15 @@ static int swr_dmic_tx_master_port_get(struct snd_kcontrol *kcontrol,
|
|
|
dev_dbg(component->dev, "%s: invalid port string\n", __func__);
|
|
|
return ret;
|
|
|
}
|
|
|
+ swr_dmic->port_type = slave_port_idx;
|
|
|
|
|
|
- if (slave_port_idx >= 0 &&
|
|
|
- slave_port_idx < SWR_DMIC_MAX_PORTS)
|
|
|
- ucontrol->value.integer.value[0] = get_master_port_val(
|
|
|
+ ucontrol->value.integer.value[0] =
|
|
|
+ swr_dmic_get_master_port_val(
|
|
|
swr_dmic->tx_master_port_map[slave_port_idx]);
|
|
|
|
|
|
dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
|
|
|
__func__, ucontrol->value.integer.value[0]);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -228,17 +158,13 @@ static int swr_dmic_tx_master_port_put(struct snd_kcontrol *kcontrol,
|
|
|
dev_dbg(component->dev, "%s: invalid port string\n", __func__);
|
|
|
return ret;
|
|
|
}
|
|
|
+ swr_dmic->port_type = slave_port_idx;
|
|
|
|
|
|
-
|
|
|
- dev_dbg(component->dev, "%s: slave_port_idx: %d",
|
|
|
- __func__, slave_port_idx);
|
|
|
- dev_dbg(component->dev, "%s: ucontrol->value.enumerated.item[0] = %ld\n",
|
|
|
- __func__, ucontrol->value.enumerated.item[0]);
|
|
|
- if (slave_port_idx >= 0 &&
|
|
|
- slave_port_idx < SWR_DMIC_MAX_PORTS)
|
|
|
- swr_dmic->tx_master_port_map[slave_port_idx] =
|
|
|
- get_master_port(
|
|
|
- ucontrol->value.enumerated.item[0]);
|
|
|
+ swr_dmic->tx_master_port_map[slave_port_idx] =
|
|
|
+ swr_master_channel_map[ucontrol->value.enumerated.item[0]];
|
|
|
+ dev_dbg(component->dev, "%s: slv port id: %d, master_port_type: %d\n",
|
|
|
+ __func__, slave_port_idx,
|
|
|
+ swr_dmic->tx_master_port_map[slave_port_idx]);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -254,20 +180,27 @@ static int dmic_swr_ctrl(struct snd_soc_dapm_widget *w,
|
|
|
|
|
|
u8 num_ch = 1;
|
|
|
u8 ch_mask = 0x01; // only DpnChannelEN1 register is available
|
|
|
- u8 port_type = 0;
|
|
|
- u32 ch_rate = 0;
|
|
|
+ u32 ch_rate = SWR_CLK_RATE_4P8MHZ;
|
|
|
u8 num_port = 1;
|
|
|
+ u8 port_type = 0;
|
|
|
+ u8 port_id = swr_dmic->port_type;
|
|
|
+
|
|
|
/*
|
|
|
* Port 1 is high quality / 2.4 or 3.072 Mbps
|
|
|
* Port 2 is listen low power / 0.6 or 0.768 Mbps
|
|
|
*/
|
|
|
- u8 port_id = swr_dmic->tx_mode;
|
|
|
+ if(swr_dmic->port_type)
|
|
|
+ ch_rate = SWR_CLK_RATE_2P4MHZ;
|
|
|
+ else
|
|
|
+ ch_rate = SWR_CLK_RATE_4P8MHZ;
|
|
|
+
|
|
|
port_type = swr_dmic->tx_master_port_map[port_id];
|
|
|
|
|
|
switch (event) {
|
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
|
- ret = swr_connect_port(swr_dmic->swr_slave, &port_id, num_port,
|
|
|
- &ch_mask, &ch_rate, &num_ch, &port_type);
|
|
|
+ ret = swr_connect_port(swr_dmic->swr_slave, &port_id,
|
|
|
+ num_port, &ch_mask, &ch_rate,
|
|
|
+ &num_ch, &port_type);
|
|
|
break;
|
|
|
case SND_SOC_DAPM_POST_PMU:
|
|
|
ret = swr_slvdev_datapath_control(swr_dmic->swr_slave,
|
|
@@ -278,56 +211,48 @@ static int dmic_swr_ctrl(struct snd_soc_dapm_widget *w,
|
|
|
swr_dmic->swr_slave->dev_num, false);
|
|
|
break;
|
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
|
- ret = swr_disconnect_port(swr_dmic->swr_slave, &port_id,
|
|
|
- num_port, &ch_mask, &port_type);
|
|
|
+ ret = swr_disconnect_port(swr_dmic->swr_slave,
|
|
|
+ &port_id, num_port, &ch_mask, &port_type);
|
|
|
break;
|
|
|
};
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static const char * const tx_mode_text_swr_mic[] = {
|
|
|
- "MIC_HIFI", "MIC_LP",
|
|
|
-};
|
|
|
-
|
|
|
-static int swr_mic_tx_mode_put(struct snd_kcontrol *kcontrol,
|
|
|
- struct snd_ctl_elem_value *ucontrol)
|
|
|
+static int swr_dmic_enable_supply(struct snd_soc_dapm_widget *w,
|
|
|
+ struct snd_kcontrol *kcontrol,
|
|
|
+ int event)
|
|
|
{
|
|
|
struct snd_soc_component *component =
|
|
|
- snd_soc_kcontrol_component(kcontrol);
|
|
|
+ snd_soc_dapm_to_component(w->dapm);
|
|
|
struct swr_dmic_priv *swr_dmic =
|
|
|
snd_soc_component_get_drvdata(component);
|
|
|
+ int ret = 0;
|
|
|
|
|
|
- dev_dbg(component->dev, "%s: tx_mode = %ld\n",
|
|
|
- __func__, ucontrol->value.integer.value[0]);
|
|
|
-
|
|
|
- swr_dmic->tx_mode = ucontrol->value.integer.value[0];
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int swr_mic_tx_mode_get(struct snd_kcontrol *kcontrol,
|
|
|
- struct snd_ctl_elem_value *ucontrol)
|
|
|
-{
|
|
|
- struct snd_soc_component *component =
|
|
|
- snd_soc_kcontrol_component(kcontrol);
|
|
|
- struct swr_dmic_priv *swr_dmic =
|
|
|
- snd_soc_component_get_drvdata(component);
|
|
|
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
|
|
|
+ w->name, event);
|
|
|
|
|
|
- ucontrol->value.integer.value[0] = swr_dmic->tx_mode;
|
|
|
+ switch (event) {
|
|
|
+ case SND_SOC_DAPM_PRE_PMU:
|
|
|
+ ret = swr_dmic_up(swr_dmic->swr_slave);
|
|
|
+ break;
|
|
|
+ case SND_SOC_DAPM_POST_PMU:
|
|
|
+ ret = swr_dmic_reset(swr_dmic->swr_slave);
|
|
|
+ break;
|
|
|
+ case SND_SOC_DAPM_POST_PMD:
|
|
|
+ ret = swr_dmic_down(swr_dmic->swr_slave);
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
- dev_dbg(component->dev, "%s: tx_mode = 0x%x\n", __func__,
|
|
|
- swr_dmic->tx_mode);
|
|
|
+ if (ret)
|
|
|
+ dev_dbg(component->dev, "%s wname: %s event: %d ret : %d\n",
|
|
|
+ __func__, w->name, event, ret);
|
|
|
|
|
|
- return 0;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
-static const struct soc_enum tx_mode_enum_swr_mic =
|
|
|
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tx_mode_text_swr_mic),
|
|
|
- tx_mode_text_swr_mic);
|
|
|
-
|
|
|
static const char * const tx_master_port_text[] = {
|
|
|
- "SWRM_TX1_CH1", "SWRM_TX1_CH2", "SWRM_TX1_CH3", "SWRM_TX1_CH4",
|
|
|
+ "ZERO", "SWRM_TX1_CH1", "SWRM_TX1_CH2", "SWRM_TX1_CH3", "SWRM_TX1_CH4",
|
|
|
"SWRM_TX2_CH1", "SWRM_TX2_CH2", "SWRM_TX2_CH3", "SWRM_TX2_CH4",
|
|
|
"SWRM_TX3_CH1", "SWRM_TX3_CH2", "SWRM_TX3_CH3", "SWRM_TX3_CH4",
|
|
|
"SWRM_PCM_IN",
|
|
@@ -338,9 +263,6 @@ static const struct soc_enum tx_master_port_enum =
|
|
|
tx_master_port_text);
|
|
|
|
|
|
static const struct snd_kcontrol_new swr_dmic_snd_controls[] = {
|
|
|
- SOC_ENUM_EXT("TX MODE", tx_mode_enum_swr_mic,
|
|
|
- swr_mic_tx_mode_get, swr_mic_tx_mode_put),
|
|
|
-
|
|
|
SOC_ENUM_EXT("HIFI PortMap", tx_master_port_enum,
|
|
|
swr_dmic_tx_master_port_get, swr_dmic_tx_master_port_put),
|
|
|
SOC_ENUM_EXT("LP PortMap", tx_master_port_enum,
|
|
@@ -352,17 +274,23 @@ static const struct snd_kcontrol_new dmic_switch[] = {
|
|
|
};
|
|
|
|
|
|
static const struct snd_soc_dapm_widget swr_dmic_dapm_widgets[] = {
|
|
|
- SND_SOC_DAPM_MIXER_E("DMIC_SWR_MIXER", SND_SOC_NOPM, 0, 0,
|
|
|
+ SND_SOC_DAPM_MIXER_E("SWR_DMIC_MIXER", SND_SOC_NOPM, 0, 0,
|
|
|
dmic_switch, ARRAY_SIZE(dmic_switch), dmic_swr_ctrl,
|
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
|
|
|
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
|
|
|
|
|
|
SND_SOC_DAPM_INPUT("SWR_DMIC"),
|
|
|
|
|
|
+ SND_SOC_DAPM_SUPPLY_S("SMIC_SUPPLY", 1, SND_SOC_NOPM, 0, 0,
|
|
|
+ swr_dmic_enable_supply,
|
|
|
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
|
|
|
+ SND_SOC_DAPM_POST_PMD),
|
|
|
+
|
|
|
SND_SOC_DAPM_OUTPUT("SWR_DMIC_OUTPUT"),
|
|
|
};
|
|
|
|
|
|
static const struct snd_soc_dapm_route swr_dmic_audio_map[] = {
|
|
|
+ {"SWR_DMIC", NULL, "SMIC_SUPPLY"},
|
|
|
{"SWR_DMIC_MIXER", "Switch", "SWR_DMIC"},
|
|
|
{"SWR_DMIC_OUTPUT", NULL, "SWR_DMIC_MIXER"},
|
|
|
};
|
|
@@ -400,55 +328,63 @@ static const struct snd_soc_component_driver soc_codec_dev_swr_dmic = {
|
|
|
.num_dapm_routes = ARRAY_SIZE(swr_dmic_audio_map),
|
|
|
};
|
|
|
|
|
|
-static struct snd_soc_dai_ops wsa_dai_ops = {
|
|
|
-};
|
|
|
+static int enable_wcd_codec_supply(struct swr_dmic_priv *swr_dmic, bool enable)
|
|
|
+{
|
|
|
+ int rc = 0;
|
|
|
+ int micb_num = swr_dmic->micb_num;
|
|
|
+ struct snd_soc_component *component = swr_dmic->supply_component;
|
|
|
|
|
|
-static struct snd_soc_dai_driver swr_dmic_dai[] = {
|
|
|
- {
|
|
|
- .name = "",
|
|
|
- .id = 0,
|
|
|
- .playback = {
|
|
|
- .stream_name = "",
|
|
|
- .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
|
|
|
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
|
|
|
- SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000),
|
|
|
- .formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
|
|
- SNDRV_PCM_FMTBIT_S24_LE |
|
|
|
- SNDRV_PCM_FMTBIT_S32_LE),
|
|
|
- .rate_max = 192000,
|
|
|
- .rate_min = 8000,
|
|
|
- .channels_min = 1,
|
|
|
- .channels_max = 2,
|
|
|
- },
|
|
|
- .ops = &wsa_dai_ops,
|
|
|
- },
|
|
|
-};
|
|
|
+ if (!component) {
|
|
|
+ pr_err("%s: component is NULL\n", __func__);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (enable)
|
|
|
+ rc = wcd938x_codec_force_enable_micbias_v2(component,
|
|
|
+ SND_SOC_DAPM_PRE_PMU, micb_num);
|
|
|
+ else
|
|
|
+ rc = wcd938x_codec_force_enable_micbias_v2(component,
|
|
|
+ SND_SOC_DAPM_POST_PMD, micb_num);
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+static int swr_dmic_parse_supply(struct device_node *np,
|
|
|
+ struct swr_dmic_priv *swr_dmic)
|
|
|
+{
|
|
|
+ struct platform_device *pdev = NULL;
|
|
|
+
|
|
|
+ if (!np || !swr_dmic)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ pdev = of_find_device_by_node(np);
|
|
|
+ if (!pdev)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ swr_dmic->supply_component = snd_soc_lookup_component(&pdev->dev, NULL);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
static int swr_dmic_probe(struct swr_device *pdev)
|
|
|
{
|
|
|
int ret = 0;
|
|
|
- struct swr_dmic_priv *swr_dmic;
|
|
|
int i = 0;
|
|
|
- u8 devnum = 0;
|
|
|
+ u8 swr_devnum = 0;
|
|
|
+ int dev_index = -1;
|
|
|
+ char* prefix_name = NULL;
|
|
|
+ struct swr_dmic_priv *swr_dmic = NULL;
|
|
|
const char *swr_dmic_name_prefix_of = NULL;
|
|
|
const char *swr_dmic_codec_name_of = NULL;
|
|
|
- struct snd_soc_component *component;
|
|
|
- char *dai_name;
|
|
|
- char *aif_name;
|
|
|
+ struct snd_soc_component *component = NULL;
|
|
|
|
|
|
swr_dmic = devm_kzalloc(&pdev->dev, sizeof(struct swr_dmic_priv),
|
|
|
GFP_KERNEL);
|
|
|
if (!swr_dmic)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
- swr_dmic->cdc_supply = devm_kzalloc(&pdev->dev,
|
|
|
- sizeof(struct cdc_wcd_supply),
|
|
|
- GFP_KERNEL);
|
|
|
- if (!swr_dmic->cdc_supply)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
- ret = of_property_read_string(pdev->dev.of_node, "qcom,swr-dmic-supply",
|
|
|
- &swr_dmic->supply_name);
|
|
|
+ ret = of_property_read_u32(pdev->dev.of_node, "qcom,swr-dmic-supply",
|
|
|
+ &swr_dmic->micb_num);
|
|
|
if (ret) {
|
|
|
dev_dbg(&pdev->dev, "%s: Looking up %s property in node %s failed\n",
|
|
|
__func__, "qcom,swr-dmic-supply",
|
|
@@ -462,17 +398,17 @@ static int swr_dmic_probe(struct swr_device *pdev)
|
|
|
__func__);
|
|
|
swr_dmic->is_wcd_supply = false;
|
|
|
} else {
|
|
|
- msm_cdc_init_wcd_supply(swr_dmic->wcd_handle,
|
|
|
- swr_dmic->supply_name, swr_dmic->cdc_supply);
|
|
|
+ swr_dmic_parse_supply(swr_dmic->wcd_handle, swr_dmic);
|
|
|
swr_dmic->is_wcd_supply = true;
|
|
|
}
|
|
|
|
|
|
if (swr_dmic->is_wcd_supply) {
|
|
|
- ret = msm_cdc_enable_wcd_supply(swr_dmic->cdc_supply, true);
|
|
|
+ ret = enable_wcd_codec_supply(swr_dmic, true);
|
|
|
if (ret) {
|
|
|
ret = -EPROBE_DEFER;
|
|
|
- goto err;
|
|
|
+ goto dev_err;
|
|
|
}
|
|
|
+ ++swr_dmic->is_en_supply;
|
|
|
}
|
|
|
|
|
|
swr_set_dev_data(pdev, swr_dmic);
|
|
@@ -485,7 +421,7 @@ static int swr_dmic_probe(struct swr_device *pdev)
|
|
|
dev_dbg(&pdev->dev, "%s: Looking up %s property in node %s failed\n",
|
|
|
__func__, "qcom,swr-dmic-prefix",
|
|
|
pdev->dev.of_node->full_name);
|
|
|
- goto err;
|
|
|
+ goto dev_err;
|
|
|
}
|
|
|
|
|
|
ret = of_property_read_string(pdev->dev.of_node, "qcom,codec-name",
|
|
@@ -494,7 +430,7 @@ static int swr_dmic_probe(struct swr_device *pdev)
|
|
|
dev_dbg(&pdev->dev, "%s: Looking up %s property in node %s failed\n",
|
|
|
__func__, "qcom,codec-name",
|
|
|
pdev->dev.of_node->full_name);
|
|
|
- goto err;
|
|
|
+ goto dev_err;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -503,14 +439,16 @@ static int swr_dmic_probe(struct swr_device *pdev)
|
|
|
* as per HW requirement.
|
|
|
*/
|
|
|
usleep_range(5000, 5010);
|
|
|
- ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum);
|
|
|
+ ret = swr_get_logical_dev_num(pdev, pdev->addr, &swr_devnum);
|
|
|
if (ret) {
|
|
|
dev_dbg(&pdev->dev,
|
|
|
"%s get devnum %d for dev addr %lx failed\n",
|
|
|
- __func__, devnum, pdev->addr);
|
|
|
+ __func__, swr_devnum, pdev->addr);
|
|
|
+ ret = -EPROBE_DEFER;
|
|
|
goto dev_err;
|
|
|
}
|
|
|
- pdev->dev_num = devnum;
|
|
|
+ pdev->dev_num = swr_devnum;
|
|
|
+
|
|
|
|
|
|
swr_dmic->driver = devm_kzalloc(&pdev->dev,
|
|
|
sizeof(struct snd_soc_component_driver), GFP_KERNEL);
|
|
@@ -521,53 +459,23 @@ static int swr_dmic_probe(struct swr_device *pdev)
|
|
|
|
|
|
memcpy(swr_dmic->driver, &soc_codec_dev_swr_dmic,
|
|
|
sizeof(struct snd_soc_component_driver));
|
|
|
- swr_dmic->driver->name = devm_kzalloc(&pdev->dev,
|
|
|
- strlen(swr_dmic_codec_name_of), GFP_KERNEL);
|
|
|
- if (!swr_dmic->driver->name) {
|
|
|
- ret = -ENOMEM;
|
|
|
- goto dev_err;
|
|
|
- }
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(codec_name_list); i++) {
|
|
|
- if (!strcmp(swr_dmic_codec_name_of, codec_name_list[i]))
|
|
|
+ if (!strcmp(swr_dmic_codec_name_of, codec_name_list[i])) {
|
|
|
+ dev_index = i;
|
|
|
break;
|
|
|
- }
|
|
|
- if (i == ARRAY_SIZE(codec_name_list))
|
|
|
- goto dev_err;
|
|
|
-
|
|
|
- swr_dmic->dai_driver = devm_kzalloc(&pdev->dev,
|
|
|
- sizeof(struct snd_soc_dai_driver), GFP_KERNEL);
|
|
|
- if (!swr_dmic->dai_driver) {
|
|
|
- ret = -ENOMEM;
|
|
|
- goto dev_err;
|
|
|
- }
|
|
|
-
|
|
|
- memcpy(swr_dmic->dai_driver, swr_dmic_dai,
|
|
|
- sizeof(struct snd_soc_dai_driver));
|
|
|
- dai_name = devm_kzalloc(&pdev->dev, strlen(DEFAULT_CODEC_NAME),
|
|
|
- GFP_KERNEL);
|
|
|
- if (!dai_name) {
|
|
|
- ret = -ENOMEM;
|
|
|
- goto dev_err;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- memcpy(dai_name, DEFAULT_CODEC_NAME, strlen(DEFAULT_CODEC_NAME));
|
|
|
- dai_name[DAI_NAME_NUM_INDEX] = itoa(i);
|
|
|
- swr_dmic->dai_driver->name = dai_name;
|
|
|
- swr_dmic->dai_driver->id = i;
|
|
|
- aif_name = devm_kzalloc(&pdev->dev, strlen(DEFAULT_AIF_NAME),
|
|
|
- GFP_KERNEL);
|
|
|
- if (!aif_name) {
|
|
|
- ret = -ENOMEM;
|
|
|
+ if (dev_index < 0) {
|
|
|
+ ret = -EINVAL;
|
|
|
goto dev_err;
|
|
|
}
|
|
|
|
|
|
- memcpy(aif_name, DEFAULT_AIF_NAME, strlen(DEFAULT_AIF_NAME));
|
|
|
- aif_name[AIF_NAME_NUM_INDEX] = itoa(i);
|
|
|
- swr_dmic->dai_driver->playback.stream_name = aif_name;
|
|
|
+ swr_dmic->driver->name = dai_name_list[dev_index];
|
|
|
|
|
|
ret = snd_soc_register_component(&pdev->dev, swr_dmic->driver,
|
|
|
- swr_dmic->dai_driver, 1);
|
|
|
+ NULL, 0);
|
|
|
if (ret) {
|
|
|
dev_err(&pdev->dev, "%s: Codec registration failed\n",
|
|
|
__func__);
|
|
@@ -577,19 +485,26 @@ static int swr_dmic_probe(struct swr_device *pdev)
|
|
|
component = snd_soc_lookup_component(&pdev->dev,
|
|
|
swr_dmic->driver->name);
|
|
|
swr_dmic->component = component;
|
|
|
- component->name_prefix = devm_kzalloc(&pdev->dev,
|
|
|
+ prefix_name = devm_kzalloc(&pdev->dev,
|
|
|
strlen(swr_dmic_name_prefix_of),
|
|
|
- GFP_KERNEL);
|
|
|
- if (!component->name_prefix) {
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!prefix_name) {
|
|
|
ret = -ENOMEM;
|
|
|
goto dev_err;
|
|
|
}
|
|
|
+ strlcpy(prefix_name, swr_dmic_name_prefix_of,
|
|
|
+ strlen(swr_dmic_name_prefix_of));
|
|
|
+ component->name_prefix = prefix_name;
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
dev_err:
|
|
|
- if (swr_dmic->is_wcd_supply)
|
|
|
- msm_cdc_enable_wcd_supply(swr_dmic->cdc_supply, false);
|
|
|
+ if (swr_dmic->is_en_supply == 1) {
|
|
|
+ enable_wcd_codec_supply(swr_dmic, false);
|
|
|
+ --swr_dmic->is_en_supply;
|
|
|
+ }
|
|
|
+ swr_dmic->is_wcd_supply = false;
|
|
|
+ swr_dmic->wcd_handle = NULL;
|
|
|
swr_remove_device(pdev);
|
|
|
err:
|
|
|
return ret;
|
|
@@ -620,8 +535,10 @@ static int swr_dmic_up(struct swr_device *pdev)
|
|
|
dev_err(&pdev->dev, "%s: swr_dmic is NULL\n", __func__);
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
- if (swr_dmic->is_wcd_supply)
|
|
|
- ret = msm_cdc_enable_wcd_supply(swr_dmic->cdc_supply, true);
|
|
|
+
|
|
|
+ ++swr_dmic->is_en_supply;
|
|
|
+ if (swr_dmic->is_en_supply == 1)
|
|
|
+ ret = enable_wcd_codec_supply(swr_dmic, true);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
@@ -636,9 +553,18 @@ static int swr_dmic_down(struct swr_device *pdev)
|
|
|
dev_err(&pdev->dev, "%s: swr_dmic is NULL\n", __func__);
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
- if (swr_dmic->is_wcd_supply)
|
|
|
- ret = msm_cdc_enable_wcd_supply(swr_dmic->cdc_supply, false);
|
|
|
|
|
|
+ --swr_dmic->is_en_supply;
|
|
|
+ if (swr_dmic->is_en_supply < 0) {
|
|
|
+ dev_warn(&pdev->dev, "%s: mismatch in supply count %d\n",
|
|
|
+ __func__, swr_dmic->is_en_supply);
|
|
|
+ swr_dmic->is_en_supply = 0;
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+ if (!swr_dmic->is_en_supply)
|
|
|
+ enable_wcd_codec_supply(swr_dmic, false);
|
|
|
+
|
|
|
+done:
|
|
|
return ret;
|
|
|
}
|
|
|
|