summaryrefslogtreecommitdiff
path: root/sound/soc/codecs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2021-09-01 20:29:29 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2021-09-01 20:29:29 +0300
commit0d290223a6c77107b1c3988959e49279a8dafaba (patch)
tree2b250c9e698b84a38d17920c0712558226c93c78 /sound/soc/codecs
parentea7b4244b3656ca33b19a950f092b5bbc718b40c (diff)
parenta8729efbbb847f6ea9b06e73491ec8ddb560465e (diff)
downloadlinux-0d290223a6c77107b1c3988959e49279a8dafaba.tar.xz
Merge tag 'sound-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai: "There are a few intensive changes in ALSA core side at this time that helped with significant code reduction. Meanwhile we keep getting new stuff, so the total size still grows... Anyway, the below are some highlights in this development cycle. ALSA core: - New helpers to manage page allocations and card object with devres - Refactoring for memory allocation with wc-pages - A new PCM hardware flag SNDRV_PCM_INFO_EXPLICIT_SYNC for controlling the explicit sync of the stream control; it'll be used for ASoC SOF and non-coherent memory in future ASoC: - Lots of cleanups and improvements to the Intel drivers, including some new systems support - New support for AMD Vangoh, CUI CMM-4030D-261, Mediatek Mt8195, Renesas RZ/G2L Mediatek Mt8195, RealTek RT101P, Renesas RZ/G2L, Rockchip RK3568 S/PDIF USB-audio: - Re-organized the quirk handling and a new option quirk_flags - Fix for a regression in 5.14 code change for JACK - Quirks for Sony WALKMAN, Digidesign mbox HD-audio: - Enhanced support for CS8409 codec - More consistent shutdown behavior with the runtime PM - The model option can accept the PCI or codec SSID as an alias - Quirks for ASUS ROG, HP Spectre x360 Others: - Lots of code reduction in legacy drivers with devres helpers - FireWire MOTU 896HD support" * tag 'sound-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (421 commits) ASoC: Revert PCM trigger changes ALSA: usb-audio: Add lowlatency module option ALSA: hda/cs8409: Initialize Codec only in init fixup. ALSA: hda/cs8409: Ensure Type Detection is only run on startup when necessary ALSA: usb-audio: Work around for XRUN with low latency playback ALSA: pcm: fix divide error in snd_pcm_lib_ioctl ASoC: soc-pcm: test refcount before triggering ASoC: soc-pcm: protect BE dailink state changes in trigger ASoC: wcd9335: Disable irq on slave ports in the remove function ASoC: wcd9335: Fix a memory leak in the error handling path of the probe function ASoC: wcd9335: Fix a double irq free in the remove function ALSA: hda: Disable runtime resume at shutdown ASoC: rockchip: i2s: Add support for frame inversion ASoC: dt-bindings: rockchip: Add compatible strings for more SoCs ASoC: rockchip: i2s: Add compatible for more SoCs ASoC: rockchip: i2s: Make playback/capture optional ASoC: rockchip: i2s: Fixup config for DAIFMT_DSP_A/B ASoC: dt-bindings: rockchip: Document reset property for i2s ASoC: rockchip: i2s: Fix regmap_ops hang ASoC: rockchip: i2s: Improve dma data transfer efficiency ...
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/Kconfig3
-rw-r--r--sound/soc/codecs/ad193x.c30
-rw-r--r--sound/soc/codecs/ad193x.h4
-rw-r--r--sound/soc/codecs/cs42l42.c28
-rw-r--r--sound/soc/codecs/cx20442.c8
-rw-r--r--sound/soc/codecs/ics43432.c4
-rw-r--r--sound/soc/codecs/lpass-rx-macro.c65
-rw-r--r--sound/soc/codecs/max98090.c4
-rw-r--r--sound/soc/codecs/max98390.c26
-rw-r--r--sound/soc/codecs/max98390.h1
-rw-r--r--sound/soc/codecs/mt6359-accdet.c25
-rw-r--r--sound/soc/codecs/rt1015.c46
-rw-r--r--sound/soc/codecs/rt1015.h2
-rw-r--r--sound/soc/codecs/rt1015p.c2
-rw-r--r--sound/soc/codecs/rt5514.c2
-rw-r--r--sound/soc/codecs/rt5640.c133
-rw-r--r--sound/soc/codecs/rt5640.h6
-rw-r--r--sound/soc/codecs/rt5682-i2c.c15
-rw-r--r--sound/soc/codecs/rt5682.c57
-rw-r--r--sound/soc/codecs/tlv320aic32x4.c10
-rw-r--r--sound/soc/codecs/wcd9335.c23
-rw-r--r--sound/soc/codecs/wcd938x.c854
-rw-r--r--sound/soc/codecs/wcd938x.h1
-rw-r--r--sound/soc/codecs/wm_adsp.c9
24 files changed, 1126 insertions, 232 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 9ff1600ca823..82ee233a269d 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -848,7 +848,7 @@ config SND_SOC_HDAC_HDA
select SND_HDA
config SND_SOC_ICS43432
- tristate
+ tristate "ICS43423 and compatible i2s microphones"
config SND_SOC_INNO_RK3036
tristate "Inno codec driver for RK3036 SoC"
@@ -1582,6 +1582,7 @@ config SND_SOC_WCD938X
config SND_SOC_WCD938X_SDW
tristate "WCD9380/WCD9385 Codec - SDW"
select SND_SOC_WCD938X
+ select SND_SOC_WCD_MBHC
depends on SOUNDWIRE
select REGMAP_SOUNDWIRE
help
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index f37ab7eda615..278a55af158b 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -316,6 +316,13 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
int word_len = 0, master_rate = 0;
struct snd_soc_component *component = dai->component;
struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component);
+ bool is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ u8 dacc0;
+
+ dev_dbg(dai->dev, "%s() rate=%u format=%#x width=%u channels=%u\n",
+ __func__, params_rate(params), params_format(params),
+ params_width(params), params_channels(params));
+
/* bit size */
switch (params_width(params)) {
@@ -346,6 +353,25 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
break;
}
+ if (is_playback) {
+ switch (params_rate(params)) {
+ case 48000:
+ dacc0 = AD193X_DAC_SR_48;
+ break;
+ case 96000:
+ dacc0 = AD193X_DAC_SR_96;
+ break;
+ case 192000:
+ dacc0 = AD193X_DAC_SR_192;
+ break;
+ default:
+ dev_err(dai->dev, "invalid sampling rate: %d\n", params_rate(params));
+ return -EINVAL;
+ }
+
+ regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL0, AD193X_DAC_SR_MASK, dacc0);
+ }
+
regmap_update_bits(ad193x->regmap, AD193X_PLL_CLK_CTRL0,
AD193X_PLL_INPUT_MASK, master_rate);
@@ -385,7 +411,7 @@ static struct snd_soc_dai_driver ad193x_dai = {
.stream_name = "Playback",
.channels_min = 2,
.channels_max = 8,
- .rates = SNDRV_PCM_RATE_48000,
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
},
@@ -407,7 +433,7 @@ static struct snd_soc_dai_driver ad193x_no_adc_dai = {
.stream_name = "Playback",
.channels_min = 2,
.channels_max = 8,
- .rates = SNDRV_PCM_RATE_48000,
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
},
diff --git a/sound/soc/codecs/ad193x.h b/sound/soc/codecs/ad193x.h
index 377854712c20..61f4648861d5 100644
--- a/sound/soc/codecs/ad193x.h
+++ b/sound/soc/codecs/ad193x.h
@@ -37,6 +37,10 @@ int ad193x_probe(struct device *dev, struct regmap *regmap,
#define AD193X_PLL_CLK_SRC_MCLK (1 << 1)
#define AD193X_DAC_CTRL0 0x02
#define AD193X_DAC_POWERDOWN 0x01
+#define AD193X_DAC_SR_MASK 0x06
+#define AD193X_DAC_SR_48 (0 << 1)
+#define AD193X_DAC_SR_96 (1 << 1)
+#define AD193X_DAC_SR_192 (2 << 1)
#define AD193X_DAC_SERFMT_MASK 0xC0
#define AD193X_DAC_SERFMT_STEREO (0 << 6)
#define AD193X_DAC_SERFMT_TDM (1 << 6)
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
index 99c022be94a6..fb1e4c33e27d 100644
--- a/sound/soc/codecs/cs42l42.c
+++ b/sound/soc/codecs/cs42l42.c
@@ -586,6 +586,7 @@ struct cs42l42_pll_params {
* Table 4-5 from the Datasheet
*/
static const struct cs42l42_pll_params pll_ratio_table[] = {
+ { 1411200, 0, 1, 0x00, 0x80, 0x000000, 0x03, 0x10, 11289600, 128, 2},
{ 1536000, 0, 1, 0x00, 0x7D, 0x000000, 0x03, 0x10, 12000000, 125, 2},
{ 2304000, 0, 1, 0x00, 0x55, 0xC00000, 0x02, 0x10, 12288000, 85, 2},
{ 2400000, 0, 1, 0x00, 0x50, 0x000000, 0x03, 0x10, 12000000, 80, 2},
@@ -843,6 +844,13 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream,
if (channels == 1)
cs42l42->bclk *= 2;
+ /*
+ * Assume 24-bit samples are in 32-bit slots, to prevent SCLK being
+ * more than assumed (which would result in overclocking).
+ */
+ if (params_width(params) == 24)
+ cs42l42->bclk = (cs42l42->bclk / 3) * 4;
+
switch(substream->stream) {
case SNDRV_PCM_STREAM_CAPTURE:
if (channels == 2) {
@@ -890,10 +898,23 @@ static int cs42l42_set_sysclk(struct snd_soc_dai *dai,
{
struct snd_soc_component *component = dai->component;
struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
+ int i;
- cs42l42->sclk = freq;
+ if (freq == 0) {
+ cs42l42->sclk = 0;
+ return 0;
+ }
- return 0;
+ for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) {
+ if (pll_ratio_table[i].sclk == freq) {
+ cs42l42->sclk = freq;
+ return 0;
+ }
+ }
+
+ dev_err(component->dev, "SCLK %u not supported\n", freq);
+
+ return -EINVAL;
}
static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
@@ -2106,4 +2127,7 @@ MODULE_DESCRIPTION("ASoC CS42L42 driver");
MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>");
MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
MODULE_AUTHOR("Michael White, Cirrus Logic Inc, <michael.white@cirrus.com>");
+MODULE_AUTHOR("Lucas Tanure <tanureal@opensource.cirrus.com>");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_AUTHOR("Vitaly Rodionov <vitalyr@opensource.cirrus.com>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c
index ec8d6e74b467..13258f3ca9aa 100644
--- a/sound/soc/codecs/cx20442.c
+++ b/sound/soc/codecs/cx20442.c
@@ -206,7 +206,7 @@ static int cx20442_write(struct snd_soc_component *component, unsigned int reg,
*/
/* Modem init: echo off, digital speaker off, quiet off, voice mode */
-static const char *v253_init = "ate0m0q0+fclass=8\r";
+static const char v253_init[] = "ate0m0q0+fclass=8\r";
/* Line discipline .open() */
static int v253_open(struct tty_struct *tty)
@@ -279,11 +279,6 @@ static void v253_receive(struct tty_struct *tty, const unsigned char *cp,
}
}
-/* Line discipline .write_wakeup() */
-static void v253_wakeup(struct tty_struct *tty)
-{
-}
-
struct tty_ldisc_ops v253_ops = {
.name = "cx20442",
.owner = THIS_MODULE,
@@ -291,7 +286,6 @@ struct tty_ldisc_ops v253_ops = {
.close = v253_close,
.hangup = v253_hangup,
.receive_buf = v253_receive,
- .write_wakeup = v253_wakeup,
};
EXPORT_SYMBOL_GPL(v253_ops);
diff --git a/sound/soc/codecs/ics43432.c b/sound/soc/codecs/ics43432.c
index 47e749f03940..de4c8460ab3d 100644
--- a/sound/soc/codecs/ics43432.c
+++ b/sound/soc/codecs/ics43432.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * I2S MEMS microphone driver for InvenSense ICS-43432
+ * I2S MEMS microphone driver for InvenSense ICS-43432 and similar
+ * MEMS-based microphones.
*
* - Non configurable.
* - I2S interface, 64 BCLs per frame, 32 bits per channel, 24 bit data
@@ -53,6 +54,7 @@ static int ics43432_probe(struct platform_device *pdev)
#ifdef CONFIG_OF
static const struct of_device_id ics43432_ids[] = {
{ .compatible = "invensense,ics43432", },
+ { .compatible = "cui,cmm-4030d-261", },
{ }
};
MODULE_DEVICE_TABLE(of, ics43432_ids);
diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c
index 3622961f7c2c..196b06898eeb 100644
--- a/sound/soc/codecs/lpass-rx-macro.c
+++ b/sound/soc/codecs/lpass-rx-macro.c
@@ -1722,42 +1722,43 @@ static int rx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
case RX_MACRO_AIF2_PB:
case RX_MACRO_AIF3_PB:
case RX_MACRO_AIF4_PB:
- for (j = 0; j < INTERP_MAX; j++) {
- reg = CDC_RX_RXn_RX_PATH_CTL(j);
- mix_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(j);
- dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(j);
-
- if (mute) {
- snd_soc_component_update_bits(component, reg,
- CDC_RX_PATH_PGA_MUTE_MASK,
- CDC_RX_PATH_PGA_MUTE_ENABLE);
- snd_soc_component_update_bits(component, mix_reg,
- CDC_RX_PATH_PGA_MUTE_MASK,
- CDC_RX_PATH_PGA_MUTE_ENABLE);
- } else {
- snd_soc_component_update_bits(component, reg,
- CDC_RX_PATH_PGA_MUTE_MASK, 0x0);
- snd_soc_component_update_bits(component, mix_reg,
- CDC_RX_PATH_PGA_MUTE_MASK, 0x0);
- }
-
- if (j == INTERP_AUX)
- dsm_reg = CDC_RX_RX2_RX_PATH_DSM_CTL;
+ for (j = 0; j < INTERP_MAX; j++) {
+ reg = CDC_RX_RXn_RX_PATH_CTL(j);
+ mix_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(j);
+ dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(j);
+
+ if (mute) {
+ snd_soc_component_update_bits(component, reg,
+ CDC_RX_PATH_PGA_MUTE_MASK,
+ CDC_RX_PATH_PGA_MUTE_ENABLE);
+ snd_soc_component_update_bits(component, mix_reg,
+ CDC_RX_PATH_PGA_MUTE_MASK,
+ CDC_RX_PATH_PGA_MUTE_ENABLE);
+ } else {
+ snd_soc_component_update_bits(component, reg,
+ CDC_RX_PATH_PGA_MUTE_MASK, 0x0);
+ snd_soc_component_update_bits(component, mix_reg,
+ CDC_RX_PATH_PGA_MUTE_MASK, 0x0);
+ }
- int_mux_cfg0 = CDC_RX_INP_MUX_RX_INT0_CFG0 + j * 8;
- int_mux_cfg1 = int_mux_cfg0 + 4;
- int_mux_cfg0_val = snd_soc_component_read(component, int_mux_cfg0);
- int_mux_cfg1_val = snd_soc_component_read(component, int_mux_cfg1);
+ if (j == INTERP_AUX)
+ dsm_reg = CDC_RX_RX2_RX_PATH_DSM_CTL;
- if (snd_soc_component_read(component, dsm_reg) & 0x01) {
- if (int_mux_cfg0_val || (int_mux_cfg1_val & 0xF0))
- snd_soc_component_update_bits(component, reg, 0x20, 0x20);
- if (int_mux_cfg1_val & 0x0F) {
- snd_soc_component_update_bits(component, reg, 0x20, 0x20);
- snd_soc_component_update_bits(component, mix_reg, 0x20, 0x20);
+ int_mux_cfg0 = CDC_RX_INP_MUX_RX_INT0_CFG0 + j * 8;
+ int_mux_cfg1 = int_mux_cfg0 + 4;
+ int_mux_cfg0_val = snd_soc_component_read(component, int_mux_cfg0);
+ int_mux_cfg1_val = snd_soc_component_read(component, int_mux_cfg1);
+
+ if (snd_soc_component_read(component, dsm_reg) & 0x01) {
+ if (int_mux_cfg0_val || (int_mux_cfg1_val & 0xF0))
+ snd_soc_component_update_bits(component, reg, 0x20, 0x20);
+ if (int_mux_cfg1_val & 0x0F) {
+ snd_soc_component_update_bits(component, reg, 0x20, 0x20);
+ snd_soc_component_update_bits(component, mix_reg, 0x20,
+ 0x20);
+ }
}
}
- }
break;
default:
break;
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index bc30a1dc7530..b45ec35cd63c 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -2158,13 +2158,11 @@ static void max98090_jack_work(struct work_struct *work)
msleep(50);
- reg = snd_soc_component_read(component, M98090_REG_JACK_STATUS);
+ snd_soc_component_read(component, M98090_REG_JACK_STATUS);
/* Weak pull up allows only insertion detection */
snd_soc_component_update_bits(component, M98090_REG_JACK_DETECT,
M98090_JDWK_MASK, M98090_JDWK_MASK);
- } else {
- reg = snd_soc_component_read(component, M98090_REG_JACK_STATUS);
}
reg = snd_soc_component_read(component, M98090_REG_JACK_STATUS);
diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c
index 94773ccee9d5..b392567c2b3e 100644
--- a/sound/soc/codecs/max98390.c
+++ b/sound/soc/codecs/max98390.c
@@ -765,17 +765,26 @@ static int max98390_dsm_init(struct snd_soc_component *component)
vendor = dmi_get_system_info(DMI_SYS_VENDOR);
product = dmi_get_system_info(DMI_PRODUCT_NAME);
- if (vendor && product) {
- snprintf(filename, sizeof(filename), "dsm_param_%s_%s.bin",
- vendor, product);
+ if (!strcmp(max98390->dsm_param_name, "default")) {
+ if (vendor && product) {
+ snprintf(filename, sizeof(filename),
+ "dsm_param_%s_%s.bin", vendor, product);
+ } else {
+ sprintf(filename, "dsm_param.bin");
+ }
} else {
- sprintf(filename, "dsm_param.bin");
+ snprintf(filename, sizeof(filename), "%s",
+ max98390->dsm_param_name);
}
ret = request_firmware(&fw, filename, component->dev);
if (ret) {
ret = request_firmware(&fw, "dsm_param.bin", component->dev);
- if (ret)
- goto err;
+ if (ret) {
+ ret = request_firmware(&fw, "dsmparam.bin",
+ component->dev);
+ if (ret)
+ goto err;
+ }
}
dev_dbg(component->dev,
@@ -1047,6 +1056,11 @@ static int max98390_i2c_probe(struct i2c_client *i2c,
__func__, max98390->ref_rdc_value,
max98390->ambient_temp_value);
+ ret = device_property_read_string(&i2c->dev, "maxim,dsm_param_name",
+ &max98390->dsm_param_name);
+ if (ret)
+ max98390->dsm_param_name = "default";
+
/* voltage/current slot configuration */
max98390_slot_config(i2c, max98390);
diff --git a/sound/soc/codecs/max98390.h b/sound/soc/codecs/max98390.h
index e31516717d3b..c250740f73a2 100644
--- a/sound/soc/codecs/max98390.h
+++ b/sound/soc/codecs/max98390.h
@@ -662,5 +662,6 @@ struct max98390_priv {
unsigned int i_l_slot;
unsigned int ref_rdc_value;
unsigned int ambient_temp_value;
+ const char *dsm_param_name;
};
#endif
diff --git a/sound/soc/codecs/mt6359-accdet.c b/sound/soc/codecs/mt6359-accdet.c
index 78314187d37e..6d3d170144a0 100644
--- a/sound/soc/codecs/mt6359-accdet.c
+++ b/sound/soc/codecs/mt6359-accdet.c
@@ -234,7 +234,7 @@ static void recover_eint_setting(struct mt6359_accdet *priv)
static void mt6359_accdet_recover_jd_setting(struct mt6359_accdet *priv)
{
- int ret = 0;
+ int ret;
unsigned int value = 0;
regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR,
@@ -461,7 +461,7 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data)
{
struct mt6359_accdet *priv = data;
unsigned int irq_val = 0, val = 0, value = 0;
- int ret = 0;
+ int ret;
mutex_lock(&priv->res_lock);
regmap_read(priv->regmap, ACCDET_IRQ_ADDR, &irq_val);
@@ -551,7 +551,7 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data)
static int mt6359_accdet_parse_dt(struct mt6359_accdet *priv)
{
- int ret = 0;
+ int ret;
struct device *dev = priv->dev;
struct device_node *node = NULL;
int pwm_deb[15] = {0};
@@ -926,7 +926,7 @@ static int mt6359_accdet_probe(struct platform_device *pdev)
{
struct mt6359_accdet *priv;
struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);
- int ret = 0;
+ int ret;
dev_dbg(&pdev->dev, "%s(), dev name %s\n",
__func__, dev_name(&pdev->dev));
@@ -1057,22 +1057,7 @@ static struct platform_driver mt6359_accdet_driver = {
.probe = mt6359_accdet_probe,
};
-static int __init mt6359_accdet_driver_init(void)
-{
- int ret = 0;
-
- ret = platform_driver_register(&mt6359_accdet_driver);
- if (ret)
- return -ENODEV;
- return 0;
-}
-
-static void __exit mt6359_accdet_driver_exit(void)
-{
- platform_driver_unregister(&mt6359_accdet_driver);
-}
-module_init(mt6359_accdet_driver_init);
-module_exit(mt6359_accdet_driver_exit);
+module_platform_driver(mt6359_accdet_driver)
/* Module information */
MODULE_DESCRIPTION("MT6359 ALSA SoC codec jack driver");
diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c
index 9238f12999aa..c0c5952cdff7 100644
--- a/sound/soc/codecs/rt1015.c
+++ b/sound/soc/codecs/rt1015.c
@@ -547,31 +547,6 @@ static int rt1015_bypass_boost_put(struct snd_kcontrol *kcontrol,
return 0;
}
-static void rt1015_flush_work(struct work_struct *work)
-{
- struct rt1015_priv *rt1015 = container_of(work, struct rt1015_priv,
- flush_work.work);
- struct snd_soc_component *component = rt1015->component;
- unsigned int val, i;
-
- for (i = 0; i < 200; ++i) {
- usleep_range(1000, 1500);
- dev_dbg(component->dev, "Flush DAC (retry:%u)\n", i);
- regmap_read(rt1015->regmap, RT1015_CLK_DET, &val);
- if (val & 0x800)
- break;
- }
-
- regmap_write(rt1015->regmap, RT1015_SYS_RST1, 0x0597);
- regmap_write(rt1015->regmap, RT1015_SYS_RST1, 0x05f7);
- regmap_write(rt1015->regmap, RT1015_MAN_I2C, 0x0028);
-
- if (val & 0x800)
- dev_dbg(component->dev, "Flush DAC completed.\n");
- else
- dev_warn(component->dev, "Fail to flush DAC data.\n");
-}
-
static const struct snd_kcontrol_new rt1015_snd_controls[] = {
SOC_SINGLE_TLV("DAC Playback Volume", RT1015_DAC1, RT1015_DAC_VOL_SFT,
127, 0, dac_vol_tlv),
@@ -630,10 +605,6 @@ static int r1015_dac_event(struct snd_soc_dapm_widget *w,
}
break;
- case SND_SOC_DAPM_POST_PMU:
- regmap_write(rt1015->regmap, RT1015_MAN_I2C, 0x00a8);
- break;
-
case SND_SOC_DAPM_POST_PMD:
if (rt1015->bypass_boost == RT1015_Enable_Boost) {
snd_soc_component_write(component,
@@ -653,8 +624,6 @@ static int r1015_dac_event(struct snd_soc_dapm_widget *w,
RT1015_SYS_RST2, 0x0b9a);
}
rt1015->dac_is_used = 0;
-
- cancel_delayed_work_sync(&rt1015->flush_work);
break;
default:
@@ -687,8 +656,6 @@ static int rt1015_amp_drv_event(struct snd_soc_dapm_widget *w,
}
break;
case SND_SOC_DAPM_POST_PMU:
- if (rt1015->hw_config == RT1015_HW_28)
- schedule_delayed_work(&rt1015->flush_work, msecs_to_jiffies(10));
msleep(rt1015->pdata.power_up_delay_ms);
break;
default:
@@ -702,7 +669,7 @@ static const struct snd_soc_dapm_widget rt1015_dapm_widgets[] = {
NULL, 0),
SND_SOC_DAPM_AIF_IN("AIFRX", "AIF Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0,
- r1015_dac_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ r1015_dac_event, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_OUT_DRV_E("Amp Drv", SND_SOC_NOPM, 0, 0, NULL, 0,
rt1015_amp_drv_event, SND_SOC_DAPM_PRE_PMU |
@@ -722,7 +689,7 @@ static int rt1015_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_component *component = dai->component;
struct rt1015_priv *rt1015 = snd_soc_component_get_drvdata(component);
- int pre_div, bclk_ms, frame_size, lrck;
+ int pre_div, frame_size, lrck;
unsigned int val_len = 0;
lrck = params_rate(params);
@@ -739,10 +706,7 @@ static int rt1015_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- bclk_ms = frame_size > 32;
-
- dev_dbg(component->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
- bclk_ms, pre_div, dai->id);
+ dev_dbg(component->dev, "pre_div is %d for iis %d\n", pre_div, dai->id);
dev_dbg(component->dev, "lrck is %dHz and pre_div is %d for iis %d\n",
lrck, pre_div, dai->id);
@@ -1028,7 +992,6 @@ static int rt1015_probe(struct snd_soc_component *component)
snd_soc_component_get_drvdata(component);
rt1015->component = component;
- INIT_DELAYED_WORK(&rt1015->flush_work, rt1015_flush_work);
return 0;
}
@@ -1037,7 +1000,6 @@ static void rt1015_remove(struct snd_soc_component *component)
{
struct rt1015_priv *rt1015 = snd_soc_component_get_drvdata(component);
- cancel_delayed_work_sync(&rt1015->flush_work);
regmap_write(rt1015->regmap, RT1015_RESET, 0);
}
@@ -1180,8 +1142,6 @@ static int rt1015_i2c_probe(struct i2c_client *i2c,
return ret;
}
- rt1015->hw_config = (i2c->addr == 0x29) ? RT1015_HW_29 : RT1015_HW_28;
-
ret = regmap_read(rt1015->regmap, RT1015_DEVICE_ID, &val);
if (ret) {
dev_err(&i2c->dev,
diff --git a/sound/soc/codecs/rt1015.h b/sound/soc/codecs/rt1015.h
index 14344532048e..c9f636af7fd1 100644
--- a/sound/soc/codecs/rt1015.h
+++ b/sound/soc/codecs/rt1015.h
@@ -444,8 +444,6 @@ struct rt1015_priv {
int bypass_boost;
int dac_is_used;
int cali_done;
- int hw_config;
- struct delayed_work flush_work;
};
#endif /* __RT1015_H__ */
diff --git a/sound/soc/codecs/rt1015p.c b/sound/soc/codecs/rt1015p.c
index 40f2063aefbe..415cfb3b2f0d 100644
--- a/sound/soc/codecs/rt1015p.c
+++ b/sound/soc/codecs/rt1015p.c
@@ -127,6 +127,7 @@ static int rt1015p_platform_probe(struct platform_device *pdev)
#ifdef CONFIG_OF
static const struct of_device_id rt1015p_device_id[] = {
{ .compatible = "realtek,rt1015p" },
+ { .compatible = "realtek,rt1019p" },
{}
};
MODULE_DEVICE_TABLE(of, rt1015p_device_id);
@@ -135,6 +136,7 @@ MODULE_DEVICE_TABLE(of, rt1015p_device_id);
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt1015p_acpi_match[] = {
{ "RTL1015", 0},
+ { "RTL1019", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, rt1015p_acpi_match);
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c
index 7081142a355e..4b1ad5054e8d 100644
--- a/sound/soc/codecs/rt5514.c
+++ b/sound/soc/codecs/rt5514.c
@@ -494,7 +494,7 @@ static const struct snd_kcontrol_new rt5514_sto2_dmic_mux =
*/
static int rt5514_calc_dmic_clk(struct snd_soc_component *component, int rate)
{
- int div[] = {2, 3, 4, 8, 12, 16, 24, 32};
+ static const int div[] = {2, 3, 4, 8, 12, 16, 24, 32};
int i;
if (rate < 1000000 * div[0]) {
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 9523f4b5c800..cd1db5caabad 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -2093,7 +2093,7 @@ int rt5640_sel_asrc_clk_src(struct snd_soc_component *component,
}
EXPORT_SYMBOL_GPL(rt5640_sel_asrc_clk_src);
-static void rt5640_enable_micbias1_for_ovcd(struct snd_soc_component *component)
+void rt5640_enable_micbias1_for_ovcd(struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
@@ -2105,8 +2105,9 @@ static void rt5640_enable_micbias1_for_ovcd(struct snd_soc_component *component)
snd_soc_dapm_sync_unlocked(dapm);
snd_soc_dapm_mutex_unlock(dapm);
}
+EXPORT_SYMBOL_GPL(rt5640_enable_micbias1_for_ovcd);
-static void rt5640_disable_micbias1_for_ovcd(struct snd_soc_component *component)
+void rt5640_disable_micbias1_for_ovcd(struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
@@ -2117,6 +2118,7 @@ static void rt5640_disable_micbias1_for_ovcd(struct snd_soc_component *component
snd_soc_dapm_sync_unlocked(dapm);
snd_soc_dapm_mutex_unlock(dapm);
}
+EXPORT_SYMBOL_GPL(rt5640_disable_micbias1_for_ovcd);
static void rt5640_enable_micbias1_ovcd_irq(struct snd_soc_component *component)
{
@@ -2241,7 +2243,7 @@ static void rt5640_button_press_work(struct work_struct *work)
schedule_delayed_work(&rt5640->bp_work, msecs_to_jiffies(BP_POLL_TIME));
}
-static int rt5640_detect_headset(struct snd_soc_component *component)
+int rt5640_detect_headset(struct snd_soc_component *component, struct gpio_desc *hp_det_gpio)
{
int i, headset_count = 0, headphone_count = 0;
@@ -2259,8 +2261,13 @@ static int rt5640_detect_headset(struct snd_soc_component *component)
msleep(JACK_SETTLE_TIME);
/* Check the jack is still connected before checking ovcd */
- if (!rt5640_jack_inserted(component))
- return 0;
+ if (hp_det_gpio) {
+ if (gpiod_get_value_cansleep(hp_det_gpio))
+ return 0;
+ } else {
+ if (!rt5640_jack_inserted(component))
+ return 0;
+ }
if (rt5640_micbias1_ovcd(component)) {
/*
@@ -2285,6 +2292,7 @@ static int rt5640_detect_headset(struct snd_soc_component *component)
dev_err(component->dev, "Error detecting headset vs headphones, bad contact?, assuming headphones\n");
return SND_JACK_HEADPHONE;
}
+EXPORT_SYMBOL_GPL(rt5640_detect_headset);
static void rt5640_jack_work(struct work_struct *work)
{
@@ -2309,7 +2317,7 @@ static void rt5640_jack_work(struct work_struct *work)
/* Jack inserted */
WARN_ON(rt5640->ovcd_irq_enabled);
rt5640_enable_micbias1_for_ovcd(component);
- status = rt5640_detect_headset(component);
+ status = rt5640_detect_headset(component, NULL);
if (status == SND_JACK_HEADSET) {
/* Enable ovcd IRQ for button press detect. */
rt5640_enable_micbias1_ovcd_irq(component);
@@ -2362,10 +2370,59 @@ static void rt5640_cancel_work(void *data)
cancel_delayed_work_sync(&rt5640->bp_work);
}
+void rt5640_set_ovcd_params(struct snd_soc_component *component)
+{
+ struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+
+ snd_soc_component_write(component, RT5640_PR_BASE + RT5640_BIAS_CUR4,
+ 0xa800 | rt5640->ovcd_sf);
+
+ snd_soc_component_update_bits(component, RT5640_MICBIAS,
+ RT5640_MIC1_OVTH_MASK | RT5640_MIC1_OVCD_MASK,
+ rt5640->ovcd_th | RT5640_MIC1_OVCD_EN);
+
+ /*
+ * The over-current-detect is only reliable in detecting the absence
+ * of over-current, when the mic-contact in the jack is short-circuited,
+ * the hardware periodically retries if it can apply the bias-current
+ * leading to the ovcd status flip-flopping 1-0-1 with it being 0 about
+ * 10% of the time, as we poll the ovcd status bit we might hit that
+ * 10%, so we enable sticky mode and when checking OVCD we clear the
+ * status, msleep() a bit and then check to get a reliable reading.
+ */
+ snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2,
+ RT5640_MB1_OC_STKY_MASK, RT5640_MB1_OC_STKY_EN);
+}
+EXPORT_SYMBOL_GPL(rt5640_set_ovcd_params);
+
+static void rt5640_disable_jack_detect(struct snd_soc_component *component)
+{
+ struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+
+ /*
+ * soc_remove_component() force-disables jack and thus rt5640->jack
+ * could be NULL at the time of driver's module unloading.
+ */
+ if (!rt5640->jack)
+ return;
+
+ free_irq(rt5640->irq, rt5640);
+ rt5640_cancel_work(rt5640);
+
+ if (rt5640->jack->status & SND_JACK_MICROPHONE) {
+ rt5640_disable_micbias1_ovcd_irq(component);
+ rt5640_disable_micbias1_for_ovcd(component);
+ snd_soc_jack_report(rt5640->jack, 0, SND_JACK_BTN_0);
+ }
+
+ rt5640->jack = NULL;
+}
+
static void rt5640_enable_jack_detect(struct snd_soc_component *component,
struct snd_soc_jack *jack)
{
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+ int ret;
/* Select JD-source */
snd_soc_component_update_bits(component, RT5640_JD_CTRL,
@@ -2385,24 +2442,7 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component,
/* Enabling jd2 in general control 2 */
snd_soc_component_write(component, RT5640_DUMMY2, 0x4001);
- snd_soc_component_write(component, RT5640_PR_BASE + RT5640_BIAS_CUR4,
- 0xa800 | rt5640->ovcd_sf);
-
- snd_soc_component_update_bits(component, RT5640_MICBIAS,
- RT5640_MIC1_OVTH_MASK | RT5640_MIC1_OVCD_MASK,
- rt5640->ovcd_th | RT5640_MIC1_OVCD_EN);
-
- /*
- * The over-current-detect is only reliable in detecting the absence
- * of over-current, when the mic-contact in the jack is short-circuited,
- * the hardware periodically retries if it can apply the bias-current
- * leading to the ovcd status flip-flopping 1-0-1 with it being 0 about
- * 10% of the time, as we poll the ovcd status bit we might hit that
- * 10%, so we enable sticky mode and when checking OVCD we clear the
- * status, msleep() a bit and then check to get a reliable reading.
- */
- snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2,
- RT5640_MB1_OC_STKY_MASK, RT5640_MB1_OC_STKY_EN);
+ rt5640_set_ovcd_params(component);
/*
* All IRQs get or-ed together, so we need the jack IRQ to report 0
@@ -2423,32 +2463,19 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component,
rt5640_enable_micbias1_ovcd_irq(component);
}
- enable_irq(rt5640->irq);
- /* sync initial jack state */
- queue_work(system_long_wq, &rt5640->jack_work);
-}
-
-static void rt5640_disable_jack_detect(struct snd_soc_component *component)
-{
- struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
-
- /*
- * soc_remove_component() force-disables jack and thus rt5640->jack
- * could be NULL at the time of driver's module unloading.
- */
- if (!rt5640->jack)
+ ret = request_irq(rt5640->irq, rt5640_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "rt5640", rt5640);
+ if (ret) {
+ dev_warn(component->dev, "Failed to reguest IRQ %d: %d\n", rt5640->irq, ret);
+ rt5640->irq = -ENXIO;
+ /* Undo above settings */
+ rt5640_disable_jack_detect(component);
return;
-
- disable_irq(rt5640->irq);
- rt5640_cancel_work(rt5640);
-
- if (rt5640->jack->status & SND_JACK_MICROPHONE) {
- rt5640_disable_micbias1_ovcd_irq(component);
- rt5640_disable_micbias1_for_ovcd(component);
- snd_soc_jack_report(rt5640->jack, 0, SND_JACK_BTN_0);
}
- rt5640->jack = NULL;
+ /* sync initial jack state */
+ queue_work(system_long_wq, &rt5640->jack_work);
}
static int rt5640_set_jack(struct snd_soc_component *component,
@@ -2836,18 +2863,6 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
if (ret)
return ret;
- ret = devm_request_irq(&i2c->dev, rt5640->irq, rt5640_irq,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
- | IRQF_ONESHOT, "rt5640", rt5640);
- if (ret == 0) {
- /* Gets re-enabled by rt5640_set_jack() */
- disable_irq(rt5640->irq);
- } else {
- dev_warn(&i2c->dev, "Failed to reguest IRQ %d: %d\n",
- rt5640->irq, ret);
- rt5640->irq = -ENXIO;
- }
-
return devm_snd_soc_register_component(&i2c->dev,
&soc_component_dev_rt5640,
rt5640_dai, ARRAY_SIZE(rt5640_dai));
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h
index 4fd47f2b936b..2c28f83e338a 100644
--- a/sound/soc/codecs/rt5640.h
+++ b/sound/soc/codecs/rt5640.h
@@ -10,6 +10,7 @@
#define _RT5640_H
#include <linux/clk.h>
+#include <linux/gpio/consumer.h>
#include <linux/workqueue.h>
#include <dt-bindings/sound/rt5640.h>
@@ -2157,4 +2158,9 @@ int rt5640_dmic_enable(struct snd_soc_component *component,
int rt5640_sel_asrc_clk_src(struct snd_soc_component *component,
unsigned int filter_mask, unsigned int clk_src);
+void rt5640_set_ovcd_params(struct snd_soc_component *component);
+void rt5640_enable_micbias1_for_ovcd(struct snd_soc_component *component);
+void rt5640_disable_micbias1_for_ovcd(struct snd_soc_component *component);
+int rt5640_detect_headset(struct snd_soc_component *component, struct gpio_desc *hp_det_gpio);
+
#endif
diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c
index 4a56a52adab5..b9d5d7a0975b 100644
--- a/sound/soc/codecs/rt5682-i2c.c
+++ b/sound/soc/codecs/rt5682-i2c.c
@@ -117,6 +117,13 @@ static struct snd_soc_dai_driver rt5682_dai[] = {
},
};
+static void rt5682_i2c_disable_regulators(void *data)
+{
+ struct rt5682_priv *rt5682 = data;
+
+ regulator_bulk_disable(ARRAY_SIZE(rt5682->supplies), rt5682->supplies);
+}
+
static int rt5682_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -157,6 +164,11 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
return ret;
}
+ ret = devm_add_action_or_reset(&i2c->dev, rt5682_i2c_disable_regulators,
+ rt5682);
+ if (ret)
+ return ret;
+
ret = regulator_bulk_enable(ARRAY_SIZE(rt5682->supplies),
rt5682->supplies);
if (ret) {
@@ -282,10 +294,7 @@ static void rt5682_i2c_shutdown(struct i2c_client *client)
static int rt5682_i2c_remove(struct i2c_client *client)
{
- struct rt5682_priv *rt5682 = i2c_get_clientdata(client);
-
rt5682_i2c_shutdown(client);
- regulator_bulk_disable(ARRAY_SIZE(rt5682->supplies), rt5682->supplies);
return 0;
}
diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
index 51ecaa2abcd1..e822fa1b9d4b 100644
--- a/sound/soc/codecs/rt5682.c
+++ b/sound/soc/codecs/rt5682.c
@@ -43,8 +43,9 @@ static const struct reg_sequence patch_list[] = {
{RT5682_DAC_ADC_DIG_VOL1, 0xa020},
{RT5682_I2C_CTRL, 0x000f},
{RT5682_PLL2_INTERNAL, 0x8266},
- {RT5682_SAR_IL_CMD_3, 0x8365},
- {RT5682_SAR_IL_CMD_6, 0x0180},
+ {RT5682_SAR_IL_CMD_1, 0x22b7},
+ {RT5682_SAR_IL_CMD_3, 0x0365},
+ {RT5682_SAR_IL_CMD_6, 0x0110},
};
void rt5682_apply_patch_list(struct rt5682_priv *rt5682, struct device *dev)
@@ -1727,8 +1728,6 @@ static const struct snd_soc_dapm_widget rt5682_dapm_widgets[] = {
SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", RT5682_STO1_ADC_DIG_VOL,
RT5682_R_MUTE_SFT, 1, rt5682_sto1_adc_r_mix,
ARRAY_SIZE(rt5682_sto1_adc_r_mix)),
- SND_SOC_DAPM_SUPPLY("BTN Detection Mode", RT5682_SAR_IL_CMD_1,
- 14, 1, NULL, 0),
/* ADC PGA */
SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -1899,8 +1898,6 @@ static const struct snd_soc_dapm_route rt5682_dapm_routes[] = {
{"Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux"},
{"Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter"},
- {"ADC Stereo1 Filter", NULL, "BTN Detection Mode"},
-
{"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXL"},
{"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR"},
@@ -2916,10 +2913,47 @@ static void rt5682_remove(struct snd_soc_component *component)
static int rt5682_suspend(struct snd_soc_component *component)
{
struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+ unsigned int val;
if (rt5682->is_sdw)
return 0;
+ cancel_delayed_work_sync(&rt5682->jack_detect_work);
+ cancel_delayed_work_sync(&rt5682->jd_check_work);
+ if (rt5682->hs_jack && rt5682->jack_type == SND_JACK_HEADSET) {
+ snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
+ RT5682_MB1_PATH_MASK | RT5682_MB2_PATH_MASK,
+ RT5682_CTRL_MB1_REG | RT5682_CTRL_MB2_REG);
+ val = snd_soc_component_read(component,
+ RT5682_CBJ_CTRL_2) & RT5682_JACK_TYPE_MASK;
+
+ switch (val) {
+ case 0x1:
+ snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
+ RT5682_SAR_SEL_MB1_MASK | RT5682_SAR_SEL_MB2_MASK,
+ RT5682_SAR_SEL_MB1_NOSEL | RT5682_SAR_SEL_MB2_SEL);
+ break;
+ case 0x2:
+ snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
+ RT5682_SAR_SEL_MB1_MASK | RT5682_SAR_SEL_MB2_MASK,
+ RT5682_SAR_SEL_MB1_SEL | RT5682_SAR_SEL_MB2_NOSEL);
+ break;
+ default:
+ break;
+ }
+
+ snd_soc_component_update_bits(component, RT5682_PWR_ANLG_3,
+ RT5682_PWR_CBJ, 0);
+
+ /* enter SAR ADC power saving mode */
+ snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
+ RT5682_SAR_BUTT_DET_MASK | RT5682_SAR_BUTDET_MODE_MASK |
+ RT5682_SAR_BUTDET_RST_MASK | RT5682_SAR_SEL_MB1_MB2_MASK, 0);
+ snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
+ RT5682_SAR_BUTT_DET_MASK | RT5682_SAR_BUTDET_MODE_MASK | RT5682_SAR_BUTDET_RST_MASK,
+ RT5682_SAR_BUTT_DET_EN | RT5682_SAR_BUTDET_POW_SAV | RT5682_SAR_BUTDET_RST_NORMAL);
+ }
+
regcache_cache_only(rt5682->regmap, true);
regcache_mark_dirty(rt5682->regmap);
return 0;
@@ -2935,6 +2969,17 @@ static int rt5682_resume(struct snd_soc_component *component)
regcache_cache_only(rt5682->regmap, false);
regcache_sync(rt5682->regmap);
+ if (rt5682->hs_jack && rt5682->jack_type == SND_JACK_HEADSET) {
+ snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
+ RT5682_SAR_BUTDET_MODE_MASK | RT5682_SAR_SEL_MB1_MB2_MASK,
+ RT5682_SAR_BUTDET_POW_NORM | RT5682_SAR_SEL_MB1_MB2_AUTO);
+ snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
+ RT5682_MB1_PATH_MASK | RT5682_MB2_PATH_MASK,
+ RT5682_CTRL_MB1_FSM | RT5682_CTRL_MB2_FSM);
+ snd_soc_component_update_bits(component, RT5682_PWR_ANLG_3,
+ RT5682_PWR_CBJ, RT5682_PWR_CBJ);
+ }
+
mod_delayed_work(system_power_efficient_wq,
&rt5682->jack_detect_work, msecs_to_jiffies(250));
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 2e9175b37dc9..d39c7d52ecfd 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -714,7 +714,7 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component,
unsigned long adc_clock_rate, dac_clock_rate;
int ret;
- struct clk_bulk_data clocks[] = {
+ static struct clk_bulk_data clocks[] = {
{ .id = "pll" },
{ .id = "nadc" },
{ .id = "madc" },
@@ -878,7 +878,7 @@ static int aic32x4_set_bias_level(struct snd_soc_component *component,
{
int ret;
- struct clk_bulk_data clocks[] = {
+ static struct clk_bulk_data clocks[] = {
{ .id = "madc" },
{ .id = "mdac" },
{ .id = "bdiv" },
@@ -994,7 +994,7 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
u32 tmp_reg;
int ret;
- struct clk_bulk_data clocks[] = {
+ static struct clk_bulk_data clocks[] = {
{ .id = "codec_clkin" },
{ .id = "pll" },
{ .id = "bdiv" },
@@ -1131,7 +1131,7 @@ static struct snd_soc_dai_driver aic32x4_tas2505_dai = {
.playback = {
.stream_name = "Playback",
.channels_min = 1,
- .channels_max = 1,
+ .channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_96000,
.formats = AIC32X4_FORMATS,},
.ops = &aic32x4_ops,
@@ -1144,7 +1144,7 @@ static int aic32x4_tas2505_component_probe(struct snd_soc_component *component)
u32 tmp_reg;
int ret;
- struct clk_bulk_data clocks[] = {
+ static struct clk_bulk_data clocks[] = {
{ .id = "codec_clkin" },
{ .id = "pll" },
{ .id = "bdiv" },
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 86c92e03ea5d..d885ced34f60 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -4076,6 +4076,16 @@ static int wcd9335_setup_irqs(struct wcd9335_codec *wcd)
return ret;
}
+static void wcd9335_teardown_irqs(struct wcd9335_codec *wcd)
+{
+ int i;
+
+ /* disable interrupts on all slave ports */
+ for (i = 0; i < WCD9335_SLIM_NUM_PORT_REG; i++)
+ regmap_write(wcd->if_regmap, WCD9335_SLIM_PGD_PORT_INT_EN0 + i,
+ 0x00);
+}
+
static void wcd9335_cdc_sido_ccl_enable(struct wcd9335_codec *wcd,
bool ccl_flag)
{
@@ -4844,6 +4854,7 @@ static void wcd9335_codec_init(struct snd_soc_component *component)
static int wcd9335_codec_probe(struct snd_soc_component *component)
{
struct wcd9335_codec *wcd = dev_get_drvdata(component->dev);
+ int ret;
int i;
snd_soc_component_init_regmap(component, wcd->regmap);
@@ -4861,7 +4872,15 @@ static int wcd9335_codec_probe(struct snd_soc_component *component)
for (i = 0; i < NUM_CODEC_DAIS; i++)
INIT_LIST_HEAD(&wcd->dai[i].slim_ch_list);
- return wcd9335_setup_irqs(wcd);
+ ret = wcd9335_setup_irqs(wcd);
+ if (ret)
+ goto free_clsh_ctrl;
+
+ return 0;
+
+free_clsh_ctrl:
+ wcd_clsh_ctrl_free(wcd->clsh_ctrl);
+ return ret;
}
static void wcd9335_codec_remove(struct snd_soc_component *comp)
@@ -4869,7 +4888,7 @@ static void wcd9335_codec_remove(struct snd_soc_component *comp)
struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev);
wcd_clsh_ctrl_free(wcd->clsh_ctrl);
- free_irq(regmap_irq_get_virq(wcd->irq_data, WCD9335_IRQ_SLIMBUS), wcd);
+ wcd9335_teardown_irqs(wcd);
}
static int wcd9335_codec_set_sysclk(struct snd_soc_component *comp,
diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
index 2fcc97370be2..f0daf8defcf1 100644
--- a/sound/soc/codecs/wcd938x.c
+++ b/sound/soc/codecs/wcd938x.c
@@ -21,6 +21,7 @@
#include <linux/regulator/consumer.h>
#include "wcd-clsh-v2.h"
+#include "wcd-mbhc-v2.h"
#include "wcd938x.h"
#define WCD938X_MAX_MICBIAS (4)
@@ -173,6 +174,11 @@ struct wcd938x_priv {
struct device *rxdev;
struct device_node *rxnode, *txnode;
struct regmap *regmap;
+ struct mutex micb_lock;
+ /* mbhc module */
+ struct wcd_mbhc *wcd_mbhc;
+ struct wcd_mbhc_config mbhc_cfg;
+ struct wcd_mbhc_intr intr_ids;
struct wcd_clsh_ctrl *clsh_info;
struct irq_domain *virq;
struct regmap_irq_chip *wcd_regmap_irq_chip;
@@ -201,24 +207,70 @@ struct wcd938x_priv {
bool bcs_dis;
};
-enum {
- MIC_BIAS_1 = 1,
- MIC_BIAS_2,
- MIC_BIAS_3,
- MIC_BIAS_4
-};
-
-enum {
- MICB_PULLUP_ENABLE,
- MICB_PULLUP_DISABLE,
- MICB_ENABLE,
- MICB_DISABLE,
-};
-
static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800);
static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(line_gain, 600, -3000);
static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(analog_gain, 0, 3000);
+struct wcd938x_mbhc_zdet_param {
+ u16 ldo_ctl;
+ u16 noff;
+ u16 nshift;
+ u16 btn5;
+ u16 btn6;
+ u16 btn7;
+};
+
+static struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
+ WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD938X_ANA_MBHC_MECH, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD938X_ANA_MBHC_MECH, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD938X_ANA_MBHC_MECH, 0x20),
+ WCD_MBHC_FIELD(WCD_MBHC_MIC_CLAMP_CTL, WCD938X_MBHC_NEW_PLUG_DETECT_CTL, 0x30),
+ WCD_MBHC_FIELD(WCD_MBHC_ELECT_DETECTION_TYPE, WCD938X_ANA_MBHC_ELECT, 0x08),
+ WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_CTRL, WCD938X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x1F),
+ WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, WCD938X_ANA_MBHC_MECH, 0x04),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_PLUG_TYPE, WCD938X_ANA_MBHC_MECH, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_GND_PLUG_TYPE, WCD938X_ANA_MBHC_MECH, 0x08),
+ WCD_MBHC_FIELD(WCD_MBHC_SW_HPH_LP_100K_TO_GND, WCD938X_ANA_MBHC_MECH, 0x01),
+ WCD_MBHC_FIELD(WCD_MBHC_ELECT_SCHMT_ISRC, WCD938X_ANA_MBHC_ELECT, 0x06),
+ WCD_MBHC_FIELD(WCD_MBHC_FSM_EN, WCD938X_ANA_MBHC_ELECT, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_INSREM_DBNC, WCD938X_MBHC_NEW_PLUG_DETECT_CTL, 0x0F),
+ WCD_MBHC_FIELD(WCD_MBHC_BTN_DBNC, WCD938X_MBHC_NEW_CTL_1, 0x03),
+ WCD_MBHC_FIELD(WCD_MBHC_HS_VREF, WCD938X_MBHC_NEW_CTL_2, 0x03),
+ WCD_MBHC_FIELD(WCD_MBHC_HS_COMP_RESULT, WCD938X_ANA_MBHC_RESULT_3, 0x08),
+ WCD_MBHC_FIELD(WCD_MBHC_IN2P_CLAMP_STATE, WCD938X_ANA_MBHC_RESULT_3, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_MIC_SCHMT_RESULT, WCD938X_ANA_MBHC_RESULT_3, 0x20),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_SCHMT_RESULT, WCD938X_ANA_MBHC_RESULT_3, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_SCHMT_RESULT, WCD938X_ANA_MBHC_RESULT_3, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_OCP_FSM_EN, WCD938X_HPH_OCP_CTL, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_BTN_RESULT, WCD938X_ANA_MBHC_RESULT_3, 0x07),
+ WCD_MBHC_FIELD(WCD_MBHC_BTN_ISRC_CTL, WCD938X_ANA_MBHC_ELECT, 0x70),
+ WCD_MBHC_FIELD(WCD_MBHC_ELECT_RESULT, WCD938X_ANA_MBHC_RESULT_3, 0xFF),
+ WCD_MBHC_FIELD(WCD_MBHC_MICB_CTRL, WCD938X_ANA_MICB2, 0xC0),
+ WCD_MBHC_FIELD(WCD_MBHC_HPH_CNP_WG_TIME, WCD938X_HPH_CNP_WG_TIME, 0xFF),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_PA_EN, WCD938X_ANA_HPH, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_PA_EN, WCD938X_ANA_HPH, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_HPH_PA_EN, WCD938X_ANA_HPH, 0xC0),
+ WCD_MBHC_FIELD(WCD_MBHC_SWCH_LEVEL_REMOVE, WCD938X_ANA_MBHC_RESULT_3, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_ANC_DET_EN, WCD938X_MBHC_CTL_BCS, 0x02),
+ WCD_MBHC_FIELD(WCD_MBHC_FSM_STATUS, WCD938X_MBHC_NEW_FSM_STATUS, 0x01),
+ WCD_MBHC_FIELD(WCD_MBHC_MUX_CTL, WCD938X_MBHC_NEW_CTL_2, 0x70),
+ WCD_MBHC_FIELD(WCD_MBHC_MOISTURE_STATUS, WCD938X_MBHC_NEW_FSM_STATUS, 0x20),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_GND, WCD938X_HPH_PA_CTL2, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_GND, WCD938X_HPH_PA_CTL2, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_DET_EN, WCD938X_HPH_L_TEST, 0x01),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_DET_EN, WCD938X_HPH_R_TEST, 0x01),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_STATUS, WCD938X_DIGITAL_INTR_STATUS_0, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_STATUS, WCD938X_DIGITAL_INTR_STATUS_0, 0x20),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_EN, WCD938X_MBHC_NEW_CTL_1, 0x08),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_COMPLETE, WCD938X_MBHC_NEW_FSM_STATUS, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_TIMEOUT, WCD938X_MBHC_NEW_FSM_STATUS, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_RESULT, WCD938X_MBHC_NEW_ADC_RESULT, 0xFF),
+ WCD_MBHC_FIELD(WCD_MBHC_MICB2_VOUT, WCD938X_ANA_MICB2, 0x3F),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_MODE, WCD938X_MBHC_NEW_CTL_1, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_DETECTION_DONE, WCD938X_MBHC_NEW_CTL_1, 0x04),
+ WCD_MBHC_FIELD(WCD_MBHC_ELECT_ISRC_EN, WCD938X_ANA_MBHC_ZDET, 0x02),
+};
+
static const struct reg_default wcd938x_defaults[] = {
{WCD938X_ANA_PAGE_REGISTER, 0x00},
{WCD938X_ANA_BIAS, 0x00},
@@ -1360,7 +1412,6 @@ static int wcd938x_io_init(struct wcd938x_priv *wcd938x)
static int wcd938x_sdw_connect_port(struct wcd938x_sdw_ch_info *ch_info,
struct sdw_port_config *port_config,
- u32 mstr_port_num,
u8 enable)
{
u8 ch_mask, port_num;
@@ -1380,14 +1431,12 @@ static int wcd938x_sdw_connect_port(struct wcd938x_sdw_ch_info *ch_info,
static int wcd938x_connect_port(struct wcd938x_sdw_priv *wcd, u8 ch_id, u8 enable)
{
- u8 port_num, mstr_port_num;
+ u8 port_num;
port_num = wcd->ch_info[ch_id].port_num;
- mstr_port_num = wcd->port_map[port_num - 1];
return wcd938x_sdw_connect_port(&wcd->ch_info[ch_id],
&wcd->port_config[port_num],
- mstr_port_num,
enable);
}
@@ -1623,7 +1672,6 @@ static int wcd938x_codec_aux_dac_event(struct snd_soc_dapm_widget *w,
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
- int ret = 0;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -1651,7 +1699,7 @@ static int wcd938x_codec_aux_dac_event(struct snd_soc_dapm_widget *w,
WCD938X_ANA_RX_DIV4_CLK_EN_MASK, 0);
break;
}
- return ret;
+ return 0;
}
@@ -1728,6 +1776,8 @@ static int wcd938x_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
usleep_range(7000, 7100);
snd_soc_component_write_field(component, WCD938X_ANA_HPH,
WCD938X_HPHR_EN_MASK, 0);
+ wcd_mbhc_event_notify(wcd938x->wcd_mbhc,
+ WCD_EVENT_PRE_HPHR_PA_OFF);
set_bit(HPH_PA_DELAY, &wcd938x->status_mask);
break;
case SND_SOC_DAPM_POST_PMD:
@@ -1743,6 +1793,8 @@ static int wcd938x_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
usleep_range(7000, 7100);
clear_bit(HPH_PA_DELAY, &wcd938x->status_mask);
}
+ wcd_mbhc_event_notify(wcd938x->wcd_mbhc,
+ WCD_EVENT_POST_HPHR_PA_OFF);
snd_soc_component_write_field(component, WCD938X_ANA_HPH,
WCD938X_HPHR_REF_EN_MASK, 0);
snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL1,
@@ -1830,6 +1882,7 @@ static int wcd938x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
usleep_range(7000, 7100);
snd_soc_component_write_field(component, WCD938X_ANA_HPH,
WCD938X_HPHL_EN_MASK, 0);
+ wcd_mbhc_event_notify(wcd938x->wcd_mbhc, WCD_EVENT_PRE_HPHL_PA_OFF);
set_bit(HPH_PA_DELAY, &wcd938x->status_mask);
break;
case SND_SOC_DAPM_POST_PMD:
@@ -1845,6 +1898,8 @@ static int wcd938x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
usleep_range(7000, 7100);
clear_bit(HPH_PA_DELAY, &wcd938x->status_mask);
}
+ wcd_mbhc_event_notify(wcd938x->wcd_mbhc,
+ WCD_EVENT_POST_HPHL_PA_OFF);
snd_soc_component_write_field(component, WCD938X_ANA_HPH,
WCD938X_HPHL_REF_EN_MASK, 0);
snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL0,
@@ -1866,7 +1921,6 @@ static int wcd938x_codec_enable_aux_pa(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
int hph_mode = wcd938x->hph_mode;
- int ret = 0;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -1902,7 +1956,7 @@ static int wcd938x_codec_enable_aux_pa(struct snd_soc_dapm_widget *w,
WCD938X_EN_CUR_DET_MASK, 1);
break;
}
- return ret;
+ return 0;
}
static int wcd938x_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
@@ -2355,7 +2409,14 @@ static int wcd938x_micbias_control(struct snd_soc_component *component,
snd_soc_component_write_field(component, micb_reg,
WCD938X_MICB_EN_MASK,
WCD938X_MICB_ENABLE);
+ if (micb_num == MIC_BIAS_2)
+ wcd_mbhc_event_notify(wcd938x->wcd_mbhc,
+ WCD_EVENT_POST_MICBIAS_2_ON);
}
+ if (micb_num == MIC_BIAS_2 && is_dapm)
+ wcd_mbhc_event_notify(wcd938x->wcd_mbhc,
+ WCD_EVENT_POST_DAPM_MICBIAS_2_ON);
+
break;
case MICB_DISABLE:
@@ -2369,10 +2430,19 @@ static int wcd938x_micbias_control(struct snd_soc_component *component,
WCD938X_MICB_PULL_UP);
else if ((wcd938x->micb_ref[micb_index] == 0) &&
(wcd938x->pullup_ref[micb_index] == 0)) {
+ if (micb_num == MIC_BIAS_2)
+ wcd_mbhc_event_notify(wcd938x->wcd_mbhc,
+ WCD_EVENT_PRE_MICBIAS_2_OFF);
snd_soc_component_write_field(component, micb_reg,
WCD938X_MICB_EN_MASK, 0);
+ if (micb_num == MIC_BIAS_2)
+ wcd_mbhc_event_notify(wcd938x->wcd_mbhc,
+ WCD_EVENT_POST_MICBIAS_2_OFF);
}
+ if (is_dapm && micb_num == MIC_BIAS_2)
+ wcd_mbhc_event_notify(wcd938x->wcd_mbhc,
+ WCD_EVENT_POST_DAPM_MICBIAS_2_OFF);
break;
}
@@ -2845,6 +2915,704 @@ static int wcd938x_set_swr_port(struct snd_kcontrol *kcontrol,
}
+/* MBHC related */
+static void wcd938x_mbhc_clk_setup(struct snd_soc_component *component,
+ bool enable)
+{
+ snd_soc_component_write_field(component, WCD938X_MBHC_NEW_CTL_1,
+ WCD938X_MBHC_CTL_RCO_EN_MASK, enable);
+}
+
+static void wcd938x_mbhc_mbhc_bias_control(struct snd_soc_component *component,
+ bool enable)
+{
+ snd_soc_component_write_field(component, WCD938X_ANA_MBHC_ELECT,
+ WCD938X_ANA_MBHC_BIAS_EN, enable);
+}
+
+static void wcd938x_mbhc_program_btn_thr(struct snd_soc_component *component,
+ int *btn_low, int *btn_high,
+ int num_btn, bool is_micbias)
+{
+ int i, vth;
+
+ if (num_btn > WCD_MBHC_DEF_BUTTONS) {
+ dev_err(component->dev, "%s: invalid number of buttons: %d\n",
+ __func__, num_btn);
+ return;
+ }
+
+ for (i = 0; i < num_btn; i++) {
+ vth = ((btn_high[i] * 2) / 25) & 0x3F;
+ snd_soc_component_write_field(component, WCD938X_ANA_MBHC_BTN0 + i,
+ WCD938X_MBHC_BTN_VTH_MASK, vth);
+ dev_dbg(component->dev, "%s: btn_high[%d]: %d, vth: %d\n",
+ __func__, i, btn_high[i], vth);
+ }
+}
+
+static bool wcd938x_mbhc_micb_en_status(struct snd_soc_component *component, int micb_num)
+{
+ u8 val;
+
+ if (micb_num == MIC_BIAS_2) {
+ val = snd_soc_component_read_field(component,
+ WCD938X_ANA_MICB2,
+ WCD938X_ANA_MICB2_ENABLE_MASK);
+ if (val == WCD938X_MICB_ENABLE)
+ return true;
+ }
+ return false;
+}
+
+static void wcd938x_mbhc_hph_l_pull_up_control(struct snd_soc_component *component,
+ int pull_up_cur)
+{
+ /* Default pull up current to 2uA */
+ if (pull_up_cur > HS_PULLUP_I_OFF || pull_up_cur < HS_PULLUP_I_3P0_UA)
+ pull_up_cur = HS_PULLUP_I_2P0_UA;
+
+ snd_soc_component_write_field(component,
+ WCD938X_MBHC_NEW_INT_MECH_DET_CURRENT,
+ WCD938X_HSDET_PULLUP_C_MASK, pull_up_cur);
+}
+
+static int wcd938x_mbhc_request_micbias(struct snd_soc_component *component,
+ int micb_num, int req)
+{
+ return wcd938x_micbias_control(component, micb_num, req, false);
+}
+
+static void wcd938x_mbhc_micb_ramp_control(struct snd_soc_component *component,
+ bool enable)
+{
+ if (enable) {
+ snd_soc_component_write_field(component, WCD938X_ANA_MICB2_RAMP,
+ WCD938X_RAMP_SHIFT_CTRL_MASK, 0x0C);
+ snd_soc_component_write_field(component, WCD938X_ANA_MICB2_RAMP,
+ WCD938X_RAMP_EN_MASK, 1);
+ } else {
+ snd_soc_component_write_field(component, WCD938X_ANA_MICB2_RAMP,
+ WCD938X_RAMP_EN_MASK, 0);
+ snd_soc_component_write_field(component, WCD938X_ANA_MICB2_RAMP,
+ WCD938X_RAMP_SHIFT_CTRL_MASK, 0);
+ }
+}
+
+static int wcd938x_get_micb_vout_ctl_val(u32 micb_mv)
+{
+ /* min micbias voltage is 1V and maximum is 2.85V */
+ if (micb_mv < 1000 || micb_mv > 2850)
+ return -EINVAL;
+
+ return (micb_mv - 1000) / 50;
+}
+
+static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
+ int req_volt, int micb_num)
+{
+ struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+ int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en, ret = 0;
+
+ switch (micb_num) {
+ case MIC_BIAS_1:
+ micb_reg = WCD938X_ANA_MICB1;
+ break;
+ case MIC_BIAS_2:
+ micb_reg = WCD938X_ANA_MICB2;
+ break;
+ case MIC_BIAS_3:
+ micb_reg = WCD938X_ANA_MICB3;
+ break;
+ case MIC_BIAS_4:
+ micb_reg = WCD938X_ANA_MICB4;
+ break;
+ default:
+ return -EINVAL;
+ }
+ mutex_lock(&wcd938x->micb_lock);
+ /*
+ * If requested micbias voltage is same as current micbias
+ * voltage, then just return. Otherwise, adjust voltage as
+ * per requested value. If micbias is already enabled, then
+ * to avoid slow micbias ramp-up or down enable pull-up
+ * momentarily, change the micbias value and then re-enable
+ * micbias.
+ */
+ micb_en = snd_soc_component_read_field(component, micb_reg,
+ WCD938X_MICB_EN_MASK);
+ cur_vout_ctl = snd_soc_component_read_field(component, micb_reg,
+ WCD938X_MICB_VOUT_MASK);
+
+ req_vout_ctl = wcd938x_get_micb_vout_ctl_val(req_volt);
+ if (req_vout_ctl < 0) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (cur_vout_ctl == req_vout_ctl) {
+ ret = 0;
+ goto exit;
+ }
+
+ if (micb_en == WCD938X_MICB_ENABLE)
+ snd_soc_component_write_field(component, micb_reg,
+ WCD938X_MICB_EN_MASK,
+ WCD938X_MICB_PULL_UP);
+
+ snd_soc_component_write_field(component, micb_reg,
+ WCD938X_MICB_VOUT_MASK,
+ req_vout_ctl);
+
+ if (micb_en == WCD938X_MICB_ENABLE) {
+ snd_soc_component_write_field(component, micb_reg,
+ WCD938X_MICB_EN_MASK,
+ WCD938X_MICB_ENABLE);
+ /*
+ * Add 2ms delay as per HW requirement after enabling
+ * micbias
+ */
+ usleep_range(2000, 2100);
+ }
+exit:
+ mutex_unlock(&wcd938x->micb_lock);
+ return ret;
+}
+
+static int wcd938x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component,
+ int micb_num, bool req_en)
+{
+ struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+ int rc, micb_mv;
+
+ if (micb_num != MIC_BIAS_2)
+ return -EINVAL;
+ /*
+ * If device tree micbias level is already above the minimum
+ * voltage needed to detect threshold microphone, then do
+ * not change the micbias, just return.
+ */
+ if (wcd938x->micb2_mv >= WCD_MBHC_THR_HS_MICB_MV)
+ return 0;
+
+ micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : wcd938x->micb2_mv;
+
+ rc = wcd938x_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2);
+
+ return rc;
+}
+
+static inline void wcd938x_mbhc_get_result_params(struct wcd938x_priv *wcd938x,
+ s16 *d1_a, u16 noff,
+ int32_t *zdet)
+{
+ int i;
+ int val, val1;
+ s16 c1;
+ s32 x1, d1;
+ int32_t denom;
+ int minCode_param[] = {
+ 3277, 1639, 820, 410, 205, 103, 52, 26
+ };
+
+ regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MBHC_ZDET, 0x20, 0x20);
+ for (i = 0; i < WCD938X_ZDET_NUM_MEASUREMENTS; i++) {
+ regmap_read(wcd938x->regmap, WCD938X_ANA_MBHC_RESULT_2, &val);
+ if (val & 0x80)
+ break;
+ }
+ val = val << 0x8;
+ regmap_read(wcd938x->regmap, WCD938X_ANA_MBHC_RESULT_1, &val1);
+ val |= val1;
+ regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MBHC_ZDET, 0x20, 0x00);
+ x1 = WCD938X_MBHC_GET_X1(val);
+ c1 = WCD938X_MBHC_GET_C1(val);
+ /* If ramp is not complete, give additional 5ms */
+ if ((c1 < 2) && x1)
+ usleep_range(5000, 5050);
+
+ if (!c1 || !x1) {
+ pr_err("%s: Impedance detect ramp error, c1=%d, x1=0x%x\n",
+ __func__, c1, x1);
+ goto ramp_down;
+ }
+ d1 = d1_a[c1];
+ denom = (x1 * d1) - (1 << (14 - noff));
+ if (denom > 0)
+ *zdet = (WCD938X_MBHC_ZDET_CONST * 1000) / denom;
+ else if (x1 < minCode_param[noff])
+ *zdet = WCD938X_ZDET_FLOATING_IMPEDANCE;
+
+ pr_err("%s: d1=%d, c1=%d, x1=0x%x, z_val=%d(milliOhm)\n",
+ __func__, d1, c1, x1, *zdet);
+ramp_down:
+ i = 0;
+ while (x1) {
+ regmap_read(wcd938x->regmap,
+ WCD938X_ANA_MBHC_RESULT_1, &val);
+ regmap_read(wcd938x->regmap,
+ WCD938X_ANA_MBHC_RESULT_2, &val1);
+ val = val << 0x08;
+ val |= val1;
+ x1 = WCD938X_MBHC_GET_X1(val);
+ i++;
+ if (i == WCD938X_ZDET_NUM_MEASUREMENTS)
+ break;
+ }
+}
+
+static void wcd938x_mbhc_zdet_ramp(struct snd_soc_component *component,
+ struct wcd938x_mbhc_zdet_param *zdet_param,
+ int32_t *zl, int32_t *zr, s16 *d1_a)
+{
+ struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+ int32_t zdet = 0;
+
+ snd_soc_component_write_field(component, WCD938X_MBHC_NEW_ZDET_ANA_CTL,
+ WCD938X_ZDET_MAXV_CTL_MASK, zdet_param->ldo_ctl);
+ snd_soc_component_update_bits(component, WCD938X_ANA_MBHC_BTN5,
+ WCD938X_VTH_MASK, zdet_param->btn5);
+ snd_soc_component_update_bits(component, WCD938X_ANA_MBHC_BTN6,
+ WCD938X_VTH_MASK, zdet_param->btn6);
+ snd_soc_component_update_bits(component, WCD938X_ANA_MBHC_BTN7,
+ WCD938X_VTH_MASK, zdet_param->btn7);
+ snd_soc_component_write_field(component, WCD938X_MBHC_NEW_ZDET_ANA_CTL,
+ WCD938X_ZDET_RANGE_CTL_MASK, zdet_param->noff);
+ snd_soc_component_update_bits(component, WCD938X_MBHC_NEW_ZDET_RAMP_CTL,
+ 0x0F, zdet_param->nshift);
+
+ if (!zl)
+ goto z_right;
+ /* Start impedance measurement for HPH_L */
+ regmap_update_bits(wcd938x->regmap,
+ WCD938X_ANA_MBHC_ZDET, 0x80, 0x80);
+ dev_dbg(component->dev, "%s: ramp for HPH_L, noff = %d\n",
+ __func__, zdet_param->noff);
+ wcd938x_mbhc_get_result_params(wcd938x, d1_a, zdet_param->noff, &zdet);
+ regmap_update_bits(wcd938x->regmap,
+ WCD938X_ANA_MBHC_ZDET, 0x80, 0x00);
+
+ *zl = zdet;
+
+z_right:
+ if (!zr)
+ return;
+ /* Start impedance measurement for HPH_R */
+ regmap_update_bits(wcd938x->regmap,
+ WCD938X_ANA_MBHC_ZDET, 0x40, 0x40);
+ dev_dbg(component->dev, "%s: ramp for HPH_R, noff = %d\n",
+ __func__, zdet_param->noff);
+ wcd938x_mbhc_get_result_params(wcd938x, d1_a, zdet_param->noff, &zdet);
+ regmap_update_bits(wcd938x->regmap,
+ WCD938X_ANA_MBHC_ZDET, 0x40, 0x00);
+
+ *zr = zdet;
+}
+
+static inline void wcd938x_wcd_mbhc_qfuse_cal(struct snd_soc_component *component,
+ int32_t *z_val, int flag_l_r)
+{
+ s16 q1;
+ int q1_cal;
+
+ if (*z_val < (WCD938X_ZDET_VAL_400/1000))
+ q1 = snd_soc_component_read(component,
+ WCD938X_DIGITAL_EFUSE_REG_23 + (2 * flag_l_r));
+ else
+ q1 = snd_soc_component_read(component,
+ WCD938X_DIGITAL_EFUSE_REG_24 + (2 * flag_l_r));
+ if (q1 & 0x80)
+ q1_cal = (10000 - ((q1 & 0x7F) * 25));
+ else
+ q1_cal = (10000 + (q1 * 25));
+ if (q1_cal > 0)
+ *z_val = ((*z_val) * 10000) / q1_cal;
+}
+
+static void wcd938x_wcd_mbhc_calc_impedance(struct snd_soc_component *component,
+ uint32_t *zl, uint32_t *zr)
+{
+ struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+ s16 reg0, reg1, reg2, reg3, reg4;
+ int32_t z1L, z1R, z1Ls;
+ int zMono, z_diff1, z_diff2;
+ bool is_fsm_disable = false;
+ struct wcd938x_mbhc_zdet_param zdet_param[] = {
+ {4, 0, 4, 0x08, 0x14, 0x18}, /* < 32ohm */
+ {2, 0, 3, 0x18, 0x7C, 0x90}, /* 32ohm < Z < 400ohm */
+ {1, 4, 5, 0x18, 0x7C, 0x90}, /* 400ohm < Z < 1200ohm */
+ {1, 6, 7, 0x18, 0x7C, 0x90}, /* >1200ohm */
+ };
+ struct wcd938x_mbhc_zdet_param *zdet_param_ptr = NULL;
+ s16 d1_a[][4] = {
+ {0, 30, 90, 30},
+ {0, 30, 30, 5},
+ {0, 30, 30, 5},
+ {0, 30, 30, 5},
+ };
+ s16 *d1 = NULL;
+
+ reg0 = snd_soc_component_read(component, WCD938X_ANA_MBHC_BTN5);
+ reg1 = snd_soc_component_read(component, WCD938X_ANA_MBHC_BTN6);
+ reg2 = snd_soc_component_read(component, WCD938X_ANA_MBHC_BTN7);
+ reg3 = snd_soc_component_read(component, WCD938X_MBHC_CTL_CLK);
+ reg4 = snd_soc_component_read(component, WCD938X_MBHC_NEW_ZDET_ANA_CTL);
+
+ if (snd_soc_component_read(component, WCD938X_ANA_MBHC_ELECT) & 0x80) {
+ is_fsm_disable = true;
+ regmap_update_bits(wcd938x->regmap,
+ WCD938X_ANA_MBHC_ELECT, 0x80, 0x00);
+ }
+
+ /* For NO-jack, disable L_DET_EN before Z-det measurements */
+ if (wcd938x->mbhc_cfg.hphl_swh)
+ regmap_update_bits(wcd938x->regmap,
+ WCD938X_ANA_MBHC_MECH, 0x80, 0x00);
+
+ /* Turn off 100k pull down on HPHL */
+ regmap_update_bits(wcd938x->regmap,
+ WCD938X_ANA_MBHC_MECH, 0x01, 0x00);
+
+ /* Disable surge protection before impedance detection.
+ * This is done to give correct value for high impedance.
+ */
+ regmap_update_bits(wcd938x->regmap,
+ WCD938X_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0x00);
+ /* 1ms delay needed after disable surge protection */
+ usleep_range(1000, 1010);
+
+ /* First get impedance on Left */
+ d1 = d1_a[1];
+ zdet_param_ptr = &zdet_param[1];
+ wcd938x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1);
+
+ if (!WCD938X_MBHC_IS_SECOND_RAMP_REQUIRED(z1L))
+ goto left_ch_impedance;
+
+ /* Second ramp for left ch */
+ if (z1L < WCD938X_ZDET_VAL_32) {
+ zdet_param_ptr = &zdet_param[0];
+ d1 = d1_a[0];
+ } else if ((z1L > WCD938X_ZDET_VAL_400) &&
+ (z1L <= WCD938X_ZDET_VAL_1200)) {
+ zdet_param_ptr = &zdet_param[2];
+ d1 = d1_a[2];
+ } else if (z1L > WCD938X_ZDET_VAL_1200) {
+ zdet_param_ptr = &zdet_param[3];
+ d1 = d1_a[3];
+ }
+ wcd938x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1);
+
+left_ch_impedance:
+ if ((z1L == WCD938X_ZDET_FLOATING_IMPEDANCE) ||
+ (z1L > WCD938X_ZDET_VAL_100K)) {
+ *zl = WCD938X_ZDET_FLOATING_IMPEDANCE;
+ zdet_param_ptr = &zdet_param[1];
+ d1 = d1_a[1];
+ } else {
+ *zl = z1L/1000;
+ wcd938x_wcd_mbhc_qfuse_cal(component, zl, 0);
+ }
+ dev_dbg(component->dev, "%s: impedance on HPH_L = %d(ohms)\n",
+ __func__, *zl);
+
+ /* Start of right impedance ramp and calculation */
+ wcd938x_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1R, d1);
+ if (WCD938X_MBHC_IS_SECOND_RAMP_REQUIRED(z1R)) {
+ if (((z1R > WCD938X_ZDET_VAL_1200) &&
+ (zdet_param_ptr->noff == 0x6)) ||
+ ((*zl) != WCD938X_ZDET_FLOATING_IMPEDANCE))
+ goto right_ch_impedance;
+ /* Second ramp for right ch */
+ if (z1R < WCD938X_ZDET_VAL_32) {
+ zdet_param_ptr = &zdet_param[0];
+ d1 = d1_a[0];
+ } else if ((z1R > WCD938X_ZDET_VAL_400) &&
+ (z1R <= WCD938X_ZDET_VAL_1200)) {
+ zdet_param_ptr = &zdet_param[2];
+ d1 = d1_a[2];
+ } else if (z1R > WCD938X_ZDET_VAL_1200) {
+ zdet_param_ptr = &zdet_param[3];
+ d1 = d1_a[3];
+ }
+ wcd938x_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1R, d1);
+ }
+right_ch_impedance:
+ if ((z1R == WCD938X_ZDET_FLOATING_IMPEDANCE) ||
+ (z1R > WCD938X_ZDET_VAL_100K)) {
+ *zr = WCD938X_ZDET_FLOATING_IMPEDANCE;
+ } else {
+ *zr = z1R/1000;
+ wcd938x_wcd_mbhc_qfuse_cal(component, zr, 1);
+ }
+ dev_dbg(component->dev, "%s: impedance on HPH_R = %d(ohms)\n",
+ __func__, *zr);
+
+ /* Mono/stereo detection */
+ if ((*zl == WCD938X_ZDET_FLOATING_IMPEDANCE) &&
+ (*zr == WCD938X_ZDET_FLOATING_IMPEDANCE)) {
+ dev_dbg(component->dev,
+ "%s: plug type is invalid or extension cable\n",
+ __func__);
+ goto zdet_complete;
+ }
+ if ((*zl == WCD938X_ZDET_FLOATING_IMPEDANCE) ||
+ (*zr == WCD938X_ZDET_FLOATING_IMPEDANCE) ||
+ ((*zl < WCD_MONO_HS_MIN_THR) && (*zr > WCD_MONO_HS_MIN_THR)) ||
+ ((*zl > WCD_MONO_HS_MIN_THR) && (*zr < WCD_MONO_HS_MIN_THR))) {
+ dev_dbg(component->dev,
+ "%s: Mono plug type with one ch floating or shorted to GND\n",
+ __func__);
+ wcd_mbhc_set_hph_type(wcd938x->wcd_mbhc, WCD_MBHC_HPH_MONO);
+ goto zdet_complete;
+ }
+ snd_soc_component_write_field(component, WCD938X_HPH_R_ATEST,
+ WCD938X_HPHPA_GND_OVR_MASK, 1);
+ snd_soc_component_write_field(component, WCD938X_HPH_PA_CTL2,
+ WCD938X_HPHPA_GND_R_MASK, 1);
+ if (*zl < (WCD938X_ZDET_VAL_32/1000))
+ wcd938x_mbhc_zdet_ramp(component, &zdet_param[0], &z1Ls, NULL, d1);
+ else
+ wcd938x_mbhc_zdet_ramp(component, &zdet_param[1], &z1Ls, NULL, d1);
+ snd_soc_component_write_field(component, WCD938X_HPH_PA_CTL2,
+ WCD938X_HPHPA_GND_R_MASK, 0);
+ snd_soc_component_write_field(component, WCD938X_HPH_R_ATEST,
+ WCD938X_HPHPA_GND_OVR_MASK, 0);
+ z1Ls /= 1000;
+ wcd938x_wcd_mbhc_qfuse_cal(component, &z1Ls, 0);
+ /* Parallel of left Z and 9 ohm pull down resistor */
+ zMono = ((*zl) * 9) / ((*zl) + 9);
+ z_diff1 = (z1Ls > zMono) ? (z1Ls - zMono) : (zMono - z1Ls);
+ z_diff2 = ((*zl) > z1Ls) ? ((*zl) - z1Ls) : (z1Ls - (*zl));
+ if ((z_diff1 * (*zl + z1Ls)) > (z_diff2 * (z1Ls + zMono))) {
+ dev_dbg(component->dev, "%s: stereo plug type detected\n",
+ __func__);
+ wcd_mbhc_set_hph_type(wcd938x->wcd_mbhc, WCD_MBHC_HPH_STEREO);
+ } else {
+ dev_dbg(component->dev, "%s: MONO plug type detected\n",
+ __func__);
+ wcd_mbhc_set_hph_type(wcd938x->wcd_mbhc, WCD_MBHC_HPH_MONO);
+ }
+
+ /* Enable surge protection again after impedance detection */
+ regmap_update_bits(wcd938x->regmap,
+ WCD938X_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0xC0);
+zdet_complete:
+ snd_soc_component_write(component, WCD938X_ANA_MBHC_BTN5, reg0);
+ snd_soc_component_write(component, WCD938X_ANA_MBHC_BTN6, reg1);
+ snd_soc_component_write(component, WCD938X_ANA_MBHC_BTN7, reg2);
+ /* Turn on 100k pull down on HPHL */
+ regmap_update_bits(wcd938x->regmap,
+ WCD938X_ANA_MBHC_MECH, 0x01, 0x01);
+
+ /* For NO-jack, re-enable L_DET_EN after Z-det measurements */
+ if (wcd938x->mbhc_cfg.hphl_swh)
+ regmap_update_bits(wcd938x->regmap,
+ WCD938X_ANA_MBHC_MECH, 0x80, 0x80);
+
+ snd_soc_component_write(component, WCD938X_MBHC_NEW_ZDET_ANA_CTL, reg4);
+ snd_soc_component_write(component, WCD938X_MBHC_CTL_CLK, reg3);
+ if (is_fsm_disable)
+ regmap_update_bits(wcd938x->regmap,
+ WCD938X_ANA_MBHC_ELECT, 0x80, 0x80);
+}
+
+static void wcd938x_mbhc_gnd_det_ctrl(struct snd_soc_component *component,
+ bool enable)
+{
+ if (enable) {
+ snd_soc_component_write_field(component, WCD938X_ANA_MBHC_MECH,
+ WCD938X_MBHC_HSG_PULLUP_COMP_EN, 1);
+ snd_soc_component_write_field(component, WCD938X_ANA_MBHC_MECH,
+ WCD938X_MBHC_GND_DET_EN_MASK, 1);
+ } else {
+ snd_soc_component_write_field(component, WCD938X_ANA_MBHC_MECH,
+ WCD938X_MBHC_GND_DET_EN_MASK, 0);
+ snd_soc_component_write_field(component, WCD938X_ANA_MBHC_MECH,
+ WCD938X_MBHC_HSG_PULLUP_COMP_EN, 0);
+ }
+}
+
+static void wcd938x_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component,
+ bool enable)
+{
+ snd_soc_component_write_field(component, WCD938X_HPH_PA_CTL2,
+ WCD938X_HPHPA_GND_R_MASK, enable);
+ snd_soc_component_write_field(component, WCD938X_HPH_PA_CTL2,
+ WCD938X_HPHPA_GND_L_MASK, enable);
+}
+
+static void wcd938x_mbhc_moisture_config(struct snd_soc_component *component)
+{
+ struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+
+ if (wcd938x->mbhc_cfg.moist_rref == R_OFF) {
+ snd_soc_component_write_field(component, WCD938X_MBHC_NEW_CTL_2,
+ WCD938X_M_RTH_CTL_MASK, R_OFF);
+ return;
+ }
+
+ /* Do not enable moisture detection if jack type is NC */
+ if (!wcd938x->mbhc_cfg.hphl_swh) {
+ dev_dbg(component->dev, "%s: disable moisture detection for NC\n",
+ __func__);
+ snd_soc_component_write_field(component, WCD938X_MBHC_NEW_CTL_2,
+ WCD938X_M_RTH_CTL_MASK, R_OFF);
+ return;
+ }
+
+ snd_soc_component_write_field(component, WCD938X_MBHC_NEW_CTL_2,
+ WCD938X_M_RTH_CTL_MASK, wcd938x->mbhc_cfg.moist_rref);
+}
+
+static void wcd938x_mbhc_moisture_detect_en(struct snd_soc_component *component, bool enable)
+{
+ struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+
+ if (enable)
+ snd_soc_component_write_field(component, WCD938X_MBHC_NEW_CTL_2,
+ WCD938X_M_RTH_CTL_MASK, wcd938x->mbhc_cfg.moist_rref);
+ else
+ snd_soc_component_write_field(component, WCD938X_MBHC_NEW_CTL_2,
+ WCD938X_M_RTH_CTL_MASK, R_OFF);
+}
+
+static bool wcd938x_mbhc_get_moisture_status(struct snd_soc_component *component)
+{
+ struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+ bool ret = false;
+
+ if (wcd938x->mbhc_cfg.moist_rref == R_OFF) {
+ snd_soc_component_write_field(component, WCD938X_MBHC_NEW_CTL_2,
+ WCD938X_M_RTH_CTL_MASK, R_OFF);
+ goto done;
+ }
+
+ /* Do not enable moisture detection if jack type is NC */
+ if (!wcd938x->mbhc_cfg.hphl_swh) {
+ dev_dbg(component->dev, "%s: disable moisture detection for NC\n",
+ __func__);
+ snd_soc_component_write_field(component, WCD938X_MBHC_NEW_CTL_2,
+ WCD938X_M_RTH_CTL_MASK, R_OFF);
+ goto done;
+ }
+
+ /*
+ * If moisture_en is already enabled, then skip to plug type
+ * detection.
+ */
+ if (snd_soc_component_read_field(component, WCD938X_MBHC_NEW_CTL_2, WCD938X_M_RTH_CTL_MASK))
+ goto done;
+
+ wcd938x_mbhc_moisture_detect_en(component, true);
+ /* Read moisture comparator status */
+ ret = ((snd_soc_component_read(component, WCD938X_MBHC_NEW_FSM_STATUS)
+ & 0x20) ? 0 : 1);
+
+done:
+ return ret;
+
+}
+
+static void wcd938x_mbhc_moisture_polling_ctrl(struct snd_soc_component *component,
+ bool enable)
+{
+ snd_soc_component_write_field(component,
+ WCD938X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL,
+ WCD938X_MOISTURE_EN_POLLING_MASK, enable);
+}
+
+static const struct wcd_mbhc_cb mbhc_cb = {
+ .clk_setup = wcd938x_mbhc_clk_setup,
+ .mbhc_bias = wcd938x_mbhc_mbhc_bias_control,
+ .set_btn_thr = wcd938x_mbhc_program_btn_thr,
+ .micbias_enable_status = wcd938x_mbhc_micb_en_status,
+ .hph_pull_up_control_v2 = wcd938x_mbhc_hph_l_pull_up_control,
+ .mbhc_micbias_control = wcd938x_mbhc_request_micbias,
+ .mbhc_micb_ramp_control = wcd938x_mbhc_micb_ramp_control,
+ .mbhc_micb_ctrl_thr_mic = wcd938x_mbhc_micb_ctrl_threshold_mic,
+ .compute_impedance = wcd938x_wcd_mbhc_calc_impedance,
+ .mbhc_gnd_det_ctrl = wcd938x_mbhc_gnd_det_ctrl,
+ .hph_pull_down_ctrl = wcd938x_mbhc_hph_pull_down_ctrl,
+ .mbhc_moisture_config = wcd938x_mbhc_moisture_config,
+ .mbhc_get_moisture_status = wcd938x_mbhc_get_moisture_status,
+ .mbhc_moisture_polling_ctrl = wcd938x_mbhc_moisture_polling_ctrl,
+ .mbhc_moisture_detect_en = wcd938x_mbhc_moisture_detect_en,
+};
+
+static int wcd938x_get_hph_type(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = wcd_mbhc_get_hph_type(wcd938x->wcd_mbhc);
+
+ return 0;
+}
+
+static int wcd938x_hph_impedance_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ uint32_t zl, zr;
+ bool hphr;
+ struct soc_mixer_control *mc;
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+
+ mc = (struct soc_mixer_control *)(kcontrol->private_value);
+ hphr = mc->shift;
+ wcd_mbhc_get_impedance(wcd938x->wcd_mbhc, &zl, &zr);
+ dev_dbg(component->dev, "%s: zl=%u(ohms), zr=%u(ohms)\n", __func__, zl, zr);
+ ucontrol->value.integer.value[0] = hphr ? zr : zl;
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new hph_type_detect_controls[] = {
+ SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0,
+ wcd938x_get_hph_type, NULL),
+};
+
+static const struct snd_kcontrol_new impedance_detect_controls[] = {
+ SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0,
+ wcd938x_hph_impedance_get, NULL),
+ SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0,
+ wcd938x_hph_impedance_get, NULL),
+};
+
+static int wcd938x_mbhc_init(struct snd_soc_component *component)
+{
+ struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+ struct wcd_mbhc_intr *intr_ids = &wcd938x->intr_ids;
+
+ intr_ids->mbhc_sw_intr = regmap_irq_get_virq(wcd938x->irq_chip,
+ WCD938X_IRQ_MBHC_SW_DET);
+ intr_ids->mbhc_btn_press_intr = regmap_irq_get_virq(wcd938x->irq_chip,
+ WCD938X_IRQ_MBHC_BUTTON_PRESS_DET);
+ intr_ids->mbhc_btn_release_intr = regmap_irq_get_virq(wcd938x->irq_chip,
+ WCD938X_IRQ_MBHC_BUTTON_RELEASE_DET);
+ intr_ids->mbhc_hs_ins_intr = regmap_irq_get_virq(wcd938x->irq_chip,
+ WCD938X_IRQ_MBHC_ELECT_INS_REM_LEG_DET);
+ intr_ids->mbhc_hs_rem_intr = regmap_irq_get_virq(wcd938x->irq_chip,
+ WCD938X_IRQ_MBHC_ELECT_INS_REM_DET);
+ intr_ids->hph_left_ocp = regmap_irq_get_virq(wcd938x->irq_chip,
+ WCD938X_IRQ_HPHL_OCP_INT);
+ intr_ids->hph_right_ocp = regmap_irq_get_virq(wcd938x->irq_chip,
+ WCD938X_IRQ_HPHR_OCP_INT);
+
+ wcd938x->wcd_mbhc = wcd_mbhc_init(component, &mbhc_cb, intr_ids, wcd_mbhc_fields, true);
+
+ snd_soc_add_component_controls(component, impedance_detect_controls,
+ ARRAY_SIZE(impedance_detect_controls));
+ snd_soc_add_component_controls(component, hph_type_detect_controls,
+ ARRAY_SIZE(hph_type_detect_controls));
+
+ return 0;
+}
+/* END MBHC */
+
static const struct snd_kcontrol_new wcd938x_snd_controls[] = {
SOC_SINGLE_EXT("HPHL_COMP Switch", WCD938X_COMP_L, 0, 1, 0,
wcd938x_get_compander, wcd938x_set_compander),
@@ -3225,15 +3993,6 @@ static const struct snd_soc_dapm_route wcd938x_audio_map[] = {
{"EAR", NULL, "EAR PGA"},
};
-static int wcd938x_get_micb_vout_ctl_val(u32 micb_mv)
-{
- /* min micbias voltage is 1V and maximum is 2.85V */
- if (micb_mv < 1000 || micb_mv > 2850)
- return -EINVAL;
-
- return (micb_mv - 1000) / 50;
-}
-
static int wcd938x_set_micbias_data(struct wcd938x_priv *wcd938x)
{
int vout_ctl_1, vout_ctl_2, vout_ctl_3, vout_ctl_4;
@@ -3372,10 +4131,27 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component)
default:
break;
}
+
+ ret = wcd938x_mbhc_init(component);
+ if (ret)
+ dev_err(component->dev, "mbhc initialization failed\n");
err:
return ret;
}
+static int wcd938x_codec_set_jack(struct snd_soc_component *comp,
+ struct snd_soc_jack *jack, void *data)
+{
+ struct wcd938x_priv *wcd = dev_get_drvdata(comp->dev);
+
+ if (!jack)
+ return wcd_mbhc_start(wcd->wcd_mbhc, &wcd->mbhc_cfg, jack);
+
+ wcd_mbhc_stop(wcd->wcd_mbhc);
+
+ return 0;
+}
+
static const struct snd_soc_component_driver soc_codec_dev_wcd938x = {
.name = "wcd938x_codec",
.probe = wcd938x_soc_codec_probe,
@@ -3385,6 +4161,7 @@ static const struct snd_soc_component_driver soc_codec_dev_wcd938x = {
.num_dapm_widgets = ARRAY_SIZE(wcd938x_dapm_widgets),
.dapm_routes = wcd938x_audio_map,
.num_dapm_routes = ARRAY_SIZE(wcd938x_audio_map),
+ .set_jack = wcd938x_codec_set_jack,
};
static void wcd938x_dt_parse_micbias_info(struct device *dev, struct wcd938x_priv *wcd)
@@ -3420,6 +4197,7 @@ static void wcd938x_dt_parse_micbias_info(struct device *dev, struct wcd938x_pri
static int wcd938x_populate_dt_data(struct wcd938x_priv *wcd938x, struct device *dev)
{
+ struct wcd_mbhc_config *cfg = &wcd938x->mbhc_cfg;
int ret;
wcd938x->reset_gpio = of_get_named_gpio(dev->of_node, "reset-gpios", 0);
@@ -3448,6 +4226,17 @@ static int wcd938x_populate_dt_data(struct wcd938x_priv *wcd938x, struct device
wcd938x_dt_parse_micbias_info(dev, wcd938x);
+ cfg->mbhc_micbias = MIC_BIAS_2;
+ cfg->anc_micbias = MIC_BIAS_2;
+ cfg->v_hs_max = WCD_MBHC_HS_V_MAX;
+ cfg->num_btn = WCD938X_MBHC_MAX_BUTTONS;
+ cfg->micb_mv = wcd938x->micb2_mv;
+ cfg->linein_th = 5000;
+ cfg->hs_thr = 1700;
+ cfg->hph_thr = 50;
+
+ wcd_dt_parse_mbhc_data(dev, cfg);
+
return 0;
}
@@ -3679,6 +4468,7 @@ static int wcd938x_probe(struct platform_device *pdev)
return -ENOMEM;
dev_set_drvdata(dev, wcd938x);
+ mutex_init(&wcd938x->micb_lock);
ret = wcd938x_populate_dt_data(wcd938x, dev);
if (ret) {
@@ -3703,7 +4493,7 @@ static int wcd938x_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
pm_runtime_idle(dev);
- return ret;
+ return 0;
}
static int wcd938x_remove(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wcd938x.h b/sound/soc/codecs/wcd938x.h
index 07b08de4cebf..ea82039e7843 100644
--- a/sound/soc/codecs/wcd938x.h
+++ b/sound/soc/codecs/wcd938x.h
@@ -658,7 +658,6 @@ struct wcd938x_sdw_priv {
struct sdw_port_config port_config[WCD938X_MAX_SWR_PORTS];
struct wcd938x_sdw_ch_info *ch_info;
bool port_enable[WCD938X_MAX_SWR_CH_IDS];
- int port_map[WCD938X_MAX_SWR_PORTS];
int active_ports;
int num_ports;
bool is_tx;
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index fe15cbc7bcaf..f7c800927cb2 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -747,6 +747,8 @@ static void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
static void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp)
{
wm_adsp_debugfs_clear(dsp);
+ debugfs_remove_recursive(dsp->debugfs_root);
+ dsp->debugfs_root = NULL;
}
#else
static inline void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
@@ -2029,10 +2031,9 @@ static struct wm_coeff_ctl *wm_adsp_get_ctl(struct wm_adsp *dsp,
if (!pos->subname)
continue;
if (strncmp(pos->subname, name, pos->subname_len) == 0 &&
- strncmp(pos->fw_name, fw_txt,
- SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == 0 &&
- pos->alg_region.alg == alg &&
- pos->alg_region.type == type) {
+ pos->fw_name == fw_txt &&
+ pos->alg_region.alg == alg &&
+ pos->alg_region.type == type) {
rslt = pos;
break;
}