diff options
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/amd/acp/acp-mach-common.c | 6 | ||||
-rw-r--r-- | sound/soc/amd/acp/acp-sof-mach.c | 26 | ||||
-rw-r--r-- | sound/soc/atmel/mikroe-proto.c | 8 | ||||
-rw-r--r-- | sound/soc/codecs/Kconfig | 34 | ||||
-rw-r--r-- | sound/soc/codecs/Makefile | 9 | ||||
-rw-r--r-- | sound/soc/codecs/framer-codec.c | 413 | ||||
-rw-r--r-- | sound/soc/codecs/nau8540.c | 116 | ||||
-rw-r--r-- | sound/soc/codecs/nau8540.h | 13 | ||||
-rw-r--r-- | sound/soc/codecs/wcd-clsh-v2.h | 1 | ||||
-rw-r--r-- | sound/soc/codecs/wcd-mbhc-v2.c | 95 | ||||
-rw-r--r-- | sound/soc/codecs/wcd-mbhc-v2.h | 3 | ||||
-rw-r--r-- | sound/soc/codecs/wcd939x-sdw.c | 1551 | ||||
-rw-r--r-- | sound/soc/codecs/wcd939x.c | 3686 | ||||
-rw-r--r-- | sound/soc/codecs/wcd939x.h | 989 | ||||
-rw-r--r-- | sound/soc/fsl/eukrea-tlv320.c | 8 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_sai.c | 13 | ||||
-rw-r--r-- | sound/soc/fsl/p1022_rdk.c | 33 | ||||
-rw-r--r-- | sound/soc/qcom/common.c | 2 | ||||
-rw-r--r-- | sound/soc/sof/amd/acp-loader.c | 32 | ||||
-rw-r--r-- | sound/soc/sof/amd/acp.c | 30 | ||||
-rw-r--r-- | sound/soc/sof/fw-file-profile.c | 18 | ||||
-rw-r--r-- | sound/soc/ti/j721e-evm.c | 4 | ||||
-rw-r--r-- | sound/soc/ti/omap-hdmi.c | 10 |
23 files changed, 6970 insertions, 130 deletions
diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index 504d1b8c4cbb..665a6ea0a2a8 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -828,8 +828,8 @@ static const struct snd_soc_ops acp_card_maxim_ops = { }; SND_SOC_DAILINK_DEF(max98388, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ADS8388:00", "max98388-aif1"), - COMP_CODEC("i2c-ADS8388:01", "max98388-aif1"))); + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ADS8388:00", MAX98388_CODEC_DAI), + COMP_CODEC("i2c-ADS8388:01", MAX98388_CODEC_DAI))); static const struct snd_kcontrol_new max98388_controls[] = { SOC_DAPM_PIN_SWITCH("Left Spk"), @@ -1280,7 +1280,7 @@ static const struct snd_soc_ops acp_8821_ops = { SND_SOC_DAILINK_DEF(nau8821, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-NVTN2020:00", - "nau8821-hifi"))); + NAU8821_CODEC_DAI))); /* Declare DMIC codec components */ SND_SOC_DAILINK_DEF(dmic_codec, diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c index 20b94814a046..fc59ea34e687 100644 --- a/sound/soc/amd/acp/acp-sof-mach.c +++ b/sound/soc/amd/acp/acp-sof-mach.c @@ -28,7 +28,6 @@ static struct acp_card_drvdata sof_rt5682_rt1019_data = { .hs_codec_id = RT5682, .amp_codec_id = RT1019, .dmic_codec_id = DMIC, - .tdm_mode = false, }; static struct acp_card_drvdata sof_rt5682_max_data = { @@ -38,7 +37,6 @@ static struct acp_card_drvdata sof_rt5682_max_data = { .hs_codec_id = RT5682, .amp_codec_id = MAX98360A, .dmic_codec_id = DMIC, - .tdm_mode = false, }; static struct acp_card_drvdata sof_rt5682s_rt1019_data = { @@ -49,7 +47,6 @@ static struct acp_card_drvdata sof_rt5682s_rt1019_data = { .amp_codec_id = RT1019, .dmic_codec_id = DMIC, .platform = RENOIR, - .tdm_mode = false, }; static struct acp_card_drvdata sof_rt5682s_max_data = { @@ -60,7 +57,6 @@ static struct acp_card_drvdata sof_rt5682s_max_data = { .amp_codec_id = MAX98360A, .dmic_codec_id = DMIC, .platform = RENOIR, - .tdm_mode = false, }; static struct acp_card_drvdata sof_nau8825_data = { @@ -72,7 +68,6 @@ static struct acp_card_drvdata sof_nau8825_data = { .dmic_codec_id = DMIC, .platform = REMBRANDT, .soc_mclk = true, - .tdm_mode = false, }; static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = { @@ -84,20 +79,15 @@ static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = { .dmic_codec_id = DMIC, .platform = REMBRANDT, .soc_mclk = true, - .tdm_mode = false, }; static struct acp_card_drvdata sof_nau8821_max98388_data = { .hs_cpu_id = I2S_SP, .amp_cpu_id = I2S_HS, .bt_cpu_id = I2S_BT, - .dmic_cpu_id = NONE, .hs_codec_id = NAU8821, .amp_codec_id = MAX98388, - .bt_codec_id = NONE, - .dmic_codec_id = NONE, .soc_mclk = true, - .tdm_mode = false, }; static int acp_sof_probe(struct platform_device *pdev) @@ -126,16 +116,14 @@ static int acp_sof_probe(struct platform_device *pdev) if (dmi_id && dmi_id->driver_data) acp_card_drvdata->tdm_mode = dmi_id->driver_data; - acp_sofdsp_dai_links_create(card); + ret = acp_sofdsp_dai_links_create(card); + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to create DAI links\n"); ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) { - dev_err(&pdev->dev, - "devm_snd_soc_register_card(%s) failed: %d\n", - card->name, ret); - return ret; - } - + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to register card(%s)\n", card->name); return 0; } @@ -182,7 +170,7 @@ static struct platform_driver acp_asoc_audio = { module_platform_driver(acp_asoc_audio); MODULE_IMPORT_NS(SND_SOC_AMD_MACH); -MODULE_DESCRIPTION("ACP chrome SOF audio support"); +MODULE_DESCRIPTION("ACP SOF Machine Driver"); MODULE_ALIAS("platform:rt5682-rt1019"); MODULE_ALIAS("platform:rt5682-max"); MODULE_ALIAS("platform:rt5682s-max"); diff --git a/sound/soc/atmel/mikroe-proto.c b/sound/soc/atmel/mikroe-proto.c index 18a8760443ae..8341a6e06493 100644 --- a/sound/soc/atmel/mikroe-proto.c +++ b/sound/soc/atmel/mikroe-proto.c @@ -140,7 +140,7 @@ static int snd_proto_probe(struct platform_device *pdev) dai->dai_fmt = dai_fmt; - ret = snd_soc_register_card(&snd_proto); + ret = devm_snd_soc_register_card(&pdev->dev, &snd_proto); if (ret) dev_err_probe(&pdev->dev, ret, "snd_soc_register_card() failed\n"); @@ -155,11 +155,6 @@ put_codec_node: return ret; } -static void snd_proto_remove(struct platform_device *pdev) -{ - snd_soc_unregister_card(&snd_proto); -} - static const struct of_device_id snd_proto_of_match[] = { { .compatible = "mikroe,mikroe-proto", }, {}, @@ -172,7 +167,6 @@ static struct platform_driver snd_proto_driver = { .of_match_table = snd_proto_of_match, }, .probe = snd_proto_probe, - .remove_new = snd_proto_remove, }; module_platform_driver(snd_proto_driver); diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 59f9742e9ff4..75d88bd1dc6f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -114,6 +114,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_ES8328_I2C imply SND_SOC_ES7134 imply SND_SOC_ES7241 + imply SND_SOC_FRAMER imply SND_SOC_GTM601 imply SND_SOC_HDAC_HDMI imply SND_SOC_HDAC_HDA @@ -276,6 +277,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_WCD9335 imply SND_SOC_WCD934X imply SND_SOC_WCD938X_SDW + imply SND_SOC_WCD939X_SDW imply SND_SOC_LPASS_MACRO_COMMON imply SND_SOC_LPASS_RX_MACRO imply SND_SOC_LPASS_TX_MACRO @@ -1101,6 +1103,20 @@ config SND_SOC_ES8328_SPI depends on SPI_MASTER select SND_SOC_ES8328 +config SND_SOC_FRAMER + tristate "Framer codec" + depends on GENERIC_FRAMER + help + Enable support for the framer codec. + The framer codec uses the generic framer infrastructure to transport + some audio data over an analog E1/T1/J1 line. + This codec allows to use some of the time slots available on the TDM + bus on which the framer is connected to transport the audio data. + + To compile this driver as a module, choose M here: the module + will be called snd-soc-framer. + + config SND_SOC_GTM601 tristate 'GTM601 UMTS modem audio codec' @@ -2059,6 +2075,24 @@ config SND_SOC_WCD938X_SDW The WCD9380/9385 is a audio codec IC Integrated in Qualcomm SoCs like SM8250. +config SND_SOC_WCD939X + depends on SND_SOC_WCD939X_SDW + tristate + depends on SOUNDWIRE || !SOUNDWIRE + depends on TYPEC || !TYPEC + select SND_SOC_WCD_CLASSH + +config SND_SOC_WCD939X_SDW + tristate "WCD9390/WCD9395 Codec - SDW" + select SND_SOC_WCD939X + select SND_SOC_WCD_MBHC + select REGMAP_IRQ + depends on SOUNDWIRE + select REGMAP_SOUNDWIRE + help + The WCD9390/9395 is a audio codec IC Integrated in + Qualcomm SoCs like SM8650. + config SND_SOC_WL1273 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index f53baa2b9565..4080646b2dd6 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -122,6 +122,7 @@ snd-soc-es8326-objs := es8326.o snd-soc-es8328-objs := es8328.o snd-soc-es8328-i2c-objs := es8328-i2c.o snd-soc-es8328-spi-objs := es8328-spi.o +snd-soc-framer-objs := framer-codec.o snd-soc-gtm601-objs := gtm601.o snd-soc-hdac-hdmi-objs := hdac_hdmi.o snd-soc-hdac-hda-objs := hdac_hda.o @@ -313,6 +314,8 @@ snd-soc-wcd9335-objs := wcd9335.o snd-soc-wcd934x-objs := wcd934x.o snd-soc-wcd938x-objs := wcd938x.o snd-soc-wcd938x-sdw-objs := wcd938x-sdw.o +snd-soc-wcd939x-objs := wcd939x.o +snd-soc-wcd939x-sdw-objs := wcd939x-sdw.o snd-soc-wl1273-objs := wl1273.o snd-soc-wm-adsp-objs := wm_adsp.o snd-soc-wm0010-objs := wm0010.o @@ -512,6 +515,7 @@ obj-$(CONFIG_SND_SOC_ES8326) += snd-soc-es8326.o obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o +obj-$(CONFIG_SND_SOC_FRAMER) += snd-soc-framer.o obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-soc-hdac-hda.o @@ -703,6 +707,11 @@ ifdef CONFIG_SND_SOC_WCD938X_SDW # avoid link failure by forcing sdw code built-in when needed obj-$(CONFIG_SND_SOC_WCD938X) += snd-soc-wcd938x-sdw.o endif +obj-$(CONFIG_SND_SOC_WCD939X) += snd-soc-wcd939x.o +ifdef CONFIG_SND_SOC_WCD939X_SDW +# avoid link failure by forcing sdw code built-in when needed +obj-$(CONFIG_SND_SOC_WCD939X) += snd-soc-wcd939x-sdw.o +endif obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o obj-$(CONFIG_SND_SOC_WM0010) += snd-soc-wm0010.o obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o diff --git a/sound/soc/codecs/framer-codec.c b/sound/soc/codecs/framer-codec.c new file mode 100644 index 000000000000..e5fcde9ee308 --- /dev/null +++ b/sound/soc/codecs/framer-codec.c @@ -0,0 +1,413 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Framer ALSA SoC driver +// +// Copyright 2023 CS GROUP France +// +// Author: Herve Codina <herve.codina@bootlin.com> + +#include <linux/clk.h> +#include <linux/framer/framer.h> +#include <linux/module.h> +#include <linux/notifier.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <sound/jack.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/tlv.h> + +#define FRAMER_NB_CHANNEL 32 +#define FRAMER_JACK_MASK (SND_JACK_LINEIN | SND_JACK_LINEOUT) + +struct framer_codec { + struct framer *framer; + struct device *dev; + struct snd_soc_jack jack; + struct notifier_block nb; + struct work_struct carrier_work; + int max_chan_playback; + int max_chan_capture; +}; + +static int framer_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int width) +{ + struct framer_codec *framer = snd_soc_component_get_drvdata(dai->component); + + switch (width) { + case 0: + /* Not set -> default 8 */ + case 8: + break; + default: + dev_err(dai->dev, "tdm slot width %d not supported\n", width); + return -EINVAL; + } + + framer->max_chan_playback = hweight32(tx_mask); + if (framer->max_chan_playback > FRAMER_NB_CHANNEL) { + dev_err(dai->dev, "too many tx slots defined (mask = 0x%x) supported max %d\n", + tx_mask, FRAMER_NB_CHANNEL); + return -EINVAL; + } + + framer->max_chan_capture = hweight32(rx_mask); + if (framer->max_chan_capture > FRAMER_NB_CHANNEL) { + dev_err(dai->dev, "too many rx slots defined (mask = 0x%x) supported max %d\n", + rx_mask, FRAMER_NB_CHANNEL); + return -EINVAL; + } + + return 0; +} + +/* + * The constraints for format/channel is to match with the number of 8bit + * time-slots available. + */ +static int framer_dai_hw_rule_channels_by_format(struct snd_soc_dai *dai, + struct snd_pcm_hw_params *params, + unsigned int nb_ts) +{ + struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + snd_pcm_format_t format = params_format(params); + struct snd_interval ch = {0}; + int width; + + width = snd_pcm_format_physical_width(format); + if (width == 8 || width == 16 || width == 32 || width == 64) { + ch.max = nb_ts * 8 / width; + } else { + dev_err(dai->dev, "format physical width %d not supported\n", width); + return -EINVAL; + } + + ch.min = ch.max ? 1 : 0; + + return snd_interval_refine(c, &ch); +} + +static int framer_dai_hw_rule_playback_channels_by_format(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_soc_dai *dai = rule->private; + struct framer_codec *framer = snd_soc_component_get_drvdata(dai->component); + + return framer_dai_hw_rule_channels_by_format(dai, params, framer->max_chan_playback); +} + +static int framer_dai_hw_rule_capture_channels_by_format(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_soc_dai *dai = rule->private; + struct framer_codec *framer = snd_soc_component_get_drvdata(dai->component); + + return framer_dai_hw_rule_channels_by_format(dai, params, framer->max_chan_capture); +} + +static int framer_dai_hw_rule_format_by_channels(struct snd_soc_dai *dai, + struct snd_pcm_hw_params *params, + unsigned int nb_ts) +{ + struct snd_mask *f_old = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + unsigned int channels = params_channels(params); + unsigned int slot_width; + snd_pcm_format_t format; + struct snd_mask f_new; + + if (!channels || channels > nb_ts) { + dev_err(dai->dev, "channels %u not supported\n", nb_ts); + return -EINVAL; + } + + slot_width = (nb_ts / channels) * 8; + + snd_mask_none(&f_new); + pcm_for_each_format(format) { + if (snd_mask_test_format(f_old, format)) { + if (snd_pcm_format_physical_width(format) <= slot_width) + snd_mask_set_format(&f_new, format); + } + } + + return snd_mask_refine(f_old, &f_new); +} + +static int framer_dai_hw_rule_playback_format_by_channels(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_soc_dai *dai = rule->private; + struct framer_codec *framer = snd_soc_component_get_drvdata(dai->component); + + return framer_dai_hw_rule_format_by_channels(dai, params, framer->max_chan_playback); +} + +static int framer_dai_hw_rule_capture_format_by_channels(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_soc_dai *dai = rule->private; + struct framer_codec *framer = snd_soc_component_get_drvdata(dai->component); + + return framer_dai_hw_rule_format_by_channels(dai, params, framer->max_chan_capture); +} + +static u64 framer_formats(u8 nb_ts) +{ + unsigned int format_width; + unsigned int chan_width; + snd_pcm_format_t format; + u64 formats_mask; + + if (!nb_ts) + return 0; + + formats_mask = 0; + chan_width = nb_ts * 8; + pcm_for_each_format(format) { + /* Support physical width multiple of 8bit */ + format_width = snd_pcm_format_physical_width(format); + if (format_width == 0 || format_width % 8) + continue; + + /* + * And support physical width that can fit N times in the + * channel + */ + if (format_width > chan_width || chan_width % format_width) + continue; + + formats_mask |= pcm_format_to_bits(format); + } + return formats_mask; +} + +static int framer_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct framer_codec *framer = snd_soc_component_get_drvdata(dai->component); + snd_pcm_hw_rule_func_t hw_rule_channels_by_format; + snd_pcm_hw_rule_func_t hw_rule_format_by_channels; + unsigned int frame_bits; + u64 format; + int ret; + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + format = framer_formats(framer->max_chan_capture); + hw_rule_channels_by_format = framer_dai_hw_rule_capture_channels_by_format; + hw_rule_format_by_channels = framer_dai_hw_rule_capture_format_by_channels; + frame_bits = framer->max_chan_capture * 8; + } else { + format = framer_formats(framer->max_chan_playback); + hw_rule_channels_by_format = framer_dai_hw_rule_playback_channels_by_format; + hw_rule_format_by_channels = framer_dai_hw_rule_playback_format_by_channels; + frame_bits = framer->max_chan_playback * 8; + } + + ret = snd_pcm_hw_constraint_mask64(substream->runtime, + SNDRV_PCM_HW_PARAM_FORMAT, format); + if (ret) { + dev_err(dai->dev, "Failed to add format constraint (%d)\n", ret); + return ret; + } + + ret = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + hw_rule_channels_by_format, dai, + SNDRV_PCM_HW_PARAM_FORMAT, -1); + if (ret) { + dev_err(dai->dev, "Failed to add channels rule (%d)\n", ret); + return ret; + } + + ret = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, + hw_rule_format_by_channels, dai, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + if (ret) { + dev_err(dai->dev, "Failed to add format rule (%d)\n", ret); + return ret; + } + + ret = snd_pcm_hw_constraint_single(substream->runtime, + SNDRV_PCM_HW_PARAM_FRAME_BITS, + frame_bits); + if (ret < 0) { + dev_err(dai->dev, "Failed to add frame_bits constraint (%d)\n", ret); + return ret; + } + + return 0; +} + +static u64 framer_dai_formats[] = { + SND_SOC_POSSIBLE_DAIFMT_DSP_B, +}; + +static const struct snd_soc_dai_ops framer_dai_ops = { + .startup = framer_dai_startup, + .set_tdm_slot = framer_dai_set_tdm_slot, + .auto_selectable_formats = framer_dai_formats, + .num_auto_selectable_formats = ARRAY_SIZE(framer_dai_formats), +}; + +static struct snd_soc_dai_driver framer_dai_driver = { + .name = "framer", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = FRAMER_NB_CHANNEL, + .rates = SNDRV_PCM_RATE_8000, + .formats = U64_MAX, /* Will be refined on DAI .startup() */ + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = FRAMER_NB_CHANNEL, + .rates = SNDRV_PCM_RATE_8000, + .formats = U64_MAX, /* Will be refined on DAI .startup() */ + }, + .ops = &framer_dai_ops, +}; + +static void framer_carrier_work(struct work_struct *work) +{ + struct framer_codec *framer = container_of(work, struct framer_codec, carrier_work); + struct framer_status framer_status; + int jack_status; + int ret; + + ret = framer_get_status(framer->framer, &framer_status); + if (ret) { + dev_err(framer->dev, "get framer status failed (%d)\n", ret); + return; + } + + jack_status = framer_status.link_is_on ? FRAMER_JACK_MASK : 0; + snd_soc_jack_report(&framer->jack, jack_status, FRAMER_JACK_MASK); +} + +static int framer_carrier_notifier(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct framer_codec *framer = container_of(nb, struct framer_codec, nb); + + switch (action) { + case FRAMER_EVENT_STATUS: + queue_work(system_power_efficient_wq, &framer->carrier_work); + break; + default: + return NOTIFY_DONE; + } + + return NOTIFY_OK; +} + +static int framer_component_probe(struct snd_soc_component *component) +{ + struct framer_codec *framer = snd_soc_component_get_drvdata(component); + struct framer_status status; + char *name; + int ret; + + INIT_WORK(&framer->carrier_work, framer_carrier_work); + + name = "carrier"; + if (component->name_prefix) { + name = kasprintf(GFP_KERNEL, "%s carrier", component->name_prefix); + if (!name) + return -ENOMEM; + } + + ret = snd_soc_card_jack_new(component->card, name, FRAMER_JACK_MASK, &framer->jack); + if (component->name_prefix) + kfree(name); /* A copy is done by snd_soc_card_jack_new */ + if (ret) { + dev_err(component->dev, "Cannot create jack\n"); + return ret; + } + + ret = framer_init(framer->framer); + if (ret) { + dev_err(component->dev, "framer init failed (%d)\n", ret); + return ret; + } + + ret = framer_power_on(framer->framer); + if (ret) { + dev_err(component->dev, "framer power-on failed (%d)\n", ret); + goto framer_exit; + } + + /* Be sure that get_status is supported */ + ret = framer_get_status(framer->framer, &status); + if (ret) { + dev_err(component->dev, "get framer status failed (%d)\n", ret); + goto framer_power_off; + } + + framer->nb.notifier_call = framer_carrier_notifier; + ret = framer_notifier_register(framer->framer, &framer->nb); + if (ret) { + dev_err(component->dev, "Cannot register event notifier\n"); + goto framer_power_off; + } + + /* Queue work to set the initial value */ + queue_work(system_power_efficient_wq, &framer->carrier_work); + + return 0; + +framer_power_off: + framer_power_off(framer->framer); +framer_exit: + framer_exit(framer->framer); + return ret; +} + +static void framer_component_remove(struct snd_soc_component *component) +{ + struct framer_codec *framer = snd_soc_component_get_drvdata(component); + + framer_notifier_unregister(framer->framer, &framer->nb); + cancel_work_sync(&framer->carrier_work); + framer_power_off(framer->framer); + framer_exit(framer->framer); +} + +static const struct snd_soc_component_driver framer_component_driver = { + .probe = framer_component_probe, + .remove = framer_component_remove, + .endianness = 1, +}; + +static int framer_codec_probe(struct platform_device *pdev) +{ + struct framer_codec *framer; + + framer = devm_kzalloc(&pdev->dev, sizeof(*framer), GFP_KERNEL); + if (!framer) + return -ENOMEM; + + framer->dev = &pdev->dev; + + /* Get framer from parents node */ + framer->framer = devm_framer_get(&pdev->dev, NULL); + if (IS_ERR(framer->framer)) + return dev_err_probe(&pdev->dev, PTR_ERR(framer->framer), "get framer failed\n"); + + platform_set_drvdata(pdev, framer); + + return devm_snd_soc_register_component(&pdev->dev, &framer_component_driver, + &framer_dai_driver, 1); +} + +static struct platform_driver framer_codec_driver = { + .driver = { + .name = "framer-codec", + }, + .probe = framer_codec_probe, +}; +module_platform_driver(framer_codec_driver); + +MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>"); +MODULE_DESCRIPTION("FRAMER ALSA SoC driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c index f66417a0f29f..22251fb2fa1f 100644 --- a/sound/soc/codecs/nau8540.c +++ b/sound/soc/codecs/nau8540.c @@ -26,7 +26,6 @@ #include <sound/tlv.h> #include "nau8540.h" - #define NAU_FREF_MAX 13500000 #define NAU_FVCO_MAX 100000000 #define NAU_FVCO_MIN 90000000 @@ -230,6 +229,49 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new digital_ch1_mux = SOC_DAPM_ENUM("Digital CH1 Select", digital_ch1_enum); +static int nau8540_fepga_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_update_bits(nau8540->regmap, NAU8540_REG_FEPGA2, + NAU8540_ACDC_CTL_MASK, NAU8540_ACDC_CTL_MIC1P_VREF | + NAU8540_ACDC_CTL_MIC1N_VREF | NAU8540_ACDC_CTL_MIC2P_VREF | + NAU8540_ACDC_CTL_MIC2N_VREF | NAU8540_ACDC_CTL_MIC3P_VREF | + NAU8540_ACDC_CTL_MIC3N_VREF | NAU8540_ACDC_CTL_MIC4P_VREF | + NAU8540_ACDC_CTL_MIC4N_VREF); + break; + default: + break; + } + return 0; +} + +static int nau8540_precharge_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_update_bits(nau8540->regmap, NAU8540_REG_REFERENCE, + NAU8540_DISCHRG_EN, NAU8540_DISCHRG_EN); + msleep(40); + regmap_update_bits(nau8540->regmap, NAU8540_REG_REFERENCE, + NAU8540_DISCHRG_EN, 0); + regmap_update_bits(nau8540->regmap, NAU8540_REG_FEPGA2, + NAU8540_ACDC_CTL_MASK, 0); + break; + default: + break; + } + return 0; +} + static int adc_power_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { @@ -237,8 +279,10 @@ static int adc_power_control(struct snd_soc_dapm_widget *w, struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component); if (SND_SOC_DAPM_EVENT_ON(event)) { - msleep(300); + msleep(160); /* DO12 and DO34 pad output enable */ + regmap_update_bits(nau8540->regmap, NAU8540_REG_POWER_MANAGEMENT, + NAU8540_ADC_ALL_EN, NAU8540_ADC_ALL_EN); regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL1, NAU8540_I2S_DO12_TRI, 0); regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL2, @@ -248,6 +292,8 @@ static int adc_power_control(struct snd_soc_dapm_widget *w, NAU8540_I2S_DO12_TRI, NAU8540_I2S_DO12_TRI); regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL2, NAU8540_I2S_DO34_TRI, NAU8540_I2S_DO34_TRI); + regmap_update_bits(nau8540->regmap, NAU8540_REG_POWER_MANAGEMENT, + NAU8540_ADC_ALL_EN, 0); } return 0; } @@ -274,28 +320,26 @@ static const struct snd_soc_dapm_widget nau8540_dapm_widgets[] = { SND_SOC_DAPM_INPUT("MIC3"), SND_SOC_DAPM_INPUT("MIC4"), - SND_SOC_DAPM_PGA("Frontend PGA1", NAU8540_REG_PWR, 12, 0, NULL, 0), - SND_SOC_DAPM_PGA("Frontend PGA2", NAU8540_REG_PWR, 13, 0, NULL, 0), - SND_SOC_DAPM_PGA("Frontend PGA3", NAU8540_REG_PWR, 14, 0, NULL, 0), - SND_SOC_DAPM_PGA("Frontend PGA4", NAU8540_REG_PWR, 15, 0, NULL, 0), - - SND_SOC_DAPM_ADC_E("ADC1", NULL, - NAU8540_REG_POWER_MANAGEMENT, 0, 0, adc_power_control, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - SND_SOC_DAPM_ADC_E("ADC2", NULL, - NAU8540_REG_POWER_MANAGEMENT, 1, 0, adc_power_control, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - SND_SOC_DAPM_ADC_E("ADC3", NULL, - NAU8540_REG_POWER_MANAGEMENT, 2, 0, adc_power_control, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - SND_SOC_DAPM_ADC_E("ADC4", NULL, - NAU8540_REG_POWER_MANAGEMENT, 3, 0, adc_power_control, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - - SND_SOC_DAPM_PGA("ADC CH1", NAU8540_REG_ANALOG_PWR, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("ADC CH2", NAU8540_REG_ANALOG_PWR, 1, 0, NULL, 0), - SND_SOC_DAPM_PGA("ADC CH3", NAU8540_REG_ANALOG_PWR, 2, 0, NULL, 0), - SND_SOC_DAPM_PGA("ADC CH4", NAU8540_REG_ANALOG_PWR, 3, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("Frontend PGA1", 0, NAU8540_REG_PWR, 12, 0, + nau8540_fepga_event, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_S("Frontend PGA2", 0, NAU8540_REG_PWR, 13, 0, + nau8540_fepga_event, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_S("Frontend PGA3", 0, NAU8540_REG_PWR, 14, 0, + nau8540_fepga_event, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_S("Frontend PGA4", 0, NAU8540_REG_PWR, 15, 0, + nau8540_fepga_event, SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_PGA_S("Precharge", 1, SND_SOC_NOPM, 0, 0, + nau8540_precharge_event, SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_PGA_S("ADC CH1", 2, NAU8540_REG_ANALOG_PWR, 0, 0, + adc_power_control, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA_S("ADC CH2", 2, NAU8540_REG_ANALOG_PWR, 1, 0, + adc_power_control, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA_S("ADC CH3", 2, NAU8540_REG_ANALOG_PWR, 2, 0, + adc_power_control, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA_S("ADC CH4", 2, NAU8540_REG_ANALOG_PWR, 3, 0, + adc_power_control, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_MUX("Digital CH4 Mux", SND_SOC_NOPM, 0, 0, &digital_ch4_mux), @@ -316,20 +360,20 @@ static const struct snd_soc_dapm_route nau8540_dapm_routes[] = { {"Frontend PGA3", NULL, "MIC3"}, {"Frontend PGA4", NULL, "MIC4"}, - {"ADC1", NULL, "Frontend PGA1"}, - {"ADC2", NULL, "Frontend PGA2"}, - {"ADC3", NULL, "Frontend PGA3"}, - {"ADC4", NULL, "Frontend PGA4"}, + {"Precharge", NULL, "Frontend PGA1"}, + {"Precharge", NULL, "Frontend PGA2"}, + {"Precharge", NULL, "Frontend PGA3"}, + {"Precharge", NULL, "Frontend PGA4"}, - {"ADC CH1", NULL, "ADC1"}, - {"ADC CH2", NULL, "ADC2"}, - {"ADC CH3", NULL, "ADC3"}, - {"ADC CH4", NULL, "ADC4"}, + {"ADC CH1", NULL, "Precharge"}, + {"ADC CH2", NULL, "Precharge"}, + {"ADC CH3", NULL, "Precharge"}, + {"ADC CH4", NULL, "Precharge"}, - {"ADC1", NULL, "MICBIAS1"}, - {"ADC2", NULL, "MICBIAS1"}, - {"ADC3", NULL, "MICBIAS2"}, - {"ADC4", NULL, "MICBIAS2"}, + {"ADC CH1", NULL, "MICBIAS1"}, + {"ADC CH2", NULL, "MICBIAS1"}, + {"ADC CH3", NULL, "MICBIAS2"}, + {"ADC CH4", NULL, "MICBIAS2"}, {"Digital CH1 Mux", "ADC channel 1", "ADC CH1"}, {"Digital CH1 Mux", "ADC channel 2", "ADC CH2"}, diff --git a/sound/soc/codecs/nau8540.h b/sound/soc/codecs/nau8540.h index 2ce6063d462b..762bb93b06fd 100644 --- a/sound/soc/codecs/nau8540.h +++ b/sound/soc/codecs/nau8540.h @@ -78,6 +78,7 @@ /* POWER_MANAGEMENT (0x01) */ +#define NAU8540_ADC_ALL_EN 0xf #define NAU8540_ADC4_EN (0x1 << 3) #define NAU8540_ADC3_EN (0x1 << 2) #define NAU8540_ADC2_EN (0x1 << 1) @@ -202,6 +203,7 @@ /* REFERENCE (0x68) */ #define NAU8540_PRECHARGE_DIS (0x1 << 13) #define NAU8540_GLOBAL_BIAS_EN (0x1 << 12) +#define NAU8540_DISCHRG_EN (0x1 << 11) /* FEPGA1 (0x69) */ #define NAU8540_FEPGA1_MODCH2_SHT_SFT 7 @@ -214,7 +216,16 @@ #define NAU8540_FEPGA2_MODCH4_SHT (0x1 << NAU8540_FEPGA2_MODCH4_SHT_SFT) #define NAU8540_FEPGA2_MODCH3_SHT_SFT 3 #define NAU8540_FEPGA2_MODCH3_SHT (0x1 << NAU8540_FEPGA2_MODCH3_SHT_SFT) - +#define NAU8540_ACDC_CTL_SFT 8 +#define NAU8540_ACDC_CTL_MASK (0xff << NAU8540_ACDC_CTL_SFT) +#define NAU8540_ACDC_CTL_MIC4N_VREF (0x1 << 15) +#define NAU8540_ACDC_CTL_MIC4P_VREF (0x1 << 14) +#define NAU8540_ACDC_CTL_MIC3N_VREF (0x1 << 13) +#define NAU8540_ACDC_CTL_MIC3P_VREF (0x1 << 12) +#define NAU8540_ACDC_CTL_MIC2N_VREF (0x1 << 11) +#define NAU8540_ACDC_CTL_MIC2P_VREF (0x1 << 10) +#define NAU8540_ACDC_CTL_MIC1N_VREF (0x1 << 9) +#define NAU8540_ACDC_CTL_MIC1P_VREF (0x1 << 8) /* System Clock Source */ enum { diff --git a/sound/soc/codecs/wcd-clsh-v2.h b/sound/soc/codecs/wcd-clsh-v2.h index 4e3653058275..eeb9bc5b01e2 100644 --- a/sound/soc/codecs/wcd-clsh-v2.h +++ b/sound/soc/codecs/wcd-clsh-v2.h @@ -47,6 +47,7 @@ enum wcd_codec_version { /* New CLSH after this */ WCD937X = 2, WCD938X = 3, + WCD939X = 4, }; struct wcd_clsh_ctrl; diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index 5da1934527f3..0e6218ed0e5e 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -16,6 +16,7 @@ #define HS_DETECT_PLUG_TIME_MS (3 * 1000) #define MBHC_BUTTON_PRESS_THRESHOLD_MIN 250 #define GND_MIC_SWAP_THRESHOLD 4 +#define GND_MIC_USBC_SWAP_THRESHOLD 2 #define WCD_FAKE_REMOVAL_MIN_PERIOD_MS 100 #define HPHL_CROSS_CONN_THRESHOLD 100 #define HS_VREF_MIN_VAL 1400 @@ -52,12 +53,15 @@ struct wcd_mbhc { struct wcd_mbhc_field *fields; /* Delayed work to report long button press */ struct delayed_work mbhc_btn_dwork; + /* Work to handle plug report */ + struct work_struct mbhc_plug_detect_work; /* Work to correct accessory type */ struct work_struct correct_plug_swch; struct mutex lock; int buttons_pressed; u32 hph_status; /* track headhpone status */ u8 current_plug; + unsigned int swap_thr; bool is_btn_press; bool in_swch_irq_handler; bool hs_detect_work_stop; @@ -506,14 +510,13 @@ static void wcd_mbhc_adc_detect_plug_type(struct wcd_mbhc *mbhc) } } -static irqreturn_t wcd_mbhc_mech_plug_detect_irq(int irq, void *data) +static void mbhc_plug_detect_fn(struct work_struct *work) { - struct snd_soc_component *component; + struct wcd_mbhc *mbhc = container_of(work, struct wcd_mbhc, mbhc_plug_detect_work); + struct snd_soc_component *component = mbhc->component; enum snd_jack_types jack_type; - struct wcd_mbhc *mbhc = data; bool detection_type; - component = mbhc->component; mutex_lock(&mbhc->lock); mbhc->in_swch_irq_handler = true; @@ -576,9 +579,51 @@ static irqreturn_t wcd_mbhc_mech_plug_detect_irq(int irq, void *data) exit: mbhc->in_swch_irq_handler = false; mutex_unlock(&mbhc->lock); +} + +static irqreturn_t wcd_mbhc_mech_plug_detect_irq(int irq, void *data) +{ + struct wcd_mbhc *mbhc = data; + + if (!mbhc->cfg->typec_analog_mux) + schedule_work(&mbhc->mbhc_plug_detect_work); + return IRQ_HANDLED; } +int wcd_mbhc_typec_report_unplug(struct wcd_mbhc *mbhc) +{ + + if (!mbhc || !mbhc->cfg->typec_analog_mux) + return -EINVAL; + + if (mbhc->mbhc_cb->clk_setup) + mbhc->mbhc_cb->clk_setup(mbhc->component, false); + + wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 0); + wcd_mbhc_write_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE, 0); + + schedule_work(&mbhc->mbhc_plug_detect_work); + + return 0; +} +EXPORT_SYMBOL_GPL(wcd_mbhc_typec_report_unplug); + +int wcd_mbhc_typec_report_plug(struct wcd_mbhc *mbhc) +{ + if (!mbhc || !mbhc->cfg->typec_analog_mux) + return -EINVAL; + + if (mbhc->mbhc_cb->clk_setup) + mbhc->mbhc_cb->clk_setup(mbhc->component, true); + wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 1); + + schedule_work(&mbhc->mbhc_plug_detect_work); + + return 0; +} +EXPORT_SYMBOL_GPL(wcd_mbhc_typec_report_plug); + static int wcd_mbhc_get_button_mask(struct wcd_mbhc *mbhc) { int mask = 0; @@ -725,14 +770,23 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc) mutex_lock(&mbhc->lock); - /* enable HS detection */ + if (mbhc->cfg->typec_analog_mux) + mbhc->swap_thr = GND_MIC_USBC_SWAP_THRESHOLD; + else + mbhc->swap_thr = GND_MIC_SWAP_THRESHOLD; + + /* setup HS detection */ if (mbhc->mbhc_cb->hph_pull_up_control_v2) mbhc->mbhc_cb->hph_pull_up_control_v2(component, - HS_PULLUP_I_DEFAULT); + mbhc->cfg->typec_analog_mux ? + HS_PULLUP_I_OFF : HS_PULLUP_I_DEFAULT); else if (mbhc->mbhc_cb->hph_pull_up_control) - mbhc->mbhc_cb->hph_pull_up_control(component, I_DEFAULT); + mbhc->mbhc_cb->hph_pull_up_control(component, + mbhc->cfg->typec_analog_mux ? + I_OFF : I_DEFAULT); else - wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_CTRL, 3); + wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_CTRL, + mbhc->cfg->typec_analog_mux ? 0 : 3); wcd_mbhc_write_field(mbhc, WCD_MBHC_HPHL_PLUG_TYPE, mbhc->cfg->hphl_swh); wcd_mbhc_write_field(mbhc, WCD_MBHC_GND_PLUG_TYPE, mbhc->cfg->gnd_swh); @@ -741,10 +795,18 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc) mbhc->mbhc_cb->mbhc_gnd_det_ctrl(component, true); wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, 1); - wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 1); + /* Plug detect is triggered manually if analog goes through USBCC */ + if (mbhc->cfg->typec_analog_mux) + wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 0); + else + wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 1); - /* Insertion debounce set to 96ms */ - wcd_mbhc_write_field(mbhc, WCD_MBHC_INSREM_DBNC, 6); + if (mbhc->cfg->typec_analog_mux) + /* Insertion debounce set to 48ms */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_INSREM_DBNC, 4); + else + /* Insertion debounce set to 96ms */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_INSREM_DBNC, 6); /* Button Debounce set to 16ms */ wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_DBNC, 2); @@ -753,7 +815,8 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc) mbhc->mbhc_cb->mbhc_bias(component, true); /* enable MBHC clock */ if (mbhc->mbhc_cb->clk_setup) - mbhc->mbhc_cb->clk_setup(component, true); + mbhc->mbhc_cb->clk_setup(component, + mbhc->cfg->typec_analog_mux ? false : true); /* program HS_VREF value */ wcd_program_hs_vref(mbhc); @@ -1115,7 +1178,7 @@ static void wcd_correct_swch_plug(struct work_struct *work) do { cross_conn = wcd_check_cross_conn(mbhc); try++; - } while (try < GND_MIC_SWAP_THRESHOLD); + } while (try < mbhc->swap_thr); if (cross_conn > 0) { plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP; @@ -1183,7 +1246,7 @@ correct_plug_type: cross_conn = wcd_check_cross_conn(mbhc); if (cross_conn > 0) { /* cross-connection */ pt_gnd_mic_swap_cnt++; - if (pt_gnd_mic_swap_cnt < GND_MIC_SWAP_THRESHOLD) + if (pt_gnd_mic_swap_cnt < mbhc->swap_thr) continue; else plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP; @@ -1194,7 +1257,7 @@ correct_plug_type: } else /* Error if (cross_conn < 0) */ continue; - if (pt_gnd_mic_swap_cnt == GND_MIC_SWAP_THRESHOLD) { + if (pt_gnd_mic_swap_cnt == mbhc->swap_thr) { /* US_EU gpio present, flip switch */ if (mbhc->cfg->swap_gnd_mic) { if (mbhc->cfg->swap_gnd_mic(component, true)) @@ -1473,6 +1536,7 @@ struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component, mutex_init(&mbhc->lock); INIT_WORK(&mbhc->correct_plug_swch, wcd_correct_swch_plug); + INIT_WORK(&mbhc->mbhc_plug_detect_work, mbhc_plug_detect_fn); ret = request_threaded_irq(mbhc->intr_ids->mbhc_sw_intr, NULL, wcd_mbhc_mech_plug_detect_irq, @@ -1562,6 +1626,7 @@ void wcd_mbhc_deinit(struct wcd_mbhc *mbhc) mutex_lock(&mbhc->lock); wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch); + cancel_work_sync(&mbhc->mbhc_plug_detect_work); mutex_unlock(&mbhc->lock); kfree(mbhc); diff --git a/sound/soc/codecs/wcd-mbhc-v2.h b/sound/soc/codecs/wcd-mbhc-v2.h index 006118f3e81f..df68e99c81a3 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.h +++ b/sound/soc/codecs/wcd-mbhc-v2.h @@ -193,6 +193,7 @@ struct wcd_mbhc_config { int v_hs_max; int num_btn; bool mono_stero_detection; + bool typec_analog_mux; bool (*swap_gnd_mic)(struct snd_soc_component *component, bool active); bool hs_ext_micbias; bool gnd_det_en; @@ -273,6 +274,8 @@ int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *mbhc_cfg, void wcd_mbhc_stop(struct wcd_mbhc *mbhc); void wcd_mbhc_set_hph_type(struct wcd_mbhc *mbhc, int hph_type); int wcd_mbhc_get_hph_type(struct wcd_mbhc *mbhc); +int wcd_mbhc_typec_report_plug(struct wcd_mbhc *mbhc); +int wcd_mbhc_typec_report_unplug(struct wcd_mbhc *mbhc); struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component, const struct wcd_mbhc_cb *mbhc_cb, const struct wcd_mbhc_intr *mbhc_cdc_intr_ids, diff --git a/sound/soc/codecs/wcd939x-sdw.c b/sound/soc/codecs/wcd939x-sdw.c new file mode 100644 index 000000000000..8acb5651c5bc --- /dev/null +++ b/sound/soc/codecs/wcd939x-sdw.c @@ -0,0 +1,1551 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023, Linaro Limited + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/component.h> +#include <linux/pm_runtime.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/of.h> +#include <linux/soundwire/sdw.h> +#include <linux/soundwire/sdw_type.h> +#include <linux/soundwire/sdw_registers.h> +#include <linux/regmap.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include "wcd939x.h" + +#define SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(m) (0xE0 + 0x10 * (m)) + +static struct wcd939x_sdw_ch_info wcd939x_sdw_rx_ch_info[] = { + WCD_SDW_CH(WCD939X_HPH_L, WCD939X_HPH_PORT, BIT(0)), + WCD_SDW_CH(WCD939X_HPH_R, WCD939X_HPH_PORT, BIT(1)), + WCD_SDW_CH(WCD939X_CLSH, WCD939X_CLSH_PORT, BIT(0)), + WCD_SDW_CH(WCD939X_COMP_L, WCD939X_COMP_PORT, BIT(0)), + WCD_SDW_CH(WCD939X_COMP_R, WCD939X_COMP_PORT, BIT(1)), + WCD_SDW_CH(WCD939X_LO, WCD939X_LO_PORT, BIT(0)), + WCD_SDW_CH(WCD939X_DSD_L, WCD939X_DSD_PORT, BIT(0)), + WCD_SDW_CH(WCD939X_DSD_R, WCD939X_DSD_PORT, BIT(1)), + WCD_SDW_CH(WCD939X_HIFI_PCM_L, WCD939X_HIFI_PCM_PORT, BIT(0)), + WCD_SDW_CH(WCD939X_HIFI_PCM_R, WCD939X_HIFI_PCM_PORT, BIT(1)), +}; + +static struct wcd939x_sdw_ch_info wcd939x_sdw_tx_ch_info[] = { + WCD_SDW_CH(WCD939X_ADC1, WCD939X_ADC_1_4_PORT, BIT(0)), + WCD_SDW_CH(WCD939X_ADC2, WCD939X_ADC_1_4_PORT, BIT(1)), + WCD_SDW_CH(WCD939X_ADC3, WCD939X_ADC_1_4_PORT, BIT(2)), + WCD_SDW_CH(WCD939X_ADC4, WCD939X_ADC_1_4_PORT, BIT(3)), + WCD_SDW_CH(WCD939X_DMIC0, WCD939X_DMIC_0_3_MBHC_PORT, BIT(0)), + WCD_SDW_CH(WCD939X_DMIC1, WCD939X_DMIC_0_3_MBHC_PORT, BIT(1)), + WCD_SDW_CH(WCD939X_MBHC, WCD939X_DMIC_0_3_MBHC_PORT, BIT(2)), + WCD_SDW_CH(WCD939X_DMIC2, WCD939X_DMIC_0_3_MBHC_PORT, BIT(2)), + WCD_SDW_CH(WCD939X_DMIC3, WCD939X_DMIC_0_3_MBHC_PORT, BIT(3)), + WCD_SDW_CH(WCD939X_DMIC4, WCD939X_DMIC_3_7_PORT, BIT(0)), + WCD_SDW_CH(WCD939X_DMIC5, WCD939X_DMIC_3_7_PORT, BIT(1)), + WCD_SDW_CH(WCD939X_DMIC6, WCD939X_DMIC_3_7_PORT, BIT(2)), + WCD_SDW_CH(WCD939X_DMIC7, WCD939X_DMIC_3_7_PORT, BIT(3)), +}; + +static struct sdw_dpn_prop wcd939x_rx_dpn_prop[WCD939X_MAX_RX_SWR_PORTS] = { + { + .num = WCD939X_HPH_PORT, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 2, + .simple_ch_prep_sm = true, + }, + { + .num = WCD939X_CLSH_PORT, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 1, + .simple_ch_prep_sm = true, + }, + { + .num = WCD939X_COMP_PORT, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 2, + .simple_ch_prep_sm = true, + }, + { + .num = WCD939X_LO_PORT, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 1, + .simple_ch_prep_sm = true, + }, + { + .num = WCD939X_DSD_PORT, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 2, + .simple_ch_prep_sm = true, + }, + { + .num = WCD939X_HIFI_PCM_PORT, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 2, + .simple_ch_prep_sm = true, + } +}; + +static struct sdw_dpn_prop wcd939x_tx_dpn_prop[WCD939X_MAX_TX_SWR_PORTS] = { + { + .num = WCD939X_ADC_1_4_PORT, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 4, + .simple_ch_prep_sm = true, + }, + { + .num = WCD939X_ADC_DMIC_1_2_PORT, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 4, + .simple_ch_prep_sm = true, + }, + { + .num = WCD939X_DMIC_0_3_MBHC_PORT, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 4, + .simple_ch_prep_sm = true, + }, + { + .num = WCD939X_DMIC_3_7_PORT, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 4, + .simple_ch_prep_sm = true, + } +}; + +struct device *wcd939x_sdw_device_get(struct device_node *np) +{ + return bus_find_device_by_of_node(&sdw_bus_type, np); +} +EXPORT_SYMBOL_GPL(wcd939x_sdw_device_get); + +unsigned int wcd939x_swr_get_current_bank(struct sdw_slave *sdev) +{ + return FIELD_GET(SDW_SCP_STAT_CURR_BANK, + sdw_read(sdev, SDW_SCP_CTRL)); +} +EXPORT_SYMBOL_GPL(wcd939x_swr_get_current_bank); + +int wcd939x_sdw_hw_params(struct wcd939x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct sdw_port_config port_config[WCD939X_MAX_SWR_PORTS]; + unsigned long ch_mask; + int i, j; + + wcd->sconfig.ch_count = 1; + wcd->active_ports = 0; + for (i = 0; i < WCD939X_MAX_SWR_PORTS; i++) { + ch_mask = wcd->port_config[i].ch_mask; + + if (!ch_mask) + continue; + + for_each_set_bit(j, &ch_mask, 4) + wcd->sconfig.ch_count++; + + port_config[wcd->active_ports] = wcd->port_config[i]; + wcd->active_ports++; + } + + wcd->sconfig.bps = 1; + wcd->sconfig.frame_rate = params_rate(params); + if (wcd->is_tx) + wcd->sconfig.direction = SDW_DATA_DIR_TX; + else + wcd->sconfig.direction = SDW_DATA_DIR_RX; + + wcd->sconfig.type = SDW_STREAM_PCM; + + return sdw_stream_add_slave(wcd->sdev, &wcd->sconfig, &port_config[0], + wcd->active_ports, wcd->sruntime); +} +EXPORT_SYMBOL_GPL(wcd939x_sdw_hw_params); + +int wcd939x_sdw_free(struct wcd939x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + sdw_stream_remove_slave(wcd->sdev, wcd->sruntime); + + return 0; +} +EXPORT_SYMBOL_GPL(wcd939x_sdw_free); + +int wcd939x_sdw_set_sdw_stream(struct wcd939x_sdw_priv *wcd, + struct snd_soc_dai *dai, void *stream, + int direction) +{ + wcd->sruntime = stream; + + return 0; +} +EXPORT_SYMBOL_GPL(wcd939x_sdw_set_sdw_stream); + +struct regmap *wcd939x_swr_get_regmap(struct wcd939x_sdw_priv *wcd) +{ + if (wcd->regmap) + return wcd->regmap; + + return ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL_GPL(wcd939x_swr_get_regmap); + +static int wcd9390_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + struct wcd939x_sdw_priv *wcd = dev_get_drvdata(&slave->dev); + + if (wcd->regmap && status == SDW_SLAVE_ATTACHED) { + /* Write out any cached changes that happened between probe and attach */ + regcache_cache_only(wcd->regmap, false); + return regcache_sync(wcd->regmap); + } + + return 0; +} + +static int wcd9390_bus_config(struct sdw_slave *slave, + struct sdw_bus_params *params) +{ + sdw_write(slave, SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(params->next_bank), + 0x01); + + return 0; +} + +/* + * Handle Soundwire out-of-band interrupt event by triggering + * the first irq of the slave_irq irq domain, which then will + * be handled by the regmap_irq threaded irq. + * Looping is to ensure no interrupts were missed in the process. + */ +static int wcd9390_interrupt_callback(struct sdw_slave *slave, + struct sdw_slave_intr_status *status) +{ + struct wcd939x_sdw_priv *wcd = dev_get_drvdata(&slave->dev); + struct irq_domain *slave_irq = wcd->slave_irq; + u32 sts1, sts2, sts3; + + do { + handle_nested_irq(irq_find_mapping(slave_irq, 0)); + regmap_read(wcd->regmap, WCD939X_DIGITAL_INTR_STATUS_0, &sts1); + regmap_read(wcd->regmap, WCD939X_DIGITAL_INTR_STATUS_1, &sts2); + regmap_read(wcd->regmap, WCD939X_DIGITAL_INTR_STATUS_2, &sts3); + + } while (sts1 || sts2 || sts3); + + return IRQ_HANDLED; +} + +static const struct reg_default wcd939x_defaults[] = { + /* Default values except for Read-Only & Volatile registers */ + { WCD939X_ANA_PAGE, 0x00 }, + { WCD939X_ANA_BIAS, 0x00 }, + { WCD939X_ANA_RX_SUPPLIES, 0x00 }, + { WCD939X_ANA_HPH, 0x0c }, + { WCD939X_ANA_EAR, 0x00 }, + { WCD939X_ANA_EAR_COMPANDER_CTL, 0x02 }, + { WCD939X_ANA_TX_CH1, 0x20 }, + { WCD939X_ANA_TX_CH2, 0x00 }, + { WCD939X_ANA_TX_CH3, 0x20 }, + { WCD939X_ANA_TX_CH4, 0x00 }, + { WCD939X_ANA_MICB1_MICB2_DSP_EN_LOGIC, 0x00 }, + { WCD939X_ANA_MICB3_DSP_EN_LOGIC, 0x00 }, + { WCD939X_ANA_MBHC_MECH, 0x39 }, + { WCD939X_ANA_MBHC_ELECT, 0x08 }, + { WCD939X_ANA_MBHC_ZDET, 0x00 }, + { WCD939X_ANA_MBHC_BTN0, 0x00 }, + { WCD939X_ANA_MBHC_BTN1, 0x10 }, + { WCD939X_ANA_MBHC_BTN2, 0x20 }, + { WCD939X_ANA_MBHC_BTN3, 0x30 }, + { WCD939X_ANA_MBHC_BTN4, 0x40 }, + { WCD939X_ANA_MBHC_BTN5, 0x50 }, + { WCD939X_ANA_MBHC_BTN6, 0x60 }, + { WCD939X_ANA_MBHC_BTN7, 0x70 }, + { WCD939X_ANA_MICB1, 0x10 }, + { WCD939X_ANA_MICB2, 0x10 }, + { WCD939X_ANA_MICB2_RAMP, 0x00 }, + { WCD939X_ANA_MICB3, 0x00 }, + { WCD939X_ANA_MICB4, 0x00 }, + { WCD939X_BIAS_CTL, 0x2a }, + { WCD939X_BIAS_VBG_FINE_ADJ, 0x55 }, + { WCD939X_LDOL_VDDCX_ADJUST, 0x01 }, + { WCD939X_LDOL_DISABLE_LDOL, 0x00 }, + { WCD939X_MBHC_CTL_CLK, 0x00 }, + { WCD939X_MBHC_CTL_ANA, 0x00 }, + { WCD939X_MBHC_ZDET_VNEG_CTL, 0x00 }, + { WCD939X_MBHC_ZDET_BIAS_CTL, 0x46 }, + { WCD939X_MBHC_CTL_BCS, 0x00 }, + { WCD939X_MBHC_TEST_CTL, 0x00 }, + { WCD939X_LDOH_MODE, 0x2b }, + { WCD939X_LDOH_BIAS, 0x68 }, + { WCD939X_LDOH_STB_LOADS, 0x00 }, + { WCD939X_LDOH_SLOWRAMP, 0x50 }, + { WCD939X_MICB1_TEST_CTL_1, 0x1a }, + { WCD939X_MICB1_TEST_CTL_2, 0x00 }, + { WCD939X_MICB1_TEST_CTL_3, 0xa4 }, + { WCD939X_MICB2_TEST_CTL_1, 0x1a }, + { WCD939X_MICB2_TEST_CTL_2, 0x00 }, + { WCD939X_MICB2_TEST_CTL_3, 0x24 }, + { WCD939X_MICB3_TEST_CTL_1, 0x9a }, + { WCD939X_MICB3_TEST_CTL_2, 0x80 }, + { WCD939X_MICB3_TEST_CTL_3, 0x24 }, + { WCD939X_MICB4_TEST_CTL_1, 0x1a }, + { WCD939X_MICB4_TEST_CTL_2, 0x80 }, + { WCD939X_MICB4_TEST_CTL_3, 0x24 }, + { WCD939X_TX_COM_ADC_VCM, 0x39 }, + { WCD939X_TX_COM_BIAS_ATEST, 0xe0 }, + { WCD939X_TX_COM_SPARE1, 0x00 }, + { WCD939X_TX_COM_SPARE2, 0x00 }, + { WCD939X_TX_COM_TXFE_DIV_CTL, 0x22 }, + { WCD939X_TX_COM_TXFE_DIV_START, 0x00 }, + { WCD939X_TX_COM_SPARE3, 0x00 }, + { WCD939X_TX_COM_SPARE4, 0x00 }, + { WCD939X_TX_1_2_TEST_EN, 0xcc }, + { WCD939X_TX_1_2_ADC_IB, 0xe9 }, + { WCD939X_TX_1_2_ATEST_REFCTL, 0x0b }, + { WCD939X_TX_1_2_TEST_CTL, 0x38 }, + { WCD939X_TX_1_2_TEST_BLK_EN1, 0xff }, + { WCD939X_TX_1_2_TXFE1_CLKDIV, 0x00 }, + { WCD939X_TX_3_4_TEST_EN, 0xcc }, + { WCD939X_TX_3_4_ADC_IB, 0xe9 }, + { WCD939X_TX_3_4_ATEST_REFCTL, 0x0b }, + { WCD939X_TX_3_4_TEST_CTL, 0x38 }, + { WCD939X_TX_3_4_TEST_BLK_EN3, 0xff }, + { WCD939X_TX_3_4_TXFE3_CLKDIV, 0x00 }, + { WCD939X_TX_3_4_TEST_BLK_EN2, 0xfb }, + { WCD939X_TX_3_4_TXFE2_CLKDIV, 0x00 }, + { WCD939X_TX_3_4_SPARE1, 0x00 }, + { WCD939X_TX_3_4_TEST_BLK_EN4, 0xfb }, + { WCD939X_TX_3_4_TXFE4_CLKDIV, 0x00 }, + { WCD939X_TX_3_4_SPARE2, 0x00 }, + { WCD939X_CLASSH_MODE_1, 0x40 }, + { WCD939X_CLASSH_MODE_2, 0x3a }, + { WCD939X_CLASSH_MODE_3, 0xf0 }, + { WCD939X_CLASSH_CTRL_VCL_1, 0x7c }, + { WCD939X_CLASSH_CTRL_VCL_2, 0x82 }, + { WCD939X_CLASSH_CTRL_CCL_1, 0x31 }, + { WCD939X_CLASSH_CTRL_CCL_2, 0x80 }, + { WCD939X_CLASSH_CTRL_CCL_3, 0x80 }, + { WCD939X_CLASSH_CTRL_CCL_4, 0x51 }, + { WCD939X_CLASSH_CTRL_CCL_5, 0x00 }, + { WCD939X_CLASSH_BUCK_TMUX_A_D, 0x00 }, + { WCD939X_CLASSH_BUCK_SW_DRV_CNTL, 0x77 }, + { WCD939X_CLASSH_SPARE, 0x80 }, + { WCD939X_FLYBACK_EN, 0x4e }, + { WCD939X_FLYBACK_VNEG_CTRL_1, 0x0b }, + { WCD939X_FLYBACK_VNEG_CTRL_2, 0x45 }, + { WCD939X_FLYBACK_VNEG_CTRL_3, 0x14 }, + { WCD939X_FLYBACK_VNEG_CTRL_4, 0xdb }, + { WCD939X_FLYBACK_VNEG_CTRL_5, 0x83 }, + { WCD939X_FLYBACK_VNEG_CTRL_6, 0x98 }, + { WCD939X_FLYBACK_VNEG_CTRL_7, 0xa9 }, + { WCD939X_FLYBACK_VNEG_CTRL_8, 0x68 }, + { WCD939X_FLYBACK_VNEG_CTRL_9, 0x66 }, + { WCD939X_FLYBACK_VNEGDAC_CTRL_1, 0xed }, + { WCD939X_FLYBACK_VNEGDAC_CTRL_2, 0xf8 }, + { WCD939X_FLYBACK_VNEGDAC_CTRL_3, 0xa6 }, + { WCD939X_FLYBACK_CTRL_1, 0x65 }, + { WCD939X_FLYBACK_TEST_CTL, 0x02 }, + { WCD939X_RX_AUX_SW_CTL, 0x00 }, + { WCD939X_RX_PA_AUX_IN_CONN, 0x01 }, + { WCD939X_RX_TIMER_DIV, 0x32 }, + { WCD939X_RX_OCP_CTL, 0x1f }, + { WCD939X_RX_OCP_COUNT, 0x77 }, + { WCD939X_RX_BIAS_EAR_DAC, 0xa0 }, + { WCD939X_RX_BIAS_EAR_AMP, 0xaa }, + { WCD939X_RX_BIAS_HPH_LDO, 0xa9 }, + { WCD939X_RX_BIAS_HPH_PA, 0xaa }, + { WCD939X_RX_BIAS_HPH_RDACBUFF_CNP2, 0xca }, + { WCD939X_RX_BIAS_HPH_RDAC_LDO, 0x88 }, + { WCD939X_RX_BIAS_HPH_CNP1, 0x82 }, + { WCD939X_RX_BIAS_HPH_LOWPOWER, 0x82 }, + { WCD939X_RX_BIAS_AUX_DAC, 0xa0 }, + { WCD939X_RX_BIAS_AUX_AMP, 0xaa }, + { WCD939X_RX_BIAS_VNEGDAC_BLEEDER, 0x50 }, + { WCD939X_RX_BIAS_MISC, 0x00 }, + { WCD939X_RX_BIAS_BUCK_RST, 0x08 }, + { WCD939X_RX_BIAS_BUCK_VREF_ERRAMP, 0x44 }, + { WCD939X_RX_BIAS_FLYB_ERRAMP, 0x40 }, + { WCD939X_RX_BIAS_FLYB_BUFF, 0xaa }, + { WCD939X_RX_BIAS_FLYB_MID_RST, 0x14 }, + { WCD939X_HPH_CNP_EN, 0x80 }, + { WCD939X_HPH_CNP_WG_CTL, 0x9a }, + { WCD939X_HPH_CNP_WG_TIME, 0x14 }, + { WCD939X_HPH_OCP_CTL, 0x28 }, + { WCD939X_HPH_AUTO_CHOP, 0x56 }, + { WCD939X_HPH_CHOP_CTL, 0x83 }, + { WCD939X_HPH_PA_CTL1, 0x46 }, + { WCD939X_HPH_PA_CTL2, 0x50 }, + { WCD939X_HPH_L_EN, 0x80 }, + { WCD939X_HPH_L_TEST, 0xe0 }, + { WCD939X_HPH_L_ATEST, 0x50 }, + { WCD939X_HPH_R_EN, 0x80 }, + { WCD939X_HPH_R_TEST, 0xe0 }, + { WCD939X_HPH_R_ATEST, 0x50 }, + { WCD939X_HPH_RDAC_CLK_CTL1, 0x80 }, + { WCD939X_HPH_RDAC_CLK_CTL2, 0x0b }, + { WCD939X_HPH_RDAC_LDO_CTL, 0x33 }, + { WCD939X_HPH_RDAC_CHOP_CLK_LP_CTL, 0x00 }, + { WCD939X_HPH_REFBUFF_UHQA_CTL, 0x00 }, + { WCD939X_HPH_REFBUFF_LP_CTL, 0x8e }, + { WCD939X_HPH_L_DAC_CTL, 0x20 }, + { WCD939X_HPH_R_DAC_CTL, 0x20 }, + { WCD939X_HPH_SURGE_COMP_SEL, 0x55 }, + { WCD939X_HPH_SURGE_EN, 0x19 }, + { WCD939X_HPH_SURGE_MISC1, 0xa0 }, + { WCD939X_EAR_EN, 0x22 }, + { WCD939X_EAR_PA_CON, 0x44 }, + { WCD939X_EAR_SP_CON, 0xdb }, + { WCD939X_EAR_DAC_CON, 0x80 }, + { WCD939X_EAR_CNP_FSM_CON, 0xb2 }, + { WCD939X_EAR_TEST_CTL, 0x00 }, + { WCD939X_FLYBACK_NEW_CTRL_2, 0x00 }, + { WCD939X_FLYBACK_NEW_CTRL_3, 0x00 }, + { WCD939X_FLYBACK_NEW_CTRL_4, 0x44 }, + { WCD939X_ANA_NEW_PAGE, 0x00 }, + { WCD939X_HPH_NEW_ANA_HPH2, 0x00 }, + { WCD939X_HPH_NEW_ANA_HPH3, 0x00 }, + { WCD939X_SLEEP_CTL, 0x18 }, + { WCD939X_SLEEP_WATCHDOG_CTL, 0x00 }, + { WCD939X_MBHC_NEW_ELECT_REM_CLAMP_CTL, 0x00 }, + { WCD939X_MBHC_NEW_CTL_1, 0x02 }, + { WCD939X_MBHC_NEW_CTL_2, 0x05 }, + { WCD939X_MBHC_NEW_PLUG_DETECT_CTL, 0xe9 }, + { WCD939X_MBHC_NEW_ZDET_ANA_CTL, 0x0f }, + { WCD939X_MBHC_NEW_ZDET_RAMP_CTL, 0x00 }, + { WCD939X_TX_NEW_CH12_MUX, 0x11 }, + { WCD939X_TX_NEW_CH34_MUX, 0x23 }, + { WCD939X_DIE_CRACK_DET_EN, 0x00 }, + { WCD939X_HPH_NEW_INT_RDAC_GAIN_CTL, 0x00 }, + { WCD939X_HPH_NEW_INT_PA_GAIN_CTL_L, 0x00 }, + { WCD939X_HPH_NEW_INT_RDAC_VREF_CTL, 0x08 }, + { WCD939X_HPH_NEW_INT_RDAC_OVERRIDE_CTL, 0x00 }, + { WCD939X_HPH_NEW_INT_PA_GAIN_CTL_R, 0x00 }, + { WCD939X_HPH_NEW_INT_PA_MISC1, 0x32 }, + { WCD939X_HPH_NEW_INT_PA_MISC2, 0x00 }, + { WCD939X_HPH_NEW_INT_PA_RDAC_MISC, 0x00 }, + { WCD939X_HPH_NEW_INT_TIMER1, 0xfe }, + { WCD939X_HPH_NEW_INT_TIMER2, 0x02 }, + { WCD939X_HPH_NEW_INT_TIMER3, 0x4e }, + { WCD939X_HPH_NEW_INT_TIMER4, 0x54 }, + { WCD939X_HPH_NEW_INT_PA_RDAC_MISC2, 0x0b }, + { WCD939X_HPH_NEW_INT_PA_RDAC_MISC3, 0x00 }, + { WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0xa0 }, + { WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0xa0 }, + { WCD939X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI, 0x64 }, + { WCD939X_RX_NEW_INT_HPH_RDAC_BIAS_ULP, 0x01 }, + { WCD939X_RX_NEW_INT_HPH_RDAC_LDO_LP, 0x11 }, + { WCD939X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL, 0x57 }, + { WCD939X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL, 0x01 }, + { WCD939X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x00 }, + { WCD939X_MBHC_NEW_INT_ZDET_CLK_AND_MOISTURE_CTL_NEW, 0x47 }, + { WCD939X_EAR_INT_NEW_CHOPPER_CON, 0xa8 }, + { WCD939X_EAR_INT_NEW_CNP_VCM_CON1, 0x42 }, + { WCD939X_EAR_INT_NEW_CNP_VCM_CON2, 0x22 }, + { WCD939X_EAR_INT_NEW_DYNAMIC_BIAS, 0x00 }, + { WCD939X_SLEEP_INT_WATCHDOG_CTL_1, 0x0a }, + { WCD939X_SLEEP_INT_WATCHDOG_CTL_2, 0x0a }, + { WCD939X_DIE_CRACK_INT_DET_INT1, 0x02 }, + { WCD939X_DIE_CRACK_INT_DET_INT2, 0x60 }, + { WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_L2, 0xff }, + { WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_L1, 0x7f }, + { WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_L0, 0x3f }, + { WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_ULP1P2M, 0x1f }, + { WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_ULP0P6M, 0x0f }, + { WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG1_L2L1, 0xd7 }, + { WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG1_L0, 0xc8 }, + { WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG1_ULP, 0xc6 }, + { WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2MAIN_L2L1, 0x95 }, + { WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2MAIN_L0, 0x6a }, + { WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2MAIN_ULP, 0x05 }, + { WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2CASC_L2L1L0, 0xa5 }, + { WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2CASC_ULP, 0x13 }, + { WCD939X_TX_COM_NEW_INT_ADC_SCBIAS_L2L1, 0x88 }, + { WCD939X_TX_COM_NEW_INT_ADC_SCBIAS_L0ULP, 0x42 }, + { WCD939X_TX_COM_NEW_INT_ADC_INT_L2, 0xff }, + { WCD939X_TX_COM_NEW_INT_ADC_INT_L1, 0x64 }, + { WCD939X_TX_COM_NEW_INT_ADC_INT_L0, 0x64 }, + { WCD939X_TX_COM_NEW_INT_ADC_INT_ULP, 0x77 }, + { WCD939X_DIGITAL_PAGE, 0x00 }, + { WCD939X_DIGITAL_SWR_TX_CLK_RATE, 0x00 }, + { WCD939X_DIGITAL_CDC_RST_CTL, 0x03 }, + { WCD939X_DIGITAL_TOP_CLK_CFG, 0x00 }, + { WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 0x00 }, + { WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 0xf0 }, + { WCD939X_DIGITAL_SWR_RST_EN, 0x00 }, + { WCD939X_DIGITAL_CDC_PATH_MODE, 0x55 }, + { WCD939X_DIGITAL_CDC_RX_RST, 0x00 }, + { WCD939X_DIGITAL_CDC_RX0_CTL, 0xfc }, + { WCD939X_DIGITAL_CDC_RX1_CTL, 0xfc }, + { WCD939X_DIGITAL_CDC_RX2_CTL, 0xfc }, + { WCD939X_DIGITAL_CDC_TX_ANA_MODE_0_1, 0x00 }, + { WCD939X_DIGITAL_CDC_TX_ANA_MODE_2_3, 0x00 }, + { WCD939X_DIGITAL_CDC_COMP_CTL_0, 0x00 }, + { WCD939X_DIGITAL_CDC_ANA_TX_CLK_CTL, 0x1e }, + { WCD939X_DIGITAL_CDC_HPH_DSM_A1_0, 0x00 }, + { WCD939X_DIGITAL_CDC_HPH_DSM_A1_1, 0x01 }, + { WCD939X_DIGITAL_CDC_HPH_DSM_A2_0, 0x63 }, + { WCD939X_DIGITAL_CDC_HPH_DSM_A2_1, 0x04 }, + { WCD939X_DIGITAL_CDC_HPH_DSM_A3_0, 0xac }, + { WCD939X_DIGITAL_CDC_HPH_DSM_A3_1, 0x04 }, + { WCD939X_DIGITAL_CDC_HPH_DSM_A4_0, 0x1a }, + { WCD939X_DIGITAL_CDC_HPH_DSM_A4_1, 0x03 }, + { WCD939X_DIGITAL_CDC_HPH_DSM_A5_0, 0xbc }, + { WCD939X_DIGITAL_CDC_HPH_DSM_A5_1, 0x02 }, + { WCD939X_DIGITAL_CDC_HPH_DSM_A6_0, 0xc7 }, + { WCD939X_DIGITAL_CDC_HPH_DSM_A7_0, 0xf8 }, + { WCD939X_DIGITAL_CDC_HPH_DSM_C_0, 0x47 }, + { WCD939X_DIGITAL_CDC_HPH_DSM_C_1, 0x43 }, + { WCD939X_DIGITAL_CDC_HPH_DSM_C_2, 0xb1 }, + { WCD939X_DIGITAL_CDC_HPH_DSM_C_3, 0x17 }, + { WCD939X_DIGITAL_CDC_HPH_DSM_R1, 0x4d }, + { WCD939X_DIGITAL_CDC_HPH_DSM_R2, 0x29 }, + { WCD939X_DIGITAL_CDC_HPH_DSM_R3, 0x34 }, + { WCD939X_DIGITAL_CDC_HPH_DSM_R4, 0x59 }, + { WCD939X_DIGITAL_CDC_HPH_DSM_R5, 0x66 }, + { WCD939X_DIGITAL_CDC_HPH_DSM_R6, 0x87 }, + { WCD939X_DIGITAL_CDC_HPH_DSM_R7, 0x64 }, + { WCD939X_DIGITAL_CDC_EAR_DSM_A1_0, 0x00 }, + { WCD939X_DIGITAL_CDC_EAR_DSM_A1_1, 0x01 }, + { WCD939X_DIGITAL_CDC_EAR_DSM_A2_0, 0x96 }, + { WCD939X_DIGITAL_CDC_EAR_DSM_A2_1, 0x09 }, + { WCD939X_DIGITAL_CDC_EAR_DSM_A3_0, 0xab }, + { WCD939X_DIGITAL_CDC_EAR_DSM_A3_1, 0x05 }, + { WCD939X_DIGITAL_CDC_EAR_DSM_A4_0, 0x1c }, + { WCD939X_DIGITAL_CDC_EAR_DSM_A4_1, 0x02 }, + { WCD939X_DIGITAL_CDC_EAR_DSM_A5_0, 0x17 }, + { WCD939X_DIGITAL_CDC_EAR_DSM_A5_1, 0x02 }, + { WCD939X_DIGITAL_CDC_EAR_DSM_A6_0, 0xaa }, + { WCD939X_DIGITAL_CDC_EAR_DSM_A7_0, 0xe3 }, + { WCD939X_DIGITAL_CDC_EAR_DSM_C_0, 0x69 }, + { WCD939X_DIGITAL_CDC_EAR_DSM_C_1, 0x54 }, + { WCD939X_DIGITAL_CDC_EAR_DSM_C_2, 0x02 }, + { WCD939X_DIGITAL_CDC_EAR_DSM_C_3, 0x15 }, + { WCD939X_DIGITAL_CDC_EAR_DSM_R1, 0xa4 }, + { WCD939X_DIGITAL_CDC_EAR_DSM_R2, 0xb5 }, + { WCD939X_DIGITAL_CDC_EAR_DSM_R3, 0x86 }, + { WCD939X_DIGITAL_CDC_EAR_DSM_R4, 0x85 }, + { WCD939X_DIGITAL_CDC_EAR_DSM_R5, 0xaa }, + { WCD939X_DIGITAL_CDC_EAR_DSM_R6, 0xe2 }, + { WCD939X_DIGITAL_CDC_EAR_DSM_R7, 0x62 }, + { WCD939X_DIGITAL_CDC_HPH_GAIN_RX_0, 0x55 }, + { WCD939X_DIGITAL_CDC_HPH_GAIN_RX_1, 0xa9 }, + { WCD939X_DIGITAL_CDC_HPH_GAIN_DSD_0, 0x3d }, + { WCD939X_DIGITAL_CDC_HPH_GAIN_DSD_1, 0x2e }, + { WCD939X_DIGITAL_CDC_HPH_GAIN_DSD_2, 0x01 }, + { WCD939X_DIGITAL_CDC_EAR_GAIN_DSD_0, 0x00 }, + { WCD939X_DIGITAL_CDC_EAR_GAIN_DSD_1, 0xfc }, + { WCD939X_DIGITAL_CDC_EAR_GAIN_DSD_2, 0x01 }, + { WCD939X_DIGITAL_CDC_HPH_GAIN_CTL, 0x00 }, + { WCD939X_DIGITAL_CDC_EAR_GAIN_CTL, 0x00 }, + { WCD939X_DIGITAL_CDC_EAR_PATH_CTL, 0x00 }, + { WCD939X_DIGITAL_CDC_SWR_CLH, 0x00 }, + { WCD939X_DIGITAL_SWR_CLH_BYP, 0x00 }, + { WCD939X_DIGITAL_CDC_TX0_CTL, 0x68 }, + { WCD939X_DIGITAL_CDC_TX1_CTL, 0x68 }, + { WCD939X_DIGITAL_CDC_TX2_CTL, 0x68 }, + { WCD939X_DIGITAL_CDC_TX_RST, 0x00 }, + { WCD939X_DIGITAL_CDC_REQ_CTL, 0x01 }, + { WCD939X_DIGITAL_CDC_RST, 0x00 }, + { WCD939X_DIGITAL_CDC_AMIC_CTL, 0x0f }, + { WCD939X_DIGITAL_CDC_DMIC_CTL, 0x04 }, + { WCD939X_DIGITAL_CDC_DMIC1_CTL, 0x01 }, + { WCD939X_DIGITAL_CDC_DMIC2_CTL, 0x01 }, + { WCD939X_DIGITAL_CDC_DMIC3_CTL, 0x01 }, + { WCD939X_DIGITAL_CDC_DMIC4_CTL, 0x01 }, + { WCD939X_DIGITAL_EFUSE_PRG_CTL, 0x00 }, + { WCD939X_DIGITAL_EFUSE_CTL, 0x2b }, + { WCD939X_DIGITAL_CDC_DMIC_RATE_1_2, 0x11 }, + { WCD939X_DIGITAL_CDC_DMIC_RATE_3_4, 0x11 }, + { WCD939X_DIGITAL_PDM_WD_CTL0, 0x00 }, + { WCD939X_DIGITAL_PDM_WD_CTL1, 0x00 }, + { WCD939X_DIGITAL_PDM_WD_CTL2, 0x00 }, + { WCD939X_DIGITAL_INTR_MODE, 0x00 }, + { WCD939X_DIGITAL_INTR_MASK_0, 0xff }, + { WCD939X_DIGITAL_INTR_MASK_1, 0xe7 }, + { WCD939X_DIGITAL_INTR_MASK_2, 0x0e }, + { WCD939X_DIGITAL_INTR_CLEAR_0, 0x00 }, + { WCD939X_DIGITAL_INTR_CLEAR_1, 0x00 }, + { WCD939X_DIGITAL_INTR_CLEAR_2, 0x00 }, + { WCD939X_DIGITAL_INTR_LEVEL_0, 0x00 }, + { WCD939X_DIGITAL_INTR_LEVEL_1, 0x00 }, + { WCD939X_DIGITAL_INTR_LEVEL_2, 0x00 }, + { WCD939X_DIGITAL_INTR_SET_0, 0x00 }, + { WCD939X_DIGITAL_INTR_SET_1, 0x00 }, + { WCD939X_DIGITAL_INTR_SET_2, 0x00 }, + { WCD939X_DIGITAL_INTR_TEST_0, 0x00 }, + { WCD939X_DIGITAL_INTR_TEST_1, 0x00 }, + { WCD939X_DIGITAL_INTR_TEST_2, 0x00 }, + { WCD939X_DIGITAL_TX_MODE_DBG_EN, 0x00 }, + { WCD939X_DIGITAL_TX_MODE_DBG_0_1, 0x00 }, + { WCD939X_DIGITAL_TX_MODE_DBG_2_3, 0x00 }, + { WCD939X_DIGITAL_LB_IN_SEL_CTL, 0x00 }, + { WCD939X_DIGITAL_LOOP_BACK_MODE, 0x00 }, + { WCD939X_DIGITAL_SWR_DAC_TEST, 0x00 }, + { WCD939X_DIGITAL_SWR_HM_TEST_RX_0, 0x40 }, + { WCD939X_DIGITAL_SWR_HM_TEST_TX_0, 0x40 }, + { WCD939X_DIGITAL_SWR_HM_TEST_RX_1, 0x00 }, + { WCD939X_DIGITAL_SWR_HM_TEST_TX_1, 0x00 }, + { WCD939X_DIGITAL_SWR_HM_TEST_TX_2, 0x00 }, + { WCD939X_DIGITAL_PAD_CTL_SWR_0, 0x8f }, + { WCD939X_DIGITAL_PAD_CTL_SWR_1, 0x06 }, + { WCD939X_DIGITAL_I2C_CTL, 0x00 }, + { WCD939X_DIGITAL_CDC_TX_TANGGU_SW_MODE, 0x00 }, + { WCD939X_DIGITAL_EFUSE_TEST_CTL_0, 0x00 }, + { WCD939X_DIGITAL_EFUSE_TEST_CTL_1, 0x00 }, + { WCD939X_DIGITAL_PAD_CTL_PDM_RX0, 0xf1 }, + { WCD939X_DIGITAL_PAD_CTL_PDM_RX1, 0xf1 }, + { WCD939X_DIGITAL_PAD_CTL_PDM_TX0, 0xf1 }, + { WCD939X_DIGITAL_PAD_CTL_PDM_TX1, 0xf1 }, + { WCD939X_DIGITAL_PAD_CTL_PDM_TX2, 0xf1 }, + { WCD939X_DIGITAL_PAD_INP_DIS_0, 0x00 }, + { WCD939X_DIGITAL_PAD_INP_DIS_1, 0x00 }, + { WCD939X_DIGITAL_DRIVE_STRENGTH_0, 0x00 }, + { WCD939X_DIGITAL_DRIVE_STRENGTH_1, 0x00 }, + { WCD939X_DIGITAL_DRIVE_STRENGTH_2, 0x00 }, + { WCD939X_DIGITAL_RX_DATA_EDGE_CTL, 0x1f }, + { WCD939X_DIGITAL_TX_DATA_EDGE_CTL, 0x80 }, + { WCD939X_DIGITAL_GPIO_MODE, 0x00 }, + { WCD939X_DIGITAL_PIN_CTL_OE, 0x00 }, + { WCD939X_DIGITAL_PIN_CTL_DATA_0, 0x00 }, + { WCD939X_DIGITAL_PIN_CTL_DATA_1, 0x00 }, + { WCD939X_DIGITAL_DIG_DEBUG_CTL, 0x00 }, + { WCD939X_DIGITAL_DIG_DEBUG_EN, 0x00 }, + { WCD939X_DIGITAL_ANA_CSR_DBG_ADD, 0x00 }, + { WCD939X_DIGITAL_ANA_CSR_DBG_CTL, 0x48 }, + { WCD939X_DIGITAL_SSP_DBG, 0x00 }, + { WCD939X_DIGITAL_SPARE_0, 0x00 }, + { WCD939X_DIGITAL_SPARE_1, 0x00 }, + { WCD939X_DIGITAL_SPARE_2, 0x00 }, + { WCD939X_DIGITAL_TX_REQ_FB_CTL_0, 0x88 }, + { WCD939X_DIGITAL_TX_REQ_FB_CTL_1, 0x88 }, + { WCD939X_DIGITAL_TX_REQ_FB_CTL_2, 0x88 }, + { WCD939X_DIGITAL_TX_REQ_FB_CTL_3, 0x88 }, + { WCD939X_DIGITAL_TX_REQ_FB_CTL_4, 0x88 }, + { WCD939X_DIGITAL_DEM_BYPASS_DATA0, 0x55 }, + { WCD939X_DIGITAL_DEM_BYPASS_DATA1, 0x55 }, + { WCD939X_DIGITAL_DEM_BYPASS_DATA2, 0x55 }, + { WCD939X_DIGITAL_DEM_BYPASS_DATA3, 0x01 }, + { WCD939X_DIGITAL_DEM_SECOND_ORDER, 0x03 }, + { WCD939X_DIGITAL_DSM_CTRL, 0x00 }, + { WCD939X_DIGITAL_DSM_0_STATIC_DATA_0, 0x00 }, + { WCD939X_DIGITAL_DSM_0_STATIC_DATA_1, 0x00 }, + { WCD939X_DIGITAL_DSM_0_STATIC_DATA_2, 0x00 }, + { WCD939X_DIGITAL_DSM_0_STATIC_DATA_3, 0x00 }, + { WCD939X_DIGITAL_DSM_1_STATIC_DATA_0, 0x00 }, + { WCD939X_DIGITAL_DSM_1_STATIC_DATA_1, 0x00 }, + { WCD939X_DIGITAL_DSM_1_STATIC_DATA_2, 0x00 }, + { WCD939X_DIGITAL_DSM_1_STATIC_DATA_3, 0x00 }, + { WCD939X_RX_TOP_PAGE, 0x00 }, + { WCD939X_RX_TOP_TOP_CFG0, 0x00 }, + { WCD939X_RX_TOP_HPHL_COMP_WR_LSB, 0x00 }, + { WCD939X_RX_TOP_HPHL_COMP_WR_MSB, 0x00 }, + { WCD939X_RX_TOP_HPHL_COMP_LUT, 0x00 }, + { WCD939X_RX_TOP_HPHR_COMP_WR_LSB, 0x00 }, + { WCD939X_RX_TOP_HPHR_COMP_WR_MSB, 0x00 }, + { WCD939X_RX_TOP_HPHR_COMP_LUT, 0x00 }, + { WCD939X_RX_TOP_DSD0_DEBUG_CFG1, 0x05 }, + { WCD939X_RX_TOP_DSD0_DEBUG_CFG2, 0x08 }, + { WCD939X_RX_TOP_DSD0_DEBUG_CFG3, 0x00 }, + { WCD939X_RX_TOP_DSD0_DEBUG_CFG4, 0x00 }, + { WCD939X_RX_TOP_DSD1_DEBUG_CFG1, 0x03 }, + { WCD939X_RX_TOP_DSD1_DEBUG_CFG2, 0x08 }, + { WCD939X_RX_TOP_DSD1_DEBUG_CFG3, 0x00 }, + { WCD939X_RX_TOP_DSD1_DEBUG_CFG4, 0x00 }, + { WCD939X_RX_TOP_HPHL_PATH_CFG0, 0x00 }, + { WCD939X_RX_TOP_HPHL_PATH_CFG1, 0x00 }, + { WCD939X_RX_TOP_HPHR_PATH_CFG0, 0x00 }, + { WCD939X_RX_TOP_HPHR_PATH_CFG1, 0x00 }, + { WCD939X_RX_TOP_PATH_CFG2, 0x00 }, + { WCD939X_RX_TOP_HPHL_PATH_SEC0, 0x00 }, + { WCD939X_RX_TOP_HPHL_PATH_SEC1, 0x00 }, + { WCD939X_RX_TOP_HPHL_PATH_SEC2, 0x00 }, + { WCD939X_RX_TOP_HPHL_PATH_SEC3, 0x00 }, + { WCD939X_RX_TOP_HPHR_PATH_SEC0, 0x00 }, + { WCD939X_RX_TOP_HPHR_PATH_SEC1, 0x00 }, + { WCD939X_RX_TOP_HPHR_PATH_SEC2, 0x00 }, + { WCD939X_RX_TOP_HPHR_PATH_SEC3, 0x00 }, + { WCD939X_RX_TOP_PATH_SEC4, 0x00 }, + { WCD939X_RX_TOP_PATH_SEC5, 0x00 }, + { WCD939X_COMPANDER_HPHL_CTL0, 0x60 }, + { WCD939X_COMPANDER_HPHL_CTL1, 0xdb }, + { WCD939X_COMPANDER_HPHL_CTL2, 0xff }, + { WCD939X_COMPANDER_HPHL_CTL3, 0x35 }, + { WCD939X_COMPANDER_HPHL_CTL4, 0xff }, + { WCD939X_COMPANDER_HPHL_CTL5, 0x00 }, + { WCD939X_COMPANDER_HPHL_CTL7, 0x08 }, + { WCD939X_COMPANDER_HPHL_CTL8, 0x00 }, + { WCD939X_COMPANDER_HPHL_CTL9, 0x00 }, + { WCD939X_COMPANDER_HPHL_CTL10, 0x06 }, + { WCD939X_COMPANDER_HPHL_CTL11, 0x12 }, + { WCD939X_COMPANDER_HPHL_CTL12, 0x1e }, + { WCD939X_COMPANDER_HPHL_CTL13, 0x2a }, + { WCD939X_COMPANDER_HPHL_CTL14, 0x36 }, + { WCD939X_COMPANDER_HPHL_CTL15, 0x3c }, + { WCD939X_COMPANDER_HPHL_CTL16, 0xc4 }, + { WCD939X_COMPANDER_HPHL_CTL17, 0x00 }, + { WCD939X_COMPANDER_HPHL_CTL18, 0x0c }, + { WCD939X_COMPANDER_HPHL_CTL19, 0x16 }, + { WCD939X_R_CTL0, 0x60 }, + { WCD939X_R_CTL1, 0xdb }, + { WCD939X_R_CTL2, 0xff }, + { WCD939X_R_CTL3, 0x35 }, + { WCD939X_R_CTL4, 0xff }, + { WCD939X_R_CTL5, 0x00 }, + { WCD939X_R_CTL7, 0x08 }, + { WCD939X_R_CTL8, 0x00 }, + { WCD939X_R_CTL9, 0x00 }, + { WCD939X_R_CTL10, 0x06 }, + { WCD939X_R_CTL11, 0x12 }, + { WCD939X_R_CTL12, 0x1e }, + { WCD939X_R_CTL13, 0x2a }, + { WCD939X_R_CTL14, 0x36 }, + { WCD939X_R_CTL15, 0x3c }, + { WCD939X_R_CTL16, 0xc4 }, + { WCD939X_R_CTL17, 0x00 }, + { WCD939X_R_CTL18, 0x0c }, + { WCD939X_R_CTL19, 0x16 }, + { WCD939X_E_PATH_CTL, 0x00 }, + { WCD939X_E_CFG0, 0x07 }, + { WCD939X_E_CFG1, 0x3c }, + { WCD939X_E_CFG2, 0x00 }, + { WCD939X_E_CFG3, 0x00 }, + { WCD939X_DSD_HPHL_PATH_CTL, 0x00 }, + { WCD939X_DSD_HPHL_CFG0, 0x00 }, + { WCD939X_DSD_HPHL_CFG1, 0x00 }, + { WCD939X_DSD_HPHL_CFG2, 0x22 }, + { WCD939X_DSD_HPHL_CFG3, 0x00 }, + { WCD939X_DSD_HPHL_CFG4, 0x1a }, + { WCD939X_DSD_HPHL_CFG5, 0x00 }, + { WCD939X_DSD_HPHR_PATH_CTL, 0x00 }, + { WCD939X_DSD_HPHR_CFG0, 0x00 }, + { WCD939X_DSD_HPHR_CFG1, 0x00 }, + { WCD939X_DSD_HPHR_CFG2, 0x22 }, + { WCD939X_DSD_HPHR_CFG3, 0x00 }, + { WCD939X_DSD_HPHR_CFG4, 0x1a }, + { WCD939X_DSD_HPHR_CFG5, 0x00 }, +}; + +static bool wcd939x_rdwr_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WCD939X_ANA_PAGE: + case WCD939X_ANA_BIAS: + case WCD939X_ANA_RX_SUPPLIES: + case WCD939X_ANA_HPH: + case WCD939X_ANA_EAR: + case WCD939X_ANA_EAR_COMPANDER_CTL: + case WCD939X_ANA_TX_CH1: + case WCD939X_ANA_TX_CH2: + case WCD939X_ANA_TX_CH3: + case WCD939X_ANA_TX_CH4: + case WCD939X_ANA_MICB1_MICB2_DSP_EN_LOGIC: + case WCD939X_ANA_MICB3_DSP_EN_LOGIC: + case WCD939X_ANA_MBHC_MECH: + case WCD939X_ANA_MBHC_ELECT: + case WCD939X_ANA_MBHC_ZDET: + case WCD939X_ANA_MBHC_BTN0: + case WCD939X_ANA_MBHC_BTN1: + case WCD939X_ANA_MBHC_BTN2: + case WCD939X_ANA_MBHC_BTN3: + case WCD939X_ANA_MBHC_BTN4: + case WCD939X_ANA_MBHC_BTN5: + case WCD939X_ANA_MBHC_BTN6: + case WCD939X_ANA_MBHC_BTN7: + case WCD939X_ANA_MICB1: + case WCD939X_ANA_MICB2: + case WCD939X_ANA_MICB2_RAMP: + case WCD939X_ANA_MICB3: + case WCD939X_ANA_MICB4: + case WCD939X_BIAS_CTL: + case WCD939X_BIAS_VBG_FINE_ADJ: + case WCD939X_LDOL_VDDCX_ADJUST: + case WCD939X_LDOL_DISABLE_LDOL: + case WCD939X_MBHC_CTL_CLK: + case WCD939X_MBHC_CTL_ANA: + case WCD939X_MBHC_ZDET_VNEG_CTL: + case WCD939X_MBHC_ZDET_BIAS_CTL: + case WCD939X_MBHC_CTL_BCS: + case WCD939X_MBHC_TEST_CTL: + case WCD939X_LDOH_MODE: + case WCD939X_LDOH_BIAS: + case WCD939X_LDOH_STB_LOADS: + case WCD939X_LDOH_SLOWRAMP: + case WCD939X_MICB1_TEST_CTL_1: + case WCD939X_MICB1_TEST_CTL_2: + case WCD939X_MICB1_TEST_CTL_3: + case WCD939X_MICB2_TEST_CTL_1: + case WCD939X_MICB2_TEST_CTL_2: + case WCD939X_MICB2_TEST_CTL_3: + case WCD939X_MICB3_TEST_CTL_1: + case WCD939X_MICB3_TEST_CTL_2: + case WCD939X_MICB3_TEST_CTL_3: + case WCD939X_MICB4_TEST_CTL_1: + case WCD939X_MICB4_TEST_CTL_2: + case WCD939X_MICB4_TEST_CTL_3: + case WCD939X_TX_COM_ADC_VCM: + case WCD939X_TX_COM_BIAS_ATEST: + case WCD939X_TX_COM_SPARE1: + case WCD939X_TX_COM_SPARE2: + case WCD939X_TX_COM_TXFE_DIV_CTL: + case WCD939X_TX_COM_TXFE_DIV_START: + case WCD939X_TX_COM_SPARE3: + case WCD939X_TX_COM_SPARE4: + case WCD939X_TX_1_2_TEST_EN: + case WCD939X_TX_1_2_ADC_IB: + case WCD939X_TX_1_2_ATEST_REFCTL: + case WCD939X_TX_1_2_TEST_CTL: + case WCD939X_TX_1_2_TEST_BLK_EN1: + case WCD939X_TX_1_2_TXFE1_CLKDIV: + case WCD939X_TX_3_4_TEST_EN: + case WCD939X_TX_3_4_ADC_IB: + case WCD939X_TX_3_4_ATEST_REFCTL: + case WCD939X_TX_3_4_TEST_CTL: + case WCD939X_TX_3_4_TEST_BLK_EN3: + case WCD939X_TX_3_4_TXFE3_CLKDIV: + case WCD939X_TX_3_4_TEST_BLK_EN2: + case WCD939X_TX_3_4_TXFE2_CLKDIV: + case WCD939X_TX_3_4_SPARE1: + case WCD939X_TX_3_4_TEST_BLK_EN4: + case WCD939X_TX_3_4_TXFE4_CLKDIV: + case WCD939X_TX_3_4_SPARE2: + case WCD939X_CLASSH_MODE_1: + case WCD939X_CLASSH_MODE_2: + case WCD939X_CLASSH_MODE_3: + case WCD939X_CLASSH_CTRL_VCL_1: + case WCD939X_CLASSH_CTRL_VCL_2: + case WCD939X_CLASSH_CTRL_CCL_1: + case WCD939X_CLASSH_CTRL_CCL_2: + case WCD939X_CLASSH_CTRL_CCL_3: + case WCD939X_CLASSH_CTRL_CCL_4: + case WCD939X_CLASSH_CTRL_CCL_5: + case WCD939X_CLASSH_BUCK_TMUX_A_D: + case WCD939X_CLASSH_BUCK_SW_DRV_CNTL: + case WCD939X_CLASSH_SPARE: + case WCD939X_FLYBACK_EN: + case WCD939X_FLYBACK_VNEG_CTRL_1: + case WCD939X_FLYBACK_VNEG_CTRL_2: + case WCD939X_FLYBACK_VNEG_CTRL_3: + case WCD939X_FLYBACK_VNEG_CTRL_4: + case WCD939X_FLYBACK_VNEG_CTRL_5: + case WCD939X_FLYBACK_VNEG_CTRL_6: + case WCD939X_FLYBACK_VNEG_CTRL_7: + case WCD939X_FLYBACK_VNEG_CTRL_8: + case WCD939X_FLYBACK_VNEG_CTRL_9: + case WCD939X_FLYBACK_VNEGDAC_CTRL_1: + case WCD939X_FLYBACK_VNEGDAC_CTRL_2: + case WCD939X_FLYBACK_VNEGDAC_CTRL_3: + case WCD939X_FLYBACK_CTRL_1: + case WCD939X_FLYBACK_TEST_CTL: + case WCD939X_RX_AUX_SW_CTL: + case WCD939X_RX_PA_AUX_IN_CONN: + case WCD939X_RX_TIMER_DIV: + case WCD939X_RX_OCP_CTL: + case WCD939X_RX_OCP_COUNT: + case WCD939X_RX_BIAS_EAR_DAC: + case WCD939X_RX_BIAS_EAR_AMP: + case WCD939X_RX_BIAS_HPH_LDO: + case WCD939X_RX_BIAS_HPH_PA: + case WCD939X_RX_BIAS_HPH_RDACBUFF_CNP2: + case WCD939X_RX_BIAS_HPH_RDAC_LDO: + case WCD939X_RX_BIAS_HPH_CNP1: + case WCD939X_RX_BIAS_HPH_LOWPOWER: + case WCD939X_RX_BIAS_AUX_DAC: + case WCD939X_RX_BIAS_AUX_AMP: + case WCD939X_RX_BIAS_VNEGDAC_BLEEDER: + case WCD939X_RX_BIAS_MISC: + case WCD939X_RX_BIAS_BUCK_RST: + case WCD939X_RX_BIAS_BUCK_VREF_ERRAMP: + case WCD939X_RX_BIAS_FLYB_ERRAMP: + case WCD939X_RX_BIAS_FLYB_BUFF: + case WCD939X_RX_BIAS_FLYB_MID_RST: + case WCD939X_HPH_CNP_EN: + case WCD939X_HPH_CNP_WG_CTL: + case WCD939X_HPH_CNP_WG_TIME: + case WCD939X_HPH_OCP_CTL: + case WCD939X_HPH_AUTO_CHOP: + case WCD939X_HPH_CHOP_CTL: + case WCD939X_HPH_PA_CTL1: + case WCD939X_HPH_PA_CTL2: + case WCD939X_HPH_L_EN: + case WCD939X_HPH_L_TEST: + case WCD939X_HPH_L_ATEST: + case WCD939X_HPH_R_EN: + case WCD939X_HPH_R_TEST: + case WCD939X_HPH_R_ATEST: + case WCD939X_HPH_RDAC_CLK_CTL1: + case WCD939X_HPH_RDAC_CLK_CTL2: + case WCD939X_HPH_RDAC_LDO_CTL: + case WCD939X_HPH_RDAC_CHOP_CLK_LP_CTL: + case WCD939X_HPH_REFBUFF_UHQA_CTL: + case WCD939X_HPH_REFBUFF_LP_CTL: + case WCD939X_HPH_L_DAC_CTL: + case WCD939X_HPH_R_DAC_CTL: + case WCD939X_HPH_SURGE_COMP_SEL: + case WCD939X_HPH_SURGE_EN: + case WCD939X_HPH_SURGE_MISC1: + case WCD939X_EAR_EN: + case WCD939X_EAR_PA_CON: + case WCD939X_EAR_SP_CON: + case WCD939X_EAR_DAC_CON: + case WCD939X_EAR_CNP_FSM_CON: + case WCD939X_EAR_TEST_CTL: + case WCD939X_FLYBACK_NEW_CTRL_2: + case WCD939X_FLYBACK_NEW_CTRL_3: + case WCD939X_FLYBACK_NEW_CTRL_4: + case WCD939X_ANA_NEW_PAGE: + case WCD939X_HPH_NEW_ANA_HPH2: + case WCD939X_HPH_NEW_ANA_HPH3: + case WCD939X_SLEEP_CTL: + case WCD939X_SLEEP_WATCHDOG_CTL: + case WCD939X_MBHC_NEW_ELECT_REM_CLAMP_CTL: + case WCD939X_MBHC_NEW_CTL_1: + case WCD939X_MBHC_NEW_CTL_2: + case WCD939X_MBHC_NEW_PLUG_DETECT_CTL: + case WCD939X_MBHC_NEW_ZDET_ANA_CTL: + case WCD939X_MBHC_NEW_ZDET_RAMP_CTL: + case WCD939X_TX_NEW_CH12_MUX: + case WCD939X_TX_NEW_CH34_MUX: + case WCD939X_DIE_CRACK_DET_EN: + case WCD939X_HPH_NEW_INT_RDAC_GAIN_CTL: + case WCD939X_HPH_NEW_INT_PA_GAIN_CTL_L: + case WCD939X_HPH_NEW_INT_RDAC_VREF_CTL: + case WCD939X_HPH_NEW_INT_RDAC_OVERRIDE_CTL: + case WCD939X_HPH_NEW_INT_PA_GAIN_CTL_R: + case WCD939X_HPH_NEW_INT_PA_MISC1: + case WCD939X_HPH_NEW_INT_PA_MISC2: + case WCD939X_HPH_NEW_INT_PA_RDAC_MISC: + case WCD939X_HPH_NEW_INT_TIMER1: + case WCD939X_HPH_NEW_INT_TIMER2: + case WCD939X_HPH_NEW_INT_TIMER3: + case WCD939X_HPH_NEW_INT_TIMER4: + case WCD939X_HPH_NEW_INT_PA_RDAC_MISC2: + case WCD939X_HPH_NEW_INT_PA_RDAC_MISC3: + case WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_L: + case WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_R: + case WCD939X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI: + case WCD939X_RX_NEW_INT_HPH_RDAC_BIAS_ULP: + case WCD939X_RX_NEW_INT_HPH_RDAC_LDO_LP: + case WCD939X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL: + case WCD939X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL: + case WCD939X_MBHC_NEW_INT_MECH_DET_CURRENT: + case WCD939X_MBHC_NEW_INT_ZDET_CLK_AND_MOISTURE_CTL_NEW: + case WCD939X_EAR_INT_NEW_CHOPPER_CON: + case WCD939X_EAR_INT_NEW_CNP_VCM_CON1: + case WCD939X_EAR_INT_NEW_CNP_VCM_CON2: + case WCD939X_EAR_INT_NEW_DYNAMIC_BIAS: + case WCD939X_SLEEP_INT_WATCHDOG_CTL_1: + case WCD939X_SLEEP_INT_WATCHDOG_CTL_2: + case WCD939X_DIE_CRACK_INT_DET_INT1: + case WCD939X_DIE_CRACK_INT_DET_INT2: + case WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_L2: + case WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_L1: + case WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_L0: + case WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_ULP1P2M: + case WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_ULP0P6M: + case WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG1_L2L1: + case WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG1_L0: + case WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG1_ULP: + case WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2MAIN_L2L1: + case WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2MAIN_L0: + case WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2MAIN_ULP: + case WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2CASC_L2L1L0: + case WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2CASC_ULP: + case WCD939X_TX_COM_NEW_INT_ADC_SCBIAS_L2L1: + case WCD939X_TX_COM_NEW_INT_ADC_SCBIAS_L0ULP: + case WCD939X_TX_COM_NEW_INT_ADC_INT_L2: + case WCD939X_TX_COM_NEW_INT_ADC_INT_L1: + case WCD939X_TX_COM_NEW_INT_ADC_INT_L0: + case WCD939X_TX_COM_NEW_INT_ADC_INT_ULP: + case WCD939X_DIGITAL_PAGE: + case WCD939X_DIGITAL_SWR_TX_CLK_RATE: + case WCD939X_DIGITAL_CDC_RST_CTL: + case WCD939X_DIGITAL_TOP_CLK_CFG: + case WCD939X_DIGITAL_CDC_ANA_CLK_CTL: + case WCD939X_DIGITAL_CDC_DIG_CLK_CTL: + case WCD939X_DIGITAL_SWR_RST_EN: + case WCD939X_DIGITAL_CDC_PATH_MODE: + case WCD939X_DIGITAL_CDC_RX_RST: + case WCD939X_DIGITAL_CDC_RX0_CTL: + case WCD939X_DIGITAL_CDC_RX1_CTL: + case WCD939X_DIGITAL_CDC_RX2_CTL: + case WCD939X_DIGITAL_CDC_TX_ANA_MODE_0_1: + case WCD939X_DIGITAL_CDC_TX_ANA_MODE_2_3: + case WCD939X_DIGITAL_CDC_COMP_CTL_0: + case WCD939X_DIGITAL_CDC_ANA_TX_CLK_CTL: + case WCD939X_DIGITAL_CDC_HPH_DSM_A1_0: + case WCD939X_DIGITAL_CDC_HPH_DSM_A1_1: + case WCD939X_DIGITAL_CDC_HPH_DSM_A2_0: + case WCD939X_DIGITAL_CDC_HPH_DSM_A2_1: + case WCD939X_DIGITAL_CDC_HPH_DSM_A3_0: + case WCD939X_DIGITAL_CDC_HPH_DSM_A3_1: + case WCD939X_DIGITAL_CDC_HPH_DSM_A4_0: + case WCD939X_DIGITAL_CDC_HPH_DSM_A4_1: + case WCD939X_DIGITAL_CDC_HPH_DSM_A5_0: + case WCD939X_DIGITAL_CDC_HPH_DSM_A5_1: + case WCD939X_DIGITAL_CDC_HPH_DSM_A6_0: + case WCD939X_DIGITAL_CDC_HPH_DSM_A7_0: + case WCD939X_DIGITAL_CDC_HPH_DSM_C_0: + case WCD939X_DIGITAL_CDC_HPH_DSM_C_1: + case WCD939X_DIGITAL_CDC_HPH_DSM_C_2: + case WCD939X_DIGITAL_CDC_HPH_DSM_C_3: + case WCD939X_DIGITAL_CDC_HPH_DSM_R1: + case WCD939X_DIGITAL_CDC_HPH_DSM_R2: + case WCD939X_DIGITAL_CDC_HPH_DSM_R3: + case WCD939X_DIGITAL_CDC_HPH_DSM_R4: + case WCD939X_DIGITAL_CDC_HPH_DSM_R5: + case WCD939X_DIGITAL_CDC_HPH_DSM_R6: + case WCD939X_DIGITAL_CDC_HPH_DSM_R7: + case WCD939X_DIGITAL_CDC_EAR_DSM_A1_0: + case WCD939X_DIGITAL_CDC_EAR_DSM_A1_1: + case WCD939X_DIGITAL_CDC_EAR_DSM_A2_0: + case WCD939X_DIGITAL_CDC_EAR_DSM_A2_1: + case WCD939X_DIGITAL_CDC_EAR_DSM_A3_0: + case WCD939X_DIGITAL_CDC_EAR_DSM_A3_1: + case WCD939X_DIGITAL_CDC_EAR_DSM_A4_0: + case WCD939X_DIGITAL_CDC_EAR_DSM_A4_1: + case WCD939X_DIGITAL_CDC_EAR_DSM_A5_0: + case WCD939X_DIGITAL_CDC_EAR_DSM_A5_1: + case WCD939X_DIGITAL_CDC_EAR_DSM_A6_0: + case WCD939X_DIGITAL_CDC_EAR_DSM_A7_0: + case WCD939X_DIGITAL_CDC_EAR_DSM_C_0: + case WCD939X_DIGITAL_CDC_EAR_DSM_C_1: + case WCD939X_DIGITAL_CDC_EAR_DSM_C_2: + case WCD939X_DIGITAL_CDC_EAR_DSM_C_3: + case WCD939X_DIGITAL_CDC_EAR_DSM_R1: + case WCD939X_DIGITAL_CDC_EAR_DSM_R2: + case WCD939X_DIGITAL_CDC_EAR_DSM_R3: + case WCD939X_DIGITAL_CDC_EAR_DSM_R4: + case WCD939X_DIGITAL_CDC_EAR_DSM_R5: + case WCD939X_DIGITAL_CDC_EAR_DSM_R6: + case WCD939X_DIGITAL_CDC_EAR_DSM_R7: + case WCD939X_DIGITAL_CDC_HPH_GAIN_RX_0: + case WCD939X_DIGITAL_CDC_HPH_GAIN_RX_1: + case WCD939X_DIGITAL_CDC_HPH_GAIN_DSD_0: + case WCD939X_DIGITAL_CDC_HPH_GAIN_DSD_1: + case WCD939X_DIGITAL_CDC_HPH_GAIN_DSD_2: + case WCD939X_DIGITAL_CDC_EAR_GAIN_DSD_0: + case WCD939X_DIGITAL_CDC_EAR_GAIN_DSD_1: + case WCD939X_DIGITAL_CDC_EAR_GAIN_DSD_2: + case WCD939X_DIGITAL_CDC_HPH_GAIN_CTL: + case WCD939X_DIGITAL_CDC_EAR_GAIN_CTL: + case WCD939X_DIGITAL_CDC_EAR_PATH_CTL: + case WCD939X_DIGITAL_CDC_SWR_CLH: + case WCD939X_DIGITAL_SWR_CLH_BYP: + case WCD939X_DIGITAL_CDC_TX0_CTL: + case WCD939X_DIGITAL_CDC_TX1_CTL: + case WCD939X_DIGITAL_CDC_TX2_CTL: + case WCD939X_DIGITAL_CDC_TX_RST: + case WCD939X_DIGITAL_CDC_REQ_CTL: + case WCD939X_DIGITAL_CDC_RST: + case WCD939X_DIGITAL_CDC_AMIC_CTL: + case WCD939X_DIGITAL_CDC_DMIC_CTL: + case WCD939X_DIGITAL_CDC_DMIC1_CTL: + case WCD939X_DIGITAL_CDC_DMIC2_CTL: + case WCD939X_DIGITAL_CDC_DMIC3_CTL: + case WCD939X_DIGITAL_CDC_DMIC4_CTL: + case WCD939X_DIGITAL_EFUSE_PRG_CTL: + case WCD939X_DIGITAL_EFUSE_CTL: + case WCD939X_DIGITAL_CDC_DMIC_RATE_1_2: + case WCD939X_DIGITAL_CDC_DMIC_RATE_3_4: + case WCD939X_DIGITAL_PDM_WD_CTL0: + case WCD939X_DIGITAL_PDM_WD_CTL1: + case WCD939X_DIGITAL_PDM_WD_CTL2: + case WCD939X_DIGITAL_INTR_MODE: + case WCD939X_DIGITAL_INTR_MASK_0: + case WCD939X_DIGITAL_INTR_MASK_1: + case WCD939X_DIGITAL_INTR_MASK_2: + case WCD939X_DIGITAL_INTR_CLEAR_0: + case WCD939X_DIGITAL_INTR_CLEAR_1: + case WCD939X_DIGITAL_INTR_CLEAR_2: + case WCD939X_DIGITAL_INTR_LEVEL_0: + case WCD939X_DIGITAL_INTR_LEVEL_1: + case WCD939X_DIGITAL_INTR_LEVEL_2: + case WCD939X_DIGITAL_INTR_SET_0: + case WCD939X_DIGITAL_INTR_SET_1: + case WCD939X_DIGITAL_INTR_SET_2: + case WCD939X_DIGITAL_INTR_TEST_0: + case WCD939X_DIGITAL_INTR_TEST_1: + case WCD939X_DIGITAL_INTR_TEST_2: + case WCD939X_DIGITAL_TX_MODE_DBG_EN: + case WCD939X_DIGITAL_TX_MODE_DBG_0_1: + case WCD939X_DIGITAL_TX_MODE_DBG_2_3: + case WCD939X_DIGITAL_LB_IN_SEL_CTL: + case WCD939X_DIGITAL_LOOP_BACK_MODE: + case WCD939X_DIGITAL_SWR_DAC_TEST: + case WCD939X_DIGITAL_SWR_HM_TEST_RX_0: + case WCD939X_DIGITAL_SWR_HM_TEST_TX_0: + case WCD939X_DIGITAL_SWR_HM_TEST_RX_1: + case WCD939X_DIGITAL_SWR_HM_TEST_TX_1: + case WCD939X_DIGITAL_SWR_HM_TEST_TX_2: + case WCD939X_DIGITAL_PAD_CTL_SWR_0: + case WCD939X_DIGITAL_PAD_CTL_SWR_1: + case WCD939X_DIGITAL_I2C_CTL: + case WCD939X_DIGITAL_CDC_TX_TANGGU_SW_MODE: + case WCD939X_DIGITAL_EFUSE_TEST_CTL_0: + case WCD939X_DIGITAL_EFUSE_TEST_CTL_1: + case WCD939X_DIGITAL_PAD_CTL_PDM_RX0: + case WCD939X_DIGITAL_PAD_CTL_PDM_RX1: + case WCD939X_DIGITAL_PAD_CTL_PDM_TX0: + case WCD939X_DIGITAL_PAD_CTL_PDM_TX1: + case WCD939X_DIGITAL_PAD_CTL_PDM_TX2: + case WCD939X_DIGITAL_PAD_INP_DIS_0: + case WCD939X_DIGITAL_PAD_INP_DIS_1: + case WCD939X_DIGITAL_DRIVE_STRENGTH_0: + case WCD939X_DIGITAL_DRIVE_STRENGTH_1: + case WCD939X_DIGITAL_DRIVE_STRENGTH_2: + case WCD939X_DIGITAL_RX_DATA_EDGE_CTL: + case WCD939X_DIGITAL_TX_DATA_EDGE_CTL: + case WCD939X_DIGITAL_GPIO_MODE: + case WCD939X_DIGITAL_PIN_CTL_OE: + case WCD939X_DIGITAL_PIN_CTL_DATA_0: + case WCD939X_DIGITAL_PIN_CTL_DATA_1: + case WCD939X_DIGITAL_DIG_DEBUG_CTL: + case WCD939X_DIGITAL_DIG_DEBUG_EN: + case WCD939X_DIGITAL_ANA_CSR_DBG_ADD: + case WCD939X_DIGITAL_ANA_CSR_DBG_CTL: + case WCD939X_DIGITAL_SSP_DBG: + case WCD939X_DIGITAL_SPARE_0: + case WCD939X_DIGITAL_SPARE_1: + case WCD939X_DIGITAL_SPARE_2: + case WCD939X_DIGITAL_TX_REQ_FB_CTL_0: + case WCD939X_DIGITAL_TX_REQ_FB_CTL_1: + case WCD939X_DIGITAL_TX_REQ_FB_CTL_2: + case WCD939X_DIGITAL_TX_REQ_FB_CTL_3: + case WCD939X_DIGITAL_TX_REQ_FB_CTL_4: + case WCD939X_DIGITAL_DEM_BYPASS_DATA0: + case WCD939X_DIGITAL_DEM_BYPASS_DATA1: + case WCD939X_DIGITAL_DEM_BYPASS_DATA2: + case WCD939X_DIGITAL_DEM_BYPASS_DATA3: + case WCD939X_DIGITAL_DEM_SECOND_ORDER: + case WCD939X_DIGITAL_DSM_CTRL: + case WCD939X_DIGITAL_DSM_0_STATIC_DATA_0: + case WCD939X_DIGITAL_DSM_0_STATIC_DATA_1: + case WCD939X_DIGITAL_DSM_0_STATIC_DATA_2: + case WCD939X_DIGITAL_DSM_0_STATIC_DATA_3: + case WCD939X_DIGITAL_DSM_1_STATIC_DATA_0: + case WCD939X_DIGITAL_DSM_1_STATIC_DATA_1: + case WCD939X_DIGITAL_DSM_1_STATIC_DATA_2: + case WCD939X_DIGITAL_DSM_1_STATIC_DATA_3: + case WCD939X_RX_TOP_PAGE: + case WCD939X_RX_TOP_TOP_CFG0: + case WCD939X_RX_TOP_HPHL_COMP_WR_LSB: + case WCD939X_RX_TOP_HPHL_COMP_WR_MSB: + case WCD939X_RX_TOP_HPHL_COMP_LUT: + case WCD939X_RX_TOP_HPHR_COMP_WR_LSB: + case WCD939X_RX_TOP_HPHR_COMP_WR_MSB: + case WCD939X_RX_TOP_HPHR_COMP_LUT: + case WCD939X_RX_TOP_DSD0_DEBUG_CFG1: + case WCD939X_RX_TOP_DSD0_DEBUG_CFG2: + case WCD939X_RX_TOP_DSD0_DEBUG_CFG3: + case WCD939X_RX_TOP_DSD0_DEBUG_CFG4: + case WCD939X_RX_TOP_DSD1_DEBUG_CFG1: + case WCD939X_RX_TOP_DSD1_DEBUG_CFG2: + case WCD939X_RX_TOP_DSD1_DEBUG_CFG3: + case WCD939X_RX_TOP_DSD1_DEBUG_CFG4: + case WCD939X_RX_TOP_HPHL_PATH_CFG0: + case WCD939X_RX_TOP_HPHL_PATH_CFG1: + case WCD939X_RX_TOP_HPHR_PATH_CFG0: + case WCD939X_RX_TOP_HPHR_PATH_CFG1: + case WCD939X_RX_TOP_PATH_CFG2: + case WCD939X_RX_TOP_HPHL_PATH_SEC0: + case WCD939X_RX_TOP_HPHL_PATH_SEC1: + case WCD939X_RX_TOP_HPHL_PATH_SEC2: + case WCD939X_RX_TOP_HPHL_PATH_SEC3: + case WCD939X_RX_TOP_HPHR_PATH_SEC0: + case WCD939X_RX_TOP_HPHR_PATH_SEC1: + case WCD939X_RX_TOP_HPHR_PATH_SEC2: + case WCD939X_RX_TOP_HPHR_PATH_SEC3: + case WCD939X_RX_TOP_PATH_SEC4: + case WCD939X_RX_TOP_PATH_SEC5: + case WCD939X_COMPANDER_HPHL_CTL0: + case WCD939X_COMPANDER_HPHL_CTL1: + case WCD939X_COMPANDER_HPHL_CTL2: + case WCD939X_COMPANDER_HPHL_CTL3: + case WCD939X_COMPANDER_HPHL_CTL4: + case WCD939X_COMPANDER_HPHL_CTL5: + case WCD939X_COMPANDER_HPHL_CTL7: + case WCD939X_COMPANDER_HPHL_CTL8: + case WCD939X_COMPANDER_HPHL_CTL9: + case WCD939X_COMPANDER_HPHL_CTL10: + case WCD939X_COMPANDER_HPHL_CTL11: + case WCD939X_COMPANDER_HPHL_CTL12: + case WCD939X_COMPANDER_HPHL_CTL13: + case WCD939X_COMPANDER_HPHL_CTL14: + case WCD939X_COMPANDER_HPHL_CTL15: + case WCD939X_COMPANDER_HPHL_CTL16: + case WCD939X_COMPANDER_HPHL_CTL17: + case WCD939X_COMPANDER_HPHL_CTL18: + case WCD939X_COMPANDER_HPHL_CTL19: + case WCD939X_R_CTL0: + case WCD939X_R_CTL1: + case WCD939X_R_CTL2: + case WCD939X_R_CTL3: + case WCD939X_R_CTL4: + case WCD939X_R_CTL5: + case WCD939X_R_CTL7: + case WCD939X_R_CTL8: + case WCD939X_R_CTL9: + case WCD939X_R_CTL10: + case WCD939X_R_CTL11: + case WCD939X_R_CTL12: + case WCD939X_R_CTL13: + case WCD939X_R_CTL14: + case WCD939X_R_CTL15: + case WCD939X_R_CTL16: + case WCD939X_R_CTL17: + case WCD939X_R_CTL18: + case WCD939X_R_CTL19: + case WCD939X_E_PATH_CTL: + case WCD939X_E_CFG0: + case WCD939X_E_CFG1: + case WCD939X_E_CFG2: + case WCD939X_E_CFG3: + case WCD939X_DSD_HPHL_PATH_CTL: + case WCD939X_DSD_HPHL_CFG0: + case WCD939X_DSD_HPHL_CFG1: + case WCD939X_DSD_HPHL_CFG2: + case WCD939X_DSD_HPHL_CFG3: + case WCD939X_DSD_HPHL_CFG4: + case WCD939X_DSD_HPHL_CFG5: + case WCD939X_DSD_HPHR_PATH_CTL: + case WCD939X_DSD_HPHR_CFG0: + case WCD939X_DSD_HPHR_CFG1: + case WCD939X_DSD_HPHR_CFG2: + case WCD939X_DSD_HPHR_CFG3: + case WCD939X_DSD_HPHR_CFG4: + case WCD939X_DSD_HPHR_CFG5: + return true; + } + + return false; +} + +static bool wcd939x_readable_register(struct device *dev, unsigned int reg) +{ + /* Read-Only Registers */ + switch (reg) { + case WCD939X_ANA_MBHC_RESULT_1: + case WCD939X_ANA_MBHC_RESULT_2: + case WCD939X_ANA_MBHC_RESULT_3: + case WCD939X_MBHC_MOISTURE_DET_FSM_STATUS: + case WCD939X_TX_1_2_SAR2_ERR: + case WCD939X_TX_1_2_SAR1_ERR: + case WCD939X_TX_3_4_SAR4_ERR: + case WCD939X_TX_3_4_SAR3_ERR: + case WCD939X_HPH_L_STATUS: + case WCD939X_HPH_R_STATUS: + case WCD939X_HPH_SURGE_STATUS: + case WCD939X_EAR_STATUS_REG_1: + case WCD939X_EAR_STATUS_REG_2: + case WCD939X_MBHC_NEW_FSM_STATUS: + case WCD939X_MBHC_NEW_ADC_RESULT: + case WCD939X_DIE_CRACK_DET_OUT: + case WCD939X_DIGITAL_CHIP_ID0: + case WCD939X_DIGITAL_CHIP_ID1: + case WCD939X_DIGITAL_CHIP_ID2: + case WCD939X_DIGITAL_CHIP_ID3: + case WCD939X_DIGITAL_INTR_STATUS_0: + case WCD939X_DIGITAL_INTR_STATUS_1: + case WCD939X_DIGITAL_INTR_STATUS_2: + case WCD939X_DIGITAL_SWR_HM_TEST_0: + case WCD939X_DIGITAL_SWR_HM_TEST_1: + case WCD939X_DIGITAL_EFUSE_T_DATA_0: + case WCD939X_DIGITAL_EFUSE_T_DATA_1: + case WCD939X_DIGITAL_PIN_STATUS_0: + case WCD939X_DIGITAL_PIN_STATUS_1: + case WCD939X_DIGITAL_MODE_STATUS_0: + case WCD939X_DIGITAL_MODE_STATUS_1: + case WCD939X_DIGITAL_EFUSE_REG_0: + case WCD939X_DIGITAL_EFUSE_REG_1: + case WCD939X_DIGITAL_EFUSE_REG_2: + case WCD939X_DIGITAL_EFUSE_REG_3: + case WCD939X_DIGITAL_EFUSE_REG_4: + case WCD939X_DIGITAL_EFUSE_REG_5: + case WCD939X_DIGITAL_EFUSE_REG_6: + case WCD939X_DIGITAL_EFUSE_REG_7: + case WCD939X_DIGITAL_EFUSE_REG_8: + case WCD939X_DIGITAL_EFUSE_REG_9: + case WCD939X_DIGITAL_EFUSE_REG_10: + case WCD939X_DIGITAL_EFUSE_REG_11: + case WCD939X_DIGITAL_EFUSE_REG_12: + case WCD939X_DIGITAL_EFUSE_REG_13: + case WCD939X_DIGITAL_EFUSE_REG_14: + case WCD939X_DIGITAL_EFUSE_REG_15: + case WCD939X_DIGITAL_EFUSE_REG_16: + case WCD939X_DIGITAL_EFUSE_REG_17: + case WCD939X_DIGITAL_EFUSE_REG_18: + case WCD939X_DIGITAL_EFUSE_REG_19: + case WCD939X_DIGITAL_EFUSE_REG_20: + case WCD939X_DIGITAL_EFUSE_REG_21: + case WCD939X_DIGITAL_EFUSE_REG_22: + case WCD939X_DIGITAL_EFUSE_REG_23: + case WCD939X_DIGITAL_EFUSE_REG_24: + case WCD939X_DIGITAL_EFUSE_REG_25: + case WCD939X_DIGITAL_EFUSE_REG_26: + case WCD939X_DIGITAL_EFUSE_REG_27: + case WCD939X_DIGITAL_EFUSE_REG_28: + case WCD939X_DIGITAL_EFUSE_REG_29: + case WCD939X_DIGITAL_EFUSE_REG_30: + case WCD939X_DIGITAL_EFUSE_REG_31: + case WCD939X_RX_TOP_HPHL_COMP_RD_LSB: + case WCD939X_RX_TOP_HPHL_COMP_RD_MSB: + case WCD939X_RX_TOP_HPHR_COMP_RD_LSB: + case WCD939X_RX_TOP_HPHR_COMP_RD_MSB: + case WCD939X_RX_TOP_DSD0_DEBUG_CFG5: + case WCD939X_RX_TOP_DSD0_DEBUG_CFG6: + case WCD939X_RX_TOP_DSD1_DEBUG_CFG5: + case WCD939X_RX_TOP_DSD1_DEBUG_CFG6: + case WCD939X_COMPANDER_HPHL_CTL6: + case WCD939X_R_CTL6: + return true; + } + + return wcd939x_rdwr_register(dev, reg); +} + +static bool wcd939x_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WCD939X_ANA_MBHC_RESULT_1: + case WCD939X_ANA_MBHC_RESULT_2: + case WCD939X_ANA_MBHC_RESULT_3: + case WCD939X_MBHC_MOISTURE_DET_FSM_STATUS: + case WCD939X_TX_1_2_SAR2_ERR: + case WCD939X_TX_1_2_SAR1_ERR: + case WCD939X_TX_3_4_SAR4_ERR: + case WCD939X_TX_3_4_SAR3_ERR: + case WCD939X_HPH_L_STATUS: + case WCD939X_HPH_R_STATUS: + case WCD939X_HPH_SURGE_STATUS: + case WCD939X_EAR_STATUS_REG_1: + case WCD939X_EAR_STATUS_REG_2: + case WCD939X_MBHC_NEW_FSM_STATUS: + case WCD939X_MBHC_NEW_ADC_RESULT: + case WCD939X_DIE_CRACK_DET_OUT: + case WCD939X_DIGITAL_INTR_STATUS_0: + case WCD939X_DIGITAL_INTR_STATUS_1: + case WCD939X_DIGITAL_INTR_STATUS_2: + case WCD939X_DIGITAL_SWR_HM_TEST_0: + case WCD939X_DIGITAL_SWR_HM_TEST_1: + case WCD939X_DIGITAL_PIN_STATUS_0: + case WCD939X_DIGITAL_PIN_STATUS_1: + case WCD939X_DIGITAL_MODE_STATUS_0: + case WCD939X_DIGITAL_MODE_STATUS_1: + case WCD939X_RX_TOP_HPHL_COMP_RD_LSB: + case WCD939X_RX_TOP_HPHL_COMP_RD_MSB: + case WCD939X_RX_TOP_HPHR_COMP_RD_LSB: + case WCD939X_RX_TOP_HPHR_COMP_RD_MSB: + case WCD939X_RX_TOP_DSD0_DEBUG_CFG5: + case WCD939X_RX_TOP_DSD0_DEBUG_CFG6: + case WCD939X_RX_TOP_DSD1_DEBUG_CFG5: + case WCD939X_RX_TOP_DSD1_DEBUG_CFG6: + case WCD939X_COMPANDER_HPHL_CTL6: + case WCD939X_R_CTL6: + return true; + } + return false; +} + +static bool wcd939x_writeable_register(struct device *dev, unsigned int reg) +{ + return wcd939x_rdwr_register(dev, reg); +} + +static const struct regmap_config wcd939x_regmap_config = { + .name = "wcd939x_csr", + .reg_bits = 32, + .val_bits = 8, + .cache_type = REGCACHE_MAPLE, + .reg_defaults = wcd939x_defaults, + .num_reg_defaults = ARRAY_SIZE(wcd939x_defaults), + .max_register = WCD939X_MAX_REGISTER, + .readable_reg = wcd939x_readable_register, + .writeable_reg = wcd939x_writeable_register, + .volatile_reg = wcd939x_volatile_register, +}; + +static const struct sdw_slave_ops wcd9390_slave_ops = { + .update_status = wcd9390_update_status, + .interrupt_callback = wcd9390_interrupt_callback, + .bus_config = wcd9390_bus_config, +}; + +static int wcd939x_sdw_component_bind(struct device *dev, struct device *master, + void *data) +{ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + return 0; +} + +static void wcd939x_sdw_component_unbind(struct device *dev, + struct device *master, void *data) +{ + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_dont_use_autosuspend(dev); +} + +static const struct component_ops wcd939x_sdw_component_ops = { + .bind = wcd939x_sdw_component_bind, + .unbind = wcd939x_sdw_component_unbind, +}; + +static int wcd9390_probe(struct sdw_slave *pdev, const struct sdw_device_id *id) +{ + struct device *dev = &pdev->dev; + struct wcd939x_sdw_priv *wcd; + int ret; + + wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL); + if (!wcd) + return -ENOMEM; + + /* + * Port map index starts with 0, however the data port for this codec + * are from index 1 + */ + if (of_property_read_bool(dev->of_node, "qcom,tx-port-mapping")) { + wcd->is_tx = true; + ret = of_property_read_u32_array(dev->of_node, + "qcom,tx-port-mapping", + &pdev->m_port_map[1], + WCD939X_MAX_TX_SWR_PORTS); + } else { + ret = of_property_read_u32_array(dev->of_node, + "qcom,rx-port-mapping", + &pdev->m_port_map[1], + WCD939X_MAX_RX_SWR_PORTS); + } + + if (ret < 0) + dev_info(dev, "Static Port mapping not specified\n"); + + wcd->sdev = pdev; + dev_set_drvdata(dev, wcd); + + pdev->prop.scp_int1_mask = SDW_SCP_INT1_IMPL_DEF | + SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; + pdev->prop.lane_control_support = true; + pdev->prop.simple_clk_stop_capable = true; + if (wcd->is_tx) { + pdev->prop.source_ports = GENMASK(WCD939X_MAX_TX_SWR_PORTS, 0); + pdev->prop.src_dpn_prop = wcd939x_tx_dpn_prop; + wcd->ch_info = &wcd939x_sdw_tx_ch_info[0]; + pdev->prop.wake_capable = true; + } else { + pdev->prop.sink_ports = GENMASK(WCD939X_MAX_RX_SWR_PORTS, 0); + pdev->prop.sink_dpn_prop = wcd939x_rx_dpn_prop; + wcd->ch_info = &wcd939x_sdw_rx_ch_info[0]; + } + + if (wcd->is_tx) { + /* + * Do not use devres here since devres_release_group() could + * be called by component_unbind() id the aggregate device + * fails to bind. + */ + wcd->regmap = regmap_init_sdw(pdev, &wcd939x_regmap_config); + if (IS_ERR(wcd->regmap)) + return dev_err_probe(dev, PTR_ERR(wcd->regmap), + "Regmap init failed\n"); + + /* Start in cache-only until device is enumerated */ + regcache_cache_only(wcd->regmap, true); + } + + ret = component_add(dev, &wcd939x_sdw_component_ops); + if (ret) + return ret; + + /* Set suspended until aggregate device is bind */ + pm_runtime_set_suspended(dev); + + return 0; +} + +static int wcd9390_remove(struct sdw_slave *pdev) +{ + struct device *dev = &pdev->dev; + struct wcd939x_sdw_priv *wcd = dev_get_drvdata(dev); + + component_del(dev, &wcd939x_sdw_component_ops); + + if (wcd->regmap) + regmap_exit(wcd->regmap); + + return 0; +} + +static const struct sdw_device_id wcd9390_slave_id[] = { + SDW_SLAVE_ENTRY(0x0217, 0x10e, 0), /* WCD9390 & WCD9390 RX/TX Device ID */ + {}, +}; +MODULE_DEVICE_TABLE(sdw, wcd9390_slave_id); + +static int __maybe_unused wcd939x_sdw_runtime_suspend(struct device *dev) +{ + struct wcd939x_sdw_priv *wcd = dev_get_drvdata(dev); + + if (wcd->regmap) { + regcache_cache_only(wcd->regmap, true); + regcache_mark_dirty(wcd->regmap); + } + + return 0; +} + +static int __maybe_unused wcd939x_sdw_runtime_resume(struct device *dev) +{ + struct wcd939x_sdw_priv *wcd = dev_get_drvdata(dev); + + if (wcd->regmap) { + regcache_cache_only(wcd->regmap, false); + regcache_sync(wcd->regmap); + } + + return 0; +} + +static const struct dev_pm_ops wcd939x_sdw_pm_ops = { + SET_RUNTIME_PM_OPS(wcd939x_sdw_runtime_suspend, wcd939x_sdw_runtime_resume, NULL) +}; + +static struct sdw_driver wcd9390_codec_driver = { + .probe = wcd9390_probe, + .remove = wcd9390_remove, + .ops = &wcd9390_slave_ops, + .id_table = wcd9390_slave_id, + .driver = { + .name = "wcd9390-codec", + .pm = &wcd939x_sdw_pm_ops, + } +}; +module_sdw_driver(wcd9390_codec_driver); + +MODULE_DESCRIPTION("WCD939X SDW codec driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c new file mode 100644 index 000000000000..0ccc7b31d0c1 --- /dev/null +++ b/sound/soc/codecs/wcd939x.c @@ -0,0 +1,3686 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023, Linaro Limited + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/kernel.h> +#include <linux/pm_runtime.h> +#include <linux/component.h> +#include <sound/tlv.h> +#include <linux/of_gpio.h> +#include <linux/of_graph.h> +#include <linux/of.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <linux/regmap.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <linux/regulator/consumer.h> +#include <linux/usb/typec_mux.h> +#include <linux/usb/typec_altmode.h> + +#include "wcd-clsh-v2.h" +#include "wcd-mbhc-v2.h" +#include "wcd939x.h" + +#define WCD939X_MAX_MICBIAS (4) +#define WCD939X_MAX_SUPPLY (4) +#define WCD939X_MBHC_MAX_BUTTONS (8) +#define TX_ADC_MAX (4) +#define WCD_MBHC_HS_V_MAX 1600 + +enum { + WCD939X_VERSION_1_0 = 0, + WCD939X_VERSION_1_1, + WCD939X_VERSION_2_0, +}; + +#define WCD939X_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\ + SNDRV_PCM_RATE_384000) +/* Fractional Rates */ +#define WCD939X_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800) +#define WCD939X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +/* Convert from vout ctl to micbias voltage in mV */ +#define WCD_VOUT_CTL_TO_MICB(v) (1000 + (v) * 50) +#define SWR_CLK_RATE_0P6MHZ (600000) +#define SWR_CLK_RATE_1P2MHZ (1200000) +#define SWR_CLK_RATE_2P4MHZ (2400000) +#define SWR_CLK_RATE_4P8MHZ (4800000) +#define SWR_CLK_RATE_9P6MHZ (9600000) +#define SWR_CLK_RATE_11P2896MHZ (1128960) + +#define ADC_MODE_VAL_HIFI 0x01 +#define ADC_MODE_VAL_LO_HIF 0x02 +#define ADC_MODE_VAL_NORMAL 0x03 +#define ADC_MODE_VAL_LP 0x05 +#define ADC_MODE_VAL_ULP1 0x09 +#define ADC_MODE_VAL_ULP2 0x0B + +/* Z value defined in milliohm */ +#define WCD939X_ZDET_VAL_32 (32000) +#define WCD939X_ZDET_VAL_400 (400000) +#define WCD939X_ZDET_VAL_1200 (1200000) +#define WCD939X_ZDET_VAL_100K (100000000) + +/* Z floating defined in ohms */ +#define WCD939X_ZDET_FLOATING_IMPEDANCE (0x0FFFFFFE) +#define WCD939X_ZDET_NUM_MEASUREMENTS (900) +#define WCD939X_MBHC_GET_C1(c) (((c) & 0xC000) >> 14) +#define WCD939X_MBHC_GET_X1(x) ((x) & 0x3FFF) + +/* Z value compared in milliOhm */ +#define WCD939X_MBHC_IS_SECOND_RAMP_REQUIRED(z) false +#define WCD939X_ANA_MBHC_ZDET_CONST (1018 * 1024) + +enum { + WCD9390 = 0, + WCD9395 = 5, +}; + +enum { + /* INTR_CTRL_INT_MASK_0 */ + WCD939X_IRQ_MBHC_BUTTON_PRESS_DET = 0, + WCD939X_IRQ_MBHC_BUTTON_RELEASE_DET, + WCD939X_IRQ_MBHC_ELECT_INS_REM_DET, + WCD939X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, + WCD939X_IRQ_MBHC_SW_DET, + WCD939X_IRQ_HPHR_OCP_INT, + WCD939X_IRQ_HPHR_CNP_INT, + WCD939X_IRQ_HPHL_OCP_INT, + + /* INTR_CTRL_INT_MASK_1 */ + WCD939X_IRQ_HPHL_CNP_INT, + WCD939X_IRQ_EAR_CNP_INT, + WCD939X_IRQ_EAR_SCD_INT, + WCD939X_IRQ_HPHL_PDM_WD_INT, + WCD939X_IRQ_HPHR_PDM_WD_INT, + WCD939X_IRQ_EAR_PDM_WD_INT, + + /* INTR_CTRL_INT_MASK_2 */ + WCD939X_IRQ_MBHC_MOISTURE_INT, + WCD939X_IRQ_HPHL_SURGE_DET_INT, + WCD939X_IRQ_HPHR_SURGE_DET_INT, + WCD939X_NUM_IRQS, +}; + +enum { + MICB_BIAS_DISABLE = 0, + MICB_BIAS_ENABLE, + MICB_BIAS_PULL_UP, + MICB_BIAS_PULL_DOWN, +}; + +enum { + WCD_ADC1 = 0, + WCD_ADC2, + WCD_ADC3, + WCD_ADC4, + HPH_PA_DELAY, +}; + +enum { + ADC_MODE_INVALID = 0, + ADC_MODE_HIFI, + ADC_MODE_LO_HIF, + ADC_MODE_NORMAL, + ADC_MODE_LP, + ADC_MODE_ULP1, + ADC_MODE_ULP2, +}; + +enum { + AIF1_PB = 0, + AIF1_CAP, + NUM_CODEC_DAIS, +}; + +static u8 tx_mode_bit[] = { + [ADC_MODE_INVALID] = 0x00, + [ADC_MODE_HIFI] = 0x01, + [ADC_MODE_LO_HIF] = 0x02, + [ADC_MODE_NORMAL] = 0x04, + [ADC_MODE_LP] = 0x08, + [ADC_MODE_ULP1] = 0x10, + [ADC_MODE_ULP2] = 0x20, +}; + +struct zdet_param { + u16 ldo_ctl; + u16 noff; + u16 nshift; + u16 btn5; + u16 btn6; + u16 btn7; +}; + +struct wcd939x_priv { + struct sdw_slave *tx_sdw_dev; + struct wcd939x_sdw_priv *sdw_priv[NUM_CODEC_DAIS]; + struct device *txdev; + struct device *rxdev; + struct device_node *rxnode, *txnode; + struct regmap *regmap; + struct snd_soc_component *component; + /* micb setup lock */ + struct mutex micb_lock; + /* typec handling */ + bool typec_analog_mux; +#if IS_ENABLED(CONFIG_TYPEC) + struct typec_mux_dev *typec_mux; + struct typec_switch_dev *typec_sw; + enum typec_orientation typec_orientation; + unsigned long typec_mode; + struct typec_switch *typec_switch; +#endif /* CONFIG_TYPEC */ + /* 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; + struct regmap_irq_chip_data *irq_chip; + struct regulator_bulk_data supplies[WCD939X_MAX_SUPPLY]; + struct snd_soc_jack *jack; + unsigned long status_mask; + s32 micb_ref[WCD939X_MAX_MICBIAS]; + s32 pullup_ref[WCD939X_MAX_MICBIAS]; + u32 hph_mode; + u32 tx_mode[TX_ADC_MAX]; + int variant; + int reset_gpio; + u32 micb1_mv; + u32 micb2_mv; + u32 micb3_mv; + u32 micb4_mv; + int hphr_pdm_wd_int; + int hphl_pdm_wd_int; + int ear_pdm_wd_int; + bool comp1_enable; + bool comp2_enable; + bool ldoh; +}; + +static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800); +static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); +static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); + +static struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = { + WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD939X_ANA_MBHC_MECH, 0x80), + WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD939X_ANA_MBHC_MECH, 0x40), + WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD939X_ANA_MBHC_MECH, 0x20), + WCD_MBHC_FIELD(WCD_MBHC_MIC_CLAMP_CTL, WCD939X_MBHC_NEW_PLUG_DETECT_CTL, 0x30), + WCD_MBHC_FIELD(WCD_MBHC_ELECT_DETECTION_TYPE, WCD939X_ANA_MBHC_ELECT, 0x08), + WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_CTRL, WCD939X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x1F), + WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, WCD939X_ANA_MBHC_MECH, 0x04), + WCD_MBHC_FIELD(WCD_MBHC_HPHL_PLUG_TYPE, WCD939X_ANA_MBHC_MECH, 0x10), + WCD_MBHC_FIELD(WCD_MBHC_GND_PLUG_TYPE, WCD939X_ANA_MBHC_MECH, 0x08), + WCD_MBHC_FIELD(WCD_MBHC_SW_HPH_LP_100K_TO_GND, WCD939X_ANA_MBHC_MECH, 0x01), + WCD_MBHC_FIELD(WCD_MBHC_ELECT_SCHMT_ISRC, WCD939X_ANA_MBHC_ELECT, 0x06), + WCD_MBHC_FIELD(WCD_MBHC_FSM_EN, WCD939X_ANA_MBHC_ELECT, 0x80), + WCD_MBHC_FIELD(WCD_MBHC_INSREM_DBNC, WCD939X_MBHC_NEW_PLUG_DETECT_CTL, 0x0F), + WCD_MBHC_FIELD(WCD_MBHC_BTN_DBNC, WCD939X_MBHC_NEW_CTL_1, 0x03), + WCD_MBHC_FIELD(WCD_MBHC_HS_VREF, WCD939X_MBHC_NEW_CTL_2, 0x03), + WCD_MBHC_FIELD(WCD_MBHC_HS_COMP_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0x08), + WCD_MBHC_FIELD(WCD_MBHC_IN2P_CLAMP_STATE, WCD939X_ANA_MBHC_RESULT_3, 0x10), + WCD_MBHC_FIELD(WCD_MBHC_MIC_SCHMT_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0x20), + WCD_MBHC_FIELD(WCD_MBHC_HPHL_SCHMT_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0x80), + WCD_MBHC_FIELD(WCD_MBHC_HPHR_SCHMT_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0x40), + WCD_MBHC_FIELD(WCD_MBHC_OCP_FSM_EN, WCD939X_HPH_OCP_CTL, 0x10), + WCD_MBHC_FIELD(WCD_MBHC_BTN_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0x07), + WCD_MBHC_FIELD(WCD_MBHC_BTN_ISRC_CTL, WCD939X_ANA_MBHC_ELECT, 0x70), + WCD_MBHC_FIELD(WCD_MBHC_ELECT_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0xFF), + WCD_MBHC_FIELD(WCD_MBHC_MICB_CTRL, WCD939X_ANA_MICB2, 0xC0), + WCD_MBHC_FIELD(WCD_MBHC_HPH_CNP_WG_TIME, WCD939X_HPH_CNP_WG_TIME, 0xFF), + WCD_MBHC_FIELD(WCD_MBHC_HPHR_PA_EN, WCD939X_ANA_HPH, 0x40), + WCD_MBHC_FIELD(WCD_MBHC_HPHL_PA_EN, WCD939X_ANA_HPH, 0x80), + WCD_MBHC_FIELD(WCD_MBHC_HPH_PA_EN, WCD939X_ANA_HPH, 0xC0), + WCD_MBHC_FIELD(WCD_MBHC_SWCH_LEVEL_REMOVE, WCD939X_ANA_MBHC_RESULT_3, 0x10), + WCD_MBHC_FIELD(WCD_MBHC_ANC_DET_EN, WCD939X_MBHC_CTL_BCS, 0x02), + WCD_MBHC_FIELD(WCD_MBHC_FSM_STATUS, WCD939X_MBHC_NEW_FSM_STATUS, 0x01), + WCD_MBHC_FIELD(WCD_MBHC_MUX_CTL, WCD939X_MBHC_NEW_CTL_2, 0x70), + WCD_MBHC_FIELD(WCD_MBHC_MOISTURE_STATUS, WCD939X_MBHC_NEW_FSM_STATUS, 0x20), + WCD_MBHC_FIELD(WCD_MBHC_HPHR_GND, WCD939X_HPH_PA_CTL2, 0x40), + WCD_MBHC_FIELD(WCD_MBHC_HPHL_GND, WCD939X_HPH_PA_CTL2, 0x10), + WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_DET_EN, WCD939X_HPH_L_TEST, 0x01), + WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_DET_EN, WCD939X_HPH_R_TEST, 0x01), + WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_STATUS, WCD939X_DIGITAL_INTR_STATUS_0, 0x80), + WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_STATUS, WCD939X_DIGITAL_INTR_STATUS_0, 0x20), + WCD_MBHC_FIELD(WCD_MBHC_ADC_EN, WCD939X_MBHC_NEW_CTL_1, 0x08), + WCD_MBHC_FIELD(WCD_MBHC_ADC_COMPLETE, WCD939X_MBHC_NEW_FSM_STATUS, 0x40), + WCD_MBHC_FIELD(WCD_MBHC_ADC_TIMEOUT, WCD939X_MBHC_NEW_FSM_STATUS, 0x80), + WCD_MBHC_FIELD(WCD_MBHC_ADC_RESULT, WCD939X_MBHC_NEW_ADC_RESULT, 0xFF), + WCD_MBHC_FIELD(WCD_MBHC_MICB2_VOUT, WCD939X_ANA_MICB2, 0x3F), + WCD_MBHC_FIELD(WCD_MBHC_ADC_MODE, WCD939X_MBHC_NEW_CTL_1, 0x10), + WCD_MBHC_FIELD(WCD_MBHC_DETECTION_DONE, WCD939X_MBHC_NEW_CTL_1, 0x04), + WCD_MBHC_FIELD(WCD_MBHC_ELECT_ISRC_EN, WCD939X_ANA_MBHC_ZDET, 0x02), +}; + +static const struct regmap_irq wcd939x_irqs[WCD939X_NUM_IRQS] = { + REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_BUTTON_PRESS_DET, 0, 0x01), + REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_BUTTON_RELEASE_DET, 0, 0x02), + REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_ELECT_INS_REM_DET, 0, 0x04), + REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 0, 0x08), + REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_SW_DET, 0, 0x10), + REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_OCP_INT, 0, 0x20), + REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_CNP_INT, 0, 0x40), + REGMAP_IRQ_REG(WCD939X_IRQ_HPHL_OCP_INT, 0, 0x80), + REGMAP_IRQ_REG(WCD939X_IRQ_HPHL_CNP_INT, 1, 0x01), + REGMAP_IRQ_REG(WCD939X_IRQ_EAR_CNP_INT, 1, 0x02), + REGMAP_IRQ_REG(WCD939X_IRQ_EAR_SCD_INT, 1, 0x04), + REGMAP_IRQ_REG(WCD939X_IRQ_HPHL_PDM_WD_INT, 1, 0x20), + REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_PDM_WD_INT, 1, 0x40), + REGMAP_IRQ_REG(WCD939X_IRQ_EAR_PDM_WD_INT, 1, 0x80), + REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_MOISTURE_INT, 2, 0x02), + REGMAP_IRQ_REG(WCD939X_IRQ_HPHL_SURGE_DET_INT, 2, 0x04), + REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_SURGE_DET_INT, 2, 0x08), +}; + +static struct regmap_irq_chip wcd939x_regmap_irq_chip = { + .name = "wcd939x", + .irqs = wcd939x_irqs, + .num_irqs = ARRAY_SIZE(wcd939x_irqs), + .num_regs = 3, + .status_base = WCD939X_DIGITAL_INTR_STATUS_0, + .mask_base = WCD939X_DIGITAL_INTR_MASK_0, + .ack_base = WCD939X_DIGITAL_INTR_CLEAR_0, + .use_ack = 1, + .runtime_pm = true, + .irq_drv_data = NULL, +}; + +static int wcd939x_get_clk_rate(int mode) +{ + int rate; + + switch (mode) { + case ADC_MODE_ULP2: + rate = SWR_CLK_RATE_0P6MHZ; + break; + case ADC_MODE_ULP1: + rate = SWR_CLK_RATE_1P2MHZ; + break; + case ADC_MODE_LP: + rate = SWR_CLK_RATE_4P8MHZ; + break; + case ADC_MODE_NORMAL: + case ADC_MODE_LO_HIF: + case ADC_MODE_HIFI: + case ADC_MODE_INVALID: + default: + rate = SWR_CLK_RATE_9P6MHZ; + break; + } + + return rate; +} + +static int wcd939x_set_swr_clk_rate(struct snd_soc_component *component, int rate, int bank) +{ + u8 mask = (bank ? 0xF0 : 0x0F); + u8 val = 0; + + switch (rate) { + case SWR_CLK_RATE_0P6MHZ: + val = 6; + break; + case SWR_CLK_RATE_1P2MHZ: + val = 5; + break; + case SWR_CLK_RATE_2P4MHZ: + val = 3; + break; + case SWR_CLK_RATE_4P8MHZ: + val = 1; + break; + case SWR_CLK_RATE_9P6MHZ: + default: + val = 0; + break; + } + + snd_soc_component_write_field(component, WCD939X_DIGITAL_SWR_TX_CLK_RATE, mask, val); + + return 0; +} + +static int wcd939x_io_init(struct snd_soc_component *component) +{ + snd_soc_component_write_field(component, WCD939X_ANA_BIAS, + WCD939X_BIAS_ANALOG_BIAS_EN, true); + snd_soc_component_write_field(component, WCD939X_ANA_BIAS, + WCD939X_BIAS_PRECHRG_EN, true); + + /* 10 msec delay as per HW requirement */ + usleep_range(10000, 10010); + snd_soc_component_write_field(component, WCD939X_ANA_BIAS, + WCD939X_BIAS_PRECHRG_EN, false); + + snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_L, + WCD939X_RDAC_HD2_CTL_L_HD2_RES_DIV_CTL_L, 0x15); + snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_R, + WCD939X_RDAC_HD2_CTL_R_HD2_RES_DIV_CTL_R, 0x15); + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DMIC_CTL, + WCD939X_CDC_DMIC_CTL_CLK_SCALE_EN, true); + + snd_soc_component_write_field(component, WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2CASC_ULP, + WCD939X_FE_ICTRL_STG2CASC_ULP_ICTRL_SCBIAS_ULP0P6M, 1); + snd_soc_component_write_field(component, WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2CASC_ULP, + WCD939X_FE_ICTRL_STG2CASC_ULP_VALUE, 4); + + snd_soc_component_write_field(component, WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2MAIN_ULP, + WCD939X_FE_ICTRL_STG2MAIN_ULP_VALUE, 8); + + snd_soc_component_write_field(component, WCD939X_MICB1_TEST_CTL_1, + WCD939X_TEST_CTL_1_NOISE_FILT_RES_VAL, 7); + snd_soc_component_write_field(component, WCD939X_MICB2_TEST_CTL_1, + WCD939X_TEST_CTL_1_NOISE_FILT_RES_VAL, 7); + snd_soc_component_write_field(component, WCD939X_MICB3_TEST_CTL_1, + WCD939X_TEST_CTL_1_NOISE_FILT_RES_VAL, 7); + snd_soc_component_write_field(component, WCD939X_MICB4_TEST_CTL_1, + WCD939X_TEST_CTL_1_NOISE_FILT_RES_VAL, 7); + snd_soc_component_write_field(component, WCD939X_TX_3_4_TEST_BLK_EN2, + WCD939X_TEST_BLK_EN2_TXFE2_MBHC_CLKRST_EN, false); + + snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN, + WCD939X_EN_EN_SURGE_PROTECTION_HPHL, false); + snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN, + WCD939X_EN_EN_SURGE_PROTECTION_HPHR, false); + + snd_soc_component_write_field(component, WCD939X_HPH_OCP_CTL, + WCD939X_OCP_CTL_OCP_FSM_EN, true); + snd_soc_component_write_field(component, WCD939X_HPH_OCP_CTL, + WCD939X_OCP_CTL_SCD_OP_EN, true); + + snd_soc_component_write(component, WCD939X_E_CFG0, + WCD939X_CFG0_IDLE_STEREO | + WCD939X_CFG0_AUTO_DISABLE_ANC); + + return 0; +} + +static int wcd939x_sdw_connect_port(struct wcd939x_sdw_ch_info *ch_info, + struct sdw_port_config *port_config, + u8 enable) +{ + u8 ch_mask, port_num; + + port_num = ch_info->port_num; + ch_mask = ch_info->ch_mask; + + port_config->num = port_num; + + if (enable) + port_config->ch_mask |= ch_mask; + else + port_config->ch_mask &= ~ch_mask; + + return 0; +} + +static int wcd939x_connect_port(struct wcd939x_sdw_priv *wcd, u8 port_num, u8 ch_id, u8 enable) +{ + return wcd939x_sdw_connect_port(&wcd->ch_info[ch_id], + &wcd->port_config[port_num - 1], + enable); +} + +static int wcd939x_codec_enable_rxclk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES, + WCD939X_RX_SUPPLIES_RX_BIAS_ENABLE, true); + + /* Analog path clock controls */ + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, + WCD939X_CDC_ANA_CLK_CTL_ANA_RX_CLK_EN, true); + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, + WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV2_CLK_EN, + true); + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, + WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV4_CLK_EN, + true); + + /* Digital path clock controls */ + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL, + WCD939X_CDC_DIG_CLK_CTL_RXD0_CLK_EN, true); + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL, + WCD939X_CDC_DIG_CLK_CTL_RXD1_CLK_EN, true); + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL, + WCD939X_CDC_DIG_CLK_CTL_RXD2_CLK_EN, true); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES, + WCD939X_RX_SUPPLIES_VNEG_EN, false); + snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES, + WCD939X_RX_SUPPLIES_VPOS_EN, false); + + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL, + WCD939X_CDC_DIG_CLK_CTL_RXD2_CLK_EN, false); + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL, + WCD939X_CDC_DIG_CLK_CTL_RXD1_CLK_EN, false); + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL, + WCD939X_CDC_DIG_CLK_CTL_RXD0_CLK_EN, false); + + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, + WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV4_CLK_EN, + false); + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, + WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV2_CLK_EN, + false); + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, + WCD939X_CDC_ANA_CLK_CTL_ANA_RX_CLK_EN, false); + + snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES, + WCD939X_RX_SUPPLIES_RX_BIAS_ENABLE, false); + + break; + } + + return 0; +} + +static int wcd939x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, WCD939X_HPH_RDAC_CLK_CTL1, + WCD939X_RDAC_CLK_CTL1_OPAMP_CHOP_CLK_EN, + false); + + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_HPH_GAIN_CTL, + WCD939X_CDC_HPH_GAIN_CTL_HPHL_RX_EN, true); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_L, + WCD939X_RDAC_HD2_CTL_L_HD2_RES_DIV_CTL_L, 0x1d); + if (wcd939x->comp1_enable) { + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_COMP_CTL_0, + WCD939X_CDC_COMP_CTL_0_HPHL_COMP_EN, + true); + /* 5msec compander delay as per HW requirement */ + if (!wcd939x->comp2_enable || + snd_soc_component_read_field(component, + WCD939X_DIGITAL_CDC_COMP_CTL_0, + WCD939X_CDC_COMP_CTL_0_HPHR_COMP_EN)) + usleep_range(5000, 5010); + + snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_TIMER1, + WCD939X_TIMER1_AUTOCHOP_TIMER_CTL_EN, + false); + } else { + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_COMP_CTL_0, + WCD939X_CDC_COMP_CTL_0_HPHL_COMP_EN, + false); + snd_soc_component_write_field(component, WCD939X_HPH_L_EN, + WCD939X_L_EN_GAIN_SOURCE_SEL, true); + } + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_L, + WCD939X_RDAC_HD2_CTL_L_HD2_RES_DIV_CTL_L, 1); + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_HPH_GAIN_CTL, + WCD939X_CDC_HPH_GAIN_CTL_HPHL_RX_EN, false); + break; + } + + return 0; +} + +static int wcd939x_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, WCD939X_HPH_RDAC_CLK_CTL1, + WCD939X_RDAC_CLK_CTL1_OPAMP_CHOP_CLK_EN, + false); + + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_HPH_GAIN_CTL, + WCD939X_CDC_HPH_GAIN_CTL_HPHR_RX_EN, true); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_R, + WCD939X_RDAC_HD2_CTL_R_HD2_RES_DIV_CTL_R, 0x1d); + if (wcd939x->comp2_enable) { + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_COMP_CTL_0, + WCD939X_CDC_COMP_CTL_0_HPHR_COMP_EN, + true); + /* 5msec compander delay as per HW requirement */ + if (!wcd939x->comp1_enable || + snd_soc_component_read_field(component, + WCD939X_DIGITAL_CDC_COMP_CTL_0, + WCD939X_CDC_COMP_CTL_0_HPHL_COMP_EN)) + usleep_range(5000, 5010); + snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_TIMER1, + WCD939X_TIMER1_AUTOCHOP_TIMER_CTL_EN, + false); + } else { + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_COMP_CTL_0, + WCD939X_CDC_COMP_CTL_0_HPHR_COMP_EN, + false); + snd_soc_component_write_field(component, WCD939X_HPH_R_EN, + WCD939X_R_EN_GAIN_SOURCE_SEL, true); + } + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_R, + WCD939X_RDAC_HD2_CTL_R_HD2_RES_DIV_CTL_R, 1); + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_HPH_GAIN_CTL, + WCD939X_CDC_HPH_GAIN_CTL_HPHR_RX_EN, false); + break; + } + + return 0; +} + +static int wcd939x_codec_ear_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_EAR_GAIN_CTL, + WCD939X_CDC_EAR_GAIN_CTL_EAR_EN, true); + + snd_soc_component_write_field(component, WCD939X_EAR_DAC_CON, + WCD939X_DAC_CON_DAC_SAMPLE_EDGE_SEL, false); + + /* 5 msec delay as per HW requirement */ + usleep_range(5000, 5010); + wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_EAR, CLS_AB_HIFI); + + snd_soc_component_write_field(component, WCD939X_FLYBACK_VNEG_CTRL_4, + WCD939X_VNEG_CTRL_4_ILIM_SEL, 0xd); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_write_field(component, WCD939X_EAR_DAC_CON, + WCD939X_DAC_CON_DAC_SAMPLE_EDGE_SEL, true); + break; + } + + return 0; +} + +static int wcd939x_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd939x->hph_mode; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (wcd939x->ldoh) + snd_soc_component_write_field(component, WCD939X_LDOH_MODE, + WCD939X_MODE_LDOH_EN, true); + + wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHR, hph_mode); + wcd_clsh_set_hph_mode(wcd939x->clsh_info, CLS_H_HIFI); + + if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || hph_mode == CLS_H_ULP) + snd_soc_component_write_field(component, + WCD939X_HPH_REFBUFF_LP_CTL, + WCD939X_REFBUFF_LP_CTL_PREREF_FILT_BYPASS, true); + if (hph_mode == CLS_H_LOHIFI) + snd_soc_component_write_field(component, WCD939X_ANA_HPH, + WCD939X_HPH_PWR_LEVEL, 0); + + snd_soc_component_write_field(component, WCD939X_FLYBACK_VNEG_CTRL_4, + WCD939X_VNEG_CTRL_4_ILIM_SEL, 0xd); + snd_soc_component_write_field(component, WCD939X_ANA_HPH, + WCD939X_HPH_HPHR_REF_ENABLE, true); + + if (snd_soc_component_read_field(component, WCD939X_ANA_HPH, + WCD939X_HPH_HPHL_REF_ENABLE)) + usleep_range(2500, 2600); /* 2.5msec delay as per HW requirement */ + + set_bit(HPH_PA_DELAY, &wcd939x->status_mask); + snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL1, + WCD939X_PDM_WD_CTL1_PDM_WD_EN, 3); + break; + case SND_SOC_DAPM_POST_PMU: + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (test_bit(HPH_PA_DELAY, &wcd939x->status_mask)) { + if (!wcd939x->comp2_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + + if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || + hph_mode == CLS_H_ULP) + snd_soc_component_write_field(component, + WCD939X_HPH_REFBUFF_LP_CTL, + WCD939X_REFBUFF_LP_CTL_PREREF_FILT_BYPASS, + false); + clear_bit(HPH_PA_DELAY, &wcd939x->status_mask); + } + snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_TIMER1, + WCD939X_TIMER1_AUTOCHOP_TIMER_CTL_EN, true); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI || + hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) + snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES, + WCD939X_RX_SUPPLIES_REGULATOR_MODE, + true); + + enable_irq(wcd939x->hphr_pdm_wd_int); + break; + case SND_SOC_DAPM_PRE_PMD: + disable_irq_nosync(wcd939x->hphr_pdm_wd_int); + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (!wcd939x->comp2_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + + snd_soc_component_write_field(component, WCD939X_ANA_HPH, + WCD939X_HPH_HPHR_ENABLE, false); + + wcd_mbhc_event_notify(wcd939x->wcd_mbhc, + WCD_EVENT_PRE_HPHR_PA_OFF); + set_bit(HPH_PA_DELAY, &wcd939x->status_mask); + break; + case SND_SOC_DAPM_POST_PMD: + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (test_bit(HPH_PA_DELAY, &wcd939x->status_mask)) { + if (!wcd939x->comp2_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &wcd939x->status_mask); + } + wcd_mbhc_event_notify(wcd939x->wcd_mbhc, + WCD_EVENT_POST_HPHR_PA_OFF); + + snd_soc_component_write_field(component, WCD939X_ANA_HPH, + WCD939X_HPH_HPHR_REF_ENABLE, false); + snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL1, + WCD939X_PDM_WD_CTL1_PDM_WD_EN, 0); + + wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHR, hph_mode); + if (wcd939x->ldoh) + snd_soc_component_write_field(component, WCD939X_LDOH_MODE, + WCD939X_MODE_LDOH_EN, false); + break; + } + + return 0; +} + +static int wcd939x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd939x->hph_mode; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (wcd939x->ldoh) + snd_soc_component_write_field(component, WCD939X_LDOH_MODE, + WCD939X_MODE_LDOH_EN, true); + wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHL, hph_mode); + wcd_clsh_set_hph_mode(wcd939x->clsh_info, CLS_H_HIFI); + + if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || hph_mode == CLS_H_ULP) + snd_soc_component_write_field(component, + WCD939X_HPH_REFBUFF_LP_CTL, + WCD939X_REFBUFF_LP_CTL_PREREF_FILT_BYPASS, + true); + if (hph_mode == CLS_H_LOHIFI) + snd_soc_component_write_field(component, WCD939X_ANA_HPH, + WCD939X_HPH_PWR_LEVEL, 0); + + snd_soc_component_write_field(component, WCD939X_FLYBACK_VNEG_CTRL_4, + WCD939X_VNEG_CTRL_4_ILIM_SEL, 0xd); + snd_soc_component_write_field(component, WCD939X_ANA_HPH, + WCD939X_HPH_HPHL_REF_ENABLE, true); + + if (snd_soc_component_read_field(component, WCD939X_ANA_HPH, + WCD939X_HPH_HPHR_REF_ENABLE)) + usleep_range(2500, 2600); /* 2.5msec delay as per HW requirement */ + + set_bit(HPH_PA_DELAY, &wcd939x->status_mask); + snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL0, + WCD939X_PDM_WD_CTL0_PDM_WD_EN, 3); + break; + case SND_SOC_DAPM_POST_PMU: + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (test_bit(HPH_PA_DELAY, &wcd939x->status_mask)) { + if (!wcd939x->comp1_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || + hph_mode == CLS_H_ULP) + snd_soc_component_write_field(component, + WCD939X_HPH_REFBUFF_LP_CTL, + WCD939X_REFBUFF_LP_CTL_PREREF_FILT_BYPASS, + false); + clear_bit(HPH_PA_DELAY, &wcd939x->status_mask); + } + snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_TIMER1, + WCD939X_TIMER1_AUTOCHOP_TIMER_CTL_EN, true); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI || + hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) + snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES, + WCD939X_RX_SUPPLIES_REGULATOR_MODE, + true); + enable_irq(wcd939x->hphl_pdm_wd_int); + break; + case SND_SOC_DAPM_PRE_PMD: + disable_irq_nosync(wcd939x->hphl_pdm_wd_int); + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (!wcd939x->comp1_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + + snd_soc_component_write_field(component, WCD939X_ANA_HPH, + WCD939X_HPH_HPHL_ENABLE, false); + + wcd_mbhc_event_notify(wcd939x->wcd_mbhc, WCD_EVENT_PRE_HPHL_PA_OFF); + set_bit(HPH_PA_DELAY, &wcd939x->status_mask); + break; + case SND_SOC_DAPM_POST_PMD: + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (test_bit(HPH_PA_DELAY, &wcd939x->status_mask)) { + if (!wcd939x->comp1_enable) + usleep_range(21000, 21100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &wcd939x->status_mask); + } + wcd_mbhc_event_notify(wcd939x->wcd_mbhc, + WCD_EVENT_POST_HPHL_PA_OFF); + snd_soc_component_write_field(component, WCD939X_ANA_HPH, + WCD939X_HPH_HPHL_REF_ENABLE, false); + snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL0, + WCD939X_PDM_WD_CTL0_PDM_WD_EN, 0); + wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHL, hph_mode); + if (wcd939x->ldoh) + snd_soc_component_write_field(component, WCD939X_LDOH_MODE, + WCD939X_MODE_LDOH_EN, false); + break; + } + + return 0; +} + +static int wcd939x_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Enable watchdog interrupt for HPHL */ + snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL0, + WCD939X_PDM_WD_CTL0_PDM_WD_EN, 3); + /* For EAR, use CLASS_AB regulator mode */ + snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES, + WCD939X_RX_SUPPLIES_REGULATOR_MODE, true); + snd_soc_component_write_field(component, WCD939X_ANA_EAR_COMPANDER_CTL, + WCD939X_EAR_COMPANDER_CTL_GAIN_OVRD_REG, true); + break; + case SND_SOC_DAPM_POST_PMU: + /* 6 msec delay as per HW requirement */ + usleep_range(6000, 6010); + enable_irq(wcd939x->ear_pdm_wd_int); + break; + case SND_SOC_DAPM_PRE_PMD: + disable_irq_nosync(wcd939x->ear_pdm_wd_int); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_write_field(component, WCD939X_ANA_EAR_COMPANDER_CTL, + WCD939X_EAR_COMPANDER_CTL_GAIN_OVRD_REG, + false); + /* 7 msec delay as per HW requirement */ + usleep_range(7000, 7010); + snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL0, + WCD939X_PDM_WD_CTL0_PDM_WD_EN, 0); + wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_EAR, CLS_AB_HIFI); + break; + } + + return 0; +} + +/* TX Controls */ + +static int wcd939x_codec_enable_dmic(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + u16 dmic_clk_reg, dmic_clk_en_reg; + u8 dmic_clk_en_mask; + u8 dmic_ctl_mask; + u8 dmic_clk_mask; + + switch (w->shift) { + case 0: + case 1: + dmic_clk_reg = WCD939X_DIGITAL_CDC_DMIC_RATE_1_2; + dmic_clk_en_reg = WCD939X_DIGITAL_CDC_DMIC1_CTL; + dmic_clk_en_mask = WCD939X_CDC_DMIC1_CTL_DMIC_CLK_EN; + dmic_clk_mask = WCD939X_CDC_DMIC_RATE_1_2_DMIC1_RATE; + dmic_ctl_mask = WCD939X_CDC_AMIC_CTL_AMIC1_IN_SEL; + break; + case 2: + case 3: + dmic_clk_reg = WCD939X_DIGITAL_CDC_DMIC_RATE_1_2; + dmic_clk_en_reg = WCD939X_DIGITAL_CDC_DMIC2_CTL; + dmic_clk_en_mask = WCD939X_CDC_DMIC2_CTL_DMIC_CLK_EN; + dmic_clk_mask = WCD939X_CDC_DMIC_RATE_1_2_DMIC2_RATE; + dmic_ctl_mask = WCD939X_CDC_AMIC_CTL_AMIC3_IN_SEL; + break; + case 4: + case 5: + dmic_clk_reg = WCD939X_DIGITAL_CDC_DMIC_RATE_3_4; + dmic_clk_en_reg = WCD939X_DIGITAL_CDC_DMIC3_CTL; + dmic_clk_en_mask = WCD939X_CDC_DMIC3_CTL_DMIC_CLK_EN; + dmic_clk_mask = WCD939X_CDC_DMIC_RATE_3_4_DMIC3_RATE; + dmic_ctl_mask = WCD939X_CDC_AMIC_CTL_AMIC4_IN_SEL; + break; + case 6: + case 7: + dmic_clk_reg = WCD939X_DIGITAL_CDC_DMIC_RATE_3_4; + dmic_clk_en_reg = WCD939X_DIGITAL_CDC_DMIC4_CTL; + dmic_clk_en_mask = WCD939X_CDC_DMIC4_CTL_DMIC_CLK_EN; + dmic_clk_mask = WCD939X_CDC_DMIC_RATE_3_4_DMIC4_RATE; + dmic_ctl_mask = WCD939X_CDC_AMIC_CTL_AMIC5_IN_SEL; + break; + default: + dev_err(component->dev, "%s: Invalid DMIC Selection\n", __func__); + return -EINVAL; + }; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_AMIC_CTL, + dmic_ctl_mask, false); + /* 250us sleep as per HW requirement */ + usleep_range(250, 260); + if (w->shift == 2) + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_DMIC2_CTL, + WCD939X_CDC_DMIC2_CTL_DMIC_LEFT_EN, + true); + /* Setting DMIC clock rate to 2.4MHz */ + snd_soc_component_write_field(component, dmic_clk_reg, + dmic_clk_mask, 3); + snd_soc_component_write_field(component, dmic_clk_en_reg, + dmic_clk_en_mask, true); + /* enable clock scaling */ + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DMIC_CTL, + WCD939X_CDC_DMIC_CTL_CLK_SCALE_EN, true); + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DMIC_CTL, + WCD939X_CDC_DMIC_CTL_DMIC_DIV_BAK_EN, true); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_AMIC_CTL, + dmic_ctl_mask, 1); + if (w->shift == 2) + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_DMIC2_CTL, + WCD939X_CDC_DMIC2_CTL_DMIC_LEFT_EN, + false); + snd_soc_component_write_field(component, dmic_clk_en_reg, + dmic_clk_en_mask, 0); + break; + } + return 0; +} + +static int wcd939x_tx_swr_ctrl(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + int bank; + int rate; + + bank = wcd939x_swr_get_current_bank(wcd939x->sdw_priv[AIF1_CAP]->sdev); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (strnstr(w->name, "ADC", sizeof("ADC"))) { + int mode = 0; + + if (test_bit(WCD_ADC1, &wcd939x->status_mask)) + mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC1]]; + if (test_bit(WCD_ADC2, &wcd939x->status_mask)) + mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC2]]; + if (test_bit(WCD_ADC3, &wcd939x->status_mask)) + mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC3]]; + if (test_bit(WCD_ADC4, &wcd939x->status_mask)) + mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC4]]; + + if (mode) + rate = wcd939x_get_clk_rate(ffs(mode) - 1); + else + rate = wcd939x_get_clk_rate(ADC_MODE_INVALID); + wcd939x_set_swr_clk_rate(component, rate, bank); + wcd939x_set_swr_clk_rate(component, rate, !bank); + } + break; + case SND_SOC_DAPM_POST_PMD: + if (strnstr(w->name, "ADC", sizeof("ADC"))) { + rate = wcd939x_get_clk_rate(ADC_MODE_INVALID); + wcd939x_set_swr_clk_rate(component, rate, !bank); + wcd939x_set_swr_clk_rate(component, rate, bank); + } + break; + } + + return 0; +} + +static int wcd939x_get_adc_mode(int val) +{ + int ret = 0; + + switch (val) { + case ADC_MODE_INVALID: + ret = ADC_MODE_VAL_NORMAL; + break; + case ADC_MODE_HIFI: + ret = ADC_MODE_VAL_HIFI; + break; + case ADC_MODE_LO_HIF: + ret = ADC_MODE_VAL_LO_HIF; + break; + case ADC_MODE_NORMAL: + ret = ADC_MODE_VAL_NORMAL; + break; + case ADC_MODE_LP: + ret = ADC_MODE_VAL_LP; + break; + case ADC_MODE_ULP1: + ret = ADC_MODE_VAL_ULP1; + break; + case ADC_MODE_ULP2: + ret = ADC_MODE_VAL_ULP2; + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int wcd939x_codec_enable_adc(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, + WCD939X_CDC_ANA_CLK_CTL_ANA_TX_CLK_EN, true); + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, + WCD939X_CDC_ANA_CLK_CTL_ANA_TX_DIV2_CLK_EN, + true); + set_bit(w->shift, &wcd939x->status_mask); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, + WCD939X_CDC_ANA_CLK_CTL_ANA_TX_DIV2_CLK_EN, + false); + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, + WCD939X_CDC_ANA_CLK_CTL_ANA_TX_CLK_EN, + false); + clear_bit(w->shift, &wcd939x->status_mask); + break; + } + + return 0; +} + +static void wcd939x_tx_channel_config(struct snd_soc_component *component, + int channel, bool init) +{ + int reg, mask; + + switch (channel) { + case 0: + reg = WCD939X_ANA_TX_CH2; + mask = WCD939X_TX_CH2_HPF1_INIT; + break; + case 1: + reg = WCD939X_ANA_TX_CH2; + mask = WCD939X_TX_CH2_HPF2_INIT; + break; + case 2: + reg = WCD939X_ANA_TX_CH4; + mask = WCD939X_TX_CH4_HPF3_INIT; + break; + case 3: + reg = WCD939X_ANA_TX_CH4; + mask = WCD939X_TX_CH4_HPF4_INIT; + break; + default: + return; + } + + snd_soc_component_write_field(component, reg, mask, init); +} + +static int wcd939x_adc_enable_req(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + int mode; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_REQ_CTL, + WCD939X_CDC_REQ_CTL_FS_RATE_4P8, true); + snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_REQ_CTL, + WCD939X_CDC_REQ_CTL_NO_NOTCH, false); + + wcd939x_tx_channel_config(component, w->shift, true); + mode = wcd939x_get_adc_mode(wcd939x->tx_mode[w->shift]); + if (mode < 0) { + dev_info(component->dev, "Invalid ADC mode\n"); + return -EINVAL; + } + + switch (w->shift) { + case 0: + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_TX_ANA_MODE_0_1, + WCD939X_CDC_TX_ANA_MODE_0_1_TXD0_MODE, + mode); + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_DIG_CLK_CTL, + WCD939X_CDC_DIG_CLK_CTL_TXD0_CLK_EN, + true); + break; + case 1: + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_TX_ANA_MODE_0_1, + WCD939X_CDC_TX_ANA_MODE_0_1_TXD1_MODE, + mode); + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_DIG_CLK_CTL, + WCD939X_CDC_DIG_CLK_CTL_TXD1_CLK_EN, + true); + break; + case 2: + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_TX_ANA_MODE_2_3, + WCD939X_CDC_TX_ANA_MODE_2_3_TXD2_MODE, + mode); + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_DIG_CLK_CTL, + WCD939X_CDC_DIG_CLK_CTL_TXD2_CLK_EN, + true); + break; + case 3: + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_TX_ANA_MODE_2_3, + WCD939X_CDC_TX_ANA_MODE_2_3_TXD3_MODE, + mode); + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_DIG_CLK_CTL, + WCD939X_CDC_DIG_CLK_CTL_TXD3_CLK_EN, + true); + break; + default: + break; + } + + wcd939x_tx_channel_config(component, w->shift, false); + break; + case SND_SOC_DAPM_POST_PMD: + switch (w->shift) { + case 0: + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_TX_ANA_MODE_0_1, + WCD939X_CDC_TX_ANA_MODE_0_1_TXD0_MODE, + false); + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_DIG_CLK_CTL, + WCD939X_CDC_DIG_CLK_CTL_TXD0_CLK_EN, + false); + break; + case 1: + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_TX_ANA_MODE_0_1, + WCD939X_CDC_TX_ANA_MODE_0_1_TXD1_MODE, + false); + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_DIG_CLK_CTL, + WCD939X_CDC_DIG_CLK_CTL_TXD1_CLK_EN, + false); + break; + case 2: + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_TX_ANA_MODE_2_3, + WCD939X_CDC_TX_ANA_MODE_2_3_TXD2_MODE, + false); + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_DIG_CLK_CTL, + WCD939X_CDC_DIG_CLK_CTL_TXD2_CLK_EN, + false); + break; + case 3: + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_TX_ANA_MODE_2_3, + WCD939X_CDC_TX_ANA_MODE_2_3_TXD3_MODE, + false); + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_DIG_CLK_CTL, + WCD939X_CDC_DIG_CLK_CTL_TXD3_CLK_EN, + false); + break; + default: + break; + } + break; + } + + return 0; +} + +static int wcd939x_micbias_control(struct snd_soc_component *component, + int micb_num, int req, bool is_dapm) +{ + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + int micb_index = micb_num - 1; + u16 micb_field; + u16 micb_reg; + + switch (micb_num) { + case MIC_BIAS_1: + micb_reg = WCD939X_ANA_MICB1; + micb_field = WCD939X_MICB1_ENABLE; + break; + case MIC_BIAS_2: + micb_reg = WCD939X_ANA_MICB2; + micb_field = WCD939X_MICB2_ENABLE; + break; + case MIC_BIAS_3: + micb_reg = WCD939X_ANA_MICB3; + micb_field = WCD939X_MICB3_ENABLE; + break; + case MIC_BIAS_4: + micb_reg = WCD939X_ANA_MICB4; + micb_field = WCD939X_MICB4_ENABLE; + break; + default: + dev_err(component->dev, "%s: Invalid micbias number: %d\n", + __func__, micb_num); + return -EINVAL; + }; + + switch (req) { + case MICB_PULLUP_ENABLE: + wcd939x->pullup_ref[micb_index]++; + if (wcd939x->pullup_ref[micb_index] == 1 && + wcd939x->micb_ref[micb_index] == 0) + snd_soc_component_write_field(component, micb_reg, + micb_field, MICB_BIAS_PULL_UP); + break; + case MICB_PULLUP_DISABLE: + if (wcd939x->pullup_ref[micb_index] > 0) + wcd939x->pullup_ref[micb_index]--; + if (wcd939x->pullup_ref[micb_index] == 0 && + wcd939x->micb_ref[micb_index] == 0) + snd_soc_component_write_field(component, micb_reg, + micb_field, MICB_BIAS_DISABLE); + break; + case MICB_ENABLE: + wcd939x->micb_ref[micb_index]++; + if (wcd939x->micb_ref[micb_index] == 1) { + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_DIG_CLK_CTL, + WCD939X_CDC_DIG_CLK_CTL_TXD3_CLK_EN, true); + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_DIG_CLK_CTL, + WCD939X_CDC_DIG_CLK_CTL_TXD2_CLK_EN, true); + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_DIG_CLK_CTL, + WCD939X_CDC_DIG_CLK_CTL_TXD1_CLK_EN, true); + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_DIG_CLK_CTL, + WCD939X_CDC_DIG_CLK_CTL_TXD0_CLK_EN, true); + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_ANA_CLK_CTL, + WCD939X_CDC_ANA_CLK_CTL_ANA_TX_DIV2_CLK_EN, + true); + snd_soc_component_write_field(component, + WCD939X_DIGITAL_CDC_ANA_TX_CLK_CTL, + WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TXSCBIAS_CLK_EN, + true); + snd_soc_component_write_field(component, + WCD939X_MICB1_TEST_CTL_2, + WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER, true); + snd_soc_component_write_field(component, + WCD939X_MICB2_TEST_CTL_2, + WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER, true); + snd_soc_component_write_field(component, + WCD939X_MICB3_TEST_CTL_2, + WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER, true); + snd_soc_component_write_field(component, + WCD939X_MICB4_TEST_CTL_2, + WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER, true); + snd_soc_component_write_field(component, micb_reg, micb_field, + MICB_BIAS_ENABLE); + if (micb_num == MIC_BIAS_2) + wcd_mbhc_event_notify(wcd939x->wcd_mbhc, + WCD_EVENT_POST_MICBIAS_2_ON); + } + if (micb_num == MIC_BIAS_2 && is_dapm) + wcd_mbhc_event_notify(wcd939x->wcd_mbhc, + WCD_EVENT_POST_DAPM_MICBIAS_2_ON); + break; + case MICB_DISABLE: + if (wcd939x->micb_ref[micb_index] > 0) + wcd939x->micb_ref[micb_index]--; + + if (wcd939x->micb_ref[micb_index] == 0 && + wcd939x->pullup_ref[micb_index] > 0) + snd_soc_component_write_field(component, micb_reg, + micb_field, MICB_BIAS_PULL_UP); + else if (wcd939x->micb_ref[micb_index] == 0 && + wcd939x->pullup_ref[micb_index] == 0) { + if (micb_num == MIC_BIAS_2) + wcd_mbhc_event_notify(wcd939x->wcd_mbhc, + WCD_EVENT_PRE_MICBIAS_2_OFF); + + snd_soc_component_write_field(component, micb_reg, + micb_field, MICB_BIAS_DISABLE); + if (micb_num == MIC_BIAS_2) + wcd_mbhc_event_notify(wcd939x->wcd_mbhc, + WCD_EVENT_POST_MICBIAS_2_OFF); + } + if (is_dapm && micb_num == MIC_BIAS_2) + wcd_mbhc_event_notify(wcd939x->wcd_mbhc, + WCD_EVENT_POST_DAPM_MICBIAS_2_OFF); + break; + } + + return 0; +} + +static int wcd939x_codec_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + int micb_num = w->shift; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd939x_micbias_control(component, micb_num, MICB_ENABLE, true); + break; + case SND_SOC_DAPM_POST_PMU: + /* 1 msec delay as per HW requirement */ + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + wcd939x_micbias_control(component, micb_num, MICB_DISABLE, true); + break; + } + + return 0; +} + +static int wcd939x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + int micb_num = w->shift; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd939x_micbias_control(component, micb_num, + MICB_PULLUP_ENABLE, true); + break; + case SND_SOC_DAPM_POST_PMU: + /* 1 msec delay as per HW requirement */ + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + wcd939x_micbias_control(component, micb_num, + MICB_PULLUP_DISABLE, true); + break; + } + + return 0; +} + +static int wcd939x_tx_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int path = e->shift_l; + + ucontrol->value.enumerated.item[0] = wcd939x->tx_mode[path]; + + return 0; +} + +static int wcd939x_tx_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int path = e->shift_l; + + if (wcd939x->tx_mode[path] == ucontrol->value.enumerated.item[0]) + return 0; + + wcd939x->tx_mode[path] = ucontrol->value.enumerated.item[0]; + + return 1; +} + +/* RX Controls */ + +static int wcd939x_rx_hph_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wcd939x->hph_mode; + + return 0; +} + +static int wcd939x_rx_hph_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + u32 mode_val; + + mode_val = ucontrol->value.enumerated.item[0]; + + if (mode_val == wcd939x->hph_mode) + return 0; + + if (wcd939x->variant == WCD9390) { + switch (mode_val) { + case CLS_H_NORMAL: + case CLS_H_LP: + case CLS_AB: + case CLS_H_LOHIFI: + case CLS_H_ULP: + case CLS_AB_LP: + case CLS_AB_LOHIFI: + wcd939x->hph_mode = mode_val; + return 1; + } + } else { + switch (mode_val) { + case CLS_H_NORMAL: + case CLS_H_HIFI: + case CLS_H_LP: + case CLS_AB: + case CLS_H_LOHIFI: + case CLS_H_ULP: + case CLS_AB_HIFI: + case CLS_AB_LP: + case CLS_AB_LOHIFI: + wcd939x->hph_mode = mode_val; + return 1; + } + } + + dev_dbg(component->dev, "%s: Invalid HPH Mode\n", __func__); + return -EINVAL; +} + +static int wcd939x_get_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = (struct soc_mixer_control *)(kcontrol->private_value); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + if (mc->shift) + ucontrol->value.integer.value[0] = wcd939x->comp2_enable ? 1 : 0; + else + ucontrol->value.integer.value[0] = wcd939x->comp1_enable ? 1 : 0; + + return 0; +} + +static int wcd939x_set_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = (struct soc_mixer_control *)(kcontrol->private_value); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[AIF1_PB]; + bool value = !!ucontrol->value.integer.value[0]; + int portidx = wcd->ch_info[mc->reg].port_num; + + if (mc->shift) + wcd939x->comp2_enable = value; + else + wcd939x->comp1_enable = value; + + if (value) + wcd939x_connect_port(wcd, portidx, mc->reg, true); + else + wcd939x_connect_port(wcd, portidx, mc->reg, false); + + return 1; +} + +static int wcd939x_ldoh_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wcd939x->ldoh ? 1 : 0; + + return 0; +} + +static int wcd939x_ldoh_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + if (wcd939x->ldoh == !!ucontrol->value.integer.value[0]) + return 0; + + wcd939x->ldoh = !!ucontrol->value.integer.value[0]; + + return 1; +} + +static const char * const tx_mode_mux_text_wcd9390[] = { + "ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP", +}; + +static const struct soc_enum tx0_mode_mux_enum_wcd9390 = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tx_mode_mux_text_wcd9390), + tx_mode_mux_text_wcd9390); + +static const struct soc_enum tx1_mode_mux_enum_wcd9390 = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 1, ARRAY_SIZE(tx_mode_mux_text_wcd9390), + tx_mode_mux_text_wcd9390); + +static const struct soc_enum tx2_mode_mux_enum_wcd9390 = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 2, ARRAY_SIZE(tx_mode_mux_text_wcd9390), + tx_mode_mux_text_wcd9390); + +static const struct soc_enum tx3_mode_mux_enum_wcd9390 = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 3, ARRAY_SIZE(tx_mode_mux_text_wcd9390), + tx_mode_mux_text_wcd9390); + +static const char * const tx_mode_mux_text[] = { + "ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP", + "ADC_ULP1", "ADC_ULP2", +}; + +static const struct soc_enum tx0_mode_mux_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tx_mode_mux_text), + tx_mode_mux_text); + +static const struct soc_enum tx1_mode_mux_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 1, ARRAY_SIZE(tx_mode_mux_text), + tx_mode_mux_text); + +static const struct soc_enum tx2_mode_mux_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 2, ARRAY_SIZE(tx_mode_mux_text), + tx_mode_mux_text); + +static const struct soc_enum tx3_mode_mux_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 3, ARRAY_SIZE(tx_mode_mux_text), + tx_mode_mux_text); + +static const char * const rx_hph_mode_mux_text_wcd9390[] = { + "CLS_H_NORMAL", "CLS_H_INVALID_1", "CLS_H_LP", "CLS_AB", + "CLS_H_LOHIFI", "CLS_H_ULP", "CLS_H_INVALID_2", "CLS_AB_LP", + "CLS_AB_LOHIFI", +}; + +static const struct soc_enum rx_hph_mode_mux_enum_wcd9390 = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text_wcd9390), + rx_hph_mode_mux_text_wcd9390); + +static const char * const rx_hph_mode_mux_text[] = { + "CLS_H_NORMAL", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB", "CLS_H_LOHIFI", + "CLS_H_ULP", "CLS_AB_HIFI", "CLS_AB_LP", "CLS_AB_LOHIFI", +}; + +static const struct soc_enum rx_hph_mode_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), + rx_hph_mode_mux_text); + +static const struct snd_kcontrol_new wcd9390_snd_controls[] = { + SOC_SINGLE_TLV("EAR_PA Volume", WCD939X_ANA_EAR_COMPANDER_CTL, + 2, 0x10, 0, ear_pa_gain), + + SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum_wcd9390, + wcd939x_rx_hph_mode_get, wcd939x_rx_hph_mode_put), + + SOC_ENUM_EXT("TX0 MODE", tx0_mode_mux_enum_wcd9390, + wcd939x_tx_mode_get, wcd939x_tx_mode_put), + SOC_ENUM_EXT("TX1 MODE", tx1_mode_mux_enum_wcd9390, + wcd939x_tx_mode_get, wcd939x_tx_mode_put), + SOC_ENUM_EXT("TX2 MODE", tx2_mode_mux_enum_wcd9390, + wcd939x_tx_mode_get, wcd939x_tx_mode_put), + SOC_ENUM_EXT("TX3 MODE", tx3_mode_mux_enum_wcd9390, + wcd939x_tx_mode_get, wcd939x_tx_mode_put), +}; + +static const struct snd_kcontrol_new wcd9395_snd_controls[] = { + SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum, + wcd939x_rx_hph_mode_get, wcd939x_rx_hph_mode_put), + + SOC_ENUM_EXT("TX0 MODE", tx0_mode_mux_enum, + wcd939x_tx_mode_get, wcd939x_tx_mode_put), + SOC_ENUM_EXT("TX1 MODE", tx1_mode_mux_enum, + wcd939x_tx_mode_get, wcd939x_tx_mode_put), + SOC_ENUM_EXT("TX2 MODE", tx2_mode_mux_enum, + wcd939x_tx_mode_get, wcd939x_tx_mode_put), + SOC_ENUM_EXT("TX3 MODE", tx3_mode_mux_enum, + wcd939x_tx_mode_get, wcd939x_tx_mode_put), +}; + +static const struct snd_kcontrol_new adc1_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new adc2_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new adc3_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new adc4_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic1_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic2_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic3_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic4_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic5_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic6_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic7_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic8_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new ear_rdac_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new hphl_rdac_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new hphr_rdac_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const char * const adc1_mux_text[] = { + "CH1_AMIC_DISABLE", "CH1_AMIC1", "CH1_AMIC2", "CH1_AMIC3", "CH1_AMIC4", "CH1_AMIC5" +}; + +static const struct soc_enum adc1_enum = + SOC_ENUM_SINGLE(WCD939X_TX_NEW_CH12_MUX, 0, + ARRAY_SIZE(adc1_mux_text), adc1_mux_text); + +static const struct snd_kcontrol_new tx_adc1_mux = + SOC_DAPM_ENUM("ADC1 MUX Mux", adc1_enum); + +static const char * const adc2_mux_text[] = { + "CH2_AMIC_DISABLE", "CH2_AMIC1", "CH2_AMIC2", "CH2_AMIC3", "CH2_AMIC4", "CH2_AMIC5" +}; + +static const struct soc_enum adc2_enum = + SOC_ENUM_SINGLE(WCD939X_TX_NEW_CH12_MUX, 3, + ARRAY_SIZE(adc2_mux_text), adc2_mux_text); + +static const struct snd_kcontrol_new tx_adc2_mux = + SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum); + +static const char * const adc3_mux_text[] = { + "CH3_AMIC_DISABLE", "CH3_AMIC1", "CH3_AMIC3", "CH3_AMIC4", "CH3_AMIC5" +}; + +static const struct soc_enum adc3_enum = + SOC_ENUM_SINGLE(WCD939X_TX_NEW_CH34_MUX, 0, + ARRAY_SIZE(adc3_mux_text), adc3_mux_text); + +static const struct snd_kcontrol_new tx_adc3_mux = + SOC_DAPM_ENUM("ADC3 MUX Mux", adc3_enum); + +static const char * const adc4_mux_text[] = { + "CH4_AMIC_DISABLE", "CH4_AMIC1", "CH4_AMIC3", "CH4_AMIC4", "CH4_AMIC5" +}; + +static const struct soc_enum adc4_enum = + SOC_ENUM_SINGLE(WCD939X_TX_NEW_CH34_MUX, 3, + ARRAY_SIZE(adc4_mux_text), adc4_mux_text); + +static const struct snd_kcontrol_new tx_adc4_mux = + SOC_DAPM_ENUM("ADC4 MUX Mux", adc4_enum); + +static const char * const rdac3_mux_text[] = { + "RX3", "RX1" +}; + +static const struct soc_enum rdac3_enum = + SOC_ENUM_SINGLE(WCD939X_DIGITAL_CDC_EAR_PATH_CTL, 0, + ARRAY_SIZE(rdac3_mux_text), rdac3_mux_text); + +static const struct snd_kcontrol_new rx_rdac3_mux = + SOC_DAPM_ENUM("RDAC3_MUX Mux", rdac3_enum); + +static int wcd939x_get_swr_port(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(comp); + struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[mixer->shift]; + unsigned int portidx = wcd->ch_info[mixer->reg].port_num; + + ucontrol->value.integer.value[0] = wcd->port_enable[portidx] ? 1 : 0; + + return 0; +} + +static const char *version_to_str(u32 version) +{ + switch (version) { + case WCD939X_VERSION_1_0: + return __stringify(WCD939X_1_0); + case WCD939X_VERSION_1_1: + return __stringify(WCD939X_1_1); + case WCD939X_VERSION_2_0: + return __stringify(WCD939X_2_0); + } + return NULL; +} + +static int wcd939x_set_swr_port(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(comp); + struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[mixer->shift]; + unsigned int portidx = wcd->ch_info[mixer->reg].port_num; + + wcd->port_enable[portidx] = !!ucontrol->value.integer.value[0]; + + wcd939x_connect_port(wcd, portidx, mixer->reg, wcd->port_enable[portidx]); + + return 1; +} + +/* MBHC Related */ + +static void wcd939x_mbhc_clk_setup(struct snd_soc_component *component, + bool enable) +{ + snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_1, + WCD939X_CTL_1_RCO_EN, enable); +} + +static void wcd939x_mbhc_mbhc_bias_control(struct snd_soc_component *component, + bool enable) +{ + snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ELECT, + WCD939X_MBHC_ELECT_BIAS_EN, enable); +} + +static void wcd939x_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; + snd_soc_component_write_field(component, WCD939X_ANA_MBHC_BTN0 + i, + WCD939X_MBHC_BTN0_VTH, vth); + dev_dbg(component->dev, "%s: btn_high[%d]: %d, vth: %d\n", + __func__, i, btn_high[i], vth); + } +} + +static bool wcd939x_mbhc_micb_en_status(struct snd_soc_component *component, int micb_num) +{ + + if (micb_num == MIC_BIAS_2) { + u8 val; + + val = FIELD_GET(WCD939X_MICB2_ENABLE, + snd_soc_component_read(component, WCD939X_ANA_MICB2)); + if (val == MICB_BIAS_ENABLE) + return true; + } + + return false; +} + +static void wcd939x_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_DEFAULT) + pull_up_cur = HS_PULLUP_I_2P0_UA; + + dev_dbg(component->dev, "%s: HS pull up current:%d\n", + __func__, pull_up_cur); + + snd_soc_component_write_field(component, WCD939X_MBHC_NEW_INT_MECH_DET_CURRENT, + WCD939X_MECH_DET_CURRENT_HSDET_PULLUP_CTL, pull_up_cur); +} + +static int wcd939x_mbhc_request_micbias(struct snd_soc_component *component, + int micb_num, int req) +{ + return wcd939x_micbias_control(component, micb_num, req, false); +} + +static void wcd939x_mbhc_micb_ramp_control(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_write_field(component, WCD939X_ANA_MICB2_RAMP, + WCD939X_MICB2_RAMP_SHIFT_CTL, 3); + snd_soc_component_write_field(component, WCD939X_ANA_MICB2_RAMP, + WCD939X_MICB2_RAMP_RAMP_ENABLE, true); + } else { + snd_soc_component_write_field(component, WCD939X_ANA_MICB2_RAMP, + WCD939X_MICB2_RAMP_RAMP_ENABLE, false); + snd_soc_component_write_field(component, WCD939X_ANA_MICB2_RAMP, + WCD939X_MICB2_RAMP_SHIFT_CTL, 0); + } +} + +static int wcd939x_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) { + pr_err("%s: unsupported micbias voltage\n", __func__); + return -EINVAL; + } + + return (micb_mv - 1000) / 50; +} + +static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, + int req_volt, int micb_num) +{ + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + unsigned int micb_en_field, micb_vout_ctl_field; + unsigned int micb_reg, cur_vout_ctl, micb_en; + int req_vout_ctl; + int ret = 0; + + switch (micb_num) { + case MIC_BIAS_1: + micb_reg = WCD939X_ANA_MICB1; + micb_en_field = WCD939X_MICB1_ENABLE; + micb_vout_ctl_field = WCD939X_MICB1_VOUT_CTL; + break; + case MIC_BIAS_2: + micb_reg = WCD939X_ANA_MICB2; + micb_en_field = WCD939X_MICB2_ENABLE; + micb_vout_ctl_field = WCD939X_MICB2_VOUT_CTL; + break; + case MIC_BIAS_3: + micb_reg = WCD939X_ANA_MICB3; + micb_en_field = WCD939X_MICB3_ENABLE; + micb_vout_ctl_field = WCD939X_MICB1_VOUT_CTL; + break; + case MIC_BIAS_4: + micb_reg = WCD939X_ANA_MICB4; + micb_en_field = WCD939X_MICB4_ENABLE; + micb_vout_ctl_field = WCD939X_MICB2_VOUT_CTL; + break; + default: + return -EINVAL; + } + mutex_lock(&wcd939x->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, + micb_en_field); + cur_vout_ctl = snd_soc_component_read_field(component, micb_reg, + micb_vout_ctl_field); + + req_vout_ctl = wcd939x_get_micb_vout_ctl_val(req_volt); + if (req_vout_ctl < 0) { + ret = req_vout_ctl; + goto exit; + } + + if (cur_vout_ctl == req_vout_ctl) { + ret = 0; + goto exit; + } + + dev_dbg(component->dev, "%s: micb_num: %d, cur_mv: %d, req_mv: %d, micb_en: %d\n", + __func__, micb_num, WCD_VOUT_CTL_TO_MICB(cur_vout_ctl), + req_volt, micb_en); + + if (micb_en == MICB_BIAS_ENABLE) + snd_soc_component_write_field(component, micb_reg, + micb_en_field, MICB_BIAS_PULL_DOWN); + + snd_soc_component_write_field(component, micb_reg, + micb_vout_ctl_field, req_vout_ctl); + + if (micb_en == MICB_BIAS_ENABLE) { + snd_soc_component_write_field(component, micb_reg, + micb_en_field, MICB_BIAS_ENABLE); + /* + * Add 2ms delay as per HW requirement after enabling + * micbias + */ + usleep_range(2000, 2100); + } + +exit: + mutex_unlock(&wcd939x->micb_lock); + return ret; +} + +static int wcd939x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component, + int micb_num, bool req_en) +{ + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + int 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 (wcd939x->micb2_mv >= WCD_MBHC_THR_HS_MICB_MV) + return 0; + + micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : wcd939x->micb2_mv; + + return wcd939x_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2); +} + +/* Selected by WCD939X_MBHC_GET_C1() */ +static const s16 wcd939x_wcd_mbhc_d1_a[4] = { + 0, 30, 30, 6 +}; + +/* Selected by zdet_param.noff */ +static const int wcd939x_mbhc_mincode_param[] = { + 3277, 1639, 820, 410, 205, 103, 52, 26 +}; + +static const struct zdet_param wcd939x_mbhc_zdet_param = { + .ldo_ctl = 4, + .noff = 0, + .nshift = 6, + .btn5 = 0x18, + .btn6 = 0x60, + .btn7 = 0x78, +}; + +static void wcd939x_mbhc_get_result_params(struct snd_soc_component *component, + int32_t *zdet) +{ + const struct zdet_param *zdet_param = &wcd939x_mbhc_zdet_param; + s32 x1, d1, denom; + int val; + s16 c1; + int i; + + snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET, + WCD939X_MBHC_ZDET_ZDET_CHG_EN, true); + for (i = 0; i < WCD939X_ZDET_NUM_MEASUREMENTS; i++) { + val = snd_soc_component_read_field(component, WCD939X_ANA_MBHC_RESULT_2, + WCD939X_MBHC_RESULT_2_Z_RESULT_MSB); + if (val & BIT(7)) + break; + } + val = val << 8; + val |= snd_soc_component_read_field(component, WCD939X_ANA_MBHC_RESULT_1, + WCD939X_MBHC_RESULT_1_Z_RESULT_LSB); + snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET, + WCD939X_MBHC_ZDET_ZDET_CHG_EN, false); + x1 = WCD939X_MBHC_GET_X1(val); + c1 = WCD939X_MBHC_GET_C1(val); + + /* If ramp is not complete, give additional 5ms */ + if (c1 < 2 && x1) + mdelay(5); + + if (!c1 || !x1) { + dev_dbg(component->dev, + "%s: Impedance detect ramp error, c1=%d, x1=0x%x\n", + __func__, c1, x1); + goto ramp_down; + } + + d1 = wcd939x_wcd_mbhc_d1_a[c1]; + denom = (x1 * d1) - (1 << (14 - zdet_param->noff)); + if (denom > 0) + *zdet = (WCD939X_ANA_MBHC_ZDET_CONST * 1000) / denom; + else if (x1 < wcd939x_mbhc_mincode_param[zdet_param->noff]) + *zdet = WCD939X_ZDET_FLOATING_IMPEDANCE; + + dev_dbg(component->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d(milliOhm)\n", + __func__, d1, c1, x1, *zdet); +ramp_down: + i = 0; + while (x1) { + val = snd_soc_component_read_field(component, WCD939X_ANA_MBHC_RESULT_1, + WCD939X_MBHC_RESULT_1_Z_RESULT_LSB) << 8; + val |= snd_soc_component_read_field(component, WCD939X_ANA_MBHC_RESULT_2, + WCD939X_MBHC_RESULT_2_Z_RESULT_MSB); + x1 = WCD939X_MBHC_GET_X1(val); + i++; + if (i == WCD939X_ZDET_NUM_MEASUREMENTS) + break; + } +} + +static void wcd939x_mbhc_zdet_ramp(struct snd_soc_component *component, + s32 *zl, int32_t *zr) +{ + const struct zdet_param *zdet_param = &wcd939x_mbhc_zdet_param; + s32 zdet = 0; + + snd_soc_component_write_field(component, WCD939X_MBHC_NEW_ZDET_ANA_CTL, + WCD939X_ZDET_ANA_CTL_MAXV_CTL, zdet_param->ldo_ctl); + snd_soc_component_update_bits(component, WCD939X_ANA_MBHC_BTN5, WCD939X_MBHC_BTN5_VTH, + zdet_param->btn5); + snd_soc_component_update_bits(component, WCD939X_ANA_MBHC_BTN6, WCD939X_MBHC_BTN6_VTH, + zdet_param->btn6); + snd_soc_component_update_bits(component, WCD939X_ANA_MBHC_BTN7, WCD939X_MBHC_BTN7_VTH, + zdet_param->btn7); + snd_soc_component_write_field(component, WCD939X_MBHC_NEW_ZDET_ANA_CTL, + WCD939X_ZDET_ANA_CTL_RANGE_CTL, zdet_param->noff); + snd_soc_component_write_field(component, WCD939X_MBHC_NEW_ZDET_RAMP_CTL, + WCD939X_ZDET_RAMP_CTL_TIME_CTL, zdet_param->nshift); + snd_soc_component_write_field(component, WCD939X_MBHC_NEW_ZDET_RAMP_CTL, + WCD939X_ZDET_RAMP_CTL_ACC1_MIN_CTL, 6); /*acc1_min_63 */ + + if (!zl) + goto z_right; + + /* Start impedance measurement for HPH_L */ + snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET, + WCD939X_MBHC_ZDET_ZDET_L_MEAS_EN, true); + dev_dbg(component->dev, "%s: ramp for HPH_L, noff = %d\n", + __func__, zdet_param->noff); + wcd939x_mbhc_get_result_params(component, &zdet); + snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET, + WCD939X_MBHC_ZDET_ZDET_L_MEAS_EN, false); + + *zl = zdet; + +z_right: + if (!zr) + return; + + /* Start impedance measurement for HPH_R */ + snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET, + WCD939X_MBHC_ZDET_ZDET_R_MEAS_EN, true); + dev_dbg(component->dev, "%s: ramp for HPH_R, noff = %d\n", + __func__, zdet_param->noff); + wcd939x_mbhc_get_result_params(component, &zdet); + snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET, + WCD939X_MBHC_ZDET_ZDET_R_MEAS_EN, false); + + *zr = zdet; +} + +static void wcd939x_wcd_mbhc_qfuse_cal(struct snd_soc_component *component, + s32 *z_val, int flag_l_r) +{ + int q1_cal; + s16 q1; + + q1 = snd_soc_component_read(component, WCD939X_DIGITAL_EFUSE_REG_21 + flag_l_r); + if (q1 & BIT(7)) + q1_cal = (10000 - ((q1 & GENMASK(6, 0)) * 10)); + else + q1_cal = (10000 + (q1 * 10)); + + if (q1_cal > 0) + *z_val = ((*z_val) * 10000) / q1_cal; +} + +static void wcd939x_wcd_mbhc_calc_impedance(struct snd_soc_component *component, + u32 *zl, uint32_t *zr) +{ + struct wcd939x_priv *wcd939x = dev_get_drvdata(component->dev); + unsigned int reg0, reg1, reg2, reg3, reg4; + int z_mono, z_diff1, z_diff2; + bool is_fsm_disable = false; + s32 z1l, z1r, z1ls; + + reg0 = snd_soc_component_read(component, WCD939X_ANA_MBHC_BTN5); + reg1 = snd_soc_component_read(component, WCD939X_ANA_MBHC_BTN6); + reg2 = snd_soc_component_read(component, WCD939X_ANA_MBHC_BTN7); + reg3 = snd_soc_component_read(component, WCD939X_MBHC_CTL_CLK); + reg4 = snd_soc_component_read(component, WCD939X_MBHC_NEW_ZDET_ANA_CTL); + + if (snd_soc_component_read_field(component, WCD939X_ANA_MBHC_ELECT, + WCD939X_MBHC_ELECT_FSM_EN)) { + snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ELECT, + WCD939X_MBHC_ELECT_FSM_EN, false); + is_fsm_disable = true; + } + + /* For NO-jack, disable L_DET_EN before Z-det measurements */ + if (wcd939x->mbhc_cfg.hphl_swh) + snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, + WCD939X_MBHC_MECH_L_DET_EN, false); + + /* Turn off 100k pull down on HPHL */ + snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, + WCD939X_MBHC_MECH_SW_HPH_L_P_100K_TO_GND, + false); + + /* + * Disable surge protection before impedance detection. + * This is done to give correct value for high impedance. + */ + snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN, + WCD939X_EN_EN_SURGE_PROTECTION_HPHR, false); + snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN, + WCD939X_EN_EN_SURGE_PROTECTION_HPHL, false); + + /* 1ms delay needed after disable surge protection */ + usleep_range(1000, 1010); + + /* First get impedance on Left */ + wcd939x_mbhc_zdet_ramp(component, &z1l, NULL); + if (z1l == WCD939X_ZDET_FLOATING_IMPEDANCE || z1l > WCD939X_ZDET_VAL_100K) { + *zl = WCD939X_ZDET_FLOATING_IMPEDANCE; + } else { + *zl = z1l / 1000; + wcd939x_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 */ + wcd939x_mbhc_zdet_ramp(component, NULL, &z1r); + if (z1r == WCD939X_ZDET_FLOATING_IMPEDANCE || z1r > WCD939X_ZDET_VAL_100K) { + *zr = WCD939X_ZDET_FLOATING_IMPEDANCE; + } else { + *zr = z1r / 1000; + wcd939x_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 == WCD939X_ZDET_FLOATING_IMPEDANCE && + *zr == WCD939X_ZDET_FLOATING_IMPEDANCE) { + dev_dbg(component->dev, + "%s: plug type is invalid or extension cable\n", + __func__); + goto zdet_complete; + } + + if (*zl == WCD939X_ZDET_FLOATING_IMPEDANCE || + *zr == WCD939X_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(wcd939x->wcd_mbhc, WCD_MBHC_HPH_MONO); + goto zdet_complete; + } + + snd_soc_component_write_field(component, WCD939X_HPH_R_ATEST, + WCD939X_R_ATEST_HPH_GND_OVR, true); + snd_soc_component_write_field(component, WCD939X_HPH_PA_CTL2, + WCD939X_PA_CTL2_HPHPA_GND_R, true); + wcd939x_mbhc_zdet_ramp(component, &z1ls, NULL); + snd_soc_component_write_field(component, WCD939X_HPH_PA_CTL2, + WCD939X_PA_CTL2_HPHPA_GND_R, false); + snd_soc_component_write_field(component, WCD939X_HPH_R_ATEST, + WCD939X_R_ATEST_HPH_GND_OVR, false); + + z1ls /= 1000; + wcd939x_wcd_mbhc_qfuse_cal(component, &z1ls, 0); + + /* Parallel of left Z and 9 ohm pull down resistor */ + z_mono = (*zl * 9) / (*zl + 9); + z_diff1 = z1ls > z_mono ? z1ls - z_mono : z_mono - z1ls; + z_diff2 = *zl > z1ls ? *zl - z1ls : z1ls - *zl; + if ((z_diff1 * (*zl + z1ls)) > (z_diff2 * (z1ls + z_mono))) { + dev_dbg(component->dev, "%s: stereo plug type detected\n", + __func__); + wcd_mbhc_set_hph_type(wcd939x->wcd_mbhc, WCD_MBHC_HPH_STEREO); + } else { + dev_dbg(component->dev, "%s: MONO plug type detected\n", + __func__); + wcd_mbhc_set_hph_type(wcd939x->wcd_mbhc, WCD_MBHC_HPH_MONO); + } + + /* Enable surge protection again after impedance detection */ + snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN, + WCD939X_EN_EN_SURGE_PROTECTION_HPHR, true); + snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN, + WCD939X_EN_EN_SURGE_PROTECTION_HPHL, true); + +zdet_complete: + snd_soc_component_write(component, WCD939X_ANA_MBHC_BTN5, reg0); + snd_soc_component_write(component, WCD939X_ANA_MBHC_BTN6, reg1); + snd_soc_component_write(component, WCD939X_ANA_MBHC_BTN7, reg2); + + /* Turn on 100k pull down on HPHL */ + snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, + WCD939X_MBHC_MECH_SW_HPH_L_P_100K_TO_GND, true); + + /* For NO-jack, re-enable L_DET_EN after Z-det measurements */ + if (wcd939x->mbhc_cfg.hphl_swh) + snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, + WCD939X_MBHC_MECH_L_DET_EN, true); + + snd_soc_component_write(component, WCD939X_MBHC_NEW_ZDET_ANA_CTL, reg4); + snd_soc_component_write(component, WCD939X_MBHC_CTL_CLK, reg3); + + if (is_fsm_disable) + snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ELECT, + WCD939X_MBHC_ELECT_FSM_EN, true); +} + +static void wcd939x_mbhc_gnd_det_ctrl(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, + WCD939X_MBHC_MECH_MECH_HS_G_PULLUP_COMP_EN, + true); + snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, + WCD939X_MBHC_MECH_GND_DET_EN, true); + } else { + snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, + WCD939X_MBHC_MECH_GND_DET_EN, false); + snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, + WCD939X_MBHC_MECH_MECH_HS_G_PULLUP_COMP_EN, + false); + } +} + +static void wcd939x_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component, + bool enable) +{ + snd_soc_component_write_field(component, WCD939X_HPH_PA_CTL2, + WCD939X_PA_CTL2_HPHPA_GND_R, enable); + snd_soc_component_write_field(component, WCD939X_HPH_PA_CTL2, + WCD939X_PA_CTL2_HPHPA_GND_L, enable); +} + +static void wcd939x_mbhc_moisture_config(struct snd_soc_component *component) +{ + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + if (wcd939x->mbhc_cfg.moist_rref == R_OFF || wcd939x->typec_analog_mux) { + snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2, + WCD939X_CTL_2_M_RTH_CTL, R_OFF); + return; + } + + /* Do not enable moisture detection if jack type is NC */ + if (!wcd939x->mbhc_cfg.hphl_swh) { + dev_dbg(component->dev, "%s: disable moisture detection for NC\n", + __func__); + snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2, + WCD939X_CTL_2_M_RTH_CTL, R_OFF); + return; + } + + snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2, + WCD939X_CTL_2_M_RTH_CTL, wcd939x->mbhc_cfg.moist_rref); +} + +static void wcd939x_mbhc_moisture_detect_en(struct snd_soc_component *component, bool enable) +{ + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + if (enable) + snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2, + WCD939X_CTL_2_M_RTH_CTL, + wcd939x->mbhc_cfg.moist_rref); + else + snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2, + WCD939X_CTL_2_M_RTH_CTL, R_OFF); +} + +static bool wcd939x_mbhc_get_moisture_status(struct snd_soc_component *component) +{ + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + bool ret = false; + + if (wcd939x->mbhc_cfg.moist_rref == R_OFF || wcd939x->typec_analog_mux) { + snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2, + WCD939X_CTL_2_M_RTH_CTL, R_OFF); + goto done; + } + + /* Do not enable moisture detection if jack type is NC */ + if (!wcd939x->mbhc_cfg.hphl_swh) { + dev_dbg(component->dev, "%s: disable moisture detection for NC\n", + __func__); + snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2, + WCD939X_CTL_2_M_RTH_CTL, R_OFF); + goto done; + } + + /* + * If moisture_en is already enabled, then skip to plug type + * detection. + */ + if (snd_soc_component_read_field(component, WCD939X_MBHC_NEW_CTL_2, + WCD939X_CTL_2_M_RTH_CTL)) + goto done; + + wcd939x_mbhc_moisture_detect_en(component, true); + + /* Read moisture comparator status, invert of status bit */ + ret = !snd_soc_component_read_field(component, WCD939X_MBHC_NEW_FSM_STATUS, + WCD939X_FSM_STATUS_HS_M_COMP_STATUS); +done: + return ret; +} + +static void wcd939x_mbhc_moisture_polling_ctrl(struct snd_soc_component *component, + bool enable) +{ + snd_soc_component_write_field(component, + WCD939X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL, + WCD939X_MOISTURE_DET_POLLING_CTRL_MOIST_EN_POLLING, + enable); +} + +static const struct wcd_mbhc_cb mbhc_cb = { + .clk_setup = wcd939x_mbhc_clk_setup, + .mbhc_bias = wcd939x_mbhc_mbhc_bias_control, + .set_btn_thr = wcd939x_mbhc_program_btn_thr, + .micbias_enable_status = wcd939x_mbhc_micb_en_status, + .hph_pull_up_control_v2 = wcd939x_mbhc_hph_l_pull_up_control, + .mbhc_micbias_control = wcd939x_mbhc_request_micbias, + .mbhc_micb_ramp_control = wcd939x_mbhc_micb_ramp_control, + .mbhc_micb_ctrl_thr_mic = wcd939x_mbhc_micb_ctrl_threshold_mic, + .compute_impedance = wcd939x_wcd_mbhc_calc_impedance, + .mbhc_gnd_det_ctrl = wcd939x_mbhc_gnd_det_ctrl, + .hph_pull_down_ctrl = wcd939x_mbhc_hph_pull_down_ctrl, + .mbhc_moisture_config = wcd939x_mbhc_moisture_config, + .mbhc_get_moisture_status = wcd939x_mbhc_get_moisture_status, + .mbhc_moisture_polling_ctrl = wcd939x_mbhc_moisture_polling_ctrl, + .mbhc_moisture_detect_en = wcd939x_mbhc_moisture_detect_en, +}; + +static int wcd939x_get_hph_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wcd_mbhc_get_hph_type(wcd939x->wcd_mbhc); + + return 0; +} + +static int wcd939x_hph_impedance_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = (struct soc_mixer_control *)(kcontrol->private_value); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + bool hphr = mc->shift; + u32 zl, zr; + + wcd_mbhc_get_impedance(wcd939x->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, + wcd939x_get_hph_type, NULL), +}; + +static const struct snd_kcontrol_new impedance_detect_controls[] = { + SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0, + wcd939x_hph_impedance_get, NULL), + SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0, + wcd939x_hph_impedance_get, NULL), +}; + +static int wcd939x_mbhc_init(struct snd_soc_component *component) +{ + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + struct wcd_mbhc_intr *intr_ids = &wcd939x->intr_ids; + + intr_ids->mbhc_sw_intr = regmap_irq_get_virq(wcd939x->irq_chip, + WCD939X_IRQ_MBHC_SW_DET); + intr_ids->mbhc_btn_press_intr = regmap_irq_get_virq(wcd939x->irq_chip, + WCD939X_IRQ_MBHC_BUTTON_PRESS_DET); + intr_ids->mbhc_btn_release_intr = regmap_irq_get_virq(wcd939x->irq_chip, + WCD939X_IRQ_MBHC_BUTTON_RELEASE_DET); + intr_ids->mbhc_hs_ins_intr = regmap_irq_get_virq(wcd939x->irq_chip, + WCD939X_IRQ_MBHC_ELECT_INS_REM_LEG_DET); + intr_ids->mbhc_hs_rem_intr = regmap_irq_get_virq(wcd939x->irq_chip, + WCD939X_IRQ_MBHC_ELECT_INS_REM_DET); + intr_ids->hph_left_ocp = regmap_irq_get_virq(wcd939x->irq_chip, + WCD939X_IRQ_HPHL_OCP_INT); + intr_ids->hph_right_ocp = regmap_irq_get_virq(wcd939x->irq_chip, + WCD939X_IRQ_HPHR_OCP_INT); + + wcd939x->wcd_mbhc = wcd_mbhc_init(component, &mbhc_cb, intr_ids, wcd_mbhc_fields, true); + if (IS_ERR(wcd939x->wcd_mbhc)) + return PTR_ERR(wcd939x->wcd_mbhc); + + 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; +} + +static void wcd939x_mbhc_deinit(struct snd_soc_component *component) +{ + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + wcd_mbhc_deinit(wcd939x->wcd_mbhc); +} + +/* END MBHC */ + +static const struct snd_kcontrol_new wcd939x_snd_controls[] = { + /* RX Path */ + SOC_SINGLE_EXT("HPHL_COMP Switch", WCD939X_COMP_L, 0, 1, 0, + wcd939x_get_compander, wcd939x_set_compander), + SOC_SINGLE_EXT("HPHR_COMP Switch", WCD939X_COMP_R, 1, 1, 0, + wcd939x_get_compander, wcd939x_set_compander), + SOC_SINGLE_EXT("HPHL Switch", WCD939X_HPH_L, 0, 1, 0, + wcd939x_get_swr_port, wcd939x_set_swr_port), + SOC_SINGLE_EXT("HPHR Switch", WCD939X_HPH_R, 0, 1, 0, + wcd939x_get_swr_port, wcd939x_set_swr_port), + SOC_SINGLE_EXT("CLSH Switch", WCD939X_CLSH, 0, 1, 0, + wcd939x_get_swr_port, wcd939x_set_swr_port), + SOC_SINGLE_EXT("LO Switch", WCD939X_LO, 0, 1, 0, + wcd939x_get_swr_port, wcd939x_set_swr_port), + SOC_SINGLE_EXT("DSD_L Switch", WCD939X_DSD_L, 0, 1, 0, + wcd939x_get_swr_port, wcd939x_set_swr_port), + SOC_SINGLE_EXT("DSD_R Switch", WCD939X_DSD_R, 0, 1, 0, + wcd939x_get_swr_port, wcd939x_set_swr_port), + SOC_SINGLE_TLV("HPHL Volume", WCD939X_HPH_L_EN, 0, 20, 1, line_gain), + SOC_SINGLE_TLV("HPHR Volume", WCD939X_HPH_R_EN, 0, 20, 1, line_gain), + SOC_SINGLE_EXT("LDOH Enable Switch", SND_SOC_NOPM, 0, 1, 0, + wcd939x_ldoh_get, wcd939x_ldoh_put), + + /* TX Path */ + SOC_SINGLE_EXT("ADC1 Switch", WCD939X_ADC1, 1, 1, 0, + wcd939x_get_swr_port, wcd939x_set_swr_port), + SOC_SINGLE_EXT("ADC2 Switch", WCD939X_ADC2, 1, 1, 0, + wcd939x_get_swr_port, wcd939x_set_swr_port), + SOC_SINGLE_EXT("ADC3 Switch", WCD939X_ADC3, 1, 1, 0, + wcd939x_get_swr_port, wcd939x_set_swr_port), + SOC_SINGLE_EXT("ADC4 Switch", WCD939X_ADC4, 1, 1, 0, + wcd939x_get_swr_port, wcd939x_set_swr_port), + SOC_SINGLE_EXT("DMIC0 Switch", WCD939X_DMIC0, 1, 1, 0, + wcd939x_get_swr_port, wcd939x_set_swr_port), + SOC_SINGLE_EXT("DMIC1 Switch", WCD939X_DMIC1, 1, 1, 0, + wcd939x_get_swr_port, wcd939x_set_swr_port), + SOC_SINGLE_EXT("MBHC Switch", WCD939X_MBHC, 1, 1, 0, + wcd939x_get_swr_port, wcd939x_set_swr_port), + SOC_SINGLE_EXT("DMIC2 Switch", WCD939X_DMIC2, 1, 1, 0, + wcd939x_get_swr_port, wcd939x_set_swr_port), + SOC_SINGLE_EXT("DMIC3 Switch", WCD939X_DMIC3, 1, 1, 0, + wcd939x_get_swr_port, wcd939x_set_swr_port), + SOC_SINGLE_EXT("DMIC4 Switch", WCD939X_DMIC4, 1, 1, 0, + wcd939x_get_swr_port, wcd939x_set_swr_port), + SOC_SINGLE_EXT("DMIC5 Switch", WCD939X_DMIC5, 1, 1, 0, + wcd939x_get_swr_port, wcd939x_set_swr_port), + SOC_SINGLE_EXT("DMIC6 Switch", WCD939X_DMIC6, 1, 1, 0, + wcd939x_get_swr_port, wcd939x_set_swr_port), + SOC_SINGLE_EXT("DMIC7 Switch", WCD939X_DMIC7, 1, 1, 0, + wcd939x_get_swr_port, wcd939x_set_swr_port), + SOC_SINGLE_TLV("ADC1 Volume", WCD939X_ANA_TX_CH1, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC2 Volume", WCD939X_ANA_TX_CH2, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC3 Volume", WCD939X_ANA_TX_CH3, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC4 Volume", WCD939X_ANA_TX_CH4, 0, 20, 0, + analog_gain), +}; + +static const struct snd_soc_dapm_widget wcd939x_dapm_widgets[] = { + /*input widgets*/ + SND_SOC_DAPM_INPUT("AMIC1"), + SND_SOC_DAPM_INPUT("AMIC2"), + SND_SOC_DAPM_INPUT("AMIC3"), + SND_SOC_DAPM_INPUT("AMIC4"), + SND_SOC_DAPM_INPUT("AMIC5"), + + SND_SOC_DAPM_MIC("Analog Mic1", NULL), + SND_SOC_DAPM_MIC("Analog Mic2", NULL), + SND_SOC_DAPM_MIC("Analog Mic3", NULL), + SND_SOC_DAPM_MIC("Analog Mic4", NULL), + SND_SOC_DAPM_MIC("Analog Mic5", NULL), + + /* TX widgets */ + SND_SOC_DAPM_ADC_E("ADC1", NULL, SND_SOC_NOPM, 0, 0, + wcd939x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC2", NULL, SND_SOC_NOPM, 1, 0, + wcd939x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC3", NULL, SND_SOC_NOPM, 2, 0, + wcd939x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC4", NULL, SND_SOC_NOPM, 3, 0, + wcd939x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0, + wcd939x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 1, 0, + wcd939x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 2, 0, + wcd939x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 3, 0, + wcd939x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 4, 0, + wcd939x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 5, 0, + wcd939x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC7", NULL, SND_SOC_NOPM, 6, 0, + wcd939x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC8", NULL, SND_SOC_NOPM, 7, 0, + wcd939x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("ADC1 REQ", SND_SOC_NOPM, 0, 0, NULL, 0, + wcd939x_adc_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC2 REQ", SND_SOC_NOPM, 1, 0, NULL, 0, + wcd939x_adc_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC3 REQ", SND_SOC_NOPM, 2, 0, NULL, 0, + wcd939x_adc_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC4 REQ", SND_SOC_NOPM, 3, 0, NULL, 0, + wcd939x_adc_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("ADC1 MUX", SND_SOC_NOPM, 0, 0, &tx_adc1_mux), + SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, &tx_adc2_mux), + SND_SOC_DAPM_MUX("ADC3 MUX", SND_SOC_NOPM, 0, 0, &tx_adc3_mux), + SND_SOC_DAPM_MUX("ADC4 MUX", SND_SOC_NOPM, 0, 0, &tx_adc4_mux), + + /* tx mixers */ + SND_SOC_DAPM_MIXER_E("ADC1_MIXER", SND_SOC_NOPM, 0, 0, + adc1_switch, ARRAY_SIZE(adc1_switch), wcd939x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC2_MIXER", SND_SOC_NOPM, 0, 0, + adc2_switch, ARRAY_SIZE(adc2_switch), wcd939x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC3_MIXER", SND_SOC_NOPM, 0, 0, + adc3_switch, ARRAY_SIZE(adc3_switch), wcd939x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC4_MIXER", SND_SOC_NOPM, 0, 0, + adc4_switch, ARRAY_SIZE(adc4_switch), wcd939x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC1_MIXER", SND_SOC_NOPM, 0, 0, + dmic1_switch, ARRAY_SIZE(dmic1_switch), wcd939x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC2_MIXER", SND_SOC_NOPM, 0, 0, + dmic2_switch, ARRAY_SIZE(dmic2_switch), wcd939x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC3_MIXER", SND_SOC_NOPM, 0, 0, + dmic3_switch, ARRAY_SIZE(dmic3_switch), wcd939x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC4_MIXER", SND_SOC_NOPM, 0, 0, + dmic4_switch, ARRAY_SIZE(dmic4_switch), wcd939x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC5_MIXER", SND_SOC_NOPM, 0, 0, + dmic5_switch, ARRAY_SIZE(dmic5_switch), wcd939x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC6_MIXER", SND_SOC_NOPM, 0, 0, + dmic6_switch, ARRAY_SIZE(dmic6_switch), wcd939x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC7_MIXER", SND_SOC_NOPM, 0, 0, + dmic7_switch, ARRAY_SIZE(dmic7_switch), wcd939x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC8_MIXER", SND_SOC_NOPM, 0, 0, + dmic8_switch, ARRAY_SIZE(dmic8_switch), wcd939x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* micbias widgets */ + SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0, + wcd939x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0, + wcd939x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0, + wcd939x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS4", SND_SOC_NOPM, MIC_BIAS_4, 0, + wcd939x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + /* micbias pull up widgets */ + SND_SOC_DAPM_SUPPLY("VA MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0, + wcd939x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("VA MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0, + wcd939x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("VA MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0, + wcd939x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("VA MIC BIAS4", SND_SOC_NOPM, MIC_BIAS_4, 0, + wcd939x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + /* output widgets tx */ + SND_SOC_DAPM_OUTPUT("ADC1_OUTPUT"), + SND_SOC_DAPM_OUTPUT("ADC2_OUTPUT"), + SND_SOC_DAPM_OUTPUT("ADC3_OUTPUT"), + SND_SOC_DAPM_OUTPUT("ADC4_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC1_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC2_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC3_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC4_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC5_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC6_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC7_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC8_OUTPUT"), + + SND_SOC_DAPM_INPUT("IN1_HPHL"), + SND_SOC_DAPM_INPUT("IN2_HPHR"), + SND_SOC_DAPM_INPUT("IN3_EAR"), + + /* rx widgets */ + SND_SOC_DAPM_PGA_E("EAR PGA", WCD939X_ANA_EAR, 7, 0, NULL, 0, + wcd939x_codec_enable_ear_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHL PGA", WCD939X_ANA_HPH, 7, 0, NULL, 0, + wcd939x_codec_enable_hphl_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHR PGA", WCD939X_ANA_HPH, 6, 0, NULL, 0, + wcd939x_codec_enable_hphr_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_DAC_E("RDAC1", NULL, SND_SOC_NOPM, 0, 0, + wcd939x_codec_hphl_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RDAC2", NULL, SND_SOC_NOPM, 0, 0, + wcd939x_codec_hphr_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RDAC3", NULL, SND_SOC_NOPM, 0, 0, + wcd939x_codec_ear_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("RDAC3_MUX", SND_SOC_NOPM, 0, 0, &rx_rdac3_mux), + + SND_SOC_DAPM_SUPPLY("VDD_BUCK", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RXCLK", SND_SOC_NOPM, 0, 0, + wcd939x_codec_enable_rxclk, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("CLS_H_PORT", 1, SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MIXER_E("RX1", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0), + SND_SOC_DAPM_MIXER_E("RX2", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0), + SND_SOC_DAPM_MIXER_E("RX3", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0), + + /* rx mixer widgets */ + SND_SOC_DAPM_MIXER("EAR_RDAC", SND_SOC_NOPM, 0, 0, + ear_rdac_switch, ARRAY_SIZE(ear_rdac_switch)), + SND_SOC_DAPM_MIXER("HPHL_RDAC", SND_SOC_NOPM, 0, 0, + hphl_rdac_switch, ARRAY_SIZE(hphl_rdac_switch)), + SND_SOC_DAPM_MIXER("HPHR_RDAC", SND_SOC_NOPM, 0, 0, + hphr_rdac_switch, ARRAY_SIZE(hphr_rdac_switch)), + + /* output widgets rx */ + SND_SOC_DAPM_OUTPUT("EAR"), + SND_SOC_DAPM_OUTPUT("HPHL"), + SND_SOC_DAPM_OUTPUT("HPHR"), +}; + +static const struct snd_soc_dapm_route wcd939x_audio_map[] = { + /* TX Path */ + {"ADC1_OUTPUT", NULL, "ADC1_MIXER"}, + {"ADC1_MIXER", "Switch", "ADC1 REQ"}, + {"ADC1 REQ", NULL, "ADC1"}, + {"ADC1", NULL, "ADC1 MUX"}, + {"ADC1 MUX", "CH1_AMIC1", "AMIC1"}, + {"ADC1 MUX", "CH1_AMIC2", "AMIC2"}, + {"ADC1 MUX", "CH1_AMIC3", "AMIC3"}, + {"ADC1 MUX", "CH1_AMIC4", "AMIC4"}, + {"ADC1 MUX", "CH1_AMIC5", "AMIC5"}, + + {"ADC2_OUTPUT", NULL, "ADC2_MIXER"}, + {"ADC2_MIXER", "Switch", "ADC2 REQ"}, + {"ADC2 REQ", NULL, "ADC2"}, + {"ADC2", NULL, "ADC2 MUX"}, + {"ADC2 MUX", "CH2_AMIC1", "AMIC1"}, + {"ADC2 MUX", "CH2_AMIC2", "AMIC2"}, + {"ADC2 MUX", "CH2_AMIC3", "AMIC3"}, + {"ADC2 MUX", "CH2_AMIC4", "AMIC4"}, + {"ADC2 MUX", "CH2_AMIC5", "AMIC5"}, + + {"ADC3_OUTPUT", NULL, "ADC3_MIXER"}, + {"ADC3_MIXER", "Switch", "ADC3 REQ"}, + {"ADC3 REQ", NULL, "ADC3"}, + {"ADC3", NULL, "ADC3 MUX"}, + {"ADC3 MUX", "CH3_AMIC1", "AMIC1"}, + {"ADC3 MUX", "CH3_AMIC3", "AMIC3"}, + {"ADC3 MUX", "CH3_AMIC4", "AMIC4"}, + {"ADC3 MUX", "CH3_AMIC5", "AMIC5"}, + + {"ADC4_OUTPUT", NULL, "ADC4_MIXER"}, + {"ADC4_MIXER", "Switch", "ADC4 REQ"}, + {"ADC4 REQ", NULL, "ADC4"}, + {"ADC4", NULL, "ADC4 MUX"}, + {"ADC4 MUX", "CH4_AMIC1", "AMIC1"}, + {"ADC4 MUX", "CH4_AMIC3", "AMIC3"}, + {"ADC4 MUX", "CH4_AMIC4", "AMIC4"}, + {"ADC4 MUX", "CH4_AMIC5", "AMIC5"}, + + {"DMIC1_OUTPUT", NULL, "DMIC1_MIXER"}, + {"DMIC1_MIXER", "Switch", "DMIC1"}, + + {"DMIC2_OUTPUT", NULL, "DMIC2_MIXER"}, + {"DMIC2_MIXER", "Switch", "DMIC2"}, + + {"DMIC3_OUTPUT", NULL, "DMIC3_MIXER"}, + {"DMIC3_MIXER", "Switch", "DMIC3"}, + + {"DMIC4_OUTPUT", NULL, "DMIC4_MIXER"}, + {"DMIC4_MIXER", "Switch", "DMIC4"}, + + {"DMIC5_OUTPUT", NULL, "DMIC5_MIXER"}, + {"DMIC5_MIXER", "Switch", "DMIC5"}, + + {"DMIC6_OUTPUT", NULL, "DMIC6_MIXER"}, + {"DMIC6_MIXER", "Switch", "DMIC6"}, + + {"DMIC7_OUTPUT", NULL, "DMIC7_MIXER"}, + {"DMIC7_MIXER", "Switch", "DMIC7"}, + + {"DMIC8_OUTPUT", NULL, "DMIC8_MIXER"}, + {"DMIC8_MIXER", "Switch", "DMIC8"}, + + /* RX Path */ + {"IN1_HPHL", NULL, "VDD_BUCK"}, + {"IN1_HPHL", NULL, "CLS_H_PORT"}, + + {"RX1", NULL, "IN1_HPHL"}, + {"RX1", NULL, "RXCLK"}, + {"RDAC1", NULL, "RX1"}, + {"HPHL_RDAC", "Switch", "RDAC1"}, + {"HPHL PGA", NULL, "HPHL_RDAC"}, + {"HPHL", NULL, "HPHL PGA"}, + + {"IN2_HPHR", NULL, "VDD_BUCK"}, + {"IN2_HPHR", NULL, "CLS_H_PORT"}, + {"RX2", NULL, "IN2_HPHR"}, + {"RDAC2", NULL, "RX2"}, + {"RX2", NULL, "RXCLK"}, + {"HPHR_RDAC", "Switch", "RDAC2"}, + {"HPHR PGA", NULL, "HPHR_RDAC"}, + {"HPHR", NULL, "HPHR PGA"}, + + {"IN3_EAR", NULL, "VDD_BUCK"}, + {"RX3", NULL, "IN3_EAR"}, + {"RX3", NULL, "RXCLK"}, + + {"RDAC3_MUX", "RX3", "RX3"}, + {"RDAC3_MUX", "RX1", "RX1"}, + {"RDAC3", NULL, "RDAC3_MUX"}, + {"EAR_RDAC", "Switch", "RDAC3"}, + {"EAR PGA", NULL, "EAR_RDAC"}, + {"EAR", NULL, "EAR PGA"}, +}; + +static int wcd939x_set_micbias_data(struct wcd939x_priv *wcd939x) +{ + int vout_ctl_1, vout_ctl_2, vout_ctl_3, vout_ctl_4; + + /* set micbias voltage */ + vout_ctl_1 = wcd939x_get_micb_vout_ctl_val(wcd939x->micb1_mv); + vout_ctl_2 = wcd939x_get_micb_vout_ctl_val(wcd939x->micb2_mv); + vout_ctl_3 = wcd939x_get_micb_vout_ctl_val(wcd939x->micb3_mv); + vout_ctl_4 = wcd939x_get_micb_vout_ctl_val(wcd939x->micb4_mv); + if (vout_ctl_1 < 0 || vout_ctl_2 < 0 || vout_ctl_3 < 0 || vout_ctl_4 < 0) + return -EINVAL; + + regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB1, + WCD939X_MICB1_VOUT_CTL, vout_ctl_1); + regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB2, + WCD939X_MICB2_VOUT_CTL, vout_ctl_2); + regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB3, + WCD939X_MICB3_VOUT_CTL, vout_ctl_3); + regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB4, + WCD939X_MICB4_VOUT_CTL, vout_ctl_4); + + return 0; +} + +static irqreturn_t wcd939x_wd_handle_irq(int irq, void *data) +{ + /* + * HPHR/HPHL/EAR Watchdog interrupt threaded handler + * + * Watchdog interrupts are expected to be enabled when switching + * on the HPHL/R and EAR RX PGA in order to make sure the interrupts + * are acked by the regmap_irq handler to allow PDM sync. + * We could leave those interrupts masked but we would not have + * any valid way to enable/disable them without violating irq layers. + * + * The HPHR/HPHL/EAR Watchdog interrupts are handled + * by regmap_irq, so requesting a threaded handler is the + * safest way to be able to ack those interrupts without + * colliding with the regmap_irq setup. + */ + + return IRQ_HANDLED; +} + +/* + * Setup a virtual interrupt domain to hook regmap_irq + * The root domain will have a single interrupt which mapping + * will trigger the regmap_irq handler. + * + * root: + * wcd_irq_chip + * [0] wcd939x_regmap_irq_chip + * [0] MBHC_BUTTON_PRESS_DET + * [1] MBHC_BUTTON_RELEASE_DET + * ... + * [16] HPHR_SURGE_DET_INT + * + * Interrupt trigger: + * soundwire_interrupt_callback() + * \-handle_nested_irq(0) + * \- regmap_irq_thread() + * \- handle_nested_irq(i) + */ +static struct irq_chip wcd_irq_chip = { + .name = "WCD939x", +}; + +static int wcd_irq_chip_map(struct irq_domain *irqd, unsigned int virq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(virq, &wcd_irq_chip, handle_simple_irq); + irq_set_nested_thread(virq, 1); + irq_set_noprobe(virq); + + return 0; +} + +static const struct irq_domain_ops wcd_domain_ops = { + .map = wcd_irq_chip_map, +}; + +static int wcd939x_irq_init(struct wcd939x_priv *wcd, struct device *dev) +{ + wcd->virq = irq_domain_add_linear(NULL, 1, &wcd_domain_ops, NULL); + if (!(wcd->virq)) { + dev_err(dev, "%s: Failed to add IRQ domain\n", __func__); + return -EINVAL; + } + + return devm_regmap_add_irq_chip(dev, wcd->regmap, + irq_create_mapping(wcd->virq, 0), + IRQF_ONESHOT, 0, &wcd939x_regmap_irq_chip, + &wcd->irq_chip); +} + +static int wcd939x_soc_codec_probe(struct snd_soc_component *component) +{ + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + struct sdw_slave *tx_sdw_dev = wcd939x->tx_sdw_dev; + struct device *dev = component->dev; + unsigned long time_left; + int ret, i; + + time_left = wait_for_completion_timeout(&tx_sdw_dev->initialization_complete, + msecs_to_jiffies(2000)); + if (!time_left) { + dev_err(dev, "soundwire device init timeout\n"); + return -ETIMEDOUT; + } + + snd_soc_component_init_regmap(component, wcd939x->regmap); + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return ret; + + wcd939x->variant = snd_soc_component_read_field(component, + WCD939X_DIGITAL_EFUSE_REG_0, + WCD939X_EFUSE_REG_0_WCD939X_ID); + + wcd939x->clsh_info = wcd_clsh_ctrl_alloc(component, WCD939X); + if (IS_ERR(wcd939x->clsh_info)) { + pm_runtime_put(dev); + return PTR_ERR(wcd939x->clsh_info); + } + + wcd939x_io_init(component); + + /* Set all interrupts as edge triggered */ + for (i = 0; i < wcd939x_regmap_irq_chip.num_regs; i++) + regmap_write(wcd939x->regmap, + (WCD939X_DIGITAL_INTR_LEVEL_0 + i), 0); + + pm_runtime_put(dev); + + /* Request for watchdog interrupt */ + wcd939x->hphr_pdm_wd_int = regmap_irq_get_virq(wcd939x->irq_chip, + WCD939X_IRQ_HPHR_PDM_WD_INT); + wcd939x->hphl_pdm_wd_int = regmap_irq_get_virq(wcd939x->irq_chip, + WCD939X_IRQ_HPHL_PDM_WD_INT); + wcd939x->ear_pdm_wd_int = regmap_irq_get_virq(wcd939x->irq_chip, + WCD939X_IRQ_EAR_PDM_WD_INT); + + ret = request_threaded_irq(wcd939x->hphr_pdm_wd_int, NULL, wcd939x_wd_handle_irq, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + "HPHR PDM WD INT", wcd939x); + if (ret) { + dev_err(dev, "Failed to request HPHR WD interrupt (%d)\n", ret); + goto err_free_clsh_ctrl; + } + + ret = request_threaded_irq(wcd939x->hphl_pdm_wd_int, NULL, wcd939x_wd_handle_irq, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + "HPHL PDM WD INT", wcd939x); + if (ret) { + dev_err(dev, "Failed to request HPHL WD interrupt (%d)\n", ret); + goto err_free_hphr_pdm_wd_int; + } + + ret = request_threaded_irq(wcd939x->ear_pdm_wd_int, NULL, wcd939x_wd_handle_irq, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + "AUX PDM WD INT", wcd939x); + if (ret) { + dev_err(dev, "Failed to request Aux WD interrupt (%d)\n", ret); + goto err_free_hphl_pdm_wd_int; + } + + /* Disable watchdog interrupt for HPH and AUX */ + disable_irq_nosync(wcd939x->hphr_pdm_wd_int); + disable_irq_nosync(wcd939x->hphl_pdm_wd_int); + disable_irq_nosync(wcd939x->ear_pdm_wd_int); + + switch (wcd939x->variant) { + case WCD9390: + ret = snd_soc_add_component_controls(component, wcd9390_snd_controls, + ARRAY_SIZE(wcd9390_snd_controls)); + if (ret < 0) { + dev_err(component->dev, + "%s: Failed to add snd ctrls for variant: %d\n", + __func__, wcd939x->variant); + goto err_free_ear_pdm_wd_int; + } + break; + case WCD9395: + ret = snd_soc_add_component_controls(component, wcd9395_snd_controls, + ARRAY_SIZE(wcd9395_snd_controls)); + if (ret < 0) { + dev_err(component->dev, + "%s: Failed to add snd ctrls for variant: %d\n", + __func__, wcd939x->variant); + goto err_free_ear_pdm_wd_int; + } + break; + default: + break; + } + + ret = wcd939x_mbhc_init(component); + if (ret) { + dev_err(component->dev, "mbhc initialization failed\n"); + goto err_free_ear_pdm_wd_int; + } + + return 0; + +err_free_ear_pdm_wd_int: + free_irq(wcd939x->ear_pdm_wd_int, wcd939x); +err_free_hphl_pdm_wd_int: + free_irq(wcd939x->hphl_pdm_wd_int, wcd939x); +err_free_hphr_pdm_wd_int: + free_irq(wcd939x->hphr_pdm_wd_int, wcd939x); +err_free_clsh_ctrl: + wcd_clsh_ctrl_free(wcd939x->clsh_info); + + return ret; +} + +static void wcd939x_soc_codec_remove(struct snd_soc_component *component) +{ + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + wcd939x_mbhc_deinit(component); + + free_irq(wcd939x->ear_pdm_wd_int, wcd939x); + free_irq(wcd939x->hphl_pdm_wd_int, wcd939x); + free_irq(wcd939x->hphr_pdm_wd_int, wcd939x); + + wcd_clsh_ctrl_free(wcd939x->clsh_info); +} + +static int wcd939x_codec_set_jack(struct snd_soc_component *comp, + struct snd_soc_jack *jack, void *data) +{ + struct wcd939x_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_wcd939x = { + .name = "wcd939x_codec", + .probe = wcd939x_soc_codec_probe, + .remove = wcd939x_soc_codec_remove, + .controls = wcd939x_snd_controls, + .num_controls = ARRAY_SIZE(wcd939x_snd_controls), + .dapm_widgets = wcd939x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wcd939x_dapm_widgets), + .dapm_routes = wcd939x_audio_map, + .num_dapm_routes = ARRAY_SIZE(wcd939x_audio_map), + .set_jack = wcd939x_codec_set_jack, + .endianness = 1, +}; + +#if IS_ENABLED(CONFIG_TYPEC) +/* Get USB-C plug orientation to provide swap event for MBHC */ +static int wcd939x_typec_switch_set(struct typec_switch_dev *sw, + enum typec_orientation orientation) +{ + struct wcd939x_priv *wcd939x = typec_switch_get_drvdata(sw); + + wcd939x->typec_orientation = orientation; + + return 0; +} + +static int wcd939x_typec_mux_set(struct typec_mux_dev *mux, + struct typec_mux_state *state) +{ + struct wcd939x_priv *wcd939x = typec_mux_get_drvdata(mux); + unsigned int previous_mode = wcd939x->typec_mode; + + if (!wcd939x->wcd_mbhc) + return -EINVAL; + + if (wcd939x->typec_mode != state->mode) { + wcd939x->typec_mode = state->mode; + + if (wcd939x->typec_mode == TYPEC_MODE_AUDIO) + return wcd_mbhc_typec_report_plug(wcd939x->wcd_mbhc); + else if (previous_mode == TYPEC_MODE_AUDIO) + return wcd_mbhc_typec_report_unplug(wcd939x->wcd_mbhc); + } + + return 0; +} +#endif /* CONFIG_TYPEC */ + +static void wcd939x_dt_parse_micbias_info(struct device *dev, struct wcd939x_priv *wcd) +{ + struct device_node *np = dev->of_node; + u32 prop_val = 0; + int rc = 0; + + rc = of_property_read_u32(np, "qcom,micbias1-microvolt", &prop_val); + if (!rc) + wcd->micb1_mv = prop_val / 1000; + else + dev_info(dev, "%s: Micbias1 DT property not found\n", __func__); + + rc = of_property_read_u32(np, "qcom,micbias2-microvolt", &prop_val); + if (!rc) + wcd->micb2_mv = prop_val / 1000; + else + dev_info(dev, "%s: Micbias2 DT property not found\n", __func__); + + rc = of_property_read_u32(np, "qcom,micbias3-microvolt", &prop_val); + if (!rc) + wcd->micb3_mv = prop_val / 1000; + else + dev_info(dev, "%s: Micbias3 DT property not found\n", __func__); + + rc = of_property_read_u32(np, "qcom,micbias4-microvolt", &prop_val); + if (!rc) + wcd->micb4_mv = prop_val / 1000; + else + dev_info(dev, "%s: Micbias4 DT property not found\n", __func__); +} + +#if IS_ENABLED(CONFIG_TYPEC) +static bool wcd939x_swap_gnd_mic(struct snd_soc_component *component, bool active) +{ + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + if (!wcd939x->typec_analog_mux || !wcd939x->typec_switch) + return false; + + /* Report inversion via Type Switch of USBSS */ + typec_switch_set(wcd939x->typec_switch, + wcd939x->typec_orientation == TYPEC_ORIENTATION_REVERSE ? + TYPEC_ORIENTATION_NORMAL : TYPEC_ORIENTATION_REVERSE); + + return true; +} +#endif /* CONFIG_TYPEC */ + +static int wcd939x_populate_dt_data(struct wcd939x_priv *wcd939x, struct device *dev) +{ + struct wcd_mbhc_config *cfg = &wcd939x->mbhc_cfg; +#if IS_ENABLED(CONFIG_TYPEC) + struct device_node *np; +#endif /* CONFIG_TYPEC */ + int ret; + + wcd939x->reset_gpio = of_get_named_gpio(dev->of_node, "reset-gpios", 0); + if (wcd939x->reset_gpio < 0) + return dev_err_probe(dev, wcd939x->reset_gpio, + "Failed to get reset gpio\n"); + + wcd939x->supplies[0].supply = "vdd-rxtx"; + wcd939x->supplies[1].supply = "vdd-io"; + wcd939x->supplies[2].supply = "vdd-buck"; + wcd939x->supplies[3].supply = "vdd-mic-bias"; + + ret = regulator_bulk_get(dev, WCD939X_MAX_SUPPLY, wcd939x->supplies); + if (ret) + return dev_err_probe(dev, ret, "Failed to get supplies\n"); + + ret = regulator_bulk_enable(WCD939X_MAX_SUPPLY, wcd939x->supplies); + if (ret) { + regulator_bulk_free(WCD939X_MAX_SUPPLY, wcd939x->supplies); + return dev_err_probe(dev, ret, "Failed to enable supplies\n"); + } + + wcd939x_dt_parse_micbias_info(dev, wcd939x); + + cfg->mbhc_micbias = MIC_BIAS_2; + cfg->anc_micbias = MIC_BIAS_2; + cfg->v_hs_max = WCD_MBHC_HS_V_MAX; + cfg->num_btn = WCD939X_MBHC_MAX_BUTTONS; + cfg->micb_mv = wcd939x->micb2_mv; + cfg->linein_th = 5000; + cfg->hs_thr = 1700; + cfg->hph_thr = 50; + + wcd_dt_parse_mbhc_data(dev, cfg); + +#if IS_ENABLED(CONFIG_TYPEC) + /* + * Is node has a port and a valid remote endpoint + * consider HP lines are connected to the USBSS part + */ + np = of_graph_get_remote_node(dev->of_node, 0, 0); + if (np) { + wcd939x->typec_analog_mux = true; + cfg->typec_analog_mux = true; + cfg->swap_gnd_mic = wcd939x_swap_gnd_mic; + } +#endif /* CONFIG_TYPEC */ + + return 0; +} + +static int wcd939x_reset(struct wcd939x_priv *wcd939x) +{ + gpio_direction_output(wcd939x->reset_gpio, 0); + /* 20us sleep required after pulling the reset gpio to LOW */ + usleep_range(20, 30); + gpio_set_value(wcd939x->reset_gpio, 1); + /* 20us sleep required after pulling the reset gpio to HIGH */ + usleep_range(20, 30); + + return 0; +} + +static int wcd939x_codec_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct wcd939x_priv *wcd939x = dev_get_drvdata(dai->dev); + struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[dai->id]; + + return wcd939x_sdw_hw_params(wcd, substream, params, dai); +} + +static int wcd939x_codec_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct wcd939x_priv *wcd939x = dev_get_drvdata(dai->dev); + struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[dai->id]; + + return wcd939x_sdw_free(wcd, substream, dai); +} + +static int wcd939x_codec_set_sdw_stream(struct snd_soc_dai *dai, + void *stream, int direction) +{ + struct wcd939x_priv *wcd939x = dev_get_drvdata(dai->dev); + struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[dai->id]; + + return wcd939x_sdw_set_sdw_stream(wcd, dai, stream, direction); +} + +static const struct snd_soc_dai_ops wcd939x_sdw_dai_ops = { + .hw_params = wcd939x_codec_hw_params, + .hw_free = wcd939x_codec_free, + .set_stream = wcd939x_codec_set_sdw_stream, +}; + +static struct snd_soc_dai_driver wcd939x_dais[] = { + [0] = { + .name = "wcd939x-sdw-rx", + .playback = { + .stream_name = "WCD AIF1 Playback", + .rates = WCD939X_RATES_MASK | WCD939X_FRAC_RATES_MASK, + .formats = WCD939X_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &wcd939x_sdw_dai_ops, + }, + [1] = { + .name = "wcd939x-sdw-tx", + .capture = { + .stream_name = "WCD AIF1 Capture", + .rates = WCD939X_RATES_MASK | WCD939X_FRAC_RATES_MASK, + .formats = WCD939X_FORMATS, + .rate_min = 8000, + .rate_max = 384000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &wcd939x_sdw_dai_ops, + }, +}; + +static int wcd939x_bind(struct device *dev) +{ + struct wcd939x_priv *wcd939x = dev_get_drvdata(dev); + unsigned int version, id1, status1; + int ret; + +#if IS_ENABLED(CONFIG_TYPEC) + /* + * Get USBSS type-c switch to send gnd/mic swap events + * typec_switch is fetched now to avoid a probe deadlock since + * the USBSS depends on the typec_mux register in wcd939x_probe() + */ + if (wcd939x->typec_analog_mux) { + wcd939x->typec_switch = fwnode_typec_switch_get(dev->fwnode); + if (IS_ERR(wcd939x->typec_switch)) + return dev_err_probe(dev, PTR_ERR(wcd939x->typec_switch), + "failed to acquire orientation-switch\n"); + } +#endif /* CONFIG_TYPEC */ + + ret = component_bind_all(dev, wcd939x); + if (ret) { + dev_err(dev, "%s: Slave bind failed, ret = %d\n", + __func__, ret); + goto err_put_typec_switch; + } + + wcd939x->rxdev = wcd939x_sdw_device_get(wcd939x->rxnode); + if (!wcd939x->rxdev) { + dev_err(dev, "could not find slave with matching of node\n"); + ret = -EINVAL; + goto err_unbind; + } + wcd939x->sdw_priv[AIF1_PB] = dev_get_drvdata(wcd939x->rxdev); + wcd939x->sdw_priv[AIF1_PB]->wcd939x = wcd939x; + + wcd939x->txdev = wcd939x_sdw_device_get(wcd939x->txnode); + if (!wcd939x->txdev) { + dev_err(dev, "could not find txslave with matching of node\n"); + ret = -EINVAL; + goto err_put_rxdev; + } + wcd939x->sdw_priv[AIF1_CAP] = dev_get_drvdata(wcd939x->txdev); + wcd939x->sdw_priv[AIF1_CAP]->wcd939x = wcd939x; + wcd939x->tx_sdw_dev = dev_to_sdw_dev(wcd939x->txdev); + + /* + * As TX is main CSR reg interface, which should not be suspended first. + * explicitly add the dependency link + */ + if (!device_link_add(wcd939x->rxdev, wcd939x->txdev, DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME)) { + dev_err(dev, "could not devlink tx and rx\n"); + ret = -EINVAL; + goto err_put_txdev; + } + + if (!device_link_add(dev, wcd939x->txdev, DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME)) { + dev_err(dev, "could not devlink wcd and tx\n"); + ret = -EINVAL; + goto err_remove_rxtx_link; + } + + if (!device_link_add(dev, wcd939x->rxdev, DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME)) { + dev_err(dev, "could not devlink wcd and rx\n"); + ret = -EINVAL; + goto err_remove_tx_link; + } + + /* Get regmap from TX SoundWire device */ + wcd939x->regmap = wcd939x_swr_get_regmap(wcd939x->sdw_priv[AIF1_CAP]); + if (IS_ERR(wcd939x->regmap)) { + dev_err(dev, "could not get TX device regmap\n"); + ret = PTR_ERR(wcd939x->regmap); + goto err_remove_rx_link; + } + + ret = wcd939x_irq_init(wcd939x, dev); + if (ret) { + dev_err(dev, "%s: IRQ init failed: %d\n", __func__, ret); + goto err_remove_rx_link; + } + + wcd939x->sdw_priv[AIF1_PB]->slave_irq = wcd939x->virq; + wcd939x->sdw_priv[AIF1_CAP]->slave_irq = wcd939x->virq; + + ret = wcd939x_set_micbias_data(wcd939x); + if (ret < 0) { + dev_err(dev, "%s: bad micbias pdata\n", __func__); + goto err_remove_rx_link; + } + + /* Check WCD9395 version */ + regmap_read(wcd939x->regmap, WCD939X_DIGITAL_CHIP_ID1, &id1); + regmap_read(wcd939x->regmap, WCD939X_EAR_STATUS_REG_1, &status1); + + if (id1 == 0) + version = ((status1 & 0x3) ? WCD939X_VERSION_1_1 : WCD939X_VERSION_1_0); + else + version = WCD939X_VERSION_2_0; + + dev_dbg(dev, "wcd939x version: %s\n", version_to_str(version)); + + ret = snd_soc_register_component(dev, &soc_codec_dev_wcd939x, + wcd939x_dais, ARRAY_SIZE(wcd939x_dais)); + if (ret) { + dev_err(dev, "%s: Codec registration failed\n", + __func__); + goto err_remove_rx_link; + } + + return 0; + +err_remove_rx_link: + device_link_remove(dev, wcd939x->rxdev); +err_remove_tx_link: + device_link_remove(dev, wcd939x->txdev); +err_remove_rxtx_link: + device_link_remove(wcd939x->rxdev, wcd939x->txdev); +err_put_txdev: + put_device(wcd939x->txdev); +err_put_rxdev: + put_device(wcd939x->rxdev); +err_unbind: + component_unbind_all(dev, wcd939x); +err_put_typec_switch: +#if IS_ENABLED(CONFIG_TYPEC) + if (wcd939x->typec_analog_mux) + typec_switch_put(wcd939x->typec_switch); +#endif /* CONFIG_TYPEC */ + + return ret; +} + +static void wcd939x_unbind(struct device *dev) +{ + struct wcd939x_priv *wcd939x = dev_get_drvdata(dev); + + snd_soc_unregister_component(dev); + device_link_remove(dev, wcd939x->txdev); + device_link_remove(dev, wcd939x->rxdev); + device_link_remove(wcd939x->rxdev, wcd939x->txdev); + put_device(wcd939x->txdev); + put_device(wcd939x->rxdev); + component_unbind_all(dev, wcd939x); +} + +static const struct component_master_ops wcd939x_comp_ops = { + .bind = wcd939x_bind, + .unbind = wcd939x_unbind, +}; + +static int wcd939x_add_slave_components(struct wcd939x_priv *wcd939x, + struct device *dev, + struct component_match **matchptr) +{ + struct device_node *np = dev->of_node; + + wcd939x->rxnode = of_parse_phandle(np, "qcom,rx-device", 0); + if (!wcd939x->rxnode) { + dev_err(dev, "%s: Rx-device node not defined\n", __func__); + return -ENODEV; + } + + of_node_get(wcd939x->rxnode); + component_match_add_release(dev, matchptr, component_release_of, + component_compare_of, wcd939x->rxnode); + + wcd939x->txnode = of_parse_phandle(np, "qcom,tx-device", 0); + if (!wcd939x->txnode) { + dev_err(dev, "%s: Tx-device node not defined\n", __func__); + return -ENODEV; + } + of_node_get(wcd939x->txnode); + component_match_add_release(dev, matchptr, component_release_of, + component_compare_of, wcd939x->txnode); + return 0; +} + +static int wcd939x_probe(struct platform_device *pdev) +{ + struct component_match *match = NULL; + struct wcd939x_priv *wcd939x = NULL; + struct device *dev = &pdev->dev; + int ret; + + wcd939x = devm_kzalloc(dev, sizeof(struct wcd939x_priv), + GFP_KERNEL); + if (!wcd939x) + return -ENOMEM; + + dev_set_drvdata(dev, wcd939x); + mutex_init(&wcd939x->micb_lock); + + ret = wcd939x_populate_dt_data(wcd939x, dev); + if (ret) { + dev_err(dev, "%s: Fail to obtain platform data\n", __func__); + return -EINVAL; + } + +#if IS_ENABLED(CONFIG_TYPEC) + /* + * Is USBSS is used to mux analog lines, + * register a typec mux/switch to get typec events + */ + if (wcd939x->typec_analog_mux) { + struct typec_mux_desc mux_desc = { + .drvdata = wcd939x, + .fwnode = dev_fwnode(dev), + .set = wcd939x_typec_mux_set, + }; + struct typec_switch_desc sw_desc = { + .drvdata = wcd939x, + .fwnode = dev_fwnode(dev), + .set = wcd939x_typec_switch_set, + }; + + wcd939x->typec_mux = typec_mux_register(dev, &mux_desc); + if (IS_ERR(wcd939x->typec_mux)) { + ret = dev_err_probe(dev, PTR_ERR(wcd939x->typec_mux), + "failed to register typec mux\n"); + goto err_disable_regulators; + } + + wcd939x->typec_sw = typec_switch_register(dev, &sw_desc); + if (IS_ERR(wcd939x->typec_sw)) { + ret = dev_err_probe(dev, PTR_ERR(wcd939x->typec_sw), + "failed to register typec switch\n"); + goto err_unregister_typec_mux; + } + } +#endif /* CONFIG_TYPEC */ + + ret = wcd939x_add_slave_components(wcd939x, dev, &match); + if (ret) + goto err_unregister_typec_switch; + + wcd939x_reset(wcd939x); + + ret = component_master_add_with_match(dev, &wcd939x_comp_ops, match); + if (ret) + goto err_disable_regulators; + + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_idle(dev); + + return 0; + +#if IS_ENABLED(CONFIG_TYPEC) +err_unregister_typec_mux: + if (wcd939x->typec_analog_mux) + typec_mux_unregister(wcd939x->typec_mux); +#endif /* CONFIG_TYPEC */ + +err_unregister_typec_switch: +#if IS_ENABLED(CONFIG_TYPEC) + if (wcd939x->typec_analog_mux) + typec_switch_unregister(wcd939x->typec_sw); +#endif /* CONFIG_TYPEC */ + +err_disable_regulators: + regulator_bulk_disable(WCD939X_MAX_SUPPLY, wcd939x->supplies); + regulator_bulk_free(WCD939X_MAX_SUPPLY, wcd939x->supplies); + + return ret; +} + +static void wcd939x_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct wcd939x_priv *wcd939x = dev_get_drvdata(dev); + + component_master_del(dev, &wcd939x_comp_ops); + + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_dont_use_autosuspend(dev); + + regulator_bulk_disable(WCD939X_MAX_SUPPLY, wcd939x->supplies); + regulator_bulk_free(WCD939X_MAX_SUPPLY, wcd939x->supplies); +} + +#if defined(CONFIG_OF) +static const struct of_device_id wcd939x_dt_match[] = { + { .compatible = "qcom,wcd9390-codec" }, + { .compatible = "qcom,wcd9395-codec" }, + {} +}; +MODULE_DEVICE_TABLE(of, wcd939x_dt_match); +#endif + +static struct platform_driver wcd939x_codec_driver = { + .probe = wcd939x_probe, + .remove_new = wcd939x_remove, + .driver = { + .name = "wcd939x_codec", + .of_match_table = of_match_ptr(wcd939x_dt_match), + .suppress_bind_attrs = true, + }, +}; + +module_platform_driver(wcd939x_codec_driver); +MODULE_DESCRIPTION("WCD939X Codec driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wcd939x.h b/sound/soc/codecs/wcd939x.h new file mode 100644 index 000000000000..807cf3113d20 --- /dev/null +++ b/sound/soc/codecs/wcd939x.h @@ -0,0 +1,989 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __WCD939X_H__ +#define __WCD939X_H__ +#include <linux/soundwire/sdw.h> +#include <linux/soundwire/sdw_type.h> + +#define WCD939X_BASE (0x3000) +#define WCD939X_ANA_PAGE (0x3000) +#define WCD939X_ANA_BIAS (0x3001) +#define WCD939X_BIAS_ANALOG_BIAS_EN BIT(7) +#define WCD939X_BIAS_PRECHRG_EN BIT(6) +#define WCD939X_BIAS_PRECHRG_CTL_MODE BIT(5) +#define WCD939X_ANA_RX_SUPPLIES (0x3008) +#define WCD939X_RX_SUPPLIES_VPOS_EN BIT(7) +#define WCD939X_RX_SUPPLIES_VNEG_EN BIT(6) +#define WCD939X_RX_SUPPLIES_VPOS_PWR_LVL BIT(3) +#define WCD939X_RX_SUPPLIES_VNEG_PWR_LVL BIT(2) +#define WCD939X_RX_SUPPLIES_REGULATOR_MODE BIT(1) +#define WCD939X_RX_SUPPLIES_RX_BIAS_ENABLE BIT(0) +#define WCD939X_ANA_HPH (0x3009) +#define WCD939X_HPH_HPHL_ENABLE BIT(7) +#define WCD939X_HPH_HPHR_ENABLE BIT(6) +#define WCD939X_HPH_HPHL_REF_ENABLE BIT(5) +#define WCD939X_HPH_HPHR_REF_ENABLE BIT(4) +#define WCD939X_HPH_PWR_LEVEL GENMASK(3, 2) +#define WCD939X_ANA_EAR (0x300a) +#define WCD939X_ANA_EAR_COMPANDER_CTL (0x300b) +#define WCD939X_EAR_COMPANDER_CTL_GAIN_OVRD_REG BIT(7) +#define WCD939X_EAR_COMPANDER_CTL_EAR_GAIN GENMASK(6, 2) +#define WCD939X_EAR_COMPANDER_CTL_COMP_DFF_BYP BIT(1) +#define WCD939X_EAR_COMPANDER_CTL_COMP_DFF_CLK_EDGE BIT(0) +#define WCD939X_ANA_TX_CH1 (0x300e) +#define WCD939X_ANA_TX_CH2 (0x300f) +#define WCD939X_TX_CH2_ENABLE BIT(7) +#define WCD939X_TX_CH2_HPF1_INIT BIT(6) +#define WCD939X_TX_CH2_HPF2_INIT BIT(5) +#define WCD939X_TX_CH2_GAIN GENMASK(4, 0) +#define WCD939X_ANA_TX_CH3 (0x3010) +#define WCD939X_ANA_TX_CH4 (0x3011) +#define WCD939X_TX_CH4_ENABLE BIT(7) +#define WCD939X_TX_CH4_HPF3_INIT BIT(6) +#define WCD939X_TX_CH4_HPF4_INIT BIT(5) +#define WCD939X_TX_CH4_GAIN GENMASK(4, 0) +#define WCD939X_ANA_MICB1_MICB2_DSP_EN_LOGIC (0x3012) +#define WCD939X_ANA_MICB3_DSP_EN_LOGIC (0x3013) +#define WCD939X_ANA_MBHC_MECH (0x3014) +#define WCD939X_MBHC_MECH_L_DET_EN BIT(7) +#define WCD939X_MBHC_MECH_GND_DET_EN BIT(6) +#define WCD939X_MBHC_MECH_MECH_DETECT_TYPE BIT(5) +#define WCD939X_MBHC_MECH_HPHL_PLUG_TYPE BIT(4) +#define WCD939X_MBHC_MECH_GND_PLUG_TYPE BIT(3) +#define WCD939X_MBHC_MECH_MECH_HS_L_PULLUP_COMP_EN BIT(2) +#define WCD939X_MBHC_MECH_MECH_HS_G_PULLUP_COMP_EN BIT(1) +#define WCD939X_MBHC_MECH_SW_HPH_L_P_100K_TO_GND BIT(0) +#define WCD939X_ANA_MBHC_ELECT (0x3015) +#define WCD939X_MBHC_ELECT_FSM_EN BIT(7) +#define WCD939X_MBHC_ELECT_BTNDET_ISRC_CTL GENMASK(6, 4) +#define WCD939X_MBHC_ELECT_ELECT_DET_TYPE BIT(3) +#define WCD939X_MBHC_ELECT_ELECT_SCHMT_ISRC_CTL GENMASK(2, 1) +#define WCD939X_MBHC_ELECT_BIAS_EN BIT(0) +#define WCD939X_ANA_MBHC_ZDET (0x3016) +#define WCD939X_MBHC_ZDET_ZDET_L_MEAS_EN BIT(7) +#define WCD939X_MBHC_ZDET_ZDET_R_MEAS_EN BIT(6) +#define WCD939X_MBHC_ZDET_ZDET_CHG_EN BIT(5) +#define WCD939X_MBHC_ZDET_ZDET_ILEAK_COMP_EN BIT(4) +#define WCD939X_MBHC_ZDET_ELECT_ISRC_EN BIT(1) +#define WCD939X_ANA_MBHC_RESULT_1 (0x3017) +#define WCD939X_MBHC_RESULT_1_Z_RESULT_LSB GENMASK(7, 0) +#define WCD939X_ANA_MBHC_RESULT_2 (0x3018) +#define WCD939X_MBHC_RESULT_2_Z_RESULT_MSB GENMASK(7, 0) +#define WCD939X_ANA_MBHC_RESULT_3 (0x3019) +#define WCD939X_ANA_MBHC_BTN0 (0x301a) +#define WCD939X_MBHC_BTN0_VTH GENMASK(7, 2) +#define WCD939X_ANA_MBHC_BTN1 (0x301b) +#define WCD939X_MBHC_BTN1_VTH GENMASK(7, 2) +#define WCD939X_ANA_MBHC_BTN2 (0x301c) +#define WCD939X_MBHC_BTN2_VTH GENMASK(7, 2) +#define WCD939X_ANA_MBHC_BTN3 (0x301d) +#define WCD939X_MBHC_BTN3_VTH GENMASK(7, 2) +#define WCD939X_ANA_MBHC_BTN4 (0x301e) +#define WCD939X_MBHC_BTN4_VTH GENMASK(7, 2) +#define WCD939X_ANA_MBHC_BTN5 (0x301f) +#define WCD939X_MBHC_BTN5_VTH GENMASK(7, 2) +#define WCD939X_ANA_MBHC_BTN6 (0x3020) +#define WCD939X_MBHC_BTN6_VTH GENMASK(7, 2) +#define WCD939X_ANA_MBHC_BTN7 (0x3021) +#define WCD939X_MBHC_BTN7_VTH GENMASK(7, 2) +#define WCD939X_ANA_MICB1 (0x3022) +#define WCD939X_MICB1_ENABLE GENMASK(7, 6) +#define WCD939X_MICB1_VOUT_CTL GENMASK(5, 0) +#define WCD939X_ANA_MICB2 (0x3023) +#define WCD939X_MICB2_ENABLE GENMASK(7, 6) +#define WCD939X_MICB2_VOUT_CTL GENMASK(5, 0) +#define WCD939X_ANA_MICB2_RAMP (0x3024) +#define WCD939X_MICB2_RAMP_RAMP_ENABLE BIT(7) +#define WCD939X_MICB2_RAMP_MB2_IN2P_SHORT_ENABLE BIT(6) +#define WCD939X_MICB2_RAMP_ALLSW_OVRD_ENABLE BIT(5) +#define WCD939X_MICB2_RAMP_SHIFT_CTL GENMASK(4, 2) +#define WCD939X_MICB2_RAMP_USB_MGDET_MICB2_RAMP GENMASK(1, 0) +#define WCD939X_ANA_MICB3 (0x3025) +#define WCD939X_MICB3_ENABLE GENMASK(7, 6) +#define WCD939X_MICB3_VOUT_CTL GENMASK(5, 0) +#define WCD939X_ANA_MICB4 (0x3026) +#define WCD939X_MICB4_ENABLE GENMASK(7, 6) +#define WCD939X_MICB4_VOUT_CTL GENMASK(5, 0) +#define WCD939X_BIAS_CTL (0x3028) +#define WCD939X_BIAS_VBG_FINE_ADJ (0x3029) +#define WCD939X_LDOL_VDDCX_ADJUST (0x3040) +#define WCD939X_LDOL_DISABLE_LDOL (0x3041) +#define WCD939X_MBHC_CTL_CLK (0x3056) +#define WCD939X_MBHC_CTL_ANA (0x3057) +#define WCD939X_MBHC_ZDET_VNEG_CTL (0x3058) +#define WCD939X_MBHC_ZDET_BIAS_CTL (0x3059) +#define WCD939X_MBHC_CTL_BCS (0x305a) +#define WCD939X_MBHC_MOISTURE_DET_FSM_STATUS (0x305b) +#define WCD939X_MBHC_TEST_CTL (0x305c) +#define WCD939X_LDOH_MODE (0x3067) +#define WCD939X_MODE_LDOH_EN BIT(7) +#define WCD939X_MODE_PWRDN_STATE BIT(6) +#define WCD939X_MODE_SLOWRAMP_EN BIT(5) +#define WCD939X_MODE_VOUT_ADJUST GENMASK(4, 3) +#define WCD939X_MODE_VOUT_COARSE_ADJ GENMASK(2, 0) +#define WCD939X_LDOH_BIAS (0x3068) +#define WCD939X_LDOH_STB_LOADS (0x3069) +#define WCD939X_LDOH_SLOWRAMP (0x306a) +#define WCD939X_MICB1_TEST_CTL_1 (0x306b) +#define WCD939X_TEST_CTL_1_NOISE_FILT_RES_VAL GENMASK(7, 5) +#define WCD939X_TEST_CTL_1_EN_VREFGEN BIT(4) +#define WCD939X_TEST_CTL_1_EN_LDO BIT(3) +#define WCD939X_TEST_CTL_1_LDO_BLEEDER_I_CTRL GENMASK(2, 0) +#define WCD939X_MICB1_TEST_CTL_2 (0x306c) +#define WCD939X_TEST_CTL_2_IBIAS_VREFGEN GENMASK(7, 6) +#define WCD939X_TEST_CTL_2_INRUSH_CURRENT_FIX_DIS BIT(5) +#define WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER GENMASK(2, 0) +#define WCD939X_MICB1_TEST_CTL_3 (0x306d) +#define WCD939X_TEST_CTL_3_CFILT_REF_EN BIT(7) +#define WCD939X_TEST_CTL_3_RZ_LDO_VAL GENMASK(6, 4) +#define WCD939X_TEST_CTL_3_IBIAS_LDO_STG3 GENMASK(3, 2) +#define WCD939X_TEST_CTL_3_ATEST_CTRL GENMASK(1, 0) +#define WCD939X_MICB2_TEST_CTL_1 (0x306e) +#define WCD939X_MICB2_TEST_CTL_2 (0x306f) +#define WCD939X_MICB2_TEST_CTL_3 (0x3070) +#define WCD939X_MICB3_TEST_CTL_1 (0x3071) +#define WCD939X_MICB3_TEST_CTL_2 (0x3072) +#define WCD939X_MICB3_TEST_CTL_3 (0x3073) +#define WCD939X_MICB4_TEST_CTL_1 (0x3074) +#define WCD939X_MICB4_TEST_CTL_2 (0x3075) +#define WCD939X_MICB4_TEST_CTL_3 (0x3076) +#define WCD939X_TX_COM_ADC_VCM (0x3077) +#define WCD939X_TX_COM_BIAS_ATEST (0x3078) +#define WCD939X_TX_COM_SPARE1 (0x3079) +#define WCD939X_TX_COM_SPARE2 (0x307a) +#define WCD939X_TX_COM_TXFE_DIV_CTL (0x307b) +#define WCD939X_TX_COM_TXFE_DIV_START (0x307c) +#define WCD939X_TX_COM_SPARE3 (0x307d) +#define WCD939X_TX_COM_SPARE4 (0x307e) +#define WCD939X_TX_1_2_TEST_EN (0x307f) +#define WCD939X_TX_1_2_ADC_IB (0x3080) +#define WCD939X_TX_1_2_ATEST_REFCTL (0x3081) +#define WCD939X_TX_1_2_TEST_CTL (0x3082) +#define WCD939X_TX_1_2_TEST_BLK_EN1 (0x3083) +#define WCD939X_TX_1_2_TXFE1_CLKDIV (0x3084) +#define WCD939X_TX_1_2_SAR2_ERR (0x3085) +#define WCD939X_TX_1_2_SAR1_ERR (0x3086) +#define WCD939X_TX_3_4_TEST_EN (0x3087) +#define WCD939X_TX_3_4_ADC_IB (0x3088) +#define WCD939X_TX_3_4_ATEST_REFCTL (0x3089) +#define WCD939X_TX_3_4_TEST_CTL (0x308a) +#define WCD939X_TX_3_4_TEST_BLK_EN3 (0x308b) +#define WCD939X_TX_3_4_TXFE3_CLKDIV (0x308c) +#define WCD939X_TX_3_4_SAR4_ERR (0x308d) +#define WCD939X_TX_3_4_SAR3_ERR (0x308e) +#define WCD939X_TX_3_4_TEST_BLK_EN2 (0x308f) +#define WCD939X_TEST_BLK_EN2_ADC2_INT1_EN BIT(7) +#define WCD939X_TEST_BLK_EN2_ADC2_INT2_EN BIT(6) +#define WCD939X_TEST_BLK_EN2_ADC2_SAR_EN BIT(5) +#define WCD939X_TEST_BLK_EN2_ADC2_CMGEN_EN BIT(4) +#define WCD939X_TEST_BLK_EN2_ADC2_CLKGEN_EN BIT(3) +#define WCD939X_TEST_BLK_EN2_ADC12_VREF_NONL2 GENMASK(2, 1) +#define WCD939X_TEST_BLK_EN2_TXFE2_MBHC_CLKRST_EN BIT(0) +#define WCD939X_TX_3_4_TXFE2_CLKDIV (0x3090) +#define WCD939X_TX_3_4_SPARE1 (0x3091) +#define WCD939X_TX_3_4_TEST_BLK_EN4 (0x3092) +#define WCD939X_TX_3_4_TXFE4_CLKDIV (0x3093) +#define WCD939X_TX_3_4_SPARE2 (0x3094) +#define WCD939X_CLASSH_MODE_1 (0x3097) +#define WCD939X_CLASSH_MODE_2 (0x3098) +#define WCD939X_CLASSH_MODE_3 (0x3099) +#define WCD939X_CLASSH_CTRL_VCL_1 (0x309a) +#define WCD939X_CLASSH_CTRL_VCL_2 (0x309b) +#define WCD939X_CLASSH_CTRL_CCL_1 (0x309c) +#define WCD939X_CLASSH_CTRL_CCL_2 (0x309d) +#define WCD939X_CLASSH_CTRL_CCL_3 (0x309e) +#define WCD939X_CLASSH_CTRL_CCL_4 (0x309f) +#define WCD939X_CLASSH_CTRL_CCL_5 (0x30a0) +#define WCD939X_CLASSH_BUCK_TMUX_A_D (0x30a1) +#define WCD939X_CLASSH_BUCK_SW_DRV_CNTL (0x30a2) +#define WCD939X_CLASSH_SPARE (0x30a3) +#define WCD939X_FLYBACK_EN (0x30a4) +#define WCD939X_FLYBACK_VNEG_CTRL_1 (0x30a5) +#define WCD939X_FLYBACK_VNEG_CTRL_2 (0x30a6) +#define WCD939X_FLYBACK_VNEG_CTRL_3 (0x30a7) +#define WCD939X_FLYBACK_VNEG_CTRL_4 (0x30a8) +#define WCD939X_VNEG_CTRL_4_ILIM_SEL GENMASK(7, 4) +#define WCD939X_VNEG_CTRL_4_PW_BUF_POS GENMASK(3, 2) +#define WCD939X_VNEG_CTRL_4_PW_BUF_NEG GENMASK(1, 0) +#define WCD939X_FLYBACK_VNEG_CTRL_5 (0x30a9) +#define WCD939X_FLYBACK_VNEG_CTRL_6 (0x30aa) +#define WCD939X_FLYBACK_VNEG_CTRL_7 (0x30ab) +#define WCD939X_FLYBACK_VNEG_CTRL_8 (0x30ac) +#define WCD939X_FLYBACK_VNEG_CTRL_9 (0x30ad) +#define WCD939X_FLYBACK_VNEGDAC_CTRL_1 (0x30ae) +#define WCD939X_FLYBACK_VNEGDAC_CTRL_2 (0x30af) +#define WCD939X_FLYBACK_VNEGDAC_CTRL_3 (0x30b0) +#define WCD939X_FLYBACK_CTRL_1 (0x30b1) +#define WCD939X_FLYBACK_TEST_CTL (0x30b2) +#define WCD939X_RX_AUX_SW_CTL (0x30b3) +#define WCD939X_RX_PA_AUX_IN_CONN (0x30b4) +#define WCD939X_RX_TIMER_DIV (0x30b5) +#define WCD939X_RX_OCP_CTL (0x30b6) +#define WCD939X_RX_OCP_COUNT (0x30b7) +#define WCD939X_RX_BIAS_EAR_DAC (0x30b8) +#define WCD939X_RX_BIAS_EAR_AMP (0x30b9) +#define WCD939X_RX_BIAS_HPH_LDO (0x30ba) +#define WCD939X_RX_BIAS_HPH_PA (0x30bb) +#define WCD939X_RX_BIAS_HPH_RDACBUFF_CNP2 (0x30bc) +#define WCD939X_RX_BIAS_HPH_RDAC_LDO (0x30bd) +#define WCD939X_RX_BIAS_HPH_CNP1 (0x30be) +#define WCD939X_RX_BIAS_HPH_LOWPOWER (0x30bf) +#define WCD939X_RX_BIAS_AUX_DAC (0x30c0) +#define WCD939X_RX_BIAS_AUX_AMP (0x30c1) +#define WCD939X_RX_BIAS_VNEGDAC_BLEEDER (0x30c2) +#define WCD939X_RX_BIAS_MISC (0x30c3) +#define WCD939X_RX_BIAS_BUCK_RST (0x30c4) +#define WCD939X_RX_BIAS_BUCK_VREF_ERRAMP (0x30c5) +#define WCD939X_RX_BIAS_FLYB_ERRAMP (0x30c6) +#define WCD939X_RX_BIAS_FLYB_BUFF (0x30c7) +#define WCD939X_RX_BIAS_FLYB_MID_RST (0x30c8) +#define WCD939X_HPH_L_STATUS (0x30c9) +#define WCD939X_HPH_R_STATUS (0x30ca) +#define WCD939X_HPH_CNP_EN (0x30cb) +#define WCD939X_HPH_CNP_WG_CTL (0x30cc) +#define WCD939X_HPH_CNP_WG_TIME (0x30cd) +#define WCD939X_HPH_OCP_CTL (0x30ce) +#define WCD939X_OCP_CTL_OCP_CURR_LIMIT GENMASK(7, 5) +#define WCD939X_OCP_CTL_OCP_FSM_EN BIT(4) +#define WCD939X_OCP_CTL_SPARE_BITS BIT(3) +#define WCD939X_OCP_CTL_SCD_OP_EN BIT(1) +#define WCD939X_HPH_AUTO_CHOP (0x30cf) +#define WCD939X_HPH_CHOP_CTL (0x30d0) +#define WCD939X_HPH_PA_CTL1 (0x30d1) +#define WCD939X_HPH_PA_CTL2 (0x30d2) +#define WCD939X_PA_CTL2_HPHPA_GND_R BIT(6) +#define WCD939X_PA_CTL2_HPHPA_GND_L BIT(4) +#define WCD939X_PA_CTL2_GM3_CASCODE_CTL_NORMAL GENMASK(1, 0) +#define WCD939X_HPH_L_EN (0x30d3) +#define WCD939X_L_EN_CONST_SEL_L GENMASK(7, 6) +#define WCD939X_L_EN_GAIN_SOURCE_SEL BIT(5) +#define WCD939X_L_EN_SPARE_BITS GENMASK(4, 0) +#define WCD939X_HPH_L_TEST (0x30d4) +#define WCD939X_HPH_L_ATEST (0x30d5) +#define WCD939X_HPH_R_EN (0x30d6) +#define WCD939X_R_EN_CONST_SEL_R GENMASK(7, 6) +#define WCD939X_R_EN_GAIN_SOURCE_SEL BIT(5) +#define WCD939X_R_EN_SPARE_BITS GENMASK(4, 0) +#define WCD939X_HPH_R_TEST (0x30d7) +#define WCD939X_HPH_R_ATEST (0x30d8) +#define WCD939X_R_ATEST_DACR_REF_ATEST1_CONN BIT(7) +#define WCD939X_R_ATEST_LDO1_R_ATEST2_CONN BIT(6) +#define WCD939X_R_ATEST_LDO_R_ATEST2_CAL BIT(5) +#define WCD939X_R_ATEST_LDO2_R_ATEST2_CONN BIT(4) +#define WCD939X_R_ATEST_LDO_1P65V_ATEST1_CONN BIT(3) +#define WCD939X_R_ATEST_HPH_GND_OVR BIT(1) +#define WCD939X_HPH_RDAC_CLK_CTL1 (0x30d9) +#define WCD939X_RDAC_CLK_CTL1_OPAMP_CHOP_CLK_EN BIT(7) +#define WCD939X_RDAC_CLK_CTL1_OPAMP_CHOP_CLK_DIV_CTRL GENMASK(6, 4) +#define WCD939X_RDAC_CLK_CTL1_SPARE_BITS GENMASK(3, 0) +#define WCD939X_HPH_RDAC_CLK_CTL2 (0x30da) +#define WCD939X_HPH_RDAC_LDO_CTL (0x30db) +#define WCD939X_HPH_RDAC_CHOP_CLK_LP_CTL (0x30dc) +#define WCD939X_HPH_REFBUFF_UHQA_CTL (0x30dd) +#define WCD939X_REFBUFF_UHQA_CTL_SPARE_BITS GENMASK(7, 6) +#define WCD939X_REFBUFF_UHQA_CTL_HPH_VNEGREG2_COMP_CTL_OV BIT(5) +#define WCD939X_REFBUFF_UHQA_CTL_REFBUFN_RBIAS_ADJUST BIT(4) +#define WCD939X_REFBUFF_UHQA_CTL_REFBUFP_IOUT_CTL GENMASK(3, 2) +#define WCD939X_REFBUFF_UHQA_CTL_REFBUFN_IOUT_CTL GENMASK(1, 0) +#define WCD939X_HPH_REFBUFF_LP_CTL (0x30de) +#define WCD939X_REFBUFF_LP_CTL_HPH_VNEGREG2_CURR_COMP GENMASK(7, 6) +#define WCD939X_REFBUFF_LP_CTL_SPARE_BITS GENMASK(5, 4) +#define WCD939X_REFBUFF_LP_CTL_EN_PREREF_FILT_STARTUP_CLKDIV BIT(3) +#define WCD939X_REFBUFF_LP_CTL_PREREF_FILT_STARTUP_CLKDIV_CTL GENMASK(2, 1) +#define WCD939X_REFBUFF_LP_CTL_PREREF_FILT_BYPASS BIT(0) +#define WCD939X_HPH_L_DAC_CTL (0x30df) +#define WCD939X_HPH_R_DAC_CTL (0x30e0) +#define WCD939X_HPH_SURGE_COMP_SEL (0x30e1) +#define WCD939X_HPH_SURGE_EN (0x30e2) +#define WCD939X_EN_EN_SURGE_PROTECTION_HPHL BIT(7) +#define WCD939X_EN_EN_SURGE_PROTECTION_HPHR BIT(6) +#define WCD939X_EN_SEL_SURGE_COMP_IQ GENMASK(5, 4) +#define WCD939X_EN_SURGE_VOLT_MODE_SHUTOFF_EN BIT(3) +#define WCD939X_EN_LATCH_INTR_OP_STG_HIZ_EN BIT(2) +#define WCD939X_EN_SURGE_LATCH_REG_RESET BIT(1) +#define WCD939X_EN_SWTICH_VN_VNDAC_NSURGE_EN BIT(0) +#define WCD939X_HPH_SURGE_MISC1 (0x30e3) +#define WCD939X_HPH_SURGE_STATUS (0x30e4) +#define WCD939X_EAR_EN (0x30e9) +#define WCD939X_EAR_PA_CON (0x30ea) +#define WCD939X_EAR_SP_CON (0x30eb) +#define WCD939X_EAR_DAC_CON (0x30ec) +#define WCD939X_DAC_CON_DAC_SAMPLE_EDGE_SEL BIT(7) +#define WCD939X_DAC_CON_REF_DBG_EN BIT(6) +#define WCD939X_DAC_CON_REF_DBG_GAIN GENMASK(5, 3) +#define WCD939X_DAC_CON_GAIN_DAC GENMASK(2, 1) +#define WCD939X_DAC_CON_INV_DATA BIT(0) +#define WCD939X_EAR_CNP_FSM_CON (0x30ed) +#define WCD939X_EAR_TEST_CTL (0x30ee) +#define WCD939X_EAR_STATUS_REG_1 (0x30ef) +#define WCD939X_EAR_STATUS_REG_2 (0x30f0) +#define WCD939X_FLYBACK_NEW_CTRL_2 (0x30f6) +#define WCD939X_FLYBACK_NEW_CTRL_3 (0x30f7) +#define WCD939X_FLYBACK_NEW_CTRL_4 (0x30f8) +#define WCD939X_ANA_NEW_PAGE (0x3100) +#define WCD939X_HPH_NEW_ANA_HPH2 (0x3101) +#define WCD939X_HPH_NEW_ANA_HPH3 (0x3102) +#define WCD939X_SLEEP_CTL (0x3103) +#define WCD939X_SLEEP_WATCHDOG_CTL (0x3104) +#define WCD939X_MBHC_NEW_ELECT_REM_CLAMP_CTL (0x311f) +#define WCD939X_MBHC_NEW_CTL_1 (0x3120) +#define WCD939X_CTL_1_RCO_EN BIT(7) +#define WCD939X_CTL_1_ADC_MODE BIT(4) +#define WCD939X_CTL_1_ADC_ENABLE BIT(3) +#define WCD939X_CTL_1_DETECTION_DONE BIT(2) +#define WCD939X_CTL_1_BTN_DBNC_CTL GENMASK(1, 0) +#define WCD939X_MBHC_NEW_CTL_2 (0x3121) +#define WCD939X_CTL_2_MUX_CTL GENMASK(6, 4) +#define WCD939X_CTL_2_M_RTH_CTL GENMASK(3, 2) +#define WCD939X_CTL_2_HS_VREF_CTL GENMASK(1, 0) +#define WCD939X_MBHC_NEW_PLUG_DETECT_CTL (0x3122) +#define WCD939X_MBHC_NEW_ZDET_ANA_CTL (0x3123) +#define WCD939X_ZDET_ANA_CTL_AVERAGING_EN BIT(7) +#define WCD939X_ZDET_ANA_CTL_MAXV_CTL GENMASK(6, 4) +#define WCD939X_ZDET_ANA_CTL_RANGE_CTL GENMASK(3, 0) +#define WCD939X_MBHC_NEW_ZDET_RAMP_CTL (0x3124) +#define WCD939X_ZDET_RAMP_CTL_ACC1_MIN_CTL GENMASK(6, 4) +#define WCD939X_ZDET_RAMP_CTL_TIME_CTL GENMASK(3, 0) +#define WCD939X_MBHC_NEW_FSM_STATUS (0x3125) +#define WCD939X_FSM_STATUS_ADC_TIMEOUT BIT(7) +#define WCD939X_FSM_STATUS_ADC_COMPLETE BIT(6) +#define WCD939X_FSM_STATUS_HS_M_COMP_STATUS BIT(5) +#define WCD939X_FSM_STATUS_FAST_PRESS_FLAG_STATUS BIT(4) +#define WCD939X_FSM_STATUS_FAST_REMOVAL_FLAG_STATUS BIT(3) +#define WCD939X_FSM_STATUS_REMOVAL_FLAG_STATUS BIT(2) +#define WCD939X_FSM_STATUS_ELECT_REM_RT_STATUS BIT(1) +#define WCD939X_FSM_STATUS_BTN_STATUS BIT(0) +#define WCD939X_MBHC_NEW_ADC_RESULT (0x3126) +#define WCD939X_ADC_RESULT_VALUE GENMASK(7, 0) +#define WCD939X_TX_NEW_CH12_MUX (0x3127) +#define WCD939X_TX_NEW_CH34_MUX (0x3128) +#define WCD939X_DIE_CRACK_DET_EN (0x312c) +#define WCD939X_DIE_CRACK_DET_OUT (0x312d) +#define WCD939X_HPH_NEW_INT_RDAC_GAIN_CTL (0x3132) +#define WCD939X_HPH_NEW_INT_PA_GAIN_CTL_L (0x3133) +#define WCD939X_PA_GAIN_CTL_L_EN_HPHPA_2VPK BIT(7) +#define WCD939X_PA_GAIN_CTL_L_RX_SUPPLY_LEVEL BIT(6) +#define WCD939X_PA_GAIN_CTL_L_DAC_DR_BOOST BIT(5) +#define WCD939X_PA_GAIN_CTL_L_VALUE GENMASK(4, 0) +#define WCD939X_HPH_NEW_INT_RDAC_VREF_CTL (0x3134) +#define WCD939X_HPH_NEW_INT_RDAC_OVERRIDE_CTL (0x3135) +#define WCD939X_HPH_NEW_INT_PA_GAIN_CTL_R (0x3136) +#define WCD939X_PA_GAIN_CTL_R_D_RCO_CLK_EN BIT(7) +#define WCD939X_PA_GAIN_CTL_R_SPARE_BITS GENMASK(6, 5) +#define WCD939X_PA_GAIN_CTL_R_VALUE GENMASK(4, 0) +#define WCD939X_HPH_NEW_INT_PA_MISC1 (0x3137) +#define WCD939X_HPH_NEW_INT_PA_MISC2 (0x3138) +#define WCD939X_HPH_NEW_INT_PA_RDAC_MISC (0x3139) +#define WCD939X_HPH_NEW_INT_TIMER1 (0x313a) +#define WCD939X_TIMER1_CURR_IDIV_CTL_CMPDR_OFF GENMASK(7, 5) +#define WCD939X_TIMER1_CURR_IDIV_CTL_AUTOCHOP GENMASK(4, 2) +#define WCD939X_TIMER1_AUTOCHOP_TIMER_CTL_EN BIT(1) +#define WCD939X_HPH_NEW_INT_TIMER2 (0x313b) +#define WCD939X_HPH_NEW_INT_TIMER3 (0x313c) +#define WCD939X_HPH_NEW_INT_TIMER4 (0x313d) +#define WCD939X_HPH_NEW_INT_PA_RDAC_MISC2 (0x313e) +#define WCD939X_HPH_NEW_INT_PA_RDAC_MISC3 (0x313f) +#define WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_L (0x3140) +#define WCD939X_RDAC_HD2_CTL_L_EN_HD2_RES_DIV_L BIT(7) +#define WCD939X_RDAC_HD2_CTL_L_HD2_RES_DIV_PULLGND_L BIT(6) +#define WCD939X_RDAC_HD2_CTL_L_HD2_RES_DIV_CTL_L GENMASK(5, 0) +#define WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_R (0x3141) +#define WCD939X_RDAC_HD2_CTL_R_EN_HD2_RES_DIV_R BIT(7) +#define WCD939X_RDAC_HD2_CTL_R_HD2_RES_DIV_PULLGND_L BIT(6) +#define WCD939X_RDAC_HD2_CTL_R_HD2_RES_DIV_CTL_R GENMASK(5, 0) +#define WCD939X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI (0x3145) +#define WCD939X_RX_NEW_INT_HPH_RDAC_BIAS_ULP (0x3146) +#define WCD939X_RX_NEW_INT_HPH_RDAC_LDO_LP (0x3147) +#define WCD939X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL (0x31af) +#define WCD939X_MOISTURE_DET_DC_CTRL_ONCOUNT GENMASK(6, 5) +#define WCD939X_MOISTURE_DET_DC_CTRL_OFFCOUNT GENMASK(4, 0) +#define WCD939X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL (0x31b0) +#define WCD939X_MOISTURE_DET_POLLING_CTRL_HPHL_PA_EN BIT(6) +#define WCD939X_MOISTURE_DET_POLLING_CTRL_DTEST_EN GENMASK(5, 4) +#define WCD939X_MOISTURE_DET_POLLING_CTRL_MOIST_OVRD_POLLING BIT(3) +#define WCD939X_MOISTURE_DET_POLLING_CTRL_MOIST_EN_POLLING BIT(2) +#define WCD939X_MOISTURE_DET_POLLING_CTRL_MOIST_DBNC_TIME GENMASK(1, 0) +#define WCD939X_MBHC_NEW_INT_MECH_DET_CURRENT (0x31b1) +#define WCD939X_MECH_DET_CURRENT_HSDET_PULLUP_CTL GENMASK(4, 0) +#define WCD939X_MBHC_NEW_INT_ZDET_CLK_AND_MOISTURE_CTL_NEW (0x31b2) +#define WCD939X_EAR_INT_NEW_CHOPPER_CON (0x31b7) +#define WCD939X_EAR_INT_NEW_CNP_VCM_CON1 (0x31b8) +#define WCD939X_EAR_INT_NEW_CNP_VCM_CON2 (0x31b9) +#define WCD939X_EAR_INT_NEW_DYNAMIC_BIAS (0x31ba) +#define WCD939X_SLEEP_INT_WATCHDOG_CTL_1 (0x31d0) +#define WCD939X_SLEEP_INT_WATCHDOG_CTL_2 (0x31d1) +#define WCD939X_DIE_CRACK_INT_DET_INT1 (0x31d3) +#define WCD939X_DIE_CRACK_INT_DET_INT2 (0x31d4) +#define WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_L2 (0x31d5) +#define WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_L1 (0x31d6) +#define WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_L0 (0x31d7) +#define WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_ULP1P2M (0x31d8) +#define WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_ULP0P6M (0x31d9) +#define WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG1_L2L1 (0x31da) +#define WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG1_L0 (0x31db) +#define WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG1_ULP (0x31dc) +#define WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2MAIN_L2L1 (0x31dd) +#define WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2MAIN_L0 (0x31de) +#define WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2MAIN_ULP (0x31df) +#define WCD939X_FE_ICTRL_STG2MAIN_ULP_VALUE GENMASK(4, 0) +#define WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2CASC_L2L1L0 (0x31e0) +#define WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2CASC_ULP (0x31e1) +#define WCD939X_FE_ICTRL_STG2CASC_ULP_ICTRL_SCBIAS_ULP0P6M GENMASK(7, 4) +#define WCD939X_FE_ICTRL_STG2CASC_ULP_VALUE GENMASK(3, 0) +#define WCD939X_TX_COM_NEW_INT_ADC_SCBIAS_L2L1 (0x31e2) +#define WCD939X_TX_COM_NEW_INT_ADC_SCBIAS_L0ULP (0x31e3) +#define WCD939X_TX_COM_NEW_INT_ADC_INT_L2 (0x31e4) +#define WCD939X_TX_COM_NEW_INT_ADC_INT_L1 (0x31e5) +#define WCD939X_TX_COM_NEW_INT_ADC_INT_L0 (0x31e6) +#define WCD939X_TX_COM_NEW_INT_ADC_INT_ULP (0x31e7) +#define WCD939X_DIGITAL_PAGE (0x3400) +#define WCD939X_DIGITAL_CHIP_ID0 (0x3401) +#define WCD939X_DIGITAL_CHIP_ID1 (0x3402) +#define WCD939X_DIGITAL_CHIP_ID2 (0x3403) +#define WCD939X_DIGITAL_CHIP_ID3 (0x3404) +#define WCD939X_DIGITAL_SWR_TX_CLK_RATE (0x3405) +#define WCD939X_DIGITAL_CDC_RST_CTL (0x3406) +#define WCD939X_DIGITAL_TOP_CLK_CFG (0x3407) +#define WCD939X_DIGITAL_CDC_ANA_CLK_CTL (0x3408) +#define WCD939X_CDC_ANA_CLK_CTL_ANA_TX_DIV4_CLK_EN BIT(5) +#define WCD939X_CDC_ANA_CLK_CTL_ANA_TX_DIV2_CLK_EN BIT(4) +#define WCD939X_CDC_ANA_CLK_CTL_ANA_TX_CLK_EN BIT(3) +#define WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV4_CLK_EN BIT(2) +#define WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV2_CLK_EN BIT(1) +#define WCD939X_CDC_ANA_CLK_CTL_ANA_RX_CLK_EN BIT(0) +#define WCD939X_CDC_ANA_CLK_CTL_ANA_TX_DIV2_CLK_EN BIT(4) +#define WCD939X_DIGITAL_CDC_DIG_CLK_CTL (0x3409) +#define WCD939X_CDC_DIG_CLK_CTL_TXD3_CLK_EN BIT(7) +#define WCD939X_CDC_DIG_CLK_CTL_TXD2_CLK_EN BIT(6) +#define WCD939X_CDC_DIG_CLK_CTL_TXD1_CLK_EN BIT(5) +#define WCD939X_CDC_DIG_CLK_CTL_TXD0_CLK_EN BIT(4) +#define WCD939X_CDC_DIG_CLK_CTL_RXD2_CLK_EN BIT(2) +#define WCD939X_CDC_DIG_CLK_CTL_RXD1_CLK_EN BIT(1) +#define WCD939X_CDC_DIG_CLK_CTL_RXD0_CLK_EN BIT(0) +#define WCD939X_DIGITAL_SWR_RST_EN (0x340a) +#define WCD939X_DIGITAL_CDC_PATH_MODE (0x340b) +#define WCD939X_DIGITAL_CDC_RX_RST (0x340c) +#define WCD939X_DIGITAL_CDC_RX0_CTL (0x340d) +#define WCD939X_DIGITAL_CDC_RX1_CTL (0x340e) +#define WCD939X_DIGITAL_CDC_RX2_CTL (0x340f) +#define WCD939X_DIGITAL_CDC_TX_ANA_MODE_0_1 (0x3410) +#define WCD939X_CDC_TX_ANA_MODE_0_1_TXD1_MODE GENMASK(7, 4) +#define WCD939X_CDC_TX_ANA_MODE_0_1_TXD0_MODE GENMASK(3, 0) +#define WCD939X_DIGITAL_CDC_TX_ANA_MODE_2_3 (0x3411) +#define WCD939X_CDC_TX_ANA_MODE_2_3_TXD3_MODE GENMASK(7, 4) +#define WCD939X_CDC_TX_ANA_MODE_2_3_TXD2_MODE GENMASK(3, 0) +#define WCD939X_DIGITAL_CDC_COMP_CTL_0 (0x3414) +#define WCD939X_CDC_COMP_CTL_0_HPHL_COMP_EN BIT(1) +#define WCD939X_CDC_COMP_CTL_0_HPHR_COMP_EN BIT(0) +#define WCD939X_DIGITAL_CDC_ANA_TX_CLK_CTL (0x3417) +#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_MBHC_1P2M_CLK_EN BIT(5) +#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TX3_ADC_CLK_EN BIT(4) +#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TX2_ADC_CLK_EN BIT(3) +#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TX1_ADC_CLK_EN BIT(2) +#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TX0_ADC_CLK_EN BIT(1) +#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TXSCBIAS_CLK_EN BIT(0) +#define WCD939X_DIGITAL_CDC_HPH_DSM_A1_0 (0x3418) +#define WCD939X_DIGITAL_CDC_HPH_DSM_A1_1 (0x3419) +#define WCD939X_DIGITAL_CDC_HPH_DSM_A2_0 (0x341a) +#define WCD939X_DIGITAL_CDC_HPH_DSM_A2_1 (0x341b) +#define WCD939X_DIGITAL_CDC_HPH_DSM_A3_0 (0x341c) +#define WCD939X_DIGITAL_CDC_HPH_DSM_A3_1 (0x341d) +#define WCD939X_DIGITAL_CDC_HPH_DSM_A4_0 (0x341e) +#define WCD939X_DIGITAL_CDC_HPH_DSM_A4_1 (0x341f) +#define WCD939X_DIGITAL_CDC_HPH_DSM_A5_0 (0x3420) +#define WCD939X_DIGITAL_CDC_HPH_DSM_A5_1 (0x3421) +#define WCD939X_DIGITAL_CDC_HPH_DSM_A6_0 (0x3422) +#define WCD939X_DIGITAL_CDC_HPH_DSM_A7_0 (0x3423) +#define WCD939X_DIGITAL_CDC_HPH_DSM_C_0 (0x3424) +#define WCD939X_DIGITAL_CDC_HPH_DSM_C_1 (0x3425) +#define WCD939X_DIGITAL_CDC_HPH_DSM_C_2 (0x3426) +#define WCD939X_DIGITAL_CDC_HPH_DSM_C_3 (0x3427) +#define WCD939X_DIGITAL_CDC_HPH_DSM_R1 (0x3428) +#define WCD939X_DIGITAL_CDC_HPH_DSM_R2 (0x3429) +#define WCD939X_DIGITAL_CDC_HPH_DSM_R3 (0x342a) +#define WCD939X_DIGITAL_CDC_HPH_DSM_R4 (0x342b) +#define WCD939X_DIGITAL_CDC_HPH_DSM_R5 (0x342c) +#define WCD939X_DIGITAL_CDC_HPH_DSM_R6 (0x342d) +#define WCD939X_DIGITAL_CDC_HPH_DSM_R7 (0x342e) +#define WCD939X_DIGITAL_CDC_EAR_DSM_A1_0 (0x342f) +#define WCD939X_DIGITAL_CDC_EAR_DSM_A1_1 (0x3430) +#define WCD939X_DIGITAL_CDC_EAR_DSM_A2_0 (0x3431) +#define WCD939X_DIGITAL_CDC_EAR_DSM_A2_1 (0x3432) +#define WCD939X_DIGITAL_CDC_EAR_DSM_A3_0 (0x3433) +#define WCD939X_DIGITAL_CDC_EAR_DSM_A3_1 (0x3434) +#define WCD939X_DIGITAL_CDC_EAR_DSM_A4_0 (0x3435) +#define WCD939X_DIGITAL_CDC_EAR_DSM_A4_1 (0x3436) +#define WCD939X_DIGITAL_CDC_EAR_DSM_A5_0 (0x3437) +#define WCD939X_DIGITAL_CDC_EAR_DSM_A5_1 (0x3438) +#define WCD939X_DIGITAL_CDC_EAR_DSM_A6_0 (0x3439) +#define WCD939X_DIGITAL_CDC_EAR_DSM_A7_0 (0x343a) +#define WCD939X_DIGITAL_CDC_EAR_DSM_C_0 (0x343b) +#define WCD939X_DIGITAL_CDC_EAR_DSM_C_1 (0x343c) +#define WCD939X_DIGITAL_CDC_EAR_DSM_C_2 (0x343d) +#define WCD939X_DIGITAL_CDC_EAR_DSM_C_3 (0x343e) +#define WCD939X_DIGITAL_CDC_EAR_DSM_R1 (0x343f) +#define WCD939X_DIGITAL_CDC_EAR_DSM_R2 (0x3440) +#define WCD939X_DIGITAL_CDC_EAR_DSM_R3 (0x3441) +#define WCD939X_DIGITAL_CDC_EAR_DSM_R4 (0x3442) +#define WCD939X_DIGITAL_CDC_EAR_DSM_R5 (0x3443) +#define WCD939X_DIGITAL_CDC_EAR_DSM_R6 (0x3444) +#define WCD939X_DIGITAL_CDC_EAR_DSM_R7 (0x3445) +#define WCD939X_DIGITAL_CDC_HPH_GAIN_RX_0 (0x3446) +#define WCD939X_DIGITAL_CDC_HPH_GAIN_RX_1 (0x3447) +#define WCD939X_DIGITAL_CDC_HPH_GAIN_DSD_0 (0x3448) +#define WCD939X_DIGITAL_CDC_HPH_GAIN_DSD_1 (0x3449) +#define WCD939X_DIGITAL_CDC_HPH_GAIN_DSD_2 (0x344a) +#define WCD939X_DIGITAL_CDC_EAR_GAIN_DSD_0 (0x344b) +#define WCD939X_DIGITAL_CDC_EAR_GAIN_DSD_1 (0x344c) +#define WCD939X_DIGITAL_CDC_EAR_GAIN_DSD_2 (0x344d) +#define WCD939X_DIGITAL_CDC_HPH_GAIN_CTL (0x344e) +#define WCD939X_CDC_HPH_GAIN_CTL_HPH_STEREO_EN BIT(4) +#define WCD939X_CDC_HPH_GAIN_CTL_HPHR_RX_EN BIT(3) +#define WCD939X_CDC_HPH_GAIN_CTL_HPHL_RX_EN BIT(2) +#define WCD939X_CDC_HPH_GAIN_CTL_HPHR_DSD_EN BIT(1) +#define WCD939X_CDC_HPH_GAIN_CTL_HPHL_DSD_EN BIT(0) +#define WCD939X_DIGITAL_CDC_EAR_GAIN_CTL (0x344f) +#define WCD939X_CDC_EAR_GAIN_CTL_EAR_EN BIT(0) +#define WCD939X_DIGITAL_CDC_EAR_PATH_CTL (0x3450) +#define WCD939X_DIGITAL_CDC_SWR_CLH (0x3451) +#define WCD939X_CDC_SWR_CLH_CLH_CTL GENMASK(7, 0) +#define WCD939X_DIGITAL_SWR_CLH_BYP (0x3452) +#define WCD939X_DIGITAL_CDC_TX0_CTL (0x3453) +#define WCD939X_DIGITAL_CDC_TX1_CTL (0x3454) +#define WCD939X_DIGITAL_CDC_TX2_CTL (0x3455) +#define WCD939X_DIGITAL_CDC_TX_RST (0x3456) +#define WCD939X_DIGITAL_CDC_REQ_CTL (0x3457) +#define WCD939X_CDC_REQ_CTL_TX3_WIDE_BAND BIT(5) +#define WCD939X_CDC_REQ_CTL_TX2_WIDE_BAND BIT(4) +#define WCD939X_CDC_REQ_CTL_TX1_WIDE_BAND BIT(3) +#define WCD939X_CDC_REQ_CTL_TX0_WIDE_BAND BIT(2) +#define WCD939X_CDC_REQ_CTL_FS_RATE_4P8 BIT(1) +#define WCD939X_CDC_REQ_CTL_NO_NOTCH BIT(0) +#define WCD939X_DIGITAL_CDC_RST (0x3458) +#define WCD939X_DIGITAL_CDC_AMIC_CTL (0x345a) +#define WCD939X_CDC_AMIC_CTL_AMIC5_IN_SEL BIT(3) +#define WCD939X_CDC_AMIC_CTL_AMIC4_IN_SEL BIT(2) +#define WCD939X_CDC_AMIC_CTL_AMIC3_IN_SEL BIT(1) +#define WCD939X_CDC_AMIC_CTL_AMIC1_IN_SEL BIT(0) +#define WCD939X_DIGITAL_CDC_DMIC_CTL (0x345b) +#define WCD939X_CDC_DMIC_CTL_DMIC_LEGACY_SW_MODE BIT(3) +#define WCD939X_CDC_DMIC_CTL_DMIC_DIV_BAK_EN BIT(2) +#define WCD939X_CDC_DMIC_CTL_CLK_SCALE_EN BIT(1) +#define WCD939X_CDC_DMIC_CTL_SOFT_RESET BIT(0) +#define WCD939X_DIGITAL_CDC_DMIC1_CTL (0x345c) +#define WCD939X_CDC_DMIC1_CTL_DMIC_CLK_SCALE_SEL GENMASK(6, 4) +#define WCD939X_CDC_DMIC1_CTL_DMIC_CLK_EN BIT(3) +#define WCD939X_CDC_DMIC1_CTL_DMIC_CLK_SEL GENMASK(2, 0) +#define WCD939X_DIGITAL_CDC_DMIC2_CTL (0x345d) +#define WCD939X_CDC_DMIC2_CTL_DMIC_LEFT_EN BIT(7) +#define WCD939X_CDC_DMIC2_CTL_DMIC_CLK_SCALE_SEL GENMASK(6, 4) +#define WCD939X_CDC_DMIC2_CTL_DMIC_CLK_EN BIT(3) +#define WCD939X_CDC_DMIC2_CTL_DMIC_CLK_SEL GENMASK(2, 0) +#define WCD939X_DIGITAL_CDC_DMIC3_CTL (0x345e) +#define WCD939X_CDC_DMIC3_CTL_DMIC_CLK_SCALE_SEL GENMASK(6, 4) +#define WCD939X_CDC_DMIC3_CTL_DMIC_CLK_EN BIT(3) +#define WCD939X_CDC_DMIC3_CTL_DMIC_CLK_SEL GENMASK(2, 0) +#define WCD939X_DIGITAL_CDC_DMIC4_CTL (0x345f) +#define WCD939X_CDC_DMIC4_CTL_DMIC_CLK_SCALE_SEL GENMASK(6, 4) +#define WCD939X_CDC_DMIC4_CTL_DMIC_CLK_EN BIT(3) +#define WCD939X_CDC_DMIC4_CTL_DMIC_CLK_SEL GENMASK(2, 0) +#define WCD939X_DIGITAL_EFUSE_PRG_CTL (0x3460) +#define WCD939X_DIGITAL_EFUSE_CTL (0x3461) +#define WCD939X_DIGITAL_CDC_DMIC_RATE_1_2 (0x3462) +#define WCD939X_CDC_DMIC_RATE_1_2_DMIC2_RATE GENMASK(7, 4) +#define WCD939X_CDC_DMIC_RATE_1_2_DMIC1_RATE GENMASK(3, 0) +#define WCD939X_DIGITAL_CDC_DMIC_RATE_3_4 (0x3463) +#define WCD939X_CDC_DMIC_RATE_3_4_DMIC4_RATE GENMASK(7, 4) +#define WCD939X_CDC_DMIC_RATE_3_4_DMIC3_RATE GENMASK(3, 0) +#define WCD939X_DIGITAL_PDM_WD_CTL0 (0x3465) +#define WCD939X_PDM_WD_CTL0_HOLD_OFF BIT(4) +#define WCD939X_PDM_WD_CTL0_TIME_OUT_SEL BIT(3) +#define WCD939X_PDM_WD_CTL0_PDM_WD_EN GENMASK(2, 0) +#define WCD939X_DIGITAL_PDM_WD_CTL1 (0x3466) +#define WCD939X_PDM_WD_CTL1_HOLD_OFF BIT(4) +#define WCD939X_PDM_WD_CTL1_TIME_OUT_SEL BIT(3) +#define WCD939X_PDM_WD_CTL1_PDM_WD_EN GENMASK(2, 0) +#define WCD939X_DIGITAL_PDM_WD_CTL2 (0x3467) +#define WCD939X_DIGITAL_INTR_MODE (0x346a) +#define WCD939X_DIGITAL_INTR_MASK_0 (0x346b) +#define WCD939X_DIGITAL_INTR_MASK_1 (0x346c) +#define WCD939X_DIGITAL_INTR_MASK_2 (0x346d) +#define WCD939X_DIGITAL_INTR_STATUS_0 (0x346e) +#define WCD939X_DIGITAL_INTR_STATUS_1 (0x346f) +#define WCD939X_DIGITAL_INTR_STATUS_2 (0x3470) +#define WCD939X_DIGITAL_INTR_CLEAR_0 (0x3471) +#define WCD939X_DIGITAL_INTR_CLEAR_1 (0x3472) +#define WCD939X_DIGITAL_INTR_CLEAR_2 (0x3473) +#define WCD939X_DIGITAL_INTR_LEVEL_0 (0x3474) +#define WCD939X_DIGITAL_INTR_LEVEL_1 (0x3475) +#define WCD939X_DIGITAL_INTR_LEVEL_2 (0x3476) +#define WCD939X_DIGITAL_INTR_SET_0 (0x3477) +#define WCD939X_DIGITAL_INTR_SET_1 (0x3478) +#define WCD939X_DIGITAL_INTR_SET_2 (0x3479) +#define WCD939X_DIGITAL_INTR_TEST_0 (0x347a) +#define WCD939X_DIGITAL_INTR_TEST_1 (0x347b) +#define WCD939X_DIGITAL_INTR_TEST_2 (0x347c) +#define WCD939X_DIGITAL_TX_MODE_DBG_EN (0x347f) +#define WCD939X_DIGITAL_TX_MODE_DBG_0_1 (0x3480) +#define WCD939X_DIGITAL_TX_MODE_DBG_2_3 (0x3481) +#define WCD939X_DIGITAL_LB_IN_SEL_CTL (0x3482) +#define WCD939X_DIGITAL_LOOP_BACK_MODE (0x3483) +#define WCD939X_DIGITAL_SWR_DAC_TEST (0x3484) +#define WCD939X_DIGITAL_SWR_HM_TEST_RX_0 (0x3485) +#define WCD939X_DIGITAL_SWR_HM_TEST_TX_0 (0x3486) +#define WCD939X_DIGITAL_SWR_HM_TEST_RX_1 (0x3487) +#define WCD939X_DIGITAL_SWR_HM_TEST_TX_1 (0x3488) +#define WCD939X_DIGITAL_SWR_HM_TEST_TX_2 (0x3489) +#define WCD939X_DIGITAL_SWR_HM_TEST_0 (0x348a) +#define WCD939X_DIGITAL_SWR_HM_TEST_1 (0x348b) +#define WCD939X_DIGITAL_PAD_CTL_SWR_0 (0x348c) +#define WCD939X_DIGITAL_PAD_CTL_SWR_1 (0x348d) +#define WCD939X_DIGITAL_I2C_CTL (0x348e) +#define WCD939X_DIGITAL_CDC_TX_TANGGU_SW_MODE (0x348f) +#define WCD939X_DIGITAL_EFUSE_TEST_CTL_0 (0x3490) +#define WCD939X_DIGITAL_EFUSE_TEST_CTL_1 (0x3491) +#define WCD939X_DIGITAL_EFUSE_T_DATA_0 (0x3492) +#define WCD939X_DIGITAL_EFUSE_T_DATA_1 (0x3493) +#define WCD939X_DIGITAL_PAD_CTL_PDM_RX0 (0x3494) +#define WCD939X_DIGITAL_PAD_CTL_PDM_RX1 (0x3495) +#define WCD939X_DIGITAL_PAD_CTL_PDM_TX0 (0x3496) +#define WCD939X_DIGITAL_PAD_CTL_PDM_TX1 (0x3497) +#define WCD939X_DIGITAL_PAD_CTL_PDM_TX2 (0x3498) +#define WCD939X_DIGITAL_PAD_INP_DIS_0 (0x3499) +#define WCD939X_DIGITAL_PAD_INP_DIS_1 (0x349a) +#define WCD939X_DIGITAL_DRIVE_STRENGTH_0 (0x349b) +#define WCD939X_DIGITAL_DRIVE_STRENGTH_1 (0x349c) +#define WCD939X_DIGITAL_DRIVE_STRENGTH_2 (0x349d) +#define WCD939X_DIGITAL_RX_DATA_EDGE_CTL (0x349e) +#define WCD939X_DIGITAL_TX_DATA_EDGE_CTL (0x349f) +#define WCD939X_DIGITAL_GPIO_MODE (0x34a0) +#define WCD939X_DIGITAL_PIN_CTL_OE (0x34a1) +#define WCD939X_DIGITAL_PIN_CTL_DATA_0 (0x34a2) +#define WCD939X_DIGITAL_PIN_CTL_DATA_1 (0x34a3) +#define WCD939X_DIGITAL_PIN_STATUS_0 (0x34a4) +#define WCD939X_DIGITAL_PIN_STATUS_1 (0x34a5) +#define WCD939X_DIGITAL_DIG_DEBUG_CTL (0x34a6) +#define WCD939X_DIGITAL_DIG_DEBUG_EN (0x34a7) +#define WCD939X_DIGITAL_ANA_CSR_DBG_ADD (0x34a8) +#define WCD939X_DIGITAL_ANA_CSR_DBG_CTL (0x34a9) +#define WCD939X_DIGITAL_SSP_DBG (0x34aa) +#define WCD939X_DIGITAL_MODE_STATUS_0 (0x34ab) +#define WCD939X_DIGITAL_MODE_STATUS_1 (0x34ac) +#define WCD939X_DIGITAL_SPARE_0 (0x34ad) +#define WCD939X_DIGITAL_SPARE_1 (0x34ae) +#define WCD939X_DIGITAL_SPARE_2 (0x34af) +#define WCD939X_DIGITAL_EFUSE_REG_0 (0x34b0) +#define WCD939X_EFUSE_REG_0_WCD939X_ID GENMASK(4, 1) +#define WCD939X_EFUSE_REG_0_EFUSE_BLOWN BIT(0) +#define WCD939X_DIGITAL_EFUSE_REG_1 (0x34b1) +#define WCD939X_DIGITAL_EFUSE_REG_2 (0x34b2) +#define WCD939X_DIGITAL_EFUSE_REG_3 (0x34b3) +#define WCD939X_DIGITAL_EFUSE_REG_4 (0x34b4) +#define WCD939X_DIGITAL_EFUSE_REG_5 (0x34b5) +#define WCD939X_DIGITAL_EFUSE_REG_6 (0x34b6) +#define WCD939X_DIGITAL_EFUSE_REG_7 (0x34b7) +#define WCD939X_DIGITAL_EFUSE_REG_8 (0x34b8) +#define WCD939X_DIGITAL_EFUSE_REG_9 (0x34b9) +#define WCD939X_DIGITAL_EFUSE_REG_10 (0x34ba) +#define WCD939X_DIGITAL_EFUSE_REG_11 (0x34bb) +#define WCD939X_DIGITAL_EFUSE_REG_12 (0x34bc) +#define WCD939X_DIGITAL_EFUSE_REG_13 (0x34bd) +#define WCD939X_DIGITAL_EFUSE_REG_14 (0x34be) +#define WCD939X_DIGITAL_EFUSE_REG_15 (0x34bf) +#define WCD939X_DIGITAL_EFUSE_REG_16 (0x34c0) +#define WCD939X_DIGITAL_EFUSE_REG_17 (0x34c1) +#define WCD939X_DIGITAL_EFUSE_REG_18 (0x34c2) +#define WCD939X_DIGITAL_EFUSE_REG_19 (0x34c3) +#define WCD939X_DIGITAL_EFUSE_REG_20 (0x34c4) +#define WCD939X_DIGITAL_EFUSE_REG_21 (0x34c5) +#define WCD939X_DIGITAL_EFUSE_REG_22 (0x34c6) +#define WCD939X_DIGITAL_EFUSE_REG_23 (0x34c7) +#define WCD939X_DIGITAL_EFUSE_REG_24 (0x34c8) +#define WCD939X_DIGITAL_EFUSE_REG_25 (0x34c9) +#define WCD939X_DIGITAL_EFUSE_REG_26 (0x34ca) +#define WCD939X_DIGITAL_EFUSE_REG_27 (0x34cb) +#define WCD939X_DIGITAL_EFUSE_REG_28 (0x34cc) +#define WCD939X_DIGITAL_EFUSE_REG_29 (0x34cd) +#define WCD939X_DIGITAL_EFUSE_REG_30 (0x34ce) +#define WCD939X_DIGITAL_EFUSE_REG_31 (0x34cf) +#define WCD939X_DIGITAL_TX_REQ_FB_CTL_0 (0x34d0) +#define WCD939X_DIGITAL_TX_REQ_FB_CTL_1 (0x34d1) +#define WCD939X_DIGITAL_TX_REQ_FB_CTL_2 (0x34d2) +#define WCD939X_DIGITAL_TX_REQ_FB_CTL_3 (0x34d3) +#define WCD939X_DIGITAL_TX_REQ_FB_CTL_4 (0x34d4) +#define WCD939X_DIGITAL_DEM_BYPASS_DATA0 (0x34d5) +#define WCD939X_DIGITAL_DEM_BYPASS_DATA1 (0x34d6) +#define WCD939X_DIGITAL_DEM_BYPASS_DATA2 (0x34d7) +#define WCD939X_DIGITAL_DEM_BYPASS_DATA3 (0x34d8) +#define WCD939X_DIGITAL_DEM_SECOND_ORDER (0x34d9) +#define WCD939X_DIGITAL_DSM_CTRL (0x34da) +#define WCD939X_DIGITAL_DSM_0_STATIC_DATA_0 (0x34db) +#define WCD939X_DIGITAL_DSM_0_STATIC_DATA_1 (0x34dc) +#define WCD939X_DIGITAL_DSM_0_STATIC_DATA_2 (0x34dd) +#define WCD939X_DIGITAL_DSM_0_STATIC_DATA_3 (0x34de) +#define WCD939X_DIGITAL_DSM_1_STATIC_DATA_0 (0x34df) +#define WCD939X_DIGITAL_DSM_1_STATIC_DATA_1 (0x34e0) +#define WCD939X_DIGITAL_DSM_1_STATIC_DATA_2 (0x34e1) +#define WCD939X_DIGITAL_DSM_1_STATIC_DATA_3 (0x34e2) +#define WCD939X_RX_TOP_PAGE (0x3500) +#define WCD939X_RX_TOP_TOP_CFG0 (0x3501) +#define WCD939X_TOP_CFG0_HPH_DAC_RATE_SEL BIT(1) +#define WCD939X_TOP_CFG0_PGA_UPDATE BIT(0) +#define WCD939X_RX_TOP_HPHL_COMP_WR_LSB (0x3502) +#define WCD939X_RX_TOP_HPHL_COMP_WR_MSB (0x3503) +#define WCD939X_RX_TOP_HPHL_COMP_LUT (0x3504) +#define WCD939X_RX_TOP_HPHL_COMP_RD_LSB (0x3505) +#define WCD939X_RX_TOP_HPHL_COMP_RD_MSB (0x3506) +#define WCD939X_RX_TOP_HPHR_COMP_WR_LSB (0x3507) +#define WCD939X_RX_TOP_HPHR_COMP_WR_MSB (0x3508) +#define WCD939X_RX_TOP_HPHR_COMP_LUT (0x3509) +#define WCD939X_RX_TOP_HPHR_COMP_RD_LSB (0x350a) +#define WCD939X_RX_TOP_HPHR_COMP_RD_MSB (0x350b) +#define WCD939X_RX_TOP_DSD0_DEBUG_CFG1 (0x350c) +#define WCD939X_RX_TOP_DSD0_DEBUG_CFG2 (0x350d) +#define WCD939X_RX_TOP_DSD0_DEBUG_CFG3 (0x350e) +#define WCD939X_RX_TOP_DSD0_DEBUG_CFG4 (0x350f) +#define WCD939X_RX_TOP_DSD0_DEBUG_CFG5 (0x3510) +#define WCD939X_RX_TOP_DSD0_DEBUG_CFG6 (0x3511) +#define WCD939X_RX_TOP_DSD1_DEBUG_CFG1 (0x3512) +#define WCD939X_RX_TOP_DSD1_DEBUG_CFG2 (0x3513) +#define WCD939X_RX_TOP_DSD1_DEBUG_CFG3 (0x3514) +#define WCD939X_RX_TOP_DSD1_DEBUG_CFG4 (0x3515) +#define WCD939X_RX_TOP_DSD1_DEBUG_CFG5 (0x3516) +#define WCD939X_RX_TOP_DSD1_DEBUG_CFG6 (0x3517) +#define WCD939X_RX_TOP_HPHL_PATH_CFG0 (0x351c) +#define WCD939X_HPHL_PATH_CFG0_INT_EN BIT(1) +#define WCD939X_HPHL_PATH_CFG0_DLY_ZN_EN BIT(0) +#define WCD939X_RX_TOP_HPHL_PATH_CFG1 (0x351d) +#define WCD939X_HPHL_PATH_CFG1_DSM_SOFT_RST BIT(5) +#define WCD939X_HPHL_PATH_CFG1_INT_SOFT_RST BIT(4) +#define WCD939X_HPHL_PATH_CFG1_FMT_CONV BIT(3) +#define WCD939X_HPHL_PATH_CFG1_IDLE_OVRD_EN BIT(2) +#define WCD939X_HPHL_PATH_CFG1_RX_DC_DROOP_COEFF_SEL GENMASK(1, 0) +#define WCD939X_RX_TOP_HPHR_PATH_CFG0 (0x351e) +#define WCD939X_HPHR_PATH_CFG0_INT_EN BIT(2) +#define WCD939X_HPHR_PATH_CFG0_DLY_ZN_EN BIT(1) +#define WCD939X_RX_TOP_HPHR_PATH_CFG1 (0x351f) +#define WCD939X_HPHR_PATH_CFG1_DSM_SOFT_RST BIT(5) +#define WCD939X_HPHR_PATH_CFG1_INT_SOFT_RST BIT(4) +#define WCD939X_HPHR_PATH_CFG1_FMT_CONV BIT(3) +#define WCD939X_HPHR_PATH_CFG1_IDLE_OVRD_EN BIT(2) +#define WCD939X_HPHR_PATH_CFG1_RX_DC_DROOP_COEFF_SEL GENMASK(1, 0) +#define WCD939X_RX_TOP_PATH_CFG2 (0x3520) +#define WCD939X_RX_TOP_HPHL_PATH_SEC0 (0x3521) +#define WCD939X_RX_TOP_HPHL_PATH_SEC1 (0x3522) +#define WCD939X_RX_TOP_HPHL_PATH_SEC2 (0x3523) +#define WCD939X_RX_TOP_HPHL_PATH_SEC3 (0x3524) +#define WCD939X_RX_TOP_HPHR_PATH_SEC0 (0x3525) +#define WCD939X_RX_TOP_HPHR_PATH_SEC1 (0x3526) +#define WCD939X_RX_TOP_HPHR_PATH_SEC2 (0x3527) +#define WCD939X_RX_TOP_HPHR_PATH_SEC3 (0x3528) +#define WCD939X_RX_TOP_PATH_SEC4 (0x3529) +#define WCD939X_RX_TOP_PATH_SEC5 (0x352a) +#define WCD939X_COMPANDER_HPHL_CTL0 (0x3540) +#define WCD939X_COMPANDER_HPHL_CTL1 (0x3541) +#define WCD939X_COMPANDER_HPHL_CTL2 (0x3542) +#define WCD939X_COMPANDER_HPHL_CTL3 (0x3543) +#define WCD939X_COMPANDER_HPHL_CTL4 (0x3544) +#define WCD939X_COMPANDER_HPHL_CTL5 (0x3545) +#define WCD939X_COMPANDER_HPHL_CTL6 (0x3546) +#define WCD939X_COMPANDER_HPHL_CTL7 (0x3547) +#define WCD939X_COMPANDER_HPHL_CTL8 (0x3548) +#define WCD939X_COMPANDER_HPHL_CTL9 (0x3549) +#define WCD939X_COMPANDER_HPHL_CTL10 (0x354a) +#define WCD939X_COMPANDER_HPHL_CTL11 (0x354b) +#define WCD939X_COMPANDER_HPHL_CTL12 (0x354c) +#define WCD939X_COMPANDER_HPHL_CTL13 (0x354d) +#define WCD939X_COMPANDER_HPHL_CTL14 (0x354e) +#define WCD939X_COMPANDER_HPHL_CTL15 (0x354f) +#define WCD939X_COMPANDER_HPHL_CTL16 (0x3550) +#define WCD939X_COMPANDER_HPHL_CTL17 (0x3551) +#define WCD939X_COMPANDER_HPHL_CTL18 (0x3552) +#define WCD939X_COMPANDER_HPHL_CTL19 (0x3553) +#define WCD939X_R_CTL0 (0x3560) +#define WCD939X_R_CTL1 (0x3561) +#define WCD939X_R_CTL2 (0x3562) +#define WCD939X_R_CTL3 (0x3563) +#define WCD939X_R_CTL4 (0x3564) +#define WCD939X_R_CTL5 (0x3565) +#define WCD939X_R_CTL6 (0x3566) +#define WCD939X_R_CTL7 (0x3567) +#define WCD939X_R_CTL8 (0x3568) +#define WCD939X_R_CTL9 (0x3569) +#define WCD939X_R_CTL10 (0x356a) +#define WCD939X_R_CTL11 (0x356b) +#define WCD939X_R_CTL12 (0x356c) +#define WCD939X_R_CTL13 (0x356d) +#define WCD939X_R_CTL14 (0x356e) +#define WCD939X_R_CTL15 (0x356f) +#define WCD939X_R_CTL16 (0x3570) +#define WCD939X_R_CTL17 (0x3571) +#define WCD939X_R_CTL18 (0x3572) +#define WCD939X_R_CTL19 (0x3573) +#define WCD939X_E_PATH_CTL (0x3580) +#define WCD939X_E_CFG0 (0x3581) +#define WCD939X_CFG0_AUTO_DISABLE_ANC BIT(2) +#define WCD939X_CFG0_AUTO_DISABLE_DSD BIT(1) +#define WCD939X_CFG0_IDLE_STEREO BIT(0) +#define WCD939X_E_CFG1 (0x3582) +#define WCD939X_E_CFG2 (0x3583) +#define WCD939X_E_CFG3 (0x3584) +#define WCD939X_DSD_HPHL_PATH_CTL (0x3590) +#define WCD939X_DSD_HPHL_CFG0 (0x3591) +#define WCD939X_DSD_HPHL_CFG1 (0x3592) +#define WCD939X_DSD_HPHL_CFG2 (0x3593) +#define WCD939X_DSD_HPHL_CFG3 (0x3594) +#define WCD939X_DSD_HPHL_CFG4 (0x3595) +#define WCD939X_DSD_HPHL_CFG5 (0x3596) +#define WCD939X_DSD_HPHR_PATH_CTL (0x35a0) +#define WCD939X_DSD_HPHR_CFG0 (0x35a1) +#define WCD939X_DSD_HPHR_CFG1 (0x35a2) +#define WCD939X_DSD_HPHR_CFG2 (0x35a3) +#define WCD939X_DSD_HPHR_CFG3 (0x35a4) +#define WCD939X_DSD_HPHR_CFG4 (0x35a5) +#define WCD939X_DSD_HPHR_CFG5 (0x35a6) +#define WCD939X_MAX_REGISTER (WCD939X_DSD_HPHR_CFG5) + +#define WCD939X_MAX_SWR_PORTS (6) +#define WCD939X_MAX_RX_SWR_PORTS (6) +#define WCD939X_MAX_TX_SWR_PORTS (4) +#define WCD939X_MAX_SWR_CH_IDS (15) + +struct wcd939x_sdw_ch_info { + int port_num; + unsigned int ch_mask; +}; + +#define WCD_SDW_CH(id, pn, cmask) \ + [id] = { \ + .port_num = pn, \ + .ch_mask = cmask, \ + } + +enum wcd939x_tx_sdw_ports { + WCD939X_ADC_1_4_PORT = 1, + WCD939X_ADC_DMIC_1_2_PORT, + WCD939X_DMIC_0_3_MBHC_PORT, + WCD939X_DMIC_3_7_PORT, +}; + +enum wcd939x_tx_sdw_channels { + WCD939X_ADC1, + WCD939X_ADC2, + WCD939X_ADC3, + WCD939X_ADC4, + WCD939X_DMIC0, + WCD939X_DMIC1, + WCD939X_MBHC, + WCD939X_DMIC2, + WCD939X_DMIC3, + WCD939X_DMIC4, + WCD939X_DMIC5, + WCD939X_DMIC6, + WCD939X_DMIC7, +}; + +enum wcd939x_rx_sdw_ports { + WCD939X_HPH_PORT = 1, + WCD939X_CLSH_PORT, + WCD939X_COMP_PORT, + WCD939X_LO_PORT, + WCD939X_DSD_PORT, + WCD939X_HIFI_PCM_PORT, +}; + +enum wcd939x_rx_sdw_channels { + WCD939X_HPH_L, + WCD939X_HPH_R, + WCD939X_CLSH, + WCD939X_COMP_L, + WCD939X_COMP_R, + WCD939X_LO, + WCD939X_DSD_L, + WCD939X_DSD_R, + WCD939X_HIFI_PCM_L, + WCD939X_HIFI_PCM_R, +}; + +enum { + WCD939X_SDW_DIR_RX, + WCD939X_SDW_DIR_TX, +}; + +struct wcd939x_priv; +struct wcd939x_sdw_priv { + struct sdw_slave *sdev; + struct sdw_stream_config sconfig; + struct sdw_stream_runtime *sruntime; + struct sdw_port_config port_config[WCD939X_MAX_SWR_PORTS]; + struct wcd939x_sdw_ch_info *ch_info; + bool port_enable[WCD939X_MAX_SWR_CH_IDS]; + int active_ports; + int num_ports; + bool is_tx; + struct wcd939x_priv *wcd939x; + struct irq_domain *slave_irq; + struct regmap *regmap; +}; + +#if IS_ENABLED(CONFIG_SND_SOC_WCD939X_SDW) +int wcd939x_sdw_free(struct wcd939x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); +int wcd939x_sdw_set_sdw_stream(struct wcd939x_sdw_priv *wcd, + struct snd_soc_dai *dai, + void *stream, int direction); +int wcd939x_sdw_hw_params(struct wcd939x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); + +struct device *wcd939x_sdw_device_get(struct device_node *np); +unsigned int wcd939x_swr_get_current_bank(struct sdw_slave *sdev); + +struct regmap *wcd939x_swr_get_regmap(struct wcd939x_sdw_priv *wcd); +#else + +static inline int wcd939x_sdw_free(struct wcd939x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + return -EOPNOTSUPP; +} + +static inline int wcd939x_sdw_set_sdw_stream(struct wcd939x_sdw_priv *wcd, + struct snd_soc_dai *dai, + void *stream, int direction) +{ + return -EOPNOTSUPP; +} + +static inline int wcd939x_sdw_hw_params(struct wcd939x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + return -EOPNOTSUPP; +} + +static inline struct device *wcd939x_sdw_device_get(struct device_node *np) +{ + return NULL; +} + +static inline unsigned int wcd939x_swr_get_current_bank(struct sdw_slave *sdev) +{ + return 0; +} + +struct regmap *wcd939x_swr_get_regmap(struct wcd939x_sdw_priv *wcd) +{ + return PTR_ERR(-EINVAL); +} +#endif /* CONFIG_SND_SOC_WCD939X_SDW */ + +#endif /* __WCD939X_H__ */ diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c index 63f1f05da947..6be074ea0b3f 100644 --- a/sound/soc/fsl/eukrea-tlv320.c +++ b/sound/soc/fsl/eukrea-tlv320.c @@ -196,7 +196,7 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) } } - ret = snd_soc_register_card(&eukrea_tlv320); + ret = devm_snd_soc_register_card(&pdev->dev, &eukrea_tlv320); err: if (ret) dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); @@ -205,11 +205,6 @@ err: return ret; } -static void eukrea_tlv320_remove(struct platform_device *pdev) -{ - snd_soc_unregister_card(&eukrea_tlv320); -} - static const struct of_device_id imx_tlv320_dt_ids[] = { { .compatible = "eukrea,asoc-tlv320"}, { /* sentinel */ } @@ -222,7 +217,6 @@ static struct platform_driver eukrea_tlv320_driver = { .of_match_table = imx_tlv320_dt_ids, }, .probe = eukrea_tlv320_probe, - .remove_new = eukrea_tlv320_remove, }; module_platform_driver(eukrea_tlv320_driver); diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 546bd4e333b5..0e2c31439670 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -1639,6 +1639,18 @@ static const struct fsl_sai_soc_data fsl_sai_imx93_data = { .max_burst = {8, 8}, }; +static const struct fsl_sai_soc_data fsl_sai_imx95_data = { + .use_imx_pcm = true, + .use_edma = true, + .fifo_depth = 128, + .reg_offset = 8, + .mclk0_is_mclk1 = false, + .pins = 8, + .flags = 0, + .max_register = FSL_SAI_MCTL, + .max_burst = {8, 8}, +}; + static const struct of_device_id fsl_sai_ids[] = { { .compatible = "fsl,vf610-sai", .data = &fsl_sai_vf610_data }, { .compatible = "fsl,imx6sx-sai", .data = &fsl_sai_imx6sx_data }, @@ -1651,6 +1663,7 @@ static const struct of_device_id fsl_sai_ids[] = { { .compatible = "fsl,imx8ulp-sai", .data = &fsl_sai_imx8ulp_data }, { .compatible = "fsl,imx8mn-sai", .data = &fsl_sai_imx8mn_data }, { .compatible = "fsl,imx93-sai", .data = &fsl_sai_imx93_data }, + { .compatible = "fsl,imx95-sai", .data = &fsl_sai_imx95_data }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_sai_ids); diff --git a/sound/soc/fsl/p1022_rdk.c b/sound/soc/fsl/p1022_rdk.c index 18d129c21648..a42149311c8b 100644 --- a/sound/soc/fsl/p1022_rdk.c +++ b/sound/soc/fsl/p1022_rdk.c @@ -61,7 +61,7 @@ static inline void guts_set_dmuxcr(struct ccsr_guts __iomem *guts, /* There's only one global utilities register */ static phys_addr_t guts_phys; -/** +/* * machine_data: machine-specific ASoC device data * * This structure contains data for a single sound platform device on an @@ -80,11 +80,14 @@ struct machine_data { }; /** - * p1022_rdk_machine_probe: initialize the board + * p1022_rdk_machine_probe - initialize the board + * @card: ASoC card instance * * This function is used to initialize the board-specific hardware. * * Here we program the DMACR and PMUXCR registers. + * + * Returns: %0 on success or negative errno value on error */ static int p1022_rdk_machine_probe(struct snd_soc_card *card) { @@ -119,11 +122,14 @@ static int p1022_rdk_machine_probe(struct snd_soc_card *card) } /** - * p1022_rdk_startup: program the board with various hardware parameters + * p1022_rdk_startup - program the board with various hardware parameters + * @substream: ASoC substream object * * This function takes board-specific information, like clock frequencies * and serial data formats, and passes that information to the codec and * transport drivers. + * + * Returns: %0 on success or negative errno value on error */ static int p1022_rdk_startup(struct snd_pcm_substream *substream) { @@ -153,10 +159,13 @@ static int p1022_rdk_startup(struct snd_pcm_substream *substream) } /** - * p1022_rdk_machine_remove: Remove the sound device + * p1022_rdk_machine_remove - Remove the sound device + * @card: ASoC card instance * * This function is called to remove the sound device for one SSI. We * de-program the DMACR and PMUXCR register. + * + * Returns: %0 on success or negative errno value on error */ static int p1022_rdk_machine_remove(struct snd_soc_card *card) { @@ -181,7 +190,7 @@ static int p1022_rdk_machine_remove(struct snd_soc_card *card) return 0; } -/** +/* * p1022_rdk_ops: ASoC machine driver operations */ static const struct snd_soc_ops p1022_rdk_ops = { @@ -189,11 +198,14 @@ static const struct snd_soc_ops p1022_rdk_ops = { }; /** - * p1022_rdk_probe: platform probe function for the machine driver + * p1022_rdk_probe - platform probe function for the machine driver + * @pdev: platform device pointer * * Although this is a machine driver, the SSI node is the "master" node with * respect to audio hardware connections. Therefore, we create a new ASoC * device for each new SSI node that has a codec attached. + * + * Returns: %0 on success or negative errno value on error */ static int p1022_rdk_probe(struct platform_device *pdev) { @@ -341,7 +353,8 @@ error_put: } /** - * p1022_rdk_remove: remove the platform device + * p1022_rdk_remove - remove the platform device + * @pdev: platform device pointer * * This function is called when the platform device is removed. */ @@ -368,9 +381,11 @@ static struct platform_driver p1022_rdk_driver = { }; /** - * p1022_rdk_init: machine driver initialization. + * p1022_rdk_init - machine driver initialization. * * This function is called when this module is loaded. + * + * Returns: %0 on success or negative errno value on error */ static int __init p1022_rdk_init(void) { @@ -391,7 +406,7 @@ static int __init p1022_rdk_init(void) } /** - * p1022_rdk_exit: machine driver exit + * p1022_rdk_exit - machine driver exit * * This function is called when this driver is unloaded. */ diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c index 756706d5b493..747041fa7866 100644 --- a/sound/soc/qcom/common.c +++ b/sound/soc/qcom/common.c @@ -73,7 +73,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card) link = card->dai_link; for_each_available_child_of_node(dev->of_node, np) { - dlc = devm_kzalloc(dev, 2 * sizeof(*dlc), GFP_KERNEL); + dlc = devm_kcalloc(dev, 2, sizeof(*dlc), GFP_KERNEL); if (!dlc) { ret = -ENOMEM; goto err_put_np; diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c index e05eb7a86dd4..d2d21478399e 100644 --- a/sound/soc/sof/amd/acp-loader.c +++ b/sound/soc/sof/amd/acp-loader.c @@ -267,29 +267,49 @@ int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev) { struct snd_sof_pdata *plat_data = sdev->pdata; struct acp_dev_data *adata = plat_data->hw_pdata; + const char *fw_filename; int ret; - ret = request_firmware(&sdev->basefw.fw, adata->fw_code_bin, sdev->dev); + fw_filename = kasprintf(GFP_KERNEL, "%s/%s", + plat_data->fw_filename_prefix, + adata->fw_code_bin); + if (!fw_filename) + return -ENOMEM; + + ret = request_firmware(&sdev->basefw.fw, fw_filename, sdev->dev); if (ret < 0) { + kfree(fw_filename); dev_err(sdev->dev, "sof signed firmware code bin is missing\n"); return ret; } else { - dev_dbg(sdev->dev, "request_firmware %s successful\n", adata->fw_code_bin); + dev_dbg(sdev->dev, "request_firmware %s successful\n", fw_filename); } + kfree(fw_filename); + ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_IRAM, 0, - (void *)sdev->basefw.fw->data, sdev->basefw.fw->size); + (void *)sdev->basefw.fw->data, + sdev->basefw.fw->size); + + fw_filename = kasprintf(GFP_KERNEL, "%s/%s", + plat_data->fw_filename_prefix, + adata->fw_data_bin); + if (!fw_filename) + return -ENOMEM; - ret = request_firmware(&adata->fw_dbin, adata->fw_data_bin, sdev->dev); + ret = request_firmware(&adata->fw_dbin, fw_filename, sdev->dev); if (ret < 0) { + kfree(fw_filename); dev_err(sdev->dev, "sof signed firmware data bin is missing\n"); return ret; } else { - dev_dbg(sdev->dev, "request_firmware %s successful\n", adata->fw_data_bin); + dev_dbg(sdev->dev, "request_firmware %s successful\n", fw_filename); } + kfree(fw_filename); ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0, - (void *)adata->fw_dbin->data, adata->fw_dbin->size); + (void *)adata->fw_dbin->data, + adata->fw_dbin->size); return ret; } EXPORT_SYMBOL_NS(acp_sof_load_signed_firmware, SND_SOC_SOF_AMD_COMMON); diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 32a741fcb84f..a2b441e3d6d3 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -28,11 +28,10 @@ MODULE_PARM_DESC(enable_fw_debug, "Enable Firmware debug"); const struct dmi_system_id acp_sof_quirk_table[] = { { - /* Valve Jupiter device */ + /* Steam Deck OLED device */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Valve"), DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"), - DMI_MATCH(DMI_PRODUCT_FAMILY, "Sephiroth"), }, .driver_data = (void *)SECURED_FIRMWARE, }, @@ -494,7 +493,6 @@ EXPORT_SYMBOL_NS(amd_sof_acp_resume, SND_SOC_SOF_AMD_COMMON); int amd_sof_acp_probe(struct snd_sof_dev *sdev) { struct pci_dev *pci = to_pci_dev(sdev->dev); - struct snd_sof_pdata *plat_data = sdev->pdata; struct acp_dev_data *adata; const struct sof_amd_acp_desc *chip; const struct dmi_system_id *dmi_id; @@ -561,17 +559,25 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) adata->signed_fw_image = false; dmi_id = dmi_first_match(acp_sof_quirk_table); if (dmi_id && dmi_id->driver_data) { - adata->fw_code_bin = kasprintf(GFP_KERNEL, "%s/sof-%s-code.bin", - plat_data->fw_filename_prefix, - chip->name); - adata->fw_data_bin = kasprintf(GFP_KERNEL, "%s/sof-%s-data.bin", - plat_data->fw_filename_prefix, - chip->name); - adata->signed_fw_image = dmi_id->driver_data; + adata->fw_code_bin = devm_kasprintf(sdev->dev, GFP_KERNEL, + "sof-%s-code.bin", + chip->name); + if (!adata->fw_code_bin) { + ret = -ENOMEM; + goto free_ipc_irq; + } + + adata->fw_data_bin = devm_kasprintf(sdev->dev, GFP_KERNEL, + "sof-%s-data.bin", + chip->name); + if (!adata->fw_data_bin) { + ret = -ENOMEM; + goto free_ipc_irq; + } - dev_dbg(sdev->dev, "fw_code_bin:%s, fw_data_bin:%s\n", adata->fw_code_bin, - adata->fw_data_bin); + adata->signed_fw_image = dmi_id->driver_data; } + adata->enable_fw_debug = enable_fw_debug; acp_memory_init(sdev); diff --git a/sound/soc/sof/fw-file-profile.c b/sound/soc/sof/fw-file-profile.c index 138a1ca2c4a8..b56b14232444 100644 --- a/sound/soc/sof/fw-file-profile.c +++ b/sound/soc/sof/fw-file-profile.c @@ -89,6 +89,12 @@ static int sof_test_topology_file(struct device *dev, return ret; } +static bool sof_platform_uses_generic_loader(struct snd_sof_dev *sdev) +{ + return (sdev->pdata->desc->ops->load_firmware == snd_sof_load_firmware_raw || + sdev->pdata->desc->ops->load_firmware == snd_sof_load_firmware_memcpy); +} + static int sof_file_profile_for_ipc_type(struct snd_sof_dev *sdev, enum sof_ipc_type ipc_type, @@ -130,7 +136,8 @@ sof_file_profile_for_ipc_type(struct snd_sof_dev *sdev, * For default path and firmware name do a verification before * continuing further. */ - if (base_profile->fw_path || base_profile->fw_name) { + if ((base_profile->fw_path || base_profile->fw_name) && + sof_platform_uses_generic_loader(sdev)) { ret = sof_test_firmware_file(dev, out_profile, &ipc_type); if (ret) return ret; @@ -181,7 +188,8 @@ sof_file_profile_for_ipc_type(struct snd_sof_dev *sdev, out_profile->ipc_type = ipc_type; /* Test only default firmware file */ - if (!base_profile->fw_path && !base_profile->fw_name) + if ((!base_profile->fw_path && !base_profile->fw_name) && + sof_platform_uses_generic_loader(sdev)) ret = sof_test_firmware_file(dev, out_profile, NULL); if (!ret) @@ -267,7 +275,11 @@ static void sof_print_profile_info(struct snd_sof_dev *sdev, dev_info(dev, "Firmware paths/files for ipc type %d:\n", profile->ipc_type); - dev_info(dev, " Firmware file: %s/%s\n", profile->fw_path, profile->fw_name); + /* The firmware path is only valid when generic loader is used */ + if (sof_platform_uses_generic_loader(sdev)) + dev_info(dev, " Firmware file: %s/%s\n", + profile->fw_path, profile->fw_name); + if (profile->fw_lib_path) dev_info(dev, " Firmware lib path: %s\n", profile->fw_lib_path); dev_info(dev, " Topology file: %s/%s\n", profile->tplg_path, profile->tplg_name); diff --git a/sound/soc/ti/j721e-evm.c b/sound/soc/ti/j721e-evm.c index b4b158dc736e..d9d1e021f5b2 100644 --- a/sound/soc/ti/j721e-evm.c +++ b/sound/soc/ti/j721e-evm.c @@ -649,7 +649,7 @@ static int j721e_soc_probe_cpb(struct j721e_priv *priv, int *link_idx, * Link 2: McASP10 <- pcm3168a_1 ADC */ comp_count = 6; - compnent = devm_kzalloc(priv->dev, comp_count * sizeof(*compnent), + compnent = devm_kcalloc(priv->dev, comp_count, sizeof(*compnent), GFP_KERNEL); if (!compnent) { ret = -ENOMEM; @@ -763,7 +763,7 @@ static int j721e_soc_probe_ivi(struct j721e_priv *priv, int *link_idx, * \ pcm3168a_b ADC */ comp_count = 8; - compnent = devm_kzalloc(priv->dev, comp_count * sizeof(*compnent), + compnent = devm_kcalloc(priv->dev, comp_count, sizeof(*compnent), GFP_KERNEL); if (!compnent) { ret = -ENOMEM; diff --git a/sound/soc/ti/omap-hdmi.c b/sound/soc/ti/omap-hdmi.c index 29bff9e6337b..4513b527ab97 100644 --- a/sound/soc/ti/omap-hdmi.c +++ b/sound/soc/ti/omap-hdmi.c @@ -379,7 +379,7 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev) card->num_links = 1; card->dev = dev; - ret = snd_soc_register_card(card); + ret = devm_snd_soc_register_card(dev, card); if (ret) { dev_err(dev, "snd_soc_register_card failed (%d)\n", ret); return ret; @@ -393,19 +393,11 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev) return 0; } -static void omap_hdmi_audio_remove(struct platform_device *pdev) -{ - struct hdmi_audio_data *ad = platform_get_drvdata(pdev); - - snd_soc_unregister_card(ad->card); -} - static struct platform_driver hdmi_audio_driver = { .driver = { .name = DRV_NAME, }, .probe = omap_hdmi_audio_probe, - .remove_new = omap_hdmi_audio_remove, }; module_platform_driver(hdmi_audio_driver); |