diff options
Diffstat (limited to 'sound/soc/codecs')
199 files changed, 9123 insertions, 5335 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index e4d139108d72..f9a47e262a77 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -238,6 +238,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT715_SDCA_SDW imply SND_SOC_RT721_SDCA_SDW imply SND_SOC_RT722_SDCA_SDW + imply SND_SOC_RT766_SDCA_SDW imply SND_SOC_RT1308_SDW imply SND_SOC_RT1316_SDW imply SND_SOC_RT1318 @@ -367,6 +368,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_WSA881X imply SND_SOC_WSA883X imply SND_SOC_WSA884X + imply SND_SOC_WSA885X imply SND_SOC_ZL38060 help Normally ASoC codec drivers are only built if a machine driver which @@ -615,8 +617,8 @@ config SND_SOC_AK4613 depends on I2C config SND_SOC_AK4619 - tristate "AKM AK4619 CODEC" - depends on I2C + tristate "AKM AK4619 CODEC" + depends on I2C config SND_SOC_AK4642 tristate "AKM AK4642 CODEC" @@ -726,6 +728,10 @@ config SND_SOC_AW87390 sound quality, which is a new high efficiency, low noise, constant large volume, 6th Smart K audio amplifier. +config SND_SOC_AW88399_LIB + tristate + select SND_SOC_AW88395_LIB + config SND_SOC_AW88399 tristate "Soc Audio for awinic aw88399" depends on I2C @@ -733,6 +739,7 @@ config SND_SOC_AW88399 select REGMAP_I2C select GPIOLIB select SND_SOC_AW88395_LIB + select SND_SOC_AW88399_LIB help This option enables support for aw88399 Smart PA. The awinic AW88399 is an I2S/TDM input, high efficiency @@ -889,6 +896,7 @@ config SND_SOC_CS35L56_SDW tristate "Cirrus Logic CS35L56 CODEC (SDW)" depends on SOUNDWIRE select REGMAP_SOUNDWIRE + select IRQ_DOMAIN select SND_SOC_CS35L56 select SND_SOC_CS35L56_SHARED help @@ -1201,16 +1209,16 @@ config SND_SOC_JZ4725B_CODEC will be called snd-soc-jz4725b-codec. config SND_SOC_JZ4760_CODEC - depends on MACH_INGENIC || COMPILE_TEST - depends on OF - select REGMAP - tristate "Ingenic JZ4760 internal CODEC" - help - Enable support for the internal CODEC found in the JZ4760 SoC - from Ingenic. + depends on MACH_INGENIC || COMPILE_TEST + depends on OF + select REGMAP + tristate "Ingenic JZ4760 internal CODEC" + help + Enable support for the internal CODEC found in the JZ4760 SoC + from Ingenic. - This driver can also be built as a module. If so, the module - will be called snd-soc-jz4760-codec. + This driver can also be built as a module. If so, the module + will be called snd-soc-jz4760-codec. config SND_SOC_JZ4770_CODEC depends on MACH_INGENIC || COMPILE_TEST @@ -1888,7 +1896,7 @@ config SND_SOC_RT5670 depends on I2C config SND_SOC_RT5677 - tristate + tristate "Realtek RT5677 Codec" depends on I2C select REGMAP_I2C select REGMAP_IRQ @@ -1978,6 +1986,15 @@ config SND_SOC_RT715_SDCA_SDW select REGMAP_SOUNDWIRE select REGMAP_SOUNDWIRE_MBQ +config SND_SOC_RT766_SDCA_SDW + tristate "Realtek RT766 SDCA Codec - SDW" + depends on SOUNDWIRE + depends on SND_SOC_SDCA + select SND_SOC_SDCA_HID + select SND_SOC_SDCA_IRQ + select REGMAP_SOUNDWIRE + select REGMAP_SOUNDWIRE_MBQ + config SND_SOC_RT9120 tristate "Richtek RT9120 Stereo Class-D Amplifier" depends on I2C @@ -2297,8 +2314,8 @@ config SND_SOC_TLV320ADC3XXX depends on I2C depends on GPIOLIB help - Enable support for Texas Instruments TLV320ADC3001 and TLV320ADC3101 - ADCs. + Enable support for Texas Instruments TLV320ADC3001 and TLV320ADC3101 + ADCs. config SND_SOC_TLV320AIC23 tristate @@ -2771,6 +2788,16 @@ config SND_SOC_WSA884X This enables support for Qualcomm WSA8840/WSA8845/WSA8845H Class-D Smart Speaker Amplifier. +config SND_SOC_WSA885X + tristate "WSA885X Codec" + depends on I2C + select REGMAP_I2C + help + This enables support for Qualcomm WSA885X Stereo Smart Speaker + Amplifier. The codec driver programs the amplifier register + map and exposes the DAI and mixer controls used by Qualcomm + audio machine drivers. + config SND_SOC_ZL38060 tristate "Microsemi ZL38060 Connected Home Audio Processor" depends on SPI_MASTER @@ -2894,28 +2921,32 @@ config SND_SOC_TPA6130A2 depends on I2C config SND_SOC_LPASS_MACRO_COMMON - tristate + tristate config SND_SOC_LPASS_WSA_MACRO depends on COMMON_CLK + depends on PM_CLK select REGMAP_MMIO select SND_SOC_LPASS_MACRO_COMMON tristate "Qualcomm WSA Macro in LPASS(Low Power Audio SubSystem)" config SND_SOC_LPASS_VA_MACRO depends on COMMON_CLK + depends on PM_CLK select REGMAP_MMIO select SND_SOC_LPASS_MACRO_COMMON tristate "Qualcomm VA Macro in LPASS(Low Power Audio SubSystem)" config SND_SOC_LPASS_RX_MACRO depends on COMMON_CLK + depends on PM_CLK select REGMAP_MMIO select SND_SOC_LPASS_MACRO_COMMON tristate "Qualcomm RX Macro in LPASS(Low Power Audio SubSystem)" config SND_SOC_LPASS_TX_MACRO depends on COMMON_CLK + depends on PM_CLK select REGMAP_MMIO select SND_SOC_LPASS_MACRO_COMMON tristate "Qualcomm TX Macro in LPASS(Low Power Audio SubSystem)" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index aa0396e5b575..3d122ace75ad 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -55,6 +55,7 @@ snd-soc-aw88395-y := aw88395/aw88395.o snd-soc-aw88166-y := aw88166.o snd-soc-aw88261-y := aw88261.o snd-soc-aw88399-y := aw88399.o +snd-soc-aw88399-lib-y := aw88399-lib.o snd-soc-bd28623-y := bd28623.o snd-soc-bt-sco-y := bt-sco.o snd-soc-chv3-codec-y := chv3-codec.o @@ -284,6 +285,7 @@ snd-soc-rt715-y := rt715.o rt715-sdw.o snd-soc-rt715-sdca-y := rt715-sdca.o rt715-sdca-sdw.o snd-soc-rt721-sdca-y := rt721-sdca.o rt721-sdca-sdw.o snd-soc-rt722-sdca-y := rt722-sdca.o rt722-sdca-sdw.o +snd-soc-rt766-sdca-y := rt766-sdca.o rt766-sdca-sdw.o snd-soc-rt9120-y := rt9120.o snd-soc-rt9123-y := rt9123.o snd-soc-rt9123p-y := rt9123p.o @@ -426,6 +428,7 @@ snd-soc-wm-hubs-y := wm_hubs.o snd-soc-wsa881x-y := wsa881x.o snd-soc-wsa883x-y := wsa883x.o snd-soc-wsa884x-y := wsa884x.o +snd-soc-wsa885x-y := wsa885x.o snd-soc-zl38060-y := zl38060.o # Amp snd-soc-max9877-y := max9877.o @@ -496,6 +499,7 @@ obj-$(CONFIG_SND_SOC_AW88395) +=snd-soc-aw88395.o obj-$(CONFIG_SND_SOC_AW88166) +=snd-soc-aw88166.o obj-$(CONFIG_SND_SOC_AW88261) +=snd-soc-aw88261.o obj-$(CONFIG_SND_SOC_AW88399) += snd-soc-aw88399.o +obj-$(CONFIG_SND_SOC_AW88399_LIB) += snd-soc-aw88399-lib.o obj-$(CONFIG_SND_SOC_BD28623) += snd-soc-bd28623.o obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o obj-$(CONFIG_SND_SOC_CHV3_CODEC) += snd-soc-chv3-codec.o @@ -724,6 +728,7 @@ obj-$(CONFIG_SND_SOC_RT715) += snd-soc-rt715.o obj-$(CONFIG_SND_SOC_RT715_SDCA_SDW) += snd-soc-rt715-sdca.o obj-$(CONFIG_SND_SOC_RT721_SDCA_SDW) += snd-soc-rt721-sdca.o obj-$(CONFIG_SND_SOC_RT722_SDCA_SDW) += snd-soc-rt722-sdca.o +obj-$(CONFIG_SND_SOC_RT766_SDCA_SDW) += snd-soc-rt766-sdca.o obj-$(CONFIG_SND_SOC_RT9120) += snd-soc-rt9120.o obj-$(CONFIG_SND_SOC_RT9123) += snd-soc-rt9123.o obj-$(CONFIG_SND_SOC_RT9123P) += snd-soc-rt9123p.o @@ -876,6 +881,7 @@ obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o obj-$(CONFIG_SND_SOC_WSA881X) += snd-soc-wsa881x.o obj-$(CONFIG_SND_SOC_WSA883X) += snd-soc-wsa883x.o obj-$(CONFIG_SND_SOC_WSA884X) += snd-soc-wsa884x.o +obj-$(CONFIG_SND_SOC_WSA885X) += snd-soc-wsa885x.o obj-$(CONFIG_SND_SOC_ZL38060) += snd-soc-zl38060.o # Amp diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 6e8ef9cd1b31..2cf96cbdd294 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -14,6 +14,7 @@ * for ST-Ericsson. */ +#include <linux/cleanup.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/device.h> @@ -989,9 +990,8 @@ static int sid_status_control_get(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev); - mutex_lock(&drvdata->ctrl_lock); + guard(mutex)(&drvdata->ctrl_lock); ucontrol->value.enumerated.item[0] = drvdata->sid_status; - mutex_unlock(&drvdata->ctrl_lock); return 0; } @@ -1014,7 +1014,7 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol, return -EIO; } - mutex_lock(&drvdata->ctrl_lock); + guard(mutex)(&drvdata->ctrl_lock); sidconf = snd_soc_component_read(component, AB8500_SIDFIRCONF); if (((sidconf & BIT(AB8500_SIDFIRCONF_FIRSIDBUSY)) != 0)) { @@ -1025,7 +1025,8 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol, } else { status = -EBUSY; } - goto out; + dev_dbg(component->dev, "%s: Exit\n", __func__); + return status; } snd_soc_component_write(component, AB8500_SIDFIRADR, 0); @@ -1043,9 +1044,6 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol, drvdata->sid_status = SID_FIR_CONFIGURED; -out: - mutex_unlock(&drvdata->ctrl_lock); - dev_dbg(component->dev, "%s: Exit\n", __func__); return status; diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 8afeadcaf8b0..dbea83bd49b6 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -193,9 +193,15 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream, return 0; } +static const u64 ad1836_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_DSP_A | + SND_SOC_POSSIBLE_DAIFMT_IB_IF; + static const struct snd_soc_dai_ops ad1836_dai_ops = { .hw_params = ad1836_hw_params, .set_fmt = ad1836_set_dai_fmt, + .auto_selectable_formats = &ad1836_selectable_formats, + .num_auto_selectable_formats = 1, }; #define AD183X_DAI(_name, num_dacs, num_adcs) \ diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index b93531c3a9a4..9841c779b175 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -394,6 +394,14 @@ static int ad193x_startup(struct snd_pcm_substream *substream, &constr); } +static const u64 ad193x_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_DSP_A | + SND_SOC_POSSIBLE_DAIFMT_NB_NF | + SND_SOC_POSSIBLE_DAIFMT_NB_IF | + SND_SOC_POSSIBLE_DAIFMT_IB_NF | + SND_SOC_POSSIBLE_DAIFMT_IB_IF; + static const struct snd_soc_dai_ops ad193x_dai_ops = { .startup = ad193x_startup, .hw_params = ad193x_hw_params, @@ -401,6 +409,8 @@ static const struct snd_soc_dai_ops ad193x_dai_ops = { .set_tdm_slot = ad193x_set_tdm_slot, .set_sysclk = ad193x_set_dai_sysclk, .set_fmt = ad193x_set_dai_fmt, + .auto_selectable_formats = &ad193x_selectable_formats, + .num_auto_selectable_formats = 1, .no_capture_mute = 1, }; diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index a70c46dd5d76..27ce03b0fb91 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c @@ -68,23 +68,33 @@ #define ADAU1761_FIRMWARE "adau1761.bin" static const struct reg_default adau1761_reg_defaults[] = { - { ADAU1761_DEJITTER, 0x03 }, + { ADAU17X1_CLOCK_CONTROL, 0x00 }, + { ADAU17X1_PLL_CONTROL, 0x00 }, { ADAU1761_DIGMIC_JACKDETECT, 0x00 }, + { ADAU17X1_REC_POWER_MGMT, 0x00 }, { ADAU1761_REC_MIXER_LEFT0, 0x00 }, { ADAU1761_REC_MIXER_LEFT1, 0x00 }, { ADAU1761_REC_MIXER_RIGHT0, 0x00 }, { ADAU1761_REC_MIXER_RIGHT1, 0x00 }, { ADAU1761_LEFT_DIFF_INPUT_VOL, 0x00 }, + { ADAU1761_RIGHT_DIFF_INPUT_VOL, 0x00 }, + { ADAU17X1_MICBIAS, 0x00 }, { ADAU1761_ALC_CTRL0, 0x00 }, { ADAU1761_ALC_CTRL1, 0x00 }, { ADAU1761_ALC_CTRL2, 0x00 }, { ADAU1761_ALC_CTRL3, 0x00 }, - { ADAU1761_RIGHT_DIFF_INPUT_VOL, 0x00 }, - { ADAU1761_PLAY_LR_MIXER_LEFT, 0x00 }, + { ADAU17X1_SERIAL_PORT0, 0x00 }, + { ADAU17X1_SERIAL_PORT1, 0x00 }, + { ADAU17X1_CONVERTER0, 0x00 }, + { ADAU17X1_CONVERTER1, 0x00 }, + { ADAU17X1_ADC_CONTROL, 0x00 }, + { ADAU17X1_LEFT_INPUT_DIGITAL_VOL, 0x00 }, + { ADAU17X1_RIGHT_INPUT_DIGITAL_VOL, 0x00 }, { ADAU1761_PLAY_MIXER_LEFT0, 0x00 }, { ADAU1761_PLAY_MIXER_LEFT1, 0x00 }, { ADAU1761_PLAY_MIXER_RIGHT0, 0x00 }, { ADAU1761_PLAY_MIXER_RIGHT1, 0x00 }, + { ADAU1761_PLAY_LR_MIXER_LEFT, 0x00 }, { ADAU1761_PLAY_LR_MIXER_RIGHT, 0x00 }, { ADAU1761_PLAY_MIXER_MONO, 0x00 }, { ADAU1761_PLAY_HP_LEFT_VOL, 0x00 }, @@ -93,20 +103,6 @@ static const struct reg_default adau1761_reg_defaults[] = { { ADAU1761_PLAY_LINE_RIGHT_VOL, 0x00 }, { ADAU1761_PLAY_MONO_OUTPUT_VOL, 0x00 }, { ADAU1761_POP_CLICK_SUPPRESS, 0x00 }, - { ADAU1761_JACK_DETECT_PIN, 0x00 }, - { ADAU1761_CLK_ENABLE0, 0x00 }, - { ADAU1761_CLK_ENABLE1, 0x00 }, - { ADAU17X1_CLOCK_CONTROL, 0x00 }, - { ADAU17X1_PLL_CONTROL, 0x00 }, - { ADAU17X1_REC_POWER_MGMT, 0x00 }, - { ADAU17X1_MICBIAS, 0x00 }, - { ADAU17X1_SERIAL_PORT0, 0x00 }, - { ADAU17X1_SERIAL_PORT1, 0x00 }, - { ADAU17X1_CONVERTER0, 0x00 }, - { ADAU17X1_CONVERTER1, 0x00 }, - { ADAU17X1_LEFT_INPUT_DIGITAL_VOL, 0x00 }, - { ADAU17X1_RIGHT_INPUT_DIGITAL_VOL, 0x00 }, - { ADAU17X1_ADC_CONTROL, 0x00 }, { ADAU17X1_PLAY_POWER_MGMT, 0x00 }, { ADAU17X1_DAC_CONTROL0, 0x00 }, { ADAU17X1_DAC_CONTROL1, 0x00 }, @@ -114,12 +110,16 @@ static const struct reg_default adau1761_reg_defaults[] = { { ADAU17X1_SERIAL_PORT_PAD, 0xaa }, { ADAU17X1_CONTROL_PORT_PAD0, 0xaa }, { ADAU17X1_CONTROL_PORT_PAD1, 0x00 }, + { ADAU1761_JACK_DETECT_PIN, 0x00 }, + { ADAU1761_DEJITTER, 0x03 }, { ADAU17X1_DSP_SAMPLING_RATE, 0x01 }, { ADAU17X1_SERIAL_INPUT_ROUTE, 0x00 }, { ADAU17X1_SERIAL_OUTPUT_ROUTE, 0x00 }, { ADAU17X1_DSP_ENABLE, 0x00 }, { ADAU17X1_DSP_RUN, 0x00 }, { ADAU17X1_SERIAL_SAMPLING_RATE, 0x00 }, + { ADAU1761_CLK_ENABLE0, 0x00 }, + { ADAU1761_CLK_ENABLE1, 0x00 }, }; static const DECLARE_TLV_DB_SCALE(adau1761_sing_in_tlv, -1500, 300, 1); diff --git a/sound/soc/codecs/adau7118-hw.c b/sound/soc/codecs/adau7118-hw.c index 92b226b8b4bb..4342eb7dd9e5 100644 --- a/sound/soc/codecs/adau7118-hw.c +++ b/sound/soc/codecs/adau7118-hw.c @@ -22,7 +22,7 @@ static const struct of_device_id adau7118_of_match[] = { MODULE_DEVICE_TABLE(of, adau7118_of_match); static const struct platform_device_id adau7118_id[] = { - { .name = "adau7118" }, + { .name = "adau7118" }, { } }; MODULE_DEVICE_TABLE(platform, adau7118_id); diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index 8a89187f9c78..e97c72ac9b2b 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -743,11 +743,19 @@ static void adav80x_dai_shutdown(struct snd_pcm_substream *substream, adav80x->rate = 0; } +static const u64 adav80x_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J | + SND_SOC_POSSIBLE_DAIFMT_NB_NF; + static const struct snd_soc_dai_ops adav80x_dai_ops = { .set_fmt = adav80x_set_dai_fmt, .hw_params = adav80x_hw_params, .startup = adav80x_dai_startup, .shutdown = adav80x_dai_shutdown, + .auto_selectable_formats = &adav80x_selectable_formats, + .num_auto_selectable_formats = 1, }; #define ADAV80X_PLAYBACK_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index 3e0696b5abf5..be5306d07d40 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -95,6 +95,7 @@ * see * AK4613_ENABLE_TDM_TEST */ +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/i2c.h> @@ -384,7 +385,7 @@ static void ak4613_dai_shutdown(struct snd_pcm_substream *substream, struct ak4613_priv *priv = snd_soc_component_get_drvdata(component); struct device *dev = component->dev; - mutex_lock(&priv->lock); + guard(mutex)(&priv->lock); priv->cnt--; if (priv->cnt < 0) { dev_err(dev, "unexpected counter error\n"); @@ -392,7 +393,6 @@ static void ak4613_dai_shutdown(struct snd_pcm_substream *substream, } if (!priv->cnt) priv->ctrl1 = 0; - mutex_unlock(&priv->lock); } static void ak4613_hw_constraints(struct ak4613_priv *priv, @@ -507,10 +507,9 @@ static int ak4613_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct ak4613_priv *priv = snd_soc_component_get_drvdata(component); - mutex_lock(&priv->lock); + guard(mutex)(&priv->lock); ak4613_hw_constraints(priv, substream); priv->cnt++; - mutex_unlock(&priv->lock); return 0; } @@ -599,45 +598,47 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, */ ret = -EINVAL; - mutex_lock(&priv->lock); - if (priv->cnt > 1) { - /* - * If it was already working, use current priv->ctrl1 - */ - ret = 0; - } else { - /* - * It is not yet working, - */ - unsigned int channel = params_channels(params); - u8 tdm; - - /* STEREO or TDM */ - if (channel == 2) - tdm = AK4613_CONFIG_MODE_STEREO; - else - tdm = AK4613_CONFIG_GET(priv, MODE); - - for (i = ARRAY_SIZE(ak4613_iface) - 1; i >= 0; i--) { - const struct ak4613_interface *iface = ak4613_iface + i; - - if ((iface->fmt == fmt) && (iface->width == width)) { - /* - * Ctrl1 - * | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | - * |TDM1|TDM0|DIF2|DIF1|DIF0|ATS1|ATS0|SMUTE| - * < tdm > < iface->dif > - */ - priv->ctrl1 = (tdm << 6) | (iface->dif << 3); - ret = 0; - break; + scoped_guard(mutex, &priv->lock) { + if (priv->cnt > 1) { + /* + * If it was already working, use current priv->ctrl1 + */ + ret = 0; + } else { + /* + * It is not yet working, + */ + unsigned int channel = params_channels(params); + u8 tdm; + + /* STEREO or TDM */ + if (channel == 2) + tdm = AK4613_CONFIG_MODE_STEREO; + else + tdm = AK4613_CONFIG_GET(priv, MODE); + + for (i = ARRAY_SIZE(ak4613_iface) - 1; i >= 0; i--) { + const struct ak4613_interface *iface = ak4613_iface + i; + + if (iface->fmt == fmt && iface->width == width) { + /* + * Ctrl1 + * | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | + * |TDM1|TDM0|DIF2|DIF1|DIF0|ATS1|ATS0|SMUTE| + * < tdm > < iface->dif > + */ + priv->ctrl1 = (tdm << 6) | (iface->dif << 3); + ret = 0; + break; + } } } } - mutex_unlock(&priv->lock); - if (ret < 0) - goto hw_params_end; + if (ret < 0) { + dev_warn(dev, "unsupported data width/format combination\n"); + return ret; + } snd_soc_component_update_bits(component, CTRL1, FMT_MASK, priv->ctrl1); snd_soc_component_update_bits(component, CTRL2, DFS_MASK, ctrl2); @@ -645,10 +646,6 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, snd_soc_component_update_bits(component, ICTRL, ICTRL_MASK, priv->ic); snd_soc_component_update_bits(component, OCTRL, OCTRL_MASK, priv->oc); -hw_params_end: - if (ret < 0) - dev_warn(dev, "unsupported data width/format combination\n"); - return ret; } diff --git a/sound/soc/codecs/arizona-jack.c b/sound/soc/codecs/arizona-jack.c index a9063bac2752..819d080b1188 100644 --- a/sound/soc/codecs/arizona-jack.c +++ b/sound/soc/codecs/arizona-jack.c @@ -5,6 +5,7 @@ * Copyright (C) 2012-2014 Wolfson Microelectronics plc */ +#include <linux/cleanup.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> @@ -707,15 +708,13 @@ static void arizona_micd_timeout_work(struct work_struct *work) struct arizona_priv, micd_timeout_work.work); - mutex_lock(&info->lock); + guard(mutex)(&info->lock); dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n"); info->detecting = false; arizona_identify_headphone(info); - - mutex_unlock(&info->lock); } static int arizona_micd_adc_read(struct arizona_priv *info) @@ -921,12 +920,11 @@ static void arizona_micd_detect(struct work_struct *work) cancel_delayed_work_sync(&info->micd_timeout_work); - mutex_lock(&info->lock); + guard(mutex)(&info->lock); /* If the cable was removed while measuring ignore the result */ if (!(info->jack->status & SND_JACK_MECHANICAL)) { dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n"); - mutex_unlock(&info->lock); return; } @@ -936,7 +934,6 @@ static void arizona_micd_detect(struct work_struct *work) arizona_button_reading(info); pm_runtime_mark_last_busy(arizona->dev); - mutex_unlock(&info->lock); } static irqreturn_t arizona_micdet(int irq, void *data) @@ -948,10 +945,10 @@ static irqreturn_t arizona_micdet(int irq, void *data) cancel_delayed_work_sync(&info->micd_detect_work); cancel_delayed_work_sync(&info->micd_timeout_work); - mutex_lock(&info->lock); - if (!info->detecting) - debounce = 0; - mutex_unlock(&info->lock); + scoped_guard(mutex, &info->lock) { + if (!info->detecting) + debounce = 0; + } if (debounce) queue_delayed_work(system_power_efficient_wq, @@ -969,9 +966,8 @@ static void arizona_hpdet_work(struct work_struct *work) struct arizona_priv, hpdet_work.work); - mutex_lock(&info->lock); + guard(mutex)(&info->lock); arizona_start_hpdet_acc_id(info); - mutex_unlock(&info->lock); } static int arizona_hpdet_wait(struct arizona_priv *info) @@ -1018,9 +1014,9 @@ static irqreturn_t arizona_jackdet(int irq, void *data) cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work); cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work); - pm_runtime_get_sync(arizona->dev); + guard(pm_runtime_active_auto)(arizona->dev); - mutex_lock(&info->lock); + guard(mutex)(&info->lock); if (info->micd_clamp) { mask = ARIZONA_MICD_CLAMP_STS; @@ -1036,8 +1032,6 @@ static irqreturn_t arizona_jackdet(int irq, void *data) ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val); if (ret) { dev_err(arizona->dev, "Failed to read jackdet status: %d\n", ret); - mutex_unlock(&info->lock); - pm_runtime_put_autosuspend(arizona->dev); return IRQ_NONE; } @@ -1056,62 +1050,61 @@ static irqreturn_t arizona_jackdet(int irq, void *data) &info->micd_timeout_work, msecs_to_jiffies(micd_timeout)); } + } else { + info->last_jackdet = val; - goto out; - } - info->last_jackdet = val; + if (info->last_jackdet == present) { + dev_dbg(arizona->dev, "Detected jack\n"); + snd_soc_jack_report(info->jack, SND_JACK_MECHANICAL, SND_JACK_MECHANICAL); - if (info->last_jackdet == present) { - dev_dbg(arizona->dev, "Detected jack\n"); - snd_soc_jack_report(info->jack, SND_JACK_MECHANICAL, SND_JACK_MECHANICAL); + info->detecting = true; + info->mic = false; + info->jack_flips = 0; - info->detecting = true; - info->mic = false; - info->jack_flips = 0; + if (!arizona->pdata.hpdet_acc_id) { + arizona_start_mic(info); + } else { + queue_delayed_work(system_power_efficient_wq, + &info->hpdet_work, + msecs_to_jiffies(HPDET_DEBOUNCE)); + } - if (!arizona->pdata.hpdet_acc_id) { - arizona_start_mic(info); + if (info->micd_clamp || !arizona->pdata.jd_invert) + regmap_update_bits(arizona->regmap, + ARIZONA_JACK_DETECT_DEBOUNCE, + ARIZONA_MICD_CLAMP_DB | + ARIZONA_JD1_DB, 0); } else { - queue_delayed_work(system_power_efficient_wq, - &info->hpdet_work, - msecs_to_jiffies(HPDET_DEBOUNCE)); - } + dev_dbg(arizona->dev, "Detected jack removal\n"); - if (info->micd_clamp || !arizona->pdata.jd_invert) - regmap_update_bits(arizona->regmap, - ARIZONA_JACK_DETECT_DEBOUNCE, - ARIZONA_MICD_CLAMP_DB | - ARIZONA_JD1_DB, 0); - } else { - dev_dbg(arizona->dev, "Detected jack removal\n"); - - arizona_stop_mic(info); + arizona_stop_mic(info); - info->num_hpdet_res = 0; - for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++) - info->hpdet_res[i] = 0; - info->mic = false; - info->hpdet_done = false; - info->hpdet_retried = false; + info->num_hpdet_res = 0; + for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++) + info->hpdet_res[i] = 0; + info->mic = false; + info->hpdet_done = false; + info->hpdet_retried = false; - snd_soc_jack_report(info->jack, 0, ARIZONA_JACK_MASK | info->micd_button_mask); + snd_soc_jack_report(info->jack, 0, + ARIZONA_JACK_MASK | info->micd_button_mask); - /* - * If the jack was removed during a headphone detection we - * need to wait for the headphone detection to finish, as - * it can not be aborted. We don't want to be able to start - * a new headphone detection from a fresh insert until this - * one is finished. - */ - arizona_hpdet_wait(info); + /* + * If the jack was removed during a headphone detection we + * need to wait for the headphone detection to finish, as + * it can not be aborted. We don't want to be able to start + * a new headphone detection from a fresh insert until this + * one is finished. + */ + arizona_hpdet_wait(info); - regmap_update_bits(arizona->regmap, - ARIZONA_JACK_DETECT_DEBOUNCE, - ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, - ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB); + regmap_update_bits(arizona->regmap, + ARIZONA_JACK_DETECT_DEBOUNCE, + ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, + ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB); + } } -out: /* Clear trig_sts to make sure DCVDD is not forced up */ regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG, ARIZONA_MICD_CLAMP_FALL_TRIG_STS | @@ -1119,10 +1112,6 @@ out: ARIZONA_JD1_FALL_TRIG_STS | ARIZONA_JD1_RISE_TRIG_STS); - mutex_unlock(&info->lock); - - pm_runtime_put_autosuspend(arizona->dev); - return IRQ_HANDLED; } diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 8c683b0bb74c..4411165c3734 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -7,6 +7,7 @@ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> */ +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/gcd.h> #include <linux/module.h> @@ -1158,17 +1159,16 @@ int arizona_dvfs_up(struct snd_soc_component *component, unsigned int flags) struct arizona_priv *priv = snd_soc_component_get_drvdata(component); int ret = 0; - mutex_lock(&priv->dvfs_lock); + guard(mutex)(&priv->dvfs_lock); if (!priv->dvfs_cached && !priv->dvfs_reqs) { ret = arizona_dvfs_enable(component); if (ret) - goto err; + return ret; } priv->dvfs_reqs |= flags; -err: - mutex_unlock(&priv->dvfs_lock); + return ret; } EXPORT_SYMBOL_GPL(arizona_dvfs_up); @@ -1179,7 +1179,7 @@ int arizona_dvfs_down(struct snd_soc_component *component, unsigned int flags) unsigned int old_reqs; int ret = 0; - mutex_lock(&priv->dvfs_lock); + guard(mutex)(&priv->dvfs_lock); old_reqs = priv->dvfs_reqs; priv->dvfs_reqs &= ~flags; @@ -1187,7 +1187,6 @@ int arizona_dvfs_down(struct snd_soc_component *component, unsigned int flags) if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs) ret = arizona_dvfs_disable(component); - mutex_unlock(&priv->dvfs_lock); return ret; } EXPORT_SYMBOL_GPL(arizona_dvfs_down); @@ -1199,7 +1198,7 @@ int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w, struct arizona_priv *priv = snd_soc_component_get_drvdata(component); int ret = 0; - mutex_lock(&priv->dvfs_lock); + guard(mutex)(&priv->dvfs_lock); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -1222,7 +1221,6 @@ int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w, break; } - mutex_unlock(&priv->dvfs_lock); return ret; } EXPORT_SYMBOL_GPL(arizona_dvfs_sysclk_ev); @@ -1657,13 +1655,11 @@ static void arizona_wm5102_set_dac_comp(struct snd_soc_component *component, { 0x80, 0x0 }, }; - mutex_lock(&arizona->dac_comp_lock); - - dac_comp[1].def = arizona->dac_comp_coeff; - if (rate >= 176400) - dac_comp[2].def = arizona->dac_comp_enabled; - - mutex_unlock(&arizona->dac_comp_lock); + scoped_guard(mutex, &arizona->dac_comp_lock) { + dac_comp[1].def = arizona->dac_comp_coeff; + if (rate >= 176400) + dac_comp[2].def = arizona->dac_comp_enabled; + } regmap_multi_reg_write(arizona->regmap, dac_comp, diff --git a/sound/soc/codecs/aw87390.c b/sound/soc/codecs/aw87390.c index 020213e0ca4b..5555c45dffcc 100644 --- a/sound/soc/codecs/aw87390.c +++ b/sound/soc/codecs/aw87390.c @@ -7,6 +7,7 @@ // Author: Weidong Wang <wangweidong.a@awinic.com> // +#include <linux/cleanup.h> #include <linux/i2c.h> #include <linux/firmware.h> #include <linux/regmap.h> @@ -225,11 +226,10 @@ static int aw87390_profile_set(struct snd_kcontrol *kcontrol, struct aw87390 *aw87390 = snd_soc_component_get_drvdata(codec); int ret; - mutex_lock(&aw87390->lock); + guard(mutex)(&aw87390->lock); ret = aw87390_dev_set_profile_index(aw87390->aw_pa, ucontrol->value.integer.value[0]); if (ret) { dev_dbg(codec->dev, "profile index does not change\n"); - mutex_unlock(&aw87390->lock); return 0; } @@ -238,8 +238,6 @@ static int aw87390_profile_set(struct snd_kcontrol *kcontrol, aw87390_power_on(aw87390->aw_pa); } - mutex_unlock(&aw87390->lock); - return 1; } @@ -250,7 +248,7 @@ static const struct snd_kcontrol_new aw87390_controls[] = { static int aw87390_request_firmware_file(struct aw87390 *aw87390) { - const struct firmware *cont = NULL; + const struct firmware *cont __free(firmware) = NULL; int ret; aw87390->aw_pa->fw_status = AW87390_DEV_FW_FAILED; @@ -265,14 +263,11 @@ static int aw87390_request_firmware_file(struct aw87390 *aw87390) aw87390->aw_cfg = devm_kzalloc(aw87390->aw_pa->dev, struct_size(aw87390->aw_cfg, data, cont->size), GFP_KERNEL); - if (!aw87390->aw_cfg) { - release_firmware(cont); + if (!aw87390->aw_cfg) return -ENOMEM; - } aw87390->aw_cfg->len = cont->size; memcpy(aw87390->aw_cfg->data, cont->data, cont->size); - release_firmware(cont); ret = aw88395_dev_load_acf_check(aw87390->aw_pa, aw87390->aw_cfg); if (ret) { @@ -280,14 +275,12 @@ static int aw87390_request_firmware_file(struct aw87390 *aw87390) return ret; } - mutex_lock(&aw87390->lock); + guard(mutex)(&aw87390->lock); ret = aw88395_dev_cfg_load(aw87390->aw_pa, aw87390->aw_cfg); if (ret) dev_err(aw87390->aw_pa->dev, "aw_dev acf parse failed\n"); - mutex_unlock(&aw87390->lock); - return ret; } diff --git a/sound/soc/codecs/aw88081.c b/sound/soc/codecs/aw88081.c index d5e886a8f106..3247ba5c71b8 100644 --- a/sound/soc/codecs/aw88081.c +++ b/sound/soc/codecs/aw88081.c @@ -7,6 +7,7 @@ // Author: Weidong Wang <wangweidong.a@awinic.com> // +#include <linux/cleanup.h> #include <linux/firmware.h> #include <linux/i2c.h> #include <linux/regmap.h> @@ -763,9 +764,8 @@ static void aw88081_startup_work(struct work_struct *work) struct aw88081 *aw88081 = container_of(work, struct aw88081, start_work.work); - mutex_lock(&aw88081->lock); + guard(mutex)(&aw88081->lock); aw88081_start_pa(aw88081); - mutex_unlock(&aw88081->lock); } static void aw88081_start(struct aw88081 *aw88081, bool sync_start) @@ -942,11 +942,10 @@ static int aw88081_profile_set(struct snd_kcontrol *kcontrol, int ret; /* pa stop or stopping just set profile */ - mutex_lock(&aw88081->lock); + guard(mutex)(&aw88081->lock); ret = aw88081_dev_set_profile_index(aw88081->aw_pa, ucontrol->value.integer.value[0]); if (ret) { dev_dbg(codec->dev, "profile index does not change"); - mutex_unlock(&aw88081->lock); return 0; } @@ -955,8 +954,6 @@ static int aw88081_profile_set(struct snd_kcontrol *kcontrol, aw88081_start(aw88081, AW88081_SYNC_START); } - mutex_unlock(&aw88081->lock); - return 1; } @@ -1136,7 +1133,7 @@ static int aw88081_dev_init(struct aw88081 *aw88081, struct aw_container *aw_cfg static int aw88081_request_firmware_file(struct aw88081 *aw88081) { - const struct firmware *cont = NULL; + const struct firmware *cont __free(firmware) = NULL; struct aw_container *aw_cfg; int ret; @@ -1150,26 +1147,21 @@ static int aw88081_request_firmware_file(struct aw88081 *aw88081) AW88081_ACF_FILE, cont ? cont->size : 0); aw_cfg = devm_kzalloc(aw88081->aw_pa->dev, struct_size(aw_cfg, data, cont->size), GFP_KERNEL); - if (!aw_cfg) { - release_firmware(cont); + if (!aw_cfg) return -ENOMEM; - } + aw_cfg->len = (int)cont->size; memcpy(aw_cfg->data, cont->data, cont->size); aw88081->aw_cfg = aw_cfg; - release_firmware(cont); - ret = aw88395_dev_load_acf_check(aw88081->aw_pa, aw88081->aw_cfg); if (ret) return ret; - mutex_lock(&aw88081->lock); - ret = aw88081_dev_init(aw88081, aw88081->aw_cfg); - mutex_unlock(&aw88081->lock); + guard(mutex)(&aw88081->lock); - return ret; + return aw88081_dev_init(aw88081, aw88081->aw_cfg); } static int aw88081_playback_event(struct snd_soc_dapm_widget *w, @@ -1178,7 +1170,7 @@ static int aw88081_playback_event(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component); - mutex_lock(&aw88081->lock); + guard(mutex)(&aw88081->lock); switch (event) { case SND_SOC_DAPM_PRE_PMU: aw88081_start(aw88081, AW88081_ASYNC_START); @@ -1189,7 +1181,6 @@ static int aw88081_playback_event(struct snd_soc_dapm_widget *w, default: break; } - mutex_unlock(&aw88081->lock); return 0; } diff --git a/sound/soc/codecs/aw88166.c b/sound/soc/codecs/aw88166.c index 3f15f4ac51f7..d2a138211c59 100644 --- a/sound/soc/codecs/aw88166.c +++ b/sound/soc/codecs/aw88166.c @@ -7,6 +7,7 @@ // Author: Weidong Wang <wangweidong.a@awinic.com> // +#include <linux/cleanup.h> #include <linux/crc32.h> #include <linux/firmware.h> #include <linux/gpio/consumer.h> @@ -1173,9 +1174,8 @@ static void aw88166_startup_work(struct work_struct *work) struct aw88166 *aw88166 = container_of(work, struct aw88166, start_work.work); - mutex_lock(&aw88166->lock); + guard(mutex)(&aw88166->lock); aw88166_start_pa(aw88166); - mutex_unlock(&aw88166->lock); } static void aw88166_start(struct aw88166 *aw88166, bool sync_start) @@ -1413,11 +1413,10 @@ static int aw88166_profile_set(struct snd_kcontrol *kcontrol, struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec); int ret; - mutex_lock(&aw88166->lock); + guard(mutex)(&aw88166->lock); ret = aw88166_dev_set_profile_index(aw88166->aw_pa, ucontrol->value.integer.value[0]); if (ret) { dev_dbg(codec->dev, "profile index does not change"); - mutex_unlock(&aw88166->lock); return 0; } @@ -1426,8 +1425,6 @@ static int aw88166_profile_set(struct snd_kcontrol *kcontrol, aw88166_start(aw88166, AW88166_SYNC_START); } - mutex_unlock(&aw88166->lock); - return 1; } @@ -1573,7 +1570,7 @@ static int aw88166_dev_init(struct aw88166 *aw88166, struct aw_container *aw_cfg static int aw88166_request_firmware_file(struct aw88166 *aw88166) { - const struct firmware *cont = NULL; + const struct firmware *cont __free(firmware) = NULL; const char *fw_name; int ret; @@ -1593,13 +1590,11 @@ static int aw88166_request_firmware_file(struct aw88166 *aw88166) aw88166->aw_cfg = devm_kzalloc(aw88166->aw_pa->dev, struct_size(aw88166->aw_cfg, data, cont->size), GFP_KERNEL); - if (!aw88166->aw_cfg) { - release_firmware(cont); + if (!aw88166->aw_cfg) return -ENOMEM; - } + aw88166->aw_cfg->len = (int)cont->size; memcpy(aw88166->aw_cfg->data, cont->data, cont->size); - release_firmware(cont); ret = aw88395_dev_load_acf_check(aw88166->aw_pa, aw88166->aw_cfg); if (ret) { @@ -1607,12 +1602,12 @@ static int aw88166_request_firmware_file(struct aw88166 *aw88166) return ret; } - mutex_lock(&aw88166->lock); - /* aw device init */ - ret = aw88166_dev_init(aw88166, aw88166->aw_cfg); - if (ret) - dev_err(aw88166->aw_pa->dev, "dev init failed\n"); - mutex_unlock(&aw88166->lock); + scoped_guard(mutex, &aw88166->lock) { + /* aw device init */ + ret = aw88166_dev_init(aw88166, aw88166->aw_cfg); + if (ret) + dev_err(aw88166->aw_pa->dev, "dev init failed\n"); + } return ret; } @@ -1639,7 +1634,7 @@ static int aw88166_playback_event(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct aw88166 *aw88166 = snd_soc_component_get_drvdata(component); - mutex_lock(&aw88166->lock); + guard(mutex)(&aw88166->lock); switch (event) { case SND_SOC_DAPM_PRE_PMU: aw88166_start(aw88166, AW88166_ASYNC_START); @@ -1650,7 +1645,6 @@ static int aw88166_playback_event(struct snd_soc_dapm_widget *w, default: break; } - mutex_unlock(&aw88166->lock); return 0; } diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c index 549783d3e75e..b8d06534bc8f 100644 --- a/sound/soc/codecs/aw88261.c +++ b/sound/soc/codecs/aw88261.c @@ -8,6 +8,7 @@ // Author: Weidong Wang <wangweidong.a@awinic.com> // +#include <linux/cleanup.h> #include <linux/i2c.h> #include <linux/firmware.h> #include <linux/bitops.h> @@ -206,10 +207,10 @@ static int aw88261_dev_check_sysst(struct aw_device *aw_dev) return ret; check_val = reg_val & (~AW88261_BIT_SYSST_CHECK_MASK) - & AW88261_BIT_SYSST_CHECK; - if (check_val != AW88261_BIT_SYSST_CHECK) { + & AW88261_BIT_PLL_CHECK; + if (check_val != AW88261_BIT_PLL_CHECK) { dev_dbg(aw_dev->dev, "check sysst fail, reg_val=0x%04x, check:0x%x", - reg_val, AW88261_BIT_SYSST_CHECK); + reg_val, AW88261_BIT_PLL_CHECK); usleep_range(AW88261_2000_US, AW88261_2000_US + 10); } else { return 0; @@ -960,11 +961,10 @@ static int aw88261_profile_set(struct snd_kcontrol *kcontrol, int ret; /* pa stop or stopping just set profile */ - mutex_lock(&aw88261->lock); + guard(mutex)(&aw88261->lock); ret = aw88261_dev_set_profile_index(aw88261->aw_pa, ucontrol->value.integer.value[0]); if (ret) { dev_dbg(codec->dev, "profile index does not change"); - mutex_unlock(&aw88261->lock); return 0; } @@ -973,8 +973,6 @@ static int aw88261_profile_set(struct snd_kcontrol *kcontrol, aw88261_start(aw88261); } - mutex_unlock(&aw88261->lock); - return 1; } @@ -1038,7 +1036,7 @@ static int aw88261_playback_event(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); - mutex_lock(&aw88261->lock); + guard(mutex)(&aw88261->lock); switch (event) { case SND_SOC_DAPM_PRE_PMU: aw88261_start(aw88261); @@ -1049,7 +1047,6 @@ static int aw88261_playback_event(struct snd_soc_dapm_widget *w, default: break; } - mutex_unlock(&aw88261->lock); return 0; } @@ -1152,7 +1149,7 @@ static int aw88261_dev_init(struct aw88261 *aw88261, struct aw_container *aw_cfg static int aw88261_request_firmware_file(struct aw88261 *aw88261) { - const struct firmware *cont = NULL; + const struct firmware *cont __free(firmware) = NULL; struct aw_container *aw_cfg; const char *fw_name; int ret; @@ -1172,13 +1169,11 @@ static int aw88261_request_firmware_file(struct aw88261 *aw88261) fw_name, cont ? cont->size : 0); aw_cfg = devm_kzalloc(aw88261->aw_pa->dev, struct_size(aw_cfg, data, cont->size), GFP_KERNEL); - if (!aw_cfg) { - release_firmware(cont); + if (!aw_cfg) return -ENOMEM; - } + aw_cfg->len = (int)cont->size; memcpy(aw_cfg->data, cont->data, cont->size); - release_firmware(cont); aw88261->aw_cfg = aw_cfg; @@ -1188,12 +1183,12 @@ static int aw88261_request_firmware_file(struct aw88261 *aw88261) return ret; } - mutex_lock(&aw88261->lock); - /* aw device init */ - ret = aw88261_dev_init(aw88261, aw88261->aw_cfg); - if (ret) - dev_err(aw88261->aw_pa->dev, "dev init failed"); - mutex_unlock(&aw88261->lock); + scoped_guard(mutex, &aw88261->lock) { + /* aw device init */ + ret = aw88261_dev_init(aw88261, aw88261->aw_cfg); + if (ret) + dev_err(aw88261->aw_pa->dev, "dev init failed"); + } return ret; } diff --git a/sound/soc/codecs/aw88261.h b/sound/soc/codecs/aw88261.h index 270ccf375f36..f16f9f8c40a2 100644 --- a/sound/soc/codecs/aw88261.h +++ b/sound/soc/codecs/aw88261.h @@ -194,12 +194,6 @@ AW88261_OTHS_OT_VALUE | \ AW88261_PLLS_LOCKED_VALUE)) -#define AW88261_BIT_SYSST_CHECK \ - (AW88261_BSTS_FINISHED_VALUE | \ - AW88261_SWS_SWITCHING_VALUE | \ - AW88261_CLKS_STABLE_VALUE | \ - AW88261_PLLS_LOCKED_VALUE) - #define AW88261_ULS_HMUTE_START_BIT (14) #define AW88261_ULS_HMUTE_BITS_LEN (1) #define AW88261_ULS_HMUTE_MASK \ diff --git a/sound/soc/codecs/aw88395/aw88395.c b/sound/soc/codecs/aw88395/aw88395.c index ee0e8bd8c54c..2f4108624d13 100644 --- a/sound/soc/codecs/aw88395/aw88395.c +++ b/sound/soc/codecs/aw88395/aw88395.c @@ -8,6 +8,7 @@ // Author: Weidong Wang <wangweidong.a@awinic.com> // +#include <linux/cleanup.h> #include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/firmware.h> @@ -51,9 +52,8 @@ static void aw88395_startup_work(struct work_struct *work) struct aw88395 *aw88395 = container_of(work, struct aw88395, start_work.work); - mutex_lock(&aw88395->lock); + guard(mutex)(&aw88395->lock); aw88395_start_pa(aw88395); - mutex_unlock(&aw88395->lock); } static void aw88395_start(struct aw88395 *aw88395, bool sync_start) @@ -224,11 +224,10 @@ static int aw88395_profile_set(struct snd_kcontrol *kcontrol, int ret; /* pa stop or stopping just set profile */ - mutex_lock(&aw88395->lock); + guard(mutex)(&aw88395->lock); ret = aw88395_dev_set_profile_index(aw88395->aw_pa, ucontrol->value.integer.value[0]); if (ret < 0) { dev_dbg(codec->dev, "profile index does not change"); - mutex_unlock(&aw88395->lock); return 0; } @@ -237,8 +236,6 @@ static int aw88395_profile_set(struct snd_kcontrol *kcontrol, aw88395_start(aw88395, AW88395_SYNC_START); } - mutex_unlock(&aw88395->lock); - return 1; } @@ -366,7 +363,7 @@ static int aw88395_playback_event(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct aw88395 *aw88395 = snd_soc_component_get_drvdata(component); - mutex_lock(&aw88395->lock); + guard(mutex)(&aw88395->lock); switch (event) { case SND_SOC_DAPM_PRE_PMU: aw88395_start(aw88395, AW88395_ASYNC_START); @@ -377,7 +374,6 @@ static int aw88395_playback_event(struct snd_soc_dapm_widget *w, default: break; } - mutex_unlock(&aw88395->lock); return 0; } @@ -461,7 +457,7 @@ static void aw88395_hw_reset(struct aw88395 *aw88395) static int aw88395_request_firmware_file(struct aw88395 *aw88395) { - const struct firmware *cont = NULL; + const struct firmware *cont __free(firmware) = NULL; struct aw_container *aw_cfg; int ret; @@ -477,13 +473,11 @@ static int aw88395_request_firmware_file(struct aw88395 *aw88395) AW88395_ACF_FILE, cont ? cont->size : 0); aw_cfg = devm_kzalloc(aw88395->aw_pa->dev, struct_size(aw_cfg, data, cont->size), GFP_KERNEL); - if (!aw_cfg) { - release_firmware(cont); + if (!aw_cfg) return -ENOMEM; - } + aw_cfg->len = (int)cont->size; memcpy(aw_cfg->data, cont->data, cont->size); - release_firmware(cont); aw88395->aw_cfg = aw_cfg; @@ -495,12 +489,12 @@ static int aw88395_request_firmware_file(struct aw88395 *aw88395) dev_dbg(aw88395->aw_pa->dev, "%s : bin load success\n", __func__); - mutex_lock(&aw88395->lock); - /* aw device init */ - ret = aw88395_dev_init(aw88395->aw_pa, aw88395->aw_cfg); - if (ret < 0) - dev_err(aw88395->aw_pa->dev, "dev init failed"); - mutex_unlock(&aw88395->lock); + scoped_guard(mutex, &aw88395->lock) { + /* aw device init */ + ret = aw88395_dev_init(aw88395->aw_pa, aw88395->aw_cfg); + if (ret < 0) + dev_err(aw88395->aw_pa->dev, "dev init failed"); + } return ret; } diff --git a/sound/soc/codecs/aw88395/aw88395_device.c b/sound/soc/codecs/aw88395/aw88395_device.c index 79c3135a4110..12d42d27560d 100644 --- a/sound/soc/codecs/aw88395/aw88395_device.c +++ b/sound/soc/codecs/aw88395/aw88395_device.c @@ -8,6 +8,7 @@ // Author: Ben Yi <yijiangtao@awinic.com> // +#include <linux/cleanup.h> #include <linux/crc32.h> #include <linux/i2c.h> #include <linux/minmax.h> @@ -70,7 +71,7 @@ int aw_dev_dsp_write(struct aw_device *aw_dev, u32 reg_value; int ret; - mutex_lock(&aw_dev->dsp_lock); + guard(mutex)(&aw_dev->dsp_lock); switch (data_type) { case AW_DSP_16_DATA: ret = aw_dev_dsp_write_16bit(aw_dev, dsp_addr, dsp_data); @@ -93,7 +94,6 @@ int aw_dev_dsp_write(struct aw_device *aw_dev, /* clear dsp chip select state*/ if (regmap_read(aw_dev->regmap, AW88395_ID_REG, ®_value)) dev_err(aw_dev->dev, "%s fail to clear chip state. Err=%d\n", __func__, ret); - mutex_unlock(&aw_dev->dsp_lock); return ret; } @@ -156,7 +156,7 @@ int aw_dev_dsp_read(struct aw_device *aw_dev, u32 reg_value; int ret; - mutex_lock(&aw_dev->dsp_lock); + guard(mutex)(&aw_dev->dsp_lock); switch (data_type) { case AW_DSP_16_DATA: ret = aw_dev_dsp_read_16bit(aw_dev, dsp_addr, dsp_data); @@ -179,7 +179,6 @@ int aw_dev_dsp_read(struct aw_device *aw_dev, /* clear dsp chip select state*/ if (regmap_read(aw_dev->regmap, AW88395_ID_REG, ®_value)) dev_err(aw_dev->dev, "%s fail to clear chip state. Err=%d\n", __func__, ret); - mutex_unlock(&aw_dev->dsp_lock); return ret; } @@ -1110,42 +1109,36 @@ static int aw_dev_dsp_update_container(struct aw_device *aw_dev, #ifdef AW88395_DSP_I2C_WRITES u32 tmp_len; - mutex_lock(&aw_dev->dsp_lock); + guard(mutex)(&aw_dev->dsp_lock); ret = regmap_write(aw_dev->regmap, AW88395_DSPMADD_REG, base); if (ret) - goto error_operation; + return ret; for (i = 0; i < len; i += AW88395_MAX_RAM_WRITE_BYTE_SIZE) { tmp_len = min(len - i, AW88395_MAX_RAM_WRITE_BYTE_SIZE); ret = regmap_raw_write(aw_dev->regmap, AW88395_DSPMDAT_REG, &data[i], tmp_len); if (ret) - goto error_operation; + return ret; } - mutex_unlock(&aw_dev->dsp_lock); #else __be16 reg_val; - mutex_lock(&aw_dev->dsp_lock); + guard(mutex)(&aw_dev->dsp_lock); /* i2c write */ ret = regmap_write(aw_dev->regmap, AW88395_DSPMADD_REG, base); if (ret) - goto error_operation; + return ret; for (i = 0; i < len; i += 2) { reg_val = cpu_to_be16p((u16 *)(data + i)); ret = regmap_write(aw_dev->regmap, AW88395_DSPMDAT_REG, (u16)reg_val); if (ret) - goto error_operation; + return ret; } - mutex_unlock(&aw_dev->dsp_lock); #endif return 0; - -error_operation: - mutex_unlock(&aw_dev->dsp_lock); - return ret; } static int aw_dev_dsp_update_fw(struct aw_device *aw_dev, @@ -1231,14 +1224,14 @@ static int aw_dev_check_sram(struct aw_device *aw_dev) { unsigned int reg_val; - mutex_lock(&aw_dev->dsp_lock); + guard(mutex)(&aw_dev->dsp_lock); /* check the odd bits of reg 0x40 */ regmap_write(aw_dev->regmap, AW88395_DSPMADD_REG, AW88395_DSP_ODD_NUM_BIT_TEST); regmap_read(aw_dev->regmap, AW88395_DSPMADD_REG, ®_val); if (reg_val != AW88395_DSP_ODD_NUM_BIT_TEST) { dev_err(aw_dev->dev, "check reg 0x40 odd bit failed, read[0x%x] != write[0x%x]", reg_val, AW88395_DSP_ODD_NUM_BIT_TEST); - goto error; + return -EPERM; } /* check the even bits of reg 0x40 */ @@ -1247,7 +1240,7 @@ static int aw_dev_check_sram(struct aw_device *aw_dev) if (reg_val != AW88395_DSP_EVEN_NUM_BIT_TEST) { dev_err(aw_dev->dev, "check reg 0x40 even bit failed, read[0x%x] != write[0x%x]", reg_val, AW88395_DSP_EVEN_NUM_BIT_TEST); - goto error; + return -EPERM; } /* check dsp_fw_base_addr */ @@ -1256,7 +1249,7 @@ static int aw_dev_check_sram(struct aw_device *aw_dev) if (reg_val != AW88395_DSP_EVEN_NUM_BIT_TEST) { dev_err(aw_dev->dev, "check dsp fw addr failed, read[0x%x] != write[0x%x]", reg_val, AW88395_DSP_EVEN_NUM_BIT_TEST); - goto error; + return -EPERM; } /* check dsp_cfg_base_addr */ @@ -1265,15 +1258,10 @@ static int aw_dev_check_sram(struct aw_device *aw_dev) if (reg_val != AW88395_DSP_ODD_NUM_BIT_TEST) { dev_err(aw_dev->dev, "check dsp cfg failed, read[0x%x] != write[0x%x]", reg_val, AW88395_DSP_ODD_NUM_BIT_TEST); - goto error; + return -EPERM; } - mutex_unlock(&aw_dev->dsp_lock); return 0; - -error: - mutex_unlock(&aw_dev->dsp_lock); - return -EPERM; } int aw88395_dev_fw_update(struct aw_device *aw_dev, bool up_dsp_fw_en, bool force_up_en) diff --git a/sound/soc/codecs/aw88399-lib.c b/sound/soc/codecs/aw88399-lib.c new file mode 100644 index 000000000000..809c2faa0c0c --- /dev/null +++ b/sound/soc/codecs/aw88399-lib.c @@ -0,0 +1,1409 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// aw88399-lib.c -- AW88399 Common functions for ASoC and HDA audio drivers +// +// Copyright (c) 2023 AWINIC Technology CO., LTD +// +// Author: Weidong Wang <wangweidong.a@awinic.com> +// + +#include <linux/firmware.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/minmax.h> +#include <linux/regmap.h> +#include <sound/soc.h> +#include <sound/aw88399.h> +#include "aw88395/aw88395_device.h" + +const struct regmap_config aw88399_remap_config = { + .val_bits = 16, + .reg_bits = 8, + .max_register = AW88399_REG_MAX, + .reg_format_endian = REGMAP_ENDIAN_LITTLE, + .val_format_endian = REGMAP_ENDIAN_BIG, +}; +EXPORT_SYMBOL_GPL(aw88399_remap_config); + +static void aw_dev_pwd(struct aw_device *aw_dev, bool pwd) +{ + int ret; + + if (pwd) + ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, + ~AW88399_PWDN_MASK, AW88399_PWDN_POWER_DOWN_VALUE); + else + ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, + ~AW88399_PWDN_MASK, AW88399_PWDN_WORKING_VALUE); + + if (ret) + dev_dbg(aw_dev->dev, "%s failed", __func__); +} + +static void aw_dev_get_int_status(struct aw_device *aw_dev, unsigned short *int_status) +{ + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88399_SYSINT_REG, ®_val); + if (ret) + dev_err(aw_dev->dev, "read interrupt reg fail, ret=%d", ret); + else + *int_status = reg_val; + + dev_dbg(aw_dev->dev, "read interrupt reg=0x%04x", *int_status); +} + +static void aw_dev_clear_int_status(struct aw_device *aw_dev) +{ + u16 int_status; + + /* read int status and clear */ + aw_dev_get_int_status(aw_dev, &int_status); + /* make sure int status is clear */ + aw_dev_get_int_status(aw_dev, &int_status); + if (int_status) + dev_dbg(aw_dev->dev, "int status(%d) is not cleaned.\n", int_status); +} + +static int aw_dev_get_iis_status(struct aw_device *aw_dev) +{ + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, ®_val); + if (ret) + return ret; + if ((reg_val & AW88399_BIT_PLL_CHECK) != AW88399_BIT_PLL_CHECK) { + dev_err(aw_dev->dev, "check pll lock fail, reg_val:0x%04x", reg_val); + return -EINVAL; + } + + return 0; +} + +static int aw_dev_check_mode1_pll(struct aw_device *aw_dev) +{ + int ret, i; + + for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { + ret = aw_dev_get_iis_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode1 iis signal check error"); + usleep_range(AW88399_2000_US, AW88399_2000_US + 10); + } else { + return 0; + } + } + + return -EPERM; +} + +static int aw_dev_check_mode2_pll(struct aw_device *aw_dev) +{ + unsigned int reg_val; + int ret, i; + + ret = regmap_read(aw_dev->regmap, AW88399_PLLCTRL2_REG, ®_val); + if (ret) + return ret; + + reg_val &= (~AW88399_CCO_MUX_MASK); + if (reg_val == AW88399_CCO_MUX_DIVIDED_VALUE) { + dev_dbg(aw_dev->dev, "CCO_MUX is already divider"); + return -EPERM; + } + + /* change mode2 */ + ret = regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG, + ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_DIVIDED_VALUE); + if (ret) + return ret; + + for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { + ret = aw_dev_get_iis_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 iis signal check error"); + usleep_range(AW88399_2000_US, AW88399_2000_US + 10); + } else { + break; + } + } + + /* change mode1 */ + regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG, + ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_BYPASS_VALUE); + if (ret == 0) { + usleep_range(AW88399_2000_US, AW88399_2000_US + 10); + for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { + ret = aw_dev_get_iis_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error"); + usleep_range(AW88399_2000_US, AW88399_2000_US + 10); + } else { + break; + } + } + } + + return ret; +} + +int aw_dev_check_syspll(struct aw_device *aw_dev) +{ + int ret; + + ret = aw_dev_check_mode1_pll(aw_dev); + if (ret) { + dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check"); + ret = aw_dev_check_mode2_pll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 check iis failed"); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(aw_dev_check_syspll); + +static int aw_dev_check_sysst(struct aw88399 *aw88399) +{ + struct aw_device *aw_dev = aw88399->aw_pa; + unsigned int check_val; + unsigned int reg_val; + int ret, i; + + ret = regmap_read(aw_dev->regmap, AW88399_PWMCTRL3_REG, ®_val); + if (ret) + return ret; + + if (reg_val & (~AW88399_NOISE_GATE_EN_MASK)) + check_val = AW88399_BIT_SYSST_NOSWS_CHECK; + else + check_val = AW88399_BIT_SYSST_SWS_CHECK; + + /* + * On some hardware the BSTS (boost-finished) status bit does not + * reliably assert even when audio output is working normally. + * Allow per-instance bypass when flagged by the side-codec driver. + */ + if (aw88399->bsts_unreliable) + check_val &= ~AW88399_BSTS_FINISHED_VALUE; + + for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { + ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, ®_val); + if (ret) + return ret; + + if ((reg_val & (~AW88399_BIT_SYSST_CHECK_MASK) & check_val) != check_val) { + dev_err(aw_dev->dev, "check sysst fail, cnt=%d, reg_val=0x%04x, check:0x%x", + i, reg_val, AW88399_BIT_SYSST_NOSWS_CHECK); + usleep_range(AW88399_2000_US, AW88399_2000_US + 10); + } else { + return 0; + } + } + + return -EPERM; +} + +static void aw_dev_amppd(struct aw_device *aw_dev, bool amppd) +{ + int ret; + + if (amppd) + ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, + ~AW88399_AMPPD_MASK, AW88399_AMPPD_POWER_DOWN_VALUE); + else + ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, + ~AW88399_AMPPD_MASK, AW88399_AMPPD_WORKING_VALUE); + + if (ret) + dev_dbg(aw_dev->dev, "%s failed", __func__); +} + +void aw_dev_dsp_enable(struct aw_device *aw_dev, bool is_enable) +{ + int ret; + + if (is_enable) + ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, + ~AW88399_DSPBY_MASK, AW88399_DSPBY_WORKING_VALUE); + else + ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, + ~AW88399_DSPBY_MASK, AW88399_DSPBY_BYPASS_VALUE); + + if (ret) + dev_dbg(aw_dev->dev, "%s failed\n", __func__); +} +EXPORT_SYMBOL_GPL(aw_dev_dsp_enable); + +static int aw88399_dev_get_icalk(struct aw88399 *aw88399, int16_t *icalk) +{ + uint16_t icalkh_val, icalkl_val, icalk_val; + struct aw_device *aw_dev = aw88399->aw_pa; + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88399_EFRH4_REG, ®_val); + if (ret) + return ret; + icalkh_val = reg_val & (~AW88399_EF_ISN_GESLP_H_MASK); + + ret = regmap_read(aw_dev->regmap, AW88399_EFRL4_REG, ®_val); + if (ret) + return ret; + icalkl_val = reg_val & (~AW88399_EF_ISN_GESLP_L_MASK); + + if (aw88399->check_val == AW_EF_AND_CHECK) + icalk_val = icalkh_val & icalkl_val; + else + icalk_val = icalkh_val | icalkl_val; + + if (icalk_val & (~AW88399_EF_ISN_GESLP_SIGN_MASK)) + icalk_val = icalk_val | AW88399_EF_ISN_GESLP_SIGN_NEG; + *icalk = (int16_t)icalk_val; + + return 0; +} + +static int aw88399_dev_get_vcalk(struct aw88399 *aw88399, int16_t *vcalk) +{ + uint16_t vcalkh_val, vcalkl_val, vcalk_val; + struct aw_device *aw_dev = aw88399->aw_pa; + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88399_EFRH3_REG, ®_val); + if (ret) + return ret; + + vcalkh_val = reg_val & (~AW88399_EF_VSN_GESLP_H_MASK); + + ret = regmap_read(aw_dev->regmap, AW88399_EFRL3_REG, ®_val); + if (ret) + return ret; + + vcalkl_val = reg_val & (~AW88399_EF_VSN_GESLP_L_MASK); + + if (aw88399->check_val == AW_EF_AND_CHECK) + vcalk_val = vcalkh_val & vcalkl_val; + else + vcalk_val = vcalkh_val | vcalkl_val; + + if (vcalk_val & AW88399_EF_VSN_GESLP_SIGN_MASK) + vcalk_val = vcalk_val | AW88399_EF_VSN_GESLP_SIGN_NEG; + *vcalk = (int16_t)vcalk_val; + + return 0; +} + +static int aw88399_dev_get_internal_vcalk(struct aw88399 *aw88399, int16_t *vcalk) +{ + uint16_t vcalkh_val, vcalkl_val, vcalk_val; + struct aw_device *aw_dev = aw88399->aw_pa; + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88399_EFRH2_REG, ®_val); + if (ret) + return ret; + vcalkh_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_H_MASK); + + ret = regmap_read(aw_dev->regmap, AW88399_EFRL2_REG, ®_val); + if (ret) + return ret; + vcalkl_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_L_MASK); + + if (aw88399->check_val == AW_EF_AND_CHECK) + vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) & + (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT); + else + vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) | + (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT); + + if (vcalk_val & (~AW88399_TEM4_SIGN_MASK)) + vcalk_val = vcalk_val | AW88399_TEM4_SIGN_NEG; + + *vcalk = (int16_t)vcalk_val; + + return 0; +} + +static int aw_dev_set_vcalb(struct aw88399 *aw88399) +{ + struct aw_device *aw_dev = aw88399->aw_pa; + unsigned int vsense_select, vsense_value; + int32_t ical_k, vcal_k, vcalb; + int16_t icalk, vcalk; + uint16_t reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88399_VSNCTRL1_REG, &vsense_value); + if (ret) + return ret; + + vsense_select = vsense_value & (~AW88399_VDSEL_MASK); + + ret = aw88399_dev_get_icalk(aw88399, &icalk); + if (ret) { + dev_err(aw_dev->dev, "get icalk failed\n"); + return ret; + } + + ical_k = icalk * AW88399_ICABLK_FACTOR + AW88399_CABL_BASE_VALUE; + + switch (vsense_select) { + case AW88399_DEV_VDSEL_VSENSE: + ret = aw88399_dev_get_vcalk(aw88399, &vcalk); + vcal_k = vcalk * AW88399_VCABLK_FACTOR + AW88399_CABL_BASE_VALUE; + vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_FACTOR / AW88399_ISCAL_FACTOR * + ical_k / vcal_k * aw88399->vcalb_init_val; + break; + case AW88399_DEV_VDSEL_DAC: + ret = aw88399_dev_get_internal_vcalk(aw88399, &vcalk); + vcal_k = vcalk * AW88399_VCABLK_DAC_FACTOR + AW88399_CABL_BASE_VALUE; + vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_DAC_FACTOR / + AW88399_ISCAL_DAC_FACTOR * ical_k / + vcal_k * aw88399->vcalb_init_val; + break; + default: + dev_err(aw_dev->dev, "%s: unsupported vsense\n", __func__); + ret = -EINVAL; + break; + } + if (ret) + return ret; + + vcalb = vcalb >> AW88399_VCALB_ADJ_FACTOR; + reg_val = (uint32_t)vcalb; + + regmap_write(aw_dev->regmap, AW88399_DSPVCALB_REG, reg_val); + + return 0; +} + +int aw_dev_update_cali_re(struct aw_cali_desc *cali_desc) +{ + struct aw_device *aw_dev = + container_of(cali_desc, struct aw_device, cali_desc); + uint16_t re_lbits, re_hbits; + u32 cali_re; + int ret; + + if ((aw_dev->cali_desc.cali_re >= AW88399_CALI_RE_MAX) || + (aw_dev->cali_desc.cali_re <= AW88399_CALI_RE_MIN)) + return -EINVAL; + + cali_re = AW88399_SHOW_RE_TO_DSP_RE((aw_dev->cali_desc.cali_re + + aw_dev->cali_desc.ra), AW88399_DSP_RE_SHIFT); + + re_hbits = (cali_re & (~AW88399_CALI_RE_HBITS_MASK)) >> AW88399_CALI_RE_HBITS_SHIFT; + re_lbits = (cali_re & (~AW88399_CALI_RE_LBITS_MASK)) >> AW88399_CALI_RE_LBITS_SHIFT; + + ret = regmap_write(aw_dev->regmap, AW88399_ACR1_REG, re_hbits); + if (ret) { + dev_err(aw_dev->dev, "set cali re error"); + return ret; + } + + ret = regmap_write(aw_dev->regmap, AW88399_ACR2_REG, re_lbits); + if (ret) + dev_err(aw_dev->dev, "set cali re error"); + + return ret; +} +EXPORT_SYMBOL_GPL(aw_dev_update_cali_re); + +static int aw_dev_fw_crc_check(struct aw_device *aw_dev) +{ + uint16_t check_val, fw_len_val; + unsigned int reg_val; + int ret; + + /* calculate fw_end_addr */ + fw_len_val = ((aw_dev->dsp_fw_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_FW_BASE_ADDR; + + /* write fw_end_addr to crc_end_addr */ + ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, + ~AW88399_CRC_END_ADDR_MASK, fw_len_val); + if (ret) + return ret; + /* enable fw crc check */ + ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, + ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_ENABLE_VALUE); + + usleep_range(AW88399_2000_US, AW88399_2000_US + 10); + + /* read crc check result */ + regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, ®_val); + if (ret) + return ret; + + check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT; + + /* disable fw crc check */ + ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, + ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_DISABLE_VALUE); + if (ret) + return ret; + + if (check_val != AW88399_CRC_CHECK_PASS_VAL) { + dev_err(aw_dev->dev, "%s failed, check_val 0x%x != 0x%x", + __func__, check_val, AW88399_CRC_CHECK_PASS_VAL); + ret = -EINVAL; + } + + return ret; +} + +static int aw_dev_cfg_crc_check(struct aw_device *aw_dev) +{ + uint16_t check_val, cfg_len_val; + unsigned int reg_val; + int ret; + + /* calculate cfg end addr */ + cfg_len_val = ((aw_dev->dsp_cfg_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_CFG_BASE_ADDR; + + /* write cfg_end_addr to crc_end_addr */ + ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, + ~AW88399_CRC_END_ADDR_MASK, cfg_len_val); + if (ret) + return ret; + + /* enable cfg crc check */ + ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, + ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_ENABLE_VALUE); + if (ret) + return ret; + + usleep_range(AW88399_1000_US, AW88399_1000_US + 10); + + /* read crc check result */ + ret = regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, ®_val); + if (ret) + return ret; + + check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT; + + /* disable cfg crc check */ + ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, + ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_DISABLE_VALUE); + if (ret) + return ret; + + if (check_val != AW88399_CRC_CHECK_PASS_VAL) { + dev_err(aw_dev->dev, "crc_check failed, check val 0x%x != 0x%x", + check_val, AW88399_CRC_CHECK_PASS_VAL); + ret = -EINVAL; + } + + return ret; +} + +static int aw_dev_hw_crc_check(struct aw88399 *aw88399) +{ + struct aw_device *aw_dev = aw88399->aw_pa; + int ret; + + ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, + ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_BYPASS_VALUE); + if (ret) + return ret; + + ret = aw_dev_fw_crc_check(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "fw_crc_check failed\n"); + goto crc_check_failed; + } + + ret = aw_dev_cfg_crc_check(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "cfg_crc_check failed\n"); + goto crc_check_failed; + } + + ret = regmap_write(aw_dev->regmap, AW88399_CRCCTRL_REG, aw88399->crc_init_val); + if (ret) + return ret; + + ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, + ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE); + + return ret; + +crc_check_failed: + regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, + ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE); + return ret; +} + +static void aw_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag) +{ + int ret; + + if (flag) + ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCTRL3_REG, + ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_ENABLE_VALUE); + else + ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, + ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_DISABLE_VALUE); + + if (ret) + dev_dbg(aw_dev->dev, "%s failed", __func__); +} + +int aw_dev_get_dsp_status(struct aw_device *aw_dev) +{ + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88399_WDT_REG, ®_val); + if (ret) + return ret; + if (!(reg_val & (~AW88399_WDT_CNT_MASK))) + return -EPERM; + + return 0; +} +EXPORT_SYMBOL_GPL(aw_dev_get_dsp_status); + +static int aw_dev_dsp_check(struct aw_device *aw_dev) +{ + int ret, i; + + switch (aw_dev->dsp_cfg) { + case AW88399_DEV_DSP_BYPASS: + dev_dbg(aw_dev->dev, "dsp bypass"); + ret = 0; + break; + case AW88399_DEV_DSP_WORK: + aw_dev_dsp_enable(aw_dev, false); + aw_dev_dsp_enable(aw_dev, true); + usleep_range(AW88399_1000_US, AW88399_1000_US + 10); + for (i = 0; i < AW88399_DEV_DSP_CHECK_MAX; i++) { + ret = aw_dev_get_dsp_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "dsp wdt status error=%d", ret); + usleep_range(AW88399_2000_US, AW88399_2000_US + 10); + } + } + break; + default: + dev_err(aw_dev->dev, "unknown dsp cfg=%d", aw_dev->dsp_cfg); + ret = -EINVAL; + break; + } + + return ret; +} + +int aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + unsigned int reg_value; + u16 real_value; + int ret; + + real_value = min((value + vol_desc->init_volume), (unsigned int)AW88399_MUTE_VOL); + + ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL2_REG, ®_value); + if (ret) + return ret; + + dev_dbg(aw_dev->dev, "value 0x%x , reg:0x%x", value, real_value); + + real_value = (real_value << AW88399_VOL_START_BIT) | (reg_value & AW88399_VOL_MASK); + + ret = regmap_write(aw_dev->regmap, AW88399_SYSCTRL2_REG, real_value); + + return ret; +} +EXPORT_SYMBOL_GPL(aw_dev_set_volume); + +static void aw_dev_fade_in(struct aw_device *aw_dev) +{ + struct aw_volume_desc *desc = &aw_dev->volume_desc; + u16 fade_in_vol = desc->ctl_volume; + int fade_step = aw_dev->fade_step; + int i; + + if (fade_step == 0 || aw_dev->fade_in_time == 0) { + aw_dev_set_volume(aw_dev, fade_in_vol); + return; + } + + for (i = AW88399_MUTE_VOL; i >= fade_in_vol; i -= fade_step) { + aw_dev_set_volume(aw_dev, i); + usleep_range(aw_dev->fade_in_time, aw_dev->fade_in_time + 10); + } + + if (i != fade_in_vol) + aw_dev_set_volume(aw_dev, fade_in_vol); +} + +static void aw_dev_fade_out(struct aw_device *aw_dev) +{ + struct aw_volume_desc *desc = &aw_dev->volume_desc; + int fade_step = aw_dev->fade_step; + int i; + + if (fade_step == 0 || aw_dev->fade_out_time == 0) { + aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL); + return; + } + + for (i = desc->ctl_volume; i <= AW88399_MUTE_VOL; i += fade_step) { + aw_dev_set_volume(aw_dev, i); + usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); + } + + if (i != AW88399_MUTE_VOL) { + aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL); + usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); + } +} + +void aw88399_dev_mute(struct aw_device *aw_dev, bool is_mute) +{ + if (is_mute) { + aw_dev_fade_out(aw_dev); + regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, + ~AW88399_HMUTE_MASK, AW88399_HMUTE_ENABLE_VALUE); + } else { + regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, + ~AW88399_HMUTE_MASK, AW88399_HMUTE_DISABLE_VALUE); + aw_dev_fade_in(aw_dev); + } +} +EXPORT_SYMBOL_GPL(aw88399_dev_mute); + +static void aw88399_dev_set_dither(struct aw88399 *aw88399, bool dither) +{ + struct aw_device *aw_dev = aw88399->aw_pa; + + if (dither) + regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, + ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_ENABLE_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, + ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_DISABLE_VALUE); +} + +static int aw88399_dev_start(struct aw88399 *aw88399) +{ + struct aw_device *aw_dev = aw88399->aw_pa; + int ret; + + if (aw_dev->status == AW88399_DEV_PW_ON) { + dev_dbg(aw_dev->dev, "already power on"); + return 0; + } + + aw88399_dev_set_dither(aw88399, false); + + /* power on */ + aw_dev_pwd(aw_dev, false); + usleep_range(AW88399_2000_US, AW88399_2000_US + 10); + + ret = aw_dev_check_syspll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "pll check failed cannot start"); + goto pll_check_fail; + } + + /* amppd on */ + aw_dev_amppd(aw_dev, false); + usleep_range(AW88399_1000_US, AW88399_1000_US + 50); + + /* check i2s status */ + ret = aw_dev_check_sysst(aw88399); + if (ret) { + dev_err(aw_dev->dev, "sysst check failed"); + goto sysst_check_fail; + } + + if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK) { + ret = aw_dev_hw_crc_check(aw88399); + if (ret) { + dev_err(aw_dev->dev, "dsp crc check failed"); + goto crc_check_fail; + } + aw_dev_dsp_enable(aw_dev, false); + aw_dev_set_vcalb(aw88399); + aw_dev_update_cali_re(&aw_dev->cali_desc); + + ret = aw_dev_dsp_check(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "dsp status check failed"); + goto dsp_check_fail; + } + } else { + dev_dbg(aw_dev->dev, "start pa with dsp bypass"); + } + + /* enable tx feedback */ + aw_dev_i2s_tx_enable(aw_dev, true); + + if (aw88399->dither_st == AW88399_DITHER_EN_ENABLE_VALUE) + aw88399_dev_set_dither(aw88399, true); + + /* close mute */ + aw88399_dev_mute(aw_dev, false); + /* clear inturrupt */ + aw_dev_clear_int_status(aw_dev); + aw_dev->status = AW88399_DEV_PW_ON; + + return 0; + +dsp_check_fail: +crc_check_fail: + aw_dev_dsp_enable(aw_dev, false); +sysst_check_fail: + aw_dev_clear_int_status(aw_dev); + aw_dev_amppd(aw_dev, true); +pll_check_fail: + aw_dev_pwd(aw_dev, true); + aw_dev->status = AW88399_DEV_PW_OFF; + + return ret; +} + +static int aw_dev_dsp_update_container(struct aw_device *aw_dev, + unsigned char *data, unsigned int len, unsigned short base) +{ + u32 tmp_len; + int i, ret; + + ret = regmap_write(aw_dev->regmap, AW88399_DSPMADD_REG, base); + if (ret) + return ret; + + for (i = 0; i < len; i += AW88399_MAX_RAM_WRITE_BYTE_SIZE) { + tmp_len = min(len - i, AW88399_MAX_RAM_WRITE_BYTE_SIZE); + ret = regmap_raw_write(aw_dev->regmap, AW88399_DSPMDAT_REG, + &data[i], tmp_len); + if (ret) + return ret; + } + + return 0; +} + +static int aw_dev_get_ra(struct aw_cali_desc *cali_desc) +{ + struct aw_device *aw_dev = + container_of(cali_desc, struct aw_device, cali_desc); + u32 dsp_ra; + int ret; + + ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CFG_ADPZ_RA, + &dsp_ra, AW_DSP_32_DATA); + if (ret) { + dev_err(aw_dev->dev, "read ra error"); + return ret; + } + + cali_desc->ra = AW88399_DSP_RE_TO_SHOW_RE(dsp_ra, + AW88399_DSP_RE_SHIFT); + + return 0; +} + +static int aw_dev_dsp_update_cfg(struct aw_device *aw_dev, + unsigned char *data, unsigned int len) +{ + int ret; + + dev_dbg(aw_dev->dev, "dsp config len:%d", len); + + if (!len || !data) { + dev_err(aw_dev->dev, "dsp config data is null or len is 0"); + return -EINVAL; + } + + ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_CFG_ADDR); + if (ret) + return ret; + + aw_dev->dsp_cfg_len = len; + + ret = aw_dev_get_ra(&aw_dev->cali_desc); + + return ret; +} + +static int aw_dev_dsp_update_fw(struct aw_device *aw_dev, + unsigned char *data, unsigned int len) +{ + int ret; + + dev_dbg(aw_dev->dev, "dsp firmware len:%d", len); + + if (!len || !data) { + dev_err(aw_dev->dev, "dsp firmware data is null or len is 0"); + return -EINVAL; + } + + aw_dev->dsp_fw_len = len; + ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_FW_ADDR); + + return ret; +} + +static int aw_dev_check_sram(struct aw_device *aw_dev) +{ + unsigned int reg_val; + + /* read dsp_rom_check_reg */ + aw_dev_dsp_read(aw_dev, AW88399_DSP_ROM_CHECK_ADDR, ®_val, AW_DSP_16_DATA); + if (reg_val != AW88399_DSP_ROM_CHECK_DATA) { + dev_err(aw_dev->dev, "check dsp rom failed, read[0x%x] != check[0x%x]", + reg_val, AW88399_DSP_ROM_CHECK_DATA); + return -EPERM; + } + + /* check dsp_cfg_base_addr */ + aw_dev_dsp_write(aw_dev, AW88399_DSP_CFG_ADDR, + AW88399_DSP_ODD_NUM_BIT_TEST, AW_DSP_16_DATA); + aw_dev_dsp_read(aw_dev, AW88399_DSP_CFG_ADDR, ®_val, AW_DSP_16_DATA); + if (reg_val != AW88399_DSP_ODD_NUM_BIT_TEST) { + dev_err(aw_dev->dev, "check dsp cfg failed, read[0x%x] != write[0x%x]", + reg_val, AW88399_DSP_ODD_NUM_BIT_TEST); + return -EPERM; + } + + return 0; +} + +static void aw_dev_select_memclk(struct aw_device *aw_dev, unsigned char flag) +{ + int ret; + + switch (flag) { + case AW88399_DEV_MEMCLK_PLL: + ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, + ~AW88399_MEM_CLKSEL_MASK, + AW88399_MEM_CLKSEL_DAPHCLK_VALUE); + if (ret) + dev_err(aw_dev->dev, "memclk select pll failed"); + break; + case AW88399_DEV_MEMCLK_OSC: + ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, + ~AW88399_MEM_CLKSEL_MASK, + AW88399_MEM_CLKSEL_OSCCLK_VALUE); + if (ret) + dev_err(aw_dev->dev, "memclk select OSC failed"); + break; + default: + dev_err(aw_dev->dev, "unknown memclk config, flag=0x%x", flag); + break; + } +} + +static void aw_dev_get_cur_mode_st(struct aw_device *aw_dev) +{ + struct aw_profctrl_desc *profctrl_desc = &aw_dev->profctrl_desc; + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL_REG, ®_val); + if (ret) { + dev_dbg(aw_dev->dev, "%s failed", __func__); + return; + } + if ((reg_val & (~AW88399_RCV_MODE_MASK)) == AW88399_RCV_MODE_RECEIVER_VALUE) + profctrl_desc->cur_mode = AW88399_RCV_MODE; + else + profctrl_desc->cur_mode = AW88399_NOT_RCV_MODE; +} + +static int aw_dev_update_reg_container(struct aw88399 *aw88399, + unsigned char *data, unsigned int len) +{ + struct aw_device *aw_dev = aw88399->aw_pa; + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + u16 read_vol, reg_val; + int data_len, i, ret; + int16_t *reg_data; + u8 reg_addr; + + reg_data = (int16_t *)data; + data_len = len >> 1; + + if (data_len & 0x1) { + dev_err(aw_dev->dev, "data len:%d unsupported", data_len); + return -EINVAL; + } + + for (i = 0; i < data_len; i += 2) { + reg_addr = reg_data[i]; + reg_val = reg_data[i + 1]; + + if (reg_addr == AW88399_DSPVCALB_REG) { + aw88399->vcalb_init_val = reg_val; + continue; + } + + if (reg_addr == AW88399_SYSCTRL_REG) { + if (reg_val & (~AW88399_DSPBY_MASK)) + aw_dev->dsp_cfg = AW88399_DEV_DSP_BYPASS; + else + aw_dev->dsp_cfg = AW88399_DEV_DSP_WORK; + + reg_val &= (AW88399_HMUTE_MASK | AW88399_PWDN_MASK | + AW88399_DSPBY_MASK); + reg_val |= (AW88399_HMUTE_ENABLE_VALUE | AW88399_PWDN_POWER_DOWN_VALUE | + AW88399_DSPBY_BYPASS_VALUE); + } + + if (reg_addr == AW88399_I2SCTRL3_REG) { + reg_val &= AW88399_I2STXEN_MASK; + reg_val |= AW88399_I2STXEN_DISABLE_VALUE; + } + + if (reg_addr == AW88399_SYSCTRL2_REG) { + read_vol = (reg_val & (~AW88399_VOL_MASK)) >> + AW88399_VOL_START_BIT; + aw_dev->volume_desc.init_volume = read_vol; + } + + if (reg_addr == AW88399_DBGCTRL_REG) { + if ((reg_val & (~AW88399_EF_DBMD_MASK)) == AW88399_EF_DBMD_OR_VALUE) + aw88399->check_val = AW_EF_OR_CHECK; + else + aw88399->check_val = AW_EF_AND_CHECK; + + aw88399->dither_st = reg_val & (~AW88399_DITHER_EN_MASK); + } + + if (reg_addr == AW88399_CRCCTRL_REG) + aw88399->crc_init_val = reg_val; + + ret = regmap_write(aw_dev->regmap, reg_addr, reg_val); + if (ret) + return ret; + } + + aw_dev_pwd(aw_dev, false); + usleep_range(AW88399_1000_US, AW88399_1000_US + 10); + + aw_dev_get_cur_mode_st(aw_dev); + + if (aw_dev->prof_cur != aw_dev->prof_index) + vol_desc->ctl_volume = 0; + else + aw_dev_set_volume(aw_dev, vol_desc->ctl_volume); + + return 0; +} + +static int aw_dev_reg_update(struct aw88399 *aw88399, + unsigned char *data, unsigned int len) +{ + int ret; + + if (!len || !data) { + dev_err(aw88399->aw_pa->dev, "reg data is null or len is 0"); + return -EINVAL; + } + + ret = aw_dev_update_reg_container(aw88399, data, len); + if (ret) + dev_err(aw88399->aw_pa->dev, "reg update failed"); + + return ret; +} + +int aw88399_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name) +{ + struct aw_prof_info *prof_info = &aw_dev->prof_info; + struct aw_prof_desc *prof_desc; + + if ((index >= aw_dev->prof_info.count) || (index < 0)) { + dev_err(aw_dev->dev, "index[%d] overflow count[%d]", + index, aw_dev->prof_info.count); + return -EINVAL; + } + + prof_desc = &aw_dev->prof_info.prof_desc[index]; + + *prof_name = prof_info->prof_name_list[prof_desc->id]; + + return 0; +} +EXPORT_SYMBOL_GPL(aw88399_dev_get_prof_name); + +static int aw88399_dev_get_prof_data(struct aw_device *aw_dev, int index, + struct aw_prof_desc **prof_desc) +{ + if ((index >= aw_dev->prof_info.count) || (index < 0)) { + dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n", + __func__, index, aw_dev->prof_info.count); + return -EINVAL; + } + + *prof_desc = &aw_dev->prof_info.prof_desc[index]; + + return 0; +} + +static int aw88399_dev_fw_update(struct aw88399 *aw88399, bool up_dsp_fw_en, bool force_up_en) +{ + struct aw_device *aw_dev = aw88399->aw_pa; + struct aw_prof_desc *prof_index_desc; + struct aw_sec_data_desc *sec_desc; + char *prof_name; + int ret; + + if ((aw_dev->prof_cur == aw_dev->prof_index) && + (force_up_en == AW88399_FORCE_UPDATE_OFF)) { + dev_dbg(aw_dev->dev, "scene no change, not update"); + return 0; + } + + if (aw_dev->fw_status == AW88399_DEV_FW_FAILED) { + dev_err(aw_dev->dev, "fw status[%d] error", aw_dev->fw_status); + return -EPERM; + } + + ret = aw88399_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name); + if (ret) + return ret; + + dev_dbg(aw_dev->dev, "start update %s", prof_name); + + ret = aw88399_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc); + if (ret) + return ret; + + /* update reg */ + sec_desc = prof_index_desc->sec_desc; + ret = aw_dev_reg_update(aw88399, sec_desc[AW88395_DATA_TYPE_REG].data, + sec_desc[AW88395_DATA_TYPE_REG].len); + if (ret) { + dev_err(aw_dev->dev, "update reg failed"); + return ret; + } + + aw88399_dev_mute(aw_dev, true); + + if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK) + aw_dev_dsp_enable(aw_dev, false); + + aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC); + + ret = aw_dev_check_sram(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "check sram failed"); + goto error; + } + + if (up_dsp_fw_en) { + dev_dbg(aw_dev->dev, "fw_ver: [%x]", prof_index_desc->fw_ver); + ret = aw_dev_dsp_update_fw(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_FW].data, + sec_desc[AW88395_DATA_TYPE_DSP_FW].len); + if (ret) { + dev_err(aw_dev->dev, "update dsp fw failed"); + goto error; + } + } + + /* update dsp config */ + ret = aw_dev_dsp_update_cfg(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_CFG].data, + sec_desc[AW88395_DATA_TYPE_DSP_CFG].len); + if (ret) { + dev_err(aw_dev->dev, "update dsp cfg failed"); + goto error; + } + + aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL); + + aw_dev->prof_cur = aw_dev->prof_index; + + return 0; + +error: + aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL); + return ret; +} + +static void aw88399_start_pa(struct aw88399 *aw88399) +{ + int ret, i; + + for (i = 0; i < AW88399_START_RETRIES; i++) { + ret = aw88399_dev_start(aw88399); + if (ret) { + dev_err(aw88399->aw_pa->dev, "aw88399 device start failed. retry = %d", i); + ret = aw88399_dev_fw_update(aw88399, AW88399_DSP_FW_UPDATE_ON, true); + if (ret) { + dev_err(aw88399->aw_pa->dev, "fw update failed"); + continue; + } + } else { + dev_dbg(aw88399->aw_pa->dev, "start success\n"); + break; + } + } +} + +void aw88399_startup_work(struct work_struct *work) +{ + struct aw88399 *aw88399 = + container_of(work, struct aw88399, start_work.work); + + mutex_lock(&aw88399->lock); + aw88399_start_pa(aw88399); + mutex_unlock(&aw88399->lock); +} +EXPORT_SYMBOL_GPL(aw88399_startup_work); + +void aw88399_start(struct aw88399 *aw88399, bool sync_start) +{ + int ret; + + if (aw88399->aw_pa->fw_status != AW88399_DEV_FW_OK) + return; + + if (aw88399->aw_pa->status == AW88399_DEV_PW_ON) + return; + + ret = aw88399_dev_fw_update(aw88399, aw88399->fw_needs_reload ? + AW88399_DSP_FW_UPDATE_ON : AW88399_DSP_FW_UPDATE_OFF, true); + if (ret) { + dev_err(aw88399->aw_pa->dev, "fw update failed."); + return; + } + + aw88399->fw_needs_reload = false; + + if (sync_start == AW88399_SYNC_START) + aw88399_start_pa(aw88399); + else + queue_delayed_work(system_dfl_wq, + &aw88399->start_work, + AW88399_START_WORK_DELAY_MS); +} +EXPORT_SYMBOL_GPL(aw88399_start); + +static int aw_dev_check_sysint(struct aw_device *aw_dev) +{ + u16 reg_val; + + aw_dev_get_int_status(aw_dev, ®_val); + if (reg_val & AW88399_BIT_SYSINT_CHECK) { + dev_err(aw_dev->dev, "pa stop check fail:0x%04x", reg_val); + return -EINVAL; + } + + return 0; +} + +int aw88399_stop(struct aw_device *aw_dev) +{ + struct aw_sec_data_desc *dsp_cfg = + &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_CFG]; + struct aw_sec_data_desc *dsp_fw = + &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_FW]; + int int_st; + + if (aw_dev->status == AW88399_DEV_PW_OFF) { + dev_dbg(aw_dev->dev, "already power off"); + return 0; + } + + aw_dev->status = AW88399_DEV_PW_OFF; + + aw88399_dev_mute(aw_dev, true); + usleep_range(AW88399_4000_US, AW88399_4000_US + 100); + + aw_dev_i2s_tx_enable(aw_dev, false); + usleep_range(AW88399_1000_US, AW88399_1000_US + 100); + + int_st = aw_dev_check_sysint(aw_dev); + + aw_dev_dsp_enable(aw_dev, false); + + aw_dev_amppd(aw_dev, true); + + if (int_st) { + aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC); + aw_dev_dsp_update_fw(aw_dev, dsp_fw->data, dsp_fw->len); + aw_dev_dsp_update_cfg(aw_dev, dsp_cfg->data, dsp_cfg->len); + aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL); + } + + aw_dev_pwd(aw_dev, true); + + return 0; +} +EXPORT_SYMBOL_GPL(aw88399_stop); + +static int aw88399_dev_init(struct aw88399 *aw88399, struct aw_container *aw_cfg) +{ + struct aw_device *aw_dev = aw88399->aw_pa; + int ret; + + ret = aw88395_dev_cfg_load(aw_dev, aw_cfg); + if (ret) { + dev_err(aw_dev->dev, "aw_dev acf parse failed"); + return -EINVAL; + } + aw_dev->fade_in_time = AW88399_1000_US / 10; + aw_dev->fade_out_time = AW88399_1000_US >> 1; + aw_dev->prof_cur = aw_dev->prof_info.prof_desc[0].id; + aw_dev->prof_index = aw_dev->prof_info.prof_desc[0].id; + + ret = aw88399_dev_fw_update(aw88399, AW88399_FORCE_UPDATE_ON, AW88399_DSP_FW_UPDATE_ON); + if (ret) { + dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret); + return ret; + } + + aw88399_dev_mute(aw_dev, true); + + /* close tx feedback */ + aw_dev_i2s_tx_enable(aw_dev, false); + usleep_range(AW88399_1000_US, AW88399_1000_US + 100); + + /* enable amppd */ + aw_dev_amppd(aw_dev, true); + + /* close dsp */ + aw_dev_dsp_enable(aw_dev, false); + /* set power down */ + aw_dev_pwd(aw_dev, true); + + return 0; +} + +int aw88399_request_firmware_file(struct aw88399 *aw88399) +{ + const struct firmware *cont __free(firmware) = NULL; + int ret; + + aw88399->aw_pa->fw_status = AW88399_DEV_FW_FAILED; + + ret = request_firmware(&cont, AW88399_ACF_FILE, aw88399->aw_pa->dev); + if (ret) { + dev_err(aw88399->aw_pa->dev, "request [%s] failed!", AW88399_ACF_FILE); + return ret; + } + + dev_dbg(aw88399->aw_pa->dev, "loaded %s - size: %zu\n", + AW88399_ACF_FILE, cont ? cont->size : 0); + + aw88399->aw_cfg = devm_kzalloc(aw88399->aw_pa->dev, + struct_size(aw88399->aw_cfg, data, cont->size), GFP_KERNEL); + if (!aw88399->aw_cfg) + return -ENOMEM; + + aw88399->aw_cfg->len = (int)cont->size; + memcpy(aw88399->aw_cfg->data, cont->data, cont->size); + + ret = aw88395_dev_load_acf_check(aw88399->aw_pa, aw88399->aw_cfg); + if (ret) { + dev_err(aw88399->aw_pa->dev, "load [%s] failed!", AW88399_ACF_FILE); + return ret; + } + + mutex_lock(&aw88399->lock); + /* aw device init */ + ret = aw88399_dev_init(aw88399, aw88399->aw_cfg); + if (ret) + dev_err(aw88399->aw_pa->dev, "dev init failed"); + mutex_unlock(&aw88399->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(aw88399_request_firmware_file); + +void aw88399_hw_reset(struct aw88399 *aw88399) +{ + if (aw88399->reset_gpio) { + gpiod_set_value_cansleep(aw88399->reset_gpio, 1); + usleep_range(AW88399_1000_US, AW88399_1000_US + 10); + gpiod_set_value_cansleep(aw88399->reset_gpio, 0); + usleep_range(AW88399_1000_US, AW88399_1000_US + 10); + gpiod_set_value_cansleep(aw88399->reset_gpio, 1); + usleep_range(AW88399_1000_US, AW88399_1000_US + 10); + } +} +EXPORT_SYMBOL_GPL(aw88399_hw_reset); + +static void aw88399_parse_channel_dt(struct aw_device *aw_dev) +{ + struct device_node *np = aw_dev->dev->of_node; + u32 channel_value; + int ret; + + ret = of_property_read_u32(np, "awinic,audio-channel", &channel_value); + if (ret) { + /* + * On ACPI systems, DT properties don't exist. Derive channel + * from I2C address: 0x34 -> channel 0 (left), 0x35 -> channel 1 (right) + */ + aw_dev->channel = aw_dev->i2c->addr - 0x34; + dev_dbg(aw_dev->dev, + "DT channel property not found, using I2C address-based channel %d (addr 0x%02x)\n", + aw_dev->channel, aw_dev->i2c->addr); + return; + } + aw_dev->channel = channel_value; +} + +int aw88399_init(struct aw88399 *aw88399, struct i2c_client *i2c, struct regmap *regmap) +{ + struct aw_device *aw_dev; + unsigned int chip_id; + int ret; + + ret = regmap_read(regmap, AW88399_ID_REG, &chip_id); + if (ret) { + dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret); + return ret; + } + if (chip_id != AW88399_CHIP_ID) { + dev_err(&i2c->dev, "unsupported device"); + return -ENXIO; + } + dev_dbg(&i2c->dev, "chip id = %x\n", chip_id); + + aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL); + if (!aw_dev) + return -ENOMEM; + aw88399->aw_pa = aw_dev; + + aw_dev->i2c = i2c; + aw_dev->dev = &i2c->dev; + aw_dev->regmap = regmap; + mutex_init(&aw_dev->dsp_lock); + + aw_dev->chip_id = chip_id; + aw_dev->acf = NULL; + aw_dev->prof_info.prof_desc = NULL; + aw_dev->prof_info.count = 0; + aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID; + aw_dev->channel = AW88399_DEV_DEFAULT_CH; + aw_dev->fw_status = AW88399_DEV_FW_FAILED; + + aw_dev->fade_step = AW88399_VOLUME_STEP_DB; + aw_dev->volume_desc.ctl_volume = AW88399_VOL_DEFAULT_VALUE; + + aw88399_parse_channel_dt(aw_dev); + + return 0; +} +EXPORT_SYMBOL_GPL(aw88399_init); + +void aw88399_dev_set_channel(struct aw88399 *aw88399, int channel) +{ + aw88399->aw_pa->channel = channel; +} +EXPORT_SYMBOL_GPL(aw88399_dev_set_channel); + +MODULE_DESCRIPTION("AW88399 common device library"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/aw88399.c b/sound/soc/codecs/aw88399.c index b2ec3503f7e2..e9dab5e7bae3 100644 --- a/sound/soc/codecs/aw88399.c +++ b/sound/soc/codecs/aw88399.c @@ -7,1220 +7,16 @@ // Author: Weidong Wang <wangweidong.a@awinic.com> // +#include <linux/cleanup.h> #include <linux/crc32.h> #include <linux/gpio/consumer.h> #include <linux/i2c.h> -#include <linux/firmware.h> -#include <linux/minmax.h> #include <linux/regmap.h> #include <linux/sort.h> #include <sound/soc.h> #include "aw88399.h" #include "aw88395/aw88395_device.h" -static const struct regmap_config aw88399_remap_config = { - .val_bits = 16, - .reg_bits = 8, - .max_register = AW88399_REG_MAX, - .reg_format_endian = REGMAP_ENDIAN_LITTLE, - .val_format_endian = REGMAP_ENDIAN_BIG, -}; - -static void aw_dev_pwd(struct aw_device *aw_dev, bool pwd) -{ - int ret; - - if (pwd) - ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, - ~AW88399_PWDN_MASK, AW88399_PWDN_POWER_DOWN_VALUE); - else - ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, - ~AW88399_PWDN_MASK, AW88399_PWDN_WORKING_VALUE); - - if (ret) - dev_dbg(aw_dev->dev, "%s failed", __func__); -} - -static void aw_dev_get_int_status(struct aw_device *aw_dev, unsigned short *int_status) -{ - unsigned int reg_val; - int ret; - - ret = regmap_read(aw_dev->regmap, AW88399_SYSINT_REG, ®_val); - if (ret) - dev_err(aw_dev->dev, "read interrupt reg fail, ret=%d", ret); - else - *int_status = reg_val; - - dev_dbg(aw_dev->dev, "read interrupt reg=0x%04x", *int_status); -} - -static void aw_dev_clear_int_status(struct aw_device *aw_dev) -{ - u16 int_status; - - /* read int status and clear */ - aw_dev_get_int_status(aw_dev, &int_status); - /* make sure int status is clear */ - aw_dev_get_int_status(aw_dev, &int_status); - if (int_status) - dev_dbg(aw_dev->dev, "int status(%d) is not cleaned.\n", int_status); -} - -static int aw_dev_get_iis_status(struct aw_device *aw_dev) -{ - unsigned int reg_val; - int ret; - - ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, ®_val); - if (ret) - return ret; - if ((reg_val & AW88399_BIT_PLL_CHECK) != AW88399_BIT_PLL_CHECK) { - dev_err(aw_dev->dev, "check pll lock fail, reg_val:0x%04x", reg_val); - return -EINVAL; - } - - return 0; -} - -static int aw_dev_check_mode1_pll(struct aw_device *aw_dev) -{ - int ret, i; - - for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { - ret = aw_dev_get_iis_status(aw_dev); - if (ret) { - dev_err(aw_dev->dev, "mode1 iis signal check error"); - usleep_range(AW88399_2000_US, AW88399_2000_US + 10); - } else { - return 0; - } - } - - return -EPERM; -} - -static int aw_dev_check_mode2_pll(struct aw_device *aw_dev) -{ - unsigned int reg_val; - int ret, i; - - ret = regmap_read(aw_dev->regmap, AW88399_PLLCTRL2_REG, ®_val); - if (ret) - return ret; - - reg_val &= (~AW88399_CCO_MUX_MASK); - if (reg_val == AW88399_CCO_MUX_DIVIDED_VALUE) { - dev_dbg(aw_dev->dev, "CCO_MUX is already divider"); - return -EPERM; - } - - /* change mode2 */ - ret = regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG, - ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_DIVIDED_VALUE); - if (ret) - return ret; - - for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { - ret = aw_dev_get_iis_status(aw_dev); - if (ret) { - dev_err(aw_dev->dev, "mode2 iis signal check error"); - usleep_range(AW88399_2000_US, AW88399_2000_US + 10); - } else { - break; - } - } - - /* change mode1 */ - regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG, - ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_BYPASS_VALUE); - if (ret == 0) { - usleep_range(AW88399_2000_US, AW88399_2000_US + 10); - for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { - ret = aw_dev_get_iis_status(aw_dev); - if (ret) { - dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error"); - usleep_range(AW88399_2000_US, AW88399_2000_US + 10); - } else { - break; - } - } - } - - return ret; -} - -static int aw_dev_check_syspll(struct aw_device *aw_dev) -{ - int ret; - - ret = aw_dev_check_mode1_pll(aw_dev); - if (ret) { - dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check"); - ret = aw_dev_check_mode2_pll(aw_dev); - if (ret) { - dev_err(aw_dev->dev, "mode2 check iis failed"); - return ret; - } - } - - return 0; -} - -static int aw_dev_check_sysst(struct aw_device *aw_dev) -{ - unsigned int check_val; - unsigned int reg_val; - int ret, i; - - ret = regmap_read(aw_dev->regmap, AW88399_PWMCTRL3_REG, ®_val); - if (ret) - return ret; - - if (reg_val & (~AW88399_NOISE_GATE_EN_MASK)) - check_val = AW88399_BIT_SYSST_NOSWS_CHECK; - else - check_val = AW88399_BIT_SYSST_SWS_CHECK; - - for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { - ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, ®_val); - if (ret) - return ret; - - if ((reg_val & (~AW88399_BIT_SYSST_CHECK_MASK) & check_val) != check_val) { - dev_err(aw_dev->dev, "check sysst fail, cnt=%d, reg_val=0x%04x, check:0x%x", - i, reg_val, AW88399_BIT_SYSST_NOSWS_CHECK); - usleep_range(AW88399_2000_US, AW88399_2000_US + 10); - } else { - return 0; - } - } - - return -EPERM; -} - -static void aw_dev_amppd(struct aw_device *aw_dev, bool amppd) -{ - int ret; - - if (amppd) - ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, - ~AW88399_AMPPD_MASK, AW88399_AMPPD_POWER_DOWN_VALUE); - else - ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, - ~AW88399_AMPPD_MASK, AW88399_AMPPD_WORKING_VALUE); - - if (ret) - dev_dbg(aw_dev->dev, "%s failed", __func__); -} - -static void aw_dev_dsp_enable(struct aw_device *aw_dev, bool is_enable) -{ - int ret; - - if (is_enable) - ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, - ~AW88399_DSPBY_MASK, AW88399_DSPBY_WORKING_VALUE); - else - ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, - ~AW88399_DSPBY_MASK, AW88399_DSPBY_BYPASS_VALUE); - - if (ret) - dev_dbg(aw_dev->dev, "%s failed\n", __func__); -} - -static int aw88399_dev_get_icalk(struct aw88399 *aw88399, int16_t *icalk) -{ - uint16_t icalkh_val, icalkl_val, icalk_val; - struct aw_device *aw_dev = aw88399->aw_pa; - unsigned int reg_val; - int ret; - - ret = regmap_read(aw_dev->regmap, AW88399_EFRH4_REG, ®_val); - if (ret) - return ret; - icalkh_val = reg_val & (~AW88399_EF_ISN_GESLP_H_MASK); - - ret = regmap_read(aw_dev->regmap, AW88399_EFRL4_REG, ®_val); - if (ret) - return ret; - icalkl_val = reg_val & (~AW88399_EF_ISN_GESLP_L_MASK); - - if (aw88399->check_val == AW_EF_AND_CHECK) - icalk_val = icalkh_val & icalkl_val; - else - icalk_val = icalkh_val | icalkl_val; - - if (icalk_val & (~AW88399_EF_ISN_GESLP_SIGN_MASK)) - icalk_val = icalk_val | AW88399_EF_ISN_GESLP_SIGN_NEG; - *icalk = (int16_t)icalk_val; - - return 0; -} - -static int aw88399_dev_get_vcalk(struct aw88399 *aw88399, int16_t *vcalk) -{ - uint16_t vcalkh_val, vcalkl_val, vcalk_val; - struct aw_device *aw_dev = aw88399->aw_pa; - unsigned int reg_val; - int ret; - - ret = regmap_read(aw_dev->regmap, AW88399_EFRH3_REG, ®_val); - if (ret) - return ret; - - vcalkh_val = reg_val & (~AW88399_EF_VSN_GESLP_H_MASK); - - ret = regmap_read(aw_dev->regmap, AW88399_EFRL3_REG, ®_val); - if (ret) - return ret; - - vcalkl_val = reg_val & (~AW88399_EF_VSN_GESLP_L_MASK); - - if (aw88399->check_val == AW_EF_AND_CHECK) - vcalk_val = vcalkh_val & vcalkl_val; - else - vcalk_val = vcalkh_val | vcalkl_val; - - if (vcalk_val & AW88399_EF_VSN_GESLP_SIGN_MASK) - vcalk_val = vcalk_val | AW88399_EF_VSN_GESLP_SIGN_NEG; - *vcalk = (int16_t)vcalk_val; - - return 0; -} - -static int aw88399_dev_get_internal_vcalk(struct aw88399 *aw88399, int16_t *vcalk) -{ - uint16_t vcalkh_val, vcalkl_val, vcalk_val; - struct aw_device *aw_dev = aw88399->aw_pa; - unsigned int reg_val; - int ret; - - ret = regmap_read(aw_dev->regmap, AW88399_EFRH2_REG, ®_val); - if (ret) - return ret; - vcalkh_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_H_MASK); - - ret = regmap_read(aw_dev->regmap, AW88399_EFRL2_REG, ®_val); - if (ret) - return ret; - vcalkl_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_L_MASK); - - if (aw88399->check_val == AW_EF_AND_CHECK) - vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) & - (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT); - else - vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) | - (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT); - - if (vcalk_val & (~AW88399_TEM4_SIGN_MASK)) - vcalk_val = vcalk_val | AW88399_TEM4_SIGN_NEG; - - *vcalk = (int16_t)vcalk_val; - - return 0; -} - -static int aw_dev_set_vcalb(struct aw88399 *aw88399) -{ - struct aw_device *aw_dev = aw88399->aw_pa; - unsigned int vsense_select, vsense_value; - int32_t ical_k, vcal_k, vcalb; - int16_t icalk, vcalk; - uint16_t reg_val; - int ret; - - ret = regmap_read(aw_dev->regmap, AW88399_VSNCTRL1_REG, &vsense_value); - if (ret) - return ret; - - vsense_select = vsense_value & (~AW88399_VDSEL_MASK); - - ret = aw88399_dev_get_icalk(aw88399, &icalk); - if (ret) { - dev_err(aw_dev->dev, "get icalk failed\n"); - return ret; - } - - ical_k = icalk * AW88399_ICABLK_FACTOR + AW88399_CABL_BASE_VALUE; - - switch (vsense_select) { - case AW88399_DEV_VDSEL_VSENSE: - ret = aw88399_dev_get_vcalk(aw88399, &vcalk); - vcal_k = vcalk * AW88399_VCABLK_FACTOR + AW88399_CABL_BASE_VALUE; - vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_FACTOR / AW88399_ISCAL_FACTOR * - ical_k / vcal_k * aw88399->vcalb_init_val; - break; - case AW88399_DEV_VDSEL_DAC: - ret = aw88399_dev_get_internal_vcalk(aw88399, &vcalk); - vcal_k = vcalk * AW88399_VCABLK_DAC_FACTOR + AW88399_CABL_BASE_VALUE; - vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_DAC_FACTOR / - AW88399_ISCAL_DAC_FACTOR * ical_k / - vcal_k * aw88399->vcalb_init_val; - break; - default: - dev_err(aw_dev->dev, "%s: unsupported vsense\n", __func__); - ret = -EINVAL; - break; - } - if (ret) - return ret; - - vcalb = vcalb >> AW88399_VCALB_ADJ_FACTOR; - reg_val = (uint32_t)vcalb; - - regmap_write(aw_dev->regmap, AW88399_DSPVCALB_REG, reg_val); - - return 0; -} - -static int aw_dev_update_cali_re(struct aw_cali_desc *cali_desc) -{ - struct aw_device *aw_dev = - container_of(cali_desc, struct aw_device, cali_desc); - uint16_t re_lbits, re_hbits; - u32 cali_re; - int ret; - - if ((aw_dev->cali_desc.cali_re >= AW88399_CALI_RE_MAX) || - (aw_dev->cali_desc.cali_re <= AW88399_CALI_RE_MIN)) - return -EINVAL; - - cali_re = AW88399_SHOW_RE_TO_DSP_RE((aw_dev->cali_desc.cali_re + - aw_dev->cali_desc.ra), AW88399_DSP_RE_SHIFT); - - re_hbits = (cali_re & (~AW88399_CALI_RE_HBITS_MASK)) >> AW88399_CALI_RE_HBITS_SHIFT; - re_lbits = (cali_re & (~AW88399_CALI_RE_LBITS_MASK)) >> AW88399_CALI_RE_LBITS_SHIFT; - - ret = regmap_write(aw_dev->regmap, AW88399_ACR1_REG, re_hbits); - if (ret) { - dev_err(aw_dev->dev, "set cali re error"); - return ret; - } - - ret = regmap_write(aw_dev->regmap, AW88399_ACR2_REG, re_lbits); - if (ret) - dev_err(aw_dev->dev, "set cali re error"); - - return ret; -} - -static int aw_dev_fw_crc_check(struct aw_device *aw_dev) -{ - uint16_t check_val, fw_len_val; - unsigned int reg_val; - int ret; - - /* calculate fw_end_addr */ - fw_len_val = ((aw_dev->dsp_fw_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_FW_BASE_ADDR; - - /* write fw_end_addr to crc_end_addr */ - ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, - ~AW88399_CRC_END_ADDR_MASK, fw_len_val); - if (ret) - return ret; - /* enable fw crc check */ - ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, - ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_ENABLE_VALUE); - - usleep_range(AW88399_2000_US, AW88399_2000_US + 10); - - /* read crc check result */ - regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, ®_val); - if (ret) - return ret; - - check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT; - - /* disable fw crc check */ - ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, - ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_DISABLE_VALUE); - if (ret) - return ret; - - if (check_val != AW88399_CRC_CHECK_PASS_VAL) { - dev_err(aw_dev->dev, "%s failed, check_val 0x%x != 0x%x", - __func__, check_val, AW88399_CRC_CHECK_PASS_VAL); - ret = -EINVAL; - } - - return ret; -} - -static int aw_dev_cfg_crc_check(struct aw_device *aw_dev) -{ - uint16_t check_val, cfg_len_val; - unsigned int reg_val; - int ret; - - /* calculate cfg end addr */ - cfg_len_val = ((aw_dev->dsp_cfg_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_CFG_BASE_ADDR; - - /* write cfg_end_addr to crc_end_addr */ - ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, - ~AW88399_CRC_END_ADDR_MASK, cfg_len_val); - if (ret) - return ret; - - /* enable cfg crc check */ - ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, - ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_ENABLE_VALUE); - if (ret) - return ret; - - usleep_range(AW88399_1000_US, AW88399_1000_US + 10); - - /* read crc check result */ - ret = regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, ®_val); - if (ret) - return ret; - - check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT; - - /* disable cfg crc check */ - ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, - ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_DISABLE_VALUE); - if (ret) - return ret; - - if (check_val != AW88399_CRC_CHECK_PASS_VAL) { - dev_err(aw_dev->dev, "crc_check failed, check val 0x%x != 0x%x", - check_val, AW88399_CRC_CHECK_PASS_VAL); - ret = -EINVAL; - } - - return ret; -} - -static int aw_dev_hw_crc_check(struct aw88399 *aw88399) -{ - struct aw_device *aw_dev = aw88399->aw_pa; - int ret; - - ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, - ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_BYPASS_VALUE); - if (ret) - return ret; - - ret = aw_dev_fw_crc_check(aw_dev); - if (ret) { - dev_err(aw_dev->dev, "fw_crc_check failed\n"); - goto crc_check_failed; - } - - ret = aw_dev_cfg_crc_check(aw_dev); - if (ret) { - dev_err(aw_dev->dev, "cfg_crc_check failed\n"); - goto crc_check_failed; - } - - ret = regmap_write(aw_dev->regmap, AW88399_CRCCTRL_REG, aw88399->crc_init_val); - if (ret) - return ret; - - ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, - ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE); - - return ret; - -crc_check_failed: - regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, - ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE); - return ret; -} - -static void aw_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag) -{ - int ret; - - if (flag) - ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCTRL3_REG, - ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_ENABLE_VALUE); - else - ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, - ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_DISABLE_VALUE); - - if (ret) - dev_dbg(aw_dev->dev, "%s failed", __func__); -} - -static int aw_dev_get_dsp_status(struct aw_device *aw_dev) -{ - unsigned int reg_val; - int ret; - - ret = regmap_read(aw_dev->regmap, AW88399_WDT_REG, ®_val); - if (ret) - return ret; - if (!(reg_val & (~AW88399_WDT_CNT_MASK))) - return -EPERM; - - return 0; -} - -static int aw_dev_dsp_check(struct aw_device *aw_dev) -{ - int ret, i; - - switch (aw_dev->dsp_cfg) { - case AW88399_DEV_DSP_BYPASS: - dev_dbg(aw_dev->dev, "dsp bypass"); - ret = 0; - break; - case AW88399_DEV_DSP_WORK: - aw_dev_dsp_enable(aw_dev, false); - aw_dev_dsp_enable(aw_dev, true); - usleep_range(AW88399_1000_US, AW88399_1000_US + 10); - for (i = 0; i < AW88399_DEV_DSP_CHECK_MAX; i++) { - ret = aw_dev_get_dsp_status(aw_dev); - if (ret) { - dev_err(aw_dev->dev, "dsp wdt status error=%d", ret); - usleep_range(AW88399_2000_US, AW88399_2000_US + 10); - } - } - break; - default: - dev_err(aw_dev->dev, "unknown dsp cfg=%d", aw_dev->dsp_cfg); - ret = -EINVAL; - break; - } - - return ret; -} - -static int aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value) -{ - struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; - unsigned int reg_value; - u16 real_value; - int ret; - - real_value = min((value + vol_desc->init_volume), (unsigned int)AW88399_MUTE_VOL); - - ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL2_REG, ®_value); - if (ret) - return ret; - - dev_dbg(aw_dev->dev, "value 0x%x , reg:0x%x", value, real_value); - - real_value = (real_value << AW88399_VOL_START_BIT) | (reg_value & AW88399_VOL_MASK); - - ret = regmap_write(aw_dev->regmap, AW88399_SYSCTRL2_REG, real_value); - - return ret; -} - -static void aw_dev_fade_in(struct aw_device *aw_dev) -{ - struct aw_volume_desc *desc = &aw_dev->volume_desc; - u16 fade_in_vol = desc->ctl_volume; - int fade_step = aw_dev->fade_step; - int i; - - if (fade_step == 0 || aw_dev->fade_in_time == 0) { - aw_dev_set_volume(aw_dev, fade_in_vol); - return; - } - - for (i = AW88399_MUTE_VOL; i >= fade_in_vol; i -= fade_step) { - aw_dev_set_volume(aw_dev, i); - usleep_range(aw_dev->fade_in_time, aw_dev->fade_in_time + 10); - } - - if (i != fade_in_vol) - aw_dev_set_volume(aw_dev, fade_in_vol); -} - -static void aw_dev_fade_out(struct aw_device *aw_dev) -{ - struct aw_volume_desc *desc = &aw_dev->volume_desc; - int fade_step = aw_dev->fade_step; - int i; - - if (fade_step == 0 || aw_dev->fade_out_time == 0) { - aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL); - return; - } - - for (i = desc->ctl_volume; i <= AW88399_MUTE_VOL; i += fade_step) { - aw_dev_set_volume(aw_dev, i); - usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); - } - - if (i != AW88399_MUTE_VOL) { - aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL); - usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); - } -} - -static void aw88399_dev_mute(struct aw_device *aw_dev, bool is_mute) -{ - if (is_mute) { - aw_dev_fade_out(aw_dev); - regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, - ~AW88399_HMUTE_MASK, AW88399_HMUTE_ENABLE_VALUE); - } else { - regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, - ~AW88399_HMUTE_MASK, AW88399_HMUTE_DISABLE_VALUE); - aw_dev_fade_in(aw_dev); - } -} - -static void aw88399_dev_set_dither(struct aw88399 *aw88399, bool dither) -{ - struct aw_device *aw_dev = aw88399->aw_pa; - - if (dither) - regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, - ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_ENABLE_VALUE); - else - regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, - ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_DISABLE_VALUE); -} - -static int aw88399_dev_start(struct aw88399 *aw88399) -{ - struct aw_device *aw_dev = aw88399->aw_pa; - int ret; - - if (aw_dev->status == AW88399_DEV_PW_ON) { - dev_dbg(aw_dev->dev, "already power on"); - return 0; - } - - aw88399_dev_set_dither(aw88399, false); - - /* power on */ - aw_dev_pwd(aw_dev, false); - usleep_range(AW88399_2000_US, AW88399_2000_US + 10); - - ret = aw_dev_check_syspll(aw_dev); - if (ret) { - dev_err(aw_dev->dev, "pll check failed cannot start"); - goto pll_check_fail; - } - - /* amppd on */ - aw_dev_amppd(aw_dev, false); - usleep_range(AW88399_1000_US, AW88399_1000_US + 50); - - /* check i2s status */ - ret = aw_dev_check_sysst(aw_dev); - if (ret) { - dev_err(aw_dev->dev, "sysst check failed"); - goto sysst_check_fail; - } - - if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK) { - ret = aw_dev_hw_crc_check(aw88399); - if (ret) { - dev_err(aw_dev->dev, "dsp crc check failed"); - goto crc_check_fail; - } - aw_dev_dsp_enable(aw_dev, false); - aw_dev_set_vcalb(aw88399); - aw_dev_update_cali_re(&aw_dev->cali_desc); - - ret = aw_dev_dsp_check(aw_dev); - if (ret) { - dev_err(aw_dev->dev, "dsp status check failed"); - goto dsp_check_fail; - } - } else { - dev_dbg(aw_dev->dev, "start pa with dsp bypass"); - } - - /* enable tx feedback */ - aw_dev_i2s_tx_enable(aw_dev, true); - - if (aw88399->dither_st == AW88399_DITHER_EN_ENABLE_VALUE) - aw88399_dev_set_dither(aw88399, true); - - /* close mute */ - aw88399_dev_mute(aw_dev, false); - /* clear inturrupt */ - aw_dev_clear_int_status(aw_dev); - aw_dev->status = AW88399_DEV_PW_ON; - - return 0; - -dsp_check_fail: -crc_check_fail: - aw_dev_dsp_enable(aw_dev, false); -sysst_check_fail: - aw_dev_clear_int_status(aw_dev); - aw_dev_amppd(aw_dev, true); -pll_check_fail: - aw_dev_pwd(aw_dev, true); - aw_dev->status = AW88399_DEV_PW_OFF; - - return ret; -} - -static int aw_dev_dsp_update_container(struct aw_device *aw_dev, - unsigned char *data, unsigned int len, unsigned short base) -{ - u32 tmp_len; - int i, ret; - - ret = regmap_write(aw_dev->regmap, AW88399_DSPMADD_REG, base); - if (ret) - return ret; - - for (i = 0; i < len; i += AW88399_MAX_RAM_WRITE_BYTE_SIZE) { - tmp_len = min(len - i, AW88399_MAX_RAM_WRITE_BYTE_SIZE); - ret = regmap_raw_write(aw_dev->regmap, AW88399_DSPMDAT_REG, - &data[i], tmp_len); - if (ret) - return ret; - } - - return 0; -} - -static int aw_dev_get_ra(struct aw_cali_desc *cali_desc) -{ - struct aw_device *aw_dev = - container_of(cali_desc, struct aw_device, cali_desc); - u32 dsp_ra; - int ret; - - ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CFG_ADPZ_RA, - &dsp_ra, AW_DSP_32_DATA); - if (ret) { - dev_err(aw_dev->dev, "read ra error"); - return ret; - } - - cali_desc->ra = AW88399_DSP_RE_TO_SHOW_RE(dsp_ra, - AW88399_DSP_RE_SHIFT); - - return 0; -} - -static int aw_dev_dsp_update_cfg(struct aw_device *aw_dev, - unsigned char *data, unsigned int len) -{ - int ret; - - dev_dbg(aw_dev->dev, "dsp config len:%d", len); - - if (!len || !data) { - dev_err(aw_dev->dev, "dsp config data is null or len is 0"); - return -EINVAL; - } - - ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_CFG_ADDR); - if (ret) - return ret; - - aw_dev->dsp_cfg_len = len; - - ret = aw_dev_get_ra(&aw_dev->cali_desc); - - return ret; -} - -static int aw_dev_dsp_update_fw(struct aw_device *aw_dev, - unsigned char *data, unsigned int len) -{ - int ret; - - dev_dbg(aw_dev->dev, "dsp firmware len:%d", len); - - if (!len || !data) { - dev_err(aw_dev->dev, "dsp firmware data is null or len is 0"); - return -EINVAL; - } - - aw_dev->dsp_fw_len = len; - ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_FW_ADDR); - - return ret; -} - -static int aw_dev_check_sram(struct aw_device *aw_dev) -{ - unsigned int reg_val; - - /* read dsp_rom_check_reg */ - aw_dev_dsp_read(aw_dev, AW88399_DSP_ROM_CHECK_ADDR, ®_val, AW_DSP_16_DATA); - if (reg_val != AW88399_DSP_ROM_CHECK_DATA) { - dev_err(aw_dev->dev, "check dsp rom failed, read[0x%x] != check[0x%x]", - reg_val, AW88399_DSP_ROM_CHECK_DATA); - return -EPERM; - } - - /* check dsp_cfg_base_addr */ - aw_dev_dsp_write(aw_dev, AW88399_DSP_CFG_ADDR, - AW88399_DSP_ODD_NUM_BIT_TEST, AW_DSP_16_DATA); - aw_dev_dsp_read(aw_dev, AW88399_DSP_CFG_ADDR, ®_val, AW_DSP_16_DATA); - if (reg_val != AW88399_DSP_ODD_NUM_BIT_TEST) { - dev_err(aw_dev->dev, "check dsp cfg failed, read[0x%x] != write[0x%x]", - reg_val, AW88399_DSP_ODD_NUM_BIT_TEST); - return -EPERM; - } - - return 0; -} - -static void aw_dev_select_memclk(struct aw_device *aw_dev, unsigned char flag) -{ - int ret; - - switch (flag) { - case AW88399_DEV_MEMCLK_PLL: - ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, - ~AW88399_MEM_CLKSEL_MASK, - AW88399_MEM_CLKSEL_DAPHCLK_VALUE); - if (ret) - dev_err(aw_dev->dev, "memclk select pll failed"); - break; - case AW88399_DEV_MEMCLK_OSC: - ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, - ~AW88399_MEM_CLKSEL_MASK, - AW88399_MEM_CLKSEL_OSCCLK_VALUE); - if (ret) - dev_err(aw_dev->dev, "memclk select OSC failed"); - break; - default: - dev_err(aw_dev->dev, "unknown memclk config, flag=0x%x", flag); - break; - } -} - -static void aw_dev_get_cur_mode_st(struct aw_device *aw_dev) -{ - struct aw_profctrl_desc *profctrl_desc = &aw_dev->profctrl_desc; - unsigned int reg_val; - int ret; - - ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL_REG, ®_val); - if (ret) { - dev_dbg(aw_dev->dev, "%s failed", __func__); - return; - } - if ((reg_val & (~AW88399_RCV_MODE_MASK)) == AW88399_RCV_MODE_RECEIVER_VALUE) - profctrl_desc->cur_mode = AW88399_RCV_MODE; - else - profctrl_desc->cur_mode = AW88399_NOT_RCV_MODE; -} - -static int aw_dev_update_reg_container(struct aw88399 *aw88399, - unsigned char *data, unsigned int len) -{ - struct aw_device *aw_dev = aw88399->aw_pa; - struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; - u16 read_vol, reg_val; - int data_len, i, ret; - int16_t *reg_data; - u8 reg_addr; - - reg_data = (int16_t *)data; - data_len = len >> 1; - - if (data_len & 0x1) { - dev_err(aw_dev->dev, "data len:%d unsupported", data_len); - return -EINVAL; - } - - for (i = 0; i < data_len; i += 2) { - reg_addr = reg_data[i]; - reg_val = reg_data[i + 1]; - - if (reg_addr == AW88399_DSPVCALB_REG) { - aw88399->vcalb_init_val = reg_val; - continue; - } - - if (reg_addr == AW88399_SYSCTRL_REG) { - if (reg_val & (~AW88399_DSPBY_MASK)) - aw_dev->dsp_cfg = AW88399_DEV_DSP_BYPASS; - else - aw_dev->dsp_cfg = AW88399_DEV_DSP_WORK; - - reg_val &= (AW88399_HMUTE_MASK | AW88399_PWDN_MASK | - AW88399_DSPBY_MASK); - reg_val |= (AW88399_HMUTE_ENABLE_VALUE | AW88399_PWDN_POWER_DOWN_VALUE | - AW88399_DSPBY_BYPASS_VALUE); - } - - if (reg_addr == AW88399_I2SCTRL3_REG) { - reg_val &= AW88399_I2STXEN_MASK; - reg_val |= AW88399_I2STXEN_DISABLE_VALUE; - } - - if (reg_addr == AW88399_SYSCTRL2_REG) { - read_vol = (reg_val & (~AW88399_VOL_MASK)) >> - AW88399_VOL_START_BIT; - aw_dev->volume_desc.init_volume = read_vol; - } - - if (reg_addr == AW88399_DBGCTRL_REG) { - if ((reg_val & (~AW88399_EF_DBMD_MASK)) == AW88399_EF_DBMD_OR_VALUE) - aw88399->check_val = AW_EF_OR_CHECK; - else - aw88399->check_val = AW_EF_AND_CHECK; - - aw88399->dither_st = reg_val & (~AW88399_DITHER_EN_MASK); - } - - if (reg_addr == AW88399_CRCCTRL_REG) - aw88399->crc_init_val = reg_val; - - ret = regmap_write(aw_dev->regmap, reg_addr, reg_val); - if (ret) - return ret; - } - - aw_dev_pwd(aw_dev, false); - usleep_range(AW88399_1000_US, AW88399_1000_US + 10); - - aw_dev_get_cur_mode_st(aw_dev); - - if (aw_dev->prof_cur != aw_dev->prof_index) - vol_desc->ctl_volume = 0; - else - aw_dev_set_volume(aw_dev, vol_desc->ctl_volume); - - return 0; -} - -static int aw_dev_reg_update(struct aw88399 *aw88399, - unsigned char *data, unsigned int len) -{ - int ret; - - if (!len || !data) { - dev_err(aw88399->aw_pa->dev, "reg data is null or len is 0"); - return -EINVAL; - } - - ret = aw_dev_update_reg_container(aw88399, data, len); - if (ret) - dev_err(aw88399->aw_pa->dev, "reg update failed"); - - return ret; -} - -static int aw88399_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name) -{ - struct aw_prof_info *prof_info = &aw_dev->prof_info; - struct aw_prof_desc *prof_desc; - - if ((index >= aw_dev->prof_info.count) || (index < 0)) { - dev_err(aw_dev->dev, "index[%d] overflow count[%d]", - index, aw_dev->prof_info.count); - return -EINVAL; - } - - prof_desc = &aw_dev->prof_info.prof_desc[index]; - - *prof_name = prof_info->prof_name_list[prof_desc->id]; - - return 0; -} - -static int aw88399_dev_get_prof_data(struct aw_device *aw_dev, int index, - struct aw_prof_desc **prof_desc) -{ - if ((index >= aw_dev->prof_info.count) || (index < 0)) { - dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n", - __func__, index, aw_dev->prof_info.count); - return -EINVAL; - } - - *prof_desc = &aw_dev->prof_info.prof_desc[index]; - - return 0; -} - -static int aw88399_dev_fw_update(struct aw88399 *aw88399, bool up_dsp_fw_en, bool force_up_en) -{ - struct aw_device *aw_dev = aw88399->aw_pa; - struct aw_prof_desc *prof_index_desc; - struct aw_sec_data_desc *sec_desc; - char *prof_name; - int ret; - - if ((aw_dev->prof_cur == aw_dev->prof_index) && - (force_up_en == AW88399_FORCE_UPDATE_OFF)) { - dev_dbg(aw_dev->dev, "scene no change, not update"); - return 0; - } - - if (aw_dev->fw_status == AW88399_DEV_FW_FAILED) { - dev_err(aw_dev->dev, "fw status[%d] error", aw_dev->fw_status); - return -EPERM; - } - - ret = aw88399_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name); - if (ret) - return ret; - - dev_dbg(aw_dev->dev, "start update %s", prof_name); - - ret = aw88399_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc); - if (ret) - return ret; - - /* update reg */ - sec_desc = prof_index_desc->sec_desc; - ret = aw_dev_reg_update(aw88399, sec_desc[AW88395_DATA_TYPE_REG].data, - sec_desc[AW88395_DATA_TYPE_REG].len); - if (ret) { - dev_err(aw_dev->dev, "update reg failed"); - return ret; - } - - aw88399_dev_mute(aw_dev, true); - - if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK) - aw_dev_dsp_enable(aw_dev, false); - - aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC); - - ret = aw_dev_check_sram(aw_dev); - if (ret) { - dev_err(aw_dev->dev, "check sram failed"); - goto error; - } - - if (up_dsp_fw_en) { - dev_dbg(aw_dev->dev, "fw_ver: [%x]", prof_index_desc->fw_ver); - ret = aw_dev_dsp_update_fw(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_FW].data, - sec_desc[AW88395_DATA_TYPE_DSP_FW].len); - if (ret) { - dev_err(aw_dev->dev, "update dsp fw failed"); - goto error; - } - } - - /* update dsp config */ - ret = aw_dev_dsp_update_cfg(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_CFG].data, - sec_desc[AW88395_DATA_TYPE_DSP_CFG].len); - if (ret) { - dev_err(aw_dev->dev, "update dsp cfg failed"); - goto error; - } - - aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL); - - aw_dev->prof_cur = aw_dev->prof_index; - - return 0; - -error: - aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL); - return ret; -} - -static void aw88399_start_pa(struct aw88399 *aw88399) -{ - int ret, i; - - for (i = 0; i < AW88399_START_RETRIES; i++) { - ret = aw88399_dev_start(aw88399); - if (ret) { - dev_err(aw88399->aw_pa->dev, "aw88399 device start failed. retry = %d", i); - ret = aw88399_dev_fw_update(aw88399, AW88399_DSP_FW_UPDATE_ON, true); - if (ret) { - dev_err(aw88399->aw_pa->dev, "fw update failed"); - continue; - } - } else { - dev_dbg(aw88399->aw_pa->dev, "start success\n"); - break; - } - } -} - -static void aw88399_startup_work(struct work_struct *work) -{ - struct aw88399 *aw88399 = - container_of(work, struct aw88399, start_work.work); - - mutex_lock(&aw88399->lock); - aw88399_start_pa(aw88399); - mutex_unlock(&aw88399->lock); -} - -static void aw88399_start(struct aw88399 *aw88399, bool sync_start) -{ - int ret; - - if (aw88399->aw_pa->fw_status != AW88399_DEV_FW_OK) - return; - - if (aw88399->aw_pa->status == AW88399_DEV_PW_ON) - return; - - ret = aw88399_dev_fw_update(aw88399, AW88399_DSP_FW_UPDATE_OFF, true); - if (ret) { - dev_err(aw88399->aw_pa->dev, "fw update failed."); - return; - } - - if (sync_start == AW88399_SYNC_START) - aw88399_start_pa(aw88399); - else - queue_delayed_work(system_dfl_wq, - &aw88399->start_work, - AW88399_START_WORK_DELAY_MS); -} - -static int aw_dev_check_sysint(struct aw_device *aw_dev) -{ - u16 reg_val; - - aw_dev_get_int_status(aw_dev, ®_val); - if (reg_val & AW88399_BIT_SYSINT_CHECK) { - dev_err(aw_dev->dev, "pa stop check fail:0x%04x", reg_val); - return -EINVAL; - } - - return 0; -} - -static int aw88399_stop(struct aw_device *aw_dev) -{ - struct aw_sec_data_desc *dsp_cfg = - &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_CFG]; - struct aw_sec_data_desc *dsp_fw = - &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_FW]; - int int_st; - - if (aw_dev->status == AW88399_DEV_PW_OFF) { - dev_dbg(aw_dev->dev, "already power off"); - return 0; - } - - aw_dev->status = AW88399_DEV_PW_OFF; - - aw88399_dev_mute(aw_dev, true); - usleep_range(AW88399_4000_US, AW88399_4000_US + 100); - - aw_dev_i2s_tx_enable(aw_dev, false); - usleep_range(AW88399_1000_US, AW88399_1000_US + 100); - - int_st = aw_dev_check_sysint(aw_dev); - - aw_dev_dsp_enable(aw_dev, false); - - aw_dev_amppd(aw_dev, true); - - if (int_st) { - aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC); - aw_dev_dsp_update_fw(aw_dev, dsp_fw->data, dsp_fw->len); - aw_dev_dsp_update_cfg(aw_dev, dsp_cfg->data, dsp_cfg->len); - aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL); - } - - aw_dev_pwd(aw_dev, true); - - return 0; -} - static struct snd_soc_dai_driver aw88399_dai[] = { { .name = "aw88399-aif", @@ -1702,11 +498,10 @@ static int aw88399_profile_set(struct snd_kcontrol *kcontrol, struct aw88399 *aw88399 = snd_soc_component_get_drvdata(codec); int ret; - mutex_lock(&aw88399->lock); + guard(mutex)(&aw88399->lock); ret = aw88399_dev_set_profile_index(aw88399->aw_pa, ucontrol->value.integer.value[0]); if (ret) { dev_dbg(codec->dev, "profile index does not change"); - mutex_unlock(&aw88399->lock); return 0; } @@ -1715,8 +510,6 @@ static int aw88399_profile_set(struct snd_kcontrol *kcontrol, aw88399_start(aw88399, AW88399_SYNC_START); } - mutex_unlock(&aw88399->lock); - return 1; } @@ -1869,86 +662,6 @@ static int aw88399_calib_set(struct snd_kcontrol *kcontrol, return 0; } -static int aw88399_dev_init(struct aw88399 *aw88399, struct aw_container *aw_cfg) -{ - struct aw_device *aw_dev = aw88399->aw_pa; - int ret; - - ret = aw88395_dev_cfg_load(aw_dev, aw_cfg); - if (ret) { - dev_err(aw_dev->dev, "aw_dev acf parse failed"); - return -EINVAL; - } - aw_dev->fade_in_time = AW88399_1000_US / 10; - aw_dev->fade_out_time = AW88399_1000_US >> 1; - aw_dev->prof_cur = aw_dev->prof_info.prof_desc[0].id; - aw_dev->prof_index = aw_dev->prof_info.prof_desc[0].id; - - ret = aw88399_dev_fw_update(aw88399, AW88399_FORCE_UPDATE_ON, AW88399_DSP_FW_UPDATE_ON); - if (ret) { - dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret); - return ret; - } - - aw88399_dev_mute(aw_dev, true); - - /* close tx feedback */ - aw_dev_i2s_tx_enable(aw_dev, false); - usleep_range(AW88399_1000_US, AW88399_1000_US + 100); - - /* enable amppd */ - aw_dev_amppd(aw_dev, true); - - /* close dsp */ - aw_dev_dsp_enable(aw_dev, false); - /* set power down */ - aw_dev_pwd(aw_dev, true); - - return 0; -} - -static int aw88399_request_firmware_file(struct aw88399 *aw88399) -{ - const struct firmware *cont = NULL; - int ret; - - aw88399->aw_pa->fw_status = AW88399_DEV_FW_FAILED; - - ret = request_firmware(&cont, AW88399_ACF_FILE, aw88399->aw_pa->dev); - if (ret) { - dev_err(aw88399->aw_pa->dev, "request [%s] failed!", AW88399_ACF_FILE); - return ret; - } - - dev_dbg(aw88399->aw_pa->dev, "loaded %s - size: %zu\n", - AW88399_ACF_FILE, cont ? cont->size : 0); - - aw88399->aw_cfg = devm_kzalloc(aw88399->aw_pa->dev, - struct_size(aw88399->aw_cfg, data, cont->size), GFP_KERNEL); - if (!aw88399->aw_cfg) { - release_firmware(cont); - return -ENOMEM; - } - aw88399->aw_cfg->len = (int)cont->size; - memcpy(aw88399->aw_cfg->data, cont->data, cont->size); - release_firmware(cont); - - ret = aw88395_dev_load_acf_check(aw88399->aw_pa, aw88399->aw_cfg); - if (ret) { - dev_err(aw88399->aw_pa->dev, "load [%s] failed!", AW88399_ACF_FILE); - return ret; - } - - mutex_lock(&aw88399->lock); - /* aw device init */ - ret = aw88399_dev_init(aw88399, aw88399->aw_cfg); - if (ret) - dev_err(aw88399->aw_pa->dev, "dev init failed"); - mutex_unlock(&aw88399->lock); - - return ret; -} - static const struct snd_kcontrol_new aw88399_controls[] = { SOC_SINGLE_EXT("PCM Playback Volume", AW88399_SYSCTRL2_REG, 6, AW88399_MUTE_VOL, 0, aw88399_volume_get, @@ -1975,7 +688,7 @@ static int aw88399_playback_event(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct aw88399 *aw88399 = snd_soc_component_get_drvdata(component); - mutex_lock(&aw88399->lock); + guard(mutex)(&aw88399->lock); switch (event) { case SND_SOC_DAPM_PRE_PMU: aw88399_start(aw88399, AW88399_ASYNC_START); @@ -1986,7 +699,6 @@ static int aw88399_playback_event(struct snd_soc_dapm_widget *w, default: break; } - mutex_unlock(&aw88399->lock); return 0; } @@ -2040,70 +752,6 @@ static const struct snd_soc_component_driver soc_codec_dev_aw88399 = { .num_controls = ARRAY_SIZE(aw88399_controls), }; -static void aw88399_hw_reset(struct aw88399 *aw88399) -{ - if (aw88399->reset_gpio) { - gpiod_set_value_cansleep(aw88399->reset_gpio, 1); - usleep_range(AW88399_1000_US, AW88399_1000_US + 10); - gpiod_set_value_cansleep(aw88399->reset_gpio, 0); - usleep_range(AW88399_1000_US, AW88399_1000_US + 10); - gpiod_set_value_cansleep(aw88399->reset_gpio, 1); - usleep_range(AW88399_1000_US, AW88399_1000_US + 10); - } -} - -static void aw88399_parse_channel_dt(struct aw_device *aw_dev) -{ - struct device_node *np = aw_dev->dev->of_node; - u32 channel_value; - - of_property_read_u32(np, "awinic,audio-channel", &channel_value); - aw_dev->channel = channel_value; -} - -static int aw88399_init(struct aw88399 *aw88399, struct i2c_client *i2c, struct regmap *regmap) -{ - struct aw_device *aw_dev; - unsigned int chip_id; - int ret; - - ret = regmap_read(regmap, AW88399_ID_REG, &chip_id); - if (ret) { - dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret); - return ret; - } - if (chip_id != AW88399_CHIP_ID) { - dev_err(&i2c->dev, "unsupported device"); - return -ENXIO; - } - dev_dbg(&i2c->dev, "chip id = %x\n", chip_id); - - aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL); - if (!aw_dev) - return -ENOMEM; - aw88399->aw_pa = aw_dev; - - aw_dev->i2c = i2c; - aw_dev->dev = &i2c->dev; - aw_dev->regmap = regmap; - mutex_init(&aw_dev->dsp_lock); - - aw_dev->chip_id = chip_id; - aw_dev->acf = NULL; - aw_dev->prof_info.prof_desc = NULL; - aw_dev->prof_info.count = 0; - aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID; - aw_dev->channel = AW88399_DEV_DEFAULT_CH; - aw_dev->fw_status = AW88399_DEV_FW_FAILED; - - aw_dev->fade_step = AW88399_VOLUME_STEP_DB; - aw_dev->volume_desc.ctl_volume = AW88399_VOL_DEFAULT_VALUE; - - aw88399_parse_channel_dt(aw_dev); - - return 0; -} - static int aw88399_i2c_probe(struct i2c_client *i2c) { struct aw88399 *aw88399; diff --git a/sound/soc/codecs/aw88399.h b/sound/soc/codecs/aw88399.h index b386f4836748..04123bf0ad84 100644 --- a/sound/soc/codecs/aw88399.h +++ b/sound/soc/codecs/aw88399.h @@ -10,512 +10,10 @@ #ifndef __AW88399_H__ #define __AW88399_H__ -/* registers list */ -#define AW88399_ID_REG (0x00) -#define AW88399_SYSST_REG (0x01) -#define AW88399_SYSINT_REG (0x02) -#define AW88399_SYSINTM_REG (0x03) -#define AW88399_SYSCTRL_REG (0x04) -#define AW88399_SYSCTRL2_REG (0x05) -#define AW88399_I2SCTRL1_REG (0x06) -#define AW88399_I2SCTRL2_REG (0x07) -#define AW88399_I2SCTRL3_REG (0x08) -#define AW88399_DACCFG1_REG (0x09) -#define AW88399_DACCFG2_REG (0x0A) -#define AW88399_DACCFG3_REG (0x0B) -#define AW88399_DACCFG4_REG (0x0C) -#define AW88399_DACCFG5_REG (0x0D) -#define AW88399_DACCFG6_REG (0x0E) -#define AW88399_DACCFG7_REG (0x0F) -#define AW88399_MPDCFG1_REG (0x10) -#define AW88399_MPDCFG2_REG (0x11) -#define AW88399_MPDCFG3_REG (0x12) -#define AW88399_MPDCFG4_REG (0x13) -#define AW88399_PWMCTRL1_REG (0x14) -#define AW88399_PWMCTRL2_REG (0x15) -#define AW88399_PWMCTRL3_REG (0x16) -#define AW88399_I2SCFG1_REG (0x17) -#define AW88399_DBGCTRL_REG (0x18) -#define AW88399_HAGCST_REG (0x20) -#define AW88399_VBAT_REG (0x21) -#define AW88399_TEMP_REG (0x22) -#define AW88399_PVDD_REG (0x23) -#define AW88399_ISNDAT_REG (0x24) -#define AW88399_VSNDAT_REG (0x25) -#define AW88399_I2SINT_REG (0x26) -#define AW88399_I2SCAPCNT_REG (0x27) -#define AW88399_ANASTA1_REG (0x28) -#define AW88399_ANASTA2_REG (0x29) -#define AW88399_ANASTA3_REG (0x2A) -#define AW88399_TESTDET_REG (0x2B) -#define AW88399_DSMCFG1_REG (0x30) -#define AW88399_DSMCFG2_REG (0x31) -#define AW88399_DSMCFG3_REG (0x32) -#define AW88399_DSMCFG4_REG (0x33) -#define AW88399_DSMCFG5_REG (0x34) -#define AW88399_DSMCFG6_REG (0x35) -#define AW88399_DSMCFG7_REG (0x36) -#define AW88399_DSMCFG8_REG (0x37) -#define AW88399_TESTIN_REG (0x38) -#define AW88399_TESTOUT_REG (0x39) -#define AW88399_MEMTEST_REG (0x3A) -#define AW88399_VSNCTRL1_REG (0x3B) -#define AW88399_ISNCTRL1_REG (0x3C) -#define AW88399_ISNCTRL2_REG (0x3D) -#define AW88399_DSPMADD_REG (0x40) -#define AW88399_DSPMDAT_REG (0x41) -#define AW88399_WDT_REG (0x42) -#define AW88399_ACR1_REG (0x43) -#define AW88399_ACR2_REG (0x44) -#define AW88399_ASR1_REG (0x45) -#define AW88399_ASR2_REG (0x46) -#define AW88399_DSPCFG_REG (0x47) -#define AW88399_ASR3_REG (0x48) -#define AW88399_ASR4_REG (0x49) -#define AW88399_DSPVCALB_REG (0x4A) -#define AW88399_CRCCTRL_REG (0x4B) -#define AW88399_DSPDBG1_REG (0x4C) -#define AW88399_DSPDBG2_REG (0x4D) -#define AW88399_DSPDBG3_REG (0x4E) -#define AW88399_PLLCTRL1_REG (0x50) -#define AW88399_PLLCTRL2_REG (0x51) -#define AW88399_PLLCTRL3_REG (0x52) -#define AW88399_CDACTRL1_REG (0x53) -#define AW88399_CDACTRL2_REG (0x54) -#define AW88399_CDACTRL3_REG (0x55) -#define AW88399_SADCCTRL1_REG (0x56) -#define AW88399_SADCCTRL2_REG (0x57) -#define AW88399_BOPCTRL1_REG (0x58) -#define AW88399_BOPCTRL2_REG (0x5A) -#define AW88399_BOPCTRL3_REG (0x5B) -#define AW88399_BOPCTRL4_REG (0x5C) -#define AW88399_BOPCTRL5_REG (0x5D) -#define AW88399_BOPCTRL6_REG (0x5E) -#define AW88399_BOPCTRL7_REG (0x5F) -#define AW88399_BSTCTRL1_REG (0x60) -#define AW88399_BSTCTRL2_REG (0x61) -#define AW88399_BSTCTRL3_REG (0x62) -#define AW88399_BSTCTRL4_REG (0x63) -#define AW88399_BSTCTRL5_REG (0x64) -#define AW88399_BSTCTRL6_REG (0x65) -#define AW88399_BSTCTRL7_REG (0x66) -#define AW88399_BSTCTRL8_REG (0x67) -#define AW88399_BSTCTRL9_REG (0x68) -#define AW88399_BSTCTRL10_REG (0x69) -#define AW88399_CPCTRL_REG (0x6A) -#define AW88399_EFWH_REG (0x6C) -#define AW88399_EFWM2_REG (0x6D) -#define AW88399_EFWM1_REG (0x6E) -#define AW88399_EFWL_REG (0x6F) -#define AW88399_TESTCTRL1_REG (0x70) -#define AW88399_TESTCTRL2_REG (0x71) -#define AW88399_EFCTRL1_REG (0x72) -#define AW88399_EFCTRL2_REG (0x73) -#define AW88399_EFRH4_REG (0x74) -#define AW88399_EFRH3_REG (0x75) -#define AW88399_EFRH2_REG (0x76) -#define AW88399_EFRH1_REG (0x77) -#define AW88399_EFRL4_REG (0x78) -#define AW88399_EFRL3_REG (0x79) -#define AW88399_EFRL2_REG (0x7A) -#define AW88399_EFRL1_REG (0x7B) -#define AW88399_TM_REG (0x7C) -#define AW88399_TM2_REG (0x7D) - -#define AW88399_REG_MAX (0x7E) -#define AW88399_MUTE_VOL (1023) - -#define AW88399_DSP_CFG_ADDR (0x9B00) -#define AW88399_DSP_REG_CFG_ADPZ_RA (0x9B68) -#define AW88399_DSP_FW_ADDR (0x8980) -#define AW88399_DSP_ROM_CHECK_ADDR (0x1F40) -#define AW88399_DSP_ROM_CHECK_DATA (0x4638) - -#define AW88399_CALI_RE_HBITS_MASK (~(0xFFFF0000)) -#define AW88399_CALI_RE_HBITS_SHIFT (16) - -#define AW88399_CALI_RE_LBITS_MASK (~(0xFFFF)) -#define AW88399_CALI_RE_LBITS_SHIFT (0) - -#define AW88399_I2STXEN_START_BIT (9) -#define AW88399_I2STXEN_BITS_LEN (1) -#define AW88399_I2STXEN_MASK \ - (~(((1<<AW88399_I2STXEN_BITS_LEN)-1) << AW88399_I2STXEN_START_BIT)) - -#define AW88399_I2STXEN_DISABLE (0) -#define AW88399_I2STXEN_DISABLE_VALUE \ - (AW88399_I2STXEN_DISABLE << AW88399_I2STXEN_START_BIT) - -#define AW88399_I2STXEN_ENABLE (1) -#define AW88399_I2STXEN_ENABLE_VALUE \ - (AW88399_I2STXEN_ENABLE << AW88399_I2STXEN_START_BIT) - -#define AW88399_VOL_START_BIT (0) -#define AW88399_VOL_BITS_LEN (10) -#define AW88399_VOL_MASK \ - (~(((1<<AW88399_VOL_BITS_LEN)-1) << AW88399_VOL_START_BIT)) - -#define AW88399_PWDN_START_BIT (0) -#define AW88399_PWDN_BITS_LEN (1) -#define AW88399_PWDN_MASK \ - (~(((1<<AW88399_PWDN_BITS_LEN)-1) << AW88399_PWDN_START_BIT)) - -#define AW88399_PWDN_POWER_DOWN (1) -#define AW88399_PWDN_POWER_DOWN_VALUE \ - (AW88399_PWDN_POWER_DOWN << AW88399_PWDN_START_BIT) - -#define AW88399_PWDN_WORKING (0) -#define AW88399_PWDN_WORKING_VALUE \ - (AW88399_PWDN_WORKING << AW88399_PWDN_START_BIT) - -#define AW88399_DSPBY_START_BIT (2) -#define AW88399_DSPBY_BITS_LEN (1) -#define AW88399_DSPBY_MASK \ - (~(((1<<AW88399_DSPBY_BITS_LEN)-1) << AW88399_DSPBY_START_BIT)) - -#define AW88399_DSPBY_WORKING (0) -#define AW88399_DSPBY_WORKING_VALUE \ - (AW88399_DSPBY_WORKING << AW88399_DSPBY_START_BIT) - -#define AW88399_DSPBY_BYPASS (1) -#define AW88399_DSPBY_BYPASS_VALUE \ - (AW88399_DSPBY_BYPASS << AW88399_DSPBY_START_BIT) - -#define AW88399_MEM_CLKSEL_START_BIT (3) -#define AW88399_MEM_CLKSEL_BITS_LEN (1) -#define AW88399_MEM_CLKSEL_MASK \ - (~(((1<<AW88399_MEM_CLKSEL_BITS_LEN)-1) << AW88399_MEM_CLKSEL_START_BIT)) - -#define AW88399_MEM_CLKSEL_OSCCLK (0) -#define AW88399_MEM_CLKSEL_OSCCLK_VALUE \ - (AW88399_MEM_CLKSEL_OSCCLK << AW88399_MEM_CLKSEL_START_BIT) - -#define AW88399_MEM_CLKSEL_DAPHCLK (1) -#define AW88399_MEM_CLKSEL_DAPHCLK_VALUE \ - (AW88399_MEM_CLKSEL_DAPHCLK << AW88399_MEM_CLKSEL_START_BIT) - -#define AW88399_DITHER_EN_START_BIT (15) -#define AW88399_DITHER_EN_BITS_LEN (1) -#define AW88399_DITHER_EN_MASK \ - (~(((1<<AW88399_DITHER_EN_BITS_LEN)-1) << AW88399_DITHER_EN_START_BIT)) - -#define AW88399_DITHER_EN_DISABLE (0) -#define AW88399_DITHER_EN_DISABLE_VALUE \ - (AW88399_DITHER_EN_DISABLE << AW88399_DITHER_EN_START_BIT) - -#define AW88399_DITHER_EN_ENABLE (1) -#define AW88399_DITHER_EN_ENABLE_VALUE \ - (AW88399_DITHER_EN_ENABLE << AW88399_DITHER_EN_START_BIT) - -#define AW88399_HMUTE_START_BIT (8) -#define AW88399_HMUTE_BITS_LEN (1) -#define AW88399_HMUTE_MASK \ - (~(((1<<AW88399_HMUTE_BITS_LEN)-1) << AW88399_HMUTE_START_BIT)) - -#define AW88399_HMUTE_DISABLE (0) -#define AW88399_HMUTE_DISABLE_VALUE \ - (AW88399_HMUTE_DISABLE << AW88399_HMUTE_START_BIT) - -#define AW88399_HMUTE_ENABLE (1) -#define AW88399_HMUTE_ENABLE_VALUE \ - (AW88399_HMUTE_ENABLE << AW88399_HMUTE_START_BIT) - -#define AW88399_EF_DBMD_START_BIT (2) -#define AW88399_EF_DBMD_BITS_LEN (1) -#define AW88399_EF_DBMD_MASK \ - (~(((1<<AW88399_EF_DBMD_BITS_LEN)-1) << AW88399_EF_DBMD_START_BIT)) - -#define AW88399_EF_DBMD_OR (1) -#define AW88399_EF_DBMD_OR_VALUE \ - (AW88399_EF_DBMD_OR << AW88399_EF_DBMD_START_BIT) - -#define AW88399_VDSEL_START_BIT (5) -#define AW88399_VDSEL_BITS_LEN (1) -#define AW88399_VDSEL_MASK \ - (~(((1<<AW88399_VDSEL_BITS_LEN)-1) << AW88399_VDSEL_START_BIT)) - -#define AW88399_EF_ISN_GESLP_H_START_BIT (0) -#define AW88399_EF_ISN_GESLP_H_BITS_LEN (10) -#define AW88399_EF_ISN_GESLP_H_MASK \ - (~(((1<<AW88399_EF_ISN_GESLP_H_BITS_LEN)-1) << AW88399_EF_ISN_GESLP_H_START_BIT)) - -/* EF_VSN_GESLP_H bit 9:0 (EFRH3 0x75) */ -#define AW88399_EF_VSN_GESLP_H_START_BIT (0) -#define AW88399_EF_VSN_GESLP_H_BITS_LEN (10) -#define AW88399_EF_VSN_GESLP_H_MASK \ - (~(((1<<AW88399_EF_VSN_GESLP_H_BITS_LEN)-1) << AW88399_EF_VSN_GESLP_H_START_BIT)) - -#define AW88399_EF_ISN_GESLP_L_START_BIT (0) -#define AW88399_EF_ISN_GESLP_L_BITS_LEN (10) -#define AW88399_EF_ISN_GESLP_L_MASK \ - (~(((1<<AW88399_EF_ISN_GESLP_L_BITS_LEN)-1) << AW88399_EF_ISN_GESLP_L_START_BIT)) - -/* EF_VSN_GESLP_L bit 9:0 (EFRL3 0x79) */ -#define AW88399_EF_VSN_GESLP_L_START_BIT (0) -#define AW88399_EF_VSN_GESLP_L_BITS_LEN (10) -#define AW88399_EF_VSN_GESLP_L_MASK \ - (~(((1<<AW88399_EF_VSN_GESLP_L_BITS_LEN)-1) << AW88399_EF_VSN_GESLP_L_START_BIT)) - -#define AW88399_INTERNAL_VSN_TRIM_H_START_BIT (9) -#define AW88399_INTERNAL_VSN_TRIM_H_BITS_LEN (6) -#define AW88399_INTERNAL_VSN_TRIM_H_MASK \ - (~(((1<<AW88399_INTERNAL_VSN_TRIM_H_BITS_LEN)-1) << AW88399_INTERNAL_VSN_TRIM_H_START_BIT)) - -#define AW88399_INTERNAL_VSN_TRIM_L_START_BIT (9) -#define AW88399_INTERNAL_VSN_TRIM_L_BITS_LEN (6) -#define AW88399_INTERNAL_VSN_TRIM_L_MASK \ - (~(((1<<AW88399_INTERNAL_VSN_TRIM_L_BITS_LEN)-1) << AW88399_INTERNAL_VSN_TRIM_L_START_BIT)) - -#define AW88399_RCV_MODE_START_BIT (7) -#define AW88399_RCV_MODE_BITS_LEN (1) -#define AW88399_RCV_MODE_MASK \ - (~(((1<<AW88399_RCV_MODE_BITS_LEN)-1) << AW88399_RCV_MODE_START_BIT)) - -#define AW88399_CLKI_START_BIT (4) -#define AW88399_NOCLKI_START_BIT (5) -#define AW88399_PLLI_START_BIT (0) -#define AW88399_PLLI_INT_VALUE (1) -#define AW88399_PLLI_INT_INTERRUPT \ - (AW88399_PLLI_INT_VALUE << AW88399_PLLI_START_BIT) - -#define AW88399_CLKI_INT_VALUE (1) -#define AW88399_CLKI_INT_INTERRUPT \ - (AW88399_CLKI_INT_VALUE << AW88399_CLKI_START_BIT) - -#define AW88399_NOCLKI_INT_VALUE (1) -#define AW88399_NOCLKI_INT_INTERRUPT \ - (AW88399_NOCLKI_INT_VALUE << AW88399_NOCLKI_START_BIT) - -#define AW88399_BIT_SYSINT_CHECK \ - (AW88399_PLLI_INT_INTERRUPT | \ - AW88399_CLKI_INT_INTERRUPT | \ - AW88399_NOCLKI_INT_INTERRUPT) - -#define AW88399_CRC_CHECK_START_BIT (12) -#define AW88399_CRC_CHECK_BITS_LEN (3) -#define AW88399_CRC_CHECK_BITS_MASK \ - (~(((1<<AW88399_CRC_CHECK_BITS_LEN)-1) << AW88399_CRC_CHECK_START_BIT)) - -#define AW88399_RCV_MODE_RECEIVER (1) -#define AW88399_RCV_MODE_RECEIVER_VALUE \ - (AW88399_RCV_MODE_RECEIVER << AW88399_RCV_MODE_START_BIT) - -#define AW88399_AMPPD_START_BIT (1) -#define AW88399_AMPPD_BITS_LEN (1) -#define AW88399_AMPPD_MASK \ - (~(((1<<AW88399_AMPPD_BITS_LEN)-1) << AW88399_AMPPD_START_BIT)) - -#define AW88399_AMPPD_WORKING (0) -#define AW88399_AMPPD_WORKING_VALUE \ - (AW88399_AMPPD_WORKING << AW88399_AMPPD_START_BIT) - -#define AW88399_AMPPD_POWER_DOWN (1) -#define AW88399_AMPPD_POWER_DOWN_VALUE \ - (AW88399_AMPPD_POWER_DOWN << AW88399_AMPPD_START_BIT) - -#define AW88399_RAM_CG_BYP_START_BIT (0) -#define AW88399_RAM_CG_BYP_BITS_LEN (1) -#define AW88399_RAM_CG_BYP_MASK \ - (~(((1<<AW88399_RAM_CG_BYP_BITS_LEN)-1) << AW88399_RAM_CG_BYP_START_BIT)) - -#define AW88399_RAM_CG_BYP_WORK (0) -#define AW88399_RAM_CG_BYP_WORK_VALUE \ - (AW88399_RAM_CG_BYP_WORK << AW88399_RAM_CG_BYP_START_BIT) - -#define AW88399_RAM_CG_BYP_BYPASS (1) -#define AW88399_RAM_CG_BYP_BYPASS_VALUE \ - (AW88399_RAM_CG_BYP_BYPASS << AW88399_RAM_CG_BYP_START_BIT) - -#define AW88399_CRC_END_ADDR_START_BIT (0) -#define AW88399_CRC_END_ADDR_BITS_LEN (12) -#define AW88399_CRC_END_ADDR_MASK \ - (~(((1<<AW88399_CRC_END_ADDR_BITS_LEN)-1) << AW88399_CRC_END_ADDR_START_BIT)) - -#define AW88399_CRC_CODE_EN_START_BIT (13) -#define AW88399_CRC_CODE_EN_BITS_LEN (1) -#define AW88399_CRC_CODE_EN_MASK \ - (~(((1<<AW88399_CRC_CODE_EN_BITS_LEN)-1) << AW88399_CRC_CODE_EN_START_BIT)) - -#define AW88399_CRC_CODE_EN_DISABLE (0) -#define AW88399_CRC_CODE_EN_DISABLE_VALUE \ - (AW88399_CRC_CODE_EN_DISABLE << AW88399_CRC_CODE_EN_START_BIT) - -#define AW88399_CRC_CODE_EN_ENABLE (1) -#define AW88399_CRC_CODE_EN_ENABLE_VALUE \ - (AW88399_CRC_CODE_EN_ENABLE << AW88399_CRC_CODE_EN_START_BIT) - -#define AW88399_CRC_CFG_EN_START_BIT (12) -#define AW88399_CRC_CFG_EN_BITS_LEN (1) -#define AW88399_CRC_CFG_EN_MASK \ - (~(((1<<AW88399_CRC_CFG_EN_BITS_LEN)-1) << AW88399_CRC_CFG_EN_START_BIT)) - -#define AW88399_CRC_CFG_EN_DISABLE (0) -#define AW88399_CRC_CFG_EN_DISABLE_VALUE \ - (AW88399_CRC_CFG_EN_DISABLE << AW88399_CRC_CFG_EN_START_BIT) - -#define AW88399_CRC_CFG_EN_ENABLE (1) -#define AW88399_CRC_CFG_EN_ENABLE_VALUE \ - (AW88399_CRC_CFG_EN_ENABLE << AW88399_CRC_CFG_EN_START_BIT) - -#define AW88399_OCDS_START_BIT (3) -#define AW88399_OCDS_OC (1) -#define AW88399_OCDS_OC_VALUE \ - (AW88399_OCDS_OC << AW88399_OCDS_START_BIT) - -#define AW88399_NOCLKS_START_BIT (5) -#define AW88399_NOCLKS_NO_CLOCK (1) -#define AW88399_NOCLKS_NO_CLOCK_VALUE \ - (AW88399_NOCLKS_NO_CLOCK << AW88399_NOCLKS_START_BIT) - -#define AW88399_SWS_START_BIT (8) -#define AW88399_SWS_SWITCHING (1) -#define AW88399_SWS_SWITCHING_VALUE \ - (AW88399_SWS_SWITCHING << AW88399_SWS_START_BIT) - -#define AW88399_BSTS_START_BIT (9) -#define AW88399_BSTS_FINISHED (1) -#define AW88399_BSTS_FINISHED_VALUE \ - (AW88399_BSTS_FINISHED << AW88399_BSTS_START_BIT) - -#define AW88399_UVLS_START_BIT (14) -#define AW88399_UVLS_NORMAL (0) -#define AW88399_UVLS_NORMAL_VALUE \ - (AW88399_UVLS_NORMAL << AW88399_UVLS_START_BIT) - -#define AW88399_BSTOCS_START_BIT (11) -#define AW88399_BSTOCS_OVER_CURRENT (1) -#define AW88399_BSTOCS_OVER_CURRENT_VALUE \ - (AW88399_BSTOCS_OVER_CURRENT << AW88399_BSTOCS_START_BIT) - -#define AW88399_OTHS_START_BIT (1) -#define AW88399_OTHS_OT (1) -#define AW88399_OTHS_OT_VALUE \ - (AW88399_OTHS_OT << AW88399_OTHS_START_BIT) - -#define AW88399_PLLS_START_BIT (0) -#define AW88399_PLLS_LOCKED (1) -#define AW88399_PLLS_LOCKED_VALUE \ - (AW88399_PLLS_LOCKED << AW88399_PLLS_START_BIT) - -#define AW88399_CLKS_START_BIT (4) -#define AW88399_CLKS_STABLE (1) -#define AW88399_CLKS_STABLE_VALUE \ - (AW88399_CLKS_STABLE << AW88399_CLKS_START_BIT) - -#define AW88399_BIT_PLL_CHECK \ - (AW88399_CLKS_STABLE_VALUE | \ - AW88399_PLLS_LOCKED_VALUE) - -#define AW88399_BIT_SYSST_CHECK_MASK \ - (~(AW88399_UVLS_NORMAL_VALUE | \ - AW88399_BSTOCS_OVER_CURRENT_VALUE | \ - AW88399_BSTS_FINISHED_VALUE | \ - AW88399_SWS_SWITCHING_VALUE | \ - AW88399_NOCLKS_NO_CLOCK_VALUE | \ - AW88399_CLKS_STABLE_VALUE | \ - AW88399_OCDS_OC_VALUE | \ - AW88399_OTHS_OT_VALUE | \ - AW88399_PLLS_LOCKED_VALUE)) - -#define AW88399_BIT_SYSST_NOSWS_CHECK \ - (AW88399_BSTS_FINISHED_VALUE | \ - AW88399_CLKS_STABLE_VALUE | \ - AW88399_PLLS_LOCKED_VALUE) - -#define AW88399_BIT_SYSST_SWS_CHECK \ - (AW88399_BSTS_FINISHED_VALUE | \ - AW88399_CLKS_STABLE_VALUE | \ - AW88399_PLLS_LOCKED_VALUE | \ - AW88399_SWS_SWITCHING_VALUE) - -#define AW88399_CCO_MUX_START_BIT (14) -#define AW88399_CCO_MUX_BITS_LEN (1) -#define AW88399_CCO_MUX_MASK \ - (~(((1<<AW88399_CCO_MUX_BITS_LEN)-1) << AW88399_CCO_MUX_START_BIT)) - -#define AW88399_CCO_MUX_DIVIDED (0) -#define AW88399_CCO_MUX_DIVIDED_VALUE \ - (AW88399_CCO_MUX_DIVIDED << AW88399_CCO_MUX_START_BIT) - -#define AW88399_CCO_MUX_BYPASS (1) -#define AW88399_CCO_MUX_BYPASS_VALUE \ - (AW88399_CCO_MUX_BYPASS << AW88399_CCO_MUX_START_BIT) - -#define AW88399_NOISE_GATE_EN_START_BIT (13) -#define AW88399_NOISE_GATE_EN_BITS_LEN (1) -#define AW88399_NOISE_GATE_EN_MASK \ - (~(((1<<AW88399_NOISE_GATE_EN_BITS_LEN)-1) << AW88399_NOISE_GATE_EN_START_BIT)) - -#define AW88399_WDT_CNT_START_BIT (0) -#define AW88399_WDT_CNT_BITS_LEN (8) -#define AW88399_WDT_CNT_MASK \ - (~(((1<<AW88399_WDT_CNT_BITS_LEN)-1) << AW88399_WDT_CNT_START_BIT)) - -#define AW88399_REABS_START_BIT (3) -#define AW88399_REABS_BITS_LEN (1) -#define AW88399_REABS_MASK \ - (~(((1<<AW88399_REABS_BITS_LEN)-1) << AW88399_REABS_START_BIT)) - -#define AW88399_DSP_VOL_START_BIT (8) -#define AW88399_DSP_VOL_BITS_LEN (8) -#define AW88399_DSP_VOL_MASK \ - (~(((1<<AW88399_DSP_VOL_BITS_LEN)-1) << AW88399_DSP_VOL_START_BIT)) - -#define AW883XX_DSP_NG_EN_START (13) -#define AW883XX_DSP_NG_EN_LEN (1) -#define AW883XX_DSP_NG_EN_MASK \ - (~(((1 << AW883XX_DSP_NG_EN_LEN) - 1) << AW883XX_DSP_NG_EN_START)) -#define AW883XX_DSP_NG_EN_DISABLE (0) -#define AW883XX_DSP_NG_EN_DISABLE_VALUE \ - (AW883XX_DSP_NG_EN_DISABLE << AW883XX_DSP_NG_EN_START) - -#define AW88399_VOLUME_STEP_DB (64) -#define AW88399_VOL_DEFAULT_VALUE (0) -#define AW88399_DSP_ODD_NUM_BIT_TEST (0x5555) -#define AW88399_EF_ISN_GESLP_SIGN_MASK (~(1 << 9)) -#define AW88399_EF_ISN_GESLP_SIGN_NEG (0xfe00) - -#define AW88399_EF_VSN_GESLP_SIGN_MASK (~(1 << 9)) -#define AW88399_EF_VSN_GESLP_SIGN_NEG (0xfe00) - -#define AW88399_TEM4_SIGN_MASK (~(1 << 5)) -#define AW88399_TEM4_SIGN_NEG (0xffc0) - -#define AW88399_ICABLK_FACTOR (1) -#define AW88399_VCABLK_FACTOR (1) -#define AW88399_VCABLK_DAC_FACTOR (2) - -#define AW88399_VCALB_ADJ_FACTOR (12) -#define AW88399_VCALB_ACCURACY (1 << 12) - -#define AW88399_ISCAL_FACTOR (3125) -#define AW88399_VSCAL_FACTOR (18875) -#define AW88399_ISCAL_DAC_FACTOR (3125) -#define AW88399_VSCAL_DAC_FACTOR (12600) -#define AW88399_CABL_BASE_VALUE (1000) - -#define AW88399_DEV_DEFAULT_CH (0) -#define AW88399_DEV_DSP_CHECK_MAX (5) -#define AW88399_MAX_RAM_WRITE_BYTE_SIZE (128) -#define AW88399_DSP_RE_SHIFT (12) -#define AW88399_CALI_RE_MAX (15000) -#define AW88399_CALI_RE_MIN (4000) -#define AW_FW_ADDR_LEN (4) -#define AW88399_DSP_RE_TO_SHOW_RE(re, shift) (((re) * (1000)) >> (shift)) -#define AW88399_SHOW_RE_TO_DSP_RE(re, shift) (((re) << shift) / (1000)) -#define AW88399_CRC_CHECK_PASS_VAL (0x4) - -#define AW88399_CRC_CFG_BASE_ADDR (0xD80) -#define AW88399_CRC_FW_BASE_ADDR (0x4C0) -#define AW88399_ACF_FILE "aw88399_acf.bin" -#define AW88399_DEV_SYSST_CHECK_MAX (10) -#define AW88399_CHIP_ID 0x2183 +#include <sound/aw88399.h> #define AW88399_I2C_NAME "aw88399" -#define AW88399_START_RETRIES (5) -#define AW88399_START_WORK_DELAY_MS (0) - #define AW88399_RATES (SNDRV_PCM_RATE_8000_48000 | \ SNDRV_PCM_RATE_96000) #define AW88399_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ @@ -550,80 +48,4 @@ .put = profile_set, \ } -enum { - AW_EF_AND_CHECK = 0, - AW_EF_OR_CHECK, -}; - -enum { - AW88399_DEV_VDSEL_DAC = 0, - AW88399_DEV_VDSEL_VSENSE = 32, -}; - -enum { - AW88399_DSP_CRC_NA = 0, - AW88399_DSP_CRC_OK = 1, -}; - -enum { - AW88399_DSP_FW_UPDATE_OFF = 0, - AW88399_DSP_FW_UPDATE_ON = 1, -}; - -enum { - AW88399_FORCE_UPDATE_OFF = 0, - AW88399_FORCE_UPDATE_ON = 1, -}; - -enum { - AW88399_1000_US = 1000, - AW88399_2000_US = 2000, - AW88399_3000_US = 3000, - AW88399_4000_US = 4000, -}; - -enum AW88399_DEV_STATUS { - AW88399_DEV_PW_OFF = 0, - AW88399_DEV_PW_ON, -}; - -enum AW88399_DEV_FW_STATUS { - AW88399_DEV_FW_FAILED = 0, - AW88399_DEV_FW_OK, -}; - -enum AW88399_DEV_MEMCLK { - AW88399_DEV_MEMCLK_OSC = 0, - AW88399_DEV_MEMCLK_PLL = 1, -}; - -enum AW88399_DEV_DSP_CFG { - AW88399_DEV_DSP_WORK = 0, - AW88399_DEV_DSP_BYPASS = 1, -}; - -enum { - AW88399_NOT_RCV_MODE = 0, - AW88399_RCV_MODE = 1, -}; - -enum { - AW88399_SYNC_START = 0, - AW88399_ASYNC_START, -}; - -struct aw88399 { - struct aw_device *aw_pa; - struct mutex lock; - struct gpio_desc *reset_gpio; - struct delayed_work start_work; - struct regmap *regmap; - struct aw_container *aw_cfg; - - unsigned int check_val; - unsigned int crc_init_val; - unsigned int vcalb_init_val; - unsigned int dither_st; -}; - -#endif +#endif /* __AW88399_H__ */ diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c index c0bf45b76cb8..b085885e3f18 100644 --- a/sound/soc/codecs/bt-sco.c +++ b/sound/soc/codecs/bt-sco.c @@ -85,13 +85,9 @@ static int bt_sco_probe(struct platform_device *pdev) } static const struct platform_device_id bt_sco_driver_ids[] = { - { - .name = "dfbmcs320", - }, - { - .name = "bt-sco", - }, - {}, + { .name = "dfbmcs320" }, + { .name = "bt-sco" }, + { } }; MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids); diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c index 6b80c455b074..fc41e1547bda 100644 --- a/sound/soc/codecs/cpcap.c +++ b/sound/soc/codecs/cpcap.c @@ -26,14 +26,6 @@ /* Register 9 - CPCAP_REG_INTS2 --- Interrupt Sense 2 */ #define CPCAP_BIT_PTT_S 11 /* Push To Talk */ -/* Register 512 CPCAP_REG_VAUDIOC --- Audio Regulator and Bias Voltage */ -#define CPCAP_BIT_AUDIO_LOW_PWR 6 -#define CPCAP_BIT_AUD_LOWPWR_SPEED 5 -#define CPCAP_BIT_VAUDIOPRISTBY 4 -#define CPCAP_BIT_VAUDIO_MODE1 2 -#define CPCAP_BIT_VAUDIO_MODE0 1 -#define CPCAP_BIT_V_AUDIO_EN 0 - /* Register 513 CPCAP_REG_CC --- CODEC */ #define CPCAP_BIT_CDC_CLK2 15 #define CPCAP_BIT_CDC_CLK1 14 @@ -239,7 +231,6 @@ struct cpcap_reg_info { }; static const struct cpcap_reg_info cpcap_default_regs[] = { - { CPCAP_REG_VAUDIOC, 0x003F, 0x0000 }, { CPCAP_REG_CC, 0xFFFF, 0x0000 }, { CPCAP_REG_CC, 0xFFFF, 0x0000 }, { CPCAP_REG_CDI, 0xBFFF, 0x0000 }, @@ -1265,6 +1256,7 @@ static int cpcap_voice_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_component *component = dai->component; struct device *dev = component->dev; struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); @@ -1298,7 +1290,7 @@ static int cpcap_voice_hw_params(struct snd_pcm_substream *substream, return err; } - return 0; + return snd_soc_runtime_set_dai_fmt(rtd, rtd->dai_link->dai_fmt); } static int cpcap_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, @@ -1391,121 +1383,8 @@ static int cpcap_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, return 0; } - -/* - * Configure codec for voice call if requested. - * - * We can configure most with snd_soc_dai_set_sysclk(), snd_soc_dai_set_fmt() - * and snd_soc_dai_set_tdm_slot(). This function configures the rest of the - * cpcap related hardware as CPU is not involved in the voice call. - */ -static int cpcap_voice_call(struct cpcap_audio *cpcap, struct snd_soc_dai *dai, - bool voice_call) -{ - int mask, err; - - /* Modem to codec VAUDIO_MODE1 */ - mask = BIT(CPCAP_BIT_VAUDIO_MODE1); - err = regmap_update_bits(cpcap->regmap, CPCAP_REG_VAUDIOC, - mask, voice_call ? mask : 0); - if (err) - return err; - - /* Clear MIC1_MUX for call */ - mask = BIT(CPCAP_BIT_MIC1_MUX); - err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI, - mask, voice_call ? 0 : mask); - if (err) - return err; - - /* Set MIC2_MUX for call */ - mask = BIT(CPCAP_BIT_MB_ON1L) | BIT(CPCAP_BIT_MB_ON1R) | - BIT(CPCAP_BIT_MIC2_MUX) | BIT(CPCAP_BIT_MIC2_PGA_EN); - err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI, - mask, voice_call ? mask : 0); - if (err) - return err; - - /* Enable LDSP for call */ - mask = BIT(CPCAP_BIT_A2_LDSP_L_EN) | BIT(CPCAP_BIT_A2_LDSP_R_EN); - err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXOA, - mask, voice_call ? mask : 0); - if (err) - return err; - - /* Enable CPCAP_BIT_PGA_CDC_EN for call */ - mask = BIT(CPCAP_BIT_PGA_CDC_EN); - err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXCOA, - mask, voice_call ? mask : 0); - if (err) - return err; - - /* Unmute voice for call */ - if (dai) { - err = snd_soc_dai_digital_mute(dai, !voice_call, - SNDRV_PCM_STREAM_PLAYBACK); - if (err) - return err; - } - - /* Set modem to codec mic CDC and HPF for call */ - mask = BIT(CPCAP_BIT_MIC2_CDC_EN) | BIT(CPCAP_BIT_CDC_EN_RX) | - BIT(CPCAP_BIT_AUDOHPF_1) | BIT(CPCAP_BIT_AUDOHPF_0) | - BIT(CPCAP_BIT_AUDIHPF_1) | BIT(CPCAP_BIT_AUDIHPF_0); - err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CC, - mask, voice_call ? mask : 0); - if (err) - return err; - - /* Enable modem to codec CDC for call*/ - mask = BIT(CPCAP_BIT_CDC_CLK_EN); - err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI, - mask, voice_call ? mask : 0); - - return err; -} - -static int cpcap_voice_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int tx_mask, unsigned int rx_mask, - int slots, int slot_width) -{ - struct snd_soc_component *component = dai->component; - struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); - int err, ts_mask, mask; - bool voice_call; - - /* - * Primitive test for voice call, probably needs more checks - * later on for 16-bit calls detected, Bluetooth headset etc. - */ - if (tx_mask == 0 && rx_mask == 1 && slot_width == 8) - voice_call = true; - else - voice_call = false; - - ts_mask = 0x7 << CPCAP_BIT_MIC2_TIMESLOT0; - ts_mask |= 0x7 << CPCAP_BIT_MIC1_RX_TIMESLOT0; - - mask = (tx_mask & 0x7) << CPCAP_BIT_MIC2_TIMESLOT0; - mask |= (rx_mask & 0x7) << CPCAP_BIT_MIC1_RX_TIMESLOT0; - - err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI, - ts_mask, mask); - if (err) - return err; - - err = cpcap_set_samprate(cpcap, CPCAP_DAI_VOICE, slot_width * 1000); - if (err) - return err; - - err = cpcap_voice_call(cpcap, dai, voice_call); - if (err) - return err; - - return 0; -} - -static int cpcap_voice_set_mute(struct snd_soc_dai *dai, int mute, int direction) +static int cpcap_voice_set_mute(struct snd_soc_dai *dai, + int mute, int direction) { struct snd_soc_component *component = dai->component; struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); @@ -1526,7 +1405,6 @@ static const struct snd_soc_dai_ops cpcap_dai_voice_ops = { .hw_params = cpcap_voice_hw_params, .set_sysclk = cpcap_voice_set_dai_sysclk, .set_fmt = cpcap_voice_set_dai_fmt, - .set_tdm_slot = cpcap_voice_set_tdm_slot, .mute_stream = cpcap_voice_set_mute, .no_capture_mute = 1, }; diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c index 7dc5a7c3ca96..1148e37e29ce 100644 --- a/sound/soc/codecs/cros_ec_codec.c +++ b/sound/soc/codecs/cros_ec_codec.c @@ -12,6 +12,7 @@ #include <linux/acpi.h> #include <linux/delay.h> #include <linux/device.h> +#include <linux/cleanup.h> #include <linux/io.h> #include <linux/jiffies.h> #include <linux/kernel.h> @@ -319,10 +320,18 @@ static int i2s_rx_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) (uint8_t *)&p, sizeof(p), NULL, 0); } +static const u64 i2s_rx_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J | + SND_SOC_POSSIBLE_DAIFMT_NB_NF; + static const struct snd_soc_dai_ops i2s_rx_dai_ops = { .hw_params = i2s_rx_hw_params, .set_fmt = i2s_rx_set_fmt, .set_bclk_ratio = i2s_rx_set_bclk_ratio, + .auto_selectable_formats = &i2s_rx_selectable_formats, + .num_auto_selectable_formats = 1, }; static int i2s_rx_event(struct snd_soc_dapm_widget *w, @@ -608,10 +617,10 @@ static void wov_copy_work(struct work_struct *w) container_of(w, struct cros_ec_codec_priv, wov_copy_work.work); int ret; - mutex_lock(&priv->wov_dma_lock); + guard(mutex)(&priv->wov_dma_lock); if (!priv->wov_substream) { dev_warn(priv->dev, "no pcm substream\n"); - goto leave; + return; } if (ec_codec_capable(priv, EC_CODEC_CAP_WOV_AUDIO_SHM)) @@ -624,8 +633,6 @@ static void wov_copy_work(struct work_struct *w) msecs_to_jiffies(10)); else if (ret) dev_err(priv->dev, "failed to read audio data\n"); -leave: - mutex_unlock(&priv->wov_dma_lock); } static int wov_enable_get(struct snd_kcontrol *kcontrol, @@ -895,12 +902,11 @@ static int wov_pcm_hw_params(struct snd_soc_component *component, struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(component); - mutex_lock(&priv->wov_dma_lock); + guard(mutex)(&priv->wov_dma_lock); priv->wov_substream = substream; priv->wov_rp = priv->wov_wp = 0; priv->wov_dma_offset = 0; priv->wov_burst_read = true; - mutex_unlock(&priv->wov_dma_lock); return 0; } @@ -911,10 +917,10 @@ static int wov_pcm_hw_free(struct snd_soc_component *component, struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(component); - mutex_lock(&priv->wov_dma_lock); - wov_queue_dequeue(priv, wov_queue_size(priv)); - priv->wov_substream = NULL; - mutex_unlock(&priv->wov_dma_lock); + scoped_guard(mutex, &priv->wov_dma_lock) { + wov_queue_dequeue(priv, wov_queue_size(priv)); + priv->wov_substream = NULL; + } cancel_delayed_work_sync(&priv->wov_copy_work); diff --git a/sound/soc/codecs/cs-amp-lib.c b/sound/soc/codecs/cs-amp-lib.c index 371e99205b58..41a9a5b005c6 100644 --- a/sound/soc/codecs/cs-amp-lib.c +++ b/sound/soc/codecs/cs-amp-lib.c @@ -7,6 +7,7 @@ #include <asm/byteorder.h> #include <kunit/static_stub.h> +#include <linux/cleanup.h> #include <linux/debugfs.h> #include <linux/dev_printk.h> #include <linux/efi.h> @@ -83,10 +84,12 @@ static int cs_amp_write_cal_coeff(struct cs_dsp *dsp, KUNIT_STATIC_STUB_REDIRECT(cs_amp_write_cal_coeff, dsp, controls, ctl_name, val); if (IS_REACHABLE(CONFIG_FW_CS_DSP)) { - mutex_lock(&dsp->pwr_lock); - cs_ctl = cs_dsp_get_ctl(dsp, ctl_name, controls->mem_region, controls->alg_id); - ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, &beval, sizeof(beval)); - mutex_unlock(&dsp->pwr_lock); + scoped_guard(mutex, &dsp->pwr_lock) { + cs_ctl = cs_dsp_get_ctl(dsp, ctl_name, + controls->mem_region, + controls->alg_id); + ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, &beval, sizeof(beval)); + } if (ret < 0) { dev_err(dsp->dev, "Failed to write to '%s': %d\n", ctl_name, ret); diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index c835088de578..8288fb6d50be 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -538,7 +538,15 @@ static int cs35l32_runtime_resume(struct device *dev) gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); regcache_cache_only(cs35l32->regmap, false); - regcache_sync(cs35l32->regmap); + ret = regcache_sync(cs35l32->regmap); + if (ret) { + regcache_cache_only(cs35l32->regmap, true); + regcache_mark_dirty(cs35l32->regmap); + gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); + regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies), + cs35l32->supplies); + return ret; + } return 0; } diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c index f49edb9ea1f2..e217da124549 100644 --- a/sound/soc/codecs/cs35l33.c +++ b/sound/soc/codecs/cs35l33.c @@ -40,6 +40,7 @@ struct cs35l33_private { struct regmap *regmap; struct gpio_desc *reset_gpio; bool amp_cal; + bool irq_requested; int mclk_int; struct regulator_bulk_data core_supplies[2]; int num_core_supplies; @@ -881,6 +882,9 @@ static int cs35l33_runtime_resume(struct device *dev) goto err; } + if (cs35l33->irq_requested) + enable_irq(to_i2c_client(dev)->irq); + return 0; err: @@ -900,6 +904,10 @@ static int cs35l33_runtime_suspend(struct device *dev) /* redo the calibration in next power up */ cs35l33->amp_cal = false; + /* Drain and block the threaded IRQ before cache_only/power-off. */ + if (cs35l33->irq_requested) + disable_irq(to_i2c_client(dev)->irq); + regcache_cache_only(cs35l33->regmap, true); regcache_mark_dirty(cs35l33->regmap); regulator_bulk_disable(cs35l33->num_core_supplies, @@ -1154,10 +1162,12 @@ static int cs35l33_i2c_probe(struct i2c_client *i2c_client) } ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL, - cs35l33_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW, - "cs35l33", cs35l33); + cs35l33_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW, + "cs35l33", cs35l33); if (ret != 0) dev_warn(&i2c_client->dev, "Failed to request IRQ: %d\n", ret); + else + cs35l33->irq_requested = true; /* We could issue !RST or skip it based on AMP topology */ cs35l33->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c index e80984b22159..3f265bd760f7 100644 --- a/sound/soc/codecs/cs35l34.c +++ b/sound/soc/codecs/cs35l34.c @@ -45,6 +45,7 @@ struct cs35l34_private { int num_core_supplies; int mclk_int; bool tdm_mode; + bool irq_requested; struct gpio_desc *reset_gpio; /* Active-low reset GPIO */ }; @@ -1032,10 +1033,12 @@ static int cs35l34_i2c_probe(struct i2c_client *i2c_client) } ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL, - cs35l34_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW, - "cs35l34", cs35l34); + cs35l34_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW, + "cs35l34", cs35l34); if (ret != 0) dev_err(&i2c_client->dev, "Failed to request IRQ: %d\n", ret); + else + cs35l34->irq_requested = true; cs35l34->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, "reset", GPIOD_OUT_LOW); @@ -1140,6 +1143,9 @@ static int cs35l34_runtime_resume(struct device *dev) dev_err(dev, "Failed to restore register cache\n"); goto err; } + + if (cs35l34->irq_requested) + enable_irq(to_i2c_client(dev)->irq); return 0; err: regcache_cache_only(cs35l34->regmap, true); @@ -1153,6 +1159,10 @@ static int cs35l34_runtime_suspend(struct device *dev) { struct cs35l34_private *cs35l34 = dev_get_drvdata(dev); + /* Drain and block the threaded IRQ before cache_only/power-off. */ + if (cs35l34->irq_requested) + disable_irq(to_i2c_client(dev)->irq); + regcache_cache_only(cs35l34->regmap, true); regcache_mark_dirty(cs35l34->regmap); diff --git a/sound/soc/codecs/cs35l56-i2c.c b/sound/soc/codecs/cs35l56-i2c.c index 4f6ddf1c5a3f..5e69ddbe342a 100644 --- a/sound/soc/codecs/cs35l56-i2c.c +++ b/sound/soc/codecs/cs35l56-i2c.c @@ -51,15 +51,7 @@ static int cs35l56_i2c_probe(struct i2c_client *client) return dev_err_probe(cs35l56->base.dev, ret, "Failed to allocate register map\n"); } - ret = cs35l56_common_probe(cs35l56); - if (ret != 0) - return ret; - - ret = cs35l56_irq_request(&cs35l56->base, client->irq); - if (ret < 0) - cs35l56_remove(cs35l56); - - return ret; + return cs35l56_common_probe(cs35l56, client->irq); } static void cs35l56_i2c_remove(struct i2c_client *client) diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c index 0a55b93b96f9..4fba59e80c37 100644 --- a/sound/soc/codecs/cs35l56-sdw.c +++ b/sound/soc/codecs/cs35l56-sdw.c @@ -231,7 +231,7 @@ static void cs35l56_sdw_init(struct sdw_slave *peripheral) * a soft reset. */ if (cs35l56->base.init_done) - cs35l56_unmask_soundwire_interrupts(cs35l56->sdw_peripheral); + cs35l56_unmask_soundwire_interrupts(cs35l56); out: pm_runtime_put_autosuspend(cs35l56->base.dev); @@ -240,47 +240,17 @@ out: static int cs35l56_sdw_interrupt(struct sdw_slave *peripheral, struct sdw_slave_intr_status *status) { - struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev); - - /* SoundWire core holds our pm_runtime when calling this function. */ - - dev_dbg(cs35l56->base.dev, "int control_port=%#x\n", status->control_port); - - if ((status->control_port & SDW_SCP_INT1_IMPL_DEF) == 0) - return 0; - /* - * Prevent bus manager suspending and possibly issuing a - * bus-reset before the queued work has run. + * The IRQ itself was handled through the regmap_irq handler, this is + * just clearing up the additional Cirrus SoundWire registers that are + * not covered by the SoundWire framework or the IRQ handler itself. */ - pm_runtime_get_noresume(cs35l56->base.dev); - - /* - * Mask and clear until it has been handled. - * None of the interrupts are time-critical so use the - * power-efficient queue. - */ - cs35l56_mask_soundwire_interrupts(peripheral); - queue_work(system_power_efficient_wq, &cs35l56->sdw_irq_work); + sdw_read_no_pm(peripheral, CS35L56_SDW_GEN_INT_STAT_1); + sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_STAT_1, 0xFF); return 0; } -static void cs35l56_sdw_irq_work(struct work_struct *work) -{ - struct cs35l56_private *cs35l56 = container_of(work, - struct cs35l56_private, - sdw_irq_work); - - cs35l56_irq(-1, &cs35l56->base); - - /* unmask interrupts */ - if (!cs35l56->sdw_irq_no_unmask) - cs35l56_unmask_soundwire_interrupts(cs35l56->sdw_peripheral); - - pm_runtime_put_autosuspend(cs35l56->base.dev); -} - static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral) { struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev); @@ -302,6 +272,7 @@ static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral) prop->source_ports = BIT(CS35L56_SDW1_CAPTURE_PORT); prop->sink_ports = BIT(CS35L56_SDW1_PLAYBACK_PORT); prop->paging_support = true; + prop->use_domain_irq = true; prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY | SDW_SCP_INT1_IMPL_DEF; @@ -406,7 +377,7 @@ static int __maybe_unused cs35l56_sdw_runtime_resume(struct device *dev) if (ret) return ret; - cs35l56_unmask_soundwire_interrupts(cs35l56->sdw_peripheral); + cs35l56_unmask_soundwire_interrupts(cs35l56); return 0; } @@ -418,21 +389,12 @@ static int __maybe_unused cs35l56_sdw_system_suspend(struct device *dev) if (!cs35l56->base.init_done) return 0; - cs35l56_disable_sdw_interrupts(cs35l56); + /* runtime_resume unmasks the interrupt */ + cs35l56_mask_soundwire_interrupts(cs35l56); return cs35l56_system_suspend(dev); } -static int __maybe_unused cs35l56_sdw_system_resume(struct device *dev) -{ - struct cs35l56_private *cs35l56 = dev_get_drvdata(dev); - - cs35l56->sdw_irq_no_unmask = false; - /* runtime_resume re-enables the interrupt */ - - return cs35l56_system_resume(dev); -} - static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_device_id *id) { struct device *dev = &peripheral->dev; @@ -447,7 +409,6 @@ static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_devi cs35l56->base.dev = dev; cs35l56->sdw_peripheral = peripheral; cs35l56->sdw_link_num = peripheral->bus->link_id; - INIT_WORK(&cs35l56->sdw_irq_work, cs35l56_sdw_irq_work); dev_set_drvdata(dev, cs35l56); @@ -457,6 +418,7 @@ static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_devi regmap_config = &cs35l56_regmap_sdw; break; case 0x3563: + case 0x3562: regmap_config = &cs35l63_regmap_sdw; break; default: @@ -483,25 +445,21 @@ static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_devi /* Start in cache-only until device is enumerated */ regcache_cache_only(cs35l56->base.regmap, true); - ret = cs35l56_common_probe(cs35l56); - if (ret != 0) - return ret; - - return 0; + return cs35l56_common_probe(cs35l56, peripheral->irq); } static void cs35l56_sdw_remove(struct sdw_slave *peripheral) { struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev); - cs35l56_disable_sdw_interrupts(cs35l56); + cs35l56_mask_soundwire_interrupts(cs35l56); cs35l56_remove(cs35l56); } static const struct dev_pm_ops cs35l56_sdw_pm = { SET_RUNTIME_PM_OPS(cs35l56_sdw_runtime_suspend, cs35l56_sdw_runtime_resume, NULL) - SYSTEM_SLEEP_PM_OPS(cs35l56_sdw_system_suspend, cs35l56_sdw_system_resume) + SYSTEM_SLEEP_PM_OPS(cs35l56_sdw_system_suspend, cs35l56_system_resume) LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend_late, cs35l56_system_resume_early) /* NOIRQ stage not needed, SoundWire doesn't use a hard IRQ */ }; @@ -509,6 +467,7 @@ static const struct dev_pm_ops cs35l56_sdw_pm = { static const struct sdw_device_id cs35l56_sdw_id[] = { SDW_SLAVE_ENTRY(0x01FA, 0x3556, 0x3556), SDW_SLAVE_ENTRY(0x01FA, 0x3557, 0x3557), + SDW_SLAVE_ENTRY(0x01FA, 0x3562, 0x3562), SDW_SLAVE_ENTRY(0x01FA, 0x3563, 0x3563), {}, }; diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index f14e2eaaa4ee..7b3e37d462d6 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -96,6 +96,7 @@ int cs35l56_set_patch(struct cs35l56_base *cs35l56_base) ARRAY_SIZE(cs35l56_patch_fw)); break; case 0x63: + case 0x62: ret = regmap_register_patch(cs35l56_base->regmap, cs35l63_patch_fw, ARRAY_SIZE(cs35l63_patch_fw)); break; @@ -389,6 +390,7 @@ static void cs35l56_set_fw_reg_table(struct cs35l56_base *cs35l56_base) } break; case 0x63: + case 0x62: cs35l56_base->fw_reg = &cs35l63_fw_reg; break; } @@ -595,6 +597,7 @@ void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire) } break; case 0x63: + case 0x62: regmap_multi_reg_write_bypassed(cs35l56_base->regmap, cs35l63_system_reset_seq, ARRAY_SIZE(cs35l63_system_reset_seq)); @@ -613,26 +616,7 @@ void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire) } EXPORT_SYMBOL_NS_GPL(cs35l56_system_reset, "SND_SOC_CS35L56_SHARED"); -int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq) -{ - int ret; - - if (irq < 1) - return 0; - - ret = devm_request_threaded_irq(cs35l56_base->dev, irq, NULL, cs35l56_irq, - IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW, - "cs35l56", cs35l56_base); - if (!ret) - cs35l56_base->irq = irq; - else - dev_err(cs35l56_base->dev, "Failed to get IRQ: %d\n", ret); - - return ret; -} -EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, "SND_SOC_CS35L56_SHARED"); - -irqreturn_t cs35l56_irq(int irq, void *data) +static irqreturn_t cs35l56_irq(int irq, void *data) { struct cs35l56_base *cs35l56_base = data; unsigned int status1 = 0, status8 = 0, status20 = 0; @@ -640,23 +624,22 @@ irqreturn_t cs35l56_irq(int irq, void *data) unsigned int val; int rv; - irqreturn_t ret = IRQ_NONE; - if (!cs35l56_base->init_done) return IRQ_NONE; - mutex_lock(&cs35l56_base->irq_lock); + guard(mutex)(&cs35l56_base->irq_lock); - rv = pm_runtime_resume_and_get(cs35l56_base->dev); + PM_RUNTIME_ACQUIRE_IF_ENABLED(cs35l56_base->dev, pm); + rv = PM_RUNTIME_ACQUIRE_ERR(&pm); if (rv < 0) { dev_err(cs35l56_base->dev, "irq: failed to get pm_runtime: %d\n", rv); - goto err_unlock; + return IRQ_NONE; } regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_STATUS, &val); if ((val & CS35L56_IRQ1_STS_MASK) == 0) { dev_dbg(cs35l56_base->dev, "Spurious IRQ: no pending interrupt\n"); - goto err; + return IRQ_NONE; } /* Ack interrupts */ @@ -680,7 +663,7 @@ irqreturn_t cs35l56_irq(int irq, void *data) /* Check to see if unmasked bits are active */ if (!status1 && !status8 && !status20) - goto err; + return IRQ_NONE; if (status1 & CS35L56_AMP_SHORT_ERR_EINT1_MASK) dev_crit(cs35l56_base->dev, "Amp short error\n"); @@ -688,16 +671,27 @@ irqreturn_t cs35l56_irq(int irq, void *data) if (status8 & CS35L56_TEMP_ERR_EINT1_MASK) dev_crit(cs35l56_base->dev, "Overtemp error\n"); - ret = IRQ_HANDLED; + return IRQ_HANDLED; +} -err: - pm_runtime_put(cs35l56_base->dev); -err_unlock: - mutex_unlock(&cs35l56_base->irq_lock); +int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq) +{ + int ret; + + if (irq < 1) + return 0; + + ret = devm_request_threaded_irq(cs35l56_base->dev, irq, NULL, cs35l56_irq, + IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW, + "cs35l56", cs35l56_base); + if (!ret) + cs35l56_base->irq = irq; + else + dev_err(cs35l56_base->dev, "Failed to get IRQ: %d\n", ret); return ret; } -EXPORT_SYMBOL_NS_GPL(cs35l56_irq, "SND_SOC_CS35L56_SHARED"); +EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, "SND_SOC_CS35L56_SHARED"); int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base) { @@ -816,14 +810,10 @@ int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_sou if (!cs35l56_base->init_done) return 0; - if (!cs35l56_base->can_hibernate) - goto out_sync; - - /* Must be done before releasing cache-only */ - if (!is_soundwire) + /* Hibernate wake must be done before releasing cache-only */ + if (cs35l56_base->can_hibernate && !is_soundwire) cs35l56_issue_wake_event(cs35l56_base); -out_sync: ret = cs35l56_wait_for_firmware_boot(cs35l56_base); if (ret) { dev_err(cs35l56_base->dev, "Hibernate wake failed: %d\n", ret); @@ -1470,6 +1460,7 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base) cs35l56_base->calibration_controls = &cs35l56_calibration_controls; break; case 0x35A630: + case 0x35A620: cs35l56_base->calibration_controls = &cs35l63_calibration_controls; devid = devid >> 4; break; diff --git a/sound/soc/codecs/cs35l56-spi.c b/sound/soc/codecs/cs35l56-spi.c index b1eb924a5b6c..21b18da9e73d 100644 --- a/sound/soc/codecs/cs35l56-spi.c +++ b/sound/soc/codecs/cs35l56-spi.c @@ -40,15 +40,7 @@ static int cs35l56_spi_probe(struct spi_device *spi) if (ret) return ret; - ret = cs35l56_common_probe(cs35l56); - if (ret != 0) - return ret; - - ret = cs35l56_irq_request(&cs35l56->base, spi->irq); - if (ret < 0) - cs35l56_remove(cs35l56); - - return ret; + return cs35l56_common_probe(cs35l56, spi->irq); } static void cs35l56_spi_remove(struct spi_device *spi) diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 063ef7a70de0..b9118ad8fab5 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -37,48 +37,49 @@ #include "wm_adsp.h" #include "cs35l56.h" -void cs35l56_mask_soundwire_interrupts(struct sdw_slave *peripheral) +void cs35l56_mask_soundwire_interrupts(struct cs35l56_private *cs35l56) { /* + * Mask unconditionally. + * * The read of GEN_INT_STAT_1 is required as per the SoundWire spec * for interrupt status bits to clear. * GEN_INT_MASK_1 masks the _inputs_ to GEN_INT_STAT1. */ - sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_MASK_1, 0); - sdw_read_no_pm(peripheral, CS35L56_SDW_GEN_INT_STAT_1); - sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_STAT_1, 0xFF); + sdw_write_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_MASK_1, 0); + sdw_read_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_STAT_1); + sdw_write_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_STAT_1, 0xFF); } EXPORT_SYMBOL_NS_GPL(cs35l56_mask_soundwire_interrupts, "SND_SOC_CS35L56_CORE"); -void cs35l56_unmask_soundwire_interrupts(struct sdw_slave *peripheral) +void cs35l56_unmask_soundwire_interrupts(struct cs35l56_private *cs35l56) { - sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_MASK_1, CS35L56_SDW_INT_MASK_CODEC_IRQ); + if (!cs35l56->base.irq) + return; + + sdw_write_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_MASK_1, + CS35L56_SDW_INT_MASK_CODEC_IRQ); } EXPORT_SYMBOL_NS_GPL(cs35l56_unmask_soundwire_interrupts, "SND_SOC_CS35L56_CORE"); -void cs35l56_disable_sdw_interrupts(struct cs35l56_private *cs35l56) +static void cs35l56_disable_sdw_interrupts(struct cs35l56_private *cs35l56) { if (!cs35l56->sdw_peripheral) return; - cs35l56->sdw_irq_no_unmask = true; - flush_work(&cs35l56->sdw_irq_work); - - /* Mask interrupts and flush in case sdw_irq_work was queued again */ - cs35l56_mask_soundwire_interrupts(cs35l56->sdw_peripheral); - flush_work(&cs35l56->sdw_irq_work); + cs35l56_mask_soundwire_interrupts(cs35l56); + if (cs35l56->base.irq) + disable_irq(cs35l56->base.irq); } -EXPORT_SYMBOL_NS_GPL(cs35l56_disable_sdw_interrupts, "SND_SOC_CS35L56_CORE"); -void cs35l56_enable_sdw_interrupts(struct cs35l56_private *cs35l56) +static void cs35l56_enable_sdw_interrupts(struct cs35l56_private *cs35l56) { - if (!cs35l56->sdw_peripheral) + if (!cs35l56->sdw_peripheral || !cs35l56->base.irq) return; - cs35l56->sdw_irq_no_unmask = false; - cs35l56_unmask_soundwire_interrupts(cs35l56->sdw_peripheral); + enable_irq(cs35l56->base.irq); + cs35l56_unmask_soundwire_interrupts(cs35l56); } -EXPORT_SYMBOL_NS_GPL(cs35l56_enable_sdw_interrupts, "SND_SOC_CS35L56_CORE"); static int cs35l56_dsp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); @@ -828,11 +829,7 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56, bool firmware_missing { int ret; - /* - * Disable SoundWire interrupts to prevent race with IRQ work. - * Setting sdw_irq_no_unmask prevents the handler re-enabling - * the SoundWire interrupt. - */ + /* Disable SoundWire interrupts to prevent race with IRQ handler thread */ cs35l56_disable_sdw_interrupts(cs35l56); ret = cs35l56_firmware_shutdown(&cs35l56->base); @@ -1402,6 +1399,7 @@ static int _cs35l56_component_probe(struct snd_soc_component *component) ARRAY_SIZE(cs35l56_controls)); break; case 0x63: + case 0x62: ret = snd_soc_add_component_controls(component, cs35l63_controls, ARRAY_SIZE(cs35l63_controls)); break; @@ -1941,7 +1939,7 @@ static int cs35l56_try_get_broken_sdca_spkid_gpio(struct cs35l56_private *cs35l5 return ret; } -int cs35l56_common_probe(struct cs35l56_private *cs35l56) +int cs35l56_common_probe(struct cs35l56_private *cs35l56, int irq) { int ret; @@ -2018,16 +2016,24 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56) goto err_remove_wm_adsp; } + ret = cs35l56_irq_request(&cs35l56->base, irq); + if (ret) + goto err_remove_wm_adsp; + ret = snd_soc_register_component(cs35l56->base.dev, &soc_component_dev_cs35l56, cs35l56_dai, ARRAY_SIZE(cs35l56_dai)); if (ret < 0) { dev_err_probe(cs35l56->base.dev, ret, "Register codec failed\n"); - goto err_remove_wm_adsp; + goto err_free_irq; } return 0; +err_free_irq: + if (cs35l56->base.irq) + devm_free_irq(cs35l56->base.dev, cs35l56->base.irq, &cs35l56->base); + err_remove_wm_adsp: wm_adsp2_remove(&cs35l56->dsp); diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h index 9acd2e7e17c9..35c02ae17de3 100644 --- a/sound/soc/codecs/cs35l56.h +++ b/sound/soc/codecs/cs35l56.h @@ -39,8 +39,6 @@ struct cs35l56_private { struct sdw_slave *sdw_peripheral; struct regmap *sdw_bus_regmap; const char *fallback_fw_suffix; - struct work_struct sdw_irq_work; - bool sdw_irq_no_unmask; bool soft_resetting; bool sdw_attached; struct completion init_completion; @@ -65,10 +63,8 @@ static inline struct cs35l56_private *cs35l56_private_from_base(struct cs35l56_b extern const struct dev_pm_ops cs35l56_pm_ops_i2c_spi; -void cs35l56_mask_soundwire_interrupts(struct sdw_slave *peripheral); -void cs35l56_unmask_soundwire_interrupts(struct sdw_slave *peripheral); -void cs35l56_disable_sdw_interrupts(struct cs35l56_private *cs35l56); -void cs35l56_enable_sdw_interrupts(struct cs35l56_private *cs35l56); +void cs35l56_mask_soundwire_interrupts(struct cs35l56_private *cs35l56); +void cs35l56_unmask_soundwire_interrupts(struct cs35l56_private *cs35l56); int cs35l56_system_suspend(struct device *dev); int cs35l56_system_suspend_late(struct device *dev); @@ -76,9 +72,8 @@ int cs35l56_system_suspend_no_irq(struct device *dev); int cs35l56_system_resume_no_irq(struct device *dev); int cs35l56_system_resume_early(struct device *dev); int cs35l56_system_resume(struct device *dev); -irqreturn_t cs35l56_irq(int irq, void *data); int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq); -int cs35l56_common_probe(struct cs35l56_private *cs35l56); +int cs35l56_common_probe(struct cs35l56_private *cs35l56, int irq); int cs35l56_init(struct cs35l56_private *cs35l56); void cs35l56_remove(struct cs35l56_private *cs35l56); diff --git a/sound/soc/codecs/cs40l50-codec.c b/sound/soc/codecs/cs40l50-codec.c index aa629ef53db4..676367163067 100644 --- a/sound/soc/codecs/cs40l50-codec.c +++ b/sound/soc/codecs/cs40l50-codec.c @@ -288,8 +288,8 @@ static int cs40l50_codec_driver_probe(struct platform_device *pdev) } static const struct platform_device_id cs40l50_id[] = { - { "cs40l50-codec", }, - {} + { .name = "cs40l50-codec" }, + { } }; MODULE_DEVICE_TABLE(platform, cs40l50_id); diff --git a/sound/soc/codecs/cs42l42-sdw.c b/sound/soc/codecs/cs42l42-sdw.c index ad1256910a18..b61ca74dcf0b 100644 --- a/sound/soc/codecs/cs42l42-sdw.c +++ b/sound/soc/codecs/cs42l42-sdw.c @@ -481,10 +481,20 @@ static int cs42l42_sdw_runtime_resume(struct device *dev) regcache_cache_only(cs42l42->regmap, false); /* Sync LATCH_TO_VP first so the VP domain registers sync correctly */ - regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_DET_CTL1); - regcache_sync(cs42l42->regmap); + ret = regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_DET_CTL1); + if (ret) + goto err_sync; + + ret = regcache_sync(cs42l42->regmap); + if (ret) + goto err_sync; return 0; + +err_sync: + regcache_cache_only(cs42l42->regmap, true); + regcache_mark_dirty(cs42l42->regmap); + return ret; } static int cs42l42_sdw_resume(struct device *dev) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 2652a639a79a..fadf68860601 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -9,6 +9,7 @@ * Author: Michael White <michael.white@cirrus.com> */ +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/types.h> @@ -565,7 +566,7 @@ static int cs42l42_set_jack(struct snd_soc_component *component, struct snd_soc_ struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); /* Prevent race with interrupt handler */ - mutex_lock(&cs42l42->irq_lock); + guard(mutex)(&cs42l42->irq_lock); cs42l42->jack = jk; if (jk) { @@ -581,7 +582,6 @@ static int cs42l42_set_jack(struct snd_soc_component *component, struct snd_soc_ break; } } - mutex_unlock(&cs42l42->irq_lock); return 0; } @@ -1668,13 +1668,10 @@ irqreturn_t cs42l42_irq_thread(int irq, void *data) unsigned int current_button_status; unsigned int i; - pm_runtime_get_sync(cs42l42->dev); - mutex_lock(&cs42l42->irq_lock); - if (cs42l42->suspended || !cs42l42->init_done) { - mutex_unlock(&cs42l42->irq_lock); - pm_runtime_put_autosuspend(cs42l42->dev); + guard(pm_runtime_active_auto)(cs42l42->dev); + guard(mutex)(&cs42l42->irq_lock); + if (cs42l42->suspended || !cs42l42->init_done) return IRQ_NONE; - } /* Read sticky registers to clear interurpt */ for (i = 0; i < ARRAY_SIZE(stickies); i++) { @@ -1774,9 +1771,6 @@ irqreturn_t cs42l42_irq_thread(int irq, void *data) } } - mutex_unlock(&cs42l42->irq_lock); - pm_runtime_put_autosuspend(cs42l42->dev); - return IRQ_HANDLED; } EXPORT_SYMBOL_NS_GPL(cs42l42_irq_thread, "SND_SOC_CS42L42_CORE"); @@ -2163,22 +2157,22 @@ int cs42l42_suspend(struct device *dev) * future interrupts. This ensures a safe disable if the interrupt * is shared. */ - mutex_lock(&cs42l42->irq_lock); - cs42l42->suspended = true; + scoped_guard(mutex, &cs42l42->irq_lock) { + cs42l42->suspended = true; - /* Save register values that will be overwritten by shutdown sequence */ - for (i = 0; i < ARRAY_SIZE(cs42l42_shutdown_seq); ++i) { - regmap_read(cs42l42->regmap, cs42l42_shutdown_seq[i].reg, ®); - save_regs[i] = (u8)reg; - } + /* Save register values that will be overwritten by shutdown sequence */ + for (i = 0; i < ARRAY_SIZE(cs42l42_shutdown_seq); ++i) { + regmap_read(cs42l42->regmap, cs42l42_shutdown_seq[i].reg, ®); + save_regs[i] = (u8)reg; + } - /* Shutdown codec */ - regmap_multi_reg_write(cs42l42->regmap, - cs42l42_shutdown_seq, - ARRAY_SIZE(cs42l42_shutdown_seq)); + /* Shutdown codec */ + regmap_multi_reg_write(cs42l42->regmap, + cs42l42_shutdown_seq, + ARRAY_SIZE(cs42l42_shutdown_seq)); - /* All interrupt sources are now disabled */ - mutex_unlock(&cs42l42->irq_lock); + /* All interrupt sources are now disabled */ + } /* Wait for power-down complete */ msleep(CS42L42_PDN_DONE_TIME_MS); @@ -2250,13 +2244,13 @@ void cs42l42_resume_restore(struct device *dev) regcache_cache_only(cs42l42->regmap, false); regcache_mark_dirty(cs42l42->regmap); - mutex_lock(&cs42l42->irq_lock); - /* Sync LATCH_TO_VP first so the VP domain registers sync correctly */ - regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_DET_CTL1); - regcache_sync(cs42l42->regmap); + scoped_guard(mutex, &cs42l42->irq_lock) { + /* Sync LATCH_TO_VP first so the VP domain registers sync correctly */ + regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_DET_CTL1); + regcache_sync(cs42l42->regmap); - cs42l42->suspended = false; - mutex_unlock(&cs42l42->irq_lock); + cs42l42->suspended = false; + } dev_dbg(dev, "System resumed\n"); } diff --git a/sound/soc/codecs/cs42l43-jack.c b/sound/soc/codecs/cs42l43-jack.c index dbf45cabfffe..a2555dd9229e 100644 --- a/sound/soc/codecs/cs42l43-jack.c +++ b/sound/soc/codecs/cs42l43-jack.c @@ -6,6 +6,7 @@ // Cirrus Logic International Semiconductor Ltd. #include <linux/build_bug.h> +#include <linux/cleanup.h> #include <linux/completion.h> #include <linux/delay.h> #include <linux/errno.h> @@ -67,6 +68,21 @@ static int cs42l43_find_index(struct cs42l43_codec *priv, const char * const pro return -EINVAL; } +static void cs42l43_apply_accdet_config(struct cs42l43_codec *priv, + unsigned int autocontrol, + unsigned int pdncntl) +{ + struct cs42l43 *cs42l43 = priv->core; + + regmap_update_bits(cs42l43->regmap, CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL, + CS42L43_JACKDET_MODE_MASK | CS42L43_S0_AUTO_ADCMUTE_DISABLE_MASK | + CS42L43_HSBIAS_SENSE_TRIP_MASK, autocontrol); + regmap_update_bits(cs42l43->regmap, CS42L43_PDNCNTL, + CS42L43_RING_SENSE_EN_MASK, pdncntl); + + dev_dbg(priv->dev, "Successfully configured accessory detect\n"); +} + int cs42l43_set_jack(struct snd_soc_component *component, struct snd_soc_jack *jack, void *d) { @@ -80,31 +96,34 @@ int cs42l43_set_jack(struct snd_soc_component *component, dev_dbg(priv->dev, "Configure accessory detect\n"); - ret = pm_runtime_resume_and_get(priv->dev); + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(priv->dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); if (ret) { dev_err(priv->dev, "Failed to resume for jack config: %d\n", ret); return ret; } - mutex_lock(&priv->jack_lock); + guard(mutex)(&priv->jack_lock); priv->jack_hp = jack; - if (!jack) - goto done; + if (!jack) { + cs42l43_apply_accdet_config(priv, autocontrol, pdncntl); + return 0; + } ret = device_property_count_u32(cs42l43->dev, "cirrus,buttons-ohms"); if (ret != -EINVAL) { if (ret < 0) { dev_err(priv->dev, "Property cirrus,buttons-ohms malformed: %d\n", ret); - goto error; + return ret; } if (ret > CS42L43_N_BUTTONS) { ret = -EINVAL; dev_err(priv->dev, "Property cirrus,buttons-ohms too many entries\n"); - goto error; + return ret; } ret = device_property_read_u32_array(cs42l43->dev, "cirrus,buttons-ohms", @@ -112,7 +131,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, if (ret < 0) { dev_err(priv->dev, "Property cirrus,button-ohms malformed: %d\n", ret); - goto error; + return ret; } } else { priv->buttons[0] = 70; @@ -124,7 +143,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, ret = cs42l43_find_index(priv, "cirrus,detect-us", 50000, &priv->detect_us, cs42l43_accdet_us, ARRAY_SIZE(cs42l43_accdet_us)); if (ret < 0) - goto error; + return ret; hs2 |= ret << CS42L43_AUTO_HSDET_TIME_SHIFT; @@ -134,7 +153,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, &priv->bias_ramp_ms, cs42l43_accdet_ramp_ms, ARRAY_SIZE(cs42l43_accdet_ramp_ms)); if (ret < 0) - goto error; + return ret; hs2 |= ret << CS42L43_HSBIAS_RAMP_SHIFT; @@ -142,7 +161,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, &priv->bias_sense_ua, cs42l43_accdet_bias_sense, ARRAY_SIZE(cs42l43_accdet_bias_sense)); if (ret < 0) - goto error; + return ret; if (priv->bias_sense_ua) autocontrol |= ret << CS42L43_HSBIAS_SENSE_TRIP_SHIFT; @@ -154,7 +173,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, &priv->tip_debounce_ms); if (ret < 0 && ret != -EINVAL) { dev_err(priv->dev, "Property cirrus,tip-debounce-ms malformed: %d\n", ret); - goto error; + return ret; } /* This tip sense invert is set normally, as TIPSENSE_INV already inverted */ @@ -170,7 +189,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, &priv->tip_fall_db_ms, cs42l43_accdet_db_ms, ARRAY_SIZE(cs42l43_accdet_db_ms)); if (ret < 0) - goto error; + return ret; tip_deb |= ret << CS42L43_TIPSENSE_FALLING_DB_TIME_SHIFT; @@ -178,7 +197,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, &priv->tip_rise_db_ms, cs42l43_accdet_db_ms, ARRAY_SIZE(cs42l43_accdet_db_ms)); if (ret < 0) - goto error; + return ret; tip_deb |= ret << CS42L43_TIPSENSE_RISING_DB_TIME_SHIFT; @@ -199,7 +218,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, NULL, cs42l43_accdet_db_ms, ARRAY_SIZE(cs42l43_accdet_db_ms)); if (ret < 0) - goto error; + return ret; ring_deb |= ret << CS42L43_RINGSENSE_FALLING_DB_TIME_SHIFT; @@ -207,7 +226,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, NULL, cs42l43_accdet_db_ms, ARRAY_SIZE(cs42l43_accdet_db_ms)); if (ret < 0) - goto error; + return ret; ring_deb |= ret << CS42L43_RINGSENSE_RISING_DB_TIME_SHIFT; pdncntl |= CS42L43_RING_SENSE_EN_MASK; @@ -228,23 +247,9 @@ int cs42l43_set_jack(struct snd_soc_component *component, CS42L43_HSBIAS_RAMP_MASK | CS42L43_HSDET_MODE_MASK | CS42L43_AUTO_HSDET_TIME_MASK, hs2); -done: - ret = 0; - - regmap_update_bits(cs42l43->regmap, CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL, - CS42L43_JACKDET_MODE_MASK | CS42L43_S0_AUTO_ADCMUTE_DISABLE_MASK | - CS42L43_HSBIAS_SENSE_TRIP_MASK, autocontrol); - regmap_update_bits(cs42l43->regmap, CS42L43_PDNCNTL, - CS42L43_RING_SENSE_EN_MASK, pdncntl); - - dev_dbg(priv->dev, "Successfully configured accessory detect\n"); - -error: - mutex_unlock(&priv->jack_lock); - - pm_runtime_put_autosuspend(priv->dev); + cs42l43_apply_accdet_config(priv, autocontrol, pdncntl); - return ret; + return 0; } static void cs42l43_start_hs_bias(struct cs42l43_codec *priv, bool type_detect) @@ -370,22 +375,22 @@ irqreturn_t cs42l43_button_press(int irq, void *data) { struct cs42l43_codec *priv = data; struct cs42l43 *cs42l43 = priv->core; - irqreturn_t iret = IRQ_NONE; unsigned int buttons = 0; unsigned int val = 0; int i, ret; - ret = pm_runtime_resume_and_get(priv->dev); + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(priv->dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); if (ret) { dev_err(priv->dev, "Failed to resume for button press: %d\n", ret); - return iret; + return IRQ_NONE; } - mutex_lock(&priv->jack_lock); + guard(mutex)(&priv->jack_lock); if (!priv->button_detect_running) { dev_dbg(priv->dev, "Spurious button press IRQ\n"); - goto error; + return IRQ_NONE; } // Wait for 2 full cycles of comb filter to ensure good reading @@ -396,12 +401,12 @@ irqreturn_t cs42l43_button_press(int irq, void *data) /* Bail if jack removed, the button is irrelevant and likely invalid */ if (!cs42l43_jack_present(priv)) { dev_dbg(priv->dev, "Button ignored due to removal\n"); - goto error; + return IRQ_NONE; } if (val & CS42L43_HSBIAS_CLAMP_STS_MASK) { dev_dbg(priv->dev, "Button ignored due to bias sense\n"); - goto error; + return IRQ_NONE; } val = (val & CS42L43_HSDET_DC_STS_MASK) >> CS42L43_HSDET_DC_STS_SHIFT; @@ -424,45 +429,32 @@ irqreturn_t cs42l43_button_press(int irq, void *data) snd_soc_jack_report(priv->jack_hp, buttons, CS42L43_JACK_BUTTONS); - iret = IRQ_HANDLED; - -error: - mutex_unlock(&priv->jack_lock); - - pm_runtime_put_autosuspend(priv->dev); - - return iret; + return IRQ_HANDLED; } irqreturn_t cs42l43_button_release(int irq, void *data) { struct cs42l43_codec *priv = data; - irqreturn_t iret = IRQ_NONE; int ret; - ret = pm_runtime_resume_and_get(priv->dev); + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(priv->dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); if (ret) { dev_err(priv->dev, "Failed to resume for button release: %d\n", ret); - return iret; + return IRQ_NONE; } - mutex_lock(&priv->jack_lock); - - if (priv->button_detect_running) { - dev_dbg(priv->dev, "Button release IRQ\n"); - - snd_soc_jack_report(priv->jack_hp, 0, CS42L43_JACK_BUTTONS); + guard(mutex)(&priv->jack_lock); - iret = IRQ_HANDLED; - } else { + if (!priv->button_detect_running) { dev_dbg(priv->dev, "Spurious button release IRQ\n"); + return IRQ_NONE; } - mutex_unlock(&priv->jack_lock); + dev_dbg(priv->dev, "Button release IRQ\n"); + snd_soc_jack_report(priv->jack_hp, 0, CS42L43_JACK_BUTTONS); - pm_runtime_put_autosuspend(priv->dev); - - return iret; + return IRQ_HANDLED; } void cs42l43_bias_sense_timeout(struct work_struct *work) @@ -472,13 +464,14 @@ void cs42l43_bias_sense_timeout(struct work_struct *work) struct cs42l43 *cs42l43 = priv->core; int ret; - ret = pm_runtime_resume_and_get(priv->dev); + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(priv->dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); if (ret) { dev_err(priv->dev, "Failed to resume for bias sense: %d\n", ret); return; } - mutex_lock(&priv->jack_lock); + guard(mutex)(&priv->jack_lock); if (cs42l43_jack_present(priv) && priv->button_detect_running) { dev_dbg(priv->dev, "Bias sense timeout out, restore bias\n"); @@ -491,10 +484,6 @@ void cs42l43_bias_sense_timeout(struct work_struct *work) CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK, CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK); } - - mutex_unlock(&priv->jack_lock); - - pm_runtime_put_autosuspend(priv->dev); } static const struct reg_sequence cs42l43_3pole_patch[] = { @@ -896,9 +885,8 @@ int cs42l43_jack_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); - mutex_lock(&priv->jack_lock); + guard(mutex)(&priv->jack_lock); ucontrol->value.integer.value[0] = priv->jack_override; - mutex_unlock(&priv->jack_lock); return 0; } @@ -914,17 +902,13 @@ int cs42l43_jack_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u if (override >= e->items) return -EINVAL; - mutex_lock(&priv->jack_lock); + guard(mutex)(&priv->jack_lock); - if (!cs42l43_jack_present(priv)) { - mutex_unlock(&priv->jack_lock); + if (!cs42l43_jack_present(priv)) return -EBUSY; - } - if (override == priv->jack_override) { - mutex_unlock(&priv->jack_lock); + if (override == priv->jack_override) return 0; - } priv->jack_override = override; @@ -984,7 +968,5 @@ int cs42l43_jack_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u cs42l43_jack_override_modes[override].report); } - mutex_unlock(&priv->jack_lock); - return 1; } diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c index 1d133577702e..1b817e1a6ea5 100644 --- a/sound/soc/codecs/cs42l43.c +++ b/sound/soc/codecs/cs42l43.c @@ -8,6 +8,7 @@ #include <linux/bitops.h> #include <linux/bits.h> #include <linux/build_bug.h> +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/device.h> #include <linux/err.h> @@ -1207,14 +1208,12 @@ static void cs42l43_spk_vu_sync(struct cs42l43_codec *priv) { struct cs42l43 *cs42l43 = priv->core; - mutex_lock(&priv->spk_vu_lock); + guard(mutex)(&priv->spk_vu_lock); regmap_update_bits(cs42l43->regmap, CS42L43_INTP_VOLUME_CTRL1, CS42L43_AMP1_2_VU_MASK, CS42L43_AMP1_2_VU_MASK); regmap_update_bits(cs42l43->regmap, CS42L43_INTP_VOLUME_CTRL1, CS42L43_AMP1_2_VU_MASK, 0); - - mutex_unlock(&priv->spk_vu_lock); } static int cs42l43_shutter_get(struct cs42l43_codec *priv, unsigned int shift) @@ -1601,7 +1600,7 @@ static int cs42l43_pll_ev(struct snd_soc_dapm_widget *w, struct cs42l43 *cs42l43 = priv->core; int ret; - mutex_lock(&cs42l43->pll_lock); + guard(mutex)(&cs42l43->pll_lock); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -1626,8 +1625,6 @@ static int cs42l43_pll_ev(struct snd_soc_dapm_widget *w, break; } - mutex_unlock(&cs42l43->pll_lock); - return ret; } @@ -2565,13 +2562,10 @@ static int cs42l43_set_sysclk(struct snd_soc_component *component, int clk_id, { struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); struct cs42l43 *cs42l43 = priv->core; - int ret; - mutex_lock(&cs42l43->pll_lock); - ret = cs42l43_set_pll(priv, src, freq); - mutex_unlock(&cs42l43->pll_lock); + guard(mutex)(&cs42l43->pll_lock); - return ret; + return cs42l43_set_pll(priv, src, freq); } static int cs42l43_component_probe(struct snd_soc_component *component) @@ -2941,8 +2935,8 @@ static const struct dev_pm_ops cs42l43_codec_pm_ops = { }; static const struct platform_device_id cs42l43_codec_id_table[] = { - { "cs42l43-codec", }, - {} + { .name = "cs42l43-codec" }, + { } }; MODULE_DEVICE_TABLE(platform, cs42l43_codec_id_table); diff --git a/sound/soc/codecs/cs42l84.c b/sound/soc/codecs/cs42l84.c index f2448b4c11fc..a545730b7ed9 100644 --- a/sound/soc/codecs/cs42l84.c +++ b/sound/soc/codecs/cs42l84.c @@ -10,6 +10,7 @@ #include <linux/bitfield.h> #include <linux/bits.h> +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> @@ -280,10 +281,9 @@ static int cs42l84_set_jack(struct snd_soc_component *component, struct snd_soc_ struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component); /* Prevent race with interrupt handler */ - mutex_lock(&cs42l84->irq_lock); + guard(mutex)(&cs42l84->irq_lock); cs42l84->jack = jk; snd_soc_jack_report(jk, cs42l84->hs_type, SND_JACK_HEADSET); - mutex_unlock(&cs42l84->irq_lock); return 0; } @@ -830,7 +830,7 @@ static irqreturn_t cs42l84_irq_thread(int irq, void *data) u8 current_ring_state; int i; - mutex_lock(&cs42l84->irq_lock); + guard(mutex)(&cs42l84->irq_lock); /* Read sticky registers to clear interrupt */ for (i = 0; i < ARRAY_SIZE(stickies); i++) { regmap_read(cs42l84->regmap, irq_params_table[i].status_addr, @@ -901,8 +901,6 @@ static irqreturn_t cs42l84_irq_thread(int irq, void *data) break; } - mutex_unlock(&cs42l84->irq_lock); - return IRQ_HANDLED; } @@ -918,8 +916,6 @@ static irqreturn_t cs42l84_irq_thread(int irq, void *data) } } - mutex_unlock(&cs42l84->irq_lock); - return IRQ_HANDLED; } diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c index e7b06f962790..48d88dad4ceb 100644 --- a/sound/soc/codecs/cs43130.c +++ b/sound/soc/codecs/cs43130.c @@ -6,6 +6,7 @@ * * Authors: Li Xu <li.xu@cirrus.com> */ +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> @@ -818,26 +819,26 @@ static int cs43130_dsd_hw_params(struct snd_pcm_substream *substream, unsigned int required_clk; u8 dsd_speed; - mutex_lock(&cs43130->clk_mutex); - if (!cs43130->clk_req) { - /* no DAI is currently using clk */ - if (!(CS43130_MCLK_22M % params_rate(params))) - required_clk = CS43130_MCLK_22M; - else - required_clk = CS43130_MCLK_24M; + scoped_guard(mutex, &cs43130->clk_mutex) { + if (!cs43130->clk_req) { + /* no DAI is currently using clk */ + if (!(CS43130_MCLK_22M % params_rate(params))) + required_clk = CS43130_MCLK_22M; + else + required_clk = CS43130_MCLK_24M; + + cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk); + if (cs43130->pll_bypass) + cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT); + else + cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL); + } - cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk); - if (cs43130->pll_bypass) - cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT); - else - cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL); + cs43130->clk_req++; + if (cs43130->clk_req == 2) + cs43130_pcm_dsd_mix(true, cs43130->regmap); } - cs43130->clk_req++; - if (cs43130->clk_req == 2) - cs43130_pcm_dsd_mix(true, cs43130->regmap); - mutex_unlock(&cs43130->clk_mutex); - switch (params_rate(params)) { case 176400: dsd_speed = 0; @@ -881,26 +882,26 @@ static int cs43130_hw_params(struct snd_pcm_substream *substream, unsigned int required_clk; u8 dsd_speed; - mutex_lock(&cs43130->clk_mutex); - if (!cs43130->clk_req) { - /* no DAI is currently using clk */ - if (!(CS43130_MCLK_22M % params_rate(params))) - required_clk = CS43130_MCLK_22M; - else - required_clk = CS43130_MCLK_24M; + scoped_guard(mutex, &cs43130->clk_mutex) { + if (!cs43130->clk_req) { + /* no DAI is currently using clk */ + if (!(CS43130_MCLK_22M % params_rate(params))) + required_clk = CS43130_MCLK_22M; + else + required_clk = CS43130_MCLK_24M; + + cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk); + if (cs43130->pll_bypass) + cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT); + else + cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL); + } - cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk); - if (cs43130->pll_bypass) - cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT); - else - cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL); + cs43130->clk_req++; + if (cs43130->clk_req == 2) + cs43130_pcm_dsd_mix(true, cs43130->regmap); } - cs43130->clk_req++; - if (cs43130->clk_req == 2) - cs43130_pcm_dsd_mix(true, cs43130->regmap); - mutex_unlock(&cs43130->clk_mutex); - switch (dai->id) { case CS43130_ASP_DOP_DAI: case CS43130_XSP_DOP_DAI: @@ -988,14 +989,13 @@ static int cs43130_hw_free(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component); - mutex_lock(&cs43130->clk_mutex); + guard(mutex)(&cs43130->clk_mutex); cs43130->clk_req--; if (!cs43130->clk_req) { /* no DAI is currently using clk */ cs43130_change_clksrc(component, CS43130_MCLK_SRC_RCO); cs43130_pcm_dsd_mix(false, cs43130->regmap); } - mutex_unlock(&cs43130->clk_mutex); return 0; } diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 6ac6d306b054..9a7f70175717 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -340,7 +340,13 @@ static int cs4349_runtime_resume(struct device *dev) gpiod_set_value_cansleep(cs4349->reset_gpio, 1); regcache_cache_only(cs4349->regmap, false); - regcache_sync(cs4349->regmap); + ret = regcache_sync(cs4349->regmap); + if (ret) { + regcache_cache_only(cs4349->regmap, true); + regcache_mark_dirty(cs4349->regmap); + gpiod_set_value_cansleep(cs4349->reset_gpio, 0); + return ret; + } return 0; } diff --git a/sound/soc/codecs/cs47l15.c b/sound/soc/codecs/cs47l15.c index da64e0a1db28..2f30dd834709 100644 --- a/sound/soc/codecs/cs47l15.c +++ b/sound/soc/codecs/cs47l15.c @@ -6,6 +6,7 @@ // Cirrus Logic International Semiconductor Ltd. // +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/device.h> @@ -1285,9 +1286,8 @@ static int cs47l15_component_probe(struct snd_soc_component *component) snd_soc_component_init_regmap(component, madera->regmap); - mutex_lock(&madera->dapm_ptr_lock); - madera->dapm = snd_soc_component_to_dapm(component); - mutex_unlock(&madera->dapm_ptr_lock); + scoped_guard(mutex, &madera->dapm_ptr_lock) + madera->dapm = snd_soc_component_to_dapm(component); ret = madera_init_inputs(component); if (ret) @@ -1317,9 +1317,8 @@ static void cs47l15_component_remove(struct snd_soc_component *component) struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component); struct madera *madera = cs47l15->core.madera; - mutex_lock(&madera->dapm_ptr_lock); - madera->dapm = NULL; - mutex_unlock(&madera->dapm_ptr_lock); + scoped_guard(mutex, &madera->dapm_ptr_lock) + madera->dapm = NULL; wm_adsp2_component_remove(&cs47l15->core.adsp[0], component); } diff --git a/sound/soc/codecs/cs47l35.c b/sound/soc/codecs/cs47l35.c index a8fe5a99a8bb..e77ac7bc8466 100644 --- a/sound/soc/codecs/cs47l35.c +++ b/sound/soc/codecs/cs47l35.c @@ -6,6 +6,7 @@ // Cirrus Logic International Semiconductor Ltd. // +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/init.h> @@ -1566,9 +1567,8 @@ static int cs47l35_component_probe(struct snd_soc_component *component) snd_soc_component_init_regmap(component, madera->regmap); - mutex_lock(&madera->dapm_ptr_lock); - madera->dapm = snd_soc_component_to_dapm(component); - mutex_unlock(&madera->dapm_ptr_lock); + scoped_guard(mutex, &madera->dapm_ptr_lock) + madera->dapm = snd_soc_component_to_dapm(component); ret = madera_init_inputs(component); if (ret) @@ -1600,9 +1600,8 @@ static void cs47l35_component_remove(struct snd_soc_component *component) struct madera *madera = cs47l35->core.madera; int i; - mutex_lock(&madera->dapm_ptr_lock); - madera->dapm = NULL; - mutex_unlock(&madera->dapm_ptr_lock); + scoped_guard(mutex, &madera->dapm_ptr_lock) + madera->dapm = NULL; for (i = 0; i < CS47L35_NUM_ADSP; i++) wm_adsp2_component_remove(&cs47l35->core.adsp[i], component); diff --git a/sound/soc/codecs/cs47l85.c b/sound/soc/codecs/cs47l85.c index 42fafb0b392c..9ee60616c04c 100644 --- a/sound/soc/codecs/cs47l85.c +++ b/sound/soc/codecs/cs47l85.c @@ -6,6 +6,7 @@ // Cirrus Logic International Semiconductor Ltd. // +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/device.h> @@ -2504,9 +2505,8 @@ static int cs47l85_component_probe(struct snd_soc_component *component) snd_soc_component_init_regmap(component, madera->regmap); - mutex_lock(&madera->dapm_ptr_lock); - madera->dapm = snd_soc_component_to_dapm(component); - mutex_unlock(&madera->dapm_ptr_lock); + scoped_guard(mutex, &madera->dapm_ptr_lock) + madera->dapm = snd_soc_component_to_dapm(component); ret = madera_init_inputs(component); if (ret) @@ -2537,9 +2537,8 @@ static void cs47l85_component_remove(struct snd_soc_component *component) struct madera *madera = cs47l85->core.madera; int i; - mutex_lock(&madera->dapm_ptr_lock); - madera->dapm = NULL; - mutex_unlock(&madera->dapm_ptr_lock); + scoped_guard(mutex, &madera->dapm_ptr_lock) + madera->dapm = NULL; for (i = 0; i < CS47L85_NUM_ADSP; i++) wm_adsp2_component_remove(&cs47l85->core.adsp[i], component); diff --git a/sound/soc/codecs/cs47l90.c b/sound/soc/codecs/cs47l90.c index 77e8aabb241a..6ce603bfd500 100644 --- a/sound/soc/codecs/cs47l90.c +++ b/sound/soc/codecs/cs47l90.c @@ -6,6 +6,7 @@ // Cirrus Logic International Semiconductor Ltd. // +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/device.h> @@ -2423,9 +2424,8 @@ static int cs47l90_component_probe(struct snd_soc_component *component) snd_soc_component_init_regmap(component, madera->regmap); - mutex_lock(&madera->dapm_ptr_lock); - madera->dapm = snd_soc_component_to_dapm(component); - mutex_unlock(&madera->dapm_ptr_lock); + scoped_guard(mutex, &madera->dapm_ptr_lock) + madera->dapm = snd_soc_component_to_dapm(component); ret = madera_init_inputs(component); if (ret) @@ -2456,9 +2456,8 @@ static void cs47l90_component_remove(struct snd_soc_component *component) struct madera *madera = cs47l90->core.madera; int i; - mutex_lock(&madera->dapm_ptr_lock); - madera->dapm = NULL; - mutex_unlock(&madera->dapm_ptr_lock); + scoped_guard(mutex, &madera->dapm_ptr_lock) + madera->dapm = NULL; for (i = 0; i < CS47L90_NUM_ADSP; i++) wm_adsp2_component_remove(&cs47l90->core.adsp[i], component); diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c index 868237bd6d91..07bc303d9797 100644 --- a/sound/soc/codecs/cs47l92.c +++ b/sound/soc/codecs/cs47l92.c @@ -6,6 +6,7 @@ // Cirrus Logic International Semiconductor Ltd. // +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/device.h> @@ -1892,9 +1893,8 @@ static int cs47l92_component_probe(struct snd_soc_component *component) snd_soc_component_init_regmap(component, madera->regmap); - mutex_lock(&madera->dapm_ptr_lock); - madera->dapm = snd_soc_component_to_dapm(component); - mutex_unlock(&madera->dapm_ptr_lock); + scoped_guard(mutex, &madera->dapm_ptr_lock) + madera->dapm = snd_soc_component_to_dapm(component); ret = madera_init_inputs(component); if (ret) @@ -1922,9 +1922,8 @@ static void cs47l92_component_remove(struct snd_soc_component *component) struct cs47l92 *cs47l92 = snd_soc_component_get_drvdata(component); struct madera *madera = cs47l92->core.madera; - mutex_lock(&madera->dapm_ptr_lock); - madera->dapm = NULL; - mutex_unlock(&madera->dapm_ptr_lock); + scoped_guard(mutex, &madera->dapm_ptr_lock) + madera->dapm = NULL; wm_adsp2_component_remove(&cs47l92->core.adsp[0], component); } diff --git a/sound/soc/codecs/cs48l32.c b/sound/soc/codecs/cs48l32.c index 086ed0f57a85..a9967771124e 100644 --- a/sound/soc/codecs/cs48l32.c +++ b/sound/soc/codecs/cs48l32.c @@ -8,6 +8,7 @@ #include <dt-bindings/sound/cs48l32.h> #include <linux/array_size.h> #include <linux/build_bug.h> +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/container_of.h> #include <linux/delay.h> @@ -236,15 +237,13 @@ static int cs48l32_rate_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v int ret; /* Prevent any mixer mux changes while we do this */ - mutex_lock(&cs48l32_codec->rate_lock); + guard(mutex)(&cs48l32_codec->rate_lock); /* The write must be guarded by a number of SYSCLK cycles */ cs48l32_spin_sysclk(cs48l32_codec); ret = snd_soc_put_enum_double(kcontrol, ucontrol); cs48l32_spin_sysclk(cs48l32_codec); - mutex_unlock(&cs48l32_codec->rate_lock); - return ret; } @@ -2242,7 +2241,6 @@ static int cs48l32_dai_set_sysclk(struct snd_soc_dai *dai, struct cs48l32_dai_priv *dai_priv = &cs48l32_codec->dai[dai->id - 1]; unsigned int base = dai->driver->base; unsigned int current_asp_rate, target_asp_rate; - bool change_rate_domain = false; int ret; if (clk_id == dai_priv->clk) @@ -2284,19 +2282,15 @@ static int cs48l32_dai_set_sysclk(struct snd_soc_dai *dai, if ((current_asp_rate & CS48L32_ASP_RATE_MASK) != (target_asp_rate & CS48L32_ASP_RATE_MASK)) { - change_rate_domain = true; - - mutex_lock(&cs48l32_codec->rate_lock); /* Guard the rate change with SYSCLK cycles */ - cs48l32_spin_sysclk(cs48l32_codec); - } - - snd_soc_component_update_bits(component, base + CS48L32_ASP_CONTROL1, - CS48L32_ASP_RATE_MASK, target_asp_rate); - - if (change_rate_domain) { - cs48l32_spin_sysclk(cs48l32_codec); - mutex_unlock(&cs48l32_codec->rate_lock); + scoped_guard(mutex, &cs48l32_codec->rate_lock) { + cs48l32_spin_sysclk(cs48l32_codec); + snd_soc_component_update_bits(component, + base + CS48L32_ASP_CONTROL1, + CS48L32_ASP_RATE_MASK, + target_asp_rate); + cs48l32_spin_sysclk(cs48l32_codec); + } } } diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c index 0dd35fa86cc5..d02ab74e549b 100644 --- a/sound/soc/codecs/cx2072x.c +++ b/sound/soc/codecs/cx2072x.c @@ -9,6 +9,7 @@ // #include <linux/acpi.h> +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/gpio/consumer.h> @@ -96,51 +97,60 @@ static const struct reg_default cx2072x_reg_defaults[] = { { CX2072X_GPIO_WAKE, 0x00000000 }, { CX2072X_GPIO_UM_ENABLE, 0x00000000 }, { CX2072X_GPIO_STICKY_MASK, 0x00000000 }, - { CX2072X_DAC1_CONVERTER_FORMAT, 0x00000031 }, - { CX2072X_DAC1_AMP_GAIN_RIGHT, 0x0000004a }, - { CX2072X_DAC1_AMP_GAIN_LEFT, 0x0000004a }, { CX2072X_DAC1_POWER_STATE, 0x00000433 }, { CX2072X_DAC1_CONVERTER_STREAM_CHANNEL, 0x00000000 }, { CX2072X_DAC1_EAPD_ENABLE, 0x00000000 }, - { CX2072X_DAC2_CONVERTER_FORMAT, 0x00000031 }, - { CX2072X_DAC2_AMP_GAIN_RIGHT, 0x0000004a }, - { CX2072X_DAC2_AMP_GAIN_LEFT, 0x0000004a }, + { CX2072X_DAC1_AMP_GAIN_RIGHT, 0x0000004a }, + { CX2072X_DAC1_AMP_GAIN_LEFT, 0x0000004a }, + { CX2072X_DAC1_CONVERTER_FORMAT, 0x00000031 }, { CX2072X_DAC2_POWER_STATE, 0x00000433 }, { CX2072X_DAC2_CONVERTER_STREAM_CHANNEL, 0x00000000 }, - { CX2072X_ADC1_CONVERTER_FORMAT, 0x00000031 }, + { CX2072X_DAC2_AMP_GAIN_RIGHT, 0x0000004a }, + { CX2072X_DAC2_AMP_GAIN_LEFT, 0x0000004a }, + { CX2072X_DAC2_CONVERTER_FORMAT, 0x00000031 }, + { CX2072X_ADC1_CONNECTION_SELECT_CONTROL, 0x00000000 }, + { CX2072X_ADC1_POWER_STATE, 0x00000433 }, + { CX2072X_ADC1_CONVERTER_STREAM_CHANNEL, 0x00000000 }, { CX2072X_ADC1_AMP_GAIN_RIGHT_0, 0x0000004a }, - { CX2072X_ADC1_AMP_GAIN_LEFT_0, 0x0000004a }, { CX2072X_ADC1_AMP_GAIN_RIGHT_1, 0x0000004a }, - { CX2072X_ADC1_AMP_GAIN_LEFT_1, 0x0000004a }, { CX2072X_ADC1_AMP_GAIN_RIGHT_2, 0x0000004a }, - { CX2072X_ADC1_AMP_GAIN_LEFT_2, 0x0000004a }, { CX2072X_ADC1_AMP_GAIN_RIGHT_3, 0x0000004a }, - { CX2072X_ADC1_AMP_GAIN_LEFT_3, 0x0000004a }, { CX2072X_ADC1_AMP_GAIN_RIGHT_4, 0x0000004a }, - { CX2072X_ADC1_AMP_GAIN_LEFT_4, 0x0000004a }, { CX2072X_ADC1_AMP_GAIN_RIGHT_5, 0x0000004a }, - { CX2072X_ADC1_AMP_GAIN_LEFT_5, 0x0000004a }, { CX2072X_ADC1_AMP_GAIN_RIGHT_6, 0x0000004a }, + { CX2072X_ADC1_AMP_GAIN_LEFT_0, 0x0000004a }, + { CX2072X_ADC1_AMP_GAIN_LEFT_1, 0x0000004a }, + { CX2072X_ADC1_AMP_GAIN_LEFT_2, 0x0000004a }, + { CX2072X_ADC1_AMP_GAIN_LEFT_3, 0x0000004a }, + { CX2072X_ADC1_AMP_GAIN_LEFT_4, 0x0000004a }, + { CX2072X_ADC1_AMP_GAIN_LEFT_5, 0x0000004a }, { CX2072X_ADC1_AMP_GAIN_LEFT_6, 0x0000004a }, - { CX2072X_ADC1_CONNECTION_SELECT_CONTROL, 0x00000000 }, - { CX2072X_ADC1_POWER_STATE, 0x00000433 }, - { CX2072X_ADC1_CONVERTER_STREAM_CHANNEL, 0x00000000 }, - { CX2072X_ADC2_CONVERTER_FORMAT, 0x00000031 }, + { CX2072X_ADC1_CONVERTER_FORMAT, 0x00000031 }, + { CX2072X_ADC2_CONNECTION_SELECT_CONTROL, 0x00000000 }, + { CX2072X_ADC2_POWER_STATE, 0x00000433 }, + { CX2072X_ADC2_CONVERTER_STREAM_CHANNEL, 0x00000000 }, { CX2072X_ADC2_AMP_GAIN_RIGHT_0, 0x0000004a }, - { CX2072X_ADC2_AMP_GAIN_LEFT_0, 0x0000004a }, { CX2072X_ADC2_AMP_GAIN_RIGHT_1, 0x0000004a }, - { CX2072X_ADC2_AMP_GAIN_LEFT_1, 0x0000004a }, { CX2072X_ADC2_AMP_GAIN_RIGHT_2, 0x0000004a }, + { CX2072X_ADC2_AMP_GAIN_LEFT_0, 0x0000004a }, + { CX2072X_ADC2_AMP_GAIN_LEFT_1, 0x0000004a }, { CX2072X_ADC2_AMP_GAIN_LEFT_2, 0x0000004a }, - { CX2072X_ADC2_CONNECTION_SELECT_CONTROL, 0x00000000 }, - { CX2072X_ADC2_POWER_STATE, 0x00000433 }, - { CX2072X_ADC2_CONVERTER_STREAM_CHANNEL, 0x00000000 }, + { CX2072X_ADC2_CONVERTER_FORMAT, 0x00000031 }, + { CX2072X_MIXER_POWER_STATE, 0x00000433 }, + { CX2072X_MIXER_GAIN_RIGHT_0, 0x0000004a }, + { CX2072X_MIXER_GAIN_RIGHT_1, 0x0000004a }, + { CX2072X_MIXER_GAIN_LEFT_0, 0x0000004a }, + { CX2072X_MIXER_GAIN_LEFT_1, 0x0000004a }, { CX2072X_PORTA_CONNECTION_SELECT_CTRL, 0x00000000 }, { CX2072X_PORTA_POWER_STATE, 0x00000433 }, { CX2072X_PORTA_PIN_CTRL, 0x000000c0 }, { CX2072X_PORTA_UNSOLICITED_RESPONSE, 0x00000000 }, { CX2072X_PORTA_PIN_SENSE, 0x00000000 }, { CX2072X_PORTA_EAPD_BTL, 0x00000002 }, + { CX2072X_PORTG_CONNECTION_SELECT_CTRL, 0x00000000 }, + { CX2072X_PORTG_POWER_STATE, 0x00000433 }, + { CX2072X_PORTG_PIN_CTRL, 0x00000040 }, + { CX2072X_PORTG_EAPD_BTL, 0x00000002 }, { CX2072X_PORTB_POWER_STATE, 0x00000433 }, { CX2072X_PORTB_PIN_CTRL, 0x00000000 }, { CX2072X_PORTB_UNSOLICITED_RESPONSE, 0x00000000 }, @@ -148,43 +158,16 @@ static const struct reg_default cx2072x_reg_defaults[] = { { CX2072X_PORTB_EAPD_BTL, 0x00000002 }, { CX2072X_PORTB_GAIN_RIGHT, 0x00000000 }, { CX2072X_PORTB_GAIN_LEFT, 0x00000000 }, - { CX2072X_PORTC_POWER_STATE, 0x00000433 }, - { CX2072X_PORTC_PIN_CTRL, 0x00000000 }, - { CX2072X_PORTC_GAIN_RIGHT, 0x00000000 }, - { CX2072X_PORTC_GAIN_LEFT, 0x00000000 }, { CX2072X_PORTD_POWER_STATE, 0x00000433 }, { CX2072X_PORTD_PIN_CTRL, 0x00000020 }, { CX2072X_PORTD_UNSOLICITED_RESPONSE, 0x00000000 }, { CX2072X_PORTD_PIN_SENSE, 0x00000000 }, { CX2072X_PORTD_GAIN_RIGHT, 0x00000000 }, { CX2072X_PORTD_GAIN_LEFT, 0x00000000 }, - { CX2072X_PORTE_CONNECTION_SELECT_CTRL, 0x00000000 }, - { CX2072X_PORTE_POWER_STATE, 0x00000433 }, - { CX2072X_PORTE_PIN_CTRL, 0x00000040 }, - { CX2072X_PORTE_UNSOLICITED_RESPONSE, 0x00000000 }, - { CX2072X_PORTE_PIN_SENSE, 0x00000000 }, - { CX2072X_PORTE_EAPD_BTL, 0x00000002 }, - { CX2072X_PORTE_GAIN_RIGHT, 0x00000000 }, - { CX2072X_PORTE_GAIN_LEFT, 0x00000000 }, - { CX2072X_PORTF_POWER_STATE, 0x00000433 }, - { CX2072X_PORTF_PIN_CTRL, 0x00000000 }, - { CX2072X_PORTF_UNSOLICITED_RESPONSE, 0x00000000 }, - { CX2072X_PORTF_PIN_SENSE, 0x00000000 }, - { CX2072X_PORTF_GAIN_RIGHT, 0x00000000 }, - { CX2072X_PORTF_GAIN_LEFT, 0x00000000 }, - { CX2072X_PORTG_POWER_STATE, 0x00000433 }, - { CX2072X_PORTG_PIN_CTRL, 0x00000040 }, - { CX2072X_PORTG_CONNECTION_SELECT_CTRL, 0x00000000 }, - { CX2072X_PORTG_EAPD_BTL, 0x00000002 }, - { CX2072X_PORTM_POWER_STATE, 0x00000433 }, - { CX2072X_PORTM_PIN_CTRL, 0x00000000 }, - { CX2072X_PORTM_CONNECTION_SELECT_CTRL, 0x00000000 }, - { CX2072X_PORTM_EAPD_BTL, 0x00000002 }, - { CX2072X_MIXER_POWER_STATE, 0x00000433 }, - { CX2072X_MIXER_GAIN_RIGHT_0, 0x0000004a }, - { CX2072X_MIXER_GAIN_LEFT_0, 0x0000004a }, - { CX2072X_MIXER_GAIN_RIGHT_1, 0x0000004a }, - { CX2072X_MIXER_GAIN_LEFT_1, 0x0000004a }, + { CX2072X_PORTC_POWER_STATE, 0x00000433 }, + { CX2072X_PORTC_PIN_CTRL, 0x00000000 }, + { CX2072X_PORTC_GAIN_RIGHT, 0x00000000 }, + { CX2072X_PORTC_GAIN_LEFT, 0x00000000 }, { CX2072X_SPKR_DRC_ENABLE_STEP, 0x040065a4 }, { CX2072X_SPKR_DRC_CONTROL, 0x007b0024 }, { CX2072X_SPKR_DRC_TEST, 0x00000000 }, @@ -195,12 +178,15 @@ static const struct reg_default cx2072x_reg_defaults[] = { { CX2072X_I2SPCM_CONTROL3, 0x00000000 }, { CX2072X_I2SPCM_CONTROL4, 0x00000000 }, { CX2072X_I2SPCM_CONTROL5, 0x00000000 }, - { CX2072X_I2SPCM_CONTROL6, 0x00000000 }, { CX2072X_UM_INTERRUPT_CRTL_E, 0x00000000 }, + { CX2072X_I2SPCM_CONTROL6, 0x00000000 }, + { CX2072X_DIGITAL_TEST16, 0x00000021 }, + { CX2072X_DIGITAL_TEST17, 0x00000018 }, + { CX2072X_DIGITAL_TEST18, 0x00000024 }, + { CX2072X_DIGITAL_TEST19, 0x00000001 }, + { CX2072X_DIGITAL_TEST20, 0x00000002 }, { CX2072X_CODEC_TEST2, 0x00000000 }, { CX2072X_CODEC_TEST9, 0x00000004 }, - { CX2072X_CODEC_TEST20, 0x00000600 }, - { CX2072X_CODEC_TEST26, 0x00000208 }, { CX2072X_ANALOG_TEST4, 0x00000000 }, { CX2072X_ANALOG_TEST5, 0x00000000 }, { CX2072X_ANALOG_TEST6, 0x0000059a }, @@ -215,11 +201,26 @@ static const struct reg_default cx2072x_reg_defaults[] = { { CX2072X_DIGITAL_TEST11, 0x00000000 }, { CX2072X_DIGITAL_TEST12, 0x00000084 }, { CX2072X_DIGITAL_TEST15, 0x00000077 }, - { CX2072X_DIGITAL_TEST16, 0x00000021 }, - { CX2072X_DIGITAL_TEST17, 0x00000018 }, - { CX2072X_DIGITAL_TEST18, 0x00000024 }, - { CX2072X_DIGITAL_TEST19, 0x00000001 }, - { CX2072X_DIGITAL_TEST20, 0x00000002 }, + { CX2072X_CODEC_TEST20, 0x00000600 }, + { CX2072X_CODEC_TEST26, 0x00000208 }, + { CX2072X_PORTE_CONNECTION_SELECT_CTRL, 0x00000000 }, + { CX2072X_PORTE_POWER_STATE, 0x00000433 }, + { CX2072X_PORTE_PIN_CTRL, 0x00000040 }, + { CX2072X_PORTE_UNSOLICITED_RESPONSE, 0x00000000 }, + { CX2072X_PORTE_PIN_SENSE, 0x00000000 }, + { CX2072X_PORTE_EAPD_BTL, 0x00000002 }, + { CX2072X_PORTE_GAIN_RIGHT, 0x00000000 }, + { CX2072X_PORTE_GAIN_LEFT, 0x00000000 }, + { CX2072X_PORTF_POWER_STATE, 0x00000433 }, + { CX2072X_PORTF_PIN_CTRL, 0x00000000 }, + { CX2072X_PORTF_UNSOLICITED_RESPONSE, 0x00000000 }, + { CX2072X_PORTF_PIN_SENSE, 0x00000000 }, + { CX2072X_PORTF_GAIN_RIGHT, 0x00000000 }, + { CX2072X_PORTF_GAIN_LEFT, 0x00000000 }, + { CX2072X_PORTM_CONNECTION_SELECT_CTRL, 0x00000000 }, + { CX2072X_PORTM_POWER_STATE, 0x00000433 }, + { CX2072X_PORTM_PIN_CTRL, 0x00000000 }, + { CX2072X_PORTM_EAPD_BTL, 0x00000002 }, }; /* @@ -1408,7 +1409,7 @@ static int cx2072x_jack_status_check(void *data) unsigned int type = 0; int state = 0; - mutex_lock(&cx2072x->lock); + guard(mutex)(&cx2072x->lock); regmap_read(cx2072x->regmap, CX2072X_PORTA_PIN_SENSE, &jack); jack = jack >> 24; @@ -1434,8 +1435,6 @@ static int cx2072x_jack_status_check(void *data) /* clear interrupt */ regmap_write(cx2072x->regmap, CX2072X_UM_INTERRUPT_CRTL_E, 0x12 << 24); - mutex_unlock(&cx2072x->lock); - dev_dbg(codec->dev, "CX2072X_HSDETECT type=0x%X,Jack state = %x\n", type, state); return state; diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 4bf91ab2553a..923b997efbc4 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -11,6 +11,7 @@ #include <linux/acpi.h> #include <linux/of.h> #include <linux/property.h> +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/i2c.h> @@ -216,13 +217,10 @@ static int da7213_volsw_locked_get(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); - int ret; - mutex_lock(&da7213->ctrl_lock); - ret = snd_soc_get_volsw(kcontrol, ucontrol); - mutex_unlock(&da7213->ctrl_lock); + guard(mutex)(&da7213->ctrl_lock); - return ret; + return snd_soc_get_volsw(kcontrol, ucontrol); } static int da7213_volsw_locked_put(struct snd_kcontrol *kcontrol, @@ -230,13 +228,10 @@ static int da7213_volsw_locked_put(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); - int ret; - mutex_lock(&da7213->ctrl_lock); - ret = snd_soc_put_volsw(kcontrol, ucontrol); - mutex_unlock(&da7213->ctrl_lock); + guard(mutex)(&da7213->ctrl_lock); - return ret; + return snd_soc_put_volsw(kcontrol, ucontrol); } static int da7213_enum_locked_get(struct snd_kcontrol *kcontrol, @@ -244,13 +239,10 @@ static int da7213_enum_locked_get(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); - int ret; - mutex_lock(&da7213->ctrl_lock); - ret = snd_soc_get_enum_double(kcontrol, ucontrol); - mutex_unlock(&da7213->ctrl_lock); + guard(mutex)(&da7213->ctrl_lock); - return ret; + return snd_soc_get_enum_double(kcontrol, ucontrol); } static int da7213_enum_locked_put(struct snd_kcontrol *kcontrol, @@ -258,13 +250,10 @@ static int da7213_enum_locked_put(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); - int ret; - mutex_lock(&da7213->ctrl_lock); - ret = snd_soc_put_enum_double(kcontrol, ucontrol); - mutex_unlock(&da7213->ctrl_lock); + guard(mutex)(&da7213->ctrl_lock); - return ret; + return snd_soc_put_enum_double(kcontrol, ucontrol); } /* ALC */ @@ -465,9 +454,8 @@ static int da7213_tonegen_freq_get(struct snd_kcontrol *kcontrol, __le16 val; int ret; - mutex_lock(&da7213->ctrl_lock); - ret = regmap_raw_read(da7213->regmap, reg, &val, sizeof(val)); - mutex_unlock(&da7213->ctrl_lock); + scoped_guard(mutex, &da7213->ctrl_lock) + ret = regmap_raw_read(da7213->regmap, reg, &val, sizeof(val)); if (ret) return ret; @@ -499,12 +487,11 @@ static int da7213_tonegen_freq_put(struct snd_kcontrol *kcontrol, */ val_new = cpu_to_le16(ucontrol->value.integer.value[0]); - mutex_lock(&da7213->ctrl_lock); + guard(mutex)(&da7213->ctrl_lock); ret = regmap_raw_read(da7213->regmap, reg, &val_old, sizeof(val_old)); if (ret == 0 && (val_old != val_new)) ret = regmap_raw_write(da7213->regmap, reg, &val_new, sizeof(val_new)); - mutex_unlock(&da7213->ctrl_lock); if (ret < 0) return ret; diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index f0874d891e12..f6d371e93549 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -8,6 +8,7 @@ */ #include <linux/acpi.h> +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/clkdev.h> #include <linux/clk-provider.h> @@ -256,13 +257,10 @@ static int da7219_volsw_locked_get(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); - int ret; - mutex_lock(&da7219->ctrl_lock); - ret = snd_soc_get_volsw(kcontrol, ucontrol); - mutex_unlock(&da7219->ctrl_lock); + guard(mutex)(&da7219->ctrl_lock); - return ret; + return snd_soc_get_volsw(kcontrol, ucontrol); } static int da7219_volsw_locked_put(struct snd_kcontrol *kcontrol, @@ -270,13 +268,10 @@ static int da7219_volsw_locked_put(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); - int ret; - mutex_lock(&da7219->ctrl_lock); - ret = snd_soc_put_volsw(kcontrol, ucontrol); - mutex_unlock(&da7219->ctrl_lock); + guard(mutex)(&da7219->ctrl_lock); - return ret; + return snd_soc_put_volsw(kcontrol, ucontrol); } static int da7219_enum_locked_get(struct snd_kcontrol *kcontrol, @@ -284,13 +279,10 @@ static int da7219_enum_locked_get(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); - int ret; - mutex_lock(&da7219->ctrl_lock); - ret = snd_soc_get_enum_double(kcontrol, ucontrol); - mutex_unlock(&da7219->ctrl_lock); + guard(mutex)(&da7219->ctrl_lock); - return ret; + return snd_soc_get_enum_double(kcontrol, ucontrol); } static int da7219_enum_locked_put(struct snd_kcontrol *kcontrol, @@ -298,13 +290,10 @@ static int da7219_enum_locked_put(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); - int ret; - mutex_lock(&da7219->ctrl_lock); - ret = snd_soc_put_enum_double(kcontrol, ucontrol); - mutex_unlock(&da7219->ctrl_lock); + guard(mutex)(&da7219->ctrl_lock); - return ret; + return snd_soc_put_enum_double(kcontrol, ucontrol); } /* ALC */ @@ -422,9 +411,8 @@ static int da7219_tonegen_freq_get(struct snd_kcontrol *kcontrol, __le16 val; int ret; - mutex_lock(&da7219->ctrl_lock); - ret = regmap_raw_read(da7219->regmap, reg, &val, sizeof(val)); - mutex_unlock(&da7219->ctrl_lock); + scoped_guard(mutex, &da7219->ctrl_lock) + ret = regmap_raw_read(da7219->regmap, reg, &val, sizeof(val)); if (ret) return ret; @@ -456,12 +444,11 @@ static int da7219_tonegen_freq_put(struct snd_kcontrol *kcontrol, */ val_new = cpu_to_le16(ucontrol->value.integer.value[0]); - mutex_lock(&da7219->ctrl_lock); + guard(mutex)(&da7219->ctrl_lock); ret = regmap_raw_read(da7219->regmap, reg, &val_old, sizeof(val_old)); if (ret == 0 && (val_old != val_new)) ret = regmap_raw_write(da7219->regmap, reg, - &val_new, sizeof(val_new)); - mutex_unlock(&da7219->ctrl_lock); + &val_new, sizeof(val_new)); if (ret < 0) return ret; @@ -1167,15 +1154,12 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai, struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); int ret = 0; - mutex_lock(&da7219->pll_lock); + guard(mutex)(&da7219->pll_lock); - if ((da7219->clk_src == clk_id) && (da7219->mclk_rate == freq)) { - mutex_unlock(&da7219->pll_lock); + if (da7219->clk_src == clk_id && da7219->mclk_rate == freq) return 0; - } - if ((freq < 2000000) || (freq > 54000000)) { - mutex_unlock(&da7219->pll_lock); + if (freq < 2000000 || freq > 54000000) { dev_err(codec_dai->dev, "Unsupported MCLK value %d\n", freq); return -EINVAL; @@ -1193,7 +1177,6 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai, break; default: dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id); - mutex_unlock(&da7219->pll_lock); return -EINVAL; } @@ -1203,17 +1186,13 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai, freq = clk_round_rate(da7219->mclk, freq); ret = clk_set_rate(da7219->mclk, freq); if (ret) { - dev_err(codec_dai->dev, "Failed to set clock rate %d\n", - freq); - mutex_unlock(&da7219->pll_lock); + dev_err(codec_dai->dev, "Failed to set clock rate %d\n", freq); return ret; } } da7219->mclk_rate = freq; - mutex_unlock(&da7219->pll_lock); - return 0; } @@ -1296,13 +1275,10 @@ static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, { struct snd_soc_component *component = codec_dai->component; struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); - int ret; - mutex_lock(&da7219->pll_lock); - ret = da7219_set_pll(component, source, fout); - mutex_unlock(&da7219->pll_lock); + guard(mutex)(&da7219->pll_lock); - return ret; + return da7219_set_pll(component, source, fout); } static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 3abe77423f29..24ec8b211cdb 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -9,11 +9,13 @@ #include <linux/module.h> #include <linux/acpi.h> +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/i2c.h> #include <linux/mutex.h> #include <linux/regmap.h> +#include <linux/regulator/consumer.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> @@ -30,6 +32,13 @@ static const unsigned int supported_mclk_lrck_ratios[] = { 256, 384, 400, 500, 512, 768, 1024 }; +static const char * const es8316_supply_names[] = { + "avdd", + "cpvdd", + "dvdd", + "pvdd", +}; + struct es8316_priv { struct mutex lock; struct clk *mclk; @@ -620,15 +629,15 @@ static irqreturn_t es8316_irq(int irq, void *data) struct snd_soc_component *comp = es8316->component; unsigned int flags; - mutex_lock(&es8316->lock); + guard(mutex)(&es8316->lock); regmap_read(es8316->regmap, ES8316_GPIO_FLAG, &flags); if (flags == 0x00) - goto out; /* Powered-down / reset */ + return IRQ_HANDLED; /* Powered-down / reset */ /* Catch spurious IRQ before set_jack is called */ if (!es8316->jack) - goto out; + return IRQ_HANDLED; if (es8316->jd_inverted) flags ^= ES8316_GPIO_FLAG_HP_NOT_INSERTED; @@ -681,8 +690,6 @@ static irqreturn_t es8316_irq(int irq, void *data) } } -out: - mutex_unlock(&es8316->lock); return IRQ_HANDLED; } @@ -699,18 +706,16 @@ static void es8316_enable_jack_detect(struct snd_soc_component *component, es8316->jd_inverted = device_property_read_bool(component->dev, "everest,jack-detect-inverted"); - mutex_lock(&es8316->lock); - - es8316->jack = jack; + scoped_guard(mutex, &es8316->lock) { + es8316->jack = jack; - if (es8316->jack->status & SND_JACK_MICROPHONE) - es8316_enable_micbias_for_mic_gnd_short_detect(component); - - snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE, - ES8316_GPIO_ENABLE_INTERRUPT, - ES8316_GPIO_ENABLE_INTERRUPT); + if (es8316->jack->status & SND_JACK_MICROPHONE) + es8316_enable_micbias_for_mic_gnd_short_detect(component); - mutex_unlock(&es8316->lock); + snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE, + ES8316_GPIO_ENABLE_INTERRUPT, + ES8316_GPIO_ENABLE_INTERRUPT); + } /* Enable irq and sync initial jack state */ enable_irq(es8316->irq); @@ -726,7 +731,7 @@ static void es8316_disable_jack_detect(struct snd_soc_component *component) disable_irq(es8316->irq); - mutex_lock(&es8316->lock); + guard(mutex)(&es8316->lock); snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE, ES8316_GPIO_ENABLE_INTERRUPT, 0); @@ -737,8 +742,6 @@ static void es8316_disable_jack_detect(struct snd_soc_component *component) } es8316->jack = NULL; - - mutex_unlock(&es8316->lock); } static int es8316_set_jack(struct snd_soc_component *component, @@ -871,6 +874,11 @@ static int es8316_i2c_probe(struct i2c_client *i2c_client) i2c_set_clientdata(i2c_client, es8316); + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(es8316_supply_names), + es8316_supply_names); + if (ret) + return dev_err_probe(dev, ret, "unable to enable supplies\n"); + es8316->regmap = devm_regmap_init_i2c(i2c_client, &es8316_regmap); if (IS_ERR(es8316->regmap)) return PTR_ERR(es8316->regmap); diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index a79b2da35099..c5460589a88b 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -6,6 +6,7 @@ // Authors: David Yang <yangxiaohua@everest-semi.com> // +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/i2c.h> #include <linux/interrupt.h> @@ -790,7 +791,7 @@ static void es8326_jack_button_handler(struct work_struct *work) if (!(es8326->jack->status & SND_JACK_HEADSET)) /* Jack unplugged */ return; - mutex_lock(&es8326->lock); + guard(mutex)(&es8326->lock); iface = snd_soc_component_read(comp, ES8326_HPDET_STA); switch (iface) { case 0x93: @@ -845,7 +846,6 @@ static void es8326_jack_button_handler(struct work_struct *work) } es8326_disable_micbias(es8326->component); } - mutex_unlock(&es8326->lock); } static void es8326_jack_detect_handler(struct work_struct *work) @@ -855,7 +855,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) struct snd_soc_component *comp = es8326->component; unsigned int iface; - mutex_lock(&es8326->lock); + guard(mutex)(&es8326->lock); iface = snd_soc_component_read(comp, ES8326_HPDET_STA); dev_dbg(comp->dev, "gpio flag %#04x", iface); @@ -873,7 +873,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, ES8326_HP_DET_JACK_POL, (es8326->jd_inverted ? ~es8326->jack_pol : es8326->jack_pol)); - goto exit; + return; } if ((iface & ES8326_HPINSERT_FLAG) == 0) { @@ -930,7 +930,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) queue_delayed_work(system_dfl_wq, &es8326->jack_detect_work, msecs_to_jiffies(400)); es8326->hp = 1; - goto exit; + return; } if (es8326->jack->status & SND_JACK_HEADSET) { /* detect button */ @@ -939,7 +939,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) (ES8326_INT_SRC_PIN9 | ES8326_INT_SRC_BUTTON)); es8326_enable_micbias(es8326->component); queue_delayed_work(system_dfl_wq, &es8326->button_press_work, 10); - goto exit; + return; } if ((iface & ES8326_HPBUTTON_FLAG) == 0x01) { dev_dbg(comp->dev, "Headphone detected\n"); @@ -958,8 +958,6 @@ static void es8326_jack_detect_handler(struct work_struct *work) usleep_range(10000, 15000); } } -exit: - mutex_unlock(&es8326->lock); } static irqreturn_t es8326_irq(int irq, void *dev_id) @@ -1200,13 +1198,12 @@ static void es8326_enable_jack_detect(struct snd_soc_component *component, { struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); - mutex_lock(&es8326->lock); - if (es8326->jd_inverted) - snd_soc_component_update_bits(component, ES8326_HPDET_TYPE, - ES8326_HP_DET_JACK_POL, ~es8326->jack_pol); - es8326->jack = jack; - - mutex_unlock(&es8326->lock); + scoped_guard(mutex, &es8326->lock) { + if (es8326->jd_inverted) + snd_soc_component_update_bits(component, ES8326_HPDET_TYPE, + ES8326_HP_DET_JACK_POL, ~es8326->jack_pol); + es8326->jack = jack; + } es8326_irq(es8326->irq, es8326); } @@ -1219,13 +1216,12 @@ static void es8326_disable_jack_detect(struct snd_soc_component *component) return; /* Already disabled (or never enabled) */ cancel_delayed_work_sync(&es8326->jack_detect_work); - mutex_lock(&es8326->lock); + guard(mutex)(&es8326->lock); if (es8326->jack->status & SND_JACK_MICROPHONE) { es8326_disable_micbias(component); snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET); } es8326->jack = NULL; - mutex_unlock(&es8326->lock); } static int es8326_set_jack(struct snd_soc_component *component, diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index 9838fe42cb6f..aaa6646ad4c5 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -405,6 +405,11 @@ static const struct snd_soc_dapm_route es8328_dapm_routes[] = { { "Mic Bias", NULL, "Mic Bias Gen" }, + { "LINPUT1", NULL, "Mic Bias" }, + { "RINPUT1", NULL, "Mic Bias" }, + { "LINPUT2", NULL, "Mic Bias" }, + { "RINPUT2", NULL, "Mic Bias" }, + { "Left Mixer", NULL, "Left DAC" }, { "Left Mixer", "Left Bypass Switch", "Left Line Mux" }, { "Left Mixer", "Right Playback Switch", "Right DAC" }, diff --git a/sound/soc/codecs/es8389.c b/sound/soc/codecs/es8389.c index 3484c87853cb..80efce3e0a22 100644 --- a/sound/soc/codecs/es8389.c +++ b/sound/soc/codecs/es8389.c @@ -36,6 +36,10 @@ struct es8389_private { unsigned int sysclk; int mastermode; + u8 hpfl; + u8 hpfr; + u32 hpf_freq; + u32 capture_rate; u8 mclk_src; u8 vddd; int version; @@ -50,10 +54,29 @@ static const char * const es8389_core_supplies[] = { static bool es8389_volatile_register(struct device *dev, unsigned int reg) { - if ((reg <= 0xff)) - return true; - else + switch (reg) { + case ES8389_ADCL_VOL: + case ES8389_ADCR_VOL: + case ES8389_MIC1_GAIN: + case ES8389_MIC2_GAIN: + case ES8389_DACL_VOL: + case ES8389_DACR_VOL: + case ES8389_ALC_ON: + case ES8389_ALC_CTL: + case ES8389_ALC_TARGET: + case ES8389_ALC_GAIN: + case ES8389_ADC_MUTE: + case ES8389_OSR_VOL: + case ES8389_DAC_INV: + case ES8389_MIX_VOL: + case ES8389_DAC_MIX: + case ES8389_ADC_RESET: + case ES8389_ADC_MODE: + case ES8389_DMIC_EN: return false; + default: + return true; + } } static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9550, 50, 0); @@ -63,6 +86,92 @@ static const DECLARE_TLV_DB_SCALE(mix_vol_tlv, -9500, 100, 0); static const DECLARE_TLV_DB_SCALE(alc_target_tlv, -3200, 200, 0); static const DECLARE_TLV_DB_SCALE(alc_max_level, -3200, 200, 0); +static const u32 hpf_table[10][10] = { + {1020, 754, 624, 559, 527, 511, 502, 498, 497, 496}, + {754, 495, 368, 306, 274, 259, 251, 247, 246, 244}, + {624, 368, 243, 182, 151, 136, 128, 124, 123, 121}, + {559, 306, 182, 120, 90, 75, 68, 63, 62, 60}, + {527, 274, 151, 90, 60, 45, 38, 33, 32, 31}, + {511, 259, 136, 75, 45, 30, 23, 19, 18, 17}, + {502, 251, 128, 68, 38, 23, 16, 13, 11, 11}, + {498, 247, 124, 63, 33, 19, 13, 10, 8, 8}, + {497, 246, 123, 62, 32, 18, 11, 8, 8, 0}, + {496, 244, 121, 60, 31, 17, 11, 8, 0, 0} +}; + +static bool find_best_hpf_freq(u32 target_hz, u8 *hpf1, u8 *hpf2, u32 *out) +{ + int best_row = -1, best_col = -1; + u32 min_diff = U32_MAX; + u32 f, diff; + int i, j; + + if (target_hz > 1020) + return false; + + for (i = 0; i < 10; i++) { + for (j = i; j < 10; j++) { + f = hpf_table[i][j]; + + diff = (target_hz > f) ? (target_hz - f) : (f - target_hz); + if (diff < min_diff) { + min_diff = diff; + best_row = i; + best_col = j; + *out = f; + } + } + } + + *hpf1 = best_col + ES8389_HPF_OFFSET; + *hpf2 = best_row + ES8389_HPF_OFFSET; + + return true; +} + +static int es8389_hpf_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct es8389_private *es8389 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = es8389->hpf_freq; + return 0; +} + +static int es8389_hpf_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct es8389_private *es8389 = snd_soc_component_get_drvdata(component); + u32 freq; + bool hpf; + + if (es8389->hpf_freq == ucontrol->value.integer.value[0]) + return 0; + + if (es8389->capture_rate) { + freq = (ucontrol->value.integer.value[0] * 48000) / es8389->capture_rate; + + hpf = find_best_hpf_freq(freq, &es8389->hpfl, &es8389->hpfr, &es8389->hpf_freq); + if (!hpf) + return -EBUSY; + + if (es8389->hpf_freq != ucontrol->value.integer.value[0]) + dev_dbg(component->dev, "At the %u Hz sampling rate, %ld Hz could not be obtained." + "the frequency has been set to the closest value, %u Hz\n", + es8389->capture_rate, ucontrol->value.integer.value[0], es8389->hpf_freq); + + regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, es8389->hpfl); + regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, es8389->hpfr); + } else { + es8389->hpf_freq = ucontrol->value.integer.value[0]; + dev_dbg(component->dev, "PCM_STREAM_CAPTURE is not active.retain the input frequency\n"); + } + + return 1; +} + static int es8389_dmic_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -143,6 +252,16 @@ static const struct soc_enum alc_ramprate = static const struct soc_enum alc_winsize = SOC_ENUM_SINGLE(ES8389_ALC_CTL, 0, 16, winsize); +static const char *const es8389_adcl_mux_txt[] = { + "Normal", + "ADC2 channel to ADC1 channel", +}; + +static const char *const es8389_adcr_mux_txt[] = { + "Normal", + "ADC1 channel to ADC2 channel", +}; + static const char *const es8389_outl_mux_txt[] = { "Normal", "DAC2 channel to DAC1 channel", @@ -170,6 +289,20 @@ static const unsigned int es8389_pga_values[] = { 1, 5, 6 }; +static const struct soc_enum es8389_adcl_mux_enum = + SOC_ENUM_SINGLE(ES8389_ADC_MODE, 5, + ARRAY_SIZE(es8389_adcl_mux_txt), es8389_adcl_mux_txt); + +static const struct snd_kcontrol_new es8389_adcl_mux_controls = + SOC_DAPM_ENUM("INPUTL MUX", es8389_adcl_mux_enum); + +static const struct soc_enum es8389_adcr_mux_enum = + SOC_ENUM_SINGLE(ES8389_ADC_MODE, 4, + ARRAY_SIZE(es8389_adcr_mux_txt), es8389_adcr_mux_txt); + +static const struct snd_kcontrol_new es8389_adcr_mux_controls = + SOC_DAPM_ENUM("INPUTR MUX", es8389_adcr_mux_enum); + static const struct soc_enum es8389_outl_mux_enum = SOC_ENUM_SINGLE(ES8389_DAC_MIX, 5, ARRAY_SIZE(es8389_outl_mux_txt), es8389_outl_mux_txt); @@ -240,6 +373,8 @@ static const struct snd_kcontrol_new es8389_snd_controls[] = { SOC_DOUBLE("ADC OSR Volume ON Switch", ES8389_ADC_MUTE, 6, 7, 1, 0), SOC_SINGLE_TLV("ADC OSR Volume", ES8389_OSR_VOL, 0, 0xFF, 0, adc_vol_tlv), SOC_DOUBLE("ADC OUTPUT Invert Switch", ES8389_ADC_HPF2, 5, 6, 1, 0), + SOC_SINGLE_EXT("ADC HPF Freq Select", SND_SOC_NOPM, 0, 1020, 0, + es8389_hpf_get, es8389_hpf_set), SOC_SINGLE_TLV("DACL Playback Volume", ES8389_DACL_VOL, 0, 0xFF, 0, dac_vol_tlv), SOC_SINGLE_TLV("DACR Playback Volume", ES8389_DACR_VOL, 0, 0xFF, 0, dac_vol_tlv), @@ -298,6 +433,8 @@ static const struct snd_soc_dapm_widget es8389_dapm_widgets[] = { &es8389_adc_mixer_controls[0], ARRAY_SIZE(es8389_adc_mixer_controls)), SND_SOC_DAPM_MUX("ADC MUX", SND_SOC_NOPM, 0, 0, &es8389_dmic_mux_controls), + SND_SOC_DAPM_MUX("INPUTL MUX", SND_SOC_NOPM, 0, 0, &es8389_adcl_mux_controls), + SND_SOC_DAPM_MUX("INPUTR MUX", SND_SOC_NOPM, 0, 0, &es8389_adcr_mux_controls), SND_SOC_DAPM_MUX("OUTL MUX", SND_SOC_NOPM, 0, 0, &es8389_outl_mux_controls), SND_SOC_DAPM_MUX("OUTR MUX", SND_SOC_NOPM, 0, 0, &es8389_outr_mux_controls), @@ -311,10 +448,15 @@ static const struct snd_soc_dapm_route es8389_dapm_routes[] = { {"ADCL", NULL, "PGAL"}, {"ADCR", NULL, "PGAR"}, + {"INPUTL MUX", "Normal", "ADCL"}, + {"INPUTL MUX", "ADC2 channel to ADC1 channel", "ADCR"}, + {"INPUTR MUX", "Normal", "ADCR"}, + {"INPUTR MUX", "ADC1 channel to ADC2 channel", "ADCL"}, + {"ADC Mixer", "DACL ADCL Mixer", "DACL"}, {"ADC Mixer", "DACR ADCR Mixer", "DACR"}, - {"ADC Mixer", NULL, "ADCL"}, - {"ADC Mixer", NULL, "ADCR"}, + {"ADC Mixer", NULL, "INPUTL MUX"}, + {"ADC Mixer", NULL, "INPUTR MUX"}, {"ADC MUX", "AMIC", "ADC Mixer"}, {"ADC MUX", "DMIC", "DMIC"}, @@ -415,52 +557,54 @@ static const struct _coeff_div coeff_div[] = { {36, 576000, 16000, 0x00, 0x55, 0x84, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {48, 768000, 16000, 0x02, 0x57, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {50, 800000, 16000, 0x00, 0x7E, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {64, 1024000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {72, 1152000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, + {64, 1024000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, + {72, 1152000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {96, 1536000, 16000, 0x02, 0x55, 0x84, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {128, 2048000, 16000, 0x00, 0x51, 0x04, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {144, 2304000, 16000, 0x00, 0x51, 0x00, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, + {150, 2400000, 16000, 0x02, 0x7E, 0x01, 0xC9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, {192, 3072000, 16000, 0x02, 0x65, 0x25, 0xE0, 0x00, 0xE1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {256, 4096000, 16000, 0x00, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, + {256, 4096000, 16000, 0x00, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {300, 4800000, 16000, 0x02, 0x66, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {384, 6144000, 16000, 0x02, 0x51, 0x04, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {512, 8192000, 16000, 0x01, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, + {512, 8192000, 16000, 0x01, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {750, 12000000, 16000, 0x0E, 0x7E, 0x01, 0xC9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {768, 12288000, 16000, 0x02, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {1024, 16384000, 16000, 0x03, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, + {768, 12288000, 16000, 0x02, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, + {1024, 16384000, 16000, 0x03, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {1152, 18432000, 16000, 0x08, 0x51, 0x04, 0xD0, 0x01, 0xC1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {1200, 19200000, 16000, 0x0B, 0x66, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {1500, 24000000, 16000, 0x0E, 0x26, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {1536, 24576000, 16000, 0x05, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, + {1536, 24576000, 16000, 0x05, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {1625, 26000000, 16000, 0x40, 0x6E, 0x05, 0xC8, 0x01, 0xC2, 0x90, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {800, 19200000, 24000, 0x07, 0x66, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x1A, 0x49, 0x14, 2, 2}, {375, 12000000, 32000, 0x0E, 0x2E, 0x05, 0xC8, 0x00, 0xC2, 0x80, 0x40, 0x01, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x23, 0x61, 0x1B, 2, 0}, - {600, 19200000, 32000, 0x05, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x23, 0x61, 0x1B, 2, 2}, - {32, 1411200, 44100, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {600, 19200000, 32000, 0x05, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x23, 0x61, 0x1B, 2, 2}, + {32, 1411200, 44100, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, {64, 2822400, 44100, 0x00, 0x51, 0x00, 0xC0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {128, 5644800, 44100, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {256, 11289600, 44100, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {512, 22579200, 44100, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {32, 1536000, 48000, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {128, 5644800, 44100, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {256, 11289600, 44100, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {512, 22579200, 44100, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {32, 1536000, 48000, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, {48, 2304000, 48000, 0x02, 0x55, 0x04, 0xC0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, {50, 2400000, 48000, 0x00, 0x76, 0x01, 0xC8, 0x10, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, {64, 3072000, 48000, 0x00, 0x51, 0x04, 0xC0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {100, 4800000, 48000, 0x00, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {100, 4800000, 48000, 0x00, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, {125, 6000000, 48000, 0x04, 0x6E, 0x05, 0xC8, 0x10, 0xC2, 0x80, 0x00, 0x01, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {128, 6144000, 48000, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {200, 9600000, 48000, 0x01, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {128, 6144000, 48000, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {200, 9600000, 48000, 0x01, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, {250, 12000000, 48000, 0x04, 0x76, 0x01, 0xC8, 0x10, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {256, 12288000, 48000, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {384, 18432000, 48000, 0x02, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {400, 19200000, 48000, 0x03, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {500, 24000000, 48000, 0x04, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {512, 24576000, 48000, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {256, 12288000, 48000, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {384, 18432000, 48000, 0x02, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {400, 19200000, 48000, 0x03, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {500, 24000000, 48000, 0x04, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {512, 24576000, 48000, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, {800, 38400000, 48000, 0x18, 0x45, 0x04, 0xC0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, {128, 11289600, 88200, 0x00, 0x50, 0x00, 0xC0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x32, 0x89, 0x25, 2, 2}, - {64, 6144000, 96000, 0x00, 0x41, 0x00, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2}, + {64, 6144000, 96000, 0x00, 0x41, 0x00, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2}, {96, 9216000, 96000, 0x02, 0x43, 0x00, 0xC0, 0x10, 0xC0, 0x80, 0x00, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2}, {256, 24576000, 96000, 0x00, 0x40, 0x00, 0xC0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2}, {128, 24576000, 192000, 0x00, 0x50, 0x00, 0xC0, 0x18, 0xC1, 0x81, 0xC0, 0x00, 0x8F, 0x7F, 0xBF, 0xC0, 0x3F, 0x7F, 0x80, 0x12, 0xC0, 0x3F, 0xF9, 0x3F, 2, 2}, + {64, 12288000, 192000, 0x00, 0x41, 0x00, 0xC0, 0x18, 0xC1, 0x80, 0x00, 0x00, 0x8F, 0x7F, 0xEF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x3F, 0xF9, 0x3F, 1, 0}, }; static inline int get_coeff(u8 vddd, u8 dmic, int mclk, int rate) @@ -564,6 +708,8 @@ static int es8389_pcm_hw_params(struct snd_pcm_substream *substream, int coeff, ret; u8 dmic_enable, state = 0; unsigned int regv; + u32 freq; + bool hpf; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -590,7 +736,7 @@ static int es8389_pcm_hw_params(struct snd_pcm_substream *substream, if (es8389->mclk_src == ES8389_SCLK_PIN) { regmap_update_bits(es8389->regmap, ES8389_MASTER_CLK, - ES8389_MCLK_SOURCE, es8389->mclk_src); + ES8389_MCLK_MASK, ES8389_MCLK_FROM_SCLK); es8389->sysclk = params_channels(params) * params_width(params) * params_rate(params); } @@ -641,6 +787,28 @@ static int es8389_pcm_hw_params(struct snd_pcm_substream *substream, dev_warn(component->dev, "Clock coefficients do not match"); } + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + es8389->capture_rate = params_rate(params); + freq = (es8389->hpf_freq * 48000) / params_rate(params); + hpf = find_best_hpf_freq(freq, &es8389->hpfl, &es8389->hpfr, &es8389->hpf_freq); + if (!hpf) { + dev_err(component->dev, "The HPF frequency is invalid\n"); + return -EINVAL; + } + } + + return 0; +} + +static int es8389_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct es8389_private *es8389 = snd_soc_component_get_drvdata(component); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + es8389->capture_rate = 0; + return 0; } @@ -721,8 +889,8 @@ static int es8389_mute(struct snd_soc_dai *dai, int mute, int direction) regmap_update_bits(es8389->regmap, ES8389_DAC_FORMAT_MUTE, 0x03, 0x00); } else { - regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, 0x0a); - regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, 0x0a); + regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, es8389->hpfl); + regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, es8389->hpfr); regmap_update_bits(es8389->regmap, ES8389_ADC_FORMAT_MUTE, 0x03, 0x00); } @@ -738,6 +906,7 @@ static int es8389_mute(struct snd_soc_dai *dai, int mute, int direction) static const struct snd_soc_dai_ops es8389_ops = { .hw_params = es8389_pcm_hw_params, + .hw_free = es8389_pcm_hw_free, .set_fmt = es8389_set_dai_fmt, .set_sysclk = es8389_set_dai_sysclk, .set_tdm_slot = es8389_set_tdm_slot, @@ -771,7 +940,7 @@ static void es8389_init(struct snd_soc_component *component) regmap_read(es8389->regmap, ES8389_MAX_REGISTER, ®); es8389->version = reg; - regmap_write(es8389->regmap, ES8389_ISO_CTL, 0x00); + regmap_write(es8389->regmap, ES8389_ISO_CTL, 0x56); regmap_write(es8389->regmap, ES8389_RESET, 0x7E); regmap_write(es8389->regmap, ES8389_ISO_CTL, 0x38); regmap_write(es8389->regmap, ES8389_ADC_HPF1, 0x64); @@ -823,7 +992,7 @@ static void es8389_init(struct snd_soc_component *component) regmap_write(es8389->regmap, ES8389_SCLK_DIV, 0x04); regmap_write(es8389->regmap, ES8389_LRCK_DIV1, 0x01); regmap_write(es8389->regmap, ES8389_LRCK_DIV2, 0x00); - regmap_write(es8389->regmap, ES8389_OSC_CLK, 0x00); + regmap_write(es8389->regmap, ES8389_OSC_CLK, 0x10); regmap_write(es8389->regmap, ES8389_ADC_OSR, 0x1F); regmap_write(es8389->regmap, ES8389_ADC_DSP, 0x7F); regmap_write(es8389->regmap, ES8389_ADC_MUTE, 0xC0); @@ -861,13 +1030,13 @@ static int es8389_resume(struct snd_soc_component *component) regcache_cache_only(es8389->regmap, false); regcache_cache_bypass(es8389->regmap, true); regmap_read(es8389->regmap, ES8389_RESET, ®v); - regcache_cache_bypass(es8389->regmap, false); if (regv == 0xff) es8389_init(component); else es8389_set_bias_level(component, SND_SOC_BIAS_ON); + regcache_cache_bypass(es8389->regmap, false); regcache_sync(es8389->regmap); return 0; @@ -913,6 +1082,7 @@ static int es8389_probe(struct snd_soc_component *component) return ret; } + es8389->hpf_freq = ES8389_HPF_DEFAULT; es8389_init(component); es8389_set_bias_level(component, SND_SOC_BIAS_STANDBY); diff --git a/sound/soc/codecs/es8389.h b/sound/soc/codecs/es8389.h index d21e72f876a6..de39e9bf96e9 100644 --- a/sound/soc/codecs/es8389.h +++ b/sound/soc/codecs/es8389.h @@ -106,6 +106,9 @@ #define ES8389_MIC_SEL_MASK (7 << 4) #define ES8389_MIC_DEFAULT (1 << 4) +#define ES8389_HPF_DEFAULT 16 +#define ES8389_HPF_OFFSET 4 + #define ES8389_MASTER_MODE_EN (1 << 0) #define ES8389_TDM_OFF (0 << 0) @@ -116,9 +119,11 @@ #define ES8389_TDM_SLOT (0x70 << 0) #define ES8389_TDM_SHIFT 4 -#define ES8389_MCLK_SOURCE (1 << 6) -#define ES8389_MCLK_PIN (1 << 6) -#define ES8389_SCLK_PIN (0 << 6) +#define ES8389_MCLK_MASK (3 << 6) +#define ES8389_MCLK_FROM_SCLK (1 << 6) +#define ES8389_MCLK_SOURCE ES8389_MCLK_PIN +#define ES8389_MCLK_PIN 0 +#define ES8389_SCLK_PIN 1 /* ES8389_FMT */ #define ES8389_S24_LE (0 << 5) diff --git a/sound/soc/codecs/es9356.c b/sound/soc/codecs/es9356.c index 1122455aab77..80db0f2f4aef 100644 --- a/sound/soc/codecs/es9356.c +++ b/sound/soc/codecs/es9356.c @@ -6,6 +6,7 @@ // // +#include <linux/cleanup.h> #include <linux/device.h> #include <linux/module.h> #include <linux/soundwire/sdw.h> @@ -19,8 +20,6 @@ #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/tlv.h> -#include <sound/sdca_function.h> -#include <sound/sdca_regmap.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <sound/jack.h> @@ -500,16 +499,19 @@ static int es9356_power_state(struct snd_soc_dai *dai, unsigned char ps, unsigne } /* power state changes are not independent across functions */ - mutex_lock(&es9356->pde_lock); - ret = es9356_pde_transition_delay(es9356, func, pde_entity, ps?ps0:ps3); - if (ret) { - regmap_write(es9356->regmap, - SDW_SDCA_CTL(func, pde_entity, ES9356_SDCA_CTL_REQ_POWER_STATE, 0), ps?ps3:ps0); - es9356_pde_transition_delay(es9356, func, pde_entity, ps?ps3:ps0); - } else - dev_dbg(component->dev, "%s PDE is already %d\n", __func__, ps?ps0:ps3); - - mutex_unlock(&es9356->pde_lock); + scoped_guard(mutex, &es9356->pde_lock) { + ret = es9356_pde_transition_delay(es9356, func, pde_entity, ps ? ps0 : ps3); + if (ret) { + regmap_write(es9356->regmap, + SDW_SDCA_CTL(func, pde_entity, + ES9356_SDCA_CTL_REQ_POWER_STATE, 0), + ps ? ps3 : ps0); + es9356_pde_transition_delay(es9356, func, pde_entity, ps ? ps3 : ps0); + } else { + dev_dbg(component->dev, "%s PDE is already %d\n", __func__, + ps ? ps0 : ps3); + } + } if (rate) regmap_write(es9356->regmap, @@ -671,7 +673,7 @@ static int es9356_sdca_mbq_size(struct device *dev, unsigned int reg) } } -static struct regmap_sdw_mbq_cfg es9356_mbq_config = { +static const struct regmap_sdw_mbq_cfg es9356_mbq_config = { .mbq_size = es9356_sdca_mbq_size, }; @@ -1091,9 +1093,8 @@ static int es9356_sdca_dev_system_suspend(struct device *dev) { struct es9356_sdw_priv *es9356 = dev_get_drvdata(dev); - mutex_lock(&es9356->disable_irq_lock); - es9356->disable_irq = true; - mutex_unlock(&es9356->disable_irq_lock); + scoped_guard(mutex, &es9356->disable_irq_lock) + es9356->disable_irq = true; return es9356_sdca_dev_suspend(dev); } diff --git a/sound/soc/codecs/fs-amp-lib.c b/sound/soc/codecs/fs-amp-lib.c index c8f56617e370..a562c72fc524 100644 --- a/sound/soc/codecs/fs-amp-lib.c +++ b/sound/soc/codecs/fs-amp-lib.c @@ -221,7 +221,7 @@ static void fs_print_firmware_info(struct fs_amp_lib *amp_lib) int fs_amp_load_firmware(struct fs_amp_lib *amp_lib, const char *name) { - const struct firmware *cont; + const struct firmware *cont __free(firmware) = NULL; struct fs_fwm_header *hdr; int ret; @@ -237,7 +237,6 @@ int fs_amp_load_firmware(struct fs_amp_lib *amp_lib, const char *name) dev_info(amp_lib->dev, "Loading %s - size: %zu\n", name, cont->size); hdr = devm_kmemdup(amp_lib->dev, cont->data, cont->size, GFP_KERNEL); - release_firmware(cont); if (!hdr) return -ENOMEM; diff --git a/sound/soc/codecs/fs210x.c b/sound/soc/codecs/fs210x.c index d794ff918b6f..510cbeea5b62 100644 --- a/sound/soc/codecs/fs210x.c +++ b/sound/soc/codecs/fs210x.c @@ -4,6 +4,7 @@ // // Copyright (C) 2016-2025 Shanghai FourSemi Semiconductor Co.,Ltd. +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/i2c.h> @@ -771,9 +772,8 @@ static int fs210x_dai_hw_params(struct snd_pcm_substream *substream, if (fs210x->devid == FS2105S_DEVICE_ID && fs210x->srate == 16000) return -EOPNOTSUPP; - mutex_lock(&fs210x->lock); - ret = fs210x_set_hw_params(fs210x); - mutex_unlock(&fs210x->lock); + scoped_guard(mutex, &fs210x->lock) + ret = fs210x_set_hw_params(fs210x); if (ret) dev_err(fs210x->dev, "Failed to set hw params: %d\n", ret); @@ -790,15 +790,11 @@ static int fs210x_dai_mute(struct snd_soc_dai *dai, int mute, int stream) fs210x = snd_soc_component_get_drvdata(dai->component); - mutex_lock(&fs210x->lock); - - if (!fs210x->is_inited || fs210x->is_suspended) { - mutex_unlock(&fs210x->lock); - return 0; + scoped_guard(mutex, &fs210x->lock) { + if (!fs210x->is_inited || fs210x->is_suspended) + return 0; } - mutex_unlock(&fs210x->lock); - if (mute) { cancel_delayed_work_sync(&fs210x->fault_check_work); cancel_delayed_work_sync(&fs210x->start_work); @@ -817,15 +813,11 @@ static int fs210x_dai_trigger(struct snd_pcm_substream *substream, fs210x = snd_soc_component_get_drvdata(dai->component); - mutex_lock(&fs210x->lock); - - if (!fs210x->is_inited || fs210x->is_suspended || fs210x->is_playing) { - mutex_unlock(&fs210x->lock); - return 0; + scoped_guard(mutex, &fs210x->lock) { + if (!fs210x->is_inited || fs210x->is_suspended || fs210x->is_playing) + return 0; } - mutex_unlock(&fs210x->lock); - switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -853,13 +845,11 @@ static void fs210x_start_work(struct work_struct *work) fs210x = container_of(work, struct fs210x_priv, start_work.work); - mutex_lock(&fs210x->lock); + guard(mutex)(&fs210x->lock); ret = fs210x_dev_play(fs210x); if (ret) dev_err(fs210x->dev, "Failed to start playing: %d\n", ret); - - mutex_unlock(&fs210x->lock); } static void fs210x_fault_check_work(struct work_struct *work) @@ -870,15 +860,13 @@ static void fs210x_fault_check_work(struct work_struct *work) fs210x = container_of(work, struct fs210x_priv, fault_check_work.work); - mutex_lock(&fs210x->lock); + scoped_guard(mutex, &fs210x->lock) { + if (!fs210x->is_inited || fs210x->is_suspended || !fs210x->is_playing) + return; - if (!fs210x->is_inited || fs210x->is_suspended || !fs210x->is_playing) { - mutex_unlock(&fs210x->lock); - return; + ret = fs210x_reg_read(fs210x, FS210X_05H_ANASTAT, &status); } - ret = fs210x_reg_read(fs210x, FS210X_05H_ANASTAT, &status); - mutex_unlock(&fs210x->lock); if (ret) return; @@ -991,7 +979,7 @@ static int fs210x_effect_scene_get(struct snd_kcontrol *kcontrol, if (fs210x->scene_id < 1) return -EINVAL; - mutex_lock(&fs210x->lock); + guard(mutex)(&fs210x->lock); /* * FS210x has scene(s) as below: * init scene: id = 0 @@ -1000,7 +988,6 @@ static int fs210x_effect_scene_get(struct snd_kcontrol *kcontrol, */ index = fs210x->scene_id - 1; ucontrol->value.integer.value[0] = index; - mutex_unlock(&fs210x->lock); return 0; } @@ -1019,7 +1006,7 @@ static int fs210x_effect_scene_put(struct snd_kcontrol *kcontrol, return -EINVAL; } - mutex_lock(&fs210x->lock); + guard(mutex)(&fs210x->lock); /* * FS210x has scene(s) as below: @@ -1029,17 +1016,14 @@ static int fs210x_effect_scene_put(struct snd_kcontrol *kcontrol, */ scene_id = ucontrol->value.integer.value[0] + 1; scene_count = fs210x->amp_lib.scene_count - 1; /* Skip init scene */ - if (scene_id < 1 || scene_id > scene_count) { - mutex_unlock(&fs210x->lock); + if (scene_id < 1 || scene_id > scene_count) return -ERANGE; - } if (scene_id != fs210x->scene_id) is_changed = true; if (fs210x->is_suspended) { fs210x->scene_id = scene_id; - mutex_unlock(&fs210x->lock); return is_changed; } @@ -1047,8 +1031,6 @@ static int fs210x_effect_scene_put(struct snd_kcontrol *kcontrol, if (ret) dev_err(fs210x->dev, "Failed to set scene: %d\n", ret); - mutex_unlock(&fs210x->lock); - if (!ret && is_changed) return 1; @@ -1062,12 +1044,10 @@ static int fs210x_playback_event(struct snd_soc_dapm_widget *w, struct fs210x_priv *fs210x = snd_soc_component_get_drvdata(cmpnt); int ret = 0; - mutex_lock(&fs210x->lock); + guard(mutex)(&fs210x->lock); - if (fs210x->is_suspended) { - mutex_unlock(&fs210x->lock); + if (fs210x->is_suspended) return 0; - } switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -1088,8 +1068,6 @@ static int fs210x_playback_event(struct snd_soc_dapm_widget *w, break; } - mutex_unlock(&fs210x->lock); - return ret; } @@ -1220,11 +1198,9 @@ static int fs210x_probe(struct snd_soc_component *cmpnt) if (ret) return ret; - mutex_lock(&fs210x->lock); - ret = fs210x_init_chip(fs210x); - mutex_unlock(&fs210x->lock); + guard(mutex)(&fs210x->lock); - return ret; + return fs210x_init_chip(fs210x); } static void fs210x_remove(struct snd_soc_component *cmpnt) @@ -1251,15 +1227,15 @@ static int fs210x_suspend(struct snd_soc_component *cmpnt) regcache_cache_only(fs210x->regmap, true); - mutex_lock(&fs210x->lock); - fs210x->cur_scene = NULL; - fs210x->is_inited = false; - fs210x->is_playing = false; - fs210x->is_suspended = true; + scoped_guard(mutex, &fs210x->lock) { + fs210x->cur_scene = NULL; + fs210x->is_inited = false; + fs210x->is_playing = false; + fs210x->is_suspended = true; - gpiod_set_value_cansleep(fs210x->gpio_sdz, 1); /* Active */ - fsleep(30000); /* >= 30ms */ - mutex_unlock(&fs210x->lock); + gpiod_set_value_cansleep(fs210x->gpio_sdz, 1); /* Active */ + fsleep(30000); /* >= 30ms */ + } cancel_delayed_work_sync(&fs210x->start_work); cancel_delayed_work_sync(&fs210x->fault_check_work); @@ -1288,14 +1264,11 @@ static int fs210x_resume(struct snd_soc_component *cmpnt) return ret; } - mutex_lock(&fs210x->lock); + guard(mutex)(&fs210x->lock); fs210x->is_suspended = false; - ret = fs210x_init_chip(fs210x); - mutex_unlock(&fs210x->lock); - - return ret; + return fs210x_init_chip(fs210x); } #else #define fs210x_suspend NULL diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 680e341aa7f1..1c06fdbf0e71 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -437,7 +437,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) #ifdef CONFIG_SND_HDA_PATCH_LOADER if (loadable_patch[hda_pvt->dev_index] && *loadable_patch[hda_pvt->dev_index]) { - const struct firmware *fw; + const struct firmware *fw __free(firmware) = NULL; dev_info(&hdev->dev, "Applying patch firmware '%s'\n", loadable_patch[hda_pvt->dev_index]); @@ -451,7 +451,6 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) dev_err(&hdev->dev, "%s: failed to load hda patch %d\n", __func__, ret); goto error_no_pm; } - release_firmware(fw); } } #endif @@ -642,10 +641,8 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev) &hdac_hda_codec, hdac_hda_dais, ARRAY_SIZE(hdac_hda_dais)); - if (ret < 0) { + if (ret < 0) dev_err(&hdev->dev, "%s: failed to register HDA codec %d\n", __func__, ret); - return ret; - } snd_hdac_ext_bus_link_put(hdev->bus, hlink); diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 3220f9226e0b..d9e6fa6d3e99 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -10,6 +10,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#include <linux/cleanup.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/module.h> @@ -537,10 +538,11 @@ static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt( continue; list_for_each_entry(port, &pcm->port_list, head) { - mutex_lock(&pcm->lock); - ret = hdac_hdmi_query_port_connlist(hdev, - port->pin, port); - mutex_unlock(&pcm->lock); + scoped_guard(mutex, &pcm->lock) { + ret = hdac_hdmi_query_port_connlist(hdev, + port->pin, + port); + } if (ret < 0) continue; @@ -640,11 +642,11 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt); if (pcm) { - mutex_lock(&pcm->lock); - pcm->chmap_set = false; - memset(pcm->chmap, 0, sizeof(pcm->chmap)); - pcm->channels = 0; - mutex_unlock(&pcm->lock); + scoped_guard(mutex, &pcm->lock) { + pcm->chmap_set = false; + memset(pcm->chmap, 0, sizeof(pcm->chmap)); + pcm->channels = 0; + } } if (dai_map->port) @@ -922,7 +924,7 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol, if (port == NULL) return -EINVAL; - mutex_lock(&hdmi->pin_mutex); + guard(mutex)(&hdmi->pin_mutex); list_for_each_entry(pcm, &hdmi->pcm_list, head) { if (list_empty(&pcm->port_list)) continue; @@ -945,12 +947,10 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol, list_add_tail(&port->head, &pcm->port_list); if (port->eld.monitor_present && port->eld.eld_valid) { hdac_hdmi_jack_report_sync(pcm, port, true); - mutex_unlock(&hdmi->pin_mutex); return ret; } } } - mutex_unlock(&hdmi->pin_mutex); return ret; } @@ -1274,67 +1274,65 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, * In case of non MST pin, get_eld info API expectes port * to be -1. */ - mutex_lock(&hdmi->pin_mutex); - port->eld.monitor_present = false; + scoped_guard(mutex, &hdmi->pin_mutex) { + port->eld.monitor_present = false; - if (pin->mst_capable) - port_id = port->id; + if (pin->mst_capable) + port_id = port->id; - size = snd_hdac_acomp_get_eld(hdev, pin->nid, port_id, - &port->eld.monitor_present, - port->eld.eld_buffer, - ELD_MAX_SIZE); + size = snd_hdac_acomp_get_eld(hdev, pin->nid, port_id, + &port->eld.monitor_present, + port->eld.eld_buffer, + ELD_MAX_SIZE); - if (size > 0) { - size = min(size, ELD_MAX_SIZE); - if (hdac_hdmi_parse_eld(hdev, port) < 0) - size = -EINVAL; - } + if (size > 0) { + size = min(size, ELD_MAX_SIZE); + if (hdac_hdmi_parse_eld(hdev, port) < 0) + size = -EINVAL; + } - eld_valid = port->eld.eld_valid; + eld_valid = port->eld.eld_valid; - if (size > 0) { - port->eld.eld_valid = true; - port->eld.eld_size = size; - } else { - port->eld.eld_valid = false; - port->eld.eld_size = 0; - } + if (size > 0) { + port->eld.eld_valid = true; + port->eld.eld_size = size; + } else { + port->eld.eld_valid = false; + port->eld.eld_size = 0; + } - eld_changed = (eld_valid != port->eld.eld_valid); + eld_changed = (eld_valid != port->eld.eld_valid); - pcm = hdac_hdmi_get_pcm(hdev, port); + pcm = hdac_hdmi_get_pcm(hdev, port); - if (!port->eld.monitor_present || !port->eld.eld_valid) { + if (!port->eld.monitor_present || !port->eld.eld_valid) { - dev_dbg(&hdev->dev, "%s: disconnect for pin:port %d:%d\n", - __func__, pin->nid, port->id); - - /* - * PCMs are not registered during device probe, so don't - * report jack here. It will be done in usermode mux - * control select. - */ - if (pcm) { - hdac_hdmi_jack_report(pcm, port, false); - schedule_work(&port->dapm_work); - } + dev_dbg(&hdev->dev, "%s: disconnect for pin:port %d:%d\n", + __func__, pin->nid, port->id); - mutex_unlock(&hdmi->pin_mutex); - return; - } + /* + * PCMs are not registered during device probe, so don't + * report jack here. It will be done in usermode mux + * control select. + */ + if (pcm) { + hdac_hdmi_jack_report(pcm, port, false); + schedule_work(&port->dapm_work); + } - if (port->eld.monitor_present && port->eld.eld_valid) { - if (pcm) { - hdac_hdmi_jack_report(pcm, port, true); - schedule_work(&port->dapm_work); + return; } - print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, - port->eld.eld_buffer, port->eld.eld_size, false); + if (port->eld.monitor_present && port->eld.eld_valid) { + if (pcm) { + hdac_hdmi_jack_report(pcm, port, true); + schedule_work(&port->dapm_work); + } + print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, + port->eld.eld_buffer, port->eld.eld_size, false); + } } - mutex_unlock(&hdmi->pin_mutex); if (eld_changed && pcm) snd_ctl_notify(hdmi->card, @@ -1795,13 +1793,12 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdev, int pcm_idx, if (list_empty(&pcm->port_list)) return; - mutex_lock(&pcm->lock); + guard(mutex)(&pcm->lock); pcm->chmap_set = true; memcpy(pcm->chmap, chmap, ARRAY_SIZE(pcm->chmap)); list_for_each_entry(port, &pcm->port_list, head) if (prepared) hdac_hdmi_setup_audio_infoframe(hdev, pcm, port); - mutex_unlock(&pcm->lock); } static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdev, int pcm_idx) @@ -1866,8 +1863,10 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) snd_hdac_ext_bus_link_get(hdev->bus, hlink); hdmi_priv = devm_kzalloc(&hdev->dev, sizeof(*hdmi_priv), GFP_KERNEL); - if (hdmi_priv == NULL) + if (hdmi_priv == NULL) { + snd_hdac_ext_bus_link_put(hdev->bus, hlink); return -ENOMEM; + } snd_hdac_register_chmap_ops(hdev, &hdmi_priv->chmap); hdmi_priv->chmap.ops.get_chmap = hdac_hdmi_get_chmap; @@ -1876,8 +1875,10 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc; hdmi_priv->hdev = hdev; - if (!hdac_id) + if (!hdac_id) { + snd_hdac_ext_bus_link_put(hdev->bus, hlink); return -ENODEV; + } if (hdac_id->driver_data) hdmi_priv->drv_data = @@ -1902,6 +1903,8 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) if (ret < 0) { dev_err(&hdev->dev, "Failed in parse and map nid with err: %d\n", ret); + snd_hdac_ext_bus_link_put(hdev->bus, hlink); + snd_hdac_display_power(hdev->bus, hdev->addr, false); return ret; } snd_hdac_refresh_widgets(hdev); diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 13ae9e83bc21..bc2c22436ba6 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -4,6 +4,7 @@ * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Author: Jyri Sarha <jsarha@ti.com> */ +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/string.h> #include <sound/core.h> @@ -452,31 +453,30 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, if (!((has_playback && tx) || (has_capture && !tx))) return 0; - mutex_lock(&hcp->lock); + guard(mutex)(&hcp->lock); if (hcp->busy) { dev_err(dai->dev, "Only one simultaneous stream supported!\n"); - mutex_unlock(&hcp->lock); return -EINVAL; } if (hcp->hcd.ops->audio_startup) { ret = hcp->hcd.ops->audio_startup(dai->dev->parent, hcp->hcd.data); if (ret) - goto err; + return ret; } if (tx && hcp->hcd.ops->get_eld) { ret = hcp->hcd.ops->get_eld(dai->dev->parent, hcp->hcd.data, hcp->eld, sizeof(hcp->eld)); if (ret) - goto err; + return ret; snd_parse_eld(dai->dev, &hcp->eld_parsed, hcp->eld, sizeof(hcp->eld)); ret = snd_pcm_hw_constraint_eld(substream->runtime, hcp->eld); if (ret) - goto err; + return ret; /* Select chmap supported */ hdmi_codec_eld_chmap(hcp); @@ -484,8 +484,6 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, hcp->busy = true; -err: - mutex_unlock(&hcp->lock); return ret; } @@ -503,9 +501,8 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data); - mutex_lock(&hcp->lock); + guard(mutex)(&hcp->lock); hcp->busy = false; - mutex_unlock(&hcp->lock); } static int hdmi_codec_fill_codec_params(struct snd_soc_dai *dai, diff --git a/sound/soc/codecs/idt821034.c b/sound/soc/codecs/idt821034.c index 084090ccef77..387f17b5f7b3 100644 --- a/sound/soc/codecs/idt821034.c +++ b/sound/soc/codecs/idt821034.c @@ -7,6 +7,7 @@ // Author: Herve Codina <herve.codina@bootlin.com> #include <linux/bitrev.h> +#include <linux/cleanup.h> #include <linux/gpio/driver.h> #include <linux/module.h> #include <linux/slab.h> @@ -413,12 +414,12 @@ static int idt821034_kctrl_gain_get(struct snd_kcontrol *kcontrol, ch = IDT821034_ID_GET_CHAN(mc->reg); - mutex_lock(&idt821034->mutex); - if (IDT821034_ID_IS_OUT(mc->reg)) - val = idt821034->amps.ch[ch].amp_out.gain; - else - val = idt821034->amps.ch[ch].amp_in.gain; - mutex_unlock(&idt821034->mutex); + scoped_guard(mutex, &idt821034->mutex) { + if (IDT821034_ID_IS_OUT(mc->reg)) + val = idt821034->amps.ch[ch].amp_out.gain; + else + val = idt821034->amps.ch[ch].amp_in.gain; + } ucontrol->value.integer.value[0] = val & mask; if (invert) @@ -456,7 +457,7 @@ static int idt821034_kctrl_gain_put(struct snd_kcontrol *kcontrol, ch = IDT821034_ID_GET_CHAN(mc->reg); - mutex_lock(&idt821034->mutex); + guard(mutex)(&idt821034->mutex); if (IDT821034_ID_IS_OUT(mc->reg)) { amp = &idt821034->amps.ch[ch].amp_out; @@ -466,22 +467,18 @@ static int idt821034_kctrl_gain_put(struct snd_kcontrol *kcontrol, gain_type = IDT821034_GAIN_TX; } - if (amp->gain == val) { - ret = 0; - goto end; - } + if (amp->gain == val) + return 0; if (!amp->is_muted) { ret = idt821034_set_gain_channel(idt821034, ch, gain_type, val); if (ret) - goto end; + return ret; } amp->gain = val; - ret = 1; /* The value changed */ -end: - mutex_unlock(&idt821034->mutex); - return ret; + + return 1; } static int idt821034_kctrl_mute_get(struct snd_kcontrol *kcontrol, @@ -495,11 +492,11 @@ static int idt821034_kctrl_mute_get(struct snd_kcontrol *kcontrol, ch = IDT821034_ID_GET_CHAN(id); - mutex_lock(&idt821034->mutex); - is_muted = IDT821034_ID_IS_OUT(id) ? - idt821034->amps.ch[ch].amp_out.is_muted : - idt821034->amps.ch[ch].amp_in.is_muted; - mutex_unlock(&idt821034->mutex); + scoped_guard(mutex, &idt821034->mutex) { + is_muted = IDT821034_ID_IS_OUT(id) ? + idt821034->amps.ch[ch].amp_out.is_muted : + idt821034->amps.ch[ch].amp_in.is_muted; + } ucontrol->value.integer.value[0] = !is_muted; @@ -521,7 +518,7 @@ static int idt821034_kctrl_mute_put(struct snd_kcontrol *kcontrol, ch = IDT821034_ID_GET_CHAN(id); is_mute = !ucontrol->value.integer.value[0]; - mutex_lock(&idt821034->mutex); + guard(mutex)(&idt821034->mutex); if (IDT821034_ID_IS_OUT(id)) { amp = &idt821034->amps.ch[ch].amp_out; @@ -531,21 +528,17 @@ static int idt821034_kctrl_mute_put(struct snd_kcontrol *kcontrol, gain_type = IDT821034_GAIN_TX; } - if (amp->is_muted == is_mute) { - ret = 0; - goto end; - } + if (amp->is_muted == is_mute) + return 0; ret = idt821034_set_gain_channel(idt821034, ch, gain_type, is_mute ? 0 : amp->gain); if (ret) - goto end; + return ret; amp->is_muted = is_mute; - ret = 1; /* The value changed */ -end: - mutex_unlock(&idt821034->mutex); - return ret; + + return 1; } static const DECLARE_TLV_DB_LINEAR(idt821034_gain_in, -300, 1300); @@ -623,24 +616,20 @@ static int idt821034_power_event(struct snd_soc_dapm_widget *w, struct idt821034 *idt821034 = snd_soc_component_get_drvdata(component); unsigned int id = w->shift; u8 power, mask; - int ret; u8 ch; ch = IDT821034_ID_GET_CHAN(id); mask = IDT821034_ID_IS_OUT(id) ? IDT821034_CONF_PWRUP_RX : IDT821034_CONF_PWRUP_TX; - mutex_lock(&idt821034->mutex); + guard(mutex)(&idt821034->mutex); power = idt821034_get_channel_power(idt821034, ch); if (SND_SOC_DAPM_EVENT_ON(event)) power |= mask; else power &= ~mask; - ret = idt821034_set_channel_power(idt821034, ch, power); - - mutex_unlock(&idt821034->mutex); - return ret; + return idt821034_set_channel_power(idt821034, ch, power); } static const struct snd_soc_dapm_widget idt821034_dapm_widgets[] = { @@ -717,9 +706,9 @@ static int idt821034_dai_set_tdm_slot(struct snd_soc_dai *dai, ch = 0; while (mask && ch < IDT821034_NB_CHANNEL) { if (mask & 0x1) { - mutex_lock(&idt821034->mutex); - ret = idt821034_set_channel_ts(idt821034, ch, IDT821034_CH_RX, slot); - mutex_unlock(&idt821034->mutex); + scoped_guard(mutex, &idt821034->mutex) + ret = idt821034_set_channel_ts(idt821034, ch, + IDT821034_CH_RX, slot); if (ret) { dev_err(dai->dev, "ch%u set tx tdm slot failed (%d)\n", ch, ret); @@ -742,9 +731,9 @@ static int idt821034_dai_set_tdm_slot(struct snd_soc_dai *dai, ch = 0; while (mask && ch < IDT821034_NB_CHANNEL) { if (mask & 0x1) { - mutex_lock(&idt821034->mutex); - ret = idt821034_set_channel_ts(idt821034, ch, IDT821034_CH_TX, slot); - mutex_unlock(&idt821034->mutex); + scoped_guard(mutex, &idt821034->mutex) + ret = idt821034_set_channel_ts(idt821034, ch, + IDT821034_CH_TX, slot); if (ret) { dev_err(dai->dev, "ch%u set rx tdm slot failed (%d)\n", ch, ret); @@ -769,9 +758,8 @@ static int idt821034_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct idt821034 *idt821034 = snd_soc_component_get_drvdata(dai->component); u8 conf; - int ret; - mutex_lock(&idt821034->mutex); + guard(mutex)(&idt821034->mutex); conf = idt821034_get_codec_conf(idt821034); @@ -785,13 +773,10 @@ static int idt821034_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) default: dev_err(dai->dev, "Unsupported DAI format 0x%x\n", fmt & SND_SOC_DAIFMT_FORMAT_MASK); - ret = -EINVAL; - goto end; + return -EINVAL; } - ret = idt821034_set_codec_conf(idt821034, conf); -end: - mutex_unlock(&idt821034->mutex); - return ret; + + return idt821034_set_codec_conf(idt821034, conf); } static int idt821034_dai_hw_params(struct snd_pcm_substream *substream, @@ -800,9 +785,8 @@ static int idt821034_dai_hw_params(struct snd_pcm_substream *substream, { struct idt821034 *idt821034 = snd_soc_component_get_drvdata(dai->component); u8 conf; - int ret; - mutex_lock(&idt821034->mutex); + guard(mutex)(&idt821034->mutex); conf = idt821034_get_codec_conf(idt821034); @@ -816,13 +800,10 @@ static int idt821034_dai_hw_params(struct snd_pcm_substream *substream, default: dev_err(dai->dev, "Unsupported PCM format 0x%x\n", params_format(params)); - ret = -EINVAL; - goto end; + return -EINVAL; } - ret = idt821034_set_codec_conf(idt821034, conf); -end: - mutex_unlock(&idt821034->mutex); - return ret; + + return idt821034_set_codec_conf(idt821034, conf); } static const unsigned int idt821034_sample_bits[] = {8}; @@ -897,11 +878,11 @@ static int idt821034_reset_audio(struct idt821034 *idt821034) int ret; u8 i; - mutex_lock(&idt821034->mutex); + guard(mutex)(&idt821034->mutex); ret = idt821034_set_codec_conf(idt821034, 0); if (ret) - goto end; + return ret; for (i = 0; i < IDT821034_NB_CHANNEL; i++) { idt821034->amps.ch[i].amp_out.gain = IDT821034_GAIN_OUT_INIT_RAW; @@ -909,24 +890,21 @@ static int idt821034_reset_audio(struct idt821034 *idt821034) ret = idt821034_set_gain_channel(idt821034, i, IDT821034_GAIN_RX, idt821034->amps.ch[i].amp_out.gain); if (ret) - goto end; + return ret; idt821034->amps.ch[i].amp_in.gain = IDT821034_GAIN_IN_INIT_RAW; idt821034->amps.ch[i].amp_in.is_muted = false; ret = idt821034_set_gain_channel(idt821034, i, IDT821034_GAIN_TX, idt821034->amps.ch[i].amp_in.gain); if (ret) - goto end; + return ret; ret = idt821034_set_channel_power(idt821034, i, 0); if (ret) - goto end; + return ret; } - ret = 0; -end: - mutex_unlock(&idt821034->mutex); - return ret; + return 0; } static int idt821034_component_probe(struct snd_soc_component *component) @@ -965,7 +943,7 @@ static int idt821034_chip_gpio_set(struct gpio_chip *c, unsigned int offset, u8 slic_raw; int ret; - mutex_lock(&idt821034->mutex); + guard(mutex)(&idt821034->mutex); slic_raw = idt821034_get_written_slic_raw(idt821034, ch); if (val) @@ -974,8 +952,6 @@ static int idt821034_chip_gpio_set(struct gpio_chip *c, unsigned int offset, slic_raw &= ~mask; ret = idt821034_write_slic_raw(idt821034, ch, slic_raw); - mutex_unlock(&idt821034->mutex); - if (ret) dev_err(&idt821034->spi->dev, "set gpio %d (%u, 0x%x) failed (%d)\n", offset, ch, mask, ret); @@ -991,9 +967,8 @@ static int idt821034_chip_gpio_get(struct gpio_chip *c, unsigned int offset) u8 slic_raw; int ret; - mutex_lock(&idt821034->mutex); - ret = idt821034_read_slic_raw(idt821034, ch, &slic_raw); - mutex_unlock(&idt821034->mutex); + scoped_guard(mutex, &idt821034->mutex) + ret = idt821034_read_slic_raw(idt821034, ch, &slic_raw); if (ret) { dev_err(&idt821034->spi->dev, "get gpio %d (%u, 0x%x) failed (%d)\n", offset, ch, mask, ret); @@ -1015,9 +990,8 @@ static int idt821034_chip_get_direction(struct gpio_chip *c, unsigned int offset struct idt821034 *idt821034 = gpiochip_get_data(c); u8 slic_dir; - mutex_lock(&idt821034->mutex); + guard(mutex)(&idt821034->mutex); slic_dir = idt821034_get_slic_conf(idt821034, ch); - mutex_unlock(&idt821034->mutex); return slic_dir & mask ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT; } @@ -1034,7 +1008,7 @@ static int idt821034_chip_direction_input(struct gpio_chip *c, unsigned int offs if (mask & ~(IDT821034_SLIC_IO1_IN | IDT821034_SLIC_IO0_IN)) return -EPERM; - mutex_lock(&idt821034->mutex); + guard(mutex)(&idt821034->mutex); slic_conf = idt821034_get_slic_conf(idt821034, ch) | mask; @@ -1044,7 +1018,6 @@ static int idt821034_chip_direction_input(struct gpio_chip *c, unsigned int offs offset, ch, mask, ret); } - mutex_unlock(&idt821034->mutex); return ret; } @@ -1060,7 +1033,7 @@ static int idt821034_chip_direction_output(struct gpio_chip *c, unsigned int off if (ret) return ret; - mutex_lock(&idt821034->mutex); + guard(mutex)(&idt821034->mutex); slic_conf = idt821034_get_slic_conf(idt821034, ch) & ~mask; @@ -1070,7 +1043,6 @@ static int idt821034_chip_direction_output(struct gpio_chip *c, unsigned int off offset, ch, mask, ret); } - mutex_unlock(&idt821034->mutex); return ret; } @@ -1079,24 +1051,22 @@ static int idt821034_reset_gpio(struct idt821034 *idt821034) int ret; u8 i; - mutex_lock(&idt821034->mutex); + guard(mutex)(&idt821034->mutex); /* IO0 and IO1 as input for all channels and output IO set to 0 */ for (i = 0; i < IDT821034_NB_CHANNEL; i++) { ret = idt821034_set_slic_conf(idt821034, i, IDT821034_SLIC_IO1_IN | IDT821034_SLIC_IO0_IN); if (ret) - goto end; + return ret; ret = idt821034_write_slic_raw(idt821034, i, 0); if (ret) - goto end; + return ret; } - ret = 0; -end: - mutex_unlock(&idt821034->mutex); - return ret; + + return 0; } static int idt821034_gpio_init(struct idt821034 *idt821034) diff --git a/sound/soc/codecs/lochnagar-sc.c b/sound/soc/codecs/lochnagar-sc.c index a3d6318c9050..dadb4a6c287f 100644 --- a/sound/soc/codecs/lochnagar-sc.c +++ b/sound/soc/codecs/lochnagar-sc.c @@ -137,15 +137,23 @@ static int lochnagar_sc_set_usb_fmt(struct snd_soc_dai *dai, unsigned int fmt) return lochnagar_sc_check_fmt(dai, fmt, SND_SOC_DAIFMT_CBP_CFP); } +static const u64 lochnagar_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_NB_NF; + static const struct snd_soc_dai_ops lochnagar_sc_line_ops = { .startup = lochnagar_sc_line_startup, .shutdown = lochnagar_sc_line_shutdown, .set_fmt = lochnagar_sc_set_line_fmt, + .auto_selectable_formats = &lochnagar_selectable_formats, + .num_auto_selectable_formats = 1, }; static const struct snd_soc_dai_ops lochnagar_sc_usb_ops = { .startup = lochnagar_sc_startup, .set_fmt = lochnagar_sc_set_usb_fmt, + .auto_selectable_formats = &lochnagar_selectable_formats, + .num_auto_selectable_formats = 1, }; static struct snd_soc_dai_driver lochnagar_sc_dai[] = { diff --git a/sound/soc/codecs/lpass-macro-common.c b/sound/soc/codecs/lpass-macro-common.c index 6e3b8d0897dd..7e59616ed7bc 100644 --- a/sound/soc/codecs/lpass-macro-common.c +++ b/sound/soc/codecs/lpass-macro-common.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only // Copyright (c) 2022, The Linux Foundation. All rights reserved. +#include <linux/cleanup.h> #include <linux/export.h> #include <linux/module.h> #include <linux/init.h> @@ -71,21 +72,16 @@ EXPORT_SYMBOL_GPL(lpass_macro_pds_exit); void lpass_macro_set_codec_version(enum lpass_codec_version version) { - mutex_lock(&lpass_codec_mutex); + guard(mutex)(&lpass_codec_mutex); lpass_codec_version = version; - mutex_unlock(&lpass_codec_mutex); } EXPORT_SYMBOL_GPL(lpass_macro_set_codec_version); enum lpass_codec_version lpass_macro_get_codec_version(void) { - enum lpass_codec_version ver; + guard(mutex)(&lpass_codec_mutex); - mutex_lock(&lpass_codec_mutex); - ver = lpass_codec_version; - mutex_unlock(&lpass_codec_mutex); - - return ver; + return lpass_codec_version; } EXPORT_SYMBOL_GPL(lpass_macro_get_codec_version); diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 6233aa9f5bc6..282a6aaa9986 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -6,6 +6,7 @@ #include <linux/init.h> #include <linux/io.h> #include <linux/platform_device.h> +#include <linux/pm_clock.h> #include <linux/pm_runtime.h> #include <linux/clk.h> #include <sound/soc.h> @@ -2030,9 +2031,10 @@ static struct snd_soc_dai_driver rx_macro_dai[] = { }, }; -static void rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable) +static int rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable) { struct regmap *regmap = rx->regmap; + int ret; if (mclk_enable) { if (rx->rx_mclk_users == 0) { @@ -2047,14 +2049,16 @@ static void rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable) CDC_RX_FS_MCLK_CNT_EN_MASK, CDC_RX_FS_MCLK_CNT_ENABLE); regcache_mark_dirty(regmap); - regcache_sync(regmap); + ret = regcache_sync(regmap); + if (ret) + return ret; } rx->rx_mclk_users++; } else { if (rx->rx_mclk_users <= 0) { dev_err(rx->dev, "%s: clock already disabled\n", __func__); rx->rx_mclk_users = 0; - return; + return 0; } rx->rx_mclk_users--; if (rx->rx_mclk_users == 0) { @@ -2068,6 +2072,8 @@ static void rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable) CDC_RX_CLK_MCLK2_EN_MASK, 0x0); } } + + return 0; } static int rx_macro_mclk_event(struct snd_soc_dapm_widget *w, @@ -2079,11 +2085,9 @@ static int rx_macro_mclk_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: - rx_macro_mclk_enable(rx, true); - break; + return rx_macro_mclk_enable(rx, true); case SND_SOC_DAPM_POST_PMD: - rx_macro_mclk_enable(rx, false); - break; + return rx_macro_mclk_enable(rx, false); default: dev_err(component->dev, "%s: invalid DAPM event %d\n", __func__, event); ret = -EINVAL; @@ -3671,14 +3675,16 @@ static int swclk_gate_enable(struct clk_hw *hw) struct rx_macro *rx = to_rx_macro(hw); int ret; - ret = clk_prepare_enable(rx->mclk); + ret = pm_runtime_resume_and_get(rx->dev); + if (ret < 0) + return ret; + + ret = rx_macro_mclk_enable(rx, true); if (ret) { - dev_err(rx->dev, "unable to prepare mclk\n"); + clk_disable_unprepare(rx->mclk); return ret; } - rx_macro_mclk_enable(rx, true); - regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL, CDC_RX_SWR_CLK_EN_MASK, 1); @@ -3693,7 +3699,7 @@ static void swclk_gate_disable(struct clk_hw *hw) CDC_RX_SWR_CLK_EN_MASK, 0); rx_macro_mclk_enable(rx, false); - clk_disable_unprepare(rx->mclk); + pm_runtime_put_autosuspend(rx->dev); } static int swclk_gate_is_enabled(struct clk_hw *hw) @@ -3864,28 +3870,31 @@ static int rx_macro_probe(struct platform_device *pdev) rx->dev = dev; /* set MCLK and NPL rates */ - clk_set_rate(rx->mclk, MCLK_FREQ); - clk_set_rate(rx->npl, MCLK_FREQ); - - ret = clk_prepare_enable(rx->macro); + ret = clk_set_rate(rx->mclk, MCLK_FREQ); if (ret) return ret; - ret = clk_prepare_enable(rx->dcodec); + ret = clk_set_rate(rx->npl, MCLK_FREQ); if (ret) - goto err_dcodec; + return ret; - ret = clk_prepare_enable(rx->mclk); + ret = devm_pm_clk_create(dev); if (ret) - goto err_mclk; + return ret; - ret = clk_prepare_enable(rx->npl); + ret = of_pm_clk_add_clks(dev); + if (ret < 0) + return ret; + + pm_runtime_set_autosuspend_delay(dev, 100); + pm_runtime_use_autosuspend(dev); + ret = devm_pm_runtime_enable(dev); if (ret) - goto err_npl; + return ret; - ret = clk_prepare_enable(rx->fsgen); + ret = pm_runtime_resume_and_get(dev); if (ret) - goto err_fsgen; + return ret; /* reset swr block */ regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL, @@ -3902,46 +3911,25 @@ static int rx_macro_probe(struct platform_device *pdev) rx_macro_dai, ARRAY_SIZE(rx_macro_dai)); if (ret) - goto err_clkout; - - - 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); + goto err_rpm_put; ret = rx_macro_register_mclk_output(rx); if (ret) - goto err_clkout; + goto err_rpm_put; + + ret = pm_runtime_put_autosuspend(dev); + if (ret < 0) + dev_warn(dev, "runtime PM put failed after probe: %d\n", ret); return 0; -err_clkout: - clk_disable_unprepare(rx->fsgen); -err_fsgen: - clk_disable_unprepare(rx->npl); -err_npl: - clk_disable_unprepare(rx->mclk); -err_mclk: - clk_disable_unprepare(rx->dcodec); -err_dcodec: - clk_disable_unprepare(rx->macro); +err_rpm_put: + if (pm_runtime_put_sync_suspend(dev) < 0) + dev_warn(dev, "runtime PM sync suspend failed in probe unwind\n"); return ret; } -static void rx_macro_remove(struct platform_device *pdev) -{ - struct rx_macro *rx = dev_get_drvdata(&pdev->dev); - - clk_disable_unprepare(rx->mclk); - clk_disable_unprepare(rx->npl); - clk_disable_unprepare(rx->fsgen); - clk_disable_unprepare(rx->macro); - clk_disable_unprepare(rx->dcodec); -} - static const struct of_device_id rx_macro_dt_match[] = { { .compatible = "qcom,sc7280-lpass-rx-macro", @@ -3969,13 +3957,17 @@ MODULE_DEVICE_TABLE(of, rx_macro_dt_match); static int rx_macro_runtime_suspend(struct device *dev) { struct rx_macro *rx = dev_get_drvdata(dev); + int ret; regcache_cache_only(rx->regmap, true); - regcache_mark_dirty(rx->regmap); - clk_disable_unprepare(rx->fsgen); - clk_disable_unprepare(rx->npl); - clk_disable_unprepare(rx->mclk); + ret = pm_clk_suspend(dev); + if (ret) { + regcache_cache_only(rx->regmap, false); + return ret; + } + + regcache_mark_dirty(rx->regmap); return 0; } @@ -3985,33 +3977,23 @@ static int rx_macro_runtime_resume(struct device *dev) struct rx_macro *rx = dev_get_drvdata(dev); int ret; - ret = clk_prepare_enable(rx->mclk); + ret = pm_clk_resume(dev); if (ret) { - dev_err(dev, "unable to prepare mclk\n"); + regcache_cache_only(rx->regmap, true); + regcache_mark_dirty(rx->regmap); return ret; } - ret = clk_prepare_enable(rx->npl); - if (ret) { - dev_err(dev, "unable to prepare mclkx2\n"); - goto err_npl; - } - - ret = clk_prepare_enable(rx->fsgen); + regcache_cache_only(rx->regmap, false); + ret = regcache_sync(rx->regmap); if (ret) { - dev_err(dev, "unable to prepare fsgen\n"); - goto err_fsgen; + regcache_cache_only(rx->regmap, true); + regcache_mark_dirty(rx->regmap); + pm_clk_suspend(dev); + return ret; } - regcache_cache_only(rx->regmap, false); - regcache_sync(rx->regmap); return 0; -err_fsgen: - clk_disable_unprepare(rx->npl); -err_npl: - clk_disable_unprepare(rx->mclk); - - return ret; } static const struct dev_pm_ops rx_macro_pm_ops = { @@ -4026,7 +4008,6 @@ static struct platform_driver rx_macro_driver = { .pm = pm_ptr(&rx_macro_pm_ops), }, .probe = rx_macro_probe, - .remove = rx_macro_remove, }; module_platform_driver(rx_macro_driver); diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index 0cbf50647ff5..a8e83eb60ba2 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -6,6 +6,7 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/platform_device.h> +#include <linux/pm_clock.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> #include <sound/soc.h> @@ -614,6 +615,7 @@ static int tx_macro_mclk_enable(struct tx_macro *tx, bool mclk_enable) { struct regmap *regmap = tx->regmap; + int ret; if (mclk_enable) { if (tx->tx_mclk_users == 0) { @@ -626,7 +628,9 @@ static int tx_macro_mclk_enable(struct tx_macro *tx, CDC_TX_FS_CNT_EN_MASK, CDC_TX_FS_CNT_ENABLE); regcache_mark_dirty(regmap); - regcache_sync(regmap); + ret = regcache_sync(regmap); + if (ret) + return ret; } tx->tx_mclk_users++; } else { @@ -739,11 +743,9 @@ static int tx_macro_mclk_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: - tx_macro_mclk_enable(tx, true); - break; + return tx_macro_mclk_enable(tx, true); case SND_SOC_DAPM_POST_PMD: - tx_macro_mclk_enable(tx, false); - break; + return tx_macro_mclk_enable(tx, false); default: break; } @@ -2149,17 +2151,20 @@ static int swclk_gate_enable(struct clk_hw *hw) struct regmap *regmap = tx->regmap; int ret; - ret = clk_prepare_enable(tx->mclk); + ret = pm_runtime_resume_and_get(tx->dev); + if (ret < 0) + return ret; + + ret = tx_macro_mclk_enable(tx, true); if (ret) { - dev_err(tx->dev, "failed to enable mclk\n"); + pm_runtime_put_autosuspend(tx->dev); return ret; } - tx_macro_mclk_enable(tx, true); - regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL, CDC_TX_SWR_CLK_EN_MASK, CDC_TX_SWR_CLK_ENABLE); + return 0; } @@ -2172,7 +2177,7 @@ static void swclk_gate_disable(struct clk_hw *hw) CDC_TX_SWR_CLK_EN_MASK, 0x0); tx_macro_mclk_enable(tx, false); - clk_disable_unprepare(tx->mclk); + pm_runtime_put_autosuspend(tx->dev); } static int swclk_gate_is_enabled(struct clk_hw *hw) @@ -2315,28 +2320,31 @@ static int tx_macro_probe(struct platform_device *pdev) tx->active_decimator[TX_MACRO_AIF3_CAP] = -1; /* set MCLK and NPL rates */ - clk_set_rate(tx->mclk, MCLK_FREQ); - clk_set_rate(tx->npl, MCLK_FREQ); - - ret = clk_prepare_enable(tx->macro); + ret = clk_set_rate(tx->mclk, MCLK_FREQ); if (ret) goto err; - ret = clk_prepare_enable(tx->dcodec); + ret = clk_set_rate(tx->npl, MCLK_FREQ); if (ret) - goto err_dcodec; + goto err; - ret = clk_prepare_enable(tx->mclk); + ret = devm_pm_clk_create(dev); if (ret) - goto err_mclk; + goto err; - ret = clk_prepare_enable(tx->npl); - if (ret) - goto err_npl; + ret = of_pm_clk_add_clks(dev); + if (ret < 0) + goto err; - ret = clk_prepare_enable(tx->fsgen); + pm_runtime_set_autosuspend_delay(dev, 100); + pm_runtime_use_autosuspend(dev); + ret = devm_pm_runtime_enable(dev); if (ret) - goto err_fsgen; + goto err; + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + goto err; /* reset soundwire block */ @@ -2356,30 +2364,21 @@ static int tx_macro_probe(struct platform_device *pdev) tx_macro_dai, ARRAY_SIZE(tx_macro_dai)); if (ret) - goto err_clkout; - - 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); + goto err_rpm_put; ret = tx_macro_register_mclk_output(tx); if (ret) - goto err_clkout; + goto err_rpm_put; + + ret = pm_runtime_put_autosuspend(dev); + if (ret < 0) + dev_warn(dev, "runtime PM put failed after probe: %d\n", ret); return 0; -err_clkout: - clk_disable_unprepare(tx->fsgen); -err_fsgen: - clk_disable_unprepare(tx->npl); -err_npl: - clk_disable_unprepare(tx->mclk); -err_mclk: - clk_disable_unprepare(tx->dcodec); -err_dcodec: - clk_disable_unprepare(tx->macro); +err_rpm_put: + if (pm_runtime_put_sync_suspend(dev) < 0) + dev_warn(dev, "runtime PM sync suspend failed in probe unwind\n"); err: lpass_macro_pds_exit(tx->pds); @@ -2390,25 +2389,23 @@ static void tx_macro_remove(struct platform_device *pdev) { struct tx_macro *tx = dev_get_drvdata(&pdev->dev); - clk_disable_unprepare(tx->macro); - clk_disable_unprepare(tx->dcodec); - clk_disable_unprepare(tx->mclk); - clk_disable_unprepare(tx->npl); - clk_disable_unprepare(tx->fsgen); - lpass_macro_pds_exit(tx->pds); } static int tx_macro_runtime_suspend(struct device *dev) { struct tx_macro *tx = dev_get_drvdata(dev); + int ret; regcache_cache_only(tx->regmap, true); - regcache_mark_dirty(tx->regmap); - clk_disable_unprepare(tx->fsgen); - clk_disable_unprepare(tx->npl); - clk_disable_unprepare(tx->mclk); + ret = pm_clk_suspend(dev); + if (ret) { + regcache_cache_only(tx->regmap, false); + return ret; + } + + regcache_mark_dirty(tx->regmap); return 0; } @@ -2418,34 +2415,23 @@ static int tx_macro_runtime_resume(struct device *dev) struct tx_macro *tx = dev_get_drvdata(dev); int ret; - ret = clk_prepare_enable(tx->mclk); + ret = pm_clk_resume(dev); if (ret) { - dev_err(dev, "unable to prepare mclk\n"); + regcache_cache_only(tx->regmap, true); + regcache_mark_dirty(tx->regmap); return ret; } - ret = clk_prepare_enable(tx->npl); - if (ret) { - dev_err(dev, "unable to prepare npl\n"); - goto err_npl; - } - - ret = clk_prepare_enable(tx->fsgen); + regcache_cache_only(tx->regmap, false); + ret = regcache_sync(tx->regmap); if (ret) { - dev_err(dev, "unable to prepare fsgen\n"); - goto err_fsgen; + regcache_cache_only(tx->regmap, true); + regcache_mark_dirty(tx->regmap); + pm_clk_suspend(dev); + return ret; } - regcache_cache_only(tx->regmap, false); - regcache_sync(tx->regmap); - return 0; -err_fsgen: - clk_disable_unprepare(tx->npl); -err_npl: - clk_disable_unprepare(tx->mclk); - - return ret; } static const struct dev_pm_ops tx_macro_pm_ops = { diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index 58a5798823d7..dbc5795b9273 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -10,6 +10,7 @@ #include <linux/of_clk.h> #include <linux/of_platform.h> #include <linux/platform_device.h> +#include <linux/pm_clock.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> @@ -1351,34 +1352,43 @@ static int fsgen_gate_enable(struct clk_hw *hw) { struct va_macro *va = to_va_macro(hw); struct regmap *regmap = va->regmap; - int ret; + int ret, rpm_ret; - if (va->has_swr_master) { - ret = clk_prepare_enable(va->mclk); - if (ret) - return ret; - } + ret = pm_runtime_resume_and_get(va->dev); + if (ret < 0) + return ret; ret = va_macro_mclk_enable(va, true); + if (ret) { + rpm_ret = pm_runtime_put_autosuspend(va->dev); + if (rpm_ret < 0) + dev_warn(va->dev, + "runtime PM put failed in fsgen enable unwind: %d\n", + rpm_ret); + return ret; + } if (va->has_swr_master) regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL, CDC_VA_SWR_CLK_EN_MASK, CDC_VA_SWR_CLK_ENABLE); - return ret; + return 0; } static void fsgen_gate_disable(struct clk_hw *hw) { struct va_macro *va = to_va_macro(hw); struct regmap *regmap = va->regmap; + int ret; if (va->has_swr_master) regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL, CDC_VA_SWR_CLK_EN_MASK, 0x0); va_macro_mclk_enable(va, false); - if (va->has_swr_master) - clk_disable_unprepare(va->mclk); + + ret = pm_runtime_put_autosuspend(va->dev); + if (ret < 0) + dev_warn(va->dev, "runtime PM put failed in fsgen disable: %d\n", ret); } static int fsgen_gate_is_enabled(struct clk_hw *hw) @@ -1539,6 +1549,7 @@ static int va_macro_probe(struct platform_device *pdev) void __iomem *base; u32 sample_rate = 0; int ret; + int rpm_ret; va = devm_kzalloc(dev, sizeof(*va), GFP_KERNEL); if (!va) @@ -1594,7 +1605,9 @@ static int va_macro_probe(struct platform_device *pdev) va->has_npl_clk = data->has_npl_clk; /* mclk rate */ - clk_set_rate(va->mclk, 2 * VA_MACRO_MCLK_FREQ); + ret = clk_set_rate(va->mclk, 2 * VA_MACRO_MCLK_FREQ); + if (ret) + goto err; if (va->has_npl_clk) { va->npl = devm_clk_get(dev, "npl"); @@ -1603,25 +1616,29 @@ static int va_macro_probe(struct platform_device *pdev) goto err; } - clk_set_rate(va->npl, 2 * VA_MACRO_MCLK_FREQ); + ret = clk_set_rate(va->npl, 2 * VA_MACRO_MCLK_FREQ); + if (ret) + goto err; } - ret = clk_prepare_enable(va->macro); + ret = devm_pm_clk_create(dev); if (ret) goto err; - ret = clk_prepare_enable(va->dcodec); - if (ret) - goto err_dcodec; + ret = of_pm_clk_add_clks(dev); + if (ret < 0) + goto err; - ret = clk_prepare_enable(va->mclk); + pm_runtime_set_autosuspend_delay(dev, 100); + pm_runtime_use_autosuspend(dev); + ret = devm_pm_runtime_enable(dev); if (ret) - goto err_mclk; + goto err; - if (va->has_npl_clk) { - ret = clk_prepare_enable(va->npl); - if (ret) - goto err_npl; + rpm_ret = pm_runtime_resume_and_get(dev); + if (rpm_ret < 0) { + ret = rpm_ret; + goto err; } /** @@ -1634,7 +1651,7 @@ static int va_macro_probe(struct platform_device *pdev) /* read version from register */ ret = va_macro_set_lpass_codec_version(va); if (ret) - goto err_clkout; + goto err_rpm_put; } if (va->has_swr_master) { @@ -1664,35 +1681,28 @@ static int va_macro_probe(struct platform_device *pdev) va_macro_dais, ARRAY_SIZE(va_macro_dais)); if (ret) - goto err_clkout; - - 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); + goto err_rpm_put; ret = va_macro_register_fsgen_output(va); if (ret) - goto err_clkout; + goto err_rpm_put; va->fsgen = devm_clk_hw_get_clk(dev, &va->hw, "fsgen"); if (IS_ERR(va->fsgen)) { ret = PTR_ERR(va->fsgen); - goto err_clkout; + goto err_rpm_put; } + rpm_ret = pm_runtime_put_autosuspend(dev); + if (rpm_ret < 0) + dev_warn(dev, "runtime PM put failed after probe: %d\n", rpm_ret); + return 0; -err_clkout: - if (va->has_npl_clk) - clk_disable_unprepare(va->npl); -err_npl: - clk_disable_unprepare(va->mclk); -err_mclk: - clk_disable_unprepare(va->dcodec); -err_dcodec: - clk_disable_unprepare(va->macro); +err_rpm_put: + rpm_ret = pm_runtime_put_sync_suspend(dev); + if (rpm_ret < 0) + dev_warn(dev, "runtime PM sync suspend failed in probe unwind: %d\n", rpm_ret); err: lpass_macro_pds_exit(va->pds); @@ -1703,27 +1713,23 @@ static void va_macro_remove(struct platform_device *pdev) { struct va_macro *va = dev_get_drvdata(&pdev->dev); - if (va->has_npl_clk) - clk_disable_unprepare(va->npl); - - clk_disable_unprepare(va->mclk); - clk_disable_unprepare(va->dcodec); - clk_disable_unprepare(va->macro); - lpass_macro_pds_exit(va->pds); } static int va_macro_runtime_suspend(struct device *dev) { struct va_macro *va = dev_get_drvdata(dev); + int ret; regcache_cache_only(va->regmap, true); - regcache_mark_dirty(va->regmap); - if (va->has_npl_clk) - clk_disable_unprepare(va->npl); + ret = pm_clk_suspend(dev); + if (ret) { + regcache_cache_only(va->regmap, false); + return ret; + } - clk_disable_unprepare(va->mclk); + regcache_mark_dirty(va->regmap); return 0; } @@ -1731,25 +1737,28 @@ static int va_macro_runtime_suspend(struct device *dev) static int va_macro_runtime_resume(struct device *dev) { struct va_macro *va = dev_get_drvdata(dev); - int ret; + int ret, sret; - ret = clk_prepare_enable(va->mclk); + ret = pm_clk_resume(dev); if (ret) { - dev_err(va->dev, "unable to prepare mclk\n"); + regcache_cache_only(va->regmap, true); + regcache_mark_dirty(va->regmap); return ret; } - if (va->has_npl_clk) { - ret = clk_prepare_enable(va->npl); - if (ret) { - clk_disable_unprepare(va->mclk); - dev_err(va->dev, "unable to prepare npl\n"); - return ret; - } - } - regcache_cache_only(va->regmap, false); - regcache_sync(va->regmap); + + ret = regcache_sync(va->regmap); + if (ret) { + regcache_cache_only(va->regmap, true); + regcache_mark_dirty(va->regmap); + sret = pm_clk_suspend(dev); + if (sret) + dev_err(va->dev, + "failed to suspend clocks after regcache sync failure: %d\n", + sret); + return ret; + } return 0; } diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index af521e0988db..cfd2ac0a6cda 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -12,6 +12,7 @@ #include <linux/clk-provider.h> #include <sound/soc.h> #include <sound/soc-dapm.h> +#include <linux/pm_clock.h> #include <linux/pm_runtime.h> #include <linux/of_platform.h> #include <sound/tlv.h> @@ -2529,15 +2530,13 @@ static const struct snd_soc_dapm_route wsa_audio_map[] = { static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable) { struct regmap *regmap = wsa->regmap; + int ret; if (enable) { - int ret; - - ret = clk_prepare_enable(wsa->mclk); - if (ret) { - dev_err(wsa->dev, "failed to enable mclk\n"); + ret = pm_runtime_resume_and_get(wsa->dev); + if (ret < 0) return ret; - } + wsa_macro_mclk_enable(wsa, true); regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, @@ -2548,7 +2547,10 @@ static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable) regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, CDC_WSA_SWR_CLK_EN_MASK, 0); wsa_macro_mclk_enable(wsa, false); - clk_disable_unprepare(wsa->mclk); + + ret = pm_runtime_put_autosuspend(wsa->dev); + if (ret < 0) + dev_warn(wsa->dev, "runtime PM put failed: %d\n", ret); } return 0; @@ -2656,7 +2658,7 @@ static int wsa_macro_register_mclk_output(struct wsa_macro *wsa) init.num_parents = 1; wsa->hw.init = &init; hw = &wsa->hw; - ret = clk_hw_register(wsa->dev, hw); + ret = devm_clk_hw_register(wsa->dev, hw); if (ret) return ret; @@ -2771,28 +2773,31 @@ static int wsa_macro_probe(struct platform_device *pdev) wsa->dev = dev; /* set MCLK and NPL rates */ - clk_set_rate(wsa->mclk, WSA_MACRO_MCLK_FREQ); - clk_set_rate(wsa->npl, WSA_MACRO_MCLK_FREQ); - - ret = clk_prepare_enable(wsa->macro); + ret = clk_set_rate(wsa->mclk, WSA_MACRO_MCLK_FREQ); if (ret) - goto err; + return ret; - ret = clk_prepare_enable(wsa->dcodec); + ret = clk_set_rate(wsa->npl, WSA_MACRO_MCLK_FREQ); if (ret) - goto err_dcodec; + return ret; - ret = clk_prepare_enable(wsa->mclk); + ret = devm_pm_clk_create(dev); if (ret) - goto err_mclk; + return ret; - ret = clk_prepare_enable(wsa->npl); - if (ret) - goto err_npl; + ret = of_pm_clk_add_clks(dev); + if (ret < 0) + return ret; - ret = clk_prepare_enable(wsa->fsgen); + pm_runtime_set_autosuspend_delay(dev, 100); + pm_runtime_use_autosuspend(dev); + ret = devm_pm_runtime_enable(dev); if (ret) - goto err_fsgen; + return ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return ret; /* reset swr ip */ regmap_update_bits(wsa->regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, @@ -2809,56 +2814,37 @@ static int wsa_macro_probe(struct platform_device *pdev) wsa_macro_dai, ARRAY_SIZE(wsa_macro_dai)); if (ret) - goto err_clkout; - - 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); + goto err_rpm_put; ret = wsa_macro_register_mclk_output(wsa); if (ret) - goto err_clkout; + goto err_rpm_put; - return 0; + ret = pm_runtime_put_autosuspend(dev); + if (ret < 0) + dev_warn(dev, "runtime PM put failed after probe: %d\n", ret); -err_clkout: - clk_disable_unprepare(wsa->fsgen); -err_fsgen: - clk_disable_unprepare(wsa->npl); -err_npl: - clk_disable_unprepare(wsa->mclk); -err_mclk: - clk_disable_unprepare(wsa->dcodec); -err_dcodec: - clk_disable_unprepare(wsa->macro); -err: + return 0; +err_rpm_put: + if (pm_runtime_put_sync_suspend(dev) < 0) + dev_warn(dev, "runtime PM sync suspend failed in probe unwind\n"); return ret; - -} - -static void wsa_macro_remove(struct platform_device *pdev) -{ - struct wsa_macro *wsa = dev_get_drvdata(&pdev->dev); - - clk_disable_unprepare(wsa->macro); - clk_disable_unprepare(wsa->dcodec); - clk_disable_unprepare(wsa->mclk); - clk_disable_unprepare(wsa->npl); - clk_disable_unprepare(wsa->fsgen); } static int wsa_macro_runtime_suspend(struct device *dev) { struct wsa_macro *wsa = dev_get_drvdata(dev); + int ret; regcache_cache_only(wsa->regmap, true); - regcache_mark_dirty(wsa->regmap); - clk_disable_unprepare(wsa->fsgen); - clk_disable_unprepare(wsa->npl); - clk_disable_unprepare(wsa->mclk); + ret = pm_clk_suspend(dev); + if (ret) { + regcache_cache_only(wsa->regmap, false); + return ret; + } + + regcache_mark_dirty(wsa->regmap); return 0; } @@ -2866,36 +2852,29 @@ static int wsa_macro_runtime_suspend(struct device *dev) static int wsa_macro_runtime_resume(struct device *dev) { struct wsa_macro *wsa = dev_get_drvdata(dev); - int ret; + int ret, sret; - ret = clk_prepare_enable(wsa->mclk); + ret = pm_clk_resume(dev); if (ret) { - dev_err(dev, "unable to prepare mclk\n"); + regcache_cache_only(wsa->regmap, true); + regcache_mark_dirty(wsa->regmap); return ret; } + regcache_cache_only(wsa->regmap, false); - ret = clk_prepare_enable(wsa->npl); - if (ret) { - dev_err(dev, "unable to prepare mclkx2\n"); - goto err_npl; - } - - ret = clk_prepare_enable(wsa->fsgen); + ret = regcache_sync(wsa->regmap); if (ret) { - dev_err(dev, "unable to prepare fsgen\n"); - goto err_fsgen; + regcache_cache_only(wsa->regmap, true); + regcache_mark_dirty(wsa->regmap); + sret = pm_clk_suspend(dev); + if (sret) + dev_err(dev, + "failed to suspend clocks after regcache sync failure: %d\n", + sret); + return ret; } - regcache_cache_only(wsa->regmap, false); - regcache_sync(wsa->regmap); - return 0; -err_fsgen: - clk_disable_unprepare(wsa->npl); -err_npl: - clk_disable_unprepare(wsa->mclk); - - return ret; } static const struct dev_pm_ops wsa_macro_pm_ops = { @@ -2929,7 +2908,6 @@ static struct platform_driver wsa_macro_driver = { .pm = pm_ptr(&wsa_macro_pm_ops), }, .probe = wsa_macro_probe, - .remove = wsa_macro_remove, }; module_platform_driver(wsa_macro_driver); diff --git a/sound/soc/codecs/madera.c b/sound/soc/codecs/madera.c index 98d72db599d8..58255844b4df 100644 --- a/sound/soc/codecs/madera.c +++ b/sound/soc/codecs/madera.c @@ -6,6 +6,7 @@ // Cirrus Logic International Semiconductor Ltd. // +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/gcd.h> #include <linux/module.h> @@ -513,7 +514,7 @@ int madera_domain_clk_ev(struct snd_soc_dapm_widget *w, * We can't rely on the DAPM mutex for locking because we need a lock * that can safely be called in hw_params */ - mutex_lock(&priv->rate_lock); + guard(mutex)(&priv->rate_lock); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -532,8 +533,6 @@ int madera_domain_clk_ev(struct snd_soc_dapm_widget *w, madera_debug_dump_domain_groups(priv); - mutex_unlock(&priv->rate_lock); - return 0; } EXPORT_SYMBOL_GPL(madera_domain_clk_ev); @@ -875,9 +874,8 @@ static int madera_adsp_rate_get(struct snd_kcontrol *kcontrol, const int adsp_num = e->shift_l; int item; - mutex_lock(&priv->rate_lock); - cached_rate = priv->adsp_rate_cache[adsp_num]; - mutex_unlock(&priv->rate_lock); + scoped_guard(mutex, &priv->rate_lock) + cached_rate = priv->adsp_rate_cache[adsp_num]; item = snd_soc_enum_val_to_item(e, cached_rate); ucontrol->value.enumerated.item[0] = item; @@ -893,7 +891,6 @@ static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol, struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; const int adsp_num = e->shift_l; const unsigned int item = ucontrol->value.enumerated.item[0]; - int ret = 0; if (item >= e->items) return -EINVAL; @@ -903,22 +900,20 @@ static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol, * maintain consistent behaviour that rate domains cannot be changed * while in use since this is a hardware requirement */ - mutex_lock(&priv->rate_lock); + guard(mutex)(&priv->rate_lock); if (!madera_can_change_grp_rate(priv, priv->adsp[adsp_num].cs_dsp.base)) { dev_warn(priv->madera->dev, "Cannot change '%s' while in use by active audio paths\n", kcontrol->id.name); - ret = -EBUSY; + return -EBUSY; } else if (priv->adsp_rate_cache[adsp_num] != e->values[item]) { /* Volatile register so defer until the codec is powered up */ priv->adsp_rate_cache[adsp_num] = e->values[item]; - ret = 1; + return 1; } - mutex_unlock(&priv->rate_lock); - - return ret; + return 0; } static const struct soc_enum madera_adsp_rate_enum[] = { @@ -1061,15 +1056,13 @@ int madera_rate_put(struct snd_kcontrol *kcontrol, * Prevent the domain powering up while we're checking whether it's * safe to change rate domain */ - mutex_lock(&priv->rate_lock); + guard(mutex)(&priv->rate_lock); val = snd_soc_component_read(component, e->reg); val >>= e->shift_l; val &= e->mask; - if (snd_soc_enum_item_to_val(e, item) == val) { - ret = 0; - goto out; - } + if (snd_soc_enum_item_to_val(e, item) == val) + return 0; if (!madera_can_change_grp_rate(priv, e->reg)) { dev_warn(priv->madera->dev, @@ -1082,8 +1075,6 @@ int madera_rate_put(struct snd_kcontrol *kcontrol, ret = snd_soc_put_enum_double(kcontrol, ucontrol); madera_spin_sysclk(priv); } -out: - mutex_unlock(&priv->rate_lock); return ret; } @@ -3041,12 +3032,11 @@ static int madera_hw_params_rate(struct snd_pcm_substream *substream, if ((cur & MADERA_AIF1_RATE_MASK) == (tar & MADERA_AIF1_RATE_MASK)) return 0; - mutex_lock(&priv->rate_lock); + guard(mutex)(&priv->rate_lock); if (!madera_can_change_grp_rate(priv, base + MADERA_AIF_RATE_CTRL)) { madera_aif_warn(dai, "Cannot change rate while active\n"); - ret = -EBUSY; - goto out; + return -EBUSY; } /* Guard the rate change with SYSCLK cycles */ @@ -3055,9 +3045,6 @@ static int madera_hw_params_rate(struct snd_pcm_substream *substream, MADERA_AIF1_RATE_MASK, tar); madera_spin_sysclk(priv); -out: - mutex_unlock(&priv->rate_lock); - return ret; } @@ -3345,6 +3332,16 @@ static int madera_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, return 0; } +static const u64 madera_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J | + SND_SOC_POSSIBLE_DAIFMT_DSP_A | + SND_SOC_POSSIBLE_DAIFMT_DSP_B | + SND_SOC_POSSIBLE_DAIFMT_NB_NF | + SND_SOC_POSSIBLE_DAIFMT_NB_IF | + SND_SOC_POSSIBLE_DAIFMT_IB_NF | + SND_SOC_POSSIBLE_DAIFMT_IB_IF; + const struct snd_soc_dai_ops madera_dai_ops = { .startup = &madera_startup, .set_fmt = &madera_set_fmt, @@ -3352,6 +3349,8 @@ const struct snd_soc_dai_ops madera_dai_ops = { .hw_params = &madera_hw_params, .set_sysclk = &madera_dai_set_sysclk, .set_tristate = &madera_set_tristate, + .auto_selectable_formats = &madera_selectable_formats, + .num_auto_selectable_formats = 1, }; EXPORT_SYMBOL_GPL(madera_dai_ops); diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 57bd5a1c34c8..64dc442e9066 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -2341,6 +2341,7 @@ static irqreturn_t max98090_interrupt(int irq, void *data) * * @component: MAX98090 component * @jack: jack to report detection events on + * @data: can be used if codec driver need extra data for configuring jack * * Enable microphone detection via IRQ on the MAX98090. If GPIOs are * being used to bring out signals to the processor then only platform @@ -2646,12 +2647,18 @@ static void max98090_i2c_remove(struct i2c_client *client) static int max98090_runtime_resume(struct device *dev) { struct max98090_priv *max98090 = dev_get_drvdata(dev); + int ret; regcache_cache_only(max98090->regmap, false); max98090_reset(max98090); - regcache_sync(max98090->regmap); + ret = regcache_sync(max98090->regmap); + if (ret < 0) { + regcache_cache_only(max98090->regmap, true); + regcache_mark_dirty(max98090->regmap); + return ret; + } return 0; } diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 130b6694a634..d93436046849 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -5,6 +5,7 @@ * Copyright 2011 Maxim Integrated Products */ +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> @@ -1532,15 +1533,17 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol, regsave = snd_soc_component_read(component, M98095_088_CFG_LEVEL); snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, 0); - mutex_lock(&max98095->lock); - snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG); - m98095_eq_band(component, channel, 0, coef_set->band1); - m98095_eq_band(component, channel, 1, coef_set->band2); - m98095_eq_band(component, channel, 2, coef_set->band3); - m98095_eq_band(component, channel, 3, coef_set->band4); - m98095_eq_band(component, channel, 4, coef_set->band5); - snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, 0); - mutex_unlock(&max98095->lock); + scoped_guard(mutex, &max98095->lock) { + snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, + M98095_SEG, M98095_SEG); + m98095_eq_band(component, channel, 0, coef_set->band1); + m98095_eq_band(component, channel, 1, coef_set->band2); + m98095_eq_band(component, channel, 2, coef_set->band3); + m98095_eq_band(component, channel, 3, coef_set->band4); + m98095_eq_band(component, channel, 4, coef_set->band5); + snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, + M98095_SEG, 0); + } /* Restore the original on/off state */ snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, regsave); @@ -1683,12 +1686,14 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol, regsave = snd_soc_component_read(component, M98095_088_CFG_LEVEL); snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, 0); - mutex_lock(&max98095->lock); - snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG); - m98095_biquad_band(component, channel, 0, coef_set->band1); - m98095_biquad_band(component, channel, 1, coef_set->band2); - snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, 0); - mutex_unlock(&max98095->lock); + scoped_guard(mutex, &max98095->lock) { + snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, + M98095_SEG, M98095_SEG); + m98095_biquad_band(component, channel, 0, coef_set->band1); + m98095_biquad_band(component, channel, 1, coef_set->band2); + snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, + M98095_SEG, 0); + } /* Restore the original on/off state */ snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, regsave); diff --git a/sound/soc/codecs/max98363.c b/sound/soc/codecs/max98363.c index 099dc5bf6195..0e32b7a94cb0 100644 --- a/sound/soc/codecs/max98363.c +++ b/sound/soc/codecs/max98363.c @@ -100,7 +100,12 @@ static int max98363_resume(struct device *dev) return ret; regcache_cache_only(max98363->regmap, false); - regcache_sync(max98363->regmap); + ret = regcache_sync(max98363->regmap); + if (ret) { + regcache_cache_only(max98363->regmap, true); + regcache_mark_dirty(max98363->regmap); + return ret; + } return 0; } diff --git a/sound/soc/codecs/max98373-i2c.c b/sound/soc/codecs/max98373-i2c.c index 8805bd01153c..cbd7ebffa6d6 100644 --- a/sound/soc/codecs/max98373-i2c.c +++ b/sound/soc/codecs/max98373-i2c.c @@ -488,10 +488,17 @@ static int max98373_suspend(struct device *dev) static int max98373_resume(struct device *dev) { struct max98373_priv *max98373 = dev_get_drvdata(dev); + int ret; regcache_cache_only(max98373->regmap, false); max98373_reset(max98373, dev); - regcache_sync(max98373->regmap); + ret = regcache_sync(max98373->regmap); + if (ret) { + regcache_cache_only(max98373->regmap, true); + regcache_mark_dirty(max98373->regmap); + return ret; + } + return 0; } diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index 8fe9c58e1a62..638ef343813b 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -277,7 +277,12 @@ static int max98373_resume(struct device *dev) } regcache_cache_only(max98373->regmap, false); - regcache_sync(max98373->regmap); + ret = regcache_sync(max98373->regmap); + if (ret) { + regcache_cache_only(max98373->regmap, true); + regcache_mark_dirty(max98373->regmap); + return ret; + } return 0; } diff --git a/sound/soc/codecs/max98388.c b/sound/soc/codecs/max98388.c index a4c57152d25f..d97dab41bf0f 100644 --- a/sound/soc/codecs/max98388.c +++ b/sound/soc/codecs/max98388.c @@ -863,10 +863,16 @@ static int max98388_suspend(struct device *dev) static int max98388_resume(struct device *dev) { struct max98388_priv *max98388 = dev_get_drvdata(dev); + int ret; regcache_cache_only(max98388->regmap, false); max98388_reset(max98388, dev); - regcache_sync(max98388->regmap); + ret = regcache_sync(max98388->regmap); + if (ret) { + regcache_cache_only(max98388->regmap, true); + regcache_mark_dirty(max98388->regmap); + return ret; + } return 0; } diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c index 2bbedf84ee5d..2295fc057c71 100644 --- a/sound/soc/codecs/max98390.c +++ b/sound/soc/codecs/max98390.c @@ -788,7 +788,6 @@ static int max98390_dsm_init(struct snd_soc_component *component) const char *vendor, *product; struct max98390_priv *max98390 = snd_soc_component_get_drvdata(component); - const struct firmware *fw; char *dsm_param; vendor = dmi_get_system_info(DMI_SYS_VENDOR); @@ -805,6 +804,8 @@ static int max98390_dsm_init(struct snd_soc_component *component) snprintf(filename, sizeof(filename), "%s", max98390->dsm_param_name); } + + const struct firmware *fw __free(firmware) = NULL; ret = request_firmware(&fw, filename, component->dev); if (ret) { ret = request_firmware(&fw, "dsm_param.bin", component->dev); @@ -812,7 +813,7 @@ static int max98390_dsm_init(struct snd_soc_component *component) ret = request_firmware(&fw, "dsmparam.bin", component->dev); if (ret) - goto err; + return ret; } } @@ -822,8 +823,7 @@ static int max98390_dsm_init(struct snd_soc_component *component) if (fw->size < MAX98390_DSM_PARAM_MIN_SIZE) { dev_err(component->dev, "param fw is invalid.\n"); - ret = -EINVAL; - goto err_alloc; + return -EINVAL; } dsm_param = (char *)fw->data; param_start_addr = (dsm_param[0] & 0xff) | (dsm_param[1] & 0xff) << 8; @@ -833,8 +833,7 @@ static int max98390_dsm_init(struct snd_soc_component *component) fw->size < param_size + MAX98390_DSM_PAYLOAD_OFFSET) { dev_err(component->dev, "param fw is invalid.\n"); - ret = -EINVAL; - goto err_alloc; + return -EINVAL; } regmap_write(max98390->regmap, MAX98390_R203A_AMP_EN, 0x80); dsm_param += MAX98390_DSM_PAYLOAD_OFFSET; @@ -842,10 +841,7 @@ static int max98390_dsm_init(struct snd_soc_component *component) dsm_param, param_size); regmap_write(max98390->regmap, MAX98390_R23E1_DSP_GLOBAL_EN, 0x01); -err_alloc: - release_firmware(fw); -err: - return ret; + return 0; } static void max98390_init_regs(struct snd_soc_component *component) @@ -952,11 +948,17 @@ static int max98390_suspend(struct device *dev) static int max98390_resume(struct device *dev) { struct max98390_priv *max98390 = dev_get_drvdata(dev); + int ret; dev_dbg(dev, "%s:Enter\n", __func__); regcache_cache_only(max98390->regmap, false); - regcache_sync(max98390->regmap); + ret = regcache_sync(max98390->regmap); + if (ret) { + regcache_cache_only(max98390->regmap, true); + regcache_mark_dirty(max98390->regmap); + return ret; + } return 0; } diff --git a/sound/soc/codecs/max98396.c b/sound/soc/codecs/max98396.c index 9c1d7213410c..e5a2fe824c03 100644 --- a/sound/soc/codecs/max98396.c +++ b/sound/soc/codecs/max98396.c @@ -1600,19 +1600,37 @@ static int max98396_resume(struct device *dev) if (max98396->pvdd) { ret = regulator_enable(max98396->pvdd); if (ret < 0) - return ret; + goto err_core_supplies; } if (max98396->vbat) { ret = regulator_enable(max98396->vbat); if (ret < 0) - return ret; + goto err_pvdd; } regcache_cache_only(max98396->regmap, false); max98396_reset(max98396, dev); - regcache_sync(max98396->regmap); + ret = regcache_sync(max98396->regmap); + if (ret < 0) { + regcache_cache_only(max98396->regmap, true); + regcache_mark_dirty(max98396->regmap); + goto err_vbat; + } + return 0; + +err_vbat: + if (max98396->vbat) + regulator_disable(max98396->vbat); +err_pvdd: + if (max98396->pvdd) + regulator_disable(max98396->pvdd); +err_core_supplies: + regulator_bulk_disable(MAX98396_NUM_CORE_SUPPLIES, + max98396->core_supplies); + + return ret; } static const struct dev_pm_ops max98396_pm = { diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c index 0d7ac37850bb..20e288e38669 100644 --- a/sound/soc/codecs/max9860.c +++ b/sound/soc/codecs/max9860.c @@ -48,7 +48,6 @@ static int max9860_dvddio_event(struct notifier_block *nb, } static const struct reg_default max9860_reg_defaults[] = { - { MAX9860_PWRMAN, 0x00 }, { MAX9860_INTEN, 0x00 }, { MAX9860_SYSCLK, 0x00 }, { MAX9860_AUDIOCLKHIGH, 0x00 }, @@ -62,6 +61,7 @@ static const struct reg_default max9860_reg_defaults[] = { { MAX9860_MICGAIN, 0x00 }, { MAX9860_MICADC, 0x00 }, { MAX9860_NOISEGATE, 0x00 }, + { MAX9860_PWRMAN, 0x00 }, }; static bool max9860_readable(struct device *dev, unsigned int reg) diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index 65e6fdb30eec..524300d8fb0b 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -742,11 +742,17 @@ static int max98927_suspend(struct device *dev) static int max98927_resume(struct device *dev) { struct max98927_priv *max98927 = dev_get_drvdata(dev); + int ret; regmap_write(max98927->regmap, MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET); regcache_cache_only(max98927->regmap, false); - regcache_sync(max98927->regmap); + ret = regcache_sync(max98927->regmap); + if (ret) { + regcache_cache_only(max98927->regmap, true); + regcache_mark_dirty(max98927->regmap); + return ret; + } return 0; } diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index 8a14626d43ff..7209b47c2029 100644 --- a/sound/soc/codecs/ml26124.c +++ b/sound/soc/codecs/ml26124.c @@ -224,7 +224,6 @@ static const struct reg_default ml26124_reg[] = { /* Analog Path Control Register */ {0x54, 0x00}, /* Speaker AMP Output Control */ {0x5a, 0x00}, /* Mic IF Control */ - {0xe8, 0x01}, /* Mic Select Control */ /* Audio Interface Control Register */ {0x60, 0x00}, /* SAI-Trans Control */ @@ -287,6 +286,9 @@ static const struct reg_default ml26124_reg[] = { {0xd0, 0x01}, /* VIDEO AMP Gain Control */ {0xd2, 0x01}, /* VIDEO AMP Setup 1 */ {0xd4, 0x01}, /* VIDEO AMP Control2 */ + + /* Analog Path Control Register */ + {0xe8, 0x01}, /* Mic Select Control */ }; /* Get sampling rate value of sampling rate setting register (0x0) */ diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index 9ca381812975..87f8a47cc293 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -217,9 +217,11 @@ #define CDC_A_RX_HPH_BIAS_LDO_OCP (0xf195) #define CDC_A_RX_HPH_BIAS_CNP (0xf196) #define CDC_A_RX_HPH_CNP_EN (0xf197) +#define CDC_A_RX_HPH_L_TEST (0xf19A) #define CDC_A_RX_HPH_L_PA_DAC_CTL (0xf19B) #define RX_HPA_L_PA_DAC_CTL_DATA_RESET_MASK BIT(1) #define RX_HPA_L_PA_DAC_CTL_DATA_RESET_RESET BIT(1) +#define CDC_A_RX_HPH_R_TEST (0xf19C) #define CDC_A_RX_HPH_R_PA_DAC_CTL (0xf19D) #define RX_HPH_R_PA_DAC_CTL_DATA_RESET BIT(1) #define RX_HPH_R_PA_DAC_CTL_DATA_RESET_MASK BIT(1) @@ -232,6 +234,8 @@ #define RX_EAR_CTL_PA_SEL_MASK BIT(7) #define RX_EAR_CTL_PA_SEL BIT(7) +#define CDC_A_RX_EAR_STATUS (0xf1A1) + #define CDC_A_SPKR_DAC_CTL (0xf1B0) #define SPKR_DAC_CTL_DAC_RESET_MASK BIT(4) #define SPKR_DAC_CTL_DAC_RESET_NORMAL 0 @@ -250,6 +254,7 @@ SPKR_DRV_CAL_EN | SPKR_DRV_SETTLE_EN | \ SPKR_DRV_FW_EN | SPKR_DRV_BOOST_SET | \ SPKR_DRV_CMFB_SET | SPKR_DRV_GAIN_SET) +#define CDC_A_SPKR_ANA_BIAS_SET (0xf1B3) #define CDC_A_SPKR_OCP_CTL (0xf1B4) #define CDC_A_SPKR_PWRSTG_CTL (0xf1B5) #define SPKR_PWRSTG_CTL_DAC_EN_MASK BIT(0) @@ -264,6 +269,7 @@ #define CDC_A_SPKR_DRV_DBG (0xf1B7) #define CDC_A_CURRENT_LIMIT (0xf1C0) +#define CDC_A_BYPASS_MODE (0xf1C2) #define CDC_A_BOOST_EN_CTL (0xf1C3) #define CDC_A_SLOPE_COMP_IP_ZERO (0xf1C4) #define CDC_A_SEC_ACCESS (0xf1D0) @@ -286,6 +292,11 @@ static const char * const supply_names[] = { #define MBHC_MAX_BUTTONS (5) +struct wcd_reg_seq { + const struct reg_default *seq; + int seq_size; +}; + struct pm8916_wcd_analog_priv { u16 pmic_rev; u16 codec_version; @@ -696,6 +707,59 @@ static int pm8916_wcd_analog_enable_ear_pa(struct snd_soc_dapm_widget *w, return 0; } +static int pm8916_wcd_analog_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 pm8916_wcd_analog_priv *priv = dev_get_drvdata(component->dev); + + /* This quirk is not required for revisions prior to CAJON_2_0 */ + if (priv->codec_version < 4) + return 0; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + usleep_range(7000, 7100); + snd_soc_component_update_bits(component, CDC_A_RX_HPH_L_TEST, + 0x04, 0x04); + break; + case SND_SOC_DAPM_POST_PMD: + /* wait 20 ms after the digital codec has powered down */ + msleep(20); + snd_soc_component_update_bits(component, CDC_A_RX_HPH_L_TEST, + 0x04, 0x00); + break; + } + return 0; +} + +static int pm8916_wcd_analog_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 pm8916_wcd_analog_priv *priv = dev_get_drvdata(component->dev); + + /* This quirk is not required for revisions prior to CAJON_2_0 */ + if (priv->codec_version < 4) + return 0; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + usleep_range(7000, 7100); + snd_soc_component_update_bits(component, CDC_A_RX_HPH_R_TEST, + 0x04, 0x04); + break; + case SND_SOC_DAPM_POST_PMD: + msleep(20); + snd_soc_component_update_bits(component, CDC_A_RX_HPH_R_TEST, + 0x04, 0x00); + break; + } + return 0; +} + static const struct reg_default wcd_reg_defaults_2_0[] = { {CDC_A_RX_COM_OCP_CTL, 0xD1}, {CDC_A_RX_COM_OCP_COUNT, 0xFF}, @@ -715,9 +779,69 @@ static const struct reg_default wcd_reg_defaults_2_0[] = { {CDC_A_MASTER_BIAS_CTL, 0x30}, }; +static const struct wcd_reg_seq pm8916_data = { + .seq = wcd_reg_defaults_2_0, + .seq_size = ARRAY_SIZE(wcd_reg_defaults_2_0), +}; + +static const struct reg_default wcd_reg_defaults_pm8950[] = { + {CDC_A_RX_COM_OCP_CTL, 0xd1}, + {CDC_A_RX_COM_OCP_COUNT, 0xff}, + {CDC_D_SEC_ACCESS, 0xa5}, + {CDC_D_PERPH_RESET_CTL3, 0x0f}, + {CDC_A_TX_1_2_OPAMP_BIAS, 0x4c}, + {CDC_A_NCP_FBCTRL, 0xa8}, + {CDC_A_NCP_VCTRL, 0xa4}, + {CDC_A_SPKR_DRV_CTL, 0x69}, + {CDC_A_SPKR_DRV_DBG, 0x01}, + {CDC_A_SEC_ACCESS, 0xa5}, + {CDC_A_PERPH_RESET_CTL3, 0x0f}, + {CDC_A_CURRENT_LIMIT, 0x82}, + {CDC_A_SPKR_ANA_BIAS_SET, 0x41}, + {CDC_A_SPKR_DAC_CTL, 0x03}, + {CDC_A_SPKR_OCP_CTL, 0xe1}, + {CDC_A_RX_HPH_BIAS_PA, 0xfa}, + {CDC_A_MASTER_BIAS_CTL, 0x30}, + {CDC_A_MICB_1_INT_RBIAS, 0x00}, +}; + +static const struct wcd_reg_seq pm8950_data = { + .seq = wcd_reg_defaults_pm8950, + .seq_size = ARRAY_SIZE(wcd_reg_defaults_pm8950), +}; + +static const struct reg_default wcd_reg_defaults_pm8953[] = { + {CDC_A_RX_COM_OCP_CTL, 0xd1}, + {CDC_A_RX_COM_OCP_COUNT, 0xff}, + {CDC_D_SEC_ACCESS, 0xa5}, + {CDC_D_PERPH_RESET_CTL3, 0x0f}, + {CDC_A_TX_1_2_OPAMP_BIAS, 0x4c}, + {CDC_A_NCP_FBCTRL, 0xa8}, + {CDC_A_NCP_VCTRL, 0xa4}, + {CDC_A_SPKR_DRV_CTL, 0x69}, + {CDC_A_SPKR_DRV_DBG, 0x01}, + {CDC_A_SEC_ACCESS, 0xa5}, + {CDC_A_PERPH_RESET_CTL3, 0x0f}, + {CDC_A_CURRENT_LIMIT, 0xa2}, + {CDC_A_BYPASS_MODE, 0x18}, + {CDC_A_SPKR_ANA_BIAS_SET, 0x41}, + {CDC_A_SPKR_DAC_CTL, 0x03}, + {CDC_A_SPKR_OCP_CTL, 0xe1}, + {CDC_A_RX_HPH_BIAS_PA, 0xfa}, + {CDC_A_RX_EAR_STATUS, 0x10}, + {CDC_A_MASTER_BIAS_CTL, 0x30}, + {CDC_A_MICB_1_INT_RBIAS, 0x00}, +}; + +static const struct wcd_reg_seq pm8953_data = { + .seq = wcd_reg_defaults_pm8953, + .seq_size = ARRAY_SIZE(wcd_reg_defaults_pm8953), +}; + static int pm8916_wcd_analog_probe(struct snd_soc_component *component) { struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(component->dev); + const struct wcd_reg_seq *wcd_reg_init_data; int err, reg; err = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); @@ -738,9 +862,11 @@ static int pm8916_wcd_analog_probe(struct snd_soc_component *component) snd_soc_component_write(component, CDC_D_PERPH_RESET_CTL4, 0x01); snd_soc_component_write(component, CDC_A_PERPH_RESET_CTL4, 0x01); - for (reg = 0; reg < ARRAY_SIZE(wcd_reg_defaults_2_0); reg++) - snd_soc_component_write(component, wcd_reg_defaults_2_0[reg].reg, - wcd_reg_defaults_2_0[reg].def); + wcd_reg_init_data = of_device_get_match_data(component->dev); + + for (reg = 0; reg < wcd_reg_init_data->seq_size; reg++) + snd_soc_component_write(component, wcd_reg_init_data->seq[reg].reg, + wcd_reg_init_data->seq[reg].def); priv->component = component; @@ -883,11 +1009,15 @@ static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = { SND_SOC_DAPM_MUX("EAR_S", SND_SOC_NOPM, 0, 0, &ear_mux), SND_SOC_DAPM_SUPPLY("EAR CP", CDC_A_NCP_EN, 4, 0, NULL, 0), - SND_SOC_DAPM_PGA("HPHL PA", CDC_A_RX_HPH_CNP_EN, 5, 0, NULL, 0), + SND_SOC_DAPM_PGA_E("HPHL PA", CDC_A_RX_HPH_CNP_EN, 5, 0, NULL, 0, + pm8916_wcd_analog_enable_hphl_pa, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MUX("HPHL", SND_SOC_NOPM, 0, 0, &hphl_mux), SND_SOC_DAPM_MIXER("HPHL DAC", CDC_A_RX_HPH_L_PA_DAC_CTL, 3, 0, NULL, 0), - SND_SOC_DAPM_PGA("HPHR PA", CDC_A_RX_HPH_CNP_EN, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA_E("HPHR PA", CDC_A_RX_HPH_CNP_EN, 4, 0, NULL, 0, + pm8916_wcd_analog_enable_hphr_pa, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MUX("HPHR", SND_SOC_NOPM, 0, 0, &hphr_mux), SND_SOC_DAPM_MIXER("HPHR DAC", CDC_A_RX_HPH_R_PA_DAC_CTL, 3, 0, NULL, 0), @@ -1259,7 +1389,9 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) } static const struct of_device_id pm8916_wcd_analog_spmi_match_table[] = { - { .compatible = "qcom,pm8916-wcd-analog-codec", }, + { .compatible = "qcom,pm8916-wcd-analog-codec", .data = &pm8916_data }, + { .compatible = "qcom,pm8950-wcd-analog-codec", .data = &pm8950_data }, + { .compatible = "qcom,pm8953-wcd-analog-codec", .data = &pm8953_data }, { } }; diff --git a/sound/soc/codecs/mt6357.c b/sound/soc/codecs/mt6357.c index 674cf7df9df4..3b07087e1cab 100644 --- a/sound/soc/codecs/mt6357.c +++ b/sound/soc/codecs/mt6357.c @@ -1834,8 +1834,8 @@ static int mt6357_platform_driver_probe(struct platform_device *pdev) } static const struct platform_device_id mt6357_platform_ids[] = { - {"mt6357-sound", 0}, - { /* sentinel */ }, + { .name = "mt6357-sound" }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, mt6357_platform_ids); diff --git a/sound/soc/codecs/mt6359-accdet.c b/sound/soc/codecs/mt6359-accdet.c index ed34cc15b80e..e1190c644021 100644 --- a/sound/soc/codecs/mt6359-accdet.c +++ b/sound/soc/codecs/mt6359-accdet.c @@ -6,6 +6,7 @@ // Author: Argus Lin <argus.lin@mediatek.com> // +#include <linux/cleanup.h> #include <linux/of.h> #include <linux/input.h> #include <linux/kthread.h> @@ -398,14 +399,13 @@ static void mt6359_accdet_work(struct work_struct *work) struct mt6359_accdet *priv = container_of(work, struct mt6359_accdet, accdet_work); - mutex_lock(&priv->res_lock); + guard(mutex)(&priv->res_lock); priv->pre_accdet_status = priv->accdet_status; check_jack_btn_type(priv); if (priv->jack_plugged && priv->pre_accdet_status != priv->accdet_status) mt6359_accdet_jack_report(priv); - mutex_unlock(&priv->res_lock); } static void mt6359_accdet_jd_work(struct work_struct *work) @@ -416,7 +416,7 @@ static void mt6359_accdet_jd_work(struct work_struct *work) struct mt6359_accdet *priv = container_of(work, struct mt6359_accdet, jd_work); - mutex_lock(&priv->res_lock); + guard(mutex)(&priv->res_lock); if (priv->jd_sts == M_PLUG_IN) { priv->jack_plugged = true; @@ -450,7 +450,6 @@ static void mt6359_accdet_jd_work(struct work_struct *work) if (priv->caps & ACCDET_PMIC_EINT_IRQ) recover_eint_setting(priv); - mutex_unlock(&priv->res_lock); } static irqreturn_t mt6359_accdet_irq(int irq, void *data) @@ -459,7 +458,7 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data) unsigned int irq_val = 0, val = 0, value = 0; int ret; - mutex_lock(&priv->res_lock); + guard(mutex)(&priv->res_lock); regmap_read(priv->regmap, ACCDET_IRQ_ADDR, &irq_val); if (irq_val & ACCDET_IRQ_MASK_SFT) { @@ -474,7 +473,6 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data) 1000); if (ret) { dev_err(priv->dev, "%s(), ret %d\n", __func__, ret); - mutex_unlock(&priv->res_lock); return IRQ_NONE; } regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR, @@ -498,7 +496,6 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data) if (ret) { dev_err(priv->dev, "%s(), ret %d\n", __func__, ret); - mutex_unlock(&priv->res_lock); return IRQ_NONE; } regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR, @@ -521,7 +518,6 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data) if (ret) { dev_err(priv->dev, "%s(), ret %d\n", __func__, ret); - mutex_unlock(&priv->res_lock); return IRQ_NONE; } regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR, @@ -540,7 +536,6 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data) queue_work(priv->jd_workqueue, &priv->jd_work); } - mutex_unlock(&priv->res_lock); return IRQ_HANDLED; } diff --git a/sound/soc/codecs/ntpfw.c b/sound/soc/codecs/ntpfw.c index 5ced2e966ab7..b6443e24ae8e 100644 --- a/sound/soc/codecs/ntpfw.c +++ b/sound/soc/codecs/ntpfw.c @@ -89,7 +89,7 @@ int ntpfw_load(struct i2c_client *i2c, const char *name, u32 magic) { struct device *dev = &i2c->dev; const struct ntpfw_chunk *chunk; - const struct firmware *fw; + const struct firmware *fw __free(firmware) = NULL; const u8 *data; size_t leftover; int ret; @@ -101,10 +101,8 @@ int ntpfw_load(struct i2c_client *i2c, const char *name, u32 magic) return ret; } - if (!ntpfw_verify(dev, fw->data, fw->size, magic)) { - ret = -EINVAL; - goto done; - } + if (!ntpfw_verify(dev, fw->data, fw->size, magic)) + return -EINVAL; data = fw->data + sizeof(struct ntpfw_header); leftover = fw->size - sizeof(struct ntpfw_header); @@ -112,23 +110,18 @@ int ntpfw_load(struct i2c_client *i2c, const char *name, u32 magic) while (leftover) { chunk = (struct ntpfw_chunk *)data; - if (!ntpfw_verify_chunk(dev, chunk, leftover)) { - ret = -EINVAL; - goto done; - } + if (!ntpfw_verify_chunk(dev, chunk, leftover)) + return -EINVAL; ret = ntpfw_send_chunk(i2c, chunk); if (ret) - goto done; + return ret; data += be16_to_cpu(chunk->length) + sizeof(*chunk); leftover -= be16_to_cpu(chunk->length) + sizeof(*chunk); } -done: - release_firmware(fw); - - return ret; + return 0; } EXPORT_SYMBOL_GPL(ntpfw_load); diff --git a/sound/soc/codecs/ntpfw.h b/sound/soc/codecs/ntpfw.h index 1cf10d5480ee..efbe9aa1eca5 100644 --- a/sound/soc/codecs/ntpfw.h +++ b/sound/soc/codecs/ntpfw.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * ntpfw.h - Firmware helper functions for Neofidelity codecs * * Copyright (c) 2024, SaluteDevices. All Rights Reserved. @@ -13,10 +13,11 @@ /** * ntpfw_load - load firmware to amplifier over i2c interface. * - * @i2c Pointer to amplifier's I2C client. - * @name Firmware file name. - * @magic Magic number to validate firmware. - * @return 0 or error code upon error. + * @i2c: Pointer to amplifier's I2C client. + * @name: Firmware file name. + * @magic: Magic number to validate firmware. + * + * Returns: 0 or error code upon error. */ int ntpfw_load(struct i2c_client *i2c, const char *name, const u32 magic); diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index cb923cecb47f..60fdbe5c4e05 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c @@ -199,10 +199,17 @@ static int pcm1681_hw_params(struct snd_pcm_substream *substream, return pcm1681_set_deemph(component); } +static const u64 pcm1681_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J; + static const struct snd_soc_dai_ops pcm1681_dai_ops = { .set_fmt = pcm1681_set_dai_fmt, .hw_params = pcm1681_hw_params, .mute_stream = pcm1681_mute, + .auto_selectable_formats = &pcm1681_selectable_formats, + .num_auto_selectable_formats = 1, .no_capture_mute = 1, }; diff --git a/sound/soc/codecs/pcm1754.c b/sound/soc/codecs/pcm1754.c index b68a528000be..bb15da1c24aa 100644 --- a/sound/soc/codecs/pcm1754.c +++ b/sound/soc/codecs/pcm1754.c @@ -78,10 +78,16 @@ static int pcm1754_mute_stream(struct snd_soc_dai *dai, int mute, int stream) return 0; } +static const u64 pcm1754_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J; + static const struct snd_soc_dai_ops pcm1754_dai_ops = { .set_fmt = pcm1754_set_dai_fmt, .hw_params = pcm1754_hw_params, .mute_stream = pcm1754_mute_stream, + .auto_selectable_formats = &pcm1754_selectable_formats, + .num_auto_selectable_formats = 1, }; static const struct snd_soc_dai_driver pcm1754_dai = { diff --git a/sound/soc/codecs/pcm1789.c b/sound/soc/codecs/pcm1789.c index 3ab381e9a856..f06e353743aa 100644 --- a/sound/soc/codecs/pcm1789.c +++ b/sound/soc/codecs/pcm1789.c @@ -164,11 +164,18 @@ static int pcm1789_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } +static const u64 pcm1789_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J; + static const struct snd_soc_dai_ops pcm1789_dai_ops = { .set_fmt = pcm1789_set_dai_fmt, .hw_params = pcm1789_hw_params, .mute_stream = pcm1789_mute, .trigger = pcm1789_trigger, + .auto_selectable_formats = &pcm1789_selectable_formats, + .num_auto_selectable_formats = 1, .no_capture_mute = 1, }; diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c index f52ff66b6e64..cb70927872aa 100644 --- a/sound/soc/codecs/pcm179x.c +++ b/sound/soc/codecs/pcm179x.c @@ -142,10 +142,16 @@ static int pcm179x_hw_params(struct snd_pcm_substream *substream, return 0; } +static const u64 pcm179x_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J; + static const struct snd_soc_dai_ops pcm179x_dai_ops = { .set_fmt = pcm179x_set_dai_fmt, .hw_params = pcm179x_hw_params, .mute_stream = pcm179x_mute, + .auto_selectable_formats = &pcm179x_selectable_formats, + .num_auto_selectable_formats = 1, .no_capture_mute = 1, }; diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c index 0d1103fe4e04..461ec74e8752 100644 --- a/sound/soc/codecs/pcm186x.c +++ b/sound/soc/codecs/pcm186x.c @@ -473,11 +473,20 @@ static int pcm186x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, return 0; } +static const u64 pcm186x_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J | + SND_SOC_POSSIBLE_DAIFMT_DSP_A | + SND_SOC_POSSIBLE_DAIFMT_DSP_B | + SND_SOC_POSSIBLE_DAIFMT_NB_NF; + static const struct snd_soc_dai_ops pcm186x_dai_ops = { .set_sysclk = pcm186x_set_dai_sysclk, .set_tdm_slot = pcm186x_set_tdm_slot, .set_fmt = pcm186x_set_fmt, .hw_params = pcm186x_hw_params, + .auto_selectable_formats = &pcm186x_selectable_formats, + .num_auto_selectable_formats = 1, }; static struct snd_soc_dai_driver pcm1863_dai = { diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c index 8974200652e7..f01c46583e89 100644 --- a/sound/soc/codecs/pcm3060.c +++ b/sound/soc/codecs/pcm3060.c @@ -164,10 +164,18 @@ val_ready: return 0; } +static const u64 pcm3060_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J | + SND_SOC_POSSIBLE_DAIFMT_NB_NF; + static const struct snd_soc_dai_ops pcm3060_dai_ops = { .set_sysclk = pcm3060_set_sysclk, .set_fmt = pcm3060_set_fmt, .hw_params = pcm3060_hw_params, + .auto_selectable_formats = &pcm3060_selectable_formats, + .num_auto_selectable_formats = 1, }; #define PCM3060_DAI_RATES_ADC (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | \ diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index fe3b5011fa16..f3e20919042b 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -6,7 +6,7 @@ * Copyright 2014 Linaro Ltd */ - +#include <linux/cleanup.h> #include <linux/init.h> #include <linux/module.h> #include <linux/clk.h> @@ -78,28 +78,10 @@ static const struct reg_default pcm512x_reg_defaults[] = { { PCM512x_POWER, 0x00 }, { PCM512x_MUTE, 0x00 }, { PCM512x_DSP, 0x00 }, - { PCM512x_PLL_REF, 0x00 }, - { PCM512x_DAC_REF, 0x00 }, - { PCM512x_DAC_ROUTING, 0x11 }, - { PCM512x_DSP_PROGRAM, 0x01 }, - { PCM512x_CLKDET, 0x00 }, - { PCM512x_AUTO_MUTE, 0x00 }, - { PCM512x_ERROR_DETECT, 0x00 }, - { PCM512x_DIGITAL_VOLUME_1, 0x00 }, - { PCM512x_DIGITAL_VOLUME_2, 0x30 }, - { PCM512x_DIGITAL_VOLUME_3, 0x30 }, - { PCM512x_DIGITAL_MUTE_1, 0x22 }, - { PCM512x_DIGITAL_MUTE_2, 0x00 }, - { PCM512x_DIGITAL_MUTE_3, 0x07 }, - { PCM512x_OUTPUT_AMPLITUDE, 0x00 }, - { PCM512x_ANALOG_GAIN_CTRL, 0x00 }, - { PCM512x_UNDERVOLTAGE_PROT, 0x00 }, - { PCM512x_ANALOG_MUTE_CTRL, 0x00 }, - { PCM512x_ANALOG_GAIN_BOOST, 0x00 }, - { PCM512x_VCOM_CTRL_1, 0x00 }, - { PCM512x_VCOM_CTRL_2, 0x01 }, { PCM512x_BCLK_LRCLK_CFG, 0x00 }, { PCM512x_MASTER_MODE, 0x7c }, + { PCM512x_PLL_REF, 0x00 }, + { PCM512x_DAC_REF, 0x00 }, { PCM512x_GPIO_DACIN, 0x00 }, { PCM512x_GPIO_PLLIN, 0x00 }, { PCM512x_SYNCHRONIZE, 0x10 }, @@ -117,8 +99,26 @@ static const struct reg_default pcm512x_reg_defaults[] = { { PCM512x_FS_SPEED_MODE, 0x00 }, { PCM512x_IDAC_1, 0x01 }, { PCM512x_IDAC_2, 0x00 }, + { PCM512x_ERROR_DETECT, 0x00 }, { PCM512x_I2S_1, 0x02 }, { PCM512x_I2S_2, 0x00 }, + { PCM512x_DAC_ROUTING, 0x11 }, + { PCM512x_DSP_PROGRAM, 0x01 }, + { PCM512x_CLKDET, 0x00 }, + { PCM512x_AUTO_MUTE, 0x00 }, + { PCM512x_DIGITAL_VOLUME_1, 0x00 }, + { PCM512x_DIGITAL_VOLUME_2, 0x30 }, + { PCM512x_DIGITAL_VOLUME_3, 0x30 }, + { PCM512x_DIGITAL_MUTE_1, 0x22 }, + { PCM512x_DIGITAL_MUTE_2, 0x00 }, + { PCM512x_DIGITAL_MUTE_3, 0x07 }, + { PCM512x_OUTPUT_AMPLITUDE, 0x00 }, + { PCM512x_ANALOG_GAIN_CTRL, 0x00 }, + { PCM512x_UNDERVOLTAGE_PROT, 0x00 }, + { PCM512x_ANALOG_MUTE_CTRL, 0x00 }, + { PCM512x_ANALOG_GAIN_BOOST, 0x00 }, + { PCM512x_VCOM_CTRL_1, 0x00 }, + { PCM512x_VCOM_CTRL_2, 0x01 }, }; static bool pcm512x_readable(struct device *dev, unsigned int reg) @@ -399,10 +399,9 @@ static int pcm512x_digital_playback_switch_get(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); - mutex_lock(&pcm512x->mutex); + guard(mutex)(&pcm512x->mutex); ucontrol->value.integer.value[0] = !(pcm512x->mute & 0x4); ucontrol->value.integer.value[1] = !(pcm512x->mute & 0x2); - mutex_unlock(&pcm512x->mutex); return 0; } @@ -414,7 +413,7 @@ static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol, struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); int ret, changed = 0; - mutex_lock(&pcm512x->mutex); + guard(mutex)(&pcm512x->mutex); if ((pcm512x->mute & 0x4) == (ucontrol->value.integer.value[0] << 2)) { pcm512x->mute ^= 0x4; @@ -430,13 +429,10 @@ static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol, if (ret != 0) { dev_err(component->dev, "Failed to update digital mute: %d\n", ret); - mutex_unlock(&pcm512x->mutex); return ret; } } - mutex_unlock(&pcm512x->mutex); - return changed; } @@ -1465,7 +1461,7 @@ static int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction) int ret; unsigned int mute_det; - mutex_lock(&pcm512x->mutex); + guard(mutex)(&pcm512x->mutex); if (mute) { pcm512x->mute |= 0x1; @@ -1475,7 +1471,7 @@ static int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction) if (ret != 0) { dev_err(component->dev, "Failed to set digital mute: %d\n", ret); - goto unlock; + return ret; } regmap_read_poll_timeout(pcm512x->regmap, @@ -1488,7 +1484,7 @@ static int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction) if (ret != 0) { dev_err(component->dev, "Failed to update digital mute: %d\n", ret); - goto unlock; + return ret; } regmap_read_poll_timeout(pcm512x->regmap, @@ -1499,18 +1495,24 @@ static int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction) 200, 10000); } -unlock: - mutex_unlock(&pcm512x->mutex); - return ret; } +static const u64 pcm512x_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J | + SND_SOC_POSSIBLE_DAIFMT_DSP_A | + SND_SOC_POSSIBLE_DAIFMT_DSP_B; + static const struct snd_soc_dai_ops pcm512x_dai_ops = { .startup = pcm512x_dai_startup, .hw_params = pcm512x_hw_params, .set_fmt = pcm512x_set_fmt, .mute_stream = pcm512x_mute, .set_bclk_ratio = pcm512x_set_bclk_ratio, + .auto_selectable_formats = &pcm512x_selectable_formats, + .num_auto_selectable_formats = 1, .no_capture_mute = 1, }; diff --git a/sound/soc/codecs/pcm6240.c b/sound/soc/codecs/pcm6240.c index 4ac4448ac3c8..db85ae2f8aed 100644 --- a/sound/soc/codecs/pcm6240.c +++ b/sound/soc/codecs/pcm6240.c @@ -12,6 +12,7 @@ // Author: Shenghao Ding <shenghao-ding@ti.com> // +#include <linux/cleanup.h> #include <linux/unaligned.h> #include <linux/firmware.h> #include <linux/gpio/consumer.h> @@ -605,7 +606,7 @@ static int pcmdev_get_volsw(struct snd_kcontrol *kcontrol, unsigned int reg = mc->reg; unsigned int val; - mutex_lock(&pcm_dev->codec_lock); + guard(mutex)(&pcm_dev->codec_lock); if (pcm_dev->chip_id == PCM1690) { ret = pcmdev_dev_read(pcm_dev, dev_no, PCM1690_REG_MODE_CTRL, @@ -613,18 +614,18 @@ static int pcmdev_get_volsw(struct snd_kcontrol *kcontrol, if (ret) { dev_err(pcm_dev->dev, "%s: read mode err=%d\n", __func__, ret); - goto out; + return ret; } val &= PCM1690_REG_MODE_CTRL_DAMS_MSK; /* Set to wide-range mode, before using vol ctrl. */ if (!val && vol_ctrl_type == PCMDEV_PCM1690_VOL_CTRL) { ucontrol->value.integer.value[0] = -25500; - goto out; + return ret; } /* Set to fine mode, before using fine vol ctrl. */ if (val && vol_ctrl_type == PCMDEV_PCM1690_FINE_VOL_CTRL) { ucontrol->value.integer.value[0] = -12750; - goto out; + return ret; } } @@ -632,15 +633,14 @@ static int pcmdev_get_volsw(struct snd_kcontrol *kcontrol, if (ret) { dev_err(pcm_dev->dev, "%s: read err=%d\n", __func__, ret); - goto out; + return ret; } val = (val >> shift) & mask; val = (val > max) ? max : val; val = mc->invert ? max - val : val; ucontrol->value.integer.value[0] = val; -out: - mutex_unlock(&pcm_dev->codec_lock); + return ret; } @@ -678,7 +678,7 @@ static int pcmdev_put_volsw(struct snd_kcontrol *kcontrol, unsigned int val, val_mask; unsigned int reg = mc->reg; - mutex_lock(&pcm_dev->codec_lock); + guard(mutex)(&pcm_dev->codec_lock); val = ucontrol->value.integer.value[0] & mask; val = (val > max) ? max : val; val = mc->invert ? max - val : val; @@ -702,7 +702,7 @@ static int pcmdev_put_volsw(struct snd_kcontrol *kcontrol, __func__, rc); else rc = 1; - mutex_unlock(&pcm_dev->codec_lock); + return rc; } @@ -1577,10 +1577,10 @@ static int pcmdevice_comp_probe(struct snd_soc_component *comp) { struct pcmdevice_priv *pcm_dev = snd_soc_component_get_drvdata(comp); struct i2c_adapter *adap = pcm_dev->client->adapter; - const struct firmware *fw_entry = NULL; + const struct firmware *fw_entry __free(firmware) = NULL; int ret, i, j; - mutex_lock(&pcm_dev->codec_lock); + guard(mutex)(&pcm_dev->codec_lock); pcm_dev->component = comp; @@ -1588,7 +1588,7 @@ static int pcmdevice_comp_probe(struct snd_soc_component *comp) for (j = 0; j < 2; j++) { ret = pcmdev_gain_ctrl_add(pcm_dev, i, j); if (ret < 0) - goto out; + return ret; } } @@ -1621,21 +1621,17 @@ static int pcmdevice_comp_probe(struct snd_soc_component *comp) if (ret) { dev_err(pcm_dev->dev, "%s: request %s err = %d\n", __func__, pcm_dev->bin_name, ret); - goto out; + return ret; } ret = pcmdev_regbin_ready(fw_entry, pcm_dev); if (ret) { dev_err(pcm_dev->dev, "%s: %s parse err = %d\n", __func__, pcm_dev->bin_name, ret); - goto out; + return ret; } - ret = pcmdev_profile_ctrl_add(pcm_dev); -out: - release_firmware(fw_entry); - mutex_unlock(&pcm_dev->codec_lock); - return ret; + return pcmdev_profile_ctrl_add(pcm_dev); } @@ -1645,9 +1641,8 @@ static void pcmdevice_comp_remove(struct snd_soc_component *codec) if (!pcm_dev) return; - mutex_lock(&pcm_dev->codec_lock); + guard(mutex)(&pcm_dev->codec_lock); pcmdevice_config_info_remove(pcm_dev); - mutex_unlock(&pcm_dev->codec_lock); } static const struct snd_soc_dapm_widget pcmdevice_dapm_widgets[] = { @@ -1890,9 +1885,9 @@ static int pcmdevice_mute(struct snd_soc_dai *dai, int mute, int stream) else block_type = PCMDEVICE_BIN_BLK_PRE_POWER_UP; - mutex_lock(&pcm_dev->codec_lock); + guard(mutex)(&pcm_dev->codec_lock); pcmdevice_select_cfg_blk(pcm_dev, pcm_dev->cur_conf, block_type); - mutex_unlock(&pcm_dev->codec_lock); + return 0; } diff --git a/sound/soc/codecs/peb2466.c b/sound/soc/codecs/peb2466.c index 2d71d204d8fa..f1ded68c2d75 100644 --- a/sound/soc/codecs/peb2466.c +++ b/sound/soc/codecs/peb2466.c @@ -6,6 +6,7 @@ // // Author: Herve Codina <herve.codina@bootlin.com> +#include <linux/cleanup.h> #include <linux/unaligned.h> #include <linux/clk.h> #include <linux/firmware.h> @@ -1537,17 +1538,14 @@ static int peb2466_fw_parse(struct snd_soc_component *component, static int peb2466_load_coeffs(struct snd_soc_component *component, const char *fw_name) { - const struct firmware *fw; + const struct firmware *fw __free(firmware) = NULL; int ret; ret = request_firmware(&fw, fw_name, component->dev); if (ret) return ret; - ret = peb2466_fw_parse(component, fw->data, fw->size); - release_firmware(fw); - - return ret; + return peb2466_fw_parse(component, fw->data, fw->size); } static int peb2466_component_probe(struct snd_soc_component *component) @@ -1704,13 +1702,11 @@ static int peb2466_chip_gpio_update_bits(struct peb2466 *peb2466, unsigned int x * So, a specific cache value is used. */ - mutex_lock(&peb2466->gpio.lock); + guard(mutex)(&peb2466->gpio.lock); cache = peb2466_chip_gpio_get_cache(peb2466, xr_reg); - if (!cache) { - ret = -EINVAL; - goto end; - } + if (!cache) + return -EINVAL; tmp = *cache; tmp &= ~mask; @@ -1718,14 +1714,11 @@ static int peb2466_chip_gpio_update_bits(struct peb2466 *peb2466, unsigned int x ret = regmap_write(peb2466->regmap, xr_reg, tmp); if (ret) - goto end; + return ret; *cache = tmp; - ret = 0; -end: - mutex_unlock(&peb2466->gpio.lock); - return ret; + return 0; } static int peb2466_chip_gpio_set(struct gpio_chip *c, unsigned int offset, diff --git a/sound/soc/codecs/pm4125-sdw.c b/sound/soc/codecs/pm4125-sdw.c index 1c612ae4a4b2..182ff396301a 100644 --- a/sound/soc/codecs/pm4125-sdw.c +++ b/sound/soc/codecs/pm4125-sdw.c @@ -126,8 +126,8 @@ static const struct reg_default pm4125_defaults[] = { { PM4125_ANA_HPHPA_FSM_CLK, 0x12 }, { PM4125_ANA_HPHPA_L_GAIN, 0x00 }, { PM4125_ANA_HPHPA_R_GAIN, 0x00 }, - { PM4125_SWR_HPHPA_HD2, 0x1B }, { PM4125_ANA_HPHPA_SPARE_CTL, 0x02 }, + { PM4125_SWR_HPHPA_HD2, 0x1B }, { PM4125_ANA_SURGE_EN, 0x38 }, { PM4125_ANA_COMBOPA_CTL, 0x35 }, { PM4125_ANA_COMBOPA_CTL_4, 0x84 }, @@ -464,10 +464,16 @@ static int __maybe_unused pm4125_sdw_runtime_suspend(struct device *dev) static int __maybe_unused pm4125_sdw_runtime_resume(struct device *dev) { struct pm4125_sdw_priv *priv = dev_get_drvdata(dev); + int ret; if (priv->regmap) { regcache_cache_only(priv->regmap, false); - regcache_sync(priv->regmap); + ret = regcache_sync(priv->regmap); + if (ret) { + regcache_cache_only(priv->regmap, true); + regcache_mark_dirty(priv->regmap); + return ret; + } } return 0; diff --git a/sound/soc/codecs/pm4125.c b/sound/soc/codecs/pm4125.c index 29655175ea28..674a2fbc4eda 100644 --- a/sound/soc/codecs/pm4125.c +++ b/sound/soc/codecs/pm4125.c @@ -5,6 +5,7 @@ #include <linux/component.h> #include <linux/delay.h> #include <linux/device.h> +#include <linux/irqdomain.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> @@ -1295,7 +1296,7 @@ static const struct irq_domain_ops pm4125_domain_ops = { static int pm4125_irq_init(struct pm4125_priv *pm4125, struct device *dev) { - pm4125->virq = irq_domain_add_linear(NULL, 1, &pm4125_domain_ops, NULL); + pm4125->virq = irq_domain_create_linear(NULL, 1, &pm4125_domain_ops, NULL); if (!(pm4125->virq)) { dev_err(dev, "%s: Failed to add IRQ domain\n", __func__); return -EINVAL; diff --git a/sound/soc/codecs/rt1017-sdca-sdw.c b/sound/soc/codecs/rt1017-sdca-sdw.c index 95405cea8143..caf75e5657ef 100644 --- a/sound/soc/codecs/rt1017-sdca-sdw.c +++ b/sound/soc/codecs/rt1017-sdca-sdw.c @@ -784,7 +784,12 @@ static int rt1017_sdca_dev_resume(struct device *dev) } regcache_cache_only(rt1017->regmap, false); - regcache_sync(rt1017->regmap); + ret = regcache_sync(rt1017->regmap); + if (ret) { + regcache_cache_only(rt1017->regmap, true); + regcache_mark_dirty(rt1017->regmap); + return ret; + } return 0; } diff --git a/sound/soc/codecs/rt1017-sdca-sdw.h b/sound/soc/codecs/rt1017-sdca-sdw.h index 4932b5dbe3c0..1604e1cfd85e 100644 --- a/sound/soc/codecs/rt1017-sdca-sdw.h +++ b/sound/soc/codecs/rt1017-sdca-sdw.h @@ -165,19 +165,19 @@ static const struct reg_default rt1017_sdca_reg_defaults[] = { { 0xdb09, 0x0f }, { 0xdb0a, 0xff }, { 0xdb14, 0x00 }, - - { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21, - RT1017_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 }, { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU, RT1017_SDCA_CTL_FU_MUTE, 0x01), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_XU22, RT1017_SDCA_CTL_BYPASS, 0), 0x01 }, - { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21, - RT1017_SDCA_CTL_FS_INDEX, 0), 0x09 }, { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23, RT1017_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE22, RT1017_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21, + RT1017_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21, + RT1017_SDCA_CTL_FS_INDEX, 0), 0x09 }, }; #endif /* __RT1017_SDW_H__ */ diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c index ca318dbd946e..2ef47a82c984 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -59,13 +59,13 @@ static const struct reg_default rt1316_reg_defaults[] = { { 0xd101, 0x00 }, { 0xd102, 0x30 }, { 0xd103, 0x00 }, - { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_UDMPU21, RT1316_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 }, { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_FU21, RT1316_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_FU21, RT1316_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_XU24, RT1316_SDCA_CTL_BYPASS, 0), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE23, RT1316_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE22, RT1316_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE24, RT1316_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_UDMPU21, RT1316_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 }, }; static const struct reg_sequence rt1316_blind_write[] = { @@ -756,7 +756,12 @@ static int rt1316_dev_resume(struct device *dev) } regcache_cache_only(rt1316->regmap, false); - regcache_sync(rt1316->regmap); + ret = regcache_sync(rt1316->regmap); + if (ret) { + regcache_cache_only(rt1316->regmap, true); + regcache_mark_dirty(rt1316->regmap); + return ret; + } return 0; } diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c index c038ac0e3b76..efadb6b1b82d 100644 --- a/sound/soc/codecs/rt1318-sdw.c +++ b/sound/soc/codecs/rt1318-sdw.c @@ -235,10 +235,10 @@ static const struct reg_default rt1318_reg_defaults[] = { { 0xf805, 0x00 }, { 0xf806, 0x07 }, { 0xf807, 0xff }, - { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_UDMPU21, RT1318_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 }, { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23, RT1318_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_UDMPU21, RT1318_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 }, { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_CS21, RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, }; @@ -830,7 +830,12 @@ static int rt1318_dev_resume(struct device *dev) return ret; regcache_cache_only(rt1318->regmap, false); - regcache_sync(rt1318->regmap); + ret = regcache_sync(rt1318->regmap); + if (ret) { + regcache_cache_only(rt1318->regmap, true); + regcache_mark_dirty(rt1318->regmap); + return ret; + } return 0; } diff --git a/sound/soc/codecs/rt1318.c b/sound/soc/codecs/rt1318.c index d13fd0e14125..55607f1b9a1e 100644 --- a/sound/soc/codecs/rt1318.c +++ b/sound/soc/codecs/rt1318.c @@ -337,6 +337,8 @@ static const struct reg_default rt1318_reg[] = { { 0xdd08, 0x40 }, { 0xdd12, 0x00 }, { 0xdd35, 0x00 }, + { 0xdd93, 0x00 }, + { 0xdd94, 0x64 }, { 0xddb5, 0x00 }, { 0xddb6, 0x40 }, { 0xddb7, 0x00 }, @@ -345,8 +347,6 @@ static const struct reg_default rt1318_reg[] = { { 0xddc6, 0x00 }, { 0xddc7, 0x00 }, { 0xddc8, 0x00 }, - { 0xdd93, 0x00 }, - { 0xdd94, 0x64 }, { 0xdf00, 0x00 }, { 0xdf5f, 0x00 }, { 0xdf60, 0x00 }, diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c index 42acb6cef77a..90333779971d 100644 --- a/sound/soc/codecs/rt1320-sdw.c +++ b/sound/soc/codecs/rt1320-sdw.c @@ -410,6 +410,402 @@ static const struct reg_sequence rt1321_blind_write[] = { { 0x41001988, 0x03 }, }; +static const struct reg_sequence rt1321_va1_blind_write[] = { + { 0x0000c003, 0xf0 }, + { 0x0000c01b, 0xfc }, + { 0x0000c5c3, 0xf2 }, + { 0x0000c5c2, 0x00 }, + { 0x0000c5c1, 0x10 }, + { 0x0000c5c0, 0x04 }, + { 0x0000c5c7, 0x03 }, + { 0x0000c5c6, 0x10 }, + { 0x0000c526, 0x47 }, + { 0x0000c5c4, 0x12 }, + { 0x0000c5c5, 0x60 }, + { 0x0000c520, 0x10 }, + { 0x0000c521, 0x32 }, + { 0x0000c5c7, 0x00 }, + { 0x0000c5c8, 0x03 }, + { 0x0000c5d3, 0x08 }, + { 0x0000c5d2, 0x0a }, + { 0x0000c5d1, 0x49 }, + { 0x0000c5d0, 0x0f }, + { 0x0000c580, 0x10 }, + { 0x0000c581, 0x32 }, + { 0x0000c582, 0x01 }, + { 0x0000c682, 0x60 }, + { 0x0000c019, 0x10 }, + { 0x0000c5f0, 0x01 }, + { 0x0000c5f7, 0x22 }, + { 0x0000c5f6, 0x22 }, + { 0x0000c057, 0x51 }, + { 0x0000c054, 0x55 }, + { 0x0000c053, 0x55 }, + { 0x0000c052, 0x55 }, + { 0x0000c051, 0x01 }, + { 0x0000c050, 0x15 }, + { 0x0000c060, 0x99 }, + { 0x0000c030, 0x55 }, + { 0x0000c061, 0x55 }, + { 0x0000c063, 0x55 }, + { 0x0000c065, 0xa5 }, + { 0x0000c06b, 0x0a }, + { 0x0000ca05, 0xd6 }, + { 0x0000ca06, 0x11 }, + { 0x0000ca07, 0x1e }, + { 0x0000ca25, 0xd6 }, + { 0x0000ca26, 0x11 }, + { 0x0000ca27, 0x1e }, + { 0x0000cd00, 0x05 }, + { 0x0000cd81, 0x49 }, + { 0x0000cd82, 0x49 }, + { 0x0000c604, 0x40 }, + { 0x0000c609, 0x40 }, + { 0x0000c046, 0xf7 }, + { 0x0000c045, 0xff }, + { 0x0000c044, 0xff }, + { 0x0000c043, 0xff }, + { 0x0000c042, 0xff }, + { 0x0000c041, 0xff }, + { 0x0000c040, 0xff }, + { 0x0000c049, 0xff }, + { 0x0000c028, 0x3f }, + { 0x0000c020, 0x3f }, + { 0x0000c032, 0x13 }, + { 0x0000c033, 0x01 }, + { 0x0000cc10, 0x01 }, + { 0x0000dc20, 0x03 }, + { 0x0000de03, 0x05 }, + { 0x0000dc00, 0x00 }, + { 0x0000c700, 0xf0 }, + { 0x0000c701, 0x13 }, + { 0x0000c900, 0xc3 }, + { 0x0000c570, 0x08 }, + { 0x0000c086, 0x02 }, + { 0x0000c085, 0x7f }, + { 0x0000c084, 0x00 }, + { 0x0000c081, 0xff }, + { 0x0000f084, 0x0f }, + { 0x0000f083, 0xff }, + { 0x0000f082, 0xff }, + { 0x0000f081, 0xff }, + { 0x0000f080, 0xff }, + { 0x20003003, 0x3f }, + { 0x20005818, 0x81 }, + { 0x20009018, 0x81 }, + { 0x2000301c, 0x81 }, + { 0x0000c003, 0xc0 }, + { 0x0000c047, 0x80 }, + { 0x0000d541, 0x80 }, + { 0x0000d487, 0x0b }, + { 0x0000d487, 0x3b }, + { 0x0000d486, 0xc3 }, + { 0x0000d470, 0x89 }, + { 0x0000d471, 0x3a }, + { 0x0000d472, 0x3d }, + { 0x0000d474, 0x11 }, + { 0x0000d475, 0x32 }, + { 0x0000d476, 0x64 }, + { 0x0000d477, 0x10 }, + { 0x0000d478, 0xff }, + { 0x0000d479, 0x20 }, + { 0x0000d47a, 0x10 }, + { 0x0000d73c, 0xb7 }, + { 0x0000d73d, 0xd7 }, + { 0x0000d73e, 0x00 }, + { 0x0000d73f, 0x10 }, + { 0x1000cd56, 0x00 }, + { 0x3fc2dfc0, 0x03 }, + { 0x3fc2dfc1, 0x00 }, + { 0x3fc2dfc2, 0x00 }, + { 0x3fc2dfc3, 0x00 }, + { 0x3fc2dfc4, 0x01 }, + { 0x3fc2dfc5, 0x00 }, + { 0x3fc2dfc6, 0x00 }, + { 0x3fc2dfc7, 0x00 }, + { 0x3fc2df80, 0x00 }, + { 0x3fc2df81, 0x00 }, + { 0x3fc2df82, 0x00 }, + { 0x3fc2df83, 0x00 }, + { 0x0000d541, 0x40 }, + { 0x0000d486, 0x43 }, + { 0x1000db00, 0x04 }, + { 0x1000db01, 0x00 }, + { 0x1000db02, 0x10 }, + { 0x1000db03, 0x00 }, + { 0x1000db04, 0x00 }, + { 0x1000db05, 0x45 }, + { 0x1000db06, 0x0d }, + { 0x1000db07, 0x01 }, + { 0x1000db08, 0x00 }, + { 0x1000db09, 0x00 }, + { 0x1000db0a, 0xbf }, + { 0x1000db0b, 0x0b }, + { 0x1000db0c, 0x11 }, + { 0x1000db0d, 0x00 }, + { 0x1000db0e, 0x00 }, + { 0x1000db0f, 0x00 }, + { 0x1000db10, 0x2c }, + { 0x1000db11, 0xfa }, + { 0x1000db12, 0x00 }, + { 0x1000db13, 0x00 }, + { 0x1000db14, 0x09 }, + { 0x0000d540, 0x21 }, + { 0x0000c570, 0x08 }, + { 0x0000d714, 0x17 }, + { 0x0000c5c3, 0xf2 }, + { 0x0000c5c8, 0x03 }, + { 0x20009012, 0x00 }, + { 0x0000dd08, 0x17 }, + { 0x0000dd09, 0x0e }, + { 0x0000dd0a, 0x17 }, + { 0x0000dd0b, 0x0e }, + { 0x0000c570, 0x08 }, + { 0x0000d471, 0x3a }, + { 0x0000db00, 0x00 }, + { 0x0000db01, 0x00 }, + { 0x0000db02, 0x73 }, + { 0x0000db03, 0x00 }, + { 0x0000db04, 0x00 }, + { 0x0000db05, 0x00 }, + { 0x0000db06, 0x00 }, + { 0x0000db07, 0x00 }, + { 0x0000db08, 0x7f }, + { 0x0000db09, 0x00 }, + { 0x0000db1a, 0x00 }, + { 0x0000db1b, 0x00 }, + { 0x0000db19, 0x00 }, +}; + +static const struct reg_sequence rt1321_va2_blind_write[] = { + { 0x0000c003, 0xf0 }, + { 0x0000c01b, 0xfc }, + { 0x0000c5c3, 0xf2 }, + { 0x0000c5c2, 0x00 }, + { 0x0000c5c1, 0x10 }, + { 0x0000c5c0, 0x04 }, + { 0x0000c5c7, 0x03 }, + { 0x0000c5c6, 0x10 }, + { 0x0000c526, 0x47 }, + { 0x0000c5c4, 0x12 }, + { 0x0000c5c5, 0x60 }, + { 0x0000c520, 0x10 }, + { 0x0000c521, 0x32 }, + { 0x0000c5c7, 0x00 }, + { 0x0000c5c8, 0x03 }, + { 0x0000c5d3, 0x08 }, + { 0x0000c5d2, 0x0a }, + { 0x0000c5d1, 0x49 }, + { 0x0000c5d0, 0x0f }, + { 0x0000c580, 0x10 }, + { 0x0000c581, 0x32 }, + { 0x0000c582, 0x01 }, + { 0x0000c682, 0x60 }, + { 0x0000c019, 0x10 }, + { 0x0000c5f0, 0x01 }, + { 0x0000c5f7, 0x22 }, + { 0x0000c5f6, 0x22 }, + { 0x0000c057, 0x51 }, + { 0x0000c054, 0x55 }, + { 0x0000c053, 0x55 }, + { 0x0000c052, 0x55 }, + { 0x0000c051, 0x01 }, + { 0x0000c050, 0x15 }, + { 0x0000c060, 0x99 }, + { 0x0000c030, 0x55 }, + { 0x0000c061, 0x55 }, + { 0x0000c063, 0x55 }, + { 0x0000c065, 0xa5 }, + { 0x0000c06b, 0x0a }, + { 0x0000ca05, 0xd6 }, + { 0x0000ca06, 0x11 }, + { 0x0000ca07, 0x1e }, + { 0x0000ca25, 0xd6 }, + { 0x0000ca26, 0x11 }, + { 0x0000ca27, 0x1e }, + { 0x0000cd00, 0x05 }, + { 0x0000cd81, 0x49 }, + { 0x0000cd82, 0x49 }, + { 0x0000c604, 0x40 }, + { 0x0000c609, 0x40 }, + { 0x0000c046, 0xf7 }, + { 0x0000c045, 0xff }, + { 0x0000c044, 0xff }, + { 0x0000c043, 0xff }, + { 0x0000c042, 0xff }, + { 0x0000c041, 0xff }, + { 0x0000c040, 0xff }, + { 0x0000c049, 0xff }, + { 0x0000c028, 0x3f }, + { 0x0000c020, 0x3f }, + { 0x0000c032, 0x13 }, + { 0x0000c033, 0x01 }, + { 0x0000cc10, 0x01 }, + { 0x0000dc20, 0x03 }, + { 0x0000de03, 0x05 }, + { 0x0000dc00, 0x00 }, + { 0x0000c700, 0xf0 }, + { 0x0000c701, 0x13 }, + { 0x0000c900, 0xc3 }, + { 0x0000c570, 0x08 }, + { 0x0000c086, 0x02 }, + { 0x0000c085, 0x7f }, + { 0x0000c084, 0x00 }, + { 0x0000c081, 0xff }, + { 0x0000f084, 0x0f }, + { 0x0000f083, 0xff }, + { 0x0000f082, 0xff }, + { 0x0000f081, 0xff }, + { 0x0000f080, 0xff }, + { 0x20003003, 0x3f }, + { 0x20005818, 0x81 }, + { 0x20009018, 0x81 }, + { 0x2000301c, 0x81 }, + { 0x0000c003, 0xc0 }, + { 0x0000c047, 0x80 }, + { 0x0000d541, 0x80 }, + { 0x0000d487, 0x0b }, + { 0x0000d487, 0x3b }, + { 0x0000d486, 0xc3 }, + { 0x0000d470, 0x89 }, + { 0x0000d471, 0x3a }, + { 0x0000d472, 0x3d }, + { 0x0000d474, 0x11 }, + { 0x0000d475, 0x32 }, + { 0x0000d476, 0x64 }, + { 0x0000d477, 0x10 }, + { 0x0000d478, 0xff }, + { 0x0000d479, 0x20 }, + { 0x0000d47a, 0x10 }, + { 0x10008000, 0x67 }, + { 0x10008001, 0x80 }, + { 0x10008002, 0x00 }, + { 0x10008003, 0x00 }, + { 0x1000cd56, 0x00 }, + { 0x0000d486, 0x43 }, + { 0x3fc2dfc3, 0x00 }, + { 0x3fc2dfc2, 0x00 }, + { 0x3fc2dfc1, 0x00 }, + { 0x3fc2dfc0, 0x03 }, + { 0x3fc2dfc7, 0x00 }, + { 0x3fc2dfc6, 0x00 }, + { 0x3fc2dfc5, 0x00 }, + { 0x3fc2dfc4, 0x01 }, + { 0x3fc2dfa3, 0x00 }, + { 0x3fc2dfa2, 0x00 }, + { 0x3fc2dfa1, 0x00 }, + { 0x3fc2dfa0, 0x00 }, + { 0x3fc2df80, 0x10 }, + { 0x3fc2df81, 0x20 }, + { 0x3fc2df82, 0x00 }, + { 0x3fc2df83, 0x00 }, + { 0x3fc2df84, 0x50 }, + { 0x3fc2df85, 0x19 }, + { 0x3fc2df86, 0x00 }, + { 0x3fc2df87, 0x00 }, + { 0x3fc2df88, 0x52 }, + { 0x3fc2df89, 0x23 }, + { 0x3fc2df8a, 0x00 }, + { 0x3fc2df8b, 0x00 }, + { 0x3fc2df8c, 0xe0 }, + { 0x3fc2df8d, 0x2e }, + { 0x3fc2df8e, 0x00 }, + { 0x3fc2df8f, 0x00 }, + { 0x3fc2df90, 0xe0 }, + { 0x3fc2df91, 0x2e }, + { 0x3fc2df92, 0x00 }, + { 0x3fc2df93, 0x00 }, + { 0x3fc2df94, 0x01 }, + { 0x3fc2df95, 0x08 }, + { 0x3fc2df96, 0x00 }, + { 0x3fc2df97, 0x00 }, + { 0x3fc2df40, 0x80 }, + { 0x3fc2df41, 0xbb }, + { 0x3fc2df42, 0x00 }, + { 0x3fc2df43, 0x00 }, + { 0x3fc2df44, 0xc0 }, + { 0x3fc2df45, 0x99 }, + { 0x3fc2df46, 0x01 }, + { 0x3fc2df47, 0x00 }, + { 0x3fc2df48, 0x00 }, + { 0x3fc2df49, 0x00 }, + { 0x3fc2df4a, 0x00 }, + { 0x3fc2df4b, 0x00 }, + { 0x3fc2df4c, 0x00 }, + { 0x3fc2df4d, 0x00 }, + { 0x3fc2df4e, 0x00 }, + { 0x3fc2df4f, 0x00 }, + { 0x3fc2df50, 0x01 }, + { 0x3fc2df51, 0x00 }, + { 0x3fc2df52, 0x00 }, + { 0x3fc2df53, 0x00 }, + { 0x3fc2df54, 0x01 }, + { 0x3fc2df55, 0x00 }, + { 0x3fc2df56, 0x00 }, + { 0x3fc2df57, 0x00 }, + { 0x3fc2df58, 0x00 }, + { 0x3fc2df59, 0x00 }, + { 0x3fc2df5a, 0x00 }, + { 0x3fc2df5b, 0x00 }, + { 0x3fc2df5c, 0x01 }, + { 0x3fc2df5d, 0x00 }, + { 0x3fc2df5e, 0x00 }, + { 0x3fc2df5f, 0x00 }, + { 0x3fc2df60, 0x00 }, + { 0x3fc2df61, 0x00 }, + { 0x3fc2df62, 0x00 }, + { 0x3fc2df63, 0x00 }, + { 0x3fc2df64, 0x00 }, + { 0x3fc2df65, 0x00 }, + { 0x3fc2df66, 0x00 }, + { 0x3fc2df67, 0x10 }, + { 0x3fc2df68, 0x01 }, + { 0x3fc2df69, 0x00 }, + { 0x3fc2df6a, 0x00 }, + { 0x3fc2df6b, 0x00 }, + { 0x3fc2df6c, 0x01 }, + { 0x3fc2df6d, 0x00 }, + { 0x3fc2df6e, 0x00 }, + { 0x3fc2df6f, 0x00 }, + { 0x3fc2df70, 0x04 }, + { 0x3fc2df71, 0x00 }, + { 0x3fc2df72, 0x00 }, + { 0x3fc2df73, 0x00 }, + { 0x3fc2df74, 0x01 }, + { 0x3fc2df75, 0x00 }, + { 0x3fc2df76, 0x00 }, + { 0x3fc2df77, 0x00 }, + { 0x1000db00, 0x04 }, + { 0x1000db01, 0x00 }, + { 0x1000db02, 0x10 }, + { 0x1000db03, 0x00 }, + { 0x1000db04, 0x00 }, + { 0x1000db05, 0x45 }, + { 0x1000db06, 0x0d }, + { 0x1000db07, 0x01 }, + { 0x1000db08, 0x00 }, + { 0x1000db09, 0x00 }, + { 0x1000db0a, 0xbf }, + { 0x1000db0b, 0x0b }, + { 0x1000db0c, 0x11 }, + { 0x1000db0d, 0x00 }, + { 0x1000db0e, 0x00 }, + { 0x1000db0f, 0x00 }, + { 0x1000db10, 0x2c }, + { 0x1000db11, 0xfa }, + { 0x1000db12, 0x00 }, + { 0x1000db13, 0x00 }, + { 0x1000db14, 0x09 }, + { 0x0000d540, 0x21 }, + { 0x0000d714, 0x17 }, + { 0x0000dd0b, 0x0d }, + { 0x0000dd0a, 0xff }, + { 0x0000dd09, 0x0d }, + { 0x0000dd08, 0xff }, + { 0x0000c5fb, 0x12 }, + { 0x0000c570, 0x08 }, +}; + static const struct reg_default rt1320_reg_defaults[] = { { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, @@ -440,6 +836,7 @@ static const struct reg_default rt1320_mbq_defaults[] = { static bool rt1320_readable_register(struct device *dev, unsigned int reg) { switch (reg) { + case 0x004d: case 0xc000 ... 0xc086: case 0xc400 ... 0xc409: case 0xc480 ... 0xc48f: @@ -497,10 +894,15 @@ static bool rt1320_readable_register(struct device *dev, unsigned int reg) case RT1321_PATCH_MAIN_VER ... RT1321_PATCH_BETA_VER: case 0x1000f008: case 0x1000f021: - case 0x2000300f: + case 0x20003000 ... 0x2000300f: case 0x2000301c: - case 0x2000900f: + case 0x20003040 ... 0x20003059: + case 0x20005800 ... 0x2000580f: + case 0x20005818: + case 0x20005840 ... 0x20005859: + case 0x20009000 ... 0x2000900f: case 0x20009018: + case 0x20009040 ... 0x20009059: case 0x3fc000c0 ... 0x3fc2dfc8: case 0x3fe00000 ... 0x3fe36fff: /* 0x40801508/0x40801809/0x4080180a/0x40801909/0x4080190a */ @@ -545,6 +947,7 @@ static bool rt1320_readable_register(struct device *dev, unsigned int reg) static bool rt1320_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { + case 0x004d: case 0xc000: case 0xc003: case 0xc081: @@ -596,15 +999,20 @@ static bool rt1320_volatile_register(struct device *dev, unsigned int reg) case 0x1000c000 ... 0x1000dfff: case 0x1000f008: case 0x1000f021: - case 0x2000300f: + case 0x2000300e ... 0x2000300f: case 0x2000301c: - case 0x2000900f: + case 0x20003040 ... 0x20003059: + case 0x2000580e ... 0x2000580f: + case 0x20005818: + case 0x20005840 ... 0x20005859: + case 0x2000900e ... 0x2000900f: case 0x20009018: + case 0x20009040 ... 0x20009059: case 0x3fc2ab80 ... 0x3fc2ac4c: case 0x3fc2b780: case 0x3fc2bf80 ... 0x3fc2bf83: case 0x3fc2bfc0 ... 0x3fc2bfc8: - case 0x3fc2d300 ... 0x3fc2d354: + case 0x3fc2d300 ... 0x3fc2d3cc: case 0x3fc2dfc0 ... 0x3fc2dfc8: case 0x3fe2e000 ... 0x3fe2e003: case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0): @@ -892,6 +1300,42 @@ static int rt1320_check_fw_ready(struct rt1320_sdw_priv *rt1320) return 0; } +static int rt1320_dspfw_status(struct rt1320_sdw_priv *rt1320) +{ + struct device *dev = &rt1320->sdw_slave->dev; + unsigned int fw_status_addr, fw_ready; + unsigned int dspfw_run; + + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + fw_status_addr = RT1320_DSPFW_STATUS_ADDR; + break; + case RT1321_DEV_ID: + fw_status_addr = RT1321_DSPFW_STATUS_ADDR; + break; + default: + dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); + return -EINVAL; + } + + regmap_read(rt1320->regmap, fw_status_addr, &fw_ready); + fw_ready &= 0x1; + + if (rt1320->dev_id == RT1321_DEV_ID) { + regmap_read(rt1320->regmap, 0xf01e, &dspfw_run); + dspfw_run &= 0x1; + fw_ready = (!dspfw_run && fw_ready); + } + + if (fw_ready) { + dev_dbg(dev, "%s, DSP FW was already\n", __func__); + return 1; + } + + dev_dbg(dev, "%s, DSP FW is NOT ready. Please load DSP FW first\n", __func__); + return 0; +} + static int rt1320_check_power_state_ready(struct rt1320_sdw_priv *rt1320, enum rt1320_power_state ps) { struct device *dev = &rt1320->sdw_slave->dev; @@ -982,6 +1426,9 @@ static int rt1320_fw_param_protocol(struct rt1320_sdw_priv *rt1320, enum rt1320_ if (!tempbuf) return -ENOMEM; + if (rt1320->dev_id == RT1321_DEV_ID && rt1320->version_id == RT1321_VA2) + paramid += 0x0bff0000; + paramhr.moudleid = 1; paramhr.commandtype = cmdid; /* 8 is "sizeof(paramid) + sizeof(paramlength)" */ @@ -1120,45 +1567,73 @@ static void rt1320_calc_r0(struct rt1320_sdw_priv *rt1320) l_calir0, l_calir0_lo, r_calir0, r_calir0_lo); } +static int rt1320_pilot_tone_output(struct rt1320_sdw_priv *rt1320) +{ + struct device *dev = &rt1320->sdw_slave->dev; + int l_targetpostgain, r_targetpostgain; + unsigned long long factor = (1 << 12); + int l_pilotgain[9], r_pilotgain[9]; + const int postgain_step = 234; + int targetGain; + + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + targetGain = -320000; + break; + case RT1321_DEV_ID: + targetGain = -420000; + if (rt1320->version_id == RT1321_VA0) + targetGain = -320000; + break; + default: + dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); + return -EINVAL; + } + + rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 70, &l_pilotgain[0], sizeof(l_pilotgain)); + rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 71, &r_pilotgain[0], sizeof(r_pilotgain)); + dev_dbg(dev, "%s, LR pilotgain %d, %d\n", __func__, l_pilotgain[2], r_pilotgain[2]); + + /* calculate pilot tone gain */ + l_pilotgain[2] = (l_pilotgain[2] * 10000) / factor; + r_pilotgain[2] = (r_pilotgain[2] * 10000) / factor; + + /* calculate post gain to meet target gain */ + l_targetpostgain = abs(targetGain - l_pilotgain[2]) / postgain_step; + r_targetpostgain = abs(targetGain - r_pilotgain[2]) / postgain_step; + l_targetpostgain = 0xfff - l_targetpostgain; + r_targetpostgain = 0xfff - r_targetpostgain; + dev_dbg(dev, "%s, LR targetpostgain=0x%x, 0x%x\n", __func__, l_targetpostgain, r_targetpostgain); + + regmap_write(rt1320->regmap, 0xdd0b, (l_targetpostgain & 0xf00) >> 8); + regmap_write(rt1320->regmap, 0xdd0a, l_targetpostgain & 0xff); + regmap_write(rt1320->regmap, 0xdd09, (r_targetpostgain & 0xf00) >> 8); + regmap_write(rt1320->regmap, 0xdd08, r_targetpostgain & 0xff); + + return 0; +} + static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320) { struct device *dev = &rt1320->sdw_slave->dev; struct rt1320_datafixpoint audfixpoint[2]; unsigned int reg_c5fb, reg_c570, reg_cd00; - unsigned int vol_reg[4], fw_ready; + unsigned int vol_reg[4]; unsigned long long l_meanr0, r_meanr0; - unsigned int fw_status_addr; int l_re[5], r_re[5]; int ret, tmp; unsigned long long factor = (1 << 27); unsigned short l_advancegain, r_advancegain; unsigned int delay_s = 7; /* delay seconds for the calibration */ + int dspfw_status; if (!rt1320->component) return; - switch (rt1320->dev_id) { - case RT1320_DEV_ID: - fw_status_addr = RT1320_DSPFW_STATUS_ADDR; - break; - case RT1321_DEV_ID: - fw_status_addr = RT1321_DSPFW_STATUS_ADDR; - break; - default: - dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); - return; - } - - /* set volume 0dB */ regmap_read(rt1320->regmap, 0xdd0b, &vol_reg[3]); regmap_read(rt1320->regmap, 0xdd0a, &vol_reg[2]); regmap_read(rt1320->regmap, 0xdd09, &vol_reg[1]); regmap_read(rt1320->regmap, 0xdd08, &vol_reg[0]); - regmap_write(rt1320->regmap, 0xdd0b, 0x0f); - regmap_write(rt1320->regmap, 0xdd0a, 0xff); - regmap_write(rt1320->regmap, 0xdd09, 0x0f); - regmap_write(rt1320->regmap, 0xdd08, 0xff); - regmap_read(rt1320->regmap, 0xc5fb, ®_c5fb); regmap_read(rt1320->regmap, 0xc570, ®_c570); regmap_read(rt1320->regmap, 0xcd00, ®_cd00); @@ -1171,9 +1646,8 @@ static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320) goto _finish_; } - regmap_read(rt1320->regmap, fw_status_addr, &fw_ready); - fw_ready &= 0x1; - if (!fw_ready) { + dspfw_status = rt1320_dspfw_status(rt1320); + if (dspfw_status <= 0) { dev_dbg(dev, "%s, DSP FW is NOT ready. Please load DSP FW first\n", __func__); goto _finish_; } @@ -1184,8 +1658,19 @@ static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320) goto _finish_; } - if (rt1320->dev_id == RT1320_DEV_ID) - regmap_write(rt1320->regmap, 0xc5fb, 0x00); + /* fine tune pilot tone output */ + ret = rt1320_pilot_tone_output(rt1320); + if (ret < 0) { + dev_dbg(dev, "%s, Failed to tune pilot tone output\n", __func__); + goto _finish_; + } + + if (rt1320->dev_id == RT1321_DEV_ID) { + regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x00); + regmap_write(rt1320->regmap, 0xc5c4, 0x12); + } + + regmap_write(rt1320->regmap, 0xc5fb, 0x00); regmap_write(rt1320->regmap, 0xc570, 0x0b); regmap_write(rt1320->regmap, 0xcd00, 0xc5); @@ -1246,6 +1731,11 @@ _finish_: SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03); rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x03); + if (rt1320->dev_id == RT1321_DEV_ID) { + regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x80); + regmap_write(rt1320->regmap, 0xc5c4, 0x10); + } + /* advance gain will be set when R0 load, not here */ regmap_write(rt1320->regmap, 0xdd0b, vol_reg[3]); regmap_write(rt1320->regmap, 0xdd0a, vol_reg[2]); @@ -1296,7 +1786,7 @@ static int rt1320_r0_cali_put(struct snd_kcontrol *kcontrol, static void rt1320_load_mcu_patch(struct rt1320_sdw_priv *rt1320) { struct sdw_slave *slave = rt1320->sdw_slave; - const struct firmware *patch; + const struct firmware *patch __free(firmware) = NULL; const char *filename; unsigned int addr, val, min_addr, max_addr; const unsigned char *ptr; @@ -1312,6 +1802,9 @@ static void rt1320_load_mcu_patch(struct rt1320_sdw_priv *rt1320) max_addr = 0x10007fff; break; case RT1321_DEV_ID: + if (rt1320->version_id == RT1321_VA2) + return; + filename = RT1321_VA_MCU_PATCH; min_addr = 0x10008000; max_addr = 0x10008fff; @@ -1347,17 +1840,15 @@ static void rt1320_load_mcu_patch(struct rt1320_sdw_priv *rt1320) if (addr > max_addr || addr < min_addr) { dev_err(&slave->dev, "%s: the address 0x%x is wrong", __func__, addr); - goto _exit_; + return; } if (val > 0xff) { dev_err(&slave->dev, "%s: the value 0x%x is wrong", __func__, val); - goto _exit_; + return; } regmap_write(rt1320->regmap, addr, val); } } -_exit_: - release_firmware(patch); } } @@ -1382,30 +1873,17 @@ static void rt1320_vab_preset(struct rt1320_sdw_priv *rt1320) static void rt1320_t0_load(struct rt1320_sdw_priv *rt1320, unsigned int l_t0, unsigned int r_t0) { struct device *dev = &rt1320->sdw_slave->dev; - unsigned int factor = (1 << 22), fw_ready; + unsigned int factor = (1 << 22); int l_t0_data[38], r_t0_data[38]; - unsigned int fw_status_addr; - - switch (rt1320->dev_id) { - case RT1320_DEV_ID: - fw_status_addr = RT1320_DSPFW_STATUS_ADDR; - break; - case RT1321_DEV_ID: - fw_status_addr = RT1321_DSPFW_STATUS_ADDR; - break; - default: - dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); - return; - } + int dspfw_status; regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00); rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x00); - regmap_read(rt1320->regmap, fw_status_addr, &fw_ready); - fw_ready &= 0x1; - if (!fw_ready) { + dspfw_status = rt1320_dspfw_status(rt1320); + if (dspfw_status <= 0) { dev_warn(dev, "%s, DSP FW is NOT ready\n", __func__); goto _exit_; } @@ -1444,7 +1922,7 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320) struct device *dev = &rt1320->sdw_slave->dev; static const char func_tag[] = "FUNC"; static const char xu_tag[] = "XU"; - const struct firmware *rae_fw = NULL; + const struct firmware *rae_fw __free(firmware) = NULL; unsigned int fw_offset; unsigned char *fw_data; unsigned char *param_data; @@ -1483,22 +1961,46 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320) request_firmware(&rae_fw, rae_filename, dev); if (rae_fw) { - /* RAE CRC clear */ - regmap_write(rt1320->regmap, 0xe80b, 0x0f); - - /* RAE stop & CRC disable */ - regmap_update_bits(rt1320->regmap, 0xe803, 0xbc, 0x00); - - while (--retry) { - regmap_read(rt1320->regmap, 0xe83f, &value); - if (value & 0x40) - break; - usleep_range(1000, 1100); - } - if (!retry && !(value & 0x40)) { - dev_err(dev, "%s: RAE is not ready to load\n", __func__); - release_firmware(rae_fw); - return -ETIMEDOUT; + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + /* RAE CRC clear */ + regmap_write(rt1320->regmap, 0xe80b, 0x0f); + /* RAE stop & CRC disable */ + regmap_update_bits(rt1320->regmap, 0xe803, 0xbc, 0x00); + while (--retry) { + regmap_read(rt1320->regmap, 0xe83f, &value); + if (value & 0x40) + break; + usleep_range(1000, 1100); + } + if (!retry && !(value & 0x40)) { + dev_err(dev, "%s: RAE is not ready to load\n", __func__); + return -ETIMEDOUT; + } + break; + case RT1321_DEV_ID: + /* RAE CRC clear */ + regmap_write(rt1320->regmap, 0x2000300e, 0xc0); + regmap_write(rt1320->regmap, 0x2000300f, 0x0f); + /* RAE stop & Phase sync & CRC disable */ + regmap_update_bits(rt1320->regmap, 0x20003003, 0xfe, 0x00); + regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x00); + regmap_update_bits(rt1320->regmap, 0x2000301c, 0x01, 0x00); + /* check whether write state is ready */ + while (--retry) { + regmap_read(rt1320->regmap, 0x20003043, &value); + if (value & 0x40) + break; + usleep_range(1000, 1100); + } + if (!retry && !(value & 0x40)) { + dev_err(dev, "%s: RAE is not ready to load\n", __func__); + return -ETIMEDOUT; + } + break; + default: + dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); + return -EINVAL; } dev_dbg(dev, "%s, rae_fw size=0x%zx\n", __func__, rae_fw->size); @@ -1551,7 +2053,6 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320) } regcache_cache_bypass(rt1320->regmap, false); - release_firmware(rae_fw); } else { dev_err(dev, "%s: Failed to load %s firmware\n", __func__, rae_filename); @@ -1559,18 +2060,34 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320) goto _exit_; } - /* RAE CRC enable */ - regmap_update_bits(rt1320->regmap, 0xe803, 0x0c, 0x0c); - - /* RAE update */ - regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x00); - regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x80); - - /* RAE run */ - regmap_update_bits(rt1320->regmap, 0xe803, 0x80, 0x80); - - regmap_read(rt1320->regmap, 0xe80b, &value); - dev_dbg(dev, "%s: CAE run => 0xe80b reg = 0x%x\n", __func__, value); + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + /* RAE CRC enable */ + regmap_update_bits(rt1320->regmap, 0xe803, 0x0c, 0x0c); + /* RAE update */ + regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x00); + regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x80); + /* RAE run */ + regmap_update_bits(rt1320->regmap, 0xe803, 0x80, 0x80); + regmap_read(rt1320->regmap, 0xe80b, &value); + dev_dbg(dev, "%s: CAE run => 0xe80b reg = 0x%x\n", __func__, value); + break; + case RT1321_DEV_ID: + /* RAE CRC enable */ + regmap_update_bits(rt1320->regmap, 0x20003003, 0x30, 0x30); + /* RAE update */ + regmap_update_bits(rt1320->regmap, 0x2000301c, 0x80, 0x00); + regmap_update_bits(rt1320->regmap, 0x2000301c, 0x80, 0x80); + regmap_update_bits(rt1320->regmap, 0x20009018, 0x80, 0x00); + regmap_update_bits(rt1320->regmap, 0x20009018, 0x80, 0x80); + regmap_update_bits(rt1320->regmap, 0x20005818, 0x80, 0x00); + regmap_update_bits(rt1320->regmap, 0x20005818, 0x80, 0x80); + /* RAE run */ + regmap_update_bits(rt1320->regmap, 0x2000301c, 0x01, 0x01); + /* Phase sync eanble */ + regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x80); + break; + } rt1320->rae_update_done = true; @@ -1598,32 +2115,21 @@ struct rt1320_dspfwheader { struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(rt1320->component); struct device *dev = &rt1320->sdw_slave->dev; - unsigned int val, i, fw_offset, fw_ready; - unsigned int fw_status_addr; + unsigned int val, i, fw_offset; struct rt1320_dspfwheader *fwheader; struct rt1320_imageinfo *ptr_img; struct sdw_bpt_section sec[10]; - const struct firmware *fw = NULL; + const struct firmware *fw __free(firmware) = NULL; unsigned char *fw_data; bool dev_fw_match = false; static const char hdr_sig[] = "AFX"; unsigned int hdr_size = 0; const char *dmi_vendor, *dmi_product, *dmi_sku; int len_vendor, len_product, len_sku; + unsigned char boot_mode = 0; /* 0: from RAM; 1: from ROM */ + unsigned char has_0x3fc00000 = 0; char filename[512]; - switch (rt1320->dev_id) { - case RT1320_DEV_ID: - fw_status_addr = RT1320_DSPFW_STATUS_ADDR; - break; - case RT1321_DEV_ID: - fw_status_addr = RT1321_DSPFW_STATUS_ADDR; - break; - default: - dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); - return; - } - dmi_vendor = dmi_get_system_info(DMI_SYS_VENDOR); dmi_product = dmi_get_system_info(DMI_PRODUCT_NAME); dmi_sku = dmi_get_system_info(DMI_PRODUCT_SKU); @@ -1653,17 +2159,12 @@ struct rt1320_dspfwheader { RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00); rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x00); - regmap_read(rt1320->regmap, fw_status_addr, &fw_ready); - fw_ready &= 0x1; - if (fw_ready) { + if (rt1320_dspfw_status(rt1320)) { dev_dbg(dev, "%s, DSP FW was already\n", __func__); rt1320->fw_load_done = true; goto _exit_; } - /* change to IRAM */ - regmap_update_bits(rt1320->regmap, 0xf01e, 0x80, 0x00); - request_firmware(&fw, filename, dev); if (fw) { fwheader = (struct rt1320_dspfwheader *)fw->data; @@ -1672,7 +2173,6 @@ struct rt1320_dspfwheader { if (fwheader->sync != 0x0a1c5679) { dev_err(dev, "%s: FW sync error\n", __func__); - release_firmware(fw); goto _exit_; } @@ -1709,9 +2209,11 @@ struct rt1320_dspfwheader { dev_fw_match = true; break; case RT1321_DEV_ID: - if (ptr_img->addr == 0x3fc00000) - if (fw_data[9] == '1') + if (ptr_img->addr == 0x3fc00000) { + if (fw_data[7] == '1') dev_fw_match = true; + has_0x3fc00000 = 1; + } break; default: dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); @@ -1721,6 +2223,22 @@ struct rt1320_dspfwheader { fw_offset += ptr_img->size; } + if (rt1320->dev_id == RT1321_DEV_ID && rt1320->version_id == RT1321_VA2) { + /* + * For 1321 VA2, if the FW doesn't include the section for address 0x3fc00000, + * it means the FW will boot from ROM and force dev_fw_match to true to download FW by BRA. + */ + if (!has_0x3fc00000) { + boot_mode = 1; + dev_fw_match = true; + } + dev_dbg(dev, "%s: Boot from %s for VA2\n", __func__, (boot_mode ? "ROM" : "RAM")); + } + + /* change to IRAM */ + if (!boot_mode) + regmap_update_bits(rt1320->regmap, 0xf01e, 0x80, 0x00); + if (dev_fw_match) { dev_dbg(dev, "%s, starting BRA downloading FW..\n", __func__); rt1320->bra_msg.dev_num = rt1320->sdw_slave->dev_num; @@ -1732,7 +2250,6 @@ struct rt1320_dspfwheader { } regcache_cache_bypass(rt1320->regmap, false); - release_firmware(fw); if (!dev_fw_match) { dev_err(dev, "%s: FW file doesn't match to device\n", __func__); @@ -1743,24 +2260,39 @@ struct rt1320_dspfwheader { goto _exit_; } - /* run RAM code */ - regmap_read(rt1320->regmap, 0x3fc2bfc0, &val); - val |= 0x8; - regmap_write(rt1320->regmap, 0x3fc2bfc0, val); - - /* clear frame counter */ switch (rt1320->dev_id) { case RT1320_DEV_ID: + /* run RAM code */ + regmap_read(rt1320->regmap, 0x3fc2bfc0, &val); + val |= 0x8; + regmap_write(rt1320->regmap, 0x3fc2bfc0, val); + /* clear frame counter */ regmap_write(rt1320->regmap, 0x3fc2bfcb, 0x00); regmap_write(rt1320->regmap, 0x3fc2bfca, 0x00); regmap_write(rt1320->regmap, 0x3fc2bfc9, 0x00); regmap_write(rt1320->regmap, 0x3fc2bfc8, 0x00); break; case RT1321_DEV_ID: + if (!boot_mode) { + /* run RAM code */ + regmap_read(rt1320->regmap, 0x3fc2dfc0, &val); + val |= 0x8; + regmap_write(rt1320->regmap, 0x3fc2dfc0, val); + } + /* clear frame counter */ regmap_write(rt1320->regmap, 0x3fc2dfcb, 0x00); regmap_write(rt1320->regmap, 0x3fc2dfca, 0x00); regmap_write(rt1320->regmap, 0x3fc2dfc9, 0x00); regmap_write(rt1320->regmap, 0x3fc2dfc8, 0x00); + /* enable handshake */ + regmap_write(rt1320->regmap, 0x3fc2dfc4, 0x00); + regmap_write(rt1320->regmap, 0xd470, 0xad); + /* minimum phase settings */ + regmap_write(rt1320->regmap, 0xc5c4, 0x10); + regmap_write(rt1320->regmap, 0x20003003, 0x31); + regmap_update_bits(rt1320->regmap, 0x20003002, 0x40, 0x00); + regmap_write(rt1320->regmap, 0xc5b3, 0x01); + regmap_write(rt1320->regmap, 0xc052, 0x11); break; } @@ -1843,14 +2375,35 @@ static void rt1320_vc_preset(struct rt1320_sdw_priv *rt1320) static void rt1321_preset(struct rt1320_sdw_priv *rt1320) { + const struct reg_sequence *blindwrite; unsigned int i, reg, val, delay; + unsigned int array_size; + + switch (rt1320->version_id) { + case RT1321_VA0: + blindwrite = rt1321_blind_write; + array_size = ARRAY_SIZE(rt1321_blind_write); + break; + case RT1321_VA1: + blindwrite = rt1321_va1_blind_write; + array_size = ARRAY_SIZE(rt1321_va1_blind_write); + break; + case RT1321_VA2: + blindwrite = rt1321_va2_blind_write; + array_size = ARRAY_SIZE(rt1321_va2_blind_write); + break; + default: + dev_err(&rt1320->sdw_slave->dev, "%s: Unknown version ID %d\n", + __func__, rt1320->version_id); + return; + } - for (i = 0; i < ARRAY_SIZE(rt1321_blind_write); i++) { - reg = rt1321_blind_write[i].reg; - val = rt1321_blind_write[i].def; - delay = rt1321_blind_write[i].delay_us; + for (i = 0; i < array_size; i++) { + reg = blindwrite[i].reg; + val = blindwrite[i].def; + delay = blindwrite[i].delay_us; - if (reg == 0x3fc2dfc3) + if (reg == 0x1000cd56) rt1320_load_mcu_patch(rt1320); regmap_write(rt1320->regmap, reg, val); @@ -1892,6 +2445,24 @@ static int rt1320_io_init(struct device *dev, struct sdw_slave *slave) regmap_read(rt1320->regmap, RT1320_DEV_ID_0, &val); regmap_read(rt1320->regmap, RT1320_DEV_ID_1, &tmp); rt1320->dev_id = (val << 8) | tmp; + + /* This is a workaround that reads the value twice to obtain the correct result. */ + rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_0, &val); + rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_1, &tmp); + rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_0, &val); + rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_1, &tmp); + val = (val << 8) | tmp; + + if (rt1320->dev_id == RT1321_DEV_ID) { + if (rt1320->version_id == 0x01) + rt1320->version_id = RT1321_VA2; + else if (val == RT1321_DEV_HV_VA0_ID) + rt1320->version_id = RT1321_VA0; + else if (val == RT1321_DEV_HV_VA1_ID) + rt1320->version_id = RT1321_VA1; + else + dev_err(dev, "%s: Unknown version ID 0x%x for RT1321\n", __func__, rt1320->version_id); + } } regmap_read(rt1320->regmap, @@ -2326,25 +2897,12 @@ static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0); static int rt1320_r0_load(struct rt1320_sdw_priv *rt1320) { struct device *dev = regmap_get_device(rt1320->regmap); - unsigned int fw_status_addr; - unsigned int fw_ready; + int dspfw_status; int ret = 0; if (!rt1320->r0_l_reg || !rt1320->r0_r_reg) return -EINVAL; - switch (rt1320->dev_id) { - case RT1320_DEV_ID: - fw_status_addr = RT1320_DSPFW_STATUS_ADDR; - break; - case RT1321_DEV_ID: - fw_status_addr = RT1321_DSPFW_STATUS_ADDR; - break; - default: - dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); - return -EINVAL; - } - regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00); ret = rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x00); @@ -2353,9 +2911,8 @@ static int rt1320_r0_load(struct rt1320_sdw_priv *rt1320) goto _timeout_; } - regmap_read(rt1320->regmap, fw_status_addr, &fw_ready); - fw_ready &= 0x1; - if (!fw_ready) { + dspfw_status = rt1320_dspfw_status(rt1320); + if (dspfw_status <= 0) { dev_dbg(dev, "%s, DSP FW is NOT ready\n", __func__); goto _timeout_; } @@ -2458,7 +3015,7 @@ static int rt1320_dspfw_load_put(struct snd_kcontrol *kcontrol, if (!rt1320->hw_init) return 0; - ret = pm_runtime_resume(component->dev); + ret = pm_runtime_resume_and_get(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -2469,6 +3026,8 @@ static int rt1320_dspfw_load_put(struct snd_kcontrol *kcontrol, if (!ucontrol->value.integer.value[0]) rt1320->fw_load_done = false; + pm_runtime_mark_last_busy(component->dev); + pm_runtime_put_autosuspend(component->dev); return 0; } @@ -2819,6 +3378,37 @@ static int rt1320_sdw_pcm_hw_free(struct snd_pcm_substream *substream, return 0; } +static int rt1320_bus_config(struct sdw_slave *slave, + struct sdw_bus_params *params) +{ + struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(&slave->dev); + unsigned int clk_base; + + regmap_read(rt1320->regmap, 0x004d, &clk_base); + dev_dbg(&rt1320->sdw_slave->dev, "%s clk_base=%x", __func__, clk_base); + + switch (clk_base) { + case RT1320_CLK_FREQ_19_2_MHZ: + case RT1320_CLK_FREQ_24MHZ: + regmap_write(rt1320->regmap, 0xc600, 0x04); + regmap_write(rt1320->regmap, 0xc601, 0x83); + regmap_write(rt1320->regmap, 0xc602, 0x1f); + regmap_write(rt1320->regmap, 0xc603, 0x40); + break; + case RT1320_CLK_FREQ_24_576MHZ: + case RT1320_CLK_FREQ_22_5792MHZ: + regmap_write(rt1320->regmap, 0xc600, 0x07); + regmap_write(rt1320->regmap, 0xc601, 0x80); + regmap_write(rt1320->regmap, 0xc602, 0x0f); + regmap_write(rt1320->regmap, 0xc603, 0x40); + break; + default: + return -EINVAL; + } + + return 0; +} + /* * slave_ops: callbacks for get_clock_stop_mode, clock_stop and * port_prep are not defined for now @@ -2826,12 +3416,13 @@ static int rt1320_sdw_pcm_hw_free(struct snd_pcm_substream *substream, static const struct sdw_slave_ops rt1320_slave_ops = { .read_prop = rt1320_read_prop, .update_status = rt1320_update_status, + .bus_config = rt1320_bus_config, }; static int rt1320_sdw_component_probe(struct snd_soc_component *component) { - int ret; struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); + int ret; rt1320->component = component; @@ -3062,10 +3653,23 @@ static int rt1320_dev_resume(struct device *dev) return ret; regcache_cache_only(rt1320->regmap, false); - regcache_sync(rt1320->regmap); + ret = regcache_sync(rt1320->regmap); + if (ret) + goto err_sync; + regcache_cache_only(rt1320->mbq_regmap, false); - regcache_sync(rt1320->mbq_regmap); + ret = regcache_sync(rt1320->mbq_regmap); + if (ret) + goto err_sync; + return 0; + +err_sync: + regcache_cache_only(rt1320->regmap, true); + regcache_cache_only(rt1320->mbq_regmap, true); + regcache_mark_dirty(rt1320->regmap); + regcache_mark_dirty(rt1320->mbq_regmap); + return ret; } static const struct dev_pm_ops rt1320_pm = { diff --git a/sound/soc/codecs/rt1320-sdw.h b/sound/soc/codecs/rt1320-sdw.h index a7b573883dd0..df9ccdf92d36 100644 --- a/sound/soc/codecs/rt1320-sdw.h +++ b/sound/soc/codecs/rt1320-sdw.h @@ -17,12 +17,17 @@ #define RT1320_DEV_ID 0x6981 #define RT1321_DEV_ID 0x7045 +#define RT1321_DEV_HV_VA0_ID 0x6997 +#define RT1321_DEV_HV_VA1_ID 0x7071 /* imp-defined registers */ #define RT1320_DEV_VERSION_ID_1 0xc404 #define RT1320_DEV_ID_1 0xc405 #define RT1320_DEV_ID_0 0xc406 +#define RT1320_HV_DEV_ID_0 0xf622 +#define RT1320_HV_DEV_ID_1 0xf623 + #define RT1320_POWER_STATE 0xc560 #define RT1321_PATCH_MAIN_VER 0x1000cffe @@ -94,6 +99,12 @@ enum rt1320_version_id { RT1320_VC, }; +enum rt1321_version_id { + RT1321_VA0, + RT1321_VA1, + RT1321_VA2, +}; + #define RT1320_VER_B_ID 0x07392238 #define RT1320_VAB_MCU_PATCH "realtek/rt1320/rt1320-patch-code-vab.bin" #define RT1320_VC_MCU_PATCH "realtek/rt1320/rt1320-patch-code-vc.bin" @@ -121,6 +132,7 @@ struct rt1320_datafixpoint { int invrs; }; +/* FW parameter id 1300 */ typedef struct FwPara_HwSwGain { unsigned int SwAdvGain; unsigned int SwBasGain; @@ -163,6 +175,13 @@ enum rt1320_rw_type { RT1320_PARAM_READ = 3, }; +enum { + RT1320_CLK_FREQ_19_2_MHZ = 1, + RT1320_CLK_FREQ_24MHZ = 2, + RT1320_CLK_FREQ_24_576MHZ = 3, + RT1320_CLK_FREQ_22_5792MHZ = 4, +}; + struct rt1320_sdw_priv { struct snd_soc_component *component; struct regmap *regmap; diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index 63b5fc439773..f8c370106504 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -184,8 +184,10 @@ static const struct reg_default rt274_reg[] = { { 0x0023a000, 0x00000057 }, { 0x00270500, 0x00000400 }, { 0x00370500, 0x00000400 }, + { 0x00830000, 0x00000097 }, { 0x00870500, 0x00000400 }, { 0x00920000, 0x00000031 }, + { 0x00930000, 0x00000097 }, { 0x00935000, 0x00000097 }, { 0x00936000, 0x00000097 }, { 0x00970500, 0x00000400 }, @@ -195,10 +197,12 @@ static const struct reg_default rt274_reg[] = { { 0x00c37000, 0x00000400 }, { 0x00c37100, 0x00000400 }, { 0x01270500, 0x00000400 }, + { 0x01270700, 0x00000000 }, { 0x01370500, 0x00000400 }, { 0x01371f00, 0x411111f0 }, { 0x01937000, 0x00000000 }, { 0x01970500, 0x00000400 }, + { 0x01970700, 0x00000020 }, { 0x02050000, 0x0000001b }, { 0x02139000, 0x00000080 }, { 0x0213a000, 0x00000080 }, @@ -207,10 +211,6 @@ static const struct reg_default rt274_reg[] = { { 0x02170700, 0x00000000 }, { 0x02270100, 0x00000000 }, { 0x02370100, 0x00000000 }, - { 0x01970700, 0x00000020 }, - { 0x00830000, 0x00000097 }, - { 0x00930000, 0x00000097 }, - { 0x01270700, 0x00000000 }, }; static bool rt274_volatile_register(struct device *dev, unsigned int reg) diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index ded0ea332480..4217467904d6 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -77,8 +77,10 @@ static const struct reg_default rt286_reg[] = { { 0x0023a000, 0x0000007f }, { 0x00270500, 0x00000400 }, { 0x00370500, 0x00000400 }, + { 0x00830000, 0x000000c3 }, { 0x00870500, 0x00000400 }, { 0x00920000, 0x00000031 }, + { 0x00930000, 0x000000c3 }, { 0x00935000, 0x000000c3 }, { 0x00936000, 0x000000c3 }, { 0x00970500, 0x00000400 }, @@ -88,16 +90,18 @@ static const struct reg_default rt286_reg[] = { { 0x00c37000, 0x00000000 }, { 0x00c37100, 0x00000080 }, { 0x01270500, 0x00000400 }, + { 0x01270700, 0x00000000 }, { 0x01370500, 0x00000400 }, { 0x01371f00, 0x411111f0 }, { 0x01439000, 0x00000080 }, { 0x0143a000, 0x00000080 }, - { 0x01470700, 0x00000000 }, + { 0x01470100, 0x00000000 }, { 0x01470500, 0x00000400 }, + { 0x01470700, 0x00000000 }, { 0x01470c00, 0x00000000 }, - { 0x01470100, 0x00000000 }, { 0x01837000, 0x00000000 }, { 0x01870500, 0x00000400 }, + { 0x01870700, 0x00000020 }, { 0x02050000, 0x00000000 }, { 0x02139000, 0x00000080 }, { 0x0213a000, 0x00000080 }, @@ -106,10 +110,6 @@ static const struct reg_default rt286_reg[] = { { 0x02170700, 0x00000000 }, { 0x02270100, 0x00000000 }, { 0x02370100, 0x00000000 }, - { 0x01870700, 0x00000020 }, - { 0x00830000, 0x000000c3 }, - { 0x00930000, 0x000000c3 }, - { 0x01270700, 0x00000000 }, }; static bool rt286_volatile_register(struct device *dev, unsigned int reg) diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index 5414a1712b57..09aed08b5b79 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -78,8 +78,10 @@ static const struct reg_default rt298_reg[] = { { 0x0023a000, 0x0000007f }, { 0x00270500, 0x00000400 }, { 0x00370500, 0x00000400 }, + { 0x00830000, 0x000000c3 }, { 0x00870500, 0x00000400 }, { 0x00920000, 0x00000031 }, + { 0x00930000, 0x000000c3 }, { 0x00935000, 0x000000c3 }, { 0x00936000, 0x000000c3 }, { 0x00970500, 0x00000400 }, @@ -89,16 +91,18 @@ static const struct reg_default rt298_reg[] = { { 0x00c37000, 0x00000000 }, { 0x00c37100, 0x00000080 }, { 0x01270500, 0x00000400 }, + { 0x01270700, 0x00000000 }, { 0x01370500, 0x00000400 }, { 0x01371f00, 0x411111f0 }, { 0x01439000, 0x00000080 }, { 0x0143a000, 0x00000080 }, - { 0x01470700, 0x00000000 }, + { 0x01470100, 0x00000000 }, { 0x01470500, 0x00000400 }, + { 0x01470700, 0x00000000 }, { 0x01470c00, 0x00000000 }, - { 0x01470100, 0x00000000 }, { 0x01837000, 0x00000000 }, { 0x01870500, 0x00000400 }, + { 0x01870700, 0x00000020 }, { 0x02050000, 0x00000000 }, { 0x02139000, 0x00000080 }, { 0x0213a000, 0x00000080 }, @@ -107,10 +111,6 @@ static const struct reg_default rt298_reg[] = { { 0x02170700, 0x00000000 }, { 0x02270100, 0x00000000 }, { 0x02370100, 0x00000000 }, - { 0x01870700, 0x00000020 }, - { 0x00830000, 0x000000c3 }, - { 0x00930000, 0x000000c3 }, - { 0x01270700, 0x00000000 }, }; static bool rt298_volatile_register(struct device *dev, unsigned int reg) diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c index 199507d12841..91290bfe8daa 100644 --- a/sound/soc/codecs/rt5514-spi.c +++ b/sound/soc/codecs/rt5514-spi.c @@ -6,6 +6,7 @@ * Author: Oder Chiou <oder_chiou@realtek.com> */ +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/input.h> #include <linux/spi/spi.h> @@ -79,17 +80,17 @@ static void rt5514_spi_copy_work(struct work_struct *work) unsigned int cur_wp, remain_data; u8 buf[8]; - mutex_lock(&rt5514_dsp->dma_lock); + guard(mutex)(&rt5514_dsp->dma_lock); if (!rt5514_dsp->substream) { dev_err(rt5514_dsp->dev, "No pcm substream\n"); - goto done; + return; } runtime = rt5514_dsp->substream->runtime; period_bytes = snd_pcm_lib_period_bytes(rt5514_dsp->substream); if (!period_bytes) { schedule_delayed_work(&rt5514_dsp->copy_work, 5); - goto done; + return; } if (rt5514_dsp->buf_size % period_bytes) @@ -111,7 +112,7 @@ static void rt5514_spi_copy_work(struct work_struct *work) if (remain_data < period_bytes) { schedule_delayed_work(&rt5514_dsp->copy_work, 5); - goto done; + return; } } @@ -146,9 +147,6 @@ static void rt5514_spi_copy_work(struct work_struct *work) snd_pcm_period_elapsed(rt5514_dsp->substream); schedule_delayed_work(&rt5514_dsp->copy_work, 5); - -done: - mutex_unlock(&rt5514_dsp->dma_lock); } static void rt5514_schedule_copy(struct rt5514_dsp *rt5514_dsp) @@ -216,7 +214,7 @@ static int rt5514_spi_hw_params(struct snd_soc_component *component, snd_soc_component_get_drvdata(component); u8 buf[8]; - mutex_lock(&rt5514_dsp->dma_lock); + guard(mutex)(&rt5514_dsp->dma_lock); rt5514_dsp->substream = substream; rt5514_dsp->dma_offset = 0; @@ -225,8 +223,6 @@ static int rt5514_spi_hw_params(struct snd_soc_component *component, if (buf[0] & RT5514_IRQ_STATUS_BIT) rt5514_schedule_copy(rt5514_dsp); - mutex_unlock(&rt5514_dsp->dma_lock); - return 0; } @@ -236,9 +232,8 @@ static int rt5514_spi_hw_free(struct snd_soc_component *component, struct rt5514_dsp *rt5514_dsp = snd_soc_component_get_drvdata(component); - mutex_lock(&rt5514_dsp->dma_lock); - rt5514_dsp->substream = NULL; - mutex_unlock(&rt5514_dsp->dma_lock); + scoped_guard(mutex, &rt5514_dsp->dma_lock) + rt5514_dsp->substream = NULL; cancel_delayed_work_sync(&rt5514_dsp->copy_work); diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index 00a4a208d2fa..58aecd4c83a6 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -1073,12 +1073,18 @@ static int rt5514_set_bias_level(struct snd_soc_component *component, * settings to make sure recording properly. */ if (rt5514->dsp_enabled) { - rt5514->dsp_enabled = 0; - regmap_multi_reg_write(rt5514->i2c_regmap, - rt5514_i2c_patch, - ARRAY_SIZE(rt5514_i2c_patch)); + ret = regmap_multi_reg_write(rt5514->i2c_regmap, + rt5514_i2c_patch, + ARRAY_SIZE(rt5514_i2c_patch)); + if (ret) + return ret; + regcache_mark_dirty(rt5514->regmap); - regcache_sync(rt5514->regmap); + ret = regcache_sync(rt5514->regmap); + if (ret) + return ret; + + rt5514->dsp_enabled = 0; } } break; diff --git a/sound/soc/codecs/rt5575-spi.c b/sound/soc/codecs/rt5575-spi.c index d5b3a57c8866..750f1f7169e6 100644 --- a/sound/soc/codecs/rt5575-spi.c +++ b/sound/soc/codecs/rt5575-spi.c @@ -93,7 +93,6 @@ static void rt5575_spi_burst_write(struct spi_device *spi, u32 addr, const u8 *t int rt5575_spi_fw_load(struct spi_device *spi) { struct device *dev = &spi->dev; - const struct firmware *firmware; int i, ret; static const char * const fw_path[] = { "realtek/rt5575/rt5575_fw1.bin", @@ -104,6 +103,7 @@ int rt5575_spi_fw_load(struct spi_device *spi) static const u32 fw_addr[] = { 0x5f400000, 0x5f600000, 0x5f7fe000, 0x5f7ff000 }; for (i = 0; i < ARRAY_SIZE(fw_addr); i++) { + const struct firmware *firmware __free(firmware) = NULL; ret = request_firmware(&firmware, fw_path[i], dev); if (ret) { dev_err(dev, "Request firmware failure: %d\n", ret); @@ -111,7 +111,6 @@ int rt5575_spi_fw_load(struct spi_device *spi) } rt5575_spi_burst_write(spi, fw_addr[i], firmware->data, firmware->size); - release_firmware(firmware); } return 0; diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index e7e39671a576..7313ea71c958 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -6,6 +6,7 @@ * Author: Bard Liao <bardliao@realtek.com> */ +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> @@ -3323,93 +3324,90 @@ static void rt5645_jack_detect_work(struct work_struct *work) if (!rt5645->component) return; - mutex_lock(&rt5645->jd_mutex); - - switch (rt5645->pdata.jd_mode) { - case 0: /* Not using rt5645 JD */ - if (rt5645->gpiod_hp_det) { - gpio_state = gpiod_get_value(rt5645->gpiod_hp_det); - if (rt5645->pdata.inv_hp_pol) - gpio_state ^= 1; - dev_dbg(rt5645->component->dev, "gpio_state = %d\n", - gpio_state); - report = rt5645_jack_detect(rt5645->component, gpio_state); + scoped_guard(mutex, &rt5645->jd_mutex) { + switch (rt5645->pdata.jd_mode) { + case 0: /* Not using rt5645 JD */ + if (rt5645->gpiod_hp_det) { + gpio_state = gpiod_get_value(rt5645->gpiod_hp_det); + if (rt5645->pdata.inv_hp_pol) + gpio_state ^= 1; + dev_dbg(rt5645->component->dev, "gpio_state = %d\n", + gpio_state); + report = rt5645_jack_detect(rt5645->component, gpio_state); + } + snd_soc_jack_report(rt5645->hp_jack, + report, SND_JACK_HEADPHONE); + snd_soc_jack_report(rt5645->mic_jack, + report, SND_JACK_MICROPHONE); + return; + case 4: + val = snd_soc_component_read(rt5645->component, RT5645_A_JD_CTRL1) & 0x0020; + break; + default: /* read rt5645 jd1_1 status */ + val = snd_soc_component_read(rt5645->component, RT5645_INT_IRQ_ST) & 0x1000; + break; } - snd_soc_jack_report(rt5645->hp_jack, - report, SND_JACK_HEADPHONE); - snd_soc_jack_report(rt5645->mic_jack, - report, SND_JACK_MICROPHONE); - mutex_unlock(&rt5645->jd_mutex); - return; - case 4: - val = snd_soc_component_read(rt5645->component, RT5645_A_JD_CTRL1) & 0x0020; - break; - default: /* read rt5645 jd1_1 status */ - val = snd_soc_component_read(rt5645->component, RT5645_INT_IRQ_ST) & 0x1000; - break; - } - - if (!val && (rt5645->jack_type == 0)) { /* jack in */ - report = rt5645_jack_detect(rt5645->component, 1); - } else if (!val && rt5645->jack_type == SND_JACK_HEADSET) { - /* for push button and jack out */ - btn_type = 0; - if (snd_soc_component_read(rt5645->component, RT5645_INT_IRQ_ST) & 0x4) { - /* button pressed */ - report = SND_JACK_HEADSET; - btn_type = rt5645_button_detect(rt5645->component); - /* rt5650 can report three kinds of button behavior, - one click, double click and hold. However, - currently we will report button pressed/released - event. So all the three button behaviors are - treated as button pressed. */ - switch (btn_type) { - case 0x8000: - case 0x4000: - case 0x2000: - report |= SND_JACK_BTN_0; - break; - case 0x1000: - case 0x0800: - case 0x0400: - report |= SND_JACK_BTN_1; - break; - case 0x0200: - case 0x0100: - case 0x0080: - report |= SND_JACK_BTN_2; - break; - case 0x0040: - case 0x0020: - case 0x0010: - report |= SND_JACK_BTN_3; - break; - case 0x0000: /* unpressed */ - break; - default: - dev_err(rt5645->component->dev, - "Unexpected button code 0x%04x\n", - btn_type); - break; + if (!val && rt5645->jack_type == 0) { /* jack in */ + report = rt5645_jack_detect(rt5645->component, 1); + } else if (!val && rt5645->jack_type == SND_JACK_HEADSET) { + /* for push button and jack out */ + btn_type = 0; + if (snd_soc_component_read(rt5645->component, RT5645_INT_IRQ_ST) & 0x4) { + /* button pressed */ + report = SND_JACK_HEADSET; + btn_type = rt5645_button_detect(rt5645->component); + /* + * rt5650 can report three kinds of button behavior, + * one click, double click and hold. However, + * currently we will report button pressed/released + * event. So all the three button behaviors are + * treated as button pressed. + */ + switch (btn_type) { + case 0x8000: + case 0x4000: + case 0x2000: + report |= SND_JACK_BTN_0; + break; + case 0x1000: + case 0x0800: + case 0x0400: + report |= SND_JACK_BTN_1; + break; + case 0x0200: + case 0x0100: + case 0x0080: + report |= SND_JACK_BTN_2; + break; + case 0x0040: + case 0x0020: + case 0x0010: + report |= SND_JACK_BTN_3; + break; + case 0x0000: /* unpressed */ + break; + default: + dev_err(rt5645->component->dev, + "Unexpected button code 0x%04x\n", + btn_type); + break; + } } + if (btn_type == 0)/* button release */ + report = rt5645->jack_type; + else + mod_timer(&rt5645->btn_check_timer, + msecs_to_jiffies(100)); + } else { + /* jack out */ + report = 0; + snd_soc_component_update_bits(rt5645->component, + RT5645_INT_IRQ_ST, 0x1, 0x0); + rt5645_jack_detect(rt5645->component, 0); } - if (btn_type == 0)/* button release */ - report = rt5645->jack_type; - else { - mod_timer(&rt5645->btn_check_timer, - msecs_to_jiffies(100)); - } - } else { - /* jack out */ - report = 0; - snd_soc_component_update_bits(rt5645->component, - RT5645_INT_IRQ_ST, 0x1, 0x0); - rt5645_jack_detect(rt5645->component, 0); } - mutex_unlock(&rt5645->jd_mutex); - snd_soc_jack_report(rt5645->hp_jack, report, SND_JACK_HEADPHONE); snd_soc_jack_report(rt5645->mic_jack, report, SND_JACK_MICROPHONE); if (rt5645->en_button_func) @@ -3522,9 +3520,15 @@ static int rt5645_suspend(struct snd_soc_component *component) static int rt5645_resume(struct snd_soc_component *component) { struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component); + int ret; regcache_cache_only(rt5645->regmap, false); - regcache_sync(rt5645->regmap); + ret = regcache_sync(rt5645->regmap); + if (ret) { + regcache_cache_only(rt5645->regmap, true); + regcache_mark_dirty(rt5645->regmap); + return ret; + } return 0; } @@ -4335,9 +4339,15 @@ static int rt5645_sys_suspend(struct device *dev) static int rt5645_sys_resume(struct device *dev) { struct rt5645_priv *rt5645 = dev_get_drvdata(dev); + int ret; regcache_cache_only(rt5645->regmap, false); - regcache_sync(rt5645->regmap); + ret = regcache_sync(rt5645->regmap); + if (ret) { + regcache_cache_only(rt5645->regmap, true); + regcache_mark_dirty(rt5645->regmap); + return ret; + } if (rt5645->hp_jack) { rt5645->jack_type = 0; diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 48f57cd0920d..1d987472ba42 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -6,6 +6,7 @@ * Author: Bard Liao <bardliao@realtek.com> */ +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> @@ -1208,7 +1209,7 @@ static void rt5665_jack_detect_handler(struct work_struct *work) usleep_range(10000, 15000); } - mutex_lock(&rt5665->calibrate_mutex); + guard(mutex)(&rt5665->calibrate_mutex); val = snd_soc_component_read(rt5665->component, RT5665_AJD1_CTRL) & 0x0010; if (!val) { @@ -1274,8 +1275,6 @@ static void rt5665_jack_detect_handler(struct work_struct *work) schedule_delayed_work(&rt5665->jd_check_work, 0); else cancel_delayed_work_sync(&rt5665->jd_check_work); - - mutex_unlock(&rt5665->calibrate_mutex); } static const char * const rt5665_clk_sync[] = { @@ -4564,7 +4563,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665) { int value, count; - mutex_lock(&rt5665->calibrate_mutex); + guard(mutex)(&rt5665->calibrate_mutex); regcache_cache_bypass(rt5665->regmap, true); @@ -4601,7 +4600,8 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665) pr_err("HP Calibration Failure\n"); regmap_write(rt5665->regmap, RT5665_RESET, 0); regcache_cache_bypass(rt5665->regmap, false); - goto out_unlock; + rt5665->calibration_done = true; + return; } count++; @@ -4620,7 +4620,8 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665) pr_err("MONO Calibration Failure\n"); regmap_write(rt5665->regmap, RT5665_RESET, 0); regcache_cache_bypass(rt5665->regmap, false); - goto out_unlock; + rt5665->calibration_done = true; + return; } count++; @@ -4635,9 +4636,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665) regmap_write(rt5665->regmap, RT5665_BIAS_CUR_CTRL_8, 0xa602); regmap_write(rt5665->regmap, RT5665_ASRC_8, 0x0120); -out_unlock: rt5665->calibration_done = true; - mutex_unlock(&rt5665->calibrate_mutex); } static void rt5665_calibrate_handler(struct work_struct *work) diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c index fed6de40b8c8..4154bad27610 100644 --- a/sound/soc/codecs/rt5668.c +++ b/sound/soc/codecs/rt5668.c @@ -6,6 +6,7 @@ * Author: Bard Liao <bardliao@realtek.com> */ +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> @@ -986,7 +987,7 @@ static void rt5668_jack_detect_handler(struct work_struct *work) return; } - mutex_lock(&rt5668->calibrate_mutex); + guard(mutex)(&rt5668->calibrate_mutex); val = snd_soc_component_read(rt5668->component, RT5668_AJD1_CTRL) & RT5668_JDH_RS_MASK; @@ -1053,8 +1054,6 @@ static void rt5668_jack_detect_handler(struct work_struct *work) schedule_delayed_work(&rt5668->jd_check_work, 0); else cancel_delayed_work_sync(&rt5668->jd_check_work); - - mutex_unlock(&rt5668->calibrate_mutex); } static const struct snd_kcontrol_new rt5668_snd_controls[] = { @@ -2356,7 +2355,7 @@ static void rt5668_calibrate(struct rt5668_priv *rt5668) { int value, count; - mutex_lock(&rt5668->calibrate_mutex); + guard(mutex)(&rt5668->calibrate_mutex); rt5668_reset(rt5668->regmap); regmap_write(rt5668->regmap, RT5668_PWR_ANLG_1, 0xa2bf); @@ -2400,9 +2399,6 @@ static void rt5668_calibrate(struct rt5668_priv *rt5668) /* restore settings */ regmap_write(rt5668->regmap, RT5668_STO1_ADC_MIXER, 0xc0c4); regmap_write(rt5668->regmap, RT5668_PWR_DIG_1, 0x0000); - - mutex_unlock(&rt5668->calibrate_mutex); - } static int rt5668_i2c_probe(struct i2c_client *i2c) diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index 1bcafd5f4468..ebc527115ea5 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -6,6 +6,7 @@ * Author: Oder Chiou <oder_chiou@realtek.com> */ +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/input.h> #include <linux/spi/spi.h> @@ -133,9 +134,8 @@ static int rt5677_spi_hw_params( struct rt5677_dsp *rt5677_dsp = snd_soc_component_get_drvdata(component); - mutex_lock(&rt5677_dsp->dma_lock); + guard(mutex)(&rt5677_dsp->dma_lock); rt5677_dsp->substream = substream; - mutex_unlock(&rt5677_dsp->dma_lock); return 0; } @@ -147,9 +147,8 @@ static int rt5677_spi_hw_free( struct rt5677_dsp *rt5677_dsp = snd_soc_component_get_drvdata(component); - mutex_lock(&rt5677_dsp->dma_lock); + guard(mutex)(&rt5677_dsp->dma_lock); rt5677_dsp->substream = NULL; - mutex_unlock(&rt5677_dsp->dma_lock); return 0; } @@ -311,17 +310,17 @@ static void rt5677_spi_copy_work(struct work_struct *work) int ret = 0; /* Ensure runtime->dma_area buffer does not go away while copying. */ - mutex_lock(&rt5677_dsp->dma_lock); + guard(mutex)(&rt5677_dsp->dma_lock); if (!rt5677_dsp->substream) { dev_err(rt5677_dsp->dev, "No pcm substream\n"); - goto done; + return; } runtime = rt5677_dsp->substream->runtime; if (rt5677_spi_mic_write_offset(&mic_write_offset)) { dev_err(rt5677_dsp->dev, "No mic_write_offset\n"); - goto done; + return; } /* If this is the first time that we've asked for streaming data after @@ -355,7 +354,7 @@ static void rt5677_spi_copy_work(struct work_struct *work) ret = rt5677_spi_copy(rt5677_dsp, copy_bytes); if (ret) { dev_err(rt5677_dsp->dev, "Copy failed %d\n", ret); - goto done; + return; } rt5677_dsp->avail_bytes += copy_bytes; if (rt5677_dsp->avail_bytes >= period_bytes) { @@ -367,8 +366,6 @@ static void rt5677_spi_copy_work(struct work_struct *work) delay = bytes_to_frames(runtime, period_bytes) / runtime->rate; schedule_delayed_work(&rt5677_dsp->copy_work, secs_to_jiffies(delay)); -done: - mutex_unlock(&rt5677_dsp->dma_lock); } static int rt5677_spi_pcm_new(struct snd_soc_component *component, @@ -507,10 +504,8 @@ int rt5677_spi_read(u32 addr, void *rxbuf, size_t len) header[3] = ((addr + offset) & 0x0000ff00) >> 8; header[4] = ((addr + offset) & 0x000000ff) >> 0; - mutex_lock(&spi_mutex); - status |= spi_sync(g_spi, &m); - mutex_unlock(&spi_mutex); - + scoped_guard(mutex, &spi_mutex) + status |= spi_sync(g_spi, &m); /* Copy data back to caller buffer */ rt5677_spi_reverse(cb + offset, len - offset, body, t[1].len); @@ -564,9 +559,8 @@ int rt5677_spi_write(u32 addr, const void *txbuf, size_t len) offset += t.len; t.len += RT5677_SPI_HEADER + 1; - mutex_lock(&spi_mutex); - status |= spi_sync(g_spi, &m); - mutex_unlock(&spi_mutex); + scoped_guard(mutex, &spi_mutex) + status |= spi_sync(g_spi, &m); } return status; } @@ -591,10 +585,10 @@ void rt5677_spi_hotword_detected(void) return; } - mutex_lock(&rt5677_dsp->dma_lock); - dev_info(rt5677_dsp->dev, "Hotword detected\n"); - rt5677_dsp->new_hotword = true; - mutex_unlock(&rt5677_dsp->dma_lock); + scoped_guard(mutex, &rt5677_dsp->dma_lock) { + dev_info(rt5677_dsp->dev, "Hotword detected\n"); + rt5677_dsp->new_hotword = true; + } schedule_delayed_work(&rt5677_dsp->copy_work, 0); } diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index ac084ca008f3..4757017cc83d 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -6,6 +6,8 @@ * Author: Oder Chiou <oder_chiou@realtek.com> */ +#include <linux/cleanup.h> +#include <linux/bits.h> #include <linux/delay.h> #include <linux/firmware.h> #include <linux/fs.h> @@ -563,46 +565,43 @@ static int rt5677_dsp_mode_i2c_write_addr(struct rt5677_priv *rt5677, struct snd_soc_component *component = rt5677->component; int ret; - mutex_lock(&rt5677->dsp_cmd_lock); + guard(mutex)(&rt5677->dsp_cmd_lock); ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB, addr >> 16); if (ret < 0) { dev_err(component->dev, "Failed to set addr msb value: %d\n", ret); - goto err; + return ret; } ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB, addr & 0xffff); if (ret < 0) { dev_err(component->dev, "Failed to set addr lsb value: %d\n", ret); - goto err; + return ret; } ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB, value >> 16); if (ret < 0) { dev_err(component->dev, "Failed to set data msb value: %d\n", ret); - goto err; + return ret; } ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB, value & 0xffff); if (ret < 0) { dev_err(component->dev, "Failed to set data lsb value: %d\n", ret); - goto err; + return ret; } ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE, opcode); if (ret < 0) { dev_err(component->dev, "Failed to set op code value: %d\n", ret); - goto err; + return ret; } -err: - mutex_unlock(&rt5677->dsp_cmd_lock); - return ret; } @@ -622,36 +621,33 @@ static int rt5677_dsp_mode_i2c_read_addr( int ret; unsigned int msb, lsb; - mutex_lock(&rt5677->dsp_cmd_lock); + guard(mutex)(&rt5677->dsp_cmd_lock); ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB, addr >> 16); if (ret < 0) { dev_err(component->dev, "Failed to set addr msb value: %d\n", ret); - goto err; + return ret; } ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB, addr & 0xffff); if (ret < 0) { dev_err(component->dev, "Failed to set addr lsb value: %d\n", ret); - goto err; + return ret; } ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE, 0x0002); if (ret < 0) { dev_err(component->dev, "Failed to set op code value: %d\n", ret); - goto err; + return ret; } regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB, &msb); regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB, &lsb); *value = (msb << 16) | lsb; -err: - mutex_unlock(&rt5677->dsp_cmd_lock); - return ret; } @@ -853,11 +849,11 @@ static int rt5677_parse_and_load_dsp(struct rt5677_priv *rt5677, const u8 *buf, static int rt5677_load_dsp_from_file(struct rt5677_priv *rt5677) { - const struct firmware *fwp; struct device *dev = rt5677->component->dev; - int ret = 0; + int ret; /* Load dsp firmware from rt5677_elf_vad file */ + const struct firmware *fwp __free(firmware) = NULL; ret = request_firmware(&fwp, "rt5677_elf_vad", dev); if (ret) { dev_err(dev, "Request rt5677_elf_vad failed %d\n", ret); @@ -865,9 +861,7 @@ static int rt5677_load_dsp_from_file(struct rt5677_priv *rt5677) } dev_info(dev, "Requested rt5677_elf_vad (%zu)\n", fwp->size); - ret = rt5677_parse_and_load_dsp(rt5677, fwp->data, fwp->size); - release_firmware(fwp); - return ret; + return rt5677_parse_and_load_dsp(rt5677, fwp->data, fwp->size); } static int rt5677_set_dsp_vad(struct snd_soc_component *component, bool on) @@ -940,21 +934,20 @@ static void rt5677_dsp_work(struct work_struct *work) activity = false; /* Don't turn off the DSP while handling irqs */ - mutex_lock(&rt5677->irq_lock); - /* Set DSP CPU to Stop */ - regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, - RT5677_PWR_DSP_CPU, RT5677_PWR_DSP_CPU); + scoped_guard(mutex, &rt5677->irq_lock) { + /* Set DSP CPU to Stop */ + regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, + RT5677_PWR_DSP_CPU, RT5677_PWR_DSP_CPU); - rt5677_set_dsp_mode(rt5677, false); + rt5677_set_dsp_mode(rt5677, false); - /* Disable and clear VAD interrupt */ - regmap_write(rt5677->regmap, RT5677_VAD_CTRL1, 0x2184); - - /* Set GPIO1 pin back to be IRQ output for jack detect */ - regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, - RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_IRQ); + /* Disable and clear VAD interrupt */ + regmap_write(rt5677->regmap, RT5677_VAD_CTRL1, 0x2184); - mutex_unlock(&rt5677->irq_lock); + /* Set GPIO1 pin back to be IRQ output for jack detect */ + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, + RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_IRQ); + } } } @@ -4767,6 +4760,21 @@ static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset) return rt5677_update_gpio_bits(rt5677, offset, m, v); } +static int rt5677_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) +{ + struct rt5677_priv *rt5677 = gpiochip_get_data(chip); + unsigned int shift = RT5677_GPIOx_DIR_SFT + (offset % 5) * 3; + unsigned int bank = offset / 5; + unsigned int reg = bank ? RT5677_GPIO_CTRL3 : RT5677_GPIO_CTRL2; + int ret; + + ret = regmap_test_bits(rt5677->regmap, reg, BIT(shift)); + if (ret < 0) + return ret; + + return ret ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN; +} + /* * Configures the GPIO as * 0 - floating @@ -4834,6 +4842,7 @@ static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset) static const struct gpio_chip rt5677_template_chip = { .label = RT5677_DRV_NAME, .owner = THIS_MODULE, + .get_direction = rt5677_gpio_get_direction, .direction_output = rt5677_gpio_direction_out, .set = rt5677_gpio_set, .direction_input = rt5677_gpio_direction_in, @@ -4980,11 +4989,11 @@ static int rt5677_read(void *context, unsigned int reg, unsigned int *val) if (rt5677->is_dsp_mode) { if (reg > 0xff) { - mutex_lock(&rt5677->dsp_pri_lock); - rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX, - reg & 0xff); - rt5677_dsp_mode_i2c_read(rt5677, RT5677_PRIV_DATA, val); - mutex_unlock(&rt5677->dsp_pri_lock); + scoped_guard(mutex, &rt5677->dsp_pri_lock) { + rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX, + reg & 0xff); + rt5677_dsp_mode_i2c_read(rt5677, RT5677_PRIV_DATA, val); + } } else { rt5677_dsp_mode_i2c_read(rt5677, reg, val); } @@ -5002,12 +5011,12 @@ static int rt5677_write(void *context, unsigned int reg, unsigned int val) if (rt5677->is_dsp_mode) { if (reg > 0xff) { - mutex_lock(&rt5677->dsp_pri_lock); - rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX, - reg & 0xff); - rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_DATA, - val); - mutex_unlock(&rt5677->dsp_pri_lock); + scoped_guard(mutex, &rt5677->dsp_pri_lock) { + rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX, + reg & 0xff); + rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_DATA, + val); + } } else { rt5677_dsp_mode_i2c_write(rt5677, reg, val); } @@ -5399,7 +5408,7 @@ static void rt5677_resume_irq_check(struct work_struct *work) * Without this explicit check, unplug the headset right after suspend * starts, then after resume the headset is still shown as plugged in. */ - mutex_lock(&rt5677->irq_lock); + guard(mutex)(&rt5677->irq_lock); for (i = 0; i < RT5677_IRQ_NUM; i++) { if (rt5677->irq_en & rt5677_irq_descs[i].enable_mask) { virq = irq_find_mapping(rt5677->domain, i); @@ -5407,7 +5416,6 @@ static void rt5677_resume_irq_check(struct work_struct *work) handle_nested_irq(virq); } } - mutex_unlock(&rt5677->irq_lock); } static void rt5677_irq_bus_lock(struct irq_data *data) diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index dec8c2147d68..23c7d2a9dbee 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -6,6 +6,7 @@ // Author: Oder Chiou <oder_chiou@realtek.com> // +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> @@ -410,7 +411,9 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave) if (rt5682->first_hw_init) { regcache_cache_bypass(rt5682->regmap, false); regcache_mark_dirty(rt5682->regmap); - regcache_sync(rt5682->regmap); + ret = regcache_sync(rt5682->regmap); + if (ret) + goto err_sync; /* volatile registers */ regmap_update_bits(rt5682->regmap, RT5682_CBJ_CTRL_2, @@ -472,8 +475,16 @@ reinit: /* Mark Slave initialization complete */ rt5682->hw_init = true; rt5682->first_hw_init = true; + goto out; + +err_sync: + regcache_cache_bypass(rt5682->regmap, false); + regcache_cache_only(rt5682->sdw_regmap, true); + regcache_cache_only(rt5682->regmap, true); + regcache_mark_dirty(rt5682->regmap); err_nodev: +out: pm_runtime_put_autosuspend(&slave->dev); dev_dbg(&slave->dev, "%s hw_init complete: %d\n", __func__, ret); @@ -660,12 +671,11 @@ static int rt5682_interrupt_callback(struct sdw_slave *slave, dev_dbg(&slave->dev, "%s control_port_stat=%x", __func__, status->control_port); - mutex_lock(&rt5682->disable_irq_lock); + guard(mutex)(&rt5682->disable_irq_lock); if (status->control_port & 0x4 && !rt5682->disable_irq) { mod_delayed_work(system_power_efficient_wq, &rt5682->jack_detect_work, msecs_to_jiffies(rt5682->irq_work_delay_time)); } - mutex_unlock(&rt5682->disable_irq_lock); return 0; } @@ -736,11 +746,11 @@ static int rt5682_dev_system_suspend(struct device *dev) * deferred work completes and before the parent disables * interrupts on the link */ - mutex_lock(&rt5682->disable_irq_lock); - rt5682->disable_irq = true; - ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, - SDW_SCP_INT1_IMPL_DEF, 0); - mutex_unlock(&rt5682->disable_irq_lock); + scoped_guard(mutex, &rt5682->disable_irq_lock) { + rt5682->disable_irq = true; + ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, + SDW_SCP_INT1_IMPL_DEF, 0); + } if (ret < 0) { /* log but don't prevent suspend from happening */ @@ -760,12 +770,12 @@ static int rt5682_dev_resume(struct device *dev) return 0; if (!slave->unattach_request) { - mutex_lock(&rt5682->disable_irq_lock); - if (rt5682->disable_irq == true) { - sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF); - rt5682->disable_irq = false; + scoped_guard(mutex, &rt5682->disable_irq_lock) { + if (rt5682->disable_irq) { + sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF); + rt5682->disable_irq = false; + } } - mutex_unlock(&rt5682->disable_irq_lock); } ret = sdw_slave_wait_for_init(slave, RT5682_PROBE_TIMEOUT); @@ -776,7 +786,13 @@ static int rt5682_dev_resume(struct device *dev) regcache_cache_only(rt5682->sdw_regmap, false); regcache_cache_only(rt5682->regmap, false); - regcache_sync(rt5682->regmap); + ret = regcache_sync(rt5682->regmap); + if (ret) { + regcache_cache_only(rt5682->sdw_regmap, true); + regcache_cache_only(rt5682->regmap, true); + regcache_mark_dirty(rt5682->regmap); + return ret; + } return 0; } diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 4b82e07d3b2c..6f7e68c20d13 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -6,6 +6,7 @@ // Author: Bard Liao <bardliao@realtek.com> // +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> @@ -3125,7 +3126,7 @@ void rt5682_calibrate(struct rt5682_priv *rt5682) { int value, count; - mutex_lock(&rt5682->calibrate_mutex); + guard(mutex)(&rt5682->calibrate_mutex); rt5682_reset(rt5682); regmap_write(rt5682->regmap, RT5682_I2C_CTRL, 0x000f); @@ -3175,8 +3176,6 @@ void rt5682_calibrate(struct rt5682_priv *rt5682) regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x2005); regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0xc0c4); regmap_write(rt5682->regmap, RT5682_CAL_REC, 0x0c0c); - - mutex_unlock(&rt5682->calibrate_mutex); } EXPORT_SYMBOL_GPL(rt5682_calibrate); diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index 3624067950c0..34997cfb465b 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -6,6 +6,7 @@ // Author: Derek Fang <derek.fang@realtek.com> // +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> @@ -648,7 +649,7 @@ static void rt5682s_sar_power_mode(struct snd_soc_component *component, int mode { struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); - mutex_lock(&rt5682s->sar_mutex); + guard(mutex)(&rt5682s->sar_mutex); switch (mode) { case SAR_PWR_SAVING: @@ -695,8 +696,6 @@ static void rt5682s_sar_power_mode(struct snd_soc_component *component, int mode dev_err(component->dev, "Invalid SAR Power mode: %d\n", mode); break; } - - mutex_unlock(&rt5682s->sar_mutex); } static void rt5682s_enable_push_button_irq(struct snd_soc_component *component) @@ -2534,7 +2533,7 @@ static int rt5682s_wclk_prepare(struct clk_hw *hw) if (!rt5682s_clk_check(rt5682s)) return -EINVAL; - mutex_lock(&rt5682s->wclk_mutex); + guard(mutex)(&rt5682s->wclk_mutex); snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, RT5682S_PWR_VREF2 | RT5682S_PWR_FV2 | RT5682S_PWR_MB, @@ -2556,8 +2555,6 @@ static int rt5682s_wclk_prepare(struct clk_hw *hw) rt5682s->wclk_enabled = 1; - mutex_unlock(&rt5682s->wclk_mutex); - return 0; } @@ -2570,7 +2567,7 @@ static void rt5682s_wclk_unprepare(struct clk_hw *hw) if (!rt5682s_clk_check(rt5682s)) return; - mutex_lock(&rt5682s->wclk_mutex); + guard(mutex)(&rt5682s->wclk_mutex); if (!rt5682s->jack_type) snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, @@ -2585,8 +2582,6 @@ static void rt5682s_wclk_unprepare(struct clk_hw *hw) rt5682s_set_pllb_power(rt5682s, 0); rt5682s->wclk_enabled = 0; - - mutex_unlock(&rt5682s->wclk_mutex); } static unsigned long rt5682s_wclk_recalc_rate(struct clk_hw *hw, @@ -2997,7 +2992,7 @@ static void rt5682s_calibrate(struct rt5682s_priv *rt5682s) { unsigned int count, value; - mutex_lock(&rt5682s->calibrate_mutex); + guard(mutex)(&rt5682s->calibrate_mutex); regmap_write(rt5682s->regmap, RT5682S_PWR_ANLG_1, 0xaa80); usleep_range(15000, 20000); @@ -3034,8 +3029,6 @@ static void rt5682s_calibrate(struct rt5682s_priv *rt5682s) regmap_write(rt5682s->regmap, RT5682S_PWR_DIG_1, 0x00c0); regmap_write(rt5682s->regmap, RT5682S_PWR_ANLG_1, 0x0800); regmap_write(rt5682s->regmap, RT5682S_GLB_CLK, 0x0000); - - mutex_unlock(&rt5682s->calibrate_mutex); } static const struct regmap_config rt5682s_regmap = { diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index a451d5d1f8ab..3ba0cc37acd9 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -6,6 +6,7 @@ // // +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/soundwire/sdw.h> @@ -415,12 +416,11 @@ static int rt700_interrupt_callback(struct sdw_slave *slave, dev_dbg(&slave->dev, "%s control_port_stat=%x", __func__, status->control_port); - mutex_lock(&rt700->disable_irq_lock); + guard(mutex)(&rt700->disable_irq_lock); if (status->control_port & 0x4 && !rt700->disable_irq) { mod_delayed_work(system_power_efficient_wq, &rt700->jack_detect_work, msecs_to_jiffies(250)); } - mutex_unlock(&rt700->disable_irq_lock); return 0; } @@ -458,10 +458,8 @@ static void rt700_sdw_remove(struct sdw_slave *slave) { struct rt700_priv *rt700 = dev_get_drvdata(&slave->dev); - if (rt700->hw_init) { - cancel_delayed_work_sync(&rt700->jack_detect_work); - cancel_delayed_work_sync(&rt700->jack_btn_check_work); - } + cancel_delayed_work_sync(&rt700->jack_detect_work); + cancel_delayed_work_sync(&rt700->jack_btn_check_work); pm_runtime_disable(&slave->dev); } @@ -501,11 +499,11 @@ static int rt700_dev_system_suspend(struct device *dev) * deferred work completes and before the parent disables * interrupts on the link */ - mutex_lock(&rt700->disable_irq_lock); - rt700->disable_irq = true; - ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, - SDW_SCP_INT1_IMPL_DEF, 0); - mutex_unlock(&rt700->disable_irq_lock); + scoped_guard(mutex, &rt700->disable_irq_lock) { + rt700->disable_irq = true; + ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, + SDW_SCP_INT1_IMPL_DEF, 0); + } if (ret < 0) { /* log but don't prevent suspend from happening */ diff --git a/sound/soc/codecs/rt700-sdw.h b/sound/soc/codecs/rt700-sdw.h index 4ad0dcfd16fd..002f94493b01 100644 --- a/sound/soc/codecs/rt700-sdw.h +++ b/sound/soc/codecs/rt700-sdw.h @@ -313,17 +313,16 @@ static const struct reg_default rt700_reg_defaults[] = { { 0x3122, 0x0000 }, { 0x3123, 0x0000 }, { 0x7303, 0x0057 }, - { 0x7303, 0x0057 }, - { 0x8383, 0x0057 }, { 0x7308, 0x0097 }, - { 0x8388, 0x0097 }, { 0x7309, 0x0097 }, - { 0x8389, 0x0097 }, { 0x7312, 0x0000 }, - { 0x8392, 0x0000 }, { 0x7313, 0x0000 }, - { 0x8393, 0x0000 }, { 0x7319, 0x0000 }, + { 0x8383, 0x0057 }, + { 0x8388, 0x0097 }, + { 0x8389, 0x0097 }, + { 0x8392, 0x0000 }, + { 0x8393, 0x0000 }, { 0x8399, 0x0000 }, { 0x75201a, 0x8003 }, { 0x752045, 0x5289 }, diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c index e028a1c3a9ac..e292b28b029e 100644 --- a/sound/soc/codecs/rt711-sdca-sdw.c +++ b/sound/soc/codecs/rt711-sdca-sdw.c @@ -6,6 +6,7 @@ // // +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/soundwire/sdw_registers.h> @@ -415,13 +416,13 @@ static int rt711_sdca_dev_system_suspend(struct device *dev) * deferred work completes and before the parent disables * interrupts on the link */ - mutex_lock(&rt711_sdca->disable_irq_lock); - rt711_sdca->disable_irq = true; - ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, - SDW_SCP_SDCA_INTMASK_SDCA_0, 0); - ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, - SDW_SCP_SDCA_INTMASK_SDCA_8, 0); - mutex_unlock(&rt711_sdca->disable_irq_lock); + scoped_guard(mutex, &rt711_sdca->disable_irq_lock) { + rt711_sdca->disable_irq = true; + ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0, 0); + ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8, 0); + } if (ret1 < 0 || ret2 < 0) { /* log but don't prevent suspend from happening */ @@ -443,13 +444,15 @@ static int rt711_sdca_dev_resume(struct device *dev) return 0; if (!slave->unattach_request) { - mutex_lock(&rt711->disable_irq_lock); - if (rt711->disable_irq == true) { - sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); - sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); - rt711->disable_irq = false; + scoped_guard(mutex, &rt711->disable_irq_lock) { + if (rt711->disable_irq) { + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0); + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8); + rt711->disable_irq = false; + } } - mutex_unlock(&rt711->disable_irq_lock); } ret = sdw_slave_wait_for_init(slave, RT711_PROBE_TIMEOUT); diff --git a/sound/soc/codecs/rt711-sdca-sdw.h b/sound/soc/codecs/rt711-sdca-sdw.h index 0d774e473ab9..9aa22b52d556 100644 --- a/sound/soc/codecs/rt711-sdca-sdw.h +++ b/sound/soc/codecs/rt711-sdca-sdw.h @@ -58,12 +58,12 @@ static const struct reg_default rt711_sdca_reg_defaults[] = { { 0x2f0f, 0x00 }, { 0x2f50, 0x03 }, { 0x2f5a, 0x00 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_CS01, RT711_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PDE28, RT711_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_CS01, RT711_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, }; @@ -86,14 +86,14 @@ static const struct reg_default rt711_sdca_mbq_defaults[] = { { 0x610003f, 0xff12 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_L), 0x00 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x00 }, - { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_L), 0x00 }, - { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x00 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_VOLUME, CH_L), 0x00 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x00 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PLATFORM_FU44, RT711_SDCA_CTL_FU_CH_GAIN, CH_L), 0x00 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PLATFORM_FU44, RT711_SDCA_CTL_FU_CH_GAIN, CH_R), 0x00 }, { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_L), 0x00 }, { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_R), 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_L), 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x00 }, }; #endif /* __RT711_SDW_SDCA_H__ */ diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c index 3a26c782d800..9781f289f8ad 100644 --- a/sound/soc/codecs/rt711-sdca.c +++ b/sound/soc/codecs/rt711-sdca.c @@ -6,6 +6,7 @@ // // +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> @@ -450,7 +451,7 @@ io_error: static void rt711_sdca_jack_init(struct rt711_sdca_priv *rt711) { - mutex_lock(&rt711->calibrate_mutex); + guard(mutex)(&rt711->calibrate_mutex); if (rt711->hs_jack) { /* Enable HID1 event & set button RTC mode */ @@ -515,8 +516,6 @@ static void rt711_sdca_jack_init(struct rt711_sdca_priv *rt711) dev_dbg(&rt711->slave->dev, "in %s disable\n", __func__); } - - mutex_unlock(&rt711->calibrate_mutex); } static int rt711_sdca_set_jack_detect(struct snd_soc_component *component, diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index a0c6a9efa840..4ad2b1da1954 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -6,6 +6,7 @@ // // +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/soundwire/sdw.h> @@ -422,12 +423,11 @@ static int rt711_interrupt_callback(struct sdw_slave *slave, dev_dbg(&slave->dev, "%s control_port_stat=%x", __func__, status->control_port); - mutex_lock(&rt711->disable_irq_lock); + guard(mutex)(&rt711->disable_irq_lock); if (status->control_port & 0x4 && !rt711->disable_irq) { mod_delayed_work(system_power_efficient_wq, &rt711->jack_detect_work, msecs_to_jiffies(250)); } - mutex_unlock(&rt711->disable_irq_lock); return 0; } @@ -509,11 +509,11 @@ static int rt711_dev_system_suspend(struct device *dev) * deferred work completes and before the parent disables * interrupts on the link */ - mutex_lock(&rt711->disable_irq_lock); - rt711->disable_irq = true; - ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, - SDW_SCP_INT1_IMPL_DEF, 0); - mutex_unlock(&rt711->disable_irq_lock); + scoped_guard(mutex, &rt711->disable_irq_lock) { + rt711->disable_irq = true; + ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, + SDW_SCP_INT1_IMPL_DEF, 0); + } if (ret < 0) { /* log but don't prevent suspend from happening */ @@ -535,12 +535,12 @@ static int rt711_dev_resume(struct device *dev) return 0; if (!slave->unattach_request) { - mutex_lock(&rt711->disable_irq_lock); - if (rt711->disable_irq == true) { - sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF); - rt711->disable_irq = false; + scoped_guard(mutex, &rt711->disable_irq_lock) { + if (rt711->disable_irq) { + sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF); + rt711->disable_irq = false; + } } - mutex_unlock(&rt711->disable_irq_lock); } ret = sdw_slave_wait_for_init(slave, RT711_PROBE_TIMEOUT); diff --git a/sound/soc/codecs/rt711-sdw.h b/sound/soc/codecs/rt711-sdw.h index 6acf9858330d..82da0e62d9d7 100644 --- a/sound/soc/codecs/rt711-sdw.h +++ b/sound/soc/codecs/rt711-sdw.h @@ -256,16 +256,16 @@ static const struct reg_default rt711_reg_defaults[] = { { 0x3122, 0x00 }, { 0x3123, 0x00 }, { 0x7303, 0x57 }, - { 0x8383, 0x57 }, { 0x7308, 0x97 }, - { 0x8388, 0x97 }, { 0x7309, 0x97 }, - { 0x8389, 0x97 }, { 0x7312, 0x00 }, - { 0x8392, 0x00 }, { 0x7313, 0x00 }, - { 0x8393, 0x00 }, { 0x7319, 0x00 }, + { 0x8383, 0x57 }, + { 0x8388, 0x97 }, + { 0x8389, 0x97 }, + { 0x8392, 0x00 }, + { 0x8393, 0x00 }, { 0x8399, 0x00 }, { 0x752008, 0xa807 }, { 0x752009, 0x1029 }, diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index 5dbe9b67703e..3e49c3d0f25b 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -6,6 +6,7 @@ // // +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> @@ -89,24 +90,24 @@ static int rt711_calibration(struct rt711_priv *rt711) struct regmap *regmap = rt711->regmap; int ret = 0; - mutex_lock(&rt711->calibrate_mutex); + guard(mutex)(&rt711->calibrate_mutex); regmap_write(rt711->regmap, - RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); + RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); dev = regmap_get_device(regmap); /* Calibration manual mode */ rt711_index_update_bits(regmap, RT711_VENDOR_REG, RT711_FSM_CTL, - 0xf, 0x0); + 0xf, 0x0); /* trigger */ rt711_index_update_bits(regmap, RT711_VENDOR_CALI, - RT711_DAC_DC_CALI_CTL1, RT711_DAC_DC_CALI_TRIGGER, - RT711_DAC_DC_CALI_TRIGGER); + RT711_DAC_DC_CALI_CTL1, RT711_DAC_DC_CALI_TRIGGER, + RT711_DAC_DC_CALI_TRIGGER); /* wait for calibration process */ rt711_index_read(regmap, RT711_VENDOR_CALI, - RT711_DAC_DC_CALI_CTL1, &val); + RT711_DAC_DC_CALI_CTL1, &val); while (val & RT711_DAC_DC_CALI_TRIGGER) { if (loop >= 500) { @@ -119,16 +120,15 @@ static int rt711_calibration(struct rt711_priv *rt711) usleep_range(10000, 11000); rt711_index_read(regmap, RT711_VENDOR_CALI, - RT711_DAC_DC_CALI_CTL1, &val); + RT711_DAC_DC_CALI_CTL1, &val); } /* depop mode */ rt711_index_update_bits(regmap, RT711_VENDOR_REG, - RT711_FSM_CTL, 0xf, RT711_DEPOP_CTL); + RT711_FSM_CTL, 0xf, RT711_DEPOP_CTL); regmap_write(rt711->regmap, - RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); - mutex_unlock(&rt711->calibrate_mutex); + RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); dev_dbg(dev, "%s calibration complete, ret=%d\n", __func__, ret); return ret; @@ -362,24 +362,24 @@ static void rt711_jack_init(struct rt711_priv *rt711) { struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(rt711->component); - mutex_lock(&rt711->calibrate_mutex); + guard(mutex)(&rt711->calibrate_mutex); /* power on */ if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY) regmap_write(rt711->regmap, - RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); + RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); if (rt711->hs_jack) { /* unsolicited response & IRQ control */ regmap_write(rt711->regmap, - RT711_SET_MIC2_UNSOLICITED_ENABLE, 0x82); + RT711_SET_MIC2_UNSOLICITED_ENABLE, 0x82); regmap_write(rt711->regmap, - RT711_SET_HP_UNSOLICITED_ENABLE, 0x81); + RT711_SET_HP_UNSOLICITED_ENABLE, 0x81); regmap_write(rt711->regmap, - RT711_SET_INLINE_UNSOLICITED_ENABLE, 0x83); + RT711_SET_INLINE_UNSOLICITED_ENABLE, 0x83); rt711_index_write(rt711->regmap, RT711_VENDOR_REG, - 0x10, 0x2420); + 0x10, 0x2420); rt711_index_write(rt711->regmap, RT711_VENDOR_REG, - 0x19, 0x2e11); + 0x19, 0x2e11); switch (rt711->jd_src) { case RT711_JD1: @@ -449,8 +449,7 @@ static void rt711_jack_init(struct rt711_priv *rt711) /* power off */ if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY) regmap_write(rt711->regmap, - RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); - mutex_unlock(&rt711->calibrate_mutex); + RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); } static int rt711_set_jack_detect(struct snd_soc_component *component, @@ -511,7 +510,7 @@ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol, unsigned int read_ll, read_rl; int i; - mutex_lock(&rt711->calibrate_mutex); + guard(mutex)(&rt711->calibrate_mutex); /* Can't use update bit function, so read the original value first */ addr_h = mc->reg; @@ -599,7 +598,6 @@ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol, regmap_write(rt711->regmap, RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); - mutex_unlock(&rt711->calibrate_mutex); return 0; } @@ -908,11 +906,11 @@ static int rt711_set_bias_level(struct snd_soc_component *component, break; case SND_SOC_BIAS_STANDBY: - mutex_lock(&rt711->calibrate_mutex); - regmap_write(rt711->regmap, - RT711_SET_AUDIO_POWER_STATE, - AC_PWRST_D3); - mutex_unlock(&rt711->calibrate_mutex); + scoped_guard(mutex, &rt711->calibrate_mutex) { + regmap_write(rt711->regmap, + RT711_SET_AUDIO_POWER_STATE, + AC_PWRST_D3); + } break; default: diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c index 85779547653e..8860d81134e7 100644 --- a/sound/soc/codecs/rt712-sdca-dmic.c +++ b/sound/soc/codecs/rt712-sdca-dmic.c @@ -916,10 +916,23 @@ static int rt712_sdca_dmic_dev_resume(struct device *dev) } regcache_cache_only(rt712->regmap, false); - regcache_sync(rt712->regmap); + ret = regcache_sync(rt712->regmap); + if (ret) + goto err_sync; + regcache_cache_only(rt712->mbq_regmap, false); - regcache_sync(rt712->mbq_regmap); + ret = regcache_sync(rt712->mbq_regmap); + if (ret) + goto err_sync; + return 0; + +err_sync: + regcache_cache_only(rt712->regmap, true); + regcache_cache_only(rt712->mbq_regmap, true); + regcache_mark_dirty(rt712->regmap); + regcache_mark_dirty(rt712->mbq_regmap); + return ret; } static const struct dev_pm_ops rt712_sdca_dmic_pm = { diff --git a/sound/soc/codecs/rt712-sdca-dmic.h b/sound/soc/codecs/rt712-sdca-dmic.h index 110154e74efe..2f08e58ed519 100644 --- a/sound/soc/codecs/rt712-sdca-dmic.h +++ b/sound/soc/codecs/rt712-sdca-dmic.h @@ -36,6 +36,7 @@ struct rt712_sdca_dmic_kctrl_priv { #define CH_03 0x03 #define CH_04 0x04 +/* must stay sorted by register address, regcache_lookup_reg() does a bsearch() */ static const struct reg_default rt712_sdca_dmic_reg_defaults[] = { { 0x201a, 0x00 }, { 0x201b, 0x00 }, @@ -72,15 +73,16 @@ static const struct reg_default rt712_sdca_dmic_reg_defaults[] = { { 0x2f59, 0x07 }, { 0x3201, 0x01 }, { 0x320c, 0x00 }, - { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_IT26, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x00 }, { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_03), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_04), 0x01 }, - { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_IT26, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x00 }, }; +/* must stay sorted by register address, regcache_lookup_reg() does a bsearch() */ static const struct reg_default rt712_sdca_dmic_mbq_defaults[] = { { 0x0590001e, 0x0020 }, { 0x06100000, 0x0010 }, diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c index 70d661ce2ef2..c50e74e20a88 100644 --- a/sound/soc/codecs/rt712-sdca-sdw.c +++ b/sound/soc/codecs/rt712-sdca-sdw.c @@ -6,6 +6,7 @@ // // +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/module.h> @@ -427,13 +428,13 @@ static int rt712_sdca_dev_system_suspend(struct device *dev) * deferred work completes and before the parent disables * interrupts on the link */ - mutex_lock(&rt712_sdca->disable_irq_lock); - rt712_sdca->disable_irq = true; - ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, - SDW_SCP_SDCA_INTMASK_SDCA_0, 0); - ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, - SDW_SCP_SDCA_INTMASK_SDCA_8, 0); - mutex_unlock(&rt712_sdca->disable_irq_lock); + scoped_guard(mutex, &rt712_sdca->disable_irq_lock) { + rt712_sdca->disable_irq = true; + ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0, 0); + ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8, 0); + } if (ret1 < 0 || ret2 < 0) { /* log but don't prevent suspend from happening */ @@ -455,14 +456,15 @@ static int rt712_sdca_dev_resume(struct device *dev) return 0; if (!slave->unattach_request) { - mutex_lock(&rt712->disable_irq_lock); - if (rt712->disable_irq == true) { - - sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); - sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); - rt712->disable_irq = false; + scoped_guard(mutex, &rt712->disable_irq_lock) { + if (rt712->disable_irq) { + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0); + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8); + rt712->disable_irq = false; + } } - mutex_unlock(&rt712->disable_irq_lock); } ret = sdw_slave_wait_for_init(slave, RT712_PROBE_TIMEOUT); @@ -472,9 +474,20 @@ static int rt712_sdca_dev_resume(struct device *dev) } regcache_cache_only(rt712->regmap, false); - regcache_sync(rt712->regmap); + ret = regcache_sync(rt712->regmap); + if (ret) { + regcache_cache_only(rt712->regmap, true); + return ret; + } + regcache_cache_only(rt712->mbq_regmap, false); - regcache_sync(rt712->mbq_regmap); + ret = regcache_sync(rt712->mbq_regmap); + if (ret) { + regcache_cache_only(rt712->mbq_regmap, true); + regcache_cache_only(rt712->regmap, true); + return ret; + } + return 0; } diff --git a/sound/soc/codecs/rt712-sdca-sdw.h b/sound/soc/codecs/rt712-sdca-sdw.h index 99fd2d67f04d..7ad25cc27f62 100644 --- a/sound/soc/codecs/rt712-sdca-sdw.h +++ b/sound/soc/codecs/rt712-sdca-sdw.h @@ -11,21 +11,21 @@ #include <linux/regmap.h> #include <linux/soundwire/sdw_registers.h> +/* must stay sorted by register address, regcache_lookup_reg() does a bsearch() */ static const struct reg_default rt712_sdca_reg_defaults[] = { - - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS01, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS11, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE40, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE12, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, - { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS01, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS11, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE40, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_03), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_04), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, @@ -34,6 +34,7 @@ static const struct reg_default rt712_sdca_reg_defaults[] = { { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x00 }, }; +/* must stay sorted by register address, regcache_lookup_reg() does a bsearch() */ static const struct reg_default rt712_sdca_mbq_defaults[] = { { 0x2000004, 0xaa01 }, { 0x200000e, 0x21e0 }, diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c index d6353af07380..2218f9918ae3 100644 --- a/sound/soc/codecs/rt712-sdca.c +++ b/sound/soc/codecs/rt712-sdca.c @@ -7,6 +7,7 @@ // #include <linux/bitops.h> +#include <linux/cleanup.h> #include <sound/core.h> #include <linux/delay.h> #include <linux/init.h> @@ -403,7 +404,7 @@ io_error: static void rt712_sdca_jack_init(struct rt712_sdca_priv *rt712) { - mutex_lock(&rt712->calibrate_mutex); + guard(mutex)(&rt712->calibrate_mutex); if (rt712->hs_jack) { /* Enable HID1 event & set button RTC mode */ @@ -450,8 +451,6 @@ static void rt712_sdca_jack_init(struct rt712_sdca_priv *rt712) dev_dbg(&rt712->slave->dev, "in %s disable\n", __func__); } - - mutex_unlock(&rt712->calibrate_mutex); } static int rt712_sdca_set_jack_detect(struct snd_soc_component *component, diff --git a/sound/soc/codecs/rt715-sdca-sdw.h b/sound/soc/codecs/rt715-sdca-sdw.h index 0cbc14844f8c..d408f2d7d0f2 100644 --- a/sound/soc/codecs/rt715-sdca-sdw.h +++ b/sound/soc/codecs/rt715-sdca-sdw.h @@ -76,8 +76,6 @@ static const struct reg_default rt715_reg_defaults_sdca[] = { { 0x2f52, 0x01 }, { 0x2f5a, 0x02 }, { 0x2f5b, 0x05 }, - { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CX_CLK_SEL_EN, - RT715_SDCA_CX_CLK_SEL_CTRL, CH_00), 0x1 }, { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 }, { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, @@ -98,14 +96,12 @@ static const struct reg_default rt715_reg_defaults_sdca[] = { RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 }, { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CX_CLK_SEL_EN, + RT715_SDCA_CX_CLK_SEL_CTRL, CH_00), 0x1 }, { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN, RT715_SDCA_SMPU_TRIG_EN_CTRL, CH_00), 0x02 }, { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN, RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00), 0x00 }, - { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, - RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 }, - { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, - RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 }, }; static const struct reg_default rt715_mbq_reg_defaults_sdca[] = { @@ -149,8 +145,6 @@ static const struct reg_default rt715_mbq_reg_defaults_sdca[] = { RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_06), 0x00 }, { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_07), 0x00 }, - { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, - RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_08), 0x00 }, { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_01), 0x00 }, { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, @@ -165,6 +159,8 @@ static const struct reg_default rt715_mbq_reg_defaults_sdca[] = { RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_06), 0x00 }, { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_07), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_08), 0x00 }, { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_08), 0x00 }, }; diff --git a/sound/soc/codecs/rt715-sdw.h b/sound/soc/codecs/rt715-sdw.h index 5d7661e335ae..f19fafb913f0 100644 --- a/sound/soc/codecs/rt715-sdw.h +++ b/sound/soc/codecs/rt715-sdw.h @@ -281,8 +281,8 @@ static const struct reg_default rt715_reg_defaults[] = { { 0x371b, 0x00 }, { 0x371d, 0x00 }, { 0x3729, 0x00 }, - { 0x385e, 0x00 }, { 0x3859, 0x00 }, + { 0x385e, 0x00 }, { 0x4c12, 0x411111f0 }, { 0x4c13, 0x411111f0 }, { 0x4c1d, 0x411111f0 }, @@ -300,36 +300,36 @@ static const struct reg_default rt715_reg_defaults[] = { { 0x4f1d, 0x411111f0 }, { 0x4f29, 0x411111f0 }, { 0x7207, 0x00 }, - { 0x8287, 0x00 }, { 0x7208, 0x00 }, - { 0x8288, 0x00 }, { 0x7209, 0x00 }, - { 0x8289, 0x00 }, { 0x7227, 0x00 }, - { 0x82a7, 0x00 }, { 0x7307, 0x97 }, - { 0x8387, 0x97 }, { 0x7308, 0x97 }, - { 0x8388, 0x97 }, { 0x7309, 0x97 }, - { 0x8389, 0x97 }, { 0x7312, 0x00 }, - { 0x8392, 0x00 }, { 0x7313, 0x00 }, - { 0x8393, 0x00 }, { 0x7318, 0x00 }, - { 0x8398, 0x00 }, { 0x7319, 0x00 }, - { 0x8399, 0x00 }, { 0x731a, 0x00 }, - { 0x839a, 0x00 }, { 0x731b, 0x00 }, - { 0x839b, 0x00 }, { 0x731d, 0x00 }, - { 0x839d, 0x00 }, { 0x7327, 0x97 }, - { 0x83a7, 0x97 }, { 0x7329, 0x00 }, + { 0x8287, 0x00 }, + { 0x8288, 0x00 }, + { 0x8289, 0x00 }, + { 0x82a7, 0x00 }, + { 0x8387, 0x97 }, + { 0x8388, 0x97 }, + { 0x8389, 0x97 }, + { 0x8392, 0x00 }, + { 0x8393, 0x00 }, + { 0x8398, 0x00 }, + { 0x8399, 0x00 }, + { 0x839a, 0x00 }, + { 0x839b, 0x00 }, + { 0x839d, 0x00 }, + { 0x83a7, 0x97 }, { 0x83a9, 0x00 }, { 0x752039, 0xa500 }, }; diff --git a/sound/soc/codecs/rt721-sdca-sdw.c b/sound/soc/codecs/rt721-sdca-sdw.c index 041b381e582b..eae7d662efae 100644 --- a/sound/soc/codecs/rt721-sdca-sdw.c +++ b/sound/soc/codecs/rt721-sdca-sdw.c @@ -6,6 +6,7 @@ // // +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/module.h> @@ -466,13 +467,13 @@ static int rt721_sdca_dev_system_suspend(struct device *dev) * deferred work completes and before the parent disables * interrupts on the link */ - mutex_lock(&rt721_sdca->disable_irq_lock); - rt721_sdca->disable_irq = true; - ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, - SDW_SCP_SDCA_INTMASK_SDCA_0, 0); - ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, - SDW_SCP_SDCA_INTMASK_SDCA_8, 0); - mutex_unlock(&rt721_sdca->disable_irq_lock); + scoped_guard(mutex, &rt721_sdca->disable_irq_lock) { + rt721_sdca->disable_irq = true; + ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0, 0); + ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8, 0); + } if (ret1 < 0 || ret2 < 0) { /* log but don't prevent suspend from happening */ @@ -494,13 +495,15 @@ static int rt721_sdca_dev_resume(struct device *dev) return 0; if (!slave->unattach_request) { - mutex_lock(&rt721->disable_irq_lock); - if (rt721->disable_irq == true) { - sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); - sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); - rt721->disable_irq = false; + scoped_guard(mutex, &rt721->disable_irq_lock) { + if (rt721->disable_irq) { + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0); + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8); + rt721->disable_irq = false; + } } - mutex_unlock(&rt721->disable_irq_lock); } ret = sdw_slave_wait_for_init(slave, RT721_PROBE_TIMEOUT); @@ -510,9 +513,20 @@ static int rt721_sdca_dev_resume(struct device *dev) } regcache_cache_only(rt721->regmap, false); - regcache_sync(rt721->regmap); + ret = regcache_sync(rt721->regmap); + if (ret) { + regcache_cache_only(rt721->regmap, true); + return ret; + } + regcache_cache_only(rt721->mbq_regmap, false); - regcache_sync(rt721->mbq_regmap); + ret = regcache_sync(rt721->mbq_regmap); + if (ret) { + regcache_cache_only(rt721->mbq_regmap, true); + regcache_cache_only(rt721->regmap, true); + return ret; + } + return 0; } diff --git a/sound/soc/codecs/rt721-sdca-sdw.h b/sound/soc/codecs/rt721-sdca-sdw.h index 214b31b82583..13d6227f3392 100644 --- a/sound/soc/codecs/rt721-sdca-sdw.h +++ b/sound/soc/codecs/rt721-sdca-sdw.h @@ -29,14 +29,6 @@ static const struct reg_default rt721_sdca_reg_defaults[] = { { 0x2f5b, 0x07 }, { 0x2f5c, 0x27 }, { 0x2f5d, 0x07 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS01, - RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS11, - RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE12, - RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE40, - RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, @@ -45,6 +37,14 @@ static const struct reg_default rt721_sdca_reg_defaults[] = { RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, RT721_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE12, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS01, + RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS11, + RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE40, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, @@ -53,30 +53,30 @@ static const struct reg_default rt721_sdca_reg_defaults[] = { RT721_SDCA_CTL_FU_MUTE, CH_03), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_MUTE, CH_04), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_PDE2A, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_CS1F, RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_IT26, RT721_SDCA_CTL_VENDOR_DEF, 0), 0x00 }, - { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_PDE2A, - RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, - { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_CS31, - RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, RT721_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23, RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, - { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_OT23, - RT721_SDCA_CTL_VENDOR_DEF, 0), 0x00 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23, RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23, RT721_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_CS31, + RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55, RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55, RT721_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_OT23, + RT721_SDCA_CTL_VENDOR_DEF, 0), 0x00 }, }; static const struct reg_default rt721_sdca_mbq_defaults[] = { diff --git a/sound/soc/codecs/rt721-sdca.c b/sound/soc/codecs/rt721-sdca.c index 35960c225224..159c35d19dba 100644 --- a/sound/soc/codecs/rt721-sdca.c +++ b/sound/soc/codecs/rt721-sdca.c @@ -5,7 +5,7 @@ // Copyright(c) 2024 Realtek Semiconductor Corp. // // - +#include <linux/cleanup.h> #include <linux/bitops.h> #include <sound/core.h> #include <linux/delay.h> @@ -289,7 +289,7 @@ static void rt721_sdca_jack_preset(struct rt721_sdca_priv *rt721) static void rt721_sdca_jack_init(struct rt721_sdca_priv *rt721) { - mutex_lock(&rt721->calibrate_mutex); + guard(mutex)(&rt721->calibrate_mutex); if (rt721->hs_jack) { sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); @@ -309,7 +309,6 @@ static void rt721_sdca_jack_init(struct rt721_sdca_priv *rt721) rt_sdca_index_update_bits(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, RT721_GE_REL_CTRL1, 0x4000, 0x4000); } - mutex_unlock(&rt721->calibrate_mutex); } static int rt721_sdca_set_jack_detect(struct snd_soc_component *component, diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c index 7482a9a8d198..5bc9aed58d14 100644 --- a/sound/soc/codecs/rt722-sdca-sdw.c +++ b/sound/soc/codecs/rt722-sdca-sdw.c @@ -6,6 +6,7 @@ // // +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/module.h> @@ -517,13 +518,13 @@ static int rt722_sdca_dev_system_suspend(struct device *dev) * deferred work completes and before the parent disables * interrupts on the link */ - mutex_lock(&rt722_sdca->disable_irq_lock); - rt722_sdca->disable_irq = true; - ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, - SDW_SCP_SDCA_INTMASK_SDCA_0, 0); - ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, - SDW_SCP_SDCA_INTMASK_SDCA_8, 0); - mutex_unlock(&rt722_sdca->disable_irq_lock); + scoped_guard(mutex, &rt722_sdca->disable_irq_lock) { + rt722_sdca->disable_irq = true; + ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0, 0); + ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8, 0); + } if (ret1 < 0 || ret2 < 0) { /* log but don't prevent suspend from happening */ @@ -545,13 +546,15 @@ static int rt722_sdca_dev_resume(struct device *dev) return 0; if (!slave->unattach_request) { - mutex_lock(&rt722->disable_irq_lock); - if (rt722->disable_irq == true) { - sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); - sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); - rt722->disable_irq = false; + scoped_guard(mutex, &rt722->disable_irq_lock) { + if (rt722->disable_irq) { + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0); + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8); + rt722->disable_irq = false; + } } - mutex_unlock(&rt722->disable_irq_lock); } ret = sdw_slave_wait_for_init(slave, RT722_PROBE_TIMEOUT); @@ -561,7 +564,13 @@ static int rt722_sdca_dev_resume(struct device *dev) } regcache_cache_only(rt722->regmap, false); - regcache_sync(rt722->regmap); + ret = regcache_sync(rt722->regmap); + if (ret) { + regcache_cache_only(rt722->regmap, true); + regcache_mark_dirty(rt722->regmap); + return ret; + } + return 0; } diff --git a/sound/soc/codecs/rt722-sdca.c b/sound/soc/codecs/rt722-sdca.c index 6b509eb65d77..4cbe9e909585 100644 --- a/sound/soc/codecs/rt722-sdca.c +++ b/sound/soc/codecs/rt722-sdca.c @@ -6,6 +6,7 @@ // // +#include <linux/cleanup.h> #include <linux/bitops.h> #include <linux/delay.h> #include <linux/dmi.h> @@ -294,7 +295,7 @@ io_error: static void rt722_sdca_jack_init(struct rt722_sdca_priv *rt722) { - mutex_lock(&rt722->calibrate_mutex); + guard(mutex)(&rt722->calibrate_mutex); if (rt722->hs_jack) { /* set SCP_SDCA_IntMask1[0]=1 */ sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK1, @@ -317,7 +318,6 @@ static void rt722_sdca_jack_init(struct rt722_sdca_priv *rt722) rt722_sdca_index_update_bits(rt722, RT722_VENDOR_HDA_CTL, RT722_GE_RELATED_CTL2, 0x4000, 0x4000); } - mutex_unlock(&rt722->calibrate_mutex); } static int rt722_sdca_set_jack_detect(struct snd_soc_component *component, @@ -352,8 +352,6 @@ static int rt722_cae_load(struct rt722_sdca_priv *rt722) static const char func_tag[] = "FUNC"; static const char xu_tag[] = "XU"; const char *dmi_vendor, *dmi_product, *dmi_sku; - char *cae_filename; - const struct firmware *cae_fw = NULL; unsigned int cae_st_spk, cae_st_hp, cae_st_mic; unsigned int func, value; unsigned int combined_val; @@ -385,7 +383,8 @@ static int rt722_cae_load(struct rt722_sdca_priv *rt722) space = strchr(dmi_sku, ' '); s_len = space ? space - dmi_sku : strlen(dmi_sku); - cae_filename = kasprintf(GFP_KERNEL, + char *cae_filename __free(kfree) = + kasprintf(GFP_KERNEL, "realtek/rt722/rt722_RAE_%.*s_%.*s_%.*s.dat", v_len, dmi_vendor, p_len, dmi_product, @@ -399,8 +398,8 @@ static int rt722_cae_load(struct rt722_sdca_priv *rt722) regmap_write(rt722->regmap, RT722_MIC_CAE_PARAM39, 0x5f); usleep_range(50000, 60000); + const struct firmware *cae_fw __free(firmware) = NULL; request_firmware(&cae_fw, cae_filename, dev); - kfree(cae_filename); if (!cae_fw) { dev_err(dev, "%s: Failed to load CAE firmware\n", __func__); return -ENOENT; @@ -555,7 +554,6 @@ static int rt722_cae_load(struct rt722_sdca_priv *rt722) regcache_cache_bypass(rt722->regmap, false); rt722->cae_update_done = 1; dev_dbg(dev, "%s: CAE FW update done.\n", __func__); - release_firmware(cae_fw); return 0; verify_abort: @@ -565,7 +563,6 @@ verify_abort: out_release: rt722_sdca_index_update_bits(rt722, RT722_VENDOR_REG, RT722_MISC_CTRL1, 0x8000, 0x0000); - release_firmware(cae_fw); dev_err(dev, "%s: CAE FW update aborted (ret=%d).\n", __func__, ret); return ret; } @@ -1906,6 +1903,9 @@ int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave) rt722_sdca_amp_preset(rt722); rt722_sdca_jack_preset(rt722); + if (rt722->hs_jack && (!rt722->first_hw_init)) + rt722_sdca_jack_init(rt722); + if (rt722->first_hw_init) { regcache_cache_bypass(rt722->regmap, false); regcache_mark_dirty(rt722->regmap); diff --git a/sound/soc/codecs/rt766-sdca-sdw.c b/sound/soc/codecs/rt766-sdca-sdw.c new file mode 100644 index 000000000000..5d60c3bcc6cd --- /dev/null +++ b/sound/soc/codecs/rt766-sdca-sdw.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt766-sdca-sdw.c -- rt766 SDCA ALSA SoC audio driver +// +// Copyright(c) 2026 Realtek Semiconductor Corp. +// +// + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/soundwire/sdw_registers.h> +#include <sound/sdca.h> +#include <sound/sdca_function.h> +#include "rt766-sdca.h" +#include "rt766-sdca-sdw.h" + +#define RT766_PROBE_TIMEOUT 5000 + +static bool rt766_sdca_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SDW_SCP_SDCA_INT1 ... SDW_SCP_SDCA_INTMASK4: + case RT766_VERSION_ID ... RT766_BOND_LATCH_ID: + case 0xc344 ... 0xc345: + case 0xc900: + case 0xc920: + case 0xd540 ... 0xd542: + case 0xf01e: + case RT766_HP_POWER_STATE ... RT766_HP_FSM_CTL2_1: + case 0x310100: + case RT766_MCU_PATCH_ADDR1_START ... RT766_MCU_PATCH_ADDR1_END: + case RT766_MCU_PATCH_ADDR2_START ... RT766_MCU_PATCH_ADDR2_END: + case RT766_MUTE_REG(UAJ, USER_FU41, 1): + case RT766_MUTE_REG(UAJ, USER_FU41, 2): + case RT766_VOLUME_REG(UAJ, USER_FU41, 1): + case RT766_VOLUME_REG(UAJ, USER_FU41, 2): + case RT766_MUTE_REG(UAJ, USER_FU36, 1): + case RT766_MUTE_REG(UAJ, USER_FU36, 2): + case RT766_VOLUME_REG(UAJ, USER_FU36, 1): + case RT766_VOLUME_REG(UAJ, USER_FU36, 2): + case RT766_PDE_REQ_REG(UAJ, PDE47): + case RT766_PDE_REQ_REG(UAJ, PDE34): + case RT766_SDCA_CTL(UAJ, CS41, SDCA_CTL_CS_SAMPLERATEINDEX): + case RT766_SDCA_CTL(UAJ, CS36, SDCA_CTL_CS_SAMPLERATEINDEX): + case RT766_FUNC_STATUS_REG(UAJ): /* 0x40480000 */ + case RT766_PDE_ACTUAL_REG(UAJ, PDE47): /* 0x40481400 */ + case RT766_PDE_ACTUAL_REG(UAJ, PDE34): /* 0x40481480 */ + case RT766_GAIN_REG(UAJ, PLATFORM_FU33, 1): + case RT766_GAIN_REG(UAJ, PLATFORM_FU33, 2): + case RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_SELECTED_MODE): + case RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_DETECTED_MODE): /* 0x40600490 */ + case RT766_PDE_REQ_REG(MIC, PDE11): + case RT766_MUTE_REG(MIC, USER_FU113, 1): + case RT766_MUTE_REG(MIC, USER_FU113, 2): + case RT766_MUTE_REG(MIC, USER_FU113, 3): + case RT766_MUTE_REG(MIC, USER_FU113, 4): + case RT766_VOLUME_REG(MIC, USER_FU113, 1): + case RT766_VOLUME_REG(MIC, USER_FU113, 2): + case RT766_VOLUME_REG(MIC, USER_FU113, 3): + case RT766_VOLUME_REG(MIC, USER_FU113, 4): + case RT766_FUNC_STATUS_REG(MIC): /* 0x40880000 */ + case RT766_SDCA_CTL(MIC, CS113, SDCA_CTL_CS_SAMPLERATEINDEX): + case RT766_PDE_ACTUAL_REG(MIC, PDE11): /* 0x40881500 */ + case RT766_FUNC_STATUS_REG(HID): /* 0x40c80000 */ + /* 0x40c80080 - 0x40c80098 */ + case RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_CURRENTOWNER) ... + RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_MESSAGELENGTH): + case RT766_MUTE_REG(AMP, USER_FU21, 1): + case RT766_MUTE_REG(AMP, USER_FU21, 2): + case RT766_VOLUME_REG(AMP, USER_FU21, 1): + case RT766_VOLUME_REG(AMP, USER_FU21, 2): + case RT766_PDE_REQ_REG(AMP, PDE23): + case RT766_FUNC_STATUS_REG(AMP): /* 0x41080000 */ + case RT766_SDCA_CTL(AMP, PPU21, SDCA_CTL_PPU_POSTURENUMBER): + case RT766_SDCA_CTL(AMP, CS21, SDCA_CTL_CS_SAMPLERATEINDEX): + case RT766_PDE_ACTUAL_REG(AMP, PDE23): /* 0x41081980 */ + case RT766_BUF_ADDR_HID1 ... RT766_BUF_ADDR_HID2: + return true; + default: + return false; + } +} + +static bool rt766_sdca_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SDW_SCP_SDCA_INT1 ... SDW_SCP_SDCA_INTMASK4: + case RT766_VERSION_ID ... RT766_BOND_LATCH_ID: + case 0xc344 ... 0xc345: + case 0xc900: + case 0xc920: + case 0xd540 ... 0xd542: + case 0xf01e: + case RT766_HP_POWER_STATE ... RT766_HP_FSM_CTL2_1: + case 0x310100: + case RT766_MCU_PATCH_ADDR1_START ... RT766_MCU_PATCH_ADDR1_END: + case RT766_MCU_PATCH_ADDR2_START ... RT766_MCU_PATCH_ADDR2_END: + case RT766_FUNC_STATUS_REG(UAJ): + case RT766_PDE_ACTUAL_REG(UAJ, PDE47): + case RT766_PDE_ACTUAL_REG(UAJ, PDE34): + case RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_DETECTED_MODE): + case RT766_FUNC_STATUS_REG(MIC): + case RT766_PDE_ACTUAL_REG(MIC, PDE11): + case RT766_FUNC_STATUS_REG(HID): + case RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_CURRENTOWNER) ... + RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_MESSAGELENGTH): + case RT766_FUNC_STATUS_REG(AMP): + case RT766_PDE_ACTUAL_REG(AMP, PDE23): + case RT766_BUF_ADDR_HID1 ... RT766_BUF_ADDR_HID2: + return true; + default: + return false; + } +} + +static int rt766_sdca_mbq_size(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT766_VOLUME_REG(UAJ, USER_FU41, 1): + case RT766_VOLUME_REG(UAJ, USER_FU41, 2): + case RT766_VOLUME_REG(UAJ, USER_FU36, 1): + case RT766_VOLUME_REG(UAJ, USER_FU36, 2): + case RT766_GAIN_REG(UAJ, PLATFORM_FU33, 1): + case RT766_GAIN_REG(UAJ, PLATFORM_FU33, 2): + case RT766_VOLUME_REG(MIC, USER_FU113, 1): + case RT766_VOLUME_REG(MIC, USER_FU113, 2): + case RT766_VOLUME_REG(MIC, USER_FU113, 3): + case RT766_VOLUME_REG(MIC, USER_FU113, 4): + case RT766_VOLUME_REG(AMP, USER_FU21, 1): + case RT766_VOLUME_REG(AMP, USER_FU21, 2): + return 2; + default: + return 1; + } +} + +static const struct regmap_sdw_mbq_cfg rt766_sdca_mbq_cfg = { + .mbq_size = rt766_sdca_mbq_size, +}; + +static const struct regmap_config rt766_sdca_regmap = { + .reg_bits = 32, + .val_bits = 16, + .readable_reg = rt766_sdca_readable_register, + .volatile_reg = rt766_sdca_volatile_register, + .reg_defaults = rt766_sdca_defaults, + .num_reg_defaults = ARRAY_SIZE(rt766_sdca_defaults), + .max_register = SDW_SDCA_MAX_REGISTER, + .cache_type = REGCACHE_MAPLE, + .use_single_read = true, + .use_single_write = true, +}; + +static int rt766_sdca_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + struct rt766_sdca_priv *rt766 = dev_get_drvdata(&slave->dev); + + if (status == SDW_SLAVE_UNATTACHED) + rt766->hw_init = false; + + if (status == SDW_SLAVE_ATTACHED) { + if (rt766->hs_jack) { + /* + * Due to the SCP_SDCA_INTMASK will be cleared by any reset, and then + * if the device attached again, we will need to set the setting back. + * It could avoid losing the jack detection interrupt. + * This also could sync with the cache value as the rt766_sdca_jack_init set. + */ + sdw_write_no_pm(rt766->slave, SDW_SCP_SDCA_INTMASK3, + SDW_SCP_SDCA_INTMASK_SDCA_16); + sdw_write_no_pm(rt766->slave, SDW_SCP_SDCA_INTMASK4, + SDW_SCP_SDCA_INTMASK_SDCA_24); + } + } + + /* + * Perform initialization only if slave status is present and + * hw_init flag is false + */ + if (rt766->hw_init || status != SDW_SLAVE_ATTACHED) + return 0; + + /* perform I/O transfers required for Slave initialization */ + return rt766_sdca_io_init(&slave->dev, slave); +} + +static int rt766_sdca_read_prop(struct sdw_slave *slave) +{ + struct sdw_slave_prop *prop = &slave->prop; + int ret; + + ret = sdw_slave_read_prop(slave); + if (ret < 0) + return ret; + + prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; + prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; + /* + * SDCA interrupts are routed through SoundWire domain IRQ. + */ + prop->use_domain_irq = true; + + return 0; +} + +static const struct sdw_slave_ops rt766_sdca_slave_ops = { + .read_prop = rt766_sdca_read_prop, + .update_status = rt766_sdca_update_status, +}; + +static int rt766_sdca_sdw_probe(struct sdw_slave *slave, + const struct sdw_device_id *id) +{ + struct regmap *regmap; + + /* Regmap Initialization */ + regmap = devm_regmap_init_sdw_mbq_cfg(&slave->dev, slave, + &rt766_sdca_regmap, &rt766_sdca_mbq_cfg); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return rt766_sdca_init(&slave->dev, regmap, slave); +} + +static void rt766_sdca_sdw_remove(struct sdw_slave *slave) +{ + pm_runtime_disable(&slave->dev); +} + +static const struct sdw_device_id rt766_sdca_id[] = { + SDW_SLAVE_ENTRY_EXT(0x025d, 0x766, 0x3, 0x1, 0), + SDW_SLAVE_ENTRY_EXT(0x025d, 0x767, 0x3, 0x1, 0), + {}, +}; +MODULE_DEVICE_TABLE(sdw, rt766_sdca_id); + +static int rt766_sdca_dev_suspend(struct device *dev) +{ + struct rt766_sdca_priv *rt766 = dev_get_drvdata(dev); + + if (!rt766->hw_init) + return 0; + + regcache_cache_only(rt766->regmap, true); + return 0; +} + +static int rt766_sdca_dev_system_suspend(struct device *dev) +{ + struct rt766_sdca_priv *rt766 = dev_get_drvdata(dev); + struct sdw_slave *slave = dev_to_sdw_dev(dev); + int ret1, ret2; + + if (!rt766->hw_init) + return 0; + + /* + * prevent new interrupts from being handled after the + * deferred work completes and before the parent disables + * interrupts on the link + */ + mutex_lock(&rt766->disable_irq_lock); + rt766->disable_irq = true; + ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK3, + SDW_SCP_SDCA_INTMASK_SDCA_16, 0); + ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK4, + SDW_SCP_SDCA_INTMASK_SDCA_24, 0); + mutex_unlock(&rt766->disable_irq_lock); + + if (ret1 < 0 || ret2 < 0) { + /* log but don't prevent suspend from happening */ + dev_dbg(&slave->dev, "%s: could not disable SDCA interrupts\n:", __func__); + } + + return rt766_sdca_dev_suspend(dev); +} + +static int rt766_sdca_dev_resume(struct device *dev) +{ + struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct rt766_sdca_priv *rt766 = dev_get_drvdata(dev); + int ret; + + if (!rt766->first_hw_init) + return 0; + + if (!slave->unattach_request) { + mutex_lock(&rt766->disable_irq_lock); + if (rt766->disable_irq == true) { + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK3, SDW_SCP_SDCA_INTMASK_SDCA_16); + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK4, SDW_SCP_SDCA_INTMASK_SDCA_24); + rt766->disable_irq = false; + } + mutex_unlock(&rt766->disable_irq_lock); + goto regmap_sync; + } + + ret = sdw_slave_wait_for_init(slave, RT766_PROBE_TIMEOUT); + if (ret) { + sdw_show_ping_status(slave->bus, true); + return ret; + } + +regmap_sync: + regcache_cache_only(rt766->regmap, false); + ret = regcache_sync(rt766->regmap); + if (ret) { + regcache_cache_only(rt766->regmap, true); + regcache_mark_dirty(rt766->regmap); + return ret; + } + + return 0; +} + +static const struct dev_pm_ops rt766_sdca_pm = { + SYSTEM_SLEEP_PM_OPS(rt766_sdca_dev_system_suspend, rt766_sdca_dev_resume) + RUNTIME_PM_OPS(rt766_sdca_dev_suspend, rt766_sdca_dev_resume, NULL) +}; + +static struct sdw_driver rt766_sdca_sdw_driver = { + .driver = { + .name = "rt766-sdca", + .pm = pm_ptr(&rt766_sdca_pm), + }, + .probe = rt766_sdca_sdw_probe, + .remove = rt766_sdca_sdw_remove, + .ops = &rt766_sdca_slave_ops, + .id_table = rt766_sdca_id, +}; +module_sdw_driver(rt766_sdca_sdw_driver); + +MODULE_DESCRIPTION("ASoC RT766 SDCA SDW driver"); +MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("SND_SOC_SDCA"); diff --git a/sound/soc/codecs/rt766-sdca-sdw.h b/sound/soc/codecs/rt766-sdca-sdw.h new file mode 100644 index 000000000000..3e923a1ea2f8 --- /dev/null +++ b/sound/soc/codecs/rt766-sdca-sdw.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt766-sdca-sdw.h -- RT766 SDCA ALSA SoC audio driver header + * + * Copyright(c) 2026 Realtek Semiconductor Corp. + */ + +#ifndef __RT766_SDW_H__ +#define __RT766_SDW_H__ + +#include <linux/regmap.h> +#include <linux/soundwire/sdw_registers.h> + +static const struct reg_default rt766_sdca_defaults[] = { + /* 0x40400289 - 0x4040028a */ + { RT766_MUTE_REG(UAJ, USER_FU41, 1), 0x01 }, + { RT766_MUTE_REG(UAJ, USER_FU41, 2), 0x01 }, + /* 0x40400291 - 0x40400292 */ + { RT766_VOLUME_REG(UAJ, USER_FU41, 1), 0x0000 }, + { RT766_VOLUME_REG(UAJ, USER_FU41, 2), 0x0000 }, + /* 0x40400789 - 0x4040078a */ + { RT766_MUTE_REG(UAJ, USER_FU36, 1), 0x01 }, + { RT766_MUTE_REG(UAJ, USER_FU36, 2), 0x01 }, + /* 0x40400791 - 0x40400792 */ + { RT766_VOLUME_REG(UAJ, USER_FU36, 1), 0x0000 }, + { RT766_VOLUME_REG(UAJ, USER_FU36, 2), 0x0000 }, + { RT766_PDE_REQ_REG(UAJ, PDE47), 0x03 }, /* 0x40401408 */ + { RT766_PDE_REQ_REG(UAJ, PDE34), 0x03 }, /* 0x40401488 */ + { RT766_SDCA_CTL(UAJ, CS41, SDCA_CTL_CS_SAMPLERATEINDEX), 0x09 }, /* 0x40480080 */ + { RT766_SDCA_CTL(UAJ, CS36, SDCA_CTL_CS_SAMPLERATEINDEX), 0x09 }, /* 0x40480880 */ + /* 0x40600259 - 0x4060025a */ + { RT766_GAIN_REG(UAJ, PLATFORM_FU33, 1), 0xfe00 }, + { RT766_GAIN_REG(UAJ, PLATFORM_FU33, 2), 0xfe00 }, + { RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_SELECTED_MODE), 0x00 }, /* 0x40600488 */ + + { RT766_PDE_REQ_REG(MIC, PDE11), 0x03 }, /* 0x40801508 */ + /* 0x40801809 - 0x4080180c */ + { RT766_MUTE_REG(MIC, USER_FU113, 1), 0x01 }, + { RT766_MUTE_REG(MIC, USER_FU113, 2), 0x01 }, + { RT766_MUTE_REG(MIC, USER_FU113, 3), 0x01 }, + { RT766_MUTE_REG(MIC, USER_FU113, 4), 0x01 }, + /* 0x40801811 - 0x40801814 */ + { RT766_VOLUME_REG(MIC, USER_FU113, 1), 0x0000 }, + { RT766_VOLUME_REG(MIC, USER_FU113, 2), 0x0000 }, + { RT766_VOLUME_REG(MIC, USER_FU113, 3), 0x0000 }, + { RT766_VOLUME_REG(MIC, USER_FU113, 4), 0x0000 }, + { RT766_SDCA_CTL(MIC, CS113, SDCA_CTL_CS_SAMPLERATEINDEX), 0x09 }, /* 0x40880900 */ + + /* 0x41000189 - 0x4100018a */ + { RT766_MUTE_REG(AMP, USER_FU21, 1), 0x01 }, + { RT766_MUTE_REG(AMP, USER_FU21, 2), 0x01 }, + /* 0x41000191 - 0x41000192 */ + { RT766_VOLUME_REG(AMP, USER_FU21, 1), 0x0000 }, + { RT766_VOLUME_REG(AMP, USER_FU21, 2), 0x0000 }, + { RT766_PDE_REQ_REG(AMP, PDE23), 0x03 }, /* 0x41001988 */ + { RT766_SDCA_CTL(AMP, PPU21, SDCA_CTL_PPU_POSTURENUMBER), 0x00 }, /* 0x41080200 */ + { RT766_SDCA_CTL(AMP, CS21, SDCA_CTL_CS_SAMPLERATEINDEX), 0x09 }, /* 0x41081080 */ + +}; + +#endif /* __RT766_SDW_H__ */ diff --git a/sound/soc/codecs/rt766-sdca.c b/sound/soc/codecs/rt766-sdca.c new file mode 100644 index 000000000000..64d763b96a06 --- /dev/null +++ b/sound/soc/codecs/rt766-sdca.c @@ -0,0 +1,1378 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt766-sdca.c -- rt766 SDCA ALSA SoC audio driver +// +// Copyright(c) 2026 Realtek Semiconductor Corp. +// +// + +#include <linux/bitops.h> +#include <sound/core.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <sound/initval.h> +#include <sound/jack.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/soundwire/sdw_registers.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/sdw.h> +#include <sound/sdca.h> +#include <sound/sdca_asoc.h> +#include <sound/sdca_function.h> +#include <sound/sdca_hid.h> +#include <sound/sdca_regmap.h> +#include <sound/sdca_interrupts.h> +#include <linux/slab.h> +#include <sound/soc-dapm.h> +#include <sound/tlv.h> +#include "rt766-sdca.h" +#include "rt-sdw-common.h" + +static int rt766_sdca_btn_detect(struct sdca_interrupt *interrupt) +{ + struct rt766_sdca_priv *rt766 = interrupt->priv; + unsigned char *buf = NULL; + unsigned int offset, owner, length; + unsigned int det_mode, idx, val; + int ret; + + ret = regmap_read(rt766->regmap, + RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_DETECTED_MODE), + &det_mode); + if (ret < 0) + goto io_error; + + /* get current UMP message owner */ + ret = regmap_read(rt766->regmap, + RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_CURRENTOWNER), + &owner); + if (ret < 0) + goto io_error; + + /* if owner is device then there is no button event from device */ + if (owner == 1) + return 0; + + if (det_mode) { + /* read UMP message length */ + ret = regmap_read(rt766->regmap, + RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_MESSAGELENGTH), + &length); + if (ret < 0) + goto _end_btn_det_; + + /* read UMP message offset */ + ret = regmap_read(rt766->regmap, + RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_MESSAGEOFFSET), + &offset); + if (ret < 0) + goto _end_btn_det_; + + buf = devm_kzalloc(&rt766->slave->dev, length, GFP_KERNEL); + if (!buf) { + dev_err(&rt766->slave->dev, "%s: alloc buf failed\n", __func__); + goto _end_btn_det_; + } + + for (idx = 0; idx < length; idx++) { + ret = regmap_read(rt766->regmap, + RT766_BUF_ADDR_HID1 + offset + idx, &val); + if (ret < 0) + goto _end_btn_det_; + buf[idx] = val & 0xff; + } + + if (rt766->hid) + hid_input_report(rt766->hid, HID_INPUT_REPORT, + buf, length, 1); + } + +_end_btn_det_: + if (buf) + devm_kfree(&rt766->slave->dev, buf); + + /* Host is owner, so set back to device */ + if (owner == 0) { + regmap_write(rt766->regmap, + RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_CURRENTOWNER), 0x01); + } + + return 0; + +io_error: + pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); + return ret; +} + +static irqreturn_t rt766_sdca_irq_btn_handler(int irq, void *data) +{ + struct sdca_interrupt *interrupt = data; + struct rt766_sdca_priv *rt766 = interrupt->priv; + + if (!rt766->hs_jack) + return IRQ_HANDLED; + + if (!rt766->component->card || !rt766->component->card->instantiated) + return IRQ_HANDLED; + + mutex_lock(&rt766->disable_irq_lock); + if (!rt766->disable_irq) + rt766_sdca_btn_detect(interrupt); + mutex_unlock(&rt766->disable_irq_lock); + return IRQ_HANDLED; +} + +static int rt766_sdca_headset_detect(struct rt766_sdca_priv *rt766) +{ + unsigned int det_mode; + int ret; + + /* get detected_mode */ + ret = regmap_read(rt766->regmap, + RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_DETECTED_MODE), + &det_mode); + if (ret < 0) + goto io_error; + + switch (det_mode) { + case 0x00: + rt766->jack_type = 0; + break; + case 0x03: + rt766->jack_type = SND_JACK_HEADPHONE; + break; + case 0x05: + rt766->jack_type = SND_JACK_HEADSET; + break; + } + + /* write selected_mode */ + if (det_mode) { + ret = regmap_write(rt766->regmap, + RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_SELECTED_MODE), + det_mode); + if (ret < 0) + goto io_error; + } + + dev_dbg(&rt766->slave->dev, + "%s, detected_mode=0x%x\n", __func__, det_mode); + + return 0; + +io_error: + pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); + return ret; +} + +static irqreturn_t rt766_sdca_irq_jd_handler(int irq, void *data) +{ + struct sdca_interrupt *interrupt = data; + struct rt766_sdca_priv *rt766 = interrupt->priv; + + if (!rt766->hs_jack) + return IRQ_HANDLED; + + if (!rt766->component->card || !rt766->component->card->instantiated) + return IRQ_HANDLED; + + mutex_lock(&rt766->disable_irq_lock); + if (!rt766->disable_irq) + rt766_sdca_headset_detect(rt766); + mutex_unlock(&rt766->disable_irq_lock); + + dev_dbg(&rt766->slave->dev, + "in %s, jack_type=%d\n", __func__, rt766->jack_type); + + snd_soc_jack_report(rt766->hs_jack, rt766->jack_type, SND_JACK_HEADSET); + return IRQ_HANDLED; +} + +static void rt766_sdca_destroy_hid_device(struct sdca_interrupt *interrupt) +{ + struct rt766_sdca_priv *rt766 = interrupt->priv; + + hid_destroy_device(rt766->hid); +} + +static int rt766_sdca_irq_ctl(struct rt766_sdca_priv *rt766, + struct sdca_function_data *function, + struct snd_soc_component *component, + struct sdca_interrupt_info *info, + bool enabled) +{ + struct device *dev = &rt766->slave->dev; + struct sdca_interrupt *interrupt; + struct sdca_control *control; + struct sdca_entity *entity; + irq_handler_t handler; + int i, j, irq, ret; + + for (i = 0; i < function->num_entities; i++) { + entity = &function->entities[i]; + + for (j = 0; j < entity->num_controls; j++) { + control = &entity->controls[j]; + irq = control->interrupt_position; + + switch (SDCA_CTL_TYPE(entity->type, control->sel)) { + case SDCA_CTL_TYPE_S(GE, DETECTED_MODE): + handler = rt766_sdca_irq_jd_handler; + break; + case SDCA_CTL_TYPE_S(HIDE, HIDTX_CURRENTOWNER): + handler = rt766_sdca_irq_btn_handler; + break; + default: + continue; + } + + interrupt = &info->irqs[irq]; + + if (enabled) { + ret = sdca_irq_data_populate(dev, rt766->regmap, component, + function, entity, control, + interrupt); + if (ret) + return ret; + + if (handler == rt766_sdca_irq_btn_handler) { + ret = sdca_add_hid_device(interrupt); + if (ret) + return ret; + + interrupt->free_priv = rt766_sdca_destroy_hid_device; + rt766->hid = interrupt->priv; + } + + interrupt->priv = rt766; + ret = sdca_irq_request(dev, info, irq, interrupt->name, + handler, interrupt); + if (ret) { + dev_err(dev, "failed to request irq %s: %d\n", + interrupt->name, ret); + sdca_irq_cleanup_late(dev, function, info); + return ret; + } + dev_dbg(dev, "Requesting IRQ %d InterruptName=%s\n", irq, interrupt->name); + } else { + sdca_irq_cleanup_late(dev, function, info); + dev_dbg(dev, "Freeing IRQ %d\n", irq); + } + } + } + + return 0; +} + +static int rt766_sdca_set_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *hs_jack, void *data) +{ + struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); + int ret; + + if (!rt766->uaj_func_data) { + dev_err(&rt766->slave->dev, "The SDCA UAJ function is not supported.\n"); + return -EINVAL; + } + + rt766->hs_jack = hs_jack; + + if (!rt766->first_hw_init) + return 0; + + ret = pm_runtime_resume_and_get(component->dev); + if (ret < 0) { + if (ret != -EACCES) { + dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret); + return ret; + } + + /* pm_runtime not enabled yet */ + dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__); + return 0; + } + + /* disable interrupts if hs_jack is not set */ + if (!rt766->hs_jack) { + if (rt766->uaj_func_data) + rt766_sdca_irq_ctl(rt766, rt766->uaj_func_data, + rt766->component, rt766->irq_info, false); + + if (rt766->hid_func_data) + rt766_sdca_irq_ctl(rt766, rt766->hid_func_data, + rt766->component, rt766->irq_info, false); + } + + pm_runtime_put_autosuspend(component->dev); + + return 0; +} + +static int rt766_sdca_set_fu_ctl(struct rt766_sdca_priv *rt766, int func_num, int fu_num) +{ + unsigned int fu01_reg, fu02_reg; + unsigned int ch_01, ch_02; + unsigned int ch_mute; + unsigned int fu_reg; + int err, i; + + switch (fu_num) { + case RT766_SDCA_ENT_USER_FU41: + ch_01 = (rt766->fu41_dapm_mute || rt766->fu41_mixer_l_mute) ? 0x01 : 0x00; + ch_02 = (rt766->fu41_dapm_mute || rt766->fu41_mixer_r_mute) ? 0x01 : 0x00; + break; + case RT766_SDCA_ENT_USER_FU36: + ch_01 = (rt766->fu36_dapm_mute || rt766->fu36_mixer_l_mute) ? 0x01 : 0x00; + ch_02 = (rt766->fu36_dapm_mute || rt766->fu36_mixer_r_mute) ? 0x01 : 0x00; + break; + case RT766_SDCA_ENT_USER_FU21: + ch_01 = (rt766->fu21_dapm_mute || rt766->fu21_mixer_l_mute) ? 0x01 : 0x00; + ch_02 = (rt766->fu21_dapm_mute || rt766->fu21_mixer_r_mute) ? 0x01 : 0x00; + break; + case RT766_SDCA_ENT_USER_FU113: + for (i = 0; i < ARRAY_SIZE(rt766->fu113_mixer_mute); i++) { + ch_mute = (rt766->fu113_dapm_mute || rt766->fu113_mixer_mute[i]) ? 0x01 : 0x00; + fu_reg = SDW_SDCA_CTL(func_num, fu_num, SDCA_CTL_FU_MUTE, 1) + i; + err = regmap_write(rt766->regmap, fu_reg, ch_mute); + if (err < 0) + return err; + } + return 0; + } + + fu01_reg = SDW_SDCA_CTL(func_num, fu_num, SDCA_CTL_FU_MUTE, 1); + fu02_reg = SDW_SDCA_CTL(func_num, fu_num, SDCA_CTL_FU_MUTE, 2); + err = regmap_write(rt766->regmap, fu01_reg, ch_01); + if (err < 0) + return err; + err = regmap_write(rt766->regmap, fu02_reg, ch_02); + if (err < 0) + return err; + + return 0; +} + +static int rt766_sdca_fu41_playback_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = !rt766->fu41_mixer_l_mute; + ucontrol->value.integer.value[1] = !rt766->fu41_mixer_r_mute; + return 0; +} + +static int rt766_sdca_fu41_playback_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); + int err; + + if (rt766->fu41_mixer_l_mute == !ucontrol->value.integer.value[0] && + rt766->fu41_mixer_r_mute == !ucontrol->value.integer.value[1]) + return 0; + + rt766->fu41_mixer_l_mute = !ucontrol->value.integer.value[0]; + rt766->fu41_mixer_r_mute = !ucontrol->value.integer.value[1]; + + err = rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU41); + if (err < 0) + return err; + + return 1; +} + +static int rt766_sdca_fu36_capture_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = !rt766->fu36_mixer_l_mute; + ucontrol->value.integer.value[1] = !rt766->fu36_mixer_r_mute; + return 0; +} + +static int rt766_sdca_fu36_capture_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); + int err; + + if (rt766->fu36_mixer_l_mute == !ucontrol->value.integer.value[0] && + rt766->fu36_mixer_r_mute == !ucontrol->value.integer.value[1]) + return 0; + + rt766->fu36_mixer_l_mute = !ucontrol->value.integer.value[0]; + rt766->fu36_mixer_r_mute = !ucontrol->value.integer.value[1]; + err = rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU36); + if (err < 0) + return err; + + return 1; +} + +static int rt766_sdca_fu21_playback_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = !rt766->fu21_mixer_l_mute; + ucontrol->value.integer.value[1] = !rt766->fu21_mixer_r_mute; + return 0; +} + +static int rt766_sdca_fu21_playback_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); + int err; + + if (rt766->fu21_mixer_l_mute == !ucontrol->value.integer.value[0] && + rt766->fu21_mixer_r_mute == !ucontrol->value.integer.value[1]) + return 0; + + rt766->fu21_mixer_l_mute = !ucontrol->value.integer.value[0]; + rt766->fu21_mixer_r_mute = !ucontrol->value.integer.value[1]; + + err = rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_AMP, RT766_SDCA_ENT_USER_FU21); + if (err < 0) + return err; + + return 1; +} + +static int rt766_sdca_fu113_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 rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + rt766->fu113_dapm_mute = false; + rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_MIC, RT766_SDCA_ENT_USER_FU113); + break; + case SND_SOC_DAPM_PRE_PMD: + rt766->fu113_dapm_mute = true; + rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_MIC, RT766_SDCA_ENT_USER_FU113); + break; + } + return 0; +} + +static int rt766_sdca_dmic_set_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); + struct rt_sdca_dmic_kctrl_priv *p = + (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value; + const unsigned int interval_offset = 0xc0; + unsigned int regvalue, ctl, i; + + /* check all channels */ + for (i = 0; i < p->count; i++) { + regmap_read(rt766->regmap, p->reg_base + i, ®value); + ctl = p->max - (((0x1e00 - regvalue) & 0xffff) / interval_offset); + + ucontrol->value.integer.value[i] = ctl; + } + + return 0; +} + +static int rt766_sdca_dmic_set_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt_sdca_dmic_kctrl_priv *p = + (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value; + struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); + const unsigned int interval_offset = 0xc0; + unsigned int gain_val[4]; + unsigned int i, changed = 0; + unsigned int regvalue[4]; + int err; + + /* check all channels */ + for (i = 0; i < p->count; i++) { + regmap_read(rt766->regmap, p->reg_base + i, ®value[i]); + + gain_val[i] = ucontrol->value.integer.value[i]; + if (gain_val[i] > p->max) + gain_val[i] = p->max; + + gain_val[i] = 0x1e00 - ((p->max - gain_val[i]) * interval_offset); + gain_val[i] &= 0xffff; + + if (regvalue[i] != gain_val[i]) + changed = 1; + } + + if (!changed) + return 0; + + for (i = 0; i < p->count; i++) { + err = regmap_write(rt766->regmap, p->reg_base + i, gain_val[i]); + if (err < 0) + dev_err(&rt766->slave->dev, "0x%08x can't be set\n", p->reg_base + i); + } + + return changed; +} + +static int rt766_sdca_dmic_fu113_capture_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); + unsigned int i; + + for (i = 0; i < 4; i++) + ucontrol->value.integer.value[i] = !rt766->fu113_mixer_mute[i]; + return 0; +} + +static int rt766_sdca_dmic_fu113_capture_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); + int err, changed = 0, i; + + for (i = 0; i < 4; i++) { + if (rt766->fu113_mixer_mute[i] != !ucontrol->value.integer.value[i]) + changed = 1; + rt766->fu113_mixer_mute[i] = !ucontrol->value.integer.value[i]; + } + + err = rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_MIC, RT766_SDCA_ENT_USER_FU113); + if (err < 0) + return err; + return changed; +} + +static int rt766_sdca_fu41_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 rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + rt766->fu41_dapm_mute = false; + rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU41); + break; + case SND_SOC_DAPM_PRE_PMD: + rt766->fu41_dapm_mute = true; + rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU41); + break; + } + return 0; +} + +static int rt766_sdca_pde_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event, int func_num, int pde_num, const char *pde_ent) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); + struct sdca_function_data *func_data; + unsigned char ps0 = 0x0, ps3 = 0x3; + const struct sdca_entity *entity; + unsigned int pde_req_reg; + int from_ps, to_ps; + int ret; + + pde_req_reg = SDW_SDCA_CTL(func_num, pde_num, SDCA_CTL_PDE_REQUESTED_PS, 0); + + switch (func_num) { + case RT766_FUNC_NUM_UAJ: + func_data = rt766->uaj_func_data; + break; + case RT766_FUNC_NUM_AMP: + func_data = rt766->sa_func_data; + break; + case RT766_FUNC_NUM_MIC: + func_data = rt766->sm_func_data; + break; + default: + dev_err(component->dev, "%s: unsupported func_num %d\n", + __func__, func_num); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt766->regmap, pde_req_reg, ps0); + from_ps = ps3; + to_ps = ps0; + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt766->regmap, pde_req_reg, ps3); + from_ps = ps0; + to_ps = ps3; + break; + } + + entity = sdca_find_entity_by_label(func_data, pde_ent); + if (!entity) { + dev_err(component->dev, "%s: failed to find entity %s\n", + __func__, pde_ent); + return -EINVAL; + } + + ret = sdca_asoc_pde_poll_actual_ps(rt766->regmap, + func_num, + pde_num, + from_ps, to_ps, + entity->pde.max_delay, + entity->pde.num_max_delay); + if (ret) + dev_err(component->dev, "%s: PDE transition %x -> %x failed, err=%d\n", + __func__, from_ps, to_ps, ret); + + return ret; +} + +static int rt766_sdca_pde47_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + return rt766_sdca_pde_event(w, kcontrol, event, + RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_PDE47, "PDE 47"); +} + +static int rt766_sdca_fu36_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 rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + rt766->fu36_dapm_mute = false; + rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU36); + break; + case SND_SOC_DAPM_PRE_PMD: + rt766->fu36_dapm_mute = true; + rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU36); + break; + } + return 0; +} + +static int rt766_sdca_pde34_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + return rt766_sdca_pde_event(w, kcontrol, event, + RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_PDE34, "PDE 34"); +} + +static int rt766_sdca_fu21_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 rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + rt766->fu21_dapm_mute = false; + rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_AMP, RT766_SDCA_ENT_USER_FU21); + break; + case SND_SOC_DAPM_PRE_PMD: + rt766->fu21_dapm_mute = true; + rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_AMP, RT766_SDCA_ENT_USER_FU21); + break; + } + return 0; +} + +static int rt766_sdca_pde23_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + return rt766_sdca_pde_event(w, kcontrol, event, + RT766_FUNC_NUM_AMP, RT766_SDCA_ENT_PDE23, "PDE 23"); +} + +static int rt766_sdca_pde11_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + return rt766_sdca_pde_event(w, kcontrol, event, + RT766_FUNC_NUM_MIC, RT766_SDCA_ENT_PDE11, "PDE 11"); +} + +static int rt766_dmic_fu_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct rt_sdca_dmic_kctrl_priv *p = + (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value; + + if (p->max == 1) + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + else + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = p->count; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = p->max; + return 0; +} + +static const char * const rt766_rx_data_ch_select[] = { + "L,R", + "R,L", + "L,L", + "R,R", + "L,L+R", + "R,L+R", + "L+R,L", + "L+R,R", + "L+R,L+R", +}; + +static SOC_ENUM_SINGLE_DECL(rt766_rx_data_ch_enum, + RT766_SDCA_CTL(AMP, PPU21, SDCA_CTL_PPU_POSTURENUMBER), 0, + rt766_rx_data_ch_select); + +static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -9525, 75, 0); +static const DECLARE_TLV_DB_SCALE(spk_vol_tlv, -6525, 75, 0); +static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -1725, 75, 0); +static const DECLARE_TLV_DB_SCALE(boost_vol_tlv, -200, 200, 0); + +#define RT766_P75DB_STEP 0xC0 /* 0.75 dB in Q7.8 format */ +#define RT766_2DB_STEP 0x200 /* 2 dB in Q7.8 format */ +#define RT766_HP_VOL_MIN (-127) /* -95.25 dB / 0.75 dB step */ +#define RT766_HS_VOL_MIN (-23) /* -17.25 dB / 0.75 dB step */ +#define RT766_HS_BOOST_VOL_MIN (-1) /* -2 dB / 2 dB step */ +#define RT766_SPK_VOL_MIN (-87) /* -65.25 dB / 0.75 dB step */ +#define RT766_P_VOL_MAX 0 /* 0 dB / 0.75 dB step */ +#define RT766_HS_VOL_MAX 40 /* 30 dB / 0.75 dB step */ +#define RT766_HS_BOOST_VOL_MAX 20 /* 40 dB / 2 dB step */ + +static const struct snd_kcontrol_new rt766_sdca_controls[] = { + SOC_DOUBLE_EXT("FU41 Playback Switch", SND_SOC_NOPM, 0, 1, 1, 0, + rt766_sdca_fu41_playback_get, rt766_sdca_fu41_playback_put), + SDCA_DOUBLE_Q78_TLV("FU41 Playback Volume", + RT766_VOLUME_REG(UAJ, USER_FU41, 1), + RT766_VOLUME_REG(UAJ, USER_FU41, 2), + RT766_HP_VOL_MIN, RT766_P_VOL_MAX, RT766_P75DB_STEP, hp_vol_tlv), + SOC_DOUBLE_EXT("FU36 Capture Switch", SND_SOC_NOPM, 0, 1, 1, 0, + rt766_sdca_fu36_capture_get, rt766_sdca_fu36_capture_put), + SDCA_DOUBLE_Q78_TLV("FU36 Capture Volume", + RT766_VOLUME_REG(UAJ, USER_FU36, 1), + RT766_VOLUME_REG(UAJ, USER_FU36, 2), + RT766_HS_VOL_MIN, RT766_HS_VOL_MAX, RT766_P75DB_STEP, mic_vol_tlv), + SDCA_DOUBLE_Q78_TLV("FU33 Boost Volume", + RT766_GAIN_REG(UAJ, PLATFORM_FU33, 1), + RT766_GAIN_REG(UAJ, PLATFORM_FU33, 2), + RT766_HS_BOOST_VOL_MIN, RT766_HS_BOOST_VOL_MAX, RT766_2DB_STEP, boost_vol_tlv), + + SOC_DOUBLE_EXT("FU21 Playback Switch", SND_SOC_NOPM, 0, 1, 1, 0, + rt766_sdca_fu21_playback_get, rt766_sdca_fu21_playback_put), + SDCA_DOUBLE_Q78_TLV("FU21 Playback Volume", + RT766_VOLUME_REG(AMP, USER_FU21, 1), + RT766_VOLUME_REG(AMP, USER_FU21, 2), + RT766_SPK_VOL_MIN, RT766_P_VOL_MAX, RT766_P75DB_STEP, spk_vol_tlv), + SOC_ENUM("RX Channel Select", rt766_rx_data_ch_enum), + + RT_SDCA_FU_CTRL("FU113 Capture Switch", + RT766_MUTE_REG(MIC, USER_FU113, 1), 1, 1, 4, rt766_dmic_fu_info, + rt766_sdca_dmic_fu113_capture_get, rt766_sdca_dmic_fu113_capture_put), + RT_SDCA_EXT_TLV("FU113 Capture Volume", + RT766_VOLUME_REG(MIC, USER_FU113, 1), + rt766_sdca_dmic_set_gain_get, rt766_sdca_dmic_set_gain_put, + 4, 0x3f, mic_vol_tlv, rt766_dmic_fu_info), +}; + +static const struct snd_soc_dapm_widget rt766_sdca_dapm_widgets[] = { + /* UAJ */ + SND_SOC_DAPM_OUTPUT("HP"), + SND_SOC_DAPM_INPUT("MIC2"), + SND_SOC_DAPM_SUPPLY("PDE 47", SND_SOC_NOPM, 0, 0, + rt766_sdca_pde47_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("PDE 34", SND_SOC_NOPM, 0, 0, + rt766_sdca_pde34_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_DAC_E("FU 41", NULL, SND_SOC_NOPM, 0, 0, + rt766_sdca_fu41_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("FU 36", NULL, SND_SOC_NOPM, 0, 0, + rt766_sdca_fu36_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP12TX", "DP12 Capture", 0, SND_SOC_NOPM, 0, 0), + + /* AMP */ + SND_SOC_DAPM_OUTPUT("SPOL"), + SND_SOC_DAPM_OUTPUT("SPOR"), + SND_SOC_DAPM_DAC_E("FU 21", NULL, SND_SOC_NOPM, 0, 0, + rt766_sdca_fu21_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("PDE 23", SND_SOC_NOPM, 0, 0, + rt766_sdca_pde23_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0), + + /* DMIC */ + SND_SOC_DAPM_INPUT("DMIC1"), + SND_SOC_DAPM_INPUT("DMIC2"), + SND_SOC_DAPM_SUPPLY("PDE 11", SND_SOC_NOPM, 0, 0, + rt766_sdca_pde11_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("FU 113", NULL, SND_SOC_NOPM, 0, 0, + rt766_sdca_fu113_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_AIF_OUT("DP8TX", "DP8 Capture", 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route rt766_sdca_audio_map[] = { + { "FU 41", NULL, "DP3RX" }, + { "DP12TX", NULL, "FU 36" }, + { "FU 36", NULL, "PDE 34" }, + { "FU 36", NULL, "MIC2" }, + { "HP", NULL, "PDE 47" }, + { "HP", NULL, "FU 41" }, + + { "FU 21", NULL, "DP1RX" }, + { "FU 21", NULL, "PDE 23" }, + { "SPOL", NULL, "FU 21" }, + { "SPOR", NULL, "FU 21" }, + + {"DP8TX", NULL, "FU 113"}, + {"FU 113", NULL, "PDE 11"}, + {"FU 113", NULL, "DMIC1"}, + {"FU 113", NULL, "DMIC2"}, +}; + +static int rt766_sdca_probe(struct snd_soc_component *component) +{ + struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); + struct device *dev = &rt766->slave->dev; + int ret; + + rt766->component = component; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + if (rt766->uaj_func_data) { + dev_dbg(dev, "%s : irq %d\n", __func__, rt766->slave->irq); + + rt766->irq_info = devm_sdca_irq_allocate(dev, rt766->regmap, rt766->slave->irq); + if (IS_ERR(rt766->irq_info)) + return PTR_ERR(rt766->irq_info); + + ret = rt766_sdca_irq_ctl(rt766, rt766->uaj_func_data, + component, rt766->irq_info, true); + if (ret < 0) { + dev_err(dev, "Failed to request UAJ SDCA IRQ: %d\n", ret); + return ret; + } + + if (rt766->hid_func_data) { + ret = rt766_sdca_irq_ctl(rt766, rt766->hid_func_data, + component, rt766->irq_info, true); + if (ret < 0) { + dev_err(dev, "Failed to request HID SDCA IRQ: %d\n", ret); + return ret; + } + } + } + + return 0; +} + +static void rt766_sdca_remove(struct snd_soc_component *component) +{ + struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); + + sdca_irq_cleanup_late(component->dev, rt766->uaj_func_data, rt766->irq_info); + sdca_irq_cleanup_late(component->dev, rt766->hid_func_data, rt766->irq_info); +} + +static const struct snd_soc_component_driver soc_sdca_dev_rt766 = { + .probe = rt766_sdca_probe, + .remove = rt766_sdca_remove, + .controls = rt766_sdca_controls, + .num_controls = ARRAY_SIZE(rt766_sdca_controls), + .dapm_widgets = rt766_sdca_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt766_sdca_dapm_widgets), + .dapm_routes = rt766_sdca_audio_map, + .num_dapm_routes = ARRAY_SIZE(rt766_sdca_audio_map), + .set_jack = rt766_sdca_set_jack_detect, + .endianness = 1, +}; + +static int rt766_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, + int direction) +{ + snd_soc_dai_dma_data_set(dai, direction, sdw_stream); + + return 0; +} + +static void rt766_sdca_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + snd_soc_dai_set_dma_data(dai, substream, NULL); +} + +static int rt766_sdca_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); + struct sdw_stream_config stream_config; + struct sdw_port_config port_config; + enum sdw_data_direction direction; + struct sdw_stream_runtime *sdw_stream; + unsigned int sampling_rate; + int retval, port; + + dev_dbg(dai->dev, "%s %s id %d", __func__, dai->name, dai->id); + sdw_stream = snd_soc_dai_get_dma_data(dai, substream); + + if (!sdw_stream) + return -EINVAL; + + if (!rt766->slave) + return -EINVAL; + + /* SoundWire specific configuration */ + snd_sdw_params_to_config(substream, params, &stream_config, &port_config); + + /* SoundWire specific configuration */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + direction = SDW_DATA_DIR_RX; + if (dai->id == RT766_AIF1) + port = 3; + else if (dai->id == RT766_AIF2) + port = 1; + else + return -EINVAL; + } else { + direction = SDW_DATA_DIR_TX; + if (dai->id == RT766_AIF1) + port = 12; + else if (dai->id == RT766_AIF3) + port = 8; + else + return -EINVAL; + } + + port_config.num = port; + retval = sdw_stream_add_slave(rt766->slave, &stream_config, + &port_config, 1, sdw_stream); + if (retval) { + dev_err(dai->dev, "%s: Unable to configure port\n", __func__); + return retval; + } + + if (params_channels(params) > 16) { + dev_err(component->dev, "%s: Unsupported channels %d\n", + __func__, params_channels(params)); + return -EINVAL; + } + + /* sampling rate configuration */ + switch (params_rate(params)) { + case 44100: + sampling_rate = RT766_SDCA_RATE_44100HZ; + break; + case 48000: + sampling_rate = RT766_SDCA_RATE_48000HZ; + break; + case 96000: + sampling_rate = RT766_SDCA_RATE_96000HZ; + break; + case 192000: + sampling_rate = RT766_SDCA_RATE_192000HZ; + break; + default: + dev_err(component->dev, "%s: Rate %d is not supported\n", + __func__, params_rate(params)); + return -EINVAL; + } + + /* set sampling frequency */ + switch (dai->id) { + case RT766_AIF1: + regmap_write(rt766->regmap, + RT766_SDCA_CTL(UAJ, CS41, SDCA_CTL_CS_SAMPLERATEINDEX), + sampling_rate); + regmap_write(rt766->regmap, + RT766_SDCA_CTL(UAJ, CS36, SDCA_CTL_CS_SAMPLERATEINDEX), + sampling_rate); + break; + case RT766_AIF2: + regmap_write(rt766->regmap, + RT766_SDCA_CTL(AMP, CS21, SDCA_CTL_CS_SAMPLERATEINDEX), + sampling_rate); + break; + case RT766_AIF3: + regmap_write(rt766->regmap, + RT766_SDCA_CTL(MIC, CS113, SDCA_CTL_CS_SAMPLERATEINDEX), + sampling_rate); + break; + default: + dev_err(component->dev, "%s: Wrong DAI id\n", __func__); + return -EINVAL; + } + + return 0; +} + +static int rt766_sdca_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); + struct sdw_stream_runtime *sdw_stream = + snd_soc_dai_get_dma_data(dai, substream); + + if (!rt766->slave) + return -EINVAL; + + sdw_stream_remove_slave(rt766->slave, sdw_stream); + return 0; +} + +#define RT766_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \ + SNDRV_PCM_RATE_192000) +#define RT766_DAC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) +#define RT766_ADC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +static const struct snd_soc_dai_ops rt766_sdca_ops = { + .hw_params = rt766_sdca_pcm_hw_params, + .hw_free = rt766_sdca_pcm_hw_free, + .set_stream = rt766_sdca_set_sdw_stream, + .shutdown = rt766_sdca_shutdown, +}; + +static struct snd_soc_dai_driver rt766_sdca_dai[] = { + { + .name = "rt766-sdca-aif1", + .id = RT766_AIF1, + .playback = { + .stream_name = "DP3 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT766_STEREO_RATES, + .formats = RT766_DAC_FORMATS, + }, + .capture = { + .stream_name = "DP12 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT766_STEREO_RATES, + .formats = RT766_ADC_FORMATS, + }, + .ops = &rt766_sdca_ops, + .symmetric_rate = 1, + }, + { + .name = "rt766-sdca-aif2", + .id = RT766_AIF2, + .playback = { + .stream_name = "DP1 Playback", + .channels_min = 1, + .channels_max = 4, + .rates = RT766_STEREO_RATES, + .formats = RT766_DAC_FORMATS, + }, + .ops = &rt766_sdca_ops, + }, + { + .name = "rt766-sdca-aif3", + .id = RT766_AIF3, + .capture = { + .stream_name = "DP8 Capture", + .channels_min = 1, + .channels_max = 4, + .rates = RT766_STEREO_RATES, + .formats = RT766_ADC_FORMATS, + }, + .ops = &rt766_sdca_ops, + } +}; + +static unsigned int rt766_find_dt_rates(struct device *dev, struct sdca_function_data *function, + const char *label) +{ + struct snd_soc_pcm_stream stream; + struct sdca_entity *entity; + int i, ret; + + for (i = 0; i < function->num_entities; i++) { + entity = &function->entities[i]; + + if (strcmp(entity->label, label)) + continue; + + /* Can't check earlier as only terminals have an iot member. */ + if (!entity->iot.is_dataport) + continue; + + ret = sdca_asoc_populate_rate_format(dev, function, entity, &stream); + if (ret < 0) { + dev_dbg(dev, "%s: failed to parse rates for entity %s\n", + __func__, entity->label); + return 0; + } + + dev_dbg(dev, "%s: %s supports rates 0x%08x\n", __func__, entity->label, stream.rates); + } + + return stream.rates; +} + +int rt766_sdca_init(struct device *dev, struct regmap *regmap, struct sdw_slave *slave) +{ + struct sdca_function_data *func_data_ptr; + struct snd_soc_dai_driver *dai_drv; + struct rt766_sdca_priv *rt766; + unsigned int rates; + int ret; + int i; + + rt766 = devm_kzalloc(dev, sizeof(*rt766), GFP_KERNEL); + if (!rt766) + return -ENOMEM; + + dev_set_drvdata(dev, rt766); + rt766->slave = slave; + rt766->regmap = regmap; + + regcache_cache_only(rt766->regmap, true); + + ret = devm_mutex_init(dev, &rt766->disable_irq_lock); + if (ret < 0) { + dev_err(dev, "Failed to initialize mutex\n"); + return ret; + } + + /* + * Mark hw_init to false + * HW init will be performed when device reports present + */ + rt766->hw_init = false; + rt766->first_hw_init = false; + rt766->fu41_dapm_mute = true; + rt766->fu41_mixer_l_mute = rt766->fu41_mixer_r_mute = false; + rt766->fu36_dapm_mute = true; + rt766->fu36_mixer_l_mute = rt766->fu36_mixer_r_mute = true; + rt766->fu21_dapm_mute = true; + rt766->fu21_mixer_l_mute = rt766->fu21_mixer_r_mute = false; + rt766->fu113_dapm_mute = true; + rt766->fu113_mixer_mute[0] = rt766->fu113_mixer_mute[1] = + rt766->fu113_mixer_mute[2] = rt766->fu113_mixer_mute[3] = true; + + dai_drv = devm_kzalloc(dev, sizeof(struct snd_soc_dai_driver) * ARRAY_SIZE(rt766_sdca_dai), GFP_KERNEL); + if (!dai_drv) { + dev_err(dev, "Failed to allocate memory for DAI driver\n"); + ret = -ENOMEM; + goto _sdw_init_err_; + } + memcpy(dai_drv, rt766_sdca_dai, sizeof(struct snd_soc_dai_driver) * ARRAY_SIZE(rt766_sdca_dai)); + + /* get SDCA function data */ + dev_dbg(dev, "SDCA functions found: %d", slave->sdca_data.num_functions); + for (i = 0; i < slave->sdca_data.num_functions; i++) { + func_data_ptr = devm_kzalloc(dev, sizeof(*func_data_ptr), GFP_KERNEL); + if (!func_data_ptr) { + dev_err(dev, "Failed to allocate memory for function data\n"); + ret = -ENOMEM; + goto _free_dai_drv_; + } + + func_data_ptr->desc = &slave->sdca_data.function[i]; + ret = sdca_parse_function(dev, func_data_ptr); + if (ret) { + devm_kfree(dev, func_data_ptr); + goto _free_dai_drv_; + } + dev_dbg(dev, "Function type=%d, num_entities=%d", + slave->sdca_data.function[i].type, func_data_ptr->num_entities); + + switch (slave->sdca_data.function[i].type) { + case SDCA_FUNCTION_TYPE_UAJ: + rt766->uaj_func_data = func_data_ptr; + /* + * Some machines may only support a subset of the sample rates supported by the codec. + * Therefore, we need to parse the supported sample rates from the DisCo table and + * configure them in the DAI. If the DisCo table does not provide sample rate information, + * we will fall back to the default supported rates defined in the codec driver. + */ + rates = rt766_find_dt_rates(dev, func_data_ptr, "IT 41"); + if (rates) + dai_drv[RT766_DAI_UAJ].playback.rates = rates; + + rates = rt766_find_dt_rates(dev, func_data_ptr, "OT 36"); + if (rates) + dai_drv[RT766_DAI_UAJ].capture.rates = rates; + break; + case SDCA_FUNCTION_TYPE_SMART_AMP: + rt766->sa_func_data = func_data_ptr; + rates = rt766_find_dt_rates(dev, func_data_ptr, "IT 21"); + if (rates) + dai_drv[RT766_DAI_AMP].playback.rates = rates; + break; + case SDCA_FUNCTION_TYPE_SMART_MIC: + rt766->sm_func_data = func_data_ptr; + rates = rt766_find_dt_rates(dev, func_data_ptr, "OT 113"); + if (rates) + dai_drv[RT766_DAI_MIC].capture.rates = rates; + break; + case SDCA_FUNCTION_TYPE_HID: + rt766->hid_func_data = func_data_ptr; + break; + default: + dev_dbg(dev, "Unexpected SDCA function type found: %d", + slave->sdca_data.function[i].type); + } + } + + ret = devm_snd_soc_register_component(dev, + &soc_sdca_dev_rt766, dai_drv, ARRAY_SIZE(rt766_sdca_dai)); + if (ret < 0) + goto _free_dai_drv_; + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + dev_dbg(dev, "%s\n", __func__); + return 0; + +_free_dai_drv_: + if (dai_drv) + devm_kfree(dev, dai_drv); + +_sdw_init_err_: + return ret; +} + +static int rt766_func_initialize(struct rt766_sdca_priv *rt766, struct sdca_function_data *func_data) +{ + struct device *dev = &rt766->slave->dev; + unsigned int func_status_reg; + unsigned int func_status; + int ret; + + switch (func_data->desc->type) { + case SDCA_FUNCTION_TYPE_UAJ: + func_status_reg = RT766_FUNC_STATUS_REG(UAJ); + break; + case SDCA_FUNCTION_TYPE_SMART_AMP: + func_status_reg = RT766_FUNC_STATUS_REG(AMP); + break; + case SDCA_FUNCTION_TYPE_SMART_MIC: + func_status_reg = RT766_FUNC_STATUS_REG(MIC); + break; + case SDCA_FUNCTION_TYPE_HID: + func_status_reg = RT766_FUNC_STATUS_REG(HID); + break; + default: + dev_dbg(dev, "Unexpected SDCA function type found: %d", + func_data->desc->type); + return -EINVAL; + } + + regmap_read(rt766->regmap, func_status_reg, &func_status); + dev_dbg(dev, "%s, %s func_status=0x%x\n", __func__, func_data->desc->name, func_status); + + if ((func_status & SDCA_CTL_ENTITY_0_FUNCTION_NEEDS_INITIALIZATION) || (!rt766->first_hw_init)) { + ret = sdca_regmap_write_init(dev, rt766->regmap, func_data); + if (ret) { + dev_err(dev, "%s initialization table update failed\n", func_data->desc->name); + goto _func_init_err_; + } + + regmap_write(rt766->regmap, func_status_reg, + SDCA_CTL_ENTITY_0_FUNCTION_NEEDS_INITIALIZATION); + } + + return 0; + +_func_init_err_: + dev_err(dev, "%s: %s init writes failed, err=%d", __func__, func_data->desc->name, ret); + return ret; +} + +int rt766_sdca_io_init(struct device *dev, struct sdw_slave *slave) +{ + struct rt766_sdca_priv *rt766 = dev_get_drvdata(dev); + unsigned int val; + + rt766->disable_irq = false; + + if (rt766->hw_init) + return 0; + + regcache_cache_only(rt766->regmap, false); + if (rt766->first_hw_init) { + regcache_cache_bypass(rt766->regmap, true); + } else { + /* + * PM runtime status is marked as 'active' only when a Slave reports as Attached + */ + + /* update count of parent 'active' children */ + pm_runtime_set_active(&slave->dev); + } + + pm_runtime_get_noresume(&slave->dev); + + regmap_read(rt766->regmap, RT766_BOND_LATCH_ID, &val); + dev_dbg(&slave->dev, "%s bond ID=0x%x (%s)\n", __func__, val, (val == 0x1) ? "RT767" : "RT766"); + + /* check function status and initialize if needed */ + if (rt766->uaj_func_data) + rt766_func_initialize(rt766, rt766->uaj_func_data); + if (rt766->sa_func_data) + rt766_func_initialize(rt766, rt766->sa_func_data); + if (rt766->sm_func_data) + rt766_func_initialize(rt766, rt766->sm_func_data); + if (rt766->hid_func_data) + rt766_func_initialize(rt766, rt766->hid_func_data); + + if (rt766->first_hw_init) { + regcache_cache_bypass(rt766->regmap, false); + regcache_mark_dirty(rt766->regmap); + } else { + rt766->first_hw_init = true; + } + + /* Mark Slave initialization complete */ + rt766->hw_init = true; + + dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); + + pm_runtime_put_autosuspend(&slave->dev); + + return 0; +} + +MODULE_DESCRIPTION("ASoC RT766 SDCA SDW driver"); +MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("SND_SOC_SDCA"); diff --git a/sound/soc/codecs/rt766-sdca.h b/sound/soc/codecs/rt766-sdca.h new file mode 100644 index 000000000000..de4064007eb9 --- /dev/null +++ b/sound/soc/codecs/rt766-sdca.h @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt766-sdca.h -- RT766 SDCA ALSA SoC audio driver header + * + * Copyright(c) 2026 Realtek Semiconductor Corp. + */ + +#ifndef __RT766_H__ +#define __RT766_H__ + +#include <linux/hid.h> +#include <linux/pm.h> +#include <linux/regmap.h> +#include <linux/soundwire/sdw.h> +#include <linux/soundwire/sdw_type.h> +#include <sound/soc.h> +#include <linux/workqueue.h> + +struct rt766_sdca_priv { + struct regmap *regmap; + struct snd_soc_component *component; + struct sdw_slave *slave; + bool hw_init; + bool first_hw_init; + struct snd_soc_jack *hs_jack; + struct mutex disable_irq_lock; /* SDCA irq lock protection */ + bool disable_irq; + int jack_type; + bool fu41_dapm_mute; + bool fu41_mixer_l_mute; + bool fu41_mixer_r_mute; + bool fu113_dapm_mute; + bool fu113_mixer_mute[4]; + bool fu21_dapm_mute; + bool fu21_mixer_l_mute; + bool fu21_mixer_r_mute; + bool fu36_dapm_mute; + bool fu36_mixer_l_mute; + bool fu36_mixer_r_mute; + struct sdca_function_data *uaj_func_data; + struct sdca_function_data *sm_func_data; + struct sdca_function_data *sa_func_data; + struct sdca_function_data *hid_func_data; + struct sdca_interrupt_info *irq_info; + struct hid_device *hid; +}; + +/* vendor registers */ +#define RT766_VERSION_ID 0xc404 +#define RT766_DEV_ID1 0xc405 +#define RT766_DEV_ID0 0xc406 +#define RT766_BOND_LATCH_ID 0xc407 + +#define RT766_HP_POWER_STATE 0x1000004 +#define RT766_HP_FSM_CTL2_1 0x100000d + +/* MCU Patch address */ +#define RT766_MCU_PATCH_ADDR1_START 0x10010000 +#define RT766_MCU_PATCH_ADDR1_END 0x10011fff +#define RT766_MCU_PATCH_ADDR2_START 0x10020000 +#define RT766_MCU_PATCH_ADDR2_END 0x10023fff + +/* Buffer address for HID */ +#define RT766_BUF_ADDR_HID1 0x44030000 +#define RT766_BUF_ADDR_HID2 0x44030020 + +/* SDCA (Channel) */ +#define RT766_CH_1 0x01 +#define RT766_CH_2 0x02 +#define RT766_CH_3 0x03 +#define RT766_CH_4 0x04 + +/* RT766 SDCA Control - function number */ +#define RT766_FUNC_NUM_UAJ 0x01 +#define RT766_FUNC_NUM_MIC 0x02 +#define RT766_FUNC_NUM_HID 0x03 +#define RT766_FUNC_NUM_AMP 0x04 + +/* RT766 SDCA entity */ +#define RT766_SDCA_ENT_0 0x00 +#define RT766_SDCA_ENT_HID101 0x01 +#define RT766_SDCA_ENT_GE49 0x49 +#define RT766_SDCA_ENT_USER_FU41 0x05 +#define RT766_SDCA_ENT_USER_FU36 0x0f +#define RT766_SDCA_ENT_USER_FU21 0x03 +#define RT766_SDCA_ENT_USER_FU113 0x30 +#define RT766_SDCA_ENT_PDE23 0x33 +#define RT766_SDCA_ENT_PDE47 0x28 +#define RT766_SDCA_ENT_PDE11 0x2a +#define RT766_SDCA_ENT_PDE34 0x29 +#define RT766_SDCA_ENT_CS41 0x01 +#define RT766_SDCA_ENT_CS36 0x11 +#define RT766_SDCA_ENT_CS113 0x12 +#define RT766_SDCA_ENT_CS21 0x21 +#define RT766_SDCA_ENT_PLATFORM_FU33 0x44 +#define RT766_SDCA_ENT_PPU21 0x04 + +/* sample frequency index */ +#define RT766_SDCA_RATE_44100HZ 0x08 +#define RT766_SDCA_RATE_48000HZ 0x09 +#define RT766_SDCA_RATE_96000HZ 0x0b +#define RT766_SDCA_RATE_192000HZ 0x0d + +/* SDCA Register macros */ +#define RT766_MUTE_REG(func, fu, ch) \ + SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##fu, SDCA_CTL_FU_MUTE, RT766_CH_##ch) + +#define RT766_VOLUME_REG(func, fu, ch) \ + SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##fu, SDCA_CTL_FU_CHANNEL_VOLUME, RT766_CH_##ch) + +#define RT766_GAIN_REG(func, fu, ch) \ + SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##fu, SDCA_CTL_FU_GAIN, RT766_CH_##ch) + +#define RT766_PDE_REQ_REG(func, pde) \ + SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##pde, SDCA_CTL_PDE_REQUESTED_PS, 0) + +#define RT766_PDE_ACTUAL_REG(func, pde) \ + SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##pde, SDCA_CTL_PDE_ACTUAL_PS, 0) + +#define RT766_FUNC_STATUS_REG(func) \ + SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_0, SDCA_CTL_ENTITY_0_FUNCTION_STATUS, 0) + +#define RT766_SDCA_CTL(func, ent, ctl) \ + SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##ent, ctl, 0) + +enum { + RT766_AIF1, + RT766_AIF2, + RT766_AIF3, +}; + +enum { + RT766_DAI_UAJ, + RT766_DAI_AMP, + RT766_DAI_MIC, +}; + +int rt766_sdca_io_init(struct device *dev, struct sdw_slave *slave); +int rt766_sdca_init(struct device *dev, struct regmap *regmap, struct sdw_slave *slave); +#endif /* __RT766_H__ */ diff --git a/sound/soc/codecs/rt9120.c b/sound/soc/codecs/rt9120.c index 97f56af25577..e51cd4a31894 100644 --- a/sound/soc/codecs/rt9120.c +++ b/sound/soc/codecs/rt9120.c @@ -606,12 +606,19 @@ static int rt9120_runtime_suspend(struct device *dev) static int rt9120_runtime_resume(struct device *dev) { struct rt9120_data *data = dev_get_drvdata(dev); + int ret; if (data->pwdnn_gpio) { gpiod_set_value(data->pwdnn_gpio, 1); msleep(RT9120_CHIPON_WAITMS); regcache_cache_only(data->regmap, false); - regcache_sync(data->regmap); + ret = regcache_sync(data->regmap); + if (ret) { + regcache_cache_only(data->regmap, true); + regcache_mark_dirty(data->regmap); + gpiod_set_value(data->pwdnn_gpio, 0); + return ret; + } } return 0; diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 59642673b4cb..35df1a8c4c8c 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -56,8 +56,8 @@ static const struct reg_default sgtl5000_reg_defaults[] = { { SGTL5000_CHIP_PLL_CTRL, 0x5000 }, { SGTL5000_CHIP_CLK_TOP_CTRL, 0x0000 }, { SGTL5000_CHIP_ANA_STATUS, 0x0000 }, - { SGTL5000_CHIP_SHORT_CTRL, 0x0000 }, { SGTL5000_CHIP_ANA_TEST2, 0x0000 }, + { SGTL5000_CHIP_SHORT_CTRL, 0x0000 }, { SGTL5000_DAP_CTRL, 0x0000 }, { SGTL5000_DAP_PEQ, 0x0000 }, { SGTL5000_DAP_BASS_ENHANCE, 0x0040 }, diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index 2e08fde3989c..4ecbbac93258 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c @@ -5,6 +5,7 @@ * Copyright 2009-2014 Analog Devices Inc. */ +#include <linux/cleanup.h> #include <linux/crc32.h> #include <linux/firmware.h> #include <linux/kernel.h> @@ -135,7 +136,7 @@ static int sigmadsp_ctrl_put(struct snd_kcontrol *kcontrol, uint8_t *data; int ret = 0; - mutex_lock(&sigmadsp->lock); + guard(mutex)(&sigmadsp->lock); data = ucontrol->value.bytes.data; @@ -148,8 +149,6 @@ static int sigmadsp_ctrl_put(struct snd_kcontrol *kcontrol, ctrl->cached = true; } - mutex_unlock(&sigmadsp->lock); - return ret; } @@ -160,7 +159,7 @@ static int sigmadsp_ctrl_get(struct snd_kcontrol *kcontrol, struct sigmadsp *sigmadsp = snd_kcontrol_chip(kcontrol); int ret = 0; - mutex_lock(&sigmadsp->lock); + guard(mutex)(&sigmadsp->lock); if (!ctrl->cached) { ret = sigmadsp_read(sigmadsp, ctrl->addr, ctrl->cache, @@ -174,8 +173,6 @@ static int sigmadsp_ctrl_get(struct snd_kcontrol *kcontrol, ctrl->num_bytes); } - mutex_unlock(&sigmadsp->lock); - return ret; } @@ -487,7 +484,7 @@ static void devm_sigmadsp_release(struct device *dev, void *res) static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name) { const struct sigma_firmware_header *ssfw_head; - const struct firmware *fw; + const struct firmware *fw __free(firmware) = NULL; int ret; u32 crc; @@ -495,7 +492,7 @@ static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name) ret = request_firmware(&fw, name, sigmadsp->dev); if (ret) { pr_debug("%s: request_firmware() failed with %i\n", __func__, ret); - goto done; + return ret; } /* then verify the header */ @@ -509,13 +506,13 @@ static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name) */ if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) { dev_err(sigmadsp->dev, "Failed to load firmware: Invalid size\n"); - goto done; + return -EINVAL; } ssfw_head = (void *)fw->data; if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) { dev_err(sigmadsp->dev, "Failed to load firmware: Invalid magic\n"); - goto done; + return -EINVAL; } crc = crc32(0, fw->data + sizeof(*ssfw_head), @@ -524,7 +521,7 @@ static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name) if (crc != le32_to_cpu(ssfw_head->crc)) { dev_err(sigmadsp->dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n", le32_to_cpu(ssfw_head->crc), crc); - goto done; + return -EINVAL; } switch (ssfw_head->version) { @@ -545,9 +542,6 @@ static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name) if (ret) sigmadsp_firmware_release(sigmadsp); -done: - release_firmware(fw); - return ret; } @@ -677,10 +671,10 @@ static void sigmadsp_activate_ctrl(struct sigmadsp *sigmadsp, return; changed = snd_ctl_activate_id(card, &ctrl->kcontrol->id, active); if (active && changed > 0) { - mutex_lock(&sigmadsp->lock); - if (ctrl->cached) - sigmadsp_ctrl_write(sigmadsp, ctrl, ctrl->cache); - mutex_unlock(&sigmadsp->lock); + scoped_guard(mutex, &sigmadsp->lock) { + if (ctrl->cached) + sigmadsp_ctrl_write(sigmadsp, ctrl, ctrl->cache); + } } } diff --git a/sound/soc/codecs/sma1303.c b/sound/soc/codecs/sma1303.c index 7fce60de5e5f..15758eb13f8c 100644 --- a/sound/soc/codecs/sma1303.c +++ b/sound/soc/codecs/sma1303.c @@ -1777,6 +1777,8 @@ static void sma1303_i2c_remove(struct i2c_client *client) struct sma1303_priv *sma1303 = (struct sma1303_priv *) i2c_get_clientdata(client); + if (sma1303->attr_grp) + sysfs_remove_group(sma1303->kobj, sma1303->attr_grp); cancel_delayed_work_sync(&sma1303->check_fault_work); } diff --git a/sound/soc/codecs/sma1307.c b/sound/soc/codecs/sma1307.c index c52fe95b30c6..adb369a29b9d 100644 --- a/sound/soc/codecs/sma1307.c +++ b/sound/soc/codecs/sma1307.c @@ -1690,7 +1690,7 @@ static void sma1307_check_fault_worker(struct work_struct *work) static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *file) { - const struct firmware *fw; + const struct firmware *fw __free(firmware) = NULL; int size, offset, num_mode; int ret; @@ -1703,22 +1703,18 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil return; } else if ((fw->size) < SMA1307_SETTING_HEADER_SIZE) { dev_err(sma1307->dev, "%s: Invalid file\n", __func__); - release_firmware(fw); sma1307->set.status = false; return; } int *data __free(kfree) = kzalloc(fw->size, GFP_KERNEL); if (!data) { - release_firmware(fw); sma1307->set.status = false; return; } size = fw->size >> 2; memcpy(data, fw->data, fw->size); - release_firmware(fw); - /* HEADER */ sma1307->set.header_size = SMA1307_SETTING_HEADER_SIZE; sma1307->set.checksum = data[sma1307->set.header_size - 2]; diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 652c6e3a9e63..d6de739212f9 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -17,6 +17,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/pm.h> @@ -269,9 +270,9 @@ static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol, int numcoef = kcontrol->private_value >> 16; int index = kcontrol->private_value & 0xffff; unsigned int cfud, val; - int i, ret = 0; + int i; - mutex_lock(&sta32x->coeff_lock); + guard(mutex)(&sta32x->coeff_lock); /* preserve reserved bits in STA32X_CFUD */ regmap_read(sta32x->regmap, STA32X_CFUD, &cfud); @@ -283,24 +284,20 @@ static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol, regmap_write(sta32x->regmap, STA32X_CFUD, cfud); regmap_write(sta32x->regmap, STA32X_CFADDR2, index); - if (numcoef == 1) { + if (numcoef == 1) regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x04); - } else if (numcoef == 5) { + else if (numcoef == 5) regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x08); - } else { - ret = -EINVAL; - goto exit_unlock; - } + else + return -EINVAL; + for (i = 0; i < 3 * numcoef; i++) { regmap_read(sta32x->regmap, STA32X_B1CF1 + i, &val); ucontrol->value.bytes.data[i] = val; } -exit_unlock: - mutex_unlock(&sta32x->coeff_lock); - - return ret; + return 0; } static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol, diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c index 99c7f7ac807b..2ba35076732b 100644 --- a/sound/soc/codecs/sta350.c +++ b/sound/soc/codecs/sta350.c @@ -16,6 +16,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__ +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> @@ -306,9 +307,9 @@ static int sta350_coefficient_get(struct snd_kcontrol *kcontrol, int numcoef = kcontrol->private_value >> 16; int index = kcontrol->private_value & 0xffff; unsigned int cfud, val; - int i, ret = 0; + int i; - mutex_lock(&sta350->coeff_lock); + guard(mutex)(&sta350->coeff_lock); /* preserve reserved bits in STA350_CFUD */ regmap_read(sta350->regmap, STA350_CFUD, &cfud); @@ -320,24 +321,19 @@ static int sta350_coefficient_get(struct snd_kcontrol *kcontrol, regmap_write(sta350->regmap, STA350_CFUD, cfud); regmap_write(sta350->regmap, STA350_CFADDR2, index); - if (numcoef == 1) { + if (numcoef == 1) regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x04); - } else if (numcoef == 5) { + else if (numcoef == 5) regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x08); - } else { - ret = -EINVAL; - goto exit_unlock; - } + else + return -EINVAL; for (i = 0; i < 3 * numcoef; i++) { regmap_read(sta350->regmap, STA350_B1CF1 + i, &val); ucontrol->value.bytes.data[i] = val; } -exit_unlock: - mutex_unlock(&sta350->coeff_lock); - - return ret; + return 0; } static int sta350_coefficient_put(struct snd_kcontrol *kcontrol, diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index 4ab15be69f3a..b7eaf4795d8b 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -44,8 +44,8 @@ enum { }; static const struct reg_default stih407_sas_reg_defaults[] = { - { STIH407_AUDIO_DAC_CTRL, 0x000000000 }, { STIH407_AUDIO_GLUE_CTRL, 0x00000040 }, + { STIH407_AUDIO_DAC_CTRL, 0x000000000 }, }; struct sti_dac_audio { diff --git a/sound/soc/codecs/tac5xx2-sdw.c b/sound/soc/codecs/tac5xx2-sdw.c index ace06f5ab58c..c062065a807d 100644 --- a/sound/soc/codecs/tac5xx2-sdw.c +++ b/sound/soc/codecs/tac5xx2-sdw.c @@ -88,6 +88,9 @@ #define TAC_FW_FILE_HDR 20 #define TAC_MAX_FW_CHUNKS 512 +#define TAC_UAJ_PREP_CONNECTED 0xff +#define TAC_UAJ_PREP_DISCONNECTED 0xdf + struct tac_fw_hdr { u32 size; u32 version_offset; @@ -138,6 +141,7 @@ struct tac5xx2_prv { bool hw_init; bool first_hw_init_done; u32 part_id; + u32 rev_id; struct snd_soc_jack *hs_jack; int jack_type; /* Custom fw binary. UMP File Download is not used. */ @@ -261,7 +265,6 @@ static const struct reg_default tac_reg_default[] = { {TAC_REG_SDW(0, 0, 0x78), 0x0}, {TAC_REG_SDW(0, 0, 0x7b), 0x0}, {TAC_REG_SDW(0, 0, 0x7c), 0xd0}, - {TAC_REG_SDW(0, 0, 0x7d), 0x0}, {TAC_REG_SDW(0, 0, 0x7e), 0x0}, {TAC_REG_SDW(0, 1, 0x1), 0x0}, {TAC_REG_SDW(0, 1, 0x2), 0x0}, @@ -507,18 +510,6 @@ static const struct regmap_config tac_regmap = { .use_single_write = true, }; -/* Check if device has DSP algo that needs status monitoring */ -static bool tac_has_dsp_algo(struct tac5xx2_prv *tac_dev) -{ - switch (tac_dev->part_id) { - case 0x5682: - case 0x2883: - return true; - default: - return false; - } -} - /* Check if device has UAJ (Universal Audio Jack) support */ static bool tac_has_uaj_support(struct tac5xx2_prv *tac_dev) { @@ -800,7 +791,7 @@ static int tac_sdw_hw_params(struct snd_pcm_substream *substream, return ret; } - ret = sdca_asoc_pde_poll_actual_ps(tac_dev->dev, tac_dev->regmap, function_id, pde_entity, + ret = sdca_asoc_pde_poll_actual_ps(tac_dev->regmap, function_id, pde_entity, SDCA_PDE_PS3, SDCA_PDE_PS0, NULL, 0); if (ret) dev_err(tac_dev->dev, "failed to transition func %d, pde %d from PS3 -> PS0, err=%d\n", @@ -847,7 +838,7 @@ static int tac_sdw_pcm_hw_free(struct snd_pcm_substream *substream, return ret; } - ret = sdca_asoc_pde_poll_actual_ps(tac_dev->dev, tac_dev->regmap, function_id, + ret = sdca_asoc_pde_poll_actual_ps(tac_dev->regmap, function_id, pde_entity, SDCA_PDE_PS0, SDCA_PDE_PS3, NULL, 0); if (ret) @@ -942,6 +933,7 @@ end_btn_det: static int tac5xx2_sdca_headset_detect(struct tac5xx2_prv *tac_dev) { int val, ret; + u8 jack_prep; ret = regmap_read(tac_dev->regmap, SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_GE35, @@ -951,6 +943,8 @@ static int tac5xx2_sdca_headset_detect(struct tac5xx2_prv *tac_dev) return ret; } + jack_prep = TAC_UAJ_PREP_CONNECTED; + switch (val) { case 4: tac_dev->jack_type = SND_JACK_MICROPHONE; @@ -964,6 +958,7 @@ static int tac5xx2_sdca_headset_detect(struct tac5xx2_prv *tac_dev) case 0: default: tac_dev->jack_type = 0; + jack_prep = TAC_UAJ_PREP_DISCONNECTED; break; } @@ -973,26 +968,44 @@ static int tac5xx2_sdca_headset_detect(struct tac5xx2_prv *tac_dev) if (ret) dev_err(tac_dev->dev, "Failed to update the jack type to device"); + /* + * When uaj is uplugged and booted, we end up with the channel prepare + * timeout error for the uaj ports. This writes allows the channel prepare + * to succeed when the uaj is not plugged in. + */ + if (tac_dev->rev_id >= 0x30) { + ret = regmap_write(tac_dev->regmap, TAC_REG_SDW(0, 3, 127), jack_prep); + if (ret) + dev_warn(tac_dev->dev, "Failed to write jack_prep register: %d\n", ret); + } + return 0; } static int tac5xx2_jack_init(struct tac5xx2_prv *tac_dev) { + u32 jd_int_mask, hid_int_mask; int ret = 0; + if (tac_dev->rev_id >= 0x30) { + jd_int_mask = SDW_SCP_SDCA_INTMASK_SDCA_12; + hid_int_mask = SDW_SCP_SDCA_INTMASK_SDCA_17; + } else { + jd_int_mask = SDW_SCP_SDCA_INTMASK_SDCA_11; + hid_int_mask = SDW_SCP_SDCA_INTMASK_SDCA_16; + } + if (!tac_dev->hs_jack) goto disable_interrupts; - ret = regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK2, - SDW_SCP_SDCA_INTMASK_SDCA_11); + ret = regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK2, jd_int_mask); if (ret) { dev_err(tac_dev->dev, "Failed to register jack detection interrupt: %d\n", ret); goto disable_interrupts; } - ret = regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK3, - SDW_SCP_SDCA_INTMASK_SDCA_16); + ret = regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK3, hid_int_mask); if (ret) { dev_err(tac_dev->dev, "Failed to register for button detect interrupt: %d\n", ret); @@ -1051,6 +1064,7 @@ static int tac_interrupt_callback(struct sdw_slave *slave, unsigned int sdca_int2, sdca_int3, jack_report_mask = 0; struct tac5xx2_prv *tac_dev = dev_get_drvdata(&slave->dev); struct device *dev = &slave->dev; + u32 headset_detect_chk, hid_detect_chk; int btn_type = 0; int ret = 0; @@ -1081,14 +1095,22 @@ static int tac_interrupt_callback(struct sdw_slave *slave, dev_dbg(dev, "SDCA_INT2: 0x%02x, SDCA_INT3: 0x%02x\n", sdca_int2, sdca_int3); - if (sdca_int2 & SDW_SCP_SDCA_INT_SDCA_11) { + if (tac_dev->rev_id >= 0x30) { + headset_detect_chk = SDW_SCP_SDCA_INT_SDCA_12; + hid_detect_chk = SDW_SCP_SDCA_INT_SDCA_17; + } else { + headset_detect_chk = SDW_SCP_SDCA_INT_SDCA_11; + hid_detect_chk = SDW_SCP_SDCA_INT_SDCA_16; + } + + if (sdca_int2 & headset_detect_chk) { ret = tac5xx2_sdca_headset_detect(tac_dev); if (ret < 0) goto clear; jack_report_mask |= SND_JACK_HEADSET; } - if (sdca_int3 & SDW_SCP_SDCA_INT_SDCA_16) { + if (sdca_int3 & hid_detect_chk) { btn_type = tac5xx2_sdca_button_detect(tac_dev); if (btn_type < 0) btn_type = 0; @@ -1695,6 +1717,15 @@ static int tac_io_init(struct device *dev, struct sdw_slave *slave, bool first) goto io_init_err; } + if (!tac_dev->rev_id) { + ret = regmap_read(tac_dev->regmap, TAC_REV_ID, &tac_dev->rev_id); + if (ret) { + dev_err(tac_dev->dev, "failed to rev id, err=%d\n", ret); + goto io_init_err; + } + dev_dbg(tac_dev->dev, "detected rev_id 0x%x", tac_dev->rev_id); + } + if (tac_dev->fw_files && tac_dev->fw_file_cnt > 0) { ret = tac_download_fw_to_hw(tac_dev); if (ret) { @@ -1940,7 +1971,7 @@ static s32 tac_sdw_probe(struct sdw_slave *peripheral, "failed to allocate %s function data", func_name); function_data->desc = &peripheral->sdca_data.function[i]; - ret = sdca_parse_function(dev, peripheral, function_data); + ret = sdca_parse_function(dev, function_data); if (!ret) *func_ptr = function_data; else @@ -1959,6 +1990,7 @@ static s32 tac_sdw_probe(struct sdw_slave *peripheral, tac_dev->hw_init = false; tac_dev->first_hw_init_done = false; tac_dev->part_id = id->part_id; + tac_dev->rev_id = 0x0; dev_set_drvdata(dev, tac_dev); regmap = devm_regmap_init_sdw_mbq_cfg(&peripheral->dev, peripheral, @@ -1972,17 +2004,13 @@ static s32 tac_sdw_probe(struct sdw_slave *peripheral, tac_dev->jack_type = 0; init_completion(&tac_dev->fw_caching_complete); - if (tac_has_dsp_algo(tac_dev)) { - tac_generate_fw_name(peripheral, tac_dev->fw_binaryname, - sizeof(tac_dev->fw_binaryname)); + tac_generate_fw_name(peripheral, tac_dev->fw_binaryname, + sizeof(tac_dev->fw_binaryname)); - ret = tac_load_and_cache_firmware_async(tac_dev); - if (ret) { - complete_all(&tac_dev->fw_caching_complete); - dev_dbg(dev, "failed to load fw: %d, use rom mode\n", ret); - } - } else { + ret = tac_load_and_cache_firmware_async(tac_dev); + if (ret) { complete_all(&tac_dev->fw_caching_complete); + dev_dbg(dev, "failed to load fw: %d, use rom mode\n", ret); } ret = tac_init(tac_dev); diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index 1a7650b9b2a7..be2c9a0fa529 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -31,25 +31,25 @@ static const struct reg_default tas2552_reg_defs[] = { {TAS2552_CFG_1, 0x22}, + {TAS2552_CFG_2, 0xef}, {TAS2552_CFG_3, 0x80}, {TAS2552_DOUT, 0x00}, - {TAS2552_OUTPUT_DATA, 0xc0}, - {TAS2552_PDM_CFG, 0x01}, - {TAS2552_PGA_GAIN, 0x00}, - {TAS2552_BOOST_APT_CTRL, 0x0f}, - {TAS2552_RESERVED_0D, 0xbe}, - {TAS2552_LIMIT_RATE_HYS, 0x08}, - {TAS2552_CFG_2, 0xef}, {TAS2552_SER_CTRL_1, 0x00}, {TAS2552_SER_CTRL_2, 0x00}, + {TAS2552_OUTPUT_DATA, 0xc0}, {TAS2552_PLL_CTRL_1, 0x10}, {TAS2552_PLL_CTRL_2, 0x00}, {TAS2552_PLL_CTRL_3, 0x00}, {TAS2552_BTIP, 0x8f}, {TAS2552_BTS_CTRL, 0x80}, + {TAS2552_RESERVED_0D, 0xbe}, + {TAS2552_LIMIT_RATE_HYS, 0x08}, {TAS2552_LIMIT_RELEASE, 0x04}, {TAS2552_LIMIT_INT_COUNT, 0x00}, + {TAS2552_PDM_CFG, 0x01}, + {TAS2552_PGA_GAIN, 0x00}, {TAS2552_EDGE_RATE_CTRL, 0x40}, + {TAS2552_BOOST_APT_CTRL, 0x0f}, {TAS2552_VBAT_DATA, 0x00}, }; @@ -495,13 +495,21 @@ static int tas2552_runtime_suspend(struct device *dev) static int tas2552_runtime_resume(struct device *dev) { struct tas2552_data *tas2552 = dev_get_drvdata(dev); + int ret; gpiod_set_value_cansleep(tas2552->enable_gpio, 1); tas2552_sw_shutdown(tas2552, 0); regcache_cache_only(tas2552->regmap, false); - regcache_sync(tas2552->regmap); + ret = regcache_sync(tas2552->regmap); + if (ret) { + regcache_cache_only(tas2552->regmap, true); + regcache_mark_dirty(tas2552->regmap); + tas2552_sw_shutdown(tas2552, 1); + gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + return ret; + } return 0; } diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c index b11b998aa32a..f9c65c9f6d0a 100644 --- a/sound/soc/codecs/tas2764.c +++ b/sound/soc/codecs/tas2764.c @@ -897,13 +897,13 @@ static const struct reg_default tas2764_reg_defaults[] = { { TAS2764_PAGE, 0x00 }, { TAS2764_SW_RST, 0x00 }, { TAS2764_PWR_CTRL, 0x1a }, - { TAS2764_DVC, 0x00 }, { TAS2764_CHNL_0, 0x28 }, { TAS2764_TDM_CFG0, 0x09 }, { TAS2764_TDM_CFG1, 0x02 }, { TAS2764_TDM_CFG2, 0x0a }, { TAS2764_TDM_CFG3, 0x10 }, { TAS2764_TDM_CFG5, 0x42 }, + { TAS2764_DVC, 0x00 }, { TAS2764_INT_CLK_CFG, 0x19 }, }; diff --git a/sound/soc/codecs/tas2780.c b/sound/soc/codecs/tas2780.c index 1ec1c076204f..f1fce4305fa1 100644 --- a/sound/soc/codecs/tas2780.c +++ b/sound/soc/codecs/tas2780.c @@ -527,13 +527,13 @@ static const struct reg_default tas2780_reg_defaults[] = { { TAS2780_PAGE, 0x00 }, { TAS2780_SW_RST, 0x00 }, { TAS2780_PWR_CTRL, 0x1a }, - { TAS2780_DVC, 0x00 }, { TAS2780_CHNL_0, 0x00 }, { TAS2780_TDM_CFG0, 0x09 }, { TAS2780_TDM_CFG1, 0x02 }, { TAS2780_TDM_CFG2, 0x0a }, { TAS2780_TDM_CFG3, 0x10 }, { TAS2780_TDM_CFG5, 0x42 }, + { TAS2780_DVC, 0x00 }, }; static const struct regmap_range_cfg tas2780_regmap_ranges[] = { diff --git a/sound/soc/codecs/tas2781-comlib-i2c.c b/sound/soc/codecs/tas2781-comlib-i2c.c index e24d56a14cfd..79b5f5b04c74 100644 --- a/sound/soc/codecs/tas2781-comlib-i2c.c +++ b/sound/soc/codecs/tas2781-comlib-i2c.c @@ -6,6 +6,7 @@ // // Author: Shenghao Ding <shenghao-ding@ti.com> +#include <linux/cleanup.h> #include <linux/crc8.h> #include <linux/firmware.h> #include <linux/gpio/consumer.h> @@ -342,7 +343,7 @@ int tascodec_init(struct tasdevice_priv *tas_priv, void *codec, /* Codec Lock Hold to ensure that codec_probe and firmware parsing and * loading do not simultaneously execute. */ - mutex_lock(&tas_priv->codec_lock); + guard(mutex)(&tas_priv->codec_lock); if (tas_priv->name_prefix) scnprintf(tas_priv->rca_binaryname, 64, "%s-%sRCA%d.bin", @@ -360,8 +361,6 @@ int tascodec_init(struct tasdevice_priv *tas_priv, void *codec, dev_err(tas_priv->dev, "request_firmware_nowait err:0x%08x\n", ret); - /* Codec Lock Release*/ - mutex_unlock(&tas_priv->codec_lock); return ret; } EXPORT_SYMBOL_GPL(tascodec_init); diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c index dcbeb9618195..2b9efccf1a0b 100644 --- a/sound/soc/codecs/tas2781-fmwlib.c +++ b/sound/soc/codecs/tas2781-fmwlib.c @@ -1849,16 +1849,26 @@ static int tasdev_load_blk(struct tasdevice_priv *tas_priv, } } if (ret == -EAGAIN) { - if (block->nr_retry > 0) + if (block->nr_retry > 0) { + /* Give the hardware time to stabilize before + * next block re-transmission attempt. + */ + usleep_range(2000, 2500); continue; + } } else if (ret < 0) /*err in current device, skip it*/ break; if (block->is_pchksum_present) { ret = tasdev_block_chksum(tas_priv, block, chn); if (ret == -EAGAIN) { - if (block->nr_retry > 0) + if (block->nr_retry > 0) { + /* Give the bus time to recover after + * a checksum mismatch error. + */ + usleep_range(2000, 2500); continue; + } } else if (ret < 0) /*err in current device, skip it*/ break; } @@ -2243,7 +2253,7 @@ int tas2781_load_calibration(void *context, char *file_name, { struct tasdevice_priv *tas_priv = (struct tasdevice_priv *)context; struct tasdevice *tasdev = &(tas_priv->tasdevice[i]); - const struct firmware *fw_entry = NULL; + const struct firmware *fw_entry __free(firmware) = NULL; struct tasdevice_fw *tas_fmw; struct firmware fmw; int offset = 0; @@ -2253,60 +2263,50 @@ int tas2781_load_calibration(void *context, char *file_name, if (ret) { dev_err(tas_priv->dev, "%s: Request firmware %s failed\n", __func__, file_name); - goto out; + return ret; } if (!fw_entry->size) { dev_err(tas_priv->dev, "%s: file read error: size = %lu\n", __func__, (unsigned long)fw_entry->size); - ret = -EINVAL; - goto out; + return -EINVAL; } fmw.size = fw_entry->size; fmw.data = fw_entry->data; tas_fmw = tasdev->cali_data_fmw = kzalloc_obj(struct tasdevice_fw); - if (!tasdev->cali_data_fmw) { - ret = -ENOMEM; - goto out; - } + if (!tasdev->cali_data_fmw) + return -ENOMEM; + tas_fmw->dev = tas_priv->dev; offset = fw_parse_header(tas_priv, tas_fmw, &fmw, offset); if (offset == -EINVAL) { dev_err(tas_priv->dev, "fw_parse_header EXIT!\n"); - ret = offset; - goto out; + return -EINVAL; } offset = fw_parse_variable_hdr_cal(tas_priv, tas_fmw, &fmw, offset); if (offset == -EINVAL) { dev_err(tas_priv->dev, "%s: fw_parse_variable_header_cal EXIT!\n", __func__); - ret = offset; - goto out; + return -EINVAL; } offset = fw_parse_program_data(tas_priv, tas_fmw, &fmw, offset); if (offset < 0) { dev_err(tas_priv->dev, "fw_parse_program_data EXIT!\n"); - ret = offset; - goto out; + return offset; } offset = fw_parse_configuration_data(tas_priv, tas_fmw, &fmw, offset); if (offset < 0) { dev_err(tas_priv->dev, "fw_parse_configuration_data EXIT!\n"); - ret = offset; - goto out; + return offset; } offset = fw_parse_calibration_data(tas_priv, tas_fmw, &fmw, offset); if (offset < 0) { dev_err(tas_priv->dev, "fw_parse_calibration_data EXIT!\n"); - ret = offset; - goto out; + return offset; } -out: - release_firmware(fw_entry); - - return ret; + return 0; } EXPORT_SYMBOL_NS_GPL(tas2781_load_calibration, "SND_SOC_TAS2781_FMWLIB"); @@ -2399,7 +2399,7 @@ static int tasdevice_dspfw_ready(const struct firmware *fmw, int tasdevice_dsp_parser(void *context) { struct tasdevice_priv *tas_priv = (struct tasdevice_priv *)context; - const struct firmware *fw_entry; + const struct firmware *fw_entry __free(firmware) = NULL; int ret; ret = request_firmware(&fw_entry, tas_priv->coef_binaryname, @@ -2407,15 +2407,10 @@ int tasdevice_dsp_parser(void *context) if (ret) { dev_err(tas_priv->dev, "%s: load %s error\n", __func__, tas_priv->coef_binaryname); - goto out; + return ret; } - ret = tasdevice_dspfw_ready(fw_entry, tas_priv); - release_firmware(fw_entry); - fw_entry = NULL; - -out: - return ret; + return tasdevice_dspfw_ready(fw_entry, tas_priv); } EXPORT_SYMBOL_NS_GPL(tasdevice_dsp_parser, "SND_SOC_TAS2781_FMWLIB"); @@ -2797,11 +2792,12 @@ out: } EXPORT_SYMBOL_NS_GPL(tasdevice_prmg_load, "SND_SOC_TAS2781_FMWLIB"); -void tasdevice_tuning_switch(void *context, int state) +void tasdevice_tuning_switch(void *context, int state, bool is_cap) { struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context; struct tasdevice_fw *tas_fmw = tas_priv->fmw; - int profile_cfg_id = tas_priv->rcabin.profile_cfg_id; + int profile_cfg_id = is_cap ? tas_priv->rcabin.capture_profile_id : + tas_priv->rcabin.profile_cfg_id; /* * Only RCA-based Playback can still work with no dsp program running @@ -2818,7 +2814,6 @@ void tasdevice_tuning_switch(void *context, int state) if (state == 0) { if (tas_fmw && tas_priv->cur_prog < tas_fmw->nr_programs) { /* dsp mode or tuning mode */ - profile_cfg_id = tas_priv->rcabin.profile_cfg_id; tasdevice_select_tuningprm_cfg(tas_priv, tas_priv->cur_prog, tas_priv->cur_conf, profile_cfg_id); diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index 95d875c44b91..6f349f88f194 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -13,6 +13,7 @@ // Author: Kevin Lu <kevin-lu@ti.com> // +#include <linux/cleanup.h> #include <linux/crc8.h> #include <linux/firmware.h> #include <linux/gpio/consumer.h> @@ -617,6 +618,7 @@ static int tasdev_calib_stop_put(struct snd_kcontrol *kcontrol, { struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); struct tasdevice_priv *priv = snd_soc_component_get_drvdata(comp); + int i; guard(mutex)(&priv->codec_lock); if (priv->chip_id == TAS2563) @@ -624,6 +626,14 @@ static int tasdev_calib_stop_put(struct snd_kcontrol *kcontrol, else tas2781_calib_stop_put(priv); + /* + * Set reloading-firmware flag after calibration, the flag will work + * during next playback, then set to the program id after reloading + * firmware. + */ + for (i = 0; i < priv->ndev; i++) + priv->tasdevice[i].cur_prog = -1; + return 1; } @@ -843,12 +853,12 @@ static int tasdevice_digital_gain_get( unsigned char data[4]; int ret; - mutex_lock(&tas_dev->codec_lock); + guard(mutex)(&tas_dev->codec_lock); /* Read the primary device */ ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4); if (ret) { dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__); - goto out; + return ret; } target = get_unaligned_be32(&data[0]); @@ -868,8 +878,7 @@ static int tasdevice_digital_gain_get( /* find out the member same as or closer to the current volume */ ucontrol->value.integer.value[0] = abs(target - ar_l) <= abs(target - ar_r) ? l : r; -out: - mutex_unlock(&tas_dev->codec_lock); + return 0; } @@ -882,29 +891,26 @@ static int tasdevice_digital_gain_put( struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol); struct tasdevice_priv *tas_dev = snd_soc_component_get_drvdata(codec); int vol = ucontrol->value.integer.value[0]; - int status = 0, max = mc->max, rc = 1; + int status = 0, max = mc->max; int i, ret; unsigned int reg = mc->reg; unsigned int volrd, volwr; unsigned char data[4]; vol = clamp(vol, 0, max); - mutex_lock(&tas_dev->codec_lock); + guard(mutex)(&tas_dev->codec_lock); /* Read the primary device */ ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4); if (ret) { dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__); - rc = -1; - goto out; + return -1; } volrd = get_unaligned_be32(&data[0]); volwr = get_unaligned_be32(tas_dev->dvc_tlv_table[vol]); - if (volrd == volwr) { - rc = 0; - goto out; - } + if (volrd == volwr) + return 0; for (i = 0; i < tas_dev->ndev; i++) { ret = tasdevice_dev_bulk_write(tas_dev, i, reg, @@ -918,10 +924,9 @@ static int tasdevice_digital_gain_put( } if (status) - rc = -1; -out: - mutex_unlock(&tas_dev->codec_lock); - return rc; + return -1; + + return 1; } static const struct snd_kcontrol_new tasdevice_cali_controls[] = { @@ -995,6 +1000,57 @@ static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol, return ret; } +/** + * tasdevice_set_capture_profile_id - Set runtime capture profile index via + * ALSA control + * @kcontrol: ALSA kcontrol handle that triggers this operation + * @ucontrol: User space control value carrying the new profile index + * + * This mixer control handler validates the user-provided capture profile ID + * against the maximum valid index parsed from the loaded DSP firmware, + * then updates the runtime stored capture profile ID only if the new value + * differs from the current active one. It will immediately return -EINVAL + * if the submitted profile ID falls outside the valid range, including the + * edge case that no valid configuration blocks are detected in firmware. + * + * No actual DSP register write is performed in this handler. The updated + * profile ID will be applied to the hardware when the next ALSA capture + * stream starts up. Caller does not need to take extra codec lock here, + * as the ALSA control core already guarantees serialized execution. + * + * Return: 1 if profile ID value was changed, 0 if no modification needed, + * -EINVAL if the input profile ID is out of valid range + */ +static int tasdevice_set_capture_profile_id(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol); + struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); + unsigned int user_prof_id = ucontrol->value.integer.value[0]; + unsigned int max_valid_id; + int ret = 0; + + /* + * Align valid range with the bound defined in + * tasdevice_info_profile() + */ + max_valid_id = tas_priv->rcabin.ncfgs - 1; + + /* + * Reject invalid input including zero total configuration edge + * case + */ + if (tas_priv->rcabin.ncfgs == 0 || user_prof_id > max_valid_id) + return -EINVAL; + + if (tas_priv->rcabin.capture_profile_id != user_prof_id) { + tas_priv->rcabin.capture_profile_id = user_prof_id; + ret = 1; + } + + return ret; +} + static int tasdevice_info_active_num(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -1075,6 +1131,41 @@ static int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol, return 0; } +/** + * tasdevice_get_capture_profile_id - Report current active capture profile + * ID to user space + * @kcontrol: ALSA kcontrol structure passed from ALSA core + * @ucontrol: User-space control element value buffer to write the result back + * + * This function ensures the returned profile ID is always clamped inside the + * valid range advertised by the info callback, preventing accidental invalid + * values from being exposed to applications even if internal driver state is + * temporarily inconsistent. + * + * Returns 0 on successful fill of the control value, no error conditions + * are defined for this getter callback. + */ +static int tasdevice_get_capture_profile_id(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol); + struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); + unsigned int max_valid_id, current_prof_id; + + max_valid_id = tas_priv->rcabin.ncfgs > 0 ? + (tas_priv->rcabin.ncfgs - 1U) : 0; + + /* + * Cast current profile id to unsigned to match type with max_valid_id, + * avoid signedness mismatch; + */ + current_prof_id = (unsigned int)tas_priv->rcabin.capture_profile_id; + /* Prevent underflow when there are no loaded capture profiles. */ + ucontrol->value.integer.value[0] = min(current_prof_id, max_valid_id); + + return 0; +} + static int tasdevice_get_chip_id(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1117,6 +1208,41 @@ static int tasdevice_create_control(struct tasdevice_priv *tas_priv) ret = snd_soc_add_component_controls(tas_priv->codec, prof_ctrls, nr_controls < mix_index ? nr_controls : mix_index); + mix_index = 0; + switch (tas_priv->chip_id) { + case TAS2563: + case TAS2568: + case TAS2570: + case TAS2572: + case TAS2573: + case TAS2574: + case TAS2781: + prof_ctrls = devm_kcalloc(tas_priv->dev, nr_controls, + sizeof(prof_ctrls[0]), GFP_KERNEL); + if (!prof_ctrls) { + ret = -ENOMEM; + goto out; + } + + /* Create a mixer item for selecting the capture profile */ + name = devm_kstrdup(tas_priv->dev, "Speaker Capture Profile Id", + GFP_KERNEL); + if (!name) { + ret = -ENOMEM; + goto out; + } + prof_ctrls[mix_index].name = name; + prof_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + prof_ctrls[mix_index].info = tasdevice_info_profile; + prof_ctrls[mix_index].get = tasdevice_get_capture_profile_id; + prof_ctrls[mix_index].put = tasdevice_set_capture_profile_id; + mix_index++; + + ret = snd_soc_add_component_controls(tas_priv->codec, + prof_ctrls, nr_controls < mix_index ? nr_controls : mix_index); + break; + } + out: return ret; } @@ -1330,6 +1456,43 @@ static void alpa_cali_update(struct bulk_reg_val *p, p->val_len = 4; } +static int create_tas2781_cali_start_ktrl(struct tasdevice_priv + *priv, struct snd_kcontrol_new *cali_ctrl) +{ + struct soc_bytes_ext *ext_cali_start; + char *cali_start_name; + + ext_cali_start = devm_kzalloc(priv->dev, + sizeof(*ext_cali_start), GFP_KERNEL); + if (!ext_cali_start) + return -ENOMEM; + + cali_start_name = devm_kstrdup(priv->dev, + "Calibration Start", GFP_KERNEL); + if (!cali_start_name) + return -ENOMEM; + /* + * package structure for tas2781 ftc start: + * Pkg len (1 byte) + * Reg id (1 byte, constant 'r') + * book, page, register for pilot threshold, pilot tone + * and sine gain (12 bytes) + * for (i = 0; i < Device-Sum; i++) { + * Device #i index_info (1 byte) + * Sine gain for Device #i (8 bytes) + * } + */ + ext_cali_start->max = 14 + priv->ndev * 9; + cali_ctrl->name = cali_start_name; + cali_ctrl->iface = SNDRV_CTL_ELEM_IFACE_MIXER; + cali_ctrl->info = snd_soc_bytes_info_ext; + cali_ctrl->put = tas2781_calib_start_put; + cali_ctrl->get = tasdev_nop_get; + cali_ctrl->private_value = (unsigned long)ext_cali_start; + + return 0; +} + static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv) { struct calidata *cali_data = &priv->cali_data; @@ -1448,37 +1611,11 @@ static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv) */ cali_data->data[0] = 0xff; if (priv->chip_id == TAS2781) { - struct soc_bytes_ext *ext_cali_start; - char *cali_start_name; - - ext_cali_start = devm_kzalloc(priv->dev, - sizeof(*ext_cali_start), GFP_KERNEL); - if (!ext_cali_start) - return -ENOMEM; - - cali_start_name = devm_kstrdup(priv->dev, - "Calibration Start", GFP_KERNEL); - if (!cali_start_name) - return -ENOMEM; - /* - * package structure for tas2781 ftc start: - * Pkg len (1 byte) - * Reg id (1 byte, constant 'r') - * book, page, register for pilot threshold, pilot tone - * and sine gain (12 bytes) - * for (i = 0; i < Device-Sum; i++) { - * Device #i index_info (1 byte) - * Sine gain for Device #i (8 bytes) - * } - */ - ext_cali_start->max = 14 + priv->ndev * 9; - cali_ctrls[i].name = cali_start_name; - cali_ctrls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; - cali_ctrls[i].info = snd_soc_bytes_info_ext; - cali_ctrls[i].put = tas2781_calib_start_put; - cali_ctrls[i].get = tasdev_nop_get; - cali_ctrls[i].private_value = (unsigned long)ext_cali_start; + rc = create_tas2781_cali_start_ktrl(priv, &cali_ctrls[i]); + if (rc != 0) + return rc; i++; + } return snd_soc_add_component_controls(priv->codec, cali_ctrls, @@ -1765,13 +1902,25 @@ static int tasdevice_dapm_event(struct snd_soc_dapm_widget *w, struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); int state = 0; - /* Codec Lock Hold */ - mutex_lock(&tas_priv->codec_lock); + guard(mutex)(&tas_priv->codec_lock); if (event == SND_SOC_DAPM_PRE_PMD) state = 1; - tasdevice_tuning_switch(tas_priv, state); - /* Codec Lock Release*/ - mutex_unlock(&tas_priv->codec_lock); + tasdevice_tuning_switch(tas_priv, state, false); + + return 0; +} + +static int tasdevice_capture_dapm_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm); + struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); + int state = 0; + + guard(mutex)(&tas_priv->codec_lock); + if (event == SND_SOC_DAPM_PRE_PMD) + state = 1; + tasdevice_tuning_switch(tas_priv, state, true); return 0; } @@ -1779,7 +1928,7 @@ static int tasdevice_dapm_event(struct snd_soc_dapm_widget *w, static const struct snd_soc_dapm_widget tasdevice_dapm_widgets[] = { SND_SOC_DAPM_AIF_IN("ASI", "ASI Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT_E("ASI OUT", "ASI Capture", 0, SND_SOC_NOPM, - 0, 0, tasdevice_dapm_event, + 0, 0, tasdevice_capture_dapm_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_SPK("SPK", tasdevice_dapm_event), SND_SOC_DAPM_OUTPUT("OUT"), diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c index 3d0b116544cc..caf8fe1bf4db 100644 --- a/sound/soc/codecs/tas2783-sdw.c +++ b/sound/soc/codecs/tas2783-sdw.c @@ -12,6 +12,7 @@ // Author: Baojun Xu <baojun.xu@ti.com> // Author: Kevin Lu <kevin-lu@ti.com> +#include <linux/cleanup.h> #include <linux/unaligned.h> #include <linux/crc32.h> #include <linux/efi.h> @@ -106,7 +107,6 @@ struct tas2783_prv { static const struct reg_default tas2783_reg_default[] = { {TAS2783_AMP_LEVEL, 0x28}, - {TASDEV_REG_SDW(0, 0, 0x03), 0x28}, {TASDEV_REG_SDW(0, 0, 0x04), 0x21}, {TASDEV_REG_SDW(0, 0, 0x05), 0x41}, {TASDEV_REG_SDW(0, 0, 0x06), 0x00}, @@ -142,6 +142,7 @@ static const struct reg_default tas2783_reg_default[] = { {TASDEV_REG_SDW(0, 0, 0x41), 0x14}, {TASDEV_REG_SDW(0, 0, 0x5c), 0x19}, {TASDEV_REG_SDW(0, 0, 0x5d), 0x80}, + {TASDEV_REG_SDW(0, 0, 0x60), 0x21}, {TASDEV_REG_SDW(0, 0, 0x63), 0x48}, {TASDEV_REG_SDW(0, 0, 0x65), 0x08}, {TASDEV_REG_SDW(0, 0, 0x66), 0xb2}, @@ -157,7 +158,6 @@ static const struct reg_default tas2783_reg_default[] = { {TASDEV_REG_SDW(0, 0, 0x73), 0x08}, {TASDEV_REG_SDW(0, 0, 0x75), 0xe0}, {TASDEV_REG_SDW(0, 0, 0x7a), 0x60}, - {TASDEV_REG_SDW(0, 0, 0x60), 0x21}, {TASDEV_REG_SDW(0, 1, 0x02), 0x00}, {TASDEV_REG_SDW(0, 1, 0x17), 0xc0}, {TASDEV_REG_SDW(0, 1, 0x19), 0x60}, @@ -176,63 +176,44 @@ static const struct reg_default tas2783_reg_default[] = { {TASDEV_REG_SDW(0, 0xfd, 0x39), 0x00}, {TASDEV_REG_SDW(0, 0xfd, 0x3e), 0x00}, {TASDEV_REG_SDW(0, 0xfd, 0x45), 0x00}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x02, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x10, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x02, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x10, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x02, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x10, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x02, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x10, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x02, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x10, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU21, 0x01, 1), 0x1}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU21, 0x02, 1), 0x9c00}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x01, 0), 0x1}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x01, 1), 0x1}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x0b, 1), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x10, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x01, 1), 0x1}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x01, 0), 0x1}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x01, 1), 0x1}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x0b, 1), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x10, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 0), 0x1}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 1), 0x1}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 2), 0x1}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 1), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 2), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x10, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x01, 0), 0x1}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x06, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x07, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x08, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x09, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x0a, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x02, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x02, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x02, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x02, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x1, 0), 0x3}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x05, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x06, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x06, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x04, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x08, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x10, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x11, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x04, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x08, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x04, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x08, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x10, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x11, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x04, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x08, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x10, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x11, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x04, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x08, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x10, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x11, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x01, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x04, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x05, 0), 0x1}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x08, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x10, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x11, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x12, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x01, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x04, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x05, 0), 0x1}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x08, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x10, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x11, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x12, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x04, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x08, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x04, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x08, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x04, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x08, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x04, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x08, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 1), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 2), 0x0}, @@ -242,19 +223,60 @@ static const struct reg_default tas2783_reg_default[] = { {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 6), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 7), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x06, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x04, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x08, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x04, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x08, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x04, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x08, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 0), 0x1}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 1), 0x1}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 2), 0x1}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 1), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 2), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x02, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x01, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x04, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x05, 0), 0x1}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x08, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x01, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x04, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x05, 0), 0x1}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x08, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x10, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x10, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x10, 0), 0x1}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x12, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x13, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x14, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x15, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x16, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x10, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x10, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x10, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x10, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x10, 0), 0x3}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_UDMPU23, 0x10, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x10, 0), 0x1}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x11, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x12, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x10, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x11, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x12, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x13, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x10, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x11, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x12, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x13, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_TG23, 0x10, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x10, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x11, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x10, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x11, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x10, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x11, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x10, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x11, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x11, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x04, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x08, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x11, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x04, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x08, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x11, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x04, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x08, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x11, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 1), 0x0}, @@ -264,6 +286,14 @@ static const struct reg_default tas2783_reg_default[] = { {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 5), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 6), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 7), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x10, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x10, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x10, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x11, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x12, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x10, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x11, 0), 0x0}, + {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x12, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 8), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 9), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xa), 0x0}, @@ -272,36 +302,6 @@ static const struct reg_default tas2783_reg_default[] = { {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xd), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xe), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xf), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x1, 0), 0x3}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x10, 0), 0x3}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x06, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x10, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x11, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x12, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x13, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x06, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x10, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x11, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x12, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x13, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x05, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x10, 0), 0x1}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x11, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x12, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_TG23, 0x10, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x01, 0), 0x1}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x06, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x07, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x08, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x09, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x0a, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x10, 0), 0x1}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x12, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x13, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x14, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x15, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x16, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_UDMPU23, 0x10, 0), 0x0}, }; static const struct reg_sequence tas2783_init_seq[] = { @@ -495,6 +495,56 @@ static bool tas2783_readable_register(struct device *dev, unsigned int reg) return tas2783_sdca_mbq_size(dev, reg) > 0; } +static bool tas2783_writeable_register(struct device *dev, unsigned int reg) +{ + /* + * The Latency Control of every Entity, together with the Power Domain + * actual state and the protection status, is read-only. They are + * listed in tas2783_reg_default[] with a placeholder value, so without + * this a regcache_sync() would try to write them back and the + * peripheral would reject the transaction, aborting the sync. + */ + switch (reg) { + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_FU21, 0x10, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_FU23, 0x10, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_FU26, 0x10, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_XU22, 0x06, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_XU22, 0x07, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_XU22, 0x08, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS24, 0x02, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS21, 0x02, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS25, 0x02, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS26, 0x02, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS28, 0x02, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_PDE23, 0x10, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_UDMPU23, 0x06, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_SAPU29, 0x05, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_SAPU29, 0x11, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_PPU21, 0x06, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_PPU26, 0x06, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_IT21, 0x08, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_IT29, 0x08, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_IT26, 0x08, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_IT28, 0x08, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT24, 0x08, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT23, 0x08, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT25, 0x08, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT28, 0x08, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MU26, 0x06, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT127, 0x08, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_FU127, 0x10, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS127, 0x02, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU21, 0x08, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU21, 0x04, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU26, 0x08, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU26, 0x04, 0): + return false; + + default: + return tas2783_sdca_mbq_size(dev, reg) > 0; + } +} + static bool tas2783_volatile_register(struct device *dev, u32 reg) { switch (reg) { @@ -516,6 +566,7 @@ static const struct regmap_config tas_regmap = { .reg_bits = 32, .val_bits = 8, .readable_reg = tas2783_readable_register, + .writeable_reg = tas2783_writeable_register, .volatile_reg = tas2783_volatile_register, .reg_defaults = tas2783_reg_default, .num_reg_defaults = ARRAY_SIZE(tas2783_reg_default), @@ -693,12 +744,12 @@ static s32 tas2783_update_calibdata(struct tas2783_prv *tas_dev) return 0; } - mutex_lock(&tas_dev->calib_lock); - ret = tas2783_validate_calibdata(tas_dev, tas_dev->cali_data.data, - tas_dev->cali_data.read_sz); - if (!ret) - tas2783_set_calib_params_to_device(tas_dev, tmp_val); - mutex_unlock(&tas_dev->calib_lock); + scoped_guard(mutex, &tas_dev->calib_lock) { + ret = tas2783_validate_calibdata(tas_dev, tas_dev->cali_data.data, + tas_dev->cali_data.read_sz); + if (!ret) + tas2783_set_calib_params_to_device(tas_dev, tmp_val); + } return ret; } @@ -927,22 +978,23 @@ static s32 tas_sdw_hw_params(struct snd_pcm_substream *substream, dev_err(tas_dev->dev, "clear latch failed, err=%d", ret); - mutex_lock(&tas_dev->pde_lock); - /* - * Sometimes, there is error returned during power on. - * So added retry logic to ensure power on so that - * port prepare succeeds - */ - do { - ret = regmap_write(tas_dev->regmap, - SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, - TAS2783_SDCA_CTL_REQ_POW_STATE, 0), - TAS2783_SDCA_POW_STATE_ON); - if (!ret) - break; - usleep_range(2000, 2200); - } while (retry--); - mutex_unlock(&tas_dev->pde_lock); + scoped_guard(mutex, &tas_dev->pde_lock) { + /* + * Sometimes, there is error returned during power on. + * So added retry logic to ensure power on so that + * port prepare succeeds + */ + do { + ret = regmap_write(tas_dev->regmap, + SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, + TAS2783_SDCA_CTL_REQ_POW_STATE, 0), + TAS2783_SDCA_POW_STATE_ON); + if (!ret) + break; + usleep_range(2000, 2200); + } while (retry--); + } + if (ret) return ret; @@ -966,7 +1018,6 @@ static s32 tas_sdw_hw_params(struct snd_pcm_substream *substream, static s32 tas_sdw_pcm_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - s32 ret; struct snd_soc_component *component = dai->component; struct tas2783_prv *tas_dev = snd_soc_component_get_drvdata(component); @@ -975,14 +1026,11 @@ static s32 tas_sdw_pcm_hw_free(struct snd_pcm_substream *substream, sdw_stream_remove_slave(tas_dev->sdw_peripheral, sdw_stream); - mutex_lock(&tas_dev->pde_lock); - ret = regmap_write(tas_dev->regmap, - SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, - TAS2783_SDCA_CTL_REQ_POW_STATE, 0), - TAS2783_SDCA_POW_STATE_OFF); - mutex_unlock(&tas_dev->pde_lock); - - return ret; + guard(mutex)(&tas_dev->pde_lock); + return regmap_write(tas_dev->regmap, + SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, + TAS2783_SDCA_CTL_REQ_POW_STATE, 0), + TAS2783_SDCA_POW_STATE_OFF); } static const struct snd_soc_dai_ops tas_dai_ops = { @@ -1099,7 +1147,13 @@ static s32 tas2783_sdca_dev_resume(struct device *dev) } regcache_cache_only(tas_dev->regmap, false); - regcache_sync(tas_dev->regmap); + ret = regcache_sync(tas_dev->regmap); + if (ret) { + regcache_cache_only(tas_dev->regmap, true); + regcache_mark_dirty(tas_dev->regmap); + return ret; + } + return 0; } @@ -1225,9 +1279,23 @@ static s32 tas_update_status(struct sdw_slave *slave, if (tas_dev->hw_init || tas_dev->status != SDW_SLAVE_ATTACHED) return 0; - /* updated the cache data to device */ regcache_cache_only(tas_dev->regmap, false); - regcache_sync(tas_dev->regmap); + + /* + * The device is attaching uninitialized: either this is the first + * attach, or it lost power (and with it all register and DSP state) + * while the controller was power-gated during system suspend. The + * cache still holds the pre-suspend values, and tas_io_init() below + * resets the device via TAS2783_SW_RESET anyway, so syncing it back + * is both useless and harmful: later read-modify-write updates would + * compare against stale data and skip the hardware write. + * + * Drop the cache instead, so that subsequent accesses see the real + * hardware state. Syncing after the reset is not an option either: + * the cache accepts registers for which tas2783_sdca_mbq_size() + * returns 0, and writing those back fails with -EINVAL. + */ + regcache_drop_region(tas_dev->regmap, 0, UINT_MAX); /* perform I/O transfers required for Slave initialization */ return tas_io_init(&slave->dev, slave); @@ -1330,7 +1398,7 @@ static s32 tas_sdw_probe(struct sdw_slave *peripheral, function_data->desc = &peripheral->sdca_data.function[i]; /* Parse the function */ - ret = sdca_parse_function(dev, peripheral, function_data); + ret = sdca_parse_function(dev, function_data); if (!ret) tas_dev->sa_func_data = function_data; else diff --git a/sound/soc/codecs/tas5805m.c b/sound/soc/codecs/tas5805m.c index bcc8cab8d667..d32796a6fa75 100644 --- a/sound/soc/codecs/tas5805m.c +++ b/sound/soc/codecs/tas5805m.c @@ -12,6 +12,7 @@ // // It has been simplified a little and reworked for the 5.x ALSA SoC API. +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> @@ -230,10 +231,9 @@ static int tas5805m_vol_get(struct snd_kcontrol *kcontrol, struct tas5805m_priv *tas5805m = snd_soc_component_get_drvdata(component); - mutex_lock(&tas5805m->lock); + guard(mutex)(&tas5805m->lock); ucontrol->value.integer.value[0] = tas5805m->vol[0]; ucontrol->value.integer.value[1] = tas5805m->vol[1]; - mutex_unlock(&tas5805m->lock); return 0; } @@ -249,13 +249,12 @@ static int tas5805m_vol_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct tas5805m_priv *tas5805m = snd_soc_component_get_drvdata(component); - int ret = 0; if (!(volume_is_valid(ucontrol->value.integer.value[0]) && volume_is_valid(ucontrol->value.integer.value[1]))) return -EINVAL; - mutex_lock(&tas5805m->lock); + guard(mutex)(&tas5805m->lock); if (tas5805m->vol[0] != ucontrol->value.integer.value[0] || tas5805m->vol[1] != ucontrol->value.integer.value[1]) { tas5805m->vol[0] = ucontrol->value.integer.value[0]; @@ -265,11 +264,10 @@ static int tas5805m_vol_put(struct snd_kcontrol *kcontrol, tas5805m->is_powered); if (tas5805m->is_powered) tas5805m_refresh(tas5805m); - ret = 1; + return 1; } - mutex_unlock(&tas5805m->lock); - return ret; + return 0; } static const struct snd_kcontrol_new tas5805m_snd_controls[] = { @@ -332,7 +330,7 @@ static void do_work(struct work_struct *work) dev_dbg(&tas5805m->i2c->dev, "DSP startup\n"); - mutex_lock(&tas5805m->lock); + guard(mutex)(&tas5805m->lock); /* We mustn't issue any I2C transactions until the I2S * clock is stable. Furthermore, we must allow a 5ms * delay after the first set of register writes to @@ -345,7 +343,6 @@ static void do_work(struct work_struct *work) tas5805m->is_powered = true; tas5805m_refresh(tas5805m); - mutex_unlock(&tas5805m->lock); } static int tas5805m_dac_event(struct snd_soc_dapm_widget *w, @@ -362,7 +359,7 @@ static int tas5805m_dac_event(struct snd_soc_dapm_widget *w, dev_dbg(component->dev, "DSP shutdown\n"); cancel_work_sync(&tas5805m->work); - mutex_lock(&tas5805m->lock); + guard(mutex)(&tas5805m->lock); if (tas5805m->is_powered) { tas5805m->is_powered = false; @@ -379,7 +376,6 @@ static int tas5805m_dac_event(struct snd_soc_dapm_widget *w, regmap_write(rm, REG_DEVICE_CTRL_2, DCTRL2_MODE_HIZ); } - mutex_unlock(&tas5805m->lock); } return 0; @@ -414,14 +410,13 @@ static int tas5805m_mute(struct snd_soc_dai *dai, int mute, int direction) struct tas5805m_priv *tas5805m = snd_soc_component_get_drvdata(component); - mutex_lock(&tas5805m->lock); + guard(mutex)(&tas5805m->lock); dev_dbg(component->dev, "set mute=%d (is_powered=%d)\n", mute, tas5805m->is_powered); tas5805m->is_muted = mute; if (tas5805m->is_powered) tas5805m_refresh(tas5805m); - mutex_unlock(&tas5805m->lock); return 0; } @@ -462,7 +457,6 @@ static int tas5805m_i2c_probe(struct i2c_client *i2c) struct tas5805m_priv *tas5805m; char filename[128]; const char *config_name; - const struct firmware *fw; int ret; regmap = devm_regmap_init_i2c(i2c, &tas5805m_regmap); @@ -507,24 +501,20 @@ static int tas5805m_i2c_probe(struct i2c_client *i2c) snprintf(filename, sizeof(filename), "tas5805m_dsp_%s.bin", config_name); + const struct firmware *fw __free(firmware) = NULL; ret = request_firmware(&fw, filename, dev); if (ret) return ret; if ((fw->size < 2) || (fw->size & 1)) { dev_err(dev, "firmware is invalid\n"); - release_firmware(fw); return -EINVAL; } tas5805m->dsp_cfg_len = fw->size; tas5805m->dsp_cfg_data = devm_kmemdup(dev, fw->data, fw->size, GFP_KERNEL); - if (!tas5805m->dsp_cfg_data) { - release_firmware(fw); + if (!tas5805m->dsp_cfg_data) return -ENOMEM; - } - - release_firmware(fw); /* Do the first part of the power-on here, while we can expect * the I2S interface to be quiet. We must raise PDN# and then diff --git a/sound/soc/codecs/tas675x.c b/sound/soc/codecs/tas675x.c index 82526362de7b..404706b62156 100644 --- a/sound/soc/codecs/tas675x.c +++ b/sound/soc/codecs/tas675x.c @@ -1924,15 +1924,6 @@ static const struct reg_default tas675x_reg_defaults[] = { { TAS675X_PWM_PHASE_M_CTRL_CH2_REG, 0x00 }, { TAS675X_PWM_PHASE_M_CTRL_CH3_REG, 0x00 }, { TAS675X_PWM_PHASE_M_CTRL_CH4_REG, 0x00 }, - { TAS675X_DC_LDG_CTRL_REG, 0x00 }, - { TAS675X_DC_LDG_LO_CTRL_REG, 0x00 }, - { TAS675X_DC_LDG_TIME_CTRL_REG, 0x00 }, - { TAS675X_DC_LDG_SL_CH1_CH2_CTRL_REG, 0x11 }, - { TAS675X_DC_LDG_SL_CH3_CH4_CTRL_REG, 0x11 }, - { TAS675X_AC_LDG_CTRL_REG, 0x10 }, - { TAS675X_TWEETER_DETECT_CTRL_REG, 0x08 }, - { TAS675X_TWEETER_DETECT_THRESH_REG, 0x00 }, - { TAS675X_AC_LDG_FREQ_CTRL_REG, 0xC8 }, { TAS675X_REPORT_ROUTING_1_REG, 0x00 }, { TAS675X_OTSD_RECOVERY_EN_REG, 0x00 }, { TAS675X_REPORT_ROUTING_2_REG, 0xA2 }, @@ -1943,6 +1934,15 @@ static const struct reg_default tas675x_reg_defaults[] = { { TAS675X_GPIO1_OUTPUT_SEL_REG, 0x00 }, { TAS675X_GPIO2_OUTPUT_SEL_REG, 0x00 }, { TAS675X_GPIO_CTRL_REG, TAS675X_GPIO_CTRL_RSTVAL }, + { TAS675X_DC_LDG_CTRL_REG, 0x00 }, + { TAS675X_DC_LDG_LO_CTRL_REG, 0x00 }, + { TAS675X_DC_LDG_TIME_CTRL_REG, 0x00 }, + { TAS675X_DC_LDG_SL_CH1_CH2_CTRL_REG, 0x11 }, + { TAS675X_DC_LDG_SL_CH3_CH4_CTRL_REG, 0x11 }, + { TAS675X_AC_LDG_CTRL_REG, 0x10 }, + { TAS675X_TWEETER_DETECT_CTRL_REG, 0x08 }, + { TAS675X_TWEETER_DETECT_THRESH_REG, 0x00 }, + { TAS675X_AC_LDG_FREQ_CTRL_REG, 0xC8 }, { TAS675X_OTW_CTRL_CH1_CH2_REG, 0x11 }, { TAS675X_OTW_CTRL_CH3_CH4_REG, 0x11 }, }; diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index e5dfb3d752a3..84e954311c1b 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -320,8 +320,14 @@ static int aic26_probe(struct snd_soc_component *component) return 0; } +static void aic26_remove(struct snd_soc_component *component) +{ + device_remove_file(component->dev, &dev_attr_keyclick); +} + static const struct snd_soc_component_driver aic26_soc_component_dev = { .probe = aic26_probe, + .remove = aic26_remove, .controls = aic26_snd_controls, .num_controls = ARRAY_SIZE(aic26_snd_controls), .dapm_widgets = tlv320aic26_dapm_widgets, diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 1d2e0ea6d4fe..43bcbc5449e1 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1720,18 +1720,14 @@ static int tlv320dac3100_fw_load(struct aic31xx_priv *aic31xx, static int tlv320dac3100_load_coeffs(struct aic31xx_priv *aic31xx, const char *fw_name) { - const struct firmware *fw; + const struct firmware *fw __free(firmware) = NULL; int ret; ret = request_firmware(&fw, fw_name, aic31xx->dev); if (ret) return ret; - ret = tlv320dac3100_fw_load(aic31xx, fw->data, fw->size); - - release_firmware(fw); - - return ret; + return tlv320dac3100_fw_load(aic31xx, fw->data, fw->size); } static int aic31xx_i2c_probe(struct i2c_client *i2c) diff --git a/sound/soc/codecs/tlv320aic32x4-clk.c b/sound/soc/codecs/tlv320aic32x4-clk.c index 5c0a76a4a106..deed61650e09 100644 --- a/sound/soc/codecs/tlv320aic32x4-clk.c +++ b/sound/soc/codecs/tlv320aic32x4-clk.c @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: GPL-2.0 - * +// SPDX-License-Identifier: GPL-2.0 +/* * Clock Tree for the Texas Instruments TLV320AIC32x4 * * Copyright 2019 Annaliese McDermond @@ -9,6 +9,7 @@ #include <linux/clk-provider.h> #include <linux/clkdev.h> +#include <linux/delay.h> #include <linux/regmap.h> #include <linux/device.h> @@ -57,7 +58,7 @@ static void clk_aic32x4_pll_unprepare(struct clk_hw *hw) struct clk_aic32x4 *pll = to_clk_aic32x4(hw); regmap_update_bits(pll->regmap, AIC32X4_PLLPR, - AIC32X4_PLLEN, 0); + AIC32X4_PLLEN, 0); } static int clk_aic32x4_pll_is_prepared(struct clk_hw *hw) @@ -75,7 +76,7 @@ static int clk_aic32x4_pll_is_prepared(struct clk_hw *hw) } static int clk_aic32x4_pll_get_muldiv(struct clk_aic32x4 *pll, - struct clk_aic32x4_pll_muldiv *settings) + struct clk_aic32x4_pll_muldiv *settings) { /* Change to use regmap_bulk_read? */ unsigned int val; @@ -106,19 +107,19 @@ static int clk_aic32x4_pll_get_muldiv(struct clk_aic32x4 *pll, } static int clk_aic32x4_pll_set_muldiv(struct clk_aic32x4 *pll, - struct clk_aic32x4_pll_muldiv *settings) + struct clk_aic32x4_pll_muldiv *settings) { int ret; /* Change to use regmap_bulk_write for some if not all? */ ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR, - AIC32X4_PLL_R_MASK, settings->r); + AIC32X4_PLL_R_MASK, settings->r); if (ret < 0) return ret; ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR, - AIC32X4_PLL_P_MASK, - settings->p << AIC32X4_PLL_P_SHIFT); + AIC32X4_PLL_P_MASK, + settings->p << AIC32X4_PLL_P_SHIFT); if (ret < 0) return ret; @@ -136,23 +137,21 @@ static int clk_aic32x4_pll_set_muldiv(struct clk_aic32x4 *pll, return 0; } -static unsigned long clk_aic32x4_pll_calc_rate( - struct clk_aic32x4_pll_muldiv *settings, - unsigned long parent_rate) +static unsigned long clk_aic32x4_pll_calc_rate(struct clk_aic32x4_pll_muldiv *settings, + unsigned long parent_rate) { u64 rate; /* * We scale j by 10000 to account for the decimal part of P and divide * it back out later. */ - rate = (u64) parent_rate * settings->r * - ((settings->j * 10000) + settings->d); + rate = (u64)parent_rate * settings->r * ((settings->j * 10000) + settings->d); - return (unsigned long) DIV_ROUND_UP_ULL(rate, settings->p * 10000); + return (unsigned long)DIV_ROUND_UP_ULL(rate, settings->p * 10000); } static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings, - unsigned long rate, unsigned long parent_rate) + unsigned long rate, unsigned long parent_rate) { u64 multiplier; @@ -165,14 +164,14 @@ static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings, * of the multiplier. This is because we can't do floating point * math in the kernel. */ - multiplier = (u64) rate * settings->p * 10000; + multiplier = (u64)rate * settings->p * 10000; do_div(multiplier, parent_rate); /* * J can't be over 64, so R can scale this. * R can't be greater than 4. */ - settings->r = ((u32) multiplier / 640000) + 1; + settings->r = ((u32)multiplier / 640000) + 1; if (settings->r > 4) return -1; do_div(multiplier, settings->r); @@ -184,14 +183,14 @@ static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings, return -1; /* Figure out the integer part, J, and the fractional part, D. */ - settings->j = (u32) multiplier / 10000; - settings->d = (u32) multiplier % 10000; + settings->j = (u32)multiplier / 10000; + settings->d = (u32)multiplier % 10000; return 0; } static unsigned long clk_aic32x4_pll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) + unsigned long parent_rate) { struct clk_aic32x4 *pll = to_clk_aic32x4(hw); struct clk_aic32x4_pll_muldiv settings; @@ -220,8 +219,8 @@ static int clk_aic32x4_pll_determine_rate(struct clk_hw *hw, } static int clk_aic32x4_pll_set_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long parent_rate) + unsigned long rate, + unsigned long parent_rate) { struct clk_aic32x4 *pll = to_clk_aic32x4(hw); struct clk_aic32x4_pll_muldiv settings; @@ -236,7 +235,7 @@ static int clk_aic32x4_pll_set_rate(struct clk_hw *hw, return ret; /* 10ms is the delay to wait before the clocks are stable */ - msleep(10); + usleep_range(10000, 20000); return 0; } @@ -261,7 +260,6 @@ static u8 clk_aic32x4_pll_get_parent(struct clk_hw *hw) return (val & AIC32X4_PLL_CLKIN_MASK) >> AIC32X4_PLL_CLKIN_SHIFT; } - static const struct clk_ops aic32x4_pll_ops = { .prepare = clk_aic32x4_pll_prepare, .unprepare = clk_aic32x4_pll_unprepare, @@ -311,11 +309,11 @@ static void clk_aic32x4_div_unprepare(struct clk_hw *hw) struct clk_aic32x4 *div = to_clk_aic32x4(hw); regmap_update_bits(div->regmap, div->reg, - AIC32X4_DIVEN, 0); + AIC32X4_DIVEN, 0); } static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) + unsigned long parent_rate) { struct clk_aic32x4 *div = to_clk_aic32x4(hw); u8 divisor; @@ -342,7 +340,7 @@ static int clk_aic32x4_div_determine_rate(struct clk_hw *hw, } static unsigned long clk_aic32x4_div_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) + unsigned long parent_rate) { struct clk_aic32x4 *div = to_clk_aic32x4(hw); unsigned int val; @@ -399,7 +397,7 @@ static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = { { .name = "pll", .parent_names = - (const char* []) { "mclk", "bclk", "gpio", "din" }, + (const char *[]) { "mclk", "bclk", "gpio", "din" }, .num_parents = 4, .ops = &aic32x4_pll_ops, .reg = 0, @@ -414,28 +412,28 @@ static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = { }, { .name = "ndac", - .parent_names = (const char * []) { "codec_clkin" }, + .parent_names = (const char *[]) { "codec_clkin" }, .num_parents = 1, .ops = &aic32x4_div_ops, .reg = AIC32X4_NDAC, }, { .name = "mdac", - .parent_names = (const char * []) { "ndac" }, + .parent_names = (const char *[]) { "ndac" }, .num_parents = 1, .ops = &aic32x4_div_ops, .reg = AIC32X4_MDAC, }, { .name = "nadc", - .parent_names = (const char * []) { "codec_clkin" }, + .parent_names = (const char *[]) { "codec_clkin" }, .num_parents = 1, .ops = &aic32x4_div_ops, .reg = AIC32X4_NADC, }, { .name = "madc", - .parent_names = (const char * []) { "nadc" }, + .parent_names = (const char *[]) { "nadc" }, .num_parents = 1, .ops = &aic32x4_div_ops, .reg = AIC32X4_MADC, @@ -451,7 +449,7 @@ static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = { }; static struct clk *aic32x4_register_clk(struct device *dev, - struct aic32x4_clkdesc *desc) + struct aic32x4_clkdesc *desc) { struct clk_init_data init; struct clk_aic32x4 *priv; @@ -464,8 +462,8 @@ static struct clk *aic32x4_register_clk(struct device *dev, init.flags = 0; priv = devm_kzalloc(dev, sizeof(struct clk_aic32x4), GFP_KERNEL); - if (priv == NULL) - return (struct clk *) -ENOMEM; + if (!priv) + return ERR_PTR(-ENOMEM); priv->dev = dev; priv->hw.init = &init; diff --git a/sound/soc/codecs/tlv320aic32x4-i2c.c b/sound/soc/codecs/tlv320aic32x4-i2c.c index 449353d5f088..cbbb8ff3ee38 100644 --- a/sound/soc/codecs/tlv320aic32x4-i2c.c +++ b/sound/soc/codecs/tlv320aic32x4-i2c.c @@ -1,11 +1,10 @@ -/* SPDX-License-Identifier: GPL-2.0 - * +// SPDX-License-Identifier: GPL-2.0 +/* * Copyright 2011-2019 NW Digital Radio * * Author: Annaliese McDermond <nh6z@nh6z.net> * * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27. - * */ #include <linux/i2c.h> @@ -16,17 +15,23 @@ #include "tlv320aic32x4.h" +static const struct regmap_config aic32x4_i2c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = AIC32X4_REFPOWERUP, + .ranges = aic32x4_regmap_pages, + .num_ranges = 1, +}; + static int aic32x4_i2c_probe(struct i2c_client *i2c) { struct regmap *regmap; - struct regmap_config config; enum aic32x4_type type; - config = aic32x4_regmap_config; - config.reg_bits = 8; - config.val_bits = 8; + regmap = devm_regmap_init_i2c(i2c, &aic32x4_i2c_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); - regmap = devm_regmap_init_i2c(i2c, &config); type = (uintptr_t)i2c_get_match_data(i2c); return aic32x4_probe(&i2c->dev, regmap, type); diff --git a/sound/soc/codecs/tlv320aic32x4-spi.c b/sound/soc/codecs/tlv320aic32x4-spi.c index 92246243ff94..cb615b2e4f02 100644 --- a/sound/soc/codecs/tlv320aic32x4-spi.c +++ b/sound/soc/codecs/tlv320aic32x4-spi.c @@ -1,11 +1,10 @@ -/* SPDX-License-Identifier: GPL-2.0 - * +// SPDX-License-Identifier: GPL-2.0 +/* * Copyright 2011-2019 NW Digital Radio * * Author: Annaliese McDermond <nh6z@nh6z.net> * * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27. - * */ #include <linux/spi/spi.h> @@ -16,19 +15,25 @@ #include "tlv320aic32x4.h" +static const struct regmap_config aic32x4_spi_regmap_config = { + .reg_bits = 7, + .pad_bits = 1, + .val_bits = 8, + .read_flag_mask = 0x01, + .max_register = AIC32X4_REFPOWERUP, + .ranges = aic32x4_regmap_pages, + .num_ranges = 1, +}; + static int aic32x4_spi_probe(struct spi_device *spi) { struct regmap *regmap; - struct regmap_config config; enum aic32x4_type type; - config = aic32x4_regmap_config; - config.reg_bits = 7; - config.pad_bits = 1; - config.val_bits = 8; - config.read_flag_mask = 0x01; + regmap = devm_regmap_init_spi(spi, &aic32x4_spi_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); - regmap = devm_regmap_init_spi(spi, &config); type = (uintptr_t)spi_get_device_match_data(spi); return aic32x4_probe(&spi->dev, regmap, type); diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index d85094557215..9e0e4aa2b09c 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -1,7 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * linux/sound/soc/codecs/tlv320aic32x4.c - * * Copyright 2011 Vista Silicon S.L. * * Author: Javier Martin <javier.martin@vista-silicon.com> @@ -28,7 +26,6 @@ #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/tlv.h> -#include <sound/tlv320aic32x4.h> #include "tlv320aic32x4.h" @@ -45,7 +42,8 @@ struct aic32x4_priv { struct regulator *supply_dv; struct regulator *supply_av; - struct aic32x4_setup_data *setup; + unsigned int gpio_func[5]; + struct device *dev; enum aic32x4_type type; @@ -75,7 +73,7 @@ static int aic32x4_reset_adc(struct snd_soc_dapm_widget *w, }; static int mic_bias_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) + struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); @@ -83,25 +81,23 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMU: /* Change Mic Bias Registor */ snd_soc_component_update_bits(component, AIC32X4_MICBIAS, - AIC32x4_MICBIAS_MASK, - AIC32X4_MICBIAS_LDOIN | - AIC32X4_MICBIAS_2075V); - printk(KERN_DEBUG "%s: Mic Bias will be turned ON\n", __func__); + AIC32x4_MICBIAS_MASK, + AIC32X4_MICBIAS_LDOIN | + AIC32X4_MICBIAS_2075V); + dev_dbg(component->dev, "Mic Bias will be turned ON\n"); break; case SND_SOC_DAPM_PRE_PMD: snd_soc_component_update_bits(component, AIC32X4_MICBIAS, - AIC32x4_MICBIAS_MASK, 0); - printk(KERN_DEBUG "%s: Mic Bias will be turned OFF\n", - __func__); + AIC32x4_MICBIAS_MASK, 0); + dev_dbg(component->dev, "Mic Bias will be turned OFF\n"); break; } return 0; } - static int aic32x4_get_mfp1_gpio(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); u8 val; @@ -114,7 +110,7 @@ static int aic32x4_get_mfp1_gpio(struct snd_kcontrol *kcontrol, }; static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); u8 val; @@ -123,8 +119,7 @@ static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol, val = snd_soc_component_read(component, AIC32X4_DOUTCTL); gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED); if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) { - printk(KERN_ERR "%s: MFP2 is not configure as a GPIO output\n", - __func__); + dev_err(component->dev, "MFP2 is not configure as a GPIO output\n"); return -EINVAL; } @@ -142,7 +137,7 @@ static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol, }; static int aic32x4_get_mfp3_gpio(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); u8 val; @@ -155,7 +150,7 @@ static int aic32x4_get_mfp3_gpio(struct snd_kcontrol *kcontrol, }; static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); u8 val; @@ -164,8 +159,7 @@ static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol, val = snd_soc_component_read(component, AIC32X4_MISOCTL); gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED); if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) { - printk(KERN_ERR "%s: MFP4 is not configure as a GPIO output\n", - __func__); + dev_err(component->dev, "MFP4 is not configure as a GPIO output\n"); return -EINVAL; } @@ -183,7 +177,7 @@ static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol, }; static int aic32x4_get_mfp5_gpio(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); u8 val; @@ -195,7 +189,7 @@ static int aic32x4_get_mfp5_gpio(struct snd_kcontrol *kcontrol, }; static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); u8 val; @@ -204,8 +198,7 @@ static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol, val = snd_soc_component_read(component, AIC32X4_GPIOCTL); gpio_check = (val & AIC32X4_MFP5_GPIO_OUTPUT); if (gpio_check != AIC32X4_MFP5_GPIO_OUTPUT) { - printk(KERN_ERR "%s: MFP5 is not configure as a GPIO output\n", - __func__); + dev_err(component->dev, "MFP5 is not configure as a GPIO output\n"); return -EINVAL; } @@ -222,25 +215,31 @@ static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol, return 0; }; -static const struct snd_kcontrol_new aic32x4_mfp1[] = { - SOC_SINGLE_BOOL_EXT("MFP1 GPIO", 0, aic32x4_get_mfp1_gpio, NULL), -}; - -static const struct snd_kcontrol_new aic32x4_mfp2[] = { - SOC_SINGLE_BOOL_EXT("MFP2 GPIO", 0, NULL, aic32x4_set_mfp2_gpio), -}; - -static const struct snd_kcontrol_new aic32x4_mfp3[] = { - SOC_SINGLE_BOOL_EXT("MFP3 GPIO", 0, aic32x4_get_mfp3_gpio, NULL), -}; - -static const struct snd_kcontrol_new aic32x4_mfp4[] = { - SOC_SINGLE_BOOL_EXT("MFP4 GPIO", 0, NULL, aic32x4_set_mfp4_gpio), -}; - -static const struct snd_kcontrol_new aic32x4_mfp5[] = { - SOC_SINGLE_BOOL_EXT("MFP5 GPIO", 0, aic32x4_get_mfp5_gpio, - aic32x4_set_mfp5_gpio), +static const struct { + unsigned int reg; + struct snd_kcontrol_new ctrl; +} aic32x4_mfp_cfg[] = { + { + .reg = AIC32X4_DINCTL, + .ctrl = SOC_SINGLE_BOOL_EXT("MFP1 GPIO", 0, aic32x4_get_mfp1_gpio, NULL), + }, + { + .reg = AIC32X4_DOUTCTL, + .ctrl = SOC_SINGLE_BOOL_EXT("MFP2 GPIO", 0, NULL, aic32x4_set_mfp2_gpio), + }, + { + .reg = AIC32X4_SCLKCTL, + .ctrl = SOC_SINGLE_BOOL_EXT("MFP3 GPIO", 0, aic32x4_get_mfp3_gpio, NULL), + }, + { + .reg = AIC32X4_MISOCTL, + .ctrl = SOC_SINGLE_BOOL_EXT("MFP4 GPIO", 0, NULL, aic32x4_set_mfp4_gpio), + }, + { + .reg = AIC32X4_GPIOCTL, + .ctrl = SOC_SINGLE_BOOL_EXT("MFP5 GPIO", 0, aic32x4_get_mfp5_gpio, + aic32x4_set_mfp5_gpio), + }, }; /* 0dB min, 0.5dB steps */ @@ -270,53 +269,42 @@ static SOC_ENUM_SINGLE_DECL(r_ptm_enum, AIC32X4_RPLAYBACK, 2, ptm_text); static const struct snd_kcontrol_new aic32x4_snd_controls[] = { SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL, - AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm), + AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm), SOC_ENUM("DAC Left Playback PowerTune Switch", l_ptm_enum), SOC_ENUM("DAC Right Playback PowerTune Switch", r_ptm_enum), SOC_DOUBLE_R_S_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN, - AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0, - tlv_driver_gain), + AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0, tlv_driver_gain), SOC_DOUBLE_R_S_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN, - AIC32X4_LORGAIN, 0, -0x6, 0x1d, 5, 0, - tlv_driver_gain), + AIC32X4_LORGAIN, 0, -0x6, 0x1d, 5, 0, tlv_driver_gain), SOC_DOUBLE_R("HP DAC Playback Switch", AIC32X4_HPLGAIN, - AIC32X4_HPRGAIN, 6, 0x01, 1), + AIC32X4_HPRGAIN, 6, 0x01, 1), SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN, - AIC32X4_LORGAIN, 6, 0x01, 1), + AIC32X4_LORGAIN, 6, 0x01, 1), SOC_ENUM("LO Playback Common Mode Switch", lo_cm_enum), SOC_DOUBLE_R("Mic PGA Switch", AIC32X4_LMICPGAVOL, - AIC32X4_RMICPGAVOL, 7, 0x01, 1), + AIC32X4_RMICPGAVOL, 7, 0x01, 1), SOC_SINGLE("ADCFGA Left Mute Switch", AIC32X4_ADCFGA, 7, 1, 0), SOC_SINGLE("ADCFGA Right Mute Switch", AIC32X4_ADCFGA, 3, 1, 0), SOC_DOUBLE_R_S_TLV("ADC Level Volume", AIC32X4_LADCVOL, - AIC32X4_RADCVOL, 0, -0x18, 0x28, 6, 0, tlv_adc_vol), + AIC32X4_RADCVOL, 0, -0x18, 0x28, 6, 0, tlv_adc_vol), SOC_DOUBLE_R_TLV("PGA Level Volume", AIC32X4_LMICPGAVOL, - AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5), + AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5), SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0), SOC_SINGLE("AGC Left Switch", AIC32X4_LAGC1, 7, 1, 0), SOC_SINGLE("AGC Right Switch", AIC32X4_RAGC1, 7, 1, 0), - SOC_DOUBLE_R("AGC Target Level", AIC32X4_LAGC1, AIC32X4_RAGC1, - 4, 0x07, 0), - SOC_DOUBLE_R("AGC Gain Hysteresis", AIC32X4_LAGC1, AIC32X4_RAGC1, - 0, 0x03, 0), - SOC_DOUBLE_R("AGC Hysteresis", AIC32X4_LAGC2, AIC32X4_RAGC2, - 6, 0x03, 0), - SOC_DOUBLE_R("AGC Noise Threshold", AIC32X4_LAGC2, AIC32X4_RAGC2, - 1, 0x1F, 0), - SOC_DOUBLE_R("AGC Max PGA", AIC32X4_LAGC3, AIC32X4_RAGC3, - 0, 0x7F, 0), - SOC_DOUBLE_R("AGC Attack Time", AIC32X4_LAGC4, AIC32X4_RAGC4, - 3, 0x1F, 0), - SOC_DOUBLE_R("AGC Decay Time", AIC32X4_LAGC5, AIC32X4_RAGC5, - 3, 0x1F, 0), - SOC_DOUBLE_R("AGC Noise Debounce", AIC32X4_LAGC6, AIC32X4_RAGC6, - 0, 0x1F, 0), - SOC_DOUBLE_R("AGC Signal Debounce", AIC32X4_LAGC7, AIC32X4_RAGC7, - 0, 0x0F, 0), + SOC_DOUBLE_R("AGC Target Level", AIC32X4_LAGC1, AIC32X4_RAGC1, 4, 0x07, 0), + SOC_DOUBLE_R("AGC Gain Hysteresis", AIC32X4_LAGC1, AIC32X4_RAGC1, 0, 0x03, 0), + SOC_DOUBLE_R("AGC Hysteresis", AIC32X4_LAGC2, AIC32X4_RAGC2, 6, 0x03, 0), + SOC_DOUBLE_R("AGC Noise Threshold", AIC32X4_LAGC2, AIC32X4_RAGC2, 1, 0x1F, 0), + SOC_DOUBLE_R("AGC Max PGA", AIC32X4_LAGC3, AIC32X4_RAGC3, 0, 0x7F, 0), + SOC_DOUBLE_R("AGC Attack Time", AIC32X4_LAGC4, AIC32X4_RAGC4, 3, 0x1F, 0), + SOC_DOUBLE_R("AGC Decay Time", AIC32X4_LAGC5, AIC32X4_RAGC5, 3, 0x1F, 0), + SOC_DOUBLE_R("AGC Noise Debounce", AIC32X4_LAGC6, AIC32X4_RAGC6, 0, 0x1F, 0), + SOC_DOUBLE_R("AGC Signal Debounce", AIC32X4_LAGC7, AIC32X4_RAGC7, 0, 0x0F, 0), }; static const struct snd_kcontrol_new hpl_output_mixer_controls[] = { @@ -354,21 +342,27 @@ static SOC_ENUM_SINGLE_DECL(in3r_lpga_n_enum, AIC32X4_LMICPGANIN, 2, resistor_te static const struct snd_kcontrol_new in1l_to_lmixer_controls[] = { SOC_DAPM_ENUM("IN1_L L+ Switch", in1l_lpga_p_enum), }; + static const struct snd_kcontrol_new in2l_to_lmixer_controls[] = { SOC_DAPM_ENUM("IN2_L L+ Switch", in2l_lpga_p_enum), }; + static const struct snd_kcontrol_new in3l_to_lmixer_controls[] = { SOC_DAPM_ENUM("IN3_L L+ Switch", in3l_lpga_p_enum), }; + static const struct snd_kcontrol_new in1r_to_lmixer_controls[] = { SOC_DAPM_ENUM("IN1_R L+ Switch", in1r_lpga_p_enum), }; + static const struct snd_kcontrol_new cml_to_lmixer_controls[] = { SOC_DAPM_ENUM("CM_L L- Switch", cml_lpga_n_enum), }; + static const struct snd_kcontrol_new in2r_to_lmixer_controls[] = { SOC_DAPM_ENUM("IN2_R L- Switch", in2r_lpga_n_enum), }; + static const struct snd_kcontrol_new in3r_to_lmixer_controls[] = { SOC_DAPM_ENUM("IN3_R L- Switch", in3r_lpga_n_enum), }; @@ -385,21 +379,27 @@ static SOC_ENUM_SINGLE_DECL(in3l_rpga_n_enum, AIC32X4_RMICPGANIN, 2, resistor_te static const struct snd_kcontrol_new in1r_to_rmixer_controls[] = { SOC_DAPM_ENUM("IN1_R R+ Switch", in1r_rpga_p_enum), }; + static const struct snd_kcontrol_new in2r_to_rmixer_controls[] = { SOC_DAPM_ENUM("IN2_R R+ Switch", in2r_rpga_p_enum), }; + static const struct snd_kcontrol_new in3r_to_rmixer_controls[] = { SOC_DAPM_ENUM("IN3_R R+ Switch", in3r_rpga_p_enum), }; + static const struct snd_kcontrol_new in2l_to_rmixer_controls[] = { SOC_DAPM_ENUM("IN2_L R+ Switch", in2l_rpga_p_enum), }; + static const struct snd_kcontrol_new cmr_to_rmixer_controls[] = { SOC_DAPM_ENUM("CM_R R- Switch", cmr_rpga_n_enum), }; + static const struct snd_kcontrol_new in1l_to_rmixer_controls[] = { SOC_DAPM_ENUM("IN1_L R- Switch", in1l_rpga_n_enum), }; + static const struct snd_kcontrol_new in3l_to_rmixer_controls[] = { SOC_DAPM_ENUM("IN3_L R- Switch", in3l_rpga_n_enum), }; @@ -428,38 +428,38 @@ static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = { SND_SOC_DAPM_ADC("Right ADC", "Right Capture", AIC32X4_ADCSETUP, 6, 0), SND_SOC_DAPM_MUX("IN1_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, - in1r_to_rmixer_controls), + in1r_to_rmixer_controls), SND_SOC_DAPM_MUX("IN2_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, - in2r_to_rmixer_controls), + in2r_to_rmixer_controls), SND_SOC_DAPM_MUX("IN3_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, - in3r_to_rmixer_controls), + in3r_to_rmixer_controls), SND_SOC_DAPM_MUX("IN2_L to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, - in2l_to_rmixer_controls), + in2l_to_rmixer_controls), SND_SOC_DAPM_MUX("CM_R to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, - cmr_to_rmixer_controls), + cmr_to_rmixer_controls), SND_SOC_DAPM_MUX("IN1_L to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, - in1l_to_rmixer_controls), + in1l_to_rmixer_controls), SND_SOC_DAPM_MUX("IN3_L to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, - in3l_to_rmixer_controls), + in3l_to_rmixer_controls), SND_SOC_DAPM_ADC("Left ADC", "Left Capture", AIC32X4_ADCSETUP, 7, 0), SND_SOC_DAPM_MUX("IN1_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, - in1l_to_lmixer_controls), + in1l_to_lmixer_controls), SND_SOC_DAPM_MUX("IN2_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, - in2l_to_lmixer_controls), + in2l_to_lmixer_controls), SND_SOC_DAPM_MUX("IN3_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, - in3l_to_lmixer_controls), + in3l_to_lmixer_controls), SND_SOC_DAPM_MUX("IN1_R to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, - in1r_to_lmixer_controls), + in1r_to_lmixer_controls), SND_SOC_DAPM_MUX("CM_L to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, - cml_to_lmixer_controls), + cml_to_lmixer_controls), SND_SOC_DAPM_MUX("IN2_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, - in2r_to_lmixer_controls), + in2r_to_lmixer_controls), SND_SOC_DAPM_MUX("IN3_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, - in3r_to_lmixer_controls), + in3r_to_lmixer_controls), SND_SOC_DAPM_SUPPLY("Mic Bias", AIC32X4_MICBIAS, 6, 0, mic_bias_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_POST("ADC Reset", aic32x4_reset_adc), @@ -575,7 +575,7 @@ static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = { {"IN3_R to Left Mixer Negative Resistor", "40 kOhm", "IN3_R"}, }; -static const struct regmap_range_cfg aic32x4_regmap_pages[] = { +const struct regmap_range_cfg aic32x4_regmap_pages[] = { { .selector_reg = 0, .selector_mask = 0xff, @@ -585,13 +585,7 @@ static const struct regmap_range_cfg aic32x4_regmap_pages[] = { .range_max = AIC32X4_REFPOWERUP, }, }; - -const struct regmap_config aic32x4_regmap_config = { - .max_register = AIC32X4_REFPOWERUP, - .ranges = aic32x4_regmap_pages, - .num_ranges = ARRAY_SIZE(aic32x4_regmap_pages), -}; -EXPORT_SYMBOL(aic32x4_regmap_config); +EXPORT_SYMBOL_GPL(aic32x4_regmap_pages); static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) @@ -624,7 +618,7 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) case SND_SOC_DAIFMT_CBC_CFC: break; default: - printk(KERN_ERR "aic32x4: invalid clock provider\n"); + dev_err(component->dev, "invalid clock provider\n"); return -EINVAL; } @@ -651,19 +645,20 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) AIC32X4_IFACE1_DATATYPE_SHIFT); break; default: - printk(KERN_ERR "aic32x4: invalid DAI interface format\n"); + dev_err(component->dev, "invalid DAI interface format\n"); return -EINVAL; } aic32x4->fmt = fmt; snd_soc_component_update_bits(component, AIC32X4_IFACE1, - AIC32X4_IFACE1_DATATYPE_MASK | - AIC32X4_IFACE1_MASTER_MASK, iface_reg_1); + AIC32X4_IFACE1_DATATYPE_MASK | + AIC32X4_IFACE1_MASTER_MASK, + iface_reg_1); snd_soc_component_update_bits(component, AIC32X4_IFACE2, - AIC32X4_DATA_OFFSET_MASK, iface_reg_2); + AIC32X4_DATA_OFFSET_MASK, iface_reg_2); snd_soc_component_update_bits(component, AIC32X4_IFACE3, - AIC32X4_BCLKINV_MASK, iface_reg_3); + AIC32X4_BCLKINV_MASK, iface_reg_3); return 0; } @@ -676,14 +671,13 @@ static int aic32x4_set_aosr(struct snd_soc_component *component, u8 aosr) static int aic32x4_set_dosr(struct snd_soc_component *component, u16 dosr) { snd_soc_component_write(component, AIC32X4_DOSRMSB, dosr >> 8); - snd_soc_component_write(component, AIC32X4_DOSRLSB, - (dosr & 0xff)); + snd_soc_component_write(component, AIC32X4_DOSRLSB, dosr & 0xff); return 0; } static int aic32x4_set_processing_blocks(struct snd_soc_component *component, - u8 r_block, u8 p_block) + u8 r_block, u8 p_block) { struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component); @@ -703,6 +697,45 @@ static int aic32x4_set_processing_blocks(struct snd_soc_component *component, return 0; } +static int aic32x4_configure_rate(struct snd_soc_component *component, + unsigned int rate, u8 *aosr, u8 *adc_rc, + u8 *dac_rc, u8 *dosr_inc) +{ + struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component); + u8 prb_rx, prb_tx; + + if (rate <= 48000) { + *aosr = 128; + *adc_rc = 6; + *dac_rc = 8; + *dosr_inc = 8; + prb_rx = 1; + prb_tx = 1; + } else if (rate <= 96000) { + *aosr = 64; + *adc_rc = 6; + *dac_rc = 8; + *dosr_inc = 4; + prb_rx = 1; + prb_tx = (aic32x4->type == AIC32X4_TYPE_TAS2505) ? 1 : 9; + } else if (rate == 192000) { + *aosr = 32; + *adc_rc = 3; + *dac_rc = 4; + *dosr_inc = 2; + prb_rx = 13; + prb_tx = (aic32x4->type == AIC32X4_TYPE_TAS2505) ? 1 : 19; + } else { + dev_err(component->dev, "Sampling rate %u not supported\n", rate); + return -EINVAL; + } + + if (aic32x4->type == AIC32X4_TYPE_TAS2505) + prb_rx = 0; + + return aic32x4_set_processing_blocks(component, prb_rx, prb_tx); +} + static int aic32x4_setup_clocks(struct snd_soc_component *component, unsigned int sample_rate, unsigned int channels, unsigned int bit_depth) @@ -717,7 +750,7 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component, unsigned long adc_clock_rate, dac_clock_rate; int ret; - static struct clk_bulk_data clocks[] = { + struct clk_bulk_data clocks[] = { { .id = "pll" }, { .id = "nadc" }, { .id = "madc" }, @@ -729,37 +762,11 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component, if (ret) return ret; - if (sample_rate <= 48000) { - aosr = 128; - adc_resource_class = 6; - dac_resource_class = 8; - dosr_increment = 8; - if (aic32x4->type == AIC32X4_TYPE_TAS2505) - aic32x4_set_processing_blocks(component, 0, 1); - else - aic32x4_set_processing_blocks(component, 1, 1); - } else if (sample_rate <= 96000) { - aosr = 64; - adc_resource_class = 6; - dac_resource_class = 8; - dosr_increment = 4; - if (aic32x4->type == AIC32X4_TYPE_TAS2505) - aic32x4_set_processing_blocks(component, 0, 1); - else - aic32x4_set_processing_blocks(component, 1, 9); - } else if (sample_rate == 192000) { - aosr = 32; - adc_resource_class = 3; - dac_resource_class = 4; - dosr_increment = 2; - if (aic32x4->type == AIC32X4_TYPE_TAS2505) - aic32x4_set_processing_blocks(component, 0, 1); - else - aic32x4_set_processing_blocks(component, 13, 19); - } else { - dev_err(component->dev, "Sampling rate not supported\n"); - return -EINVAL; - } + ret = aic32x4_configure_rate(component, sample_rate, &aosr, + &adc_resource_class, &dac_resource_class, + &dosr_increment); + if (ret) + return ret; /* PCM over I2S is always 2-channel */ if ((aic32x4->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) @@ -781,50 +788,39 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component, (min_mdac * dosr * sample_rate); for (mdac = min_mdac; mdac <= 128; ++mdac) { for (ndac = max_ndac; ndac > 0; --ndac) { - dac_clock_rate = ndac * mdac * dosr * - sample_rate; - if (dac_clock_rate == adc_clock_rate) { - if (clk_round_rate(clocks[0].clk, dac_clock_rate) == 0) - continue; - - clk_set_rate(clocks[0].clk, - dac_clock_rate); - - clk_set_rate(clocks[1].clk, - sample_rate * aosr * - madc); - clk_set_rate(clocks[2].clk, - sample_rate * aosr); - aic32x4_set_aosr(component, - aosr); - - clk_set_rate(clocks[3].clk, - sample_rate * dosr * - mdac); - clk_set_rate(clocks[4].clk, - sample_rate * dosr); - aic32x4_set_dosr(component, - dosr); - - clk_set_rate(clocks[5].clk, - sample_rate * channels * - bit_depth); - - return 0; - } + dac_clock_rate = ndac * mdac * dosr * sample_rate; + if (dac_clock_rate != adc_clock_rate) + continue; + + if (clk_round_rate(clocks[0].clk, dac_clock_rate) == 0) + continue; + + clk_set_rate(clocks[0].clk, dac_clock_rate); + + clk_set_rate(clocks[1].clk, sample_rate * aosr * madc); + clk_set_rate(clocks[2].clk, sample_rate * aosr); + aic32x4_set_aosr(component, aosr); + + clk_set_rate(clocks[3].clk, sample_rate * dosr * mdac); + clk_set_rate(clocks[4].clk, sample_rate * dosr); + aic32x4_set_dosr(component, dosr); + + clk_set_rate(clocks[5].clk, + sample_rate * channels * bit_depth); + + return 0; } } } } - dev_err(component->dev, - "Could not set clocks to support sample rate.\n"); + dev_err(component->dev, "Could not set clocks to support sample rate.\n"); return -EINVAL; } static int aic32x4_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component); @@ -837,24 +833,20 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream, switch (params_physical_width(params)) { case 16: - iface1_reg |= (AIC32X4_WORD_LEN_16BITS << - AIC32X4_IFACE1_DATALEN_SHIFT); + iface1_reg |= (AIC32X4_WORD_LEN_16BITS << AIC32X4_IFACE1_DATALEN_SHIFT); break; case 20: - iface1_reg |= (AIC32X4_WORD_LEN_20BITS << - AIC32X4_IFACE1_DATALEN_SHIFT); + iface1_reg |= (AIC32X4_WORD_LEN_20BITS << AIC32X4_IFACE1_DATALEN_SHIFT); break; case 24: - iface1_reg |= (AIC32X4_WORD_LEN_24BITS << - AIC32X4_IFACE1_DATALEN_SHIFT); + iface1_reg |= (AIC32X4_WORD_LEN_24BITS << AIC32X4_IFACE1_DATALEN_SHIFT); break; case 32: - iface1_reg |= (AIC32X4_WORD_LEN_32BITS << - AIC32X4_IFACE1_DATALEN_SHIFT); + iface1_reg |= (AIC32X4_WORD_LEN_32BITS << AIC32X4_IFACE1_DATALEN_SHIFT); break; } snd_soc_component_update_bits(component, AIC32X4_IFACE1, - AIC32X4_IFACE1_DATALEN_MASK, iface1_reg); + AIC32X4_IFACE1_DATALEN_MASK, iface1_reg); if (params_channels(params) == 1) { dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN; @@ -865,7 +857,7 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream, dacsetup_reg = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN; } snd_soc_component_update_bits(component, AIC32X4_DACSETUP, - AIC32X4_DAC_CHAN_MASK, dacsetup_reg); + AIC32X4_DAC_CHAN_MASK, dacsetup_reg); return 0; } @@ -875,7 +867,7 @@ static int aic32x4_mute(struct snd_soc_dai *dai, int mute, int direction) struct snd_soc_component *component = dai->component; snd_soc_component_update_bits(component, AIC32X4_DACMUTE, - AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0); + AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0); return 0; } @@ -886,7 +878,7 @@ static int aic32x4_set_bias_level(struct snd_soc_component *component, struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); int ret; - static struct clk_bulk_data clocks[] = { + struct clk_bulk_data clocks[] = { { .id = "madc" }, { .id = "mdac" }, { .id = "bdiv" }, @@ -955,44 +947,14 @@ static void aic32x4_setup_gpios(struct snd_soc_component *component) struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component); /* setup GPIO functions */ - /* MFP1 */ - if (aic32x4->setup->gpio_func[0] != AIC32X4_MFPX_DEFAULT_VALUE) { - snd_soc_component_write(component, AIC32X4_DINCTL, - aic32x4->setup->gpio_func[0]); - snd_soc_add_component_controls(component, aic32x4_mfp1, - ARRAY_SIZE(aic32x4_mfp1)); - } - - /* MFP2 */ - if (aic32x4->setup->gpio_func[1] != AIC32X4_MFPX_DEFAULT_VALUE) { - snd_soc_component_write(component, AIC32X4_DOUTCTL, - aic32x4->setup->gpio_func[1]); - snd_soc_add_component_controls(component, aic32x4_mfp2, - ARRAY_SIZE(aic32x4_mfp2)); - } - - /* MFP3 */ - if (aic32x4->setup->gpio_func[2] != AIC32X4_MFPX_DEFAULT_VALUE) { - snd_soc_component_write(component, AIC32X4_SCLKCTL, - aic32x4->setup->gpio_func[2]); - snd_soc_add_component_controls(component, aic32x4_mfp3, - ARRAY_SIZE(aic32x4_mfp3)); - } - - /* MFP4 */ - if (aic32x4->setup->gpio_func[3] != AIC32X4_MFPX_DEFAULT_VALUE) { - snd_soc_component_write(component, AIC32X4_MISOCTL, - aic32x4->setup->gpio_func[3]); - snd_soc_add_component_controls(component, aic32x4_mfp4, - ARRAY_SIZE(aic32x4_mfp4)); - } - - /* MFP5 */ - if (aic32x4->setup->gpio_func[4] != AIC32X4_MFPX_DEFAULT_VALUE) { - snd_soc_component_write(component, AIC32X4_GPIOCTL, - aic32x4->setup->gpio_func[4]); - snd_soc_add_component_controls(component, aic32x4_mfp5, - ARRAY_SIZE(aic32x4_mfp5)); + BUILD_BUG_ON(ARRAY_SIZE(aic32x4->gpio_func) != ARRAY_SIZE(aic32x4_mfp_cfg)); + for (int i = 0; i < ARRAY_SIZE(aic32x4->gpio_func); i++) { + if (aic32x4->gpio_func[i] == AIC32X4_MFPX_DEFAULT_VALUE) + continue; + + snd_soc_component_write(component, aic32x4_mfp_cfg[i].reg, + aic32x4->gpio_func[i]); + snd_soc_add_component_controls(component, &aic32x4_mfp_cfg[i].ctrl, 1); } } @@ -1002,7 +964,7 @@ static int aic32x4_component_probe(struct snd_soc_component *component) u32 tmp_reg; int ret; - static struct clk_bulk_data clocks[] = { + struct clk_bulk_data clocks[] = { { .id = "codec_clkin" }, { .id = "pll" }, { .id = "bdiv" }, @@ -1013,8 +975,7 @@ static int aic32x4_component_probe(struct snd_soc_component *component) if (ret) return ret; - if (aic32x4->setup) - aic32x4_setup_gpios(component); + aic32x4_setup_gpios(component); clk_set_parent(clocks[0].clk, clocks[1].clk); clk_set_parent(clocks[2].clk, clocks[3].clk); @@ -1022,7 +983,7 @@ static int aic32x4_component_probe(struct snd_soc_component *component) /* Power platform configuration */ if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) { snd_soc_component_write(component, AIC32X4_MICBIAS, - AIC32X4_MICBIAS_LDOIN | AIC32X4_MICBIAS_2075V); + AIC32X4_MICBIAS_LDOIN | AIC32X4_MICBIAS_2075V); } if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE) snd_soc_component_write(component, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE); @@ -1041,16 +1002,16 @@ static int aic32x4_component_probe(struct snd_soc_component *component) /* Mic PGA routing */ if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K) snd_soc_component_write(component, AIC32X4_LMICPGANIN, - AIC32X4_LMICPGANIN_IN2R_10K); + AIC32X4_LMICPGANIN_IN2R_10K); else snd_soc_component_write(component, AIC32X4_LMICPGANIN, - AIC32X4_LMICPGANIN_CM1L_10K); + AIC32X4_LMICPGANIN_CM1L_10K); if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K) snd_soc_component_write(component, AIC32X4_RMICPGANIN, - AIC32X4_RMICPGANIN_IN1L_10K); + AIC32X4_RMICPGANIN_IN1L_10K); else snd_soc_component_write(component, AIC32X4_RMICPGANIN, - AIC32X4_RMICPGANIN_CM1R_10K); + AIC32X4_RMICPGANIN_CM1R_10K); /* * Workaround: for an unknown reason, the ADC needs to be powered up @@ -1058,8 +1019,8 @@ static int aic32x4_component_probe(struct snd_soc_component *component) * a HW BUG or some kind of behavior not documented in the datasheet. */ tmp_reg = snd_soc_component_read(component, AIC32X4_ADCSETUP); - snd_soc_component_write(component, AIC32X4_ADCSETUP, tmp_reg | - AIC32X4_LADC_EN | AIC32X4_RADC_EN); + snd_soc_component_write(component, AIC32X4_ADCSETUP, + tmp_reg | AIC32X4_LADC_EN | AIC32X4_RADC_EN); snd_soc_component_write(component, AIC32X4_ADCSETUP, tmp_reg); /* @@ -1102,13 +1063,13 @@ static const struct snd_kcontrol_new aic32x4_tas2505_snd_controls[] = { SOC_ENUM("DAC Playback PowerTune Switch", l_ptm_enum), SOC_SINGLE_TLV("HP Driver Gain Volume", - AIC32X4_HPLGAIN, 0, 0x74, 1, tlv_tas_driver_gain), + AIC32X4_HPLGAIN, 0, 0x74, 1, tlv_tas_driver_gain), SOC_SINGLE("HP DAC Playback Switch", AIC32X4_HPLGAIN, 6, 1, 1), SOC_SINGLE_TLV("Speaker Driver Playback Volume", - TAS2505_SPKVOL1, 0, 0x74, 1, tlv_tas_driver_gain), + TAS2505_SPKVOL1, 0, 0x74, 1, tlv_tas_driver_gain), SOC_SINGLE_TLV("Speaker Amplifier Playback Volume", - TAS2505_SPKVOL2, 4, 5, 0, tlv_amp_vol), + TAS2505_SPKVOL2, 4, 5, 0, tlv_amp_vol), SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0), }; @@ -1144,11 +1105,12 @@ static const struct snd_soc_dapm_route aic32x4_tas2505_dapm_routes[] = { static struct snd_soc_dai_driver aic32x4_tas2505_dai = { .name = "tas2505-hifi", .playback = { - .stream_name = "Playback", - .channels_min = 1, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_96000, - .formats = AIC32X4_FORMATS,}, + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = AIC32X4_FORMATS, + }, .ops = &aic32x4_ops, .symmetric_rate = 1, }; @@ -1159,7 +1121,7 @@ static int aic32x4_tas2505_component_probe(struct snd_soc_component *component) u32 tmp_reg; int ret; - static struct clk_bulk_data clocks[] = { + struct clk_bulk_data clocks[] = { { .id = "codec_clkin" }, { .id = "pll" }, { .id = "bdiv" }, @@ -1170,8 +1132,7 @@ static int aic32x4_tas2505_component_probe(struct snd_soc_component *component) if (ret) return ret; - if (aic32x4->setup) - aic32x4_setup_gpios(component); + aic32x4_setup_gpios(component); clk_set_parent(clocks[0].clk, clocks[1].clk); clk_set_parent(clocks[2].clk, clocks[3].clk); @@ -1192,7 +1153,7 @@ static int aic32x4_tas2505_component_probe(struct snd_soc_component *component) snd_soc_component_write(component, AIC32X4_CMMODE, tmp_reg); /* - * Enable the fast charging feature and ensure the needed 40ms ellapsed + * Enable the fast charging feature and ensure the needed 40ms elapsed * before using the analog circuits. */ snd_soc_component_write(component, TAS2505_REFPOWERUP, @@ -1218,17 +1179,10 @@ static const struct snd_soc_component_driver soc_component_dev_aic32x4_tas2505 = .endianness = 1, }; -static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, - struct device_node *np) +static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, struct device_node *np) { - struct aic32x4_setup_data *aic32x4_setup; int ret; - aic32x4_setup = devm_kzalloc(aic32x4->dev, sizeof(*aic32x4_setup), - GFP_KERNEL); - if (!aic32x4_setup) - return -ENOMEM; - ret = of_property_match_string(np, "clock-names", "mclk"); if (ret < 0) return -EINVAL; @@ -1245,9 +1199,11 @@ static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, gpiod_set_consumer_name(aic32x4->rstn_gpio, "tlv320aic32x4_rstn"); } - if (of_property_read_u32_array(np, "aic32x4-gpio-func", - aic32x4_setup->gpio_func, 5) >= 0) - aic32x4->setup = aic32x4_setup; + for (int i = 0; i < ARRAY_SIZE(aic32x4->gpio_func); i++) + aic32x4->gpio_func[i] = AIC32X4_MFPX_DEFAULT_VALUE; + of_property_read_u32_array(np, "aic32x4-gpio-func", + aic32x4->gpio_func, ARRAY_SIZE(aic32x4->gpio_func)); + return 0; } @@ -1266,7 +1222,7 @@ static void aic32x4_disable_regulators(struct aic32x4_priv *aic32x4) } static int aic32x4_setup_regulators(struct device *dev, - struct aic32x4_priv *aic32x4) + struct aic32x4_priv *aic32x4) { int ret = 0; @@ -1356,12 +1312,8 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap, struct device_node *np = dev->of_node; int ret; - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - aic32x4 = devm_kzalloc(dev, sizeof(struct aic32x4_priv), - GFP_KERNEL); - if (aic32x4 == NULL) + aic32x4 = devm_kzalloc(dev, sizeof(struct aic32x4_priv), GFP_KERNEL); + if (!aic32x4) return -ENOMEM; aic32x4->dev = dev; @@ -1405,11 +1357,13 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap, switch (aic32x4->type) { case AIC32X4_TYPE_TAS2505: ret = devm_snd_soc_register_component(dev, - &soc_component_dev_aic32x4_tas2505, &aic32x4_tas2505_dai, 1); + &soc_component_dev_aic32x4_tas2505, + &aic32x4_tas2505_dai, 1); break; default: ret = devm_snd_soc_register_component(dev, - &soc_component_dev_aic32x4, &aic32x4_dai, 1); + &soc_component_dev_aic32x4, + &aic32x4_dai, 1); } if (ret) { diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h index f68a846ef61d..cfab6f8ce5ac 100644 --- a/sound/soc/codecs/tlv320aic32x4.h +++ b/sound/soc/codecs/tlv320aic32x4.h @@ -3,7 +3,6 @@ * tlv320aic32x4.h */ - #ifndef _TLV320AIC32X4_H #define _TLV320AIC32X4_H @@ -16,7 +15,7 @@ enum aic32x4_type { AIC32X4_TYPE_TAS2505, }; -extern const struct regmap_config aic32x4_regmap_config; +extern const struct regmap_range_cfg aic32x4_regmap_pages[]; int aic32x4_probe(struct device *dev, struct regmap *regmap, enum aic32x4_type type); void aic32x4_remove(struct device *dev); @@ -24,7 +23,7 @@ int aic32x4_register_clocks(struct device *dev, const char *mclk_name); /* tlv320aic32x4 register space (in decimal to match datasheet) */ -#define AIC32X4_REG(page, reg) ((page * 128) + reg) +#define AIC32X4_REG(page, reg) (((page) * 128) + (reg)) #define AIC32X4_PSEL AIC32X4_REG(0, 0) @@ -234,4 +233,31 @@ int aic32x4_register_clocks(struct device *dev, const char *mclk_name); #define AIC32X4_MAX_CODEC_CLKIN_FREQ 110000000 #define AIC32X4_MAX_PLL_CLKIN 20000000 +#define AIC32X4_PWR_MICBIAS_2075_LDOIN 0x00000001 +#define AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE 0x00000002 +#define AIC32X4_PWR_AIC32X4_LDO_ENABLE 0x00000004 +#define AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36 0x00000008 +#define AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED 0x00000010 + +#define AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K 0x00000001 +#define AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K 0x00000002 + +/* GPIO API */ +#define AIC32X4_MFPX_DEFAULT_VALUE 0xff + +#define AIC32X4_MFP1_DIN_DISABLED 0 +#define AIC32X4_MFP1_DIN_ENABLED 0x2 +#define AIC32X4_MFP1_GPIO_IN 0x4 + +#define AIC32X4_MFP2_GPIO_OUT_LOW 0x0 +#define AIC32X4_MFP2_GPIO_OUT_HIGH 0x1 + +#define AIC32X4_MFP_GPIO_ENABLED 0x4 + +#define AIC32X4_MFP5_GPIO_DISABLED 0x0 +#define AIC32X4_MFP5_GPIO_INPUT 0x8 +#define AIC32X4_MFP5_GPIO_OUTPUT 0xc +#define AIC32X4_MFP5_GPIO_OUT_LOW 0x0 +#define AIC32X4_MFP5_GPIO_OUT_HIGH 0x1 + #endif /* _TLV320AIC32X4_H */ diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 223c49dfc450..9bd2ddd8dacd 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -7,6 +7,7 @@ * Copyright: (C) 2009 Nokia Corporation */ +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> @@ -236,13 +237,10 @@ static int dac33_write_locked(struct snd_soc_component *component, unsigned int unsigned int value) { struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component); - int ret; - mutex_lock(&dac33->mutex); - ret = dac33_write(component, reg, value); - mutex_unlock(&dac33->mutex); + guard(mutex)(&dac33->mutex); - return ret; + return dac33_write(component, reg, value); } #define DAC33_I2C_ADDR_AUTOINC 0x80 @@ -365,13 +363,13 @@ static int dac33_hard_power(struct snd_soc_component *component, int power) struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component); int ret = 0; - mutex_lock(&dac33->mutex); + guard(mutex)(&dac33->mutex); /* Safety check */ if (unlikely(power == dac33->chip_power)) { dev_dbg(component->dev, "Trying to set the same power state: %s\n", power ? "ON" : "OFF"); - goto exit; + return ret; } if (power) { @@ -380,7 +378,7 @@ static int dac33_hard_power(struct snd_soc_component *component, int power) if (ret != 0) { dev_err(component->dev, "Failed to enable supplies: %d\n", ret); - goto exit; + return ret; } if (dac33->reset_gpiod) { @@ -388,7 +386,7 @@ static int dac33_hard_power(struct snd_soc_component *component, int power) if (ret < 0) { dev_err(&dac33->i2c->dev, "Failed to set reset GPIO: %d\n", ret); - goto exit; + return ret; } } @@ -400,7 +398,7 @@ static int dac33_hard_power(struct snd_soc_component *component, int power) if (ret < 0) { dev_err(&dac33->i2c->dev, "Failed to set reset GPIO: %d\n", ret); - goto exit; + return ret; } } @@ -409,14 +407,12 @@ static int dac33_hard_power(struct snd_soc_component *component, int power) if (ret != 0) { dev_err(component->dev, "Failed to disable supplies: %d\n", ret); - goto exit; + return ret; } dac33->chip_power = 0; } -exit: - mutex_unlock(&dac33->mutex); return ret; } @@ -659,7 +655,6 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) { struct snd_soc_component *component = dac33->component; unsigned int delay; - unsigned long flags; switch (dac33->fifo_mode) { case DAC33_FIFO_MODE1: @@ -667,10 +662,10 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) DAC33_THRREG(dac33->nsample)); /* Take the timestamps */ - spin_lock_irqsave(&dac33->lock, flags); - dac33->t_stamp2 = ktime_to_us(ktime_get()); - dac33->t_stamp1 = dac33->t_stamp2; - spin_unlock_irqrestore(&dac33->lock, flags); + scoped_guard(spinlock_irqsave, &dac33->lock) { + dac33->t_stamp2 = ktime_to_us(ktime_get()); + dac33->t_stamp1 = dac33->t_stamp2; + } dac33_write16(component, DAC33_PREFILL_MSB, DAC33_THRREG(dac33->alarm_threshold)); @@ -682,11 +677,11 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) break; case DAC33_FIFO_MODE7: /* Take the timestamp */ - spin_lock_irqsave(&dac33->lock, flags); - dac33->t_stamp1 = ktime_to_us(ktime_get()); - /* Move back the timestamp with drain time */ - dac33->t_stamp1 -= dac33->mode7_us_to_lthr; - spin_unlock_irqrestore(&dac33->lock, flags); + scoped_guard(spinlock_irqsave, &dac33->lock) { + dac33->t_stamp1 = ktime_to_us(ktime_get()); + /* Move back the timestamp with drain time */ + dac33->t_stamp1 -= dac33->mode7_us_to_lthr; + } dac33_write16(component, DAC33_PREFILL_MSB, DAC33_THRREG(DAC33_MODE7_MARGIN)); @@ -704,14 +699,12 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33) { struct snd_soc_component *component = dac33->component; - unsigned long flags; switch (dac33->fifo_mode) { case DAC33_FIFO_MODE1: /* Take the timestamp */ - spin_lock_irqsave(&dac33->lock, flags); - dac33->t_stamp2 = ktime_to_us(ktime_get()); - spin_unlock_irqrestore(&dac33->lock, flags); + scoped_guard(spinlock_irqsave, &dac33->lock) + dac33->t_stamp2 = ktime_to_us(ktime_get()); dac33_write16(component, DAC33_NSAMPLE_MSB, DAC33_THRREG(dac33->nsample)); @@ -735,7 +728,7 @@ static void dac33_work(struct work_struct *work) dac33 = container_of(work, struct tlv320dac33_priv, work); component = dac33->component; - mutex_lock(&dac33->mutex); + guard(mutex)(&dac33->mutex); switch (dac33->state) { case DAC33_PREFILL: dac33->state = DAC33_PLAYBACK; @@ -757,18 +750,15 @@ static void dac33_work(struct work_struct *work) dac33_write(component, DAC33_FIFO_CTRL_A, reg); break; } - mutex_unlock(&dac33->mutex); } static irqreturn_t dac33_interrupt_handler(int irq, void *dev) { struct snd_soc_component *component = dev; struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component); - unsigned long flags; - spin_lock_irqsave(&dac33->lock, flags); - dac33->t_stamp1 = ktime_to_us(ktime_get()); - spin_unlock_irqrestore(&dac33->lock, flags); + scoped_guard(spinlock_irqsave, &dac33->lock) + dac33->t_stamp1 = ktime_to_us(ktime_get()); /* Do not schedule the workqueue in Mode7 */ if (dac33->fifo_mode != DAC33_FIFO_MODE7) @@ -902,14 +892,13 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream, return -EINVAL; } - mutex_lock(&dac33->mutex); + guard(mutex)(&dac33->mutex); if (!dac33->chip_power) { /* * Chip is not powered yet. * Do the init in the dac33_set_bias_level later. */ - mutex_unlock(&dac33->mutex); return 0; } @@ -1053,8 +1042,6 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream, break; } - mutex_unlock(&dac33->mutex); - return 0; } @@ -1156,21 +1143,20 @@ static snd_pcm_sframes_t dac33_dai_delay( unsigned int time_delta, uthr; int samples_out, samples_in, samples; snd_pcm_sframes_t delay = 0; - unsigned long flags; switch (dac33->fifo_mode) { case DAC33_FIFO_BYPASS: break; case DAC33_FIFO_MODE1: - spin_lock_irqsave(&dac33->lock, flags); - t0 = dac33->t_stamp1; - t1 = dac33->t_stamp2; - spin_unlock_irqrestore(&dac33->lock, flags); + scoped_guard(spinlock_irqsave, &dac33->lock) { + t0 = dac33->t_stamp1; + t1 = dac33->t_stamp2; + } t_now = ktime_to_us(ktime_get()); /* We have not started to fill the FIFO yet, delay is 0 */ if (!t1) - goto out; + return 0; if (t0 > t1) { /* @@ -1230,23 +1216,22 @@ static snd_pcm_sframes_t dac33_dai_delay( } break; case DAC33_FIFO_MODE7: - spin_lock_irqsave(&dac33->lock, flags); - t0 = dac33->t_stamp1; - uthr = dac33->uthr; - spin_unlock_irqrestore(&dac33->lock, flags); + scoped_guard(spinlock_irqsave, &dac33->lock) { + t0 = dac33->t_stamp1; + uthr = dac33->uthr; + } t_now = ktime_to_us(ktime_get()); /* We have not started to fill the FIFO yet, delay is 0 */ if (!t0) - goto out; + return 0; if (t_now <= t0) { /* * Either the timestamps are messed or equal. Report * maximum delay */ - delay = uthr; - goto out; + return uthr; } time_delta = t_now - t0; @@ -1287,7 +1272,7 @@ static snd_pcm_sframes_t dac33_dai_delay( dac33->fifo_mode); break; } -out: + return delay; } diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c index dba581857920..02082ef790b4 100644 --- a/sound/soc/codecs/tscs42xx.c +++ b/sound/soc/codecs/tscs42xx.c @@ -12,6 +12,7 @@ #include <linux/module.h> #include <linux/delay.h> #include <linux/mutex.h> +#include <linux/cleanup.h> #include <linux/clk.h> #include <sound/tlv.h> #include <sound/pcm_params.h> @@ -210,25 +211,21 @@ static int power_up_audio_plls(struct snd_soc_component *component) return ret; } - mutex_lock(&tscs42xx->pll_lock); + guard(mutex)(&tscs42xx->pll_lock); ret = snd_soc_component_update_bits(component, R_PLLCTL1C, mask, val); if (ret < 0) { dev_err(component->dev, "Failed to turn PLL on (%d)\n", ret); - goto exit; + return ret; } if (!plls_locked(component)) { dev_err(component->dev, "Failed to lock plls\n"); ret = -ENOMSG; - goto exit; + return ret; } - ret = 0; -exit: - mutex_unlock(&tscs42xx->pll_lock); - - return ret; + return 0; } static int power_down_audio_plls(struct snd_soc_component *component) @@ -236,28 +233,24 @@ static int power_down_audio_plls(struct snd_soc_component *component) struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component); int ret; - mutex_lock(&tscs42xx->pll_lock); + guard(mutex)(&tscs42xx->pll_lock); ret = snd_soc_component_update_bits(component, R_PLLCTL1C, RM_PLLCTL1C_PDB_PLL1, RV_PLLCTL1C_PDB_PLL1_DISABLE); if (ret < 0) { dev_err(component->dev, "Failed to turn PLL off (%d)\n", ret); - goto exit; + return ret; } ret = snd_soc_component_update_bits(component, R_PLLCTL1C, RM_PLLCTL1C_PDB_PLL2, RV_PLLCTL1C_PDB_PLL2_DISABLE); if (ret < 0) { dev_err(component->dev, "Failed to turn PLL off (%d)\n", ret); - goto exit; + return ret; } - ret = 0; -exit: - mutex_unlock(&tscs42xx->pll_lock); - - return ret; + return 0; } static int coeff_ram_get(struct snd_kcontrol *kcontrol, @@ -269,13 +262,11 @@ static int coeff_ram_get(struct snd_kcontrol *kcontrol, (struct coeff_ram_ctl *)kcontrol->private_value; struct soc_bytes_ext *params = &ctl->bytes_ext; - mutex_lock(&tscs42xx->coeff_ram_lock); + guard(mutex)(&tscs42xx->coeff_ram_lock); memcpy(ucontrol->value.bytes.data, &tscs42xx->coeff_ram[ctl->addr * COEFF_SIZE], params->max); - mutex_unlock(&tscs42xx->coeff_ram_lock); - return 0; } @@ -290,14 +281,14 @@ static int coeff_ram_put(struct snd_kcontrol *kcontrol, unsigned int coeff_cnt = params->max / COEFF_SIZE; int ret; - mutex_lock(&tscs42xx->coeff_ram_lock); + guard(mutex)(&tscs42xx->coeff_ram_lock); tscs42xx->coeff_ram_synced = false; memcpy(&tscs42xx->coeff_ram[ctl->addr * COEFF_SIZE], ucontrol->value.bytes.data, params->max); - mutex_lock(&tscs42xx->pll_lock); + guard(mutex)(&tscs42xx->pll_lock); if (plls_locked(component)) { ret = write_coeff_ram(component, tscs42xx->coeff_ram, @@ -305,18 +296,12 @@ static int coeff_ram_put(struct snd_kcontrol *kcontrol, if (ret < 0) { dev_err(component->dev, "Failed to flush coeff ram cache (%d)\n", ret); - goto exit; + return ret; } tscs42xx->coeff_ram_synced = true; } - ret = 0; -exit: - mutex_unlock(&tscs42xx->pll_lock); - - mutex_unlock(&tscs42xx->coeff_ram_lock); - - return ret; + return 0; } /* Input L Capture Route */ @@ -385,21 +370,17 @@ static int dac_event(struct snd_soc_dapm_widget *w, struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component); int ret; - mutex_lock(&tscs42xx->coeff_ram_lock); + guard(mutex)(&tscs42xx->coeff_ram_lock); if (!tscs42xx->coeff_ram_synced) { ret = write_coeff_ram(component, tscs42xx->coeff_ram, 0x00, COEFF_RAM_COEFF_COUNT); if (ret < 0) - goto exit; + return ret; tscs42xx->coeff_ram_synced = true; } - ret = 0; -exit: - mutex_unlock(&tscs42xx->coeff_ram_lock); - - return ret; + return 0; } static const struct snd_soc_dapm_widget tscs42xx_dapm_widgets[] = { @@ -926,12 +907,10 @@ static int setup_sample_rate(struct snd_soc_component *component, return ret; } - mutex_lock(&tscs42xx->audio_params_lock); + guard(mutex)(&tscs42xx->audio_params_lock); tscs42xx->samplerate = rate; - mutex_unlock(&tscs42xx->audio_params_lock); - return 0; } @@ -1253,12 +1232,10 @@ static int tscs42xx_set_dai_bclk_ratio(struct snd_soc_dai *codec_dai, return ret; } - mutex_lock(&tscs42xx->audio_params_lock); + guard(mutex)(&tscs42xx->audio_params_lock); tscs42xx->bclk_ratio = ratio; - mutex_unlock(&tscs42xx->audio_params_lock); - return 0; } diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c index aad394937ce6..b70c9d931e1e 100644 --- a/sound/soc/codecs/tscs454.c +++ b/sound/soc/codecs/tscs454.c @@ -4,6 +4,7 @@ // Author: Steven Eckhoff <steven.eckhoff.opensource@gmail.com> #include <linux/kernel.h> +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/device.h> #include <linux/regmap.h> @@ -329,12 +330,10 @@ static int coeff_ram_get(struct snd_kcontrol *kcontrol, return -EINVAL; } - mutex_lock(coeff_ram_lock); - - memcpy(ucontrol->value.bytes.data, - &coeff_ram[ctl->addr * COEFF_SIZE], params->max); - - mutex_unlock(coeff_ram_lock); + scoped_guard(mutex, coeff_ram_lock) { + memcpy(ucontrol->value.bytes.data, + &coeff_ram[ctl->addr * COEFF_SIZE], params->max); + } return 0; } @@ -428,15 +427,15 @@ static int coeff_ram_put(struct snd_kcontrol *kcontrol, return -EINVAL; } - mutex_lock(coeff_ram_lock); + guard(mutex)(coeff_ram_lock); *coeff_ram_synced = false; memcpy(&coeff_ram[ctl->addr * COEFF_SIZE], ucontrol->value.bytes.data, params->max); - mutex_lock(&tscs454->pll1.lock); - mutex_lock(&tscs454->pll2.lock); + guard(mutex)(&tscs454->pll1.lock); + guard(mutex)(&tscs454->pll2.lock); val = snd_soc_component_read(component, R_PLLSTAT); if (val) { /* PLLs locked */ @@ -446,18 +445,12 @@ static int coeff_ram_put(struct snd_kcontrol *kcontrol, if (ret < 0) { dev_err(component->dev, "Failed to flush coeff ram cache (%d)\n", ret); - goto exit; + return ret; } *coeff_ram_synced = true; } - ret = 0; -exit: - mutex_unlock(&tscs454->pll2.lock); - mutex_unlock(&tscs454->pll1.lock); - mutex_unlock(coeff_ram_lock); - - return ret; + return 0; } static inline int coeff_ram_sync(struct snd_soc_component *component, @@ -465,41 +458,35 @@ static inline int coeff_ram_sync(struct snd_soc_component *component, { int ret; - mutex_lock(&tscs454->dac_ram.lock); - if (!tscs454->dac_ram.synced) { - ret = write_coeff_ram(component, tscs454->dac_ram.cache, - R_DACCRS, R_DACCRADD, R_DACCRWDL, - 0x00, COEFF_RAM_COEFF_COUNT); - if (ret < 0) { - mutex_unlock(&tscs454->dac_ram.lock); - return ret; + scoped_guard(mutex, &tscs454->dac_ram.lock) { + if (!tscs454->dac_ram.synced) { + ret = write_coeff_ram(component, tscs454->dac_ram.cache, + R_DACCRS, R_DACCRADD, R_DACCRWDL, + 0x00, COEFF_RAM_COEFF_COUNT); + if (ret < 0) + return ret; } } - mutex_unlock(&tscs454->dac_ram.lock); - mutex_lock(&tscs454->spk_ram.lock); - if (!tscs454->spk_ram.synced) { - ret = write_coeff_ram(component, tscs454->spk_ram.cache, - R_SPKCRS, R_SPKCRADD, R_SPKCRWDL, - 0x00, COEFF_RAM_COEFF_COUNT); - if (ret < 0) { - mutex_unlock(&tscs454->spk_ram.lock); - return ret; + scoped_guard(mutex, &tscs454->spk_ram.lock) { + if (!tscs454->spk_ram.synced) { + ret = write_coeff_ram(component, tscs454->spk_ram.cache, + R_SPKCRS, R_SPKCRADD, R_SPKCRWDL, + 0x00, COEFF_RAM_COEFF_COUNT); + if (ret < 0) + return ret; } } - mutex_unlock(&tscs454->spk_ram.lock); - mutex_lock(&tscs454->sub_ram.lock); - if (!tscs454->sub_ram.synced) { - ret = write_coeff_ram(component, tscs454->sub_ram.cache, - R_SUBCRS, R_SUBCRADD, R_SUBCRWDL, - 0x00, COEFF_RAM_COEFF_COUNT); - if (ret < 0) { - mutex_unlock(&tscs454->sub_ram.lock); - return ret; + scoped_guard(mutex, &tscs454->sub_ram.lock) { + if (!tscs454->sub_ram.synced) { + ret = write_coeff_ram(component, tscs454->sub_ram.cache, + R_SUBCRS, R_SUBCRADD, R_SUBCRWDL, + 0x00, COEFF_RAM_COEFF_COUNT); + if (ret < 0) + return ret; } } - mutex_unlock(&tscs454->sub_ram.lock); return 0; } @@ -658,16 +645,14 @@ static int set_sysclk(struct snd_soc_component *component) static inline void reserve_pll(struct pll *pll) { - mutex_lock(&pll->lock); + guard(mutex)(&pll->lock); pll->users++; - mutex_unlock(&pll->lock); } static inline void free_pll(struct pll *pll) { - mutex_lock(&pll->lock); + guard(mutex)(&pll->lock); pll->users--; - mutex_unlock(&pll->lock); } static int pll_connected(struct snd_soc_dapm_widget *source, @@ -679,15 +664,13 @@ static int pll_connected(struct snd_soc_dapm_widget *source, int users; if (strstr(source->name, "PLL 1")) { - mutex_lock(&tscs454->pll1.lock); - users = tscs454->pll1.users; - mutex_unlock(&tscs454->pll1.lock); + scoped_guard(mutex, &tscs454->pll1.lock) + users = tscs454->pll1.users; dev_dbg(component->dev, "%s(): PLL 1 users = %d\n", __func__, users); } else { - mutex_lock(&tscs454->pll2.lock); - users = tscs454->pll2.users; - mutex_unlock(&tscs454->pll2.lock); + scoped_guard(mutex, &tscs454->pll2.lock) + users = tscs454->pll2.users; dev_dbg(component->dev, "%s(): PLL 2 users = %d\n", __func__, users); } @@ -806,7 +789,7 @@ static inline int aif_free(struct snd_soc_component *component, { struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component); - mutex_lock(&tscs454->aifs_status_lock); + guard(mutex)(&tscs454->aifs_status_lock); dev_dbg(component->dev, "%s(): aif %d\n", __func__, aif->id); @@ -829,8 +812,6 @@ static inline int aif_free(struct snd_soc_component *component, free_pll(tscs454->internal_rate.pll); } - mutex_unlock(&tscs454->aifs_status_lock); - return 0; } @@ -3174,7 +3155,7 @@ static int tscs454_hw_params(struct snd_pcm_substream *substream, unsigned int val; int ret; - mutex_lock(&tscs454->aifs_status_lock); + guard(mutex)(&tscs454->aifs_status_lock); dev_dbg(component->dev, "%s(): aif %d fs = %u\n", __func__, aif->id, fs); @@ -3207,14 +3188,14 @@ static int tscs454_hw_params(struct snd_pcm_substream *substream, ret = set_aif_fs(component, aif->id, fs); if (ret < 0) { dev_err(component->dev, "Failed to set aif fs (%d)\n", ret); - goto exit; + return ret; } ret = set_aif_sample_format(component, params_format(params), aif->id); if (ret < 0) { dev_err(component->dev, "Failed to set aif sample format (%d)\n", ret); - goto exit; + return ret; } set_aif_status_active(&tscs454->aifs_status, aif->id, @@ -3223,11 +3204,7 @@ static int tscs454_hw_params(struct snd_pcm_substream *substream, dev_dbg(component->dev, "Set aif %d active. Streams status is 0x%x\n", aif->id, tscs454->aifs_status.streams); - ret = 0; -exit: - mutex_unlock(&tscs454->aifs_status_lock); - - return ret; + return 0; } static int tscs454_hw_free(struct snd_pcm_substream *substream, diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index e10c51092a35..650836f9615f 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -8,6 +8,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/pm.h> #include <linux/platform_device.h> @@ -273,7 +274,7 @@ static void twl6040_hs_jack_report(struct snd_soc_component *component, struct twl6040_data *priv = snd_soc_component_get_drvdata(component); int status; - mutex_lock(&priv->mutex); + guard(mutex)(&priv->mutex); /* Sync status */ status = twl6040_read(component, TWL6040_REG_STATUS); @@ -281,8 +282,6 @@ static void twl6040_hs_jack_report(struct snd_soc_component *component, snd_soc_jack_report(jack, report, report); else snd_soc_jack_report(jack, 0, report); - - mutex_unlock(&priv->mutex); } void twl6040_hs_jack_detect(struct snd_soc_component *component, diff --git a/sound/soc/codecs/uda1342.c b/sound/soc/codecs/uda1342.c index 12f5757f4210..4e2d6240a869 100644 --- a/sound/soc/codecs/uda1342.c +++ b/sound/soc/codecs/uda1342.c @@ -308,9 +308,16 @@ static int uda1342_suspend(struct device *dev) static int uda1342_resume(struct device *dev) { struct uda1342_priv *uda1342 = dev_get_drvdata(dev); + int ret; + regcache_cache_only(uda1342->regmap, false); regcache_mark_dirty(uda1342->regmap); - regcache_sync(uda1342->regmap); + ret = regcache_sync(uda1342->regmap); + if (ret) { + regcache_cache_only(uda1342->regmap, true); + regcache_mark_dirty(uda1342->regmap); + return ret; + } return 0; } diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index e3ca5ca6de3d..40de279a9750 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -5010,9 +5010,9 @@ static int wcd9335_power_on_reset(struct wcd9335_codec *wcd) */ usleep_range(600, 650); - gpiod_set_value(wcd->reset_gpio, 1); + gpiod_set_value_cansleep(wcd->reset_gpio, 1); msleep(20); - gpiod_set_value(wcd->reset_gpio, 0); + gpiod_set_value_cansleep(wcd->reset_gpio, 0); msleep(20); return 0; diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index bc41a1466c70..caca5cc25100 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -1265,13 +1265,10 @@ static int wcd934x_set_sido_input_src(struct wcd934x_codec *wcd, int sido_src) static int wcd934x_enable_ana_bias_and_sysclk(struct wcd934x_codec *wcd) { - mutex_lock(&wcd->sysclk_mutex); - - if (++wcd->sysclk_users != 1) { - mutex_unlock(&wcd->sysclk_mutex); - return 0; + scoped_guard(mutex, &wcd->sysclk_mutex) { + if (++wcd->sysclk_users != 1) + return 0; } - mutex_unlock(&wcd->sysclk_mutex); regmap_update_bits(wcd->regmap, WCD934X_ANA_BIAS, WCD934X_ANA_BIAS_EN_MASK, @@ -1328,12 +1325,10 @@ static int wcd934x_enable_ana_bias_and_sysclk(struct wcd934x_codec *wcd) static int wcd934x_disable_ana_bias_and_syclk(struct wcd934x_codec *wcd) { - mutex_lock(&wcd->sysclk_mutex); - if (--wcd->sysclk_users != 0) { - mutex_unlock(&wcd->sysclk_mutex); - return 0; + scoped_guard(mutex, &wcd->sysclk_mutex) { + if (--wcd->sysclk_users != 0) + return 0; } - mutex_unlock(&wcd->sysclk_mutex); regmap_update_bits(wcd->regmap, WCD934X_CLK_SYS_MCLK_PRG, WCD934X_EXT_CLK_BUF_EN_MASK | @@ -2384,7 +2379,7 @@ static int wcd934x_micbias_control(struct snd_soc_component *component, __func__, micb_num); return -EINVAL; } - mutex_lock(&wcd934x->micb_lock); + guard(mutex)(&wcd934x->micb_lock); switch (req) { case MICB_PULLUP_ENABLE: @@ -2446,8 +2441,6 @@ static int wcd934x_micbias_control(struct snd_soc_component *component, break; } - mutex_unlock(&wcd934x->micb_lock); - return 0; } @@ -2488,7 +2481,7 @@ static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, int req_volt, int micb_num) { struct wcd934x_codec *wcd934x = snd_soc_component_get_drvdata(component); - int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en, ret = 0; + int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en; switch (micb_num) { case MIC_BIAS_1: @@ -2506,7 +2499,7 @@ static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, default: return -EINVAL; } - mutex_lock(&wcd934x->micb_lock); + guard(mutex)(&wcd934x->micb_lock); /* * If requested micbias voltage is same as current micbias * voltage, then just return. Otherwise, adjust voltage as @@ -2521,15 +2514,11 @@ static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, WCD934X_MICB_VAL_MASK); req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt); - if (req_vout_ctl < 0) { - ret = -EINVAL; - goto exit; - } + if (req_vout_ctl < 0) + return -EINVAL; - if (cur_vout_ctl == req_vout_ctl) { - ret = 0; - goto exit; - } + if (cur_vout_ctl == req_vout_ctl) + return 0; if (micb_en == WCD934X_MICB_ENABLE) snd_soc_component_write_field(component, micb_reg, @@ -2550,9 +2539,8 @@ static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, */ usleep_range(2000, 2100); } -exit: - mutex_unlock(&wcd934x->micb_lock); - return ret; + + return 0; } static int wcd934x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component, @@ -5899,10 +5887,8 @@ static int wcd934x_codec_probe(struct platform_device *pdev) } static const struct platform_device_id wcd934x_driver_id[] = { - { - .name = "wcd934x-codec", - }, - {}, + { .name = "wcd934x-codec" }, + { } }; MODULE_DEVICE_TABLE(platform, wcd934x_driver_id); diff --git a/sound/soc/codecs/wcd937x-sdw.c b/sound/soc/codecs/wcd937x-sdw.c index 7a18bed7f347..1ad75c226060 100644 --- a/sound/soc/codecs/wcd937x-sdw.c +++ b/sound/soc/codecs/wcd937x-sdw.c @@ -1084,10 +1084,16 @@ static int wcd937x_sdw_runtime_suspend(struct device *dev) static int wcd937x_sdw_runtime_resume(struct device *dev) { struct wcd937x_sdw_priv *wcd = dev_get_drvdata(dev); + int ret; if (wcd->regmap) { regcache_cache_only(wcd->regmap, false); - regcache_sync(wcd->regmap); + ret = regcache_sync(wcd->regmap); + if (ret) { + regcache_cache_only(wcd->regmap, true); + regcache_mark_dirty(wcd->regmap); + return ret; + } } return 0; diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index e0169e783ee9..0dd05604f5b8 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -2,6 +2,7 @@ // Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. #include <linux/component.h> +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/gpio/consumer.h> @@ -1056,7 +1057,7 @@ static int wcd937x_micbias_control(struct snd_soc_component *component, return -EINVAL; } - mutex_lock(&wcd937x->micb_lock); + guard(mutex)(&wcd937x->micb_lock); switch (req) { case MICB_PULLUP_ENABLE: wcd937x->pullup_ref[micb_index]++; @@ -1136,7 +1137,6 @@ static int wcd937x_micbias_control(struct snd_soc_component *component, } break; } - mutex_unlock(&wcd937x->micb_lock); return 0; } @@ -1460,7 +1460,7 @@ static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, int req_volt, int micb_num) { struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); - int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en, ret = 0; + int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en; switch (micb_num) { case MIC_BIAS_1: @@ -1475,7 +1475,7 @@ static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, default: return -EINVAL; } - mutex_lock(&wcd937x->micb_lock); + guard(mutex)(&wcd937x->micb_lock); /* * If requested micbias voltage is same as current micbias * voltage, then just return. Otherwise, adjust voltage as @@ -1490,15 +1490,11 @@ static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, WCD937X_MICB_VOUT_MASK); req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt); - if (req_vout_ctl < 0) { - ret = -EINVAL; - goto exit; - } + if (req_vout_ctl < 0) + return -EINVAL; - if (cur_vout_ctl == req_vout_ctl) { - ret = 0; - goto exit; - } + if (cur_vout_ctl == req_vout_ctl) + return 0; if (micb_en == WCD937X_MICB_ENABLE) snd_soc_component_write_field(component, micb_reg, @@ -1519,9 +1515,8 @@ static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, */ usleep_range(2000, 2100); } -exit: - mutex_unlock(&wcd937x->micb_lock); - return ret; + + return 0; } static int wcd937x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component, diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c index 0f0cc0ac3056..e5ad368418a2 100644 --- a/sound/soc/codecs/wcd938x-sdw.c +++ b/sound/soc/codecs/wcd938x-sdw.c @@ -1245,10 +1245,16 @@ static int wcd938x_sdw_runtime_suspend(struct device *dev) static int wcd938x_sdw_runtime_resume(struct device *dev) { struct wcd938x_sdw_priv *wcd = dev_get_drvdata(dev); + int ret; if (wcd->regmap) { regcache_cache_only(wcd->regmap, false); - regcache_sync(wcd->regmap); + ret = regcache_sync(wcd->regmap); + if (ret) { + regcache_cache_only(wcd->regmap, true); + regcache_mark_dirty(wcd->regmap); + return ret; + } } pm_runtime_mark_last_busy(dev); diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index c69e18667a85..9a9ea37ecab3 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only // Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/platform_device.h> @@ -1976,7 +1977,7 @@ static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, int req_volt, int micb_num) { struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); - int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en, ret = 0; + int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en; switch (micb_num) { case MIC_BIAS_1: @@ -1994,7 +1995,7 @@ static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, default: return -EINVAL; } - mutex_lock(&wcd938x->micb_lock); + guard(mutex)(&wcd938x->micb_lock); /* * If requested micbias voltage is same as current micbias * voltage, then just return. Otherwise, adjust voltage as @@ -2009,15 +2010,11 @@ static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, WCD938X_MICB_VOUT_MASK); req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt); - if (req_vout_ctl < 0) { - ret = -EINVAL; - goto exit; - } + if (req_vout_ctl < 0) + return -EINVAL; - if (cur_vout_ctl == req_vout_ctl) { - ret = 0; - goto exit; - } + if (cur_vout_ctl == req_vout_ctl) + return 0; if (micb_en == WCD938X_MICB_ENABLE) snd_soc_component_write_field(component, micb_reg, @@ -2038,9 +2035,8 @@ static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, */ usleep_range(2000, 2100); } -exit: - mutex_unlock(&wcd938x->micb_lock); - return ret; + + return 0; } static int wcd938x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component, diff --git a/sound/soc/codecs/wcd939x-sdw.c b/sound/soc/codecs/wcd939x-sdw.c index 95f4be287e79..69b9b08118f0 100644 --- a/sound/soc/codecs/wcd939x-sdw.c +++ b/sound/soc/codecs/wcd939x-sdw.c @@ -1431,10 +1431,16 @@ static int wcd939x_sdw_runtime_suspend(struct device *dev) static int wcd939x_sdw_runtime_resume(struct device *dev) { struct wcd939x_sdw_priv *wcd = dev_get_drvdata(dev); + int ret; if (wcd->regmap) { regcache_cache_only(wcd->regmap, false); - regcache_sync(wcd->regmap); + ret = regcache_sync(wcd->regmap); + if (ret) { + regcache_cache_only(wcd->regmap, true); + regcache_mark_dirty(wcd->regmap); + return ret; + } } return 0; diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c index 010d12466722..26fe0b6313cd 100644 --- a/sound/soc/codecs/wcd939x.c +++ b/sound/soc/codecs/wcd939x.c @@ -8,6 +8,7 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/platform_device.h> +#include <linux/cleanup.h> #include <linux/device.h> #include <linux/delay.h> #include <linux/gpio/consumer.h> @@ -1923,7 +1924,6 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); unsigned int micb_reg, cur_vout_ctl, micb_en; int req_vout_ctl; - int ret = 0; switch (micb_num) { case MIC_BIAS_1: @@ -1941,7 +1941,7 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, default: return -EINVAL; } - mutex_lock(&wcd939x->micb_lock); + guard(mutex)(&wcd939x->micb_lock); /* * If requested micbias voltage is same as current micbias @@ -1957,15 +1957,11 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, WCD939X_MICB_VOUT_CTL); req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt); - if (req_vout_ctl < 0) { - ret = req_vout_ctl; - goto exit; - } + if (req_vout_ctl < 0) + return req_vout_ctl; - if (cur_vout_ctl == req_vout_ctl) { - ret = 0; - goto exit; - } + if (cur_vout_ctl == req_vout_ctl) + return 0; 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), @@ -1990,9 +1986,7 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, usleep_range(2000, 2100); } -exit: - mutex_unlock(&wcd939x->micb_lock); - return ret; + return 0; } static int wcd939x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component, diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index 2a8c61a72c17..c44abffe9b56 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c @@ -9,6 +9,7 @@ * Scott Ling <sl@opensource.wolfsonmicro.com> */ +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/interrupt.h> @@ -148,13 +149,11 @@ static const char *wm0010_state_to_str(enum wm0010_state state) static void wm0010_halt(struct snd_soc_component *component) { struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component); - unsigned long flags; enum wm0010_state state; /* Fetch the wm0010 state */ - spin_lock_irqsave(&wm0010->irq_lock, flags); - state = wm0010->state; - spin_unlock_irqrestore(&wm0010->irq_lock, flags); + scoped_guard(spinlock_irqsave, &wm0010->irq_lock) + state = wm0010->state; switch (state) { case WM0010_POWER_OFF: @@ -173,9 +172,8 @@ static void wm0010_halt(struct snd_soc_component *component) break; } - spin_lock_irqsave(&wm0010->irq_lock, flags); - wm0010->state = WM0010_POWER_OFF; - spin_unlock_irqrestore(&wm0010->irq_lock, flags); + scoped_guard(spinlock_irqsave, &wm0010->irq_lock) + wm0010->state = WM0010_POWER_OFF; } struct wm0010_boot_xfer { @@ -190,11 +188,9 @@ struct wm0010_boot_xfer { static void wm0010_mark_boot_failure(struct wm0010_priv *wm0010) { enum wm0010_state state; - unsigned long flags; - spin_lock_irqsave(&wm0010->irq_lock, flags); - state = wm0010->state; - spin_unlock_irqrestore(&wm0010->irq_lock, flags); + scoped_guard(spinlock_irqsave, &wm0010->irq_lock) + state = wm0010->state; dev_err(wm0010->dev, "Failed to transition from `%s' state to `%s' state\n", wm0010_state_to_str(state), wm0010_state_to_str(state + 1)); @@ -337,7 +333,6 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp struct wm0010_boot_xfer *xfer; int ret; DECLARE_COMPLETION_ONSTACK(done); - const struct firmware *fw; const struct dfw_binrec *rec; const struct dfw_inforec *inforec; u64 *img; @@ -346,6 +341,7 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp INIT_LIST_HEAD(&xfer_list); + const struct firmware *fw __free(firmware) = NULL; ret = request_firmware(&fw, name, component->dev); if (ret != 0) { dev_err(component->dev, "Failed to request application(%s): %d\n", @@ -364,16 +360,14 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp /* First record should be INFO */ if (rec->command != DFW_CMD_INFO) { dev_err(component->dev, "First record not INFO\r\n"); - ret = -EINVAL; - goto abort; + return -EINVAL; } if (inforec->info_version != INFO_VERSION) { dev_err(component->dev, "Unsupported version (%02d) of INFO record\r\n", inforec->info_version); - ret = -EINVAL; - goto abort; + return -EINVAL; } dev_dbg(component->dev, "Version v%02d INFO record found\r\n", @@ -382,8 +376,7 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp /* Check it's a DSP file */ if (dsp != DEVICE_ID_WM0010) { dev_err(component->dev, "Not a WM0010 firmware file.\r\n"); - ret = -EINVAL; - goto abort; + return -EINVAL; } /* Skip the info record as we don't need to send it */ @@ -408,14 +401,14 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp out = kzalloc(len, GFP_KERNEL | GFP_DMA); if (!out) { ret = -ENOMEM; - goto abort1; + goto abort; } xfer->t.rx_buf = out; img = kzalloc(len, GFP_KERNEL | GFP_DMA); if (!img) { ret = -ENOMEM; - goto abort1; + goto abort; } xfer->t.tx_buf = img; @@ -453,13 +446,13 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp ret = spi_async(spi, &xfer->m); if (ret != 0) { dev_err(component->dev, "Write failed: %d\n", ret); - goto abort1; + goto abort; } if (wm0010->boot_failed) { dev_dbg(component->dev, "Boot fail!\n"); ret = -EINVAL; - goto abort1; + goto abort; } } @@ -467,7 +460,7 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp ret = 0; -abort1: +abort: while (!list_empty(&xfer_list)) { xfer = list_first_entry(&xfer_list, struct wm0010_boot_xfer, list); @@ -477,8 +470,6 @@ abort1: kfree(xfer); } -abort: - release_firmware(fw); return ret; } @@ -486,14 +477,12 @@ static int wm0010_stage2_load(struct snd_soc_component *component) { struct spi_device *spi = to_spi_device(component->dev); struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component); - const struct firmware *fw; struct spi_message m; struct spi_transfer t; - u32 *img; - u8 *out; int i; int ret = 0; + const struct firmware *fw __free(firmware) = NULL; ret = request_firmware(&fw, "wm0010_stage2.bin", component->dev); if (ret != 0) { dev_err(component->dev, "Failed to request stage2 loader: %d\n", @@ -504,17 +493,15 @@ static int wm0010_stage2_load(struct snd_soc_component *component) dev_dbg(component->dev, "Downloading %zu byte stage 2 loader\n", fw->size); /* Copy to local buffer first as vmalloc causes problems for dma */ - img = kmemdup(&fw->data[0], fw->size, GFP_KERNEL | GFP_DMA); - if (!img) { - ret = -ENOMEM; - goto abort2; - } + u32 *img __free(kfree) = + kmemdup(&fw->data[0], fw->size, GFP_KERNEL | GFP_DMA); + if (!img) + return -ENOMEM; - out = kzalloc(fw->size, GFP_KERNEL | GFP_DMA); - if (!out) { - ret = -ENOMEM; - goto abort1; - } + u8 *out __free(kfree) = + kzalloc(fw->size, GFP_KERNEL | GFP_DMA); + if (!out) + return -ENOMEM; spi_message_init(&m); memset(&t, 0, sizeof(t)); @@ -531,7 +518,7 @@ static int wm0010_stage2_load(struct snd_soc_component *component) ret = spi_sync(spi, &m); if (ret != 0) { dev_err(component->dev, "Initial download failed: %d\n", ret); - goto abort; + return ret; } /* Look for errors from the boot ROM */ @@ -540,18 +527,11 @@ static int wm0010_stage2_load(struct snd_soc_component *component) dev_err(component->dev, "Boot ROM error: %x in %d\n", out[i], i); wm0010_mark_boot_failure(wm0010); - ret = -EBUSY; - goto abort; + return -EBUSY; } } -abort: - kfree(out); -abort1: - kfree(img); -abort2: - release_firmware(fw); - return ret; + return 0; } static int wm0010_boot(struct snd_soc_component *component) @@ -734,9 +714,8 @@ static int wm0010_set_bias_level(struct snd_soc_component *component, break; case SND_SOC_BIAS_STANDBY: if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_PREPARE) { - mutex_lock(&wm0010->lock); - wm0010_halt(component); - mutex_unlock(&wm0010->lock); + scoped_guard(mutex, &wm0010->lock) + wm0010_halt(component); } break; case SND_SOC_BIAS_OFF: @@ -832,9 +811,8 @@ static irqreturn_t wm0010_irq(int irq, void *data) case WM0010_OUT_OF_RESET: case WM0010_BOOTROM: case WM0010_STAGE2: - spin_lock(&wm0010->irq_lock); - complete(&wm0010->boot_completion); - spin_unlock(&wm0010->irq_lock); + scoped_guard(spinlock, &wm0010->irq_lock) + complete(&wm0010->boot_completion); return IRQ_HANDLED; default: return IRQ_NONE; diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 9b68ee69324b..41c8cfb346c6 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -23,6 +23,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/firmware.h> +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/pm.h> @@ -612,20 +613,15 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev); unsigned int anc_active = ucontrol->value.integer.value[0]; - int ret; if (anc_active > 1) return -EINVAL; - mutex_lock(&wm2000->lock); + guard(mutex)(&wm2000->lock); wm2000->anc_active = anc_active; - ret = wm2000_anc_set_mode(wm2000); - - mutex_unlock(&wm2000->lock); - - return ret; + return wm2000_anc_set_mode(wm2000); } static int wm2000_speaker_get(struct snd_kcontrol *kcontrol, @@ -645,20 +641,15 @@ static int wm2000_speaker_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev); unsigned int val = ucontrol->value.integer.value[0]; - int ret; if (val > 1) return -EINVAL; - mutex_lock(&wm2000->lock); + guard(mutex)(&wm2000->lock); wm2000->spk_ena = val; - ret = wm2000_anc_set_mode(wm2000); - - mutex_unlock(&wm2000->lock); - - return ret; + return wm2000_anc_set_mode(wm2000); } static const struct snd_kcontrol_new wm2000_controls[] = { @@ -676,9 +667,8 @@ static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w, { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev); - int ret; - mutex_lock(&wm2000->lock); + guard(mutex)(&wm2000->lock); if (SND_SOC_DAPM_EVENT_ON(event)) wm2000->anc_eng_ena = 1; @@ -686,11 +676,7 @@ static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w, if (SND_SOC_DAPM_EVENT_OFF(event)) wm2000->anc_eng_ena = 0; - ret = wm2000_anc_set_mode(wm2000); - - mutex_unlock(&wm2000->lock); - - return ret; + return wm2000_anc_set_mode(wm2000); } static const struct snd_soc_dapm_widget wm2000_dapm_widgets[] = { @@ -810,7 +796,7 @@ static int wm2000_i2c_probe(struct i2c_client *i2c) struct wm2000_priv *wm2000; struct wm2000_platform_data *pdata; const char *filename; - const struct firmware *fw = NULL; + const struct firmware *fw __free(firmware) = NULL; int ret, i; unsigned int reg; u16 id; @@ -828,7 +814,7 @@ static int wm2000_i2c_probe(struct i2c_client *i2c) ret = PTR_ERR(wm2000->regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ret); - goto out; + return ret; } for (i = 0; i < WM2000_NUM_SUPPLIES; i++) @@ -922,9 +908,6 @@ static int wm2000_i2c_probe(struct i2c_client *i2c) err_supplies: regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies); - -out: - release_firmware(fw); return ret; } diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index ba8ce2e6e615..bc78b553b6cb 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -2461,7 +2461,15 @@ static int wm2200_runtime_resume(struct device *dev) } regcache_cache_only(wm2200->regmap, false); - regcache_sync(wm2200->regmap); + ret = regcache_sync(wm2200->regmap); + if (ret) { + regcache_cache_only(wm2200->regmap, true); + regcache_mark_dirty(wm2200->regmap); + gpiod_set_value_cansleep(wm2200->ldo_ena, 0); + regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies), + wm2200->core_supplies); + return ret; + } return 0; } diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index bd94fa53c362..2fe937a93026 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -2659,7 +2659,15 @@ static int wm5100_runtime_resume(struct device *dev) } regcache_cache_only(wm5100->regmap, false); - regcache_sync(wm5100->regmap); + ret = regcache_sync(wm5100->regmap); + if (ret) { + regcache_cache_only(wm5100->regmap, true); + regcache_mark_dirty(wm5100->regmap); + gpiod_set_value_cansleep(wm5100->ldo_ena, 0); + regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies), + wm5100->core_supplies); + return ret; + } return 0; } diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index b4d4137c05b4..74b775b95bfd 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -7,6 +7,7 @@ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> */ +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> @@ -667,10 +668,9 @@ static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct arizona *arizona = dev_get_drvdata(component->dev->parent); - mutex_lock(&arizona->dac_comp_lock); + guard(mutex)(&arizona->dac_comp_lock); put_unaligned_be16(arizona->dac_comp_coeff, ucontrol->value.bytes.data); - mutex_unlock(&arizona->dac_comp_lock); return 0; } @@ -681,16 +681,14 @@ static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct arizona *arizona = dev_get_drvdata(component->dev->parent); uint16_t dac_comp_coeff = get_unaligned_be16(ucontrol->value.bytes.data); - int ret = 0; - mutex_lock(&arizona->dac_comp_lock); + guard(mutex)(&arizona->dac_comp_lock); if (arizona->dac_comp_coeff != dac_comp_coeff) { arizona->dac_comp_coeff = dac_comp_coeff; - ret = 1; + return 1; } - mutex_unlock(&arizona->dac_comp_lock); - return ret; + return 0; } static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol, @@ -699,9 +697,8 @@ static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct arizona *arizona = dev_get_drvdata(component->dev->parent); - mutex_lock(&arizona->dac_comp_lock); + guard(mutex)(&arizona->dac_comp_lock); ucontrol->value.integer.value[0] = arizona->dac_comp_enabled; - mutex_unlock(&arizona->dac_comp_lock); return 0; } @@ -712,19 +709,17 @@ static int wm5102_out_comp_switch_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct arizona *arizona = dev_get_drvdata(component->dev->parent); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - int ret = 0; if (ucontrol->value.integer.value[0] > mc->max) return -EINVAL; - mutex_lock(&arizona->dac_comp_lock); + guard(mutex)(&arizona->dac_comp_lock); if (arizona->dac_comp_enabled != ucontrol->value.integer.value[0]) { arizona->dac_comp_enabled = ucontrol->value.integer.value[0]; - ret = 1; + return 1; } - mutex_unlock(&arizona->dac_comp_lock); - return ret; + return 0; } static const char * const wm5102_osr_text[] = { diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index a2f0e2f5c407..ce87280d590d 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -10,6 +10,7 @@ * Based on wm8753.c by Liam Girdwood */ +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> @@ -110,22 +111,20 @@ static int wm8731_put_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component); unsigned int deemph = ucontrol->value.integer.value[0]; - int ret = 0; if (deemph > 1) return -EINVAL; - mutex_lock(&wm8731->lock); + guard(mutex)(&wm8731->lock); if (wm8731->deemph != deemph) { wm8731->deemph = deemph; wm8731_set_deemph(component); - ret = 1; + return 1; } - mutex_unlock(&wm8731->lock); - return ret; + return 0; } static const DECLARE_TLV_DB_SCALE(in_tlv, -3450, 150, 0); diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 320d7737699d..156e1e24a388 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -14,6 +14,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> +#include <linux/cleanup.h> #include <linux/completion.h> #include <linux/delay.h> #include <linux/gpio/driver.h> @@ -458,22 +459,20 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component); unsigned int deemph = ucontrol->value.integer.value[0]; - int ret = 0; if (deemph > 1) return -EINVAL; - mutex_lock(&wm8903->lock); + guard(mutex)(&wm8903->lock); if (wm8903->deemph != deemph) { wm8903->deemph = deemph; wm8903_set_deemph(component); - ret = 1; + return 1; } - mutex_unlock(&wm8903->lock); - return ret; + return 0; } /* ALSA can only do steps of .01dB */ diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index e631ec072249..229252363188 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -333,7 +333,7 @@ static const struct snd_soc_dapm_route wm8940_dapm_routes[] = { {"ADC", NULL, "Boost Mixer"}, }; -#define wm8940_reset(c) snd_soc_component_write(c, WM8940_SOFTRESET, 0); +#define wm8940_reset(c) snd_soc_component_write(c, WM8940_SOFTRESET, 0) static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index 8ff0882732e7..f75a6dc9d2bb 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c @@ -7,6 +7,7 @@ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> */ +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> @@ -864,9 +865,8 @@ static void wm8958_enh_eq_loaded(const struct firmware *fw, void *context) struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); if (fw && (wm8958_dsp2_fw(component, "ENH_EQ", fw, true) == 0)) { - mutex_lock(&wm8994->fw_lock); + guard(mutex)(&wm8994->fw_lock); wm8994->enh_eq = fw; - mutex_unlock(&wm8994->fw_lock); } } @@ -876,9 +876,8 @@ static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context) struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); if (fw && (wm8958_dsp2_fw(component, "MBC+VSS", fw, true) == 0)) { - mutex_lock(&wm8994->fw_lock); + guard(mutex)(&wm8994->fw_lock); wm8994->mbc_vss = fw; - mutex_unlock(&wm8994->fw_lock); } } @@ -888,9 +887,8 @@ static void wm8958_mbc_loaded(const struct firmware *fw, void *context) struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); if (fw && (wm8958_dsp2_fw(component, "MBC", fw, true) == 0)) { - mutex_lock(&wm8994->fw_lock); + guard(mutex)(&wm8994->fw_lock); wm8994->mbc = fw; - mutex_unlock(&wm8994->fw_lock); } } diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index de18b1f85a32..8a9598161b35 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -10,6 +10,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/pm.h> @@ -1564,11 +1565,10 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); int old = wm8962->dsp2_ena; - int ret = 0; int dsp2_running = snd_soc_component_read(component, WM8962_DSP2_POWER_MANAGEMENT) & WM8962_DSP2_ENA; - mutex_lock(&wm8962->dsp2_ena_lock); + guard(mutex)(&wm8962->dsp2_ena_lock); if (ucontrol->value.integer.value[0]) wm8962->dsp2_ena |= 1 << shift; @@ -1576,9 +1576,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol, wm8962->dsp2_ena &= ~(1 << shift); if (wm8962->dsp2_ena == old) - goto out; - - ret = 1; + return 0; if (dsp2_running) { if (wm8962->dsp2_ena) @@ -1587,10 +1585,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol, wm8962_dsp2_stop(component); } -out: - mutex_unlock(&wm8962->dsp2_ena_lock); - - return ret; + return 1; } /* The VU bits for the headphones are in a different register to the mute @@ -3937,7 +3932,9 @@ static int wm8962_runtime_resume(struct device *dev) WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA, 0); - regcache_sync(wm8962->regmap); + ret = regcache_sync(wm8962->regmap); + if (ret) + goto cache_sync_err; regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP, WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA, @@ -3955,6 +3952,11 @@ static int wm8962_runtime_resume(struct device *dev) return 0; +cache_sync_err: + regcache_cache_only(wm8962->regmap, true); + regcache_mark_dirty(wm8962->regmap); + regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), + wm8962->supplies); disable_clock: clk_disable_unprepare(wm8962->pdata.mclk); return ret; diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 1d64c7c42ed1..8bf58a6a8af7 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -7,6 +7,7 @@ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> */ +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> @@ -766,7 +767,7 @@ static void active_reference(struct snd_soc_component *component) { struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); - mutex_lock(&wm8994->accdet_lock); + guard(mutex)(&wm8994->accdet_lock); wm8994->active_refcount++; @@ -775,8 +776,6 @@ static void active_reference(struct snd_soc_component *component) /* If we're using jack detection go into audio mode */ wm1811_jackdet_set_mode(component, WM1811_JACKDET_MODE_AUDIO); - - mutex_unlock(&wm8994->accdet_lock); } static void active_dereference(struct snd_soc_component *component) @@ -784,7 +783,7 @@ static void active_dereference(struct snd_soc_component *component) struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); u16 mode; - mutex_lock(&wm8994->accdet_lock); + guard(mutex)(&wm8994->accdet_lock); wm8994->active_refcount--; @@ -800,8 +799,6 @@ static void active_dereference(struct snd_soc_component *component) wm1811_jackdet_set_mode(component, mode); } - - mutex_unlock(&wm8994->accdet_lock); } static int clk_sys_event(struct snd_soc_dapm_widget *w, @@ -3704,7 +3701,7 @@ static void wm8958_open_circuit_work(struct work_struct *work) open_circuit_work.work); struct device *dev = wm8994->wm8994->dev; - mutex_lock(&wm8994->accdet_lock); + guard(mutex)(&wm8994->accdet_lock); wm1811_micd_stop(wm8994->hubs.component); @@ -3718,8 +3715,6 @@ static void wm8958_open_circuit_work(struct work_struct *work) snd_soc_jack_report(wm8994->micdet[0].jack, 0, wm8994->btn_mask | SND_JACK_HEADSET); - - mutex_unlock(&wm8994->accdet_lock); } static void wm8958_mic_id(void *data, u16 status) @@ -3777,7 +3772,7 @@ static void wm1811_mic_work(struct work_struct *work) struct snd_soc_component *component = wm8994->hubs.component; struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); - pm_runtime_get_sync(component->dev); + guard(pm_runtime_active)(component->dev); /* If required for an external cap force MICBIAS on */ if (control->pdata.jd_ext_cap) { @@ -3785,7 +3780,7 @@ static void wm1811_mic_work(struct work_struct *work) snd_soc_dapm_sync(dapm); } - mutex_lock(&wm8994->accdet_lock); + guard(mutex)(&wm8994->accdet_lock); dev_dbg(component->dev, "Starting mic detection\n"); @@ -3803,10 +3798,6 @@ static void wm1811_mic_work(struct work_struct *work) snd_soc_component_update_bits(component, WM8958_MIC_DETECT_1, WM8958_MICD_ENA, WM8958_MICD_ENA); } - - mutex_unlock(&wm8994->accdet_lock); - - pm_runtime_put(component->dev); } static irqreturn_t wm1811_jackdet_irq(int irq, void *data) @@ -4026,15 +4017,10 @@ static void wm8958_mic_work(struct work_struct *work) mic_complete_work.work); struct snd_soc_component *component = wm8994->hubs.component; - pm_runtime_get_sync(component->dev); - - mutex_lock(&wm8994->accdet_lock); + guard(pm_runtime_active)(component->dev); + guard(mutex)(&wm8994->accdet_lock); wm8994->mic_id_cb(wm8994->mic_id_cb_data, wm8994->mic_status); - - mutex_unlock(&wm8994->accdet_lock); - - pm_runtime_put(component->dev); } static irqreturn_t wm8958_mic_irq(int irq, void *data) diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 83cd42fa0c28..3105b2e0556f 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -6,6 +6,7 @@ * Author: Liam Girdwood <lrg@slimlogic.co.uk> */ +#include <linux/cleanup.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/mfd/wm97xx.h> @@ -229,7 +230,7 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol, shift = mc->shift & 0xff; mask = 1 << shift; - mutex_lock(&wm9712->lock); + guard(mutex)(&wm9712->lock); old = wm9712->hp_mixer[mixer]; if (ucontrol->value.integer.value[0]) wm9712->hp_mixer[mixer] |= mask; @@ -251,8 +252,6 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol, &update); } - mutex_unlock(&wm9712->lock); - return change; } diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index b3bbecf074ee..3ba7ca3c1770 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -11,6 +11,7 @@ * o Support for DAPM */ +#include <linux/cleanup.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/mfd/wm97xx.h> @@ -238,7 +239,7 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol, shift = mc->shift & 0xff; mask = (1 << shift); - mutex_lock(&wm9713->lock); + guard(mutex)(&wm9713->lock); old = wm9713->hp_mixer[mixer]; if (ucontrol->value.integer.value[0]) wm9713->hp_mixer[mixer] |= mask; @@ -260,8 +261,6 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol, &update); } - mutex_unlock(&wm9713->lock); - return change; } diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index baa75e7ff53b..90c24c4b318e 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -348,7 +348,6 @@ int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct wm_adsp *dsp = snd_soc_component_get_drvdata(component); - int ret = 1; if (ucontrol->value.enumerated.item[0] == dsp[e->shift_l].fw) return 0; @@ -356,16 +355,14 @@ int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, if (ucontrol->value.enumerated.item[0] >= WM_ADSP_NUM_FW) return -EINVAL; - mutex_lock(&dsp[e->shift_l].cs_dsp.pwr_lock); + guard(mutex)(&dsp[e->shift_l].cs_dsp.pwr_lock); if (dsp[e->shift_l].cs_dsp.booted || !list_empty(&dsp[e->shift_l].compr_list)) - ret = -EBUSY; + return -EBUSY; else dsp[e->shift_l].fw = ucontrol->value.enumerated.item[0]; - mutex_unlock(&dsp[e->shift_l].cs_dsp.pwr_lock); - - return ret; + return 1; } EXPORT_SYMBOL_GPL(wm_adsp_fw_put); @@ -450,15 +447,13 @@ static int wm_coeff_put_acked(struct snd_kcontrol *kctl, if (val == 0) return 0; /* 0 means no event */ - mutex_lock(&cs_ctl->dsp->pwr_lock); + guard(mutex)(&cs_ctl->dsp->pwr_lock); if (cs_ctl->enabled) ret = cs_dsp_coeff_write_acked_control(cs_ctl, val); else ret = -EPERM; - mutex_unlock(&cs_ctl->dsp->pwr_lock); - if (ret < 0) return ret; @@ -486,15 +481,13 @@ static int wm_coeff_tlv_get(struct snd_kcontrol *kctl, struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl; int ret = 0; - mutex_lock(&cs_ctl->dsp->pwr_lock); + guard(mutex)(&cs_ctl->dsp->pwr_lock); ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, cs_ctl->cache, size); if (!ret && copy_to_user(bytes, cs_ctl->cache, size)) ret = -EFAULT; - mutex_unlock(&cs_ctl->dsp->pwr_lock); - return ret; } @@ -694,10 +687,9 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type, struct cs_dsp_coeff_ctl *cs_ctl; int ret; - mutex_lock(&dsp->cs_dsp.pwr_lock); + guard(mutex)(&dsp->cs_dsp.pwr_lock); cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg); ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len); - mutex_unlock(&dsp->cs_dsp.pwr_lock); if (ret < 0) return ret; @@ -709,14 +701,10 @@ EXPORT_SYMBOL_GPL(wm_adsp_write_ctl); int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type, unsigned int alg, void *buf, size_t len) { - int ret; + guard(mutex)(&dsp->cs_dsp.pwr_lock); - mutex_lock(&dsp->cs_dsp.pwr_lock); - ret = cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg), + return cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg), 0, buf, len); - mutex_unlock(&dsp->cs_dsp.pwr_lock); - - return ret; } EXPORT_SYMBOL_GPL(wm_adsp_read_ctl); @@ -1270,38 +1258,32 @@ int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) { struct wm_adsp_compr *compr, *tmp; struct snd_soc_pcm_runtime *rtd = stream->private_data; - int ret = 0; - mutex_lock(&dsp->cs_dsp.pwr_lock); + guard(mutex)(&dsp->cs_dsp.pwr_lock); if (wm_adsp_fw[dsp->fw].num_caps == 0) { adsp_err(dsp, "%s: Firmware does not support compressed API\n", snd_soc_rtd_to_codec(rtd, 0)->name); - ret = -ENXIO; - goto out; + return -ENXIO; } if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) { adsp_err(dsp, "%s: Firmware does not support stream direction\n", snd_soc_rtd_to_codec(rtd, 0)->name); - ret = -EINVAL; - goto out; + return -EINVAL; } list_for_each_entry(tmp, &dsp->compr_list, list) { if (!strcmp(tmp->name, snd_soc_rtd_to_codec(rtd, 0)->name)) { adsp_err(dsp, "%s: Only a single stream supported per dai\n", snd_soc_rtd_to_codec(rtd, 0)->name); - ret = -EBUSY; - goto out; + return -EBUSY; } } compr = kzalloc_obj(*compr); - if (!compr) { - ret = -ENOMEM; - goto out; - } + if (!compr) + return -ENOMEM; compr->dsp = dsp; compr->stream = stream; @@ -1311,10 +1293,7 @@ int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) stream->runtime->private_data = compr; -out: - mutex_unlock(&dsp->cs_dsp.pwr_lock); - - return ret; + return 0; } EXPORT_SYMBOL_GPL(wm_adsp_compr_open); @@ -1324,7 +1303,7 @@ int wm_adsp_compr_free(struct snd_soc_component *component, struct wm_adsp_compr *compr = stream->runtime->private_data; struct wm_adsp *dsp = compr->dsp; - mutex_lock(&dsp->cs_dsp.pwr_lock); + guard(mutex)(&dsp->cs_dsp.pwr_lock); wm_adsp_compr_detach(compr); list_del(&compr->list); @@ -1332,8 +1311,6 @@ int wm_adsp_compr_free(struct snd_soc_component *component, kfree(compr->raw_buf); kfree(compr); - mutex_unlock(&dsp->cs_dsp.pwr_lock); - return 0; } EXPORT_SYMBOL_GPL(wm_adsp_compr_free); @@ -1741,7 +1718,7 @@ int wm_adsp_compr_trigger(struct snd_soc_component *component, compr_dbg(compr, "Trigger: %d\n", cmd); - mutex_lock(&dsp->cs_dsp.pwr_lock); + guard(mutex)(&dsp->cs_dsp.pwr_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -1777,8 +1754,6 @@ int wm_adsp_compr_trigger(struct snd_soc_component *component, break; } - mutex_unlock(&dsp->cs_dsp.pwr_lock); - return ret; } EXPORT_SYMBOL_GPL(wm_adsp_compr_trigger); @@ -1907,21 +1882,20 @@ int wm_adsp_compr_pointer(struct snd_soc_component *component, compr_dbg(compr, "Pointer request\n"); - mutex_lock(&dsp->cs_dsp.pwr_lock); + guard(mutex)(&dsp->cs_dsp.pwr_lock); buf = compr->buf; if (dsp->fatal_error || !buf || buf->error) { snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN); - ret = -EIO; - goto out; + return -EIO; } if (buf->avail < wm_adsp_compr_frag_words(compr)) { ret = wm_adsp_buffer_update_avail(buf); if (ret < 0) { compr_err(compr, "Error reading avail: %d\n", ret); - goto out; + return ret; } /* @@ -1934,14 +1908,14 @@ int wm_adsp_compr_pointer(struct snd_soc_component *component, if (buf->error) snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN); - goto out; + return ret; } ret = wm_adsp_buffer_reenable_irq(buf); if (ret < 0) { compr_err(compr, "Failed to re-enable buffer IRQ: %d\n", ret); - goto out; + return ret; } } } @@ -1950,9 +1924,6 @@ int wm_adsp_compr_pointer(struct snd_soc_component *component, tstamp->copied_total += buf->avail * CS_DSP_DATA_WORD_SIZE; tstamp->sampling_rate = compr->sample_rate; -out: - mutex_unlock(&dsp->cs_dsp.pwr_lock); - return ret; } EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer); @@ -2063,15 +2034,13 @@ int wm_adsp_compr_copy(struct snd_soc_component *component, struct wm_adsp *dsp = compr->dsp; int ret; - mutex_lock(&dsp->cs_dsp.pwr_lock); + guard(mutex)(&dsp->cs_dsp.pwr_lock); if (stream->direction == SND_COMPRESS_CAPTURE) ret = wm_adsp_compr_read(compr, buf, count); else ret = -ENOTSUPP; - mutex_unlock(&dsp->cs_dsp.pwr_lock); - return ret; } EXPORT_SYMBOL_GPL(wm_adsp_compr_copy); diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index 5174614c3e83..47ac3e4985a5 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -1178,7 +1178,13 @@ static int wsa881x_runtime_resume(struct device *dev) } regcache_cache_only(regmap, false); - regcache_sync(regmap); + ret = regcache_sync(regmap); + if (ret) { + regcache_cache_only(regmap, true); + regcache_mark_dirty(regmap); + gpiod_direction_output(wsa881x->sd_n, 1); + return ret; + } return 0; } diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index 468d2b38a22a..442cf9f3eaac 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -4,6 +4,7 @@ */ #include <linux/bitops.h> +#include <linux/cleanup.h> #include <linux/device.h> #include <linux/gpio/consumer.h> #include <linux/hwmon.h> @@ -1237,9 +1238,8 @@ static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: - mutex_lock(&wsa883x->sp_lock); - wsa883x->pa_on = true; - mutex_unlock(&wsa883x->sp_lock); + scoped_guard(mutex, &wsa883x->sp_lock) + wsa883x->pa_on = true; switch (wsa883x->dev_mode) { case RECEIVER: @@ -1290,9 +1290,8 @@ static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w, WSA883X_GLOBAL_PA_EN_MASK, 0); snd_soc_component_write_field(component, WSA883X_PDM_WD_CTL, WSA883X_PDM_EN_MASK, 0); - mutex_lock(&wsa883x->sp_lock); - wsa883x->pa_on = false; - mutex_unlock(&wsa883x->sp_lock); + scoped_guard(mutex, &wsa883x->sp_lock) + wsa883x->pa_on = false; break; } return 0; @@ -1696,9 +1695,15 @@ static int wsa883x_runtime_suspend(struct device *dev) static int wsa883x_runtime_resume(struct device *dev) { struct regmap *regmap = dev_get_regmap(dev, NULL); + int ret; regcache_cache_only(regmap, false); - regcache_sync(regmap); + ret = regcache_sync(regmap); + if (ret) { + regcache_cache_only(regmap, true); + regcache_mark_dirty(regmap); + return ret; + } return 0; } diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c index 6c6b497657d0..a367c94bfb4d 100644 --- a/sound/soc/codecs/wsa884x.c +++ b/sound/soc/codecs/wsa884x.c @@ -1701,9 +1701,8 @@ static int wsa884x_spkr_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: - mutex_lock(&wsa884x->sp_lock); - wsa884x->pa_on = true; - mutex_unlock(&wsa884x->sp_lock); + scoped_guard(mutex, &wsa884x->sp_lock) + wsa884x->pa_on = true; wsa884x_spkr_post_pmu(component, wsa884x); @@ -1717,9 +1716,8 @@ static int wsa884x_spkr_event(struct snd_soc_dapm_widget *w, WSA884X_PDM_WD_CTL_PDM_WD_EN_MASK, 0x0); - mutex_lock(&wsa884x->sp_lock); - wsa884x->pa_on = false; - mutex_unlock(&wsa884x->sp_lock); + scoped_guard(mutex, &wsa884x->sp_lock) + wsa884x->pa_on = false; break; } @@ -2147,9 +2145,15 @@ static int wsa884x_runtime_suspend(struct device *dev) static int wsa884x_runtime_resume(struct device *dev) { struct regmap *regmap = dev_get_regmap(dev, NULL); + int ret; regcache_cache_only(regmap, false); - regcache_sync(regmap); + ret = regcache_sync(regmap); + if (ret) { + regcache_cache_only(regmap, true); + regcache_mark_dirty(regmap); + return ret; + } return 0; } diff --git a/sound/soc/codecs/wsa885x.c b/sound/soc/codecs/wsa885x.c new file mode 100644 index 000000000000..1faa8541a872 --- /dev/null +++ b/sound/soc/codecs/wsa885x.c @@ -0,0 +1,1533 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +/* WSA885X codec driver */ + +#include <linux/bitfield.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/mutex.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/reset.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/tlv.h> + +/* Control Registers - Audio Processing */ +#define WSA885X_SMP_AMP_CTRL_STEREO_STEREO_SMP_AMP_CTRL_I2S 0x0000 +#define WSA885X_SMP_AMP_CTRL_STEREO_CMT_GRP_MASK 0x0004 +#define WSA885X_SMP_AMP_CTRL_STEREO_IT21_CLUSERINDEX 0x0140 +#define WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID 0x0208 +#define WSA885X_SMP_AMP_CTRL_STEREO_CS21_SAMPLERATEINDEX 0x0240 +#define WSA885X_SMP_AMP_CTRL_STEREO_PPU21_POSTURENUMBER 0x0340 +#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X0 0x4405 +#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X1 0x4406 +#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_LSB 0x4409 +#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_MSB 0x6409 +#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_LSB 0x440a +#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_MSB 0x640a +#define WSA885X_SMP_AMP_CTRL_STEREO_PDE23_REQ_PS 0x0a04 +#define WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS 0x0a40 +#define WSA885X_SMP_AMP_CTRL_STEREO_OT23_USAGE 0x0b10 +#define WSA885X_SMP_AMP_CTRL_STEREO_CS24_SAMPLERATEINDEX 0x0e40 + +/* Analog Top Registers - Power and Clock Control */ +#define WSA885X_ANA_TOP_PON_CKSK_CTL_0 0x800d +#define WSA885X_ANA_TOP_BG_TVP_UVLO1_PROG 0x8024 +#define WSA885X_ANA_TOP_BG_TVP_UVLO2_PROG 0x8025 +#define WSA885X_ANA_TOP_BG_TVP_OVRD_CTL 0x8034 + +/* Analog PLL Registers */ +#define WSA885X_ANA_PLL_DIV_CTL_0 0x8090 +#define WSA885X_ANA_PLL_DIV_CTL_1 0x8091 +#define WSA885X_ANA_TOP_PLL_VCO_CTL 0x8092 +#define WSA885X_ANA_TOP_PLL_LOOPFILT_0 0x8093 +#define WSA885X_ANA_TOP_PLL_OVRD_CTL 0x8098 +#define WSA885X_ANA_TOP_PLL_STATUS_0 0x809a +#define WSA885X_ANA_TOP_PLL_STATUS_1 0x809b + +/* Analog Boost Control Registers */ +#define WSA885X_ANA_TOP_BOOST_STB_CTRL2 0x805b +#define WSA885X_ANA_TOP_BOOST_STB_CTRL3 0x805c +#define WSA885X_ANA_TOP_BOOST_BYP_CTRL2 0x805e +#define WSA885X_ANA_TOP_BOOST_BYP_CTRL3 0x805f +#define WSA885X_ANA_TOP_BOOST_MISC 0x8063 +#define WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL2 0x8065 +#define WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL4 0x8067 + +/* Analog IV Sense ADC Registers */ +#define WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL2 0x80ca +#define WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL3 0x80cb +#define WSA885X_ANA_TOP_IVSENSE_ADC_REF_CTL 0x80cc +#define WSA885X_ANA_TOP_IVSENSE_ADC_CDAC_CAL_CTL2 0x80d0 + +/* Analog Speaker Power Stage Registers */ +#define WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_CTRL3 0x8108 +#define WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_TUNE3 0x810b +#define WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_CTRL3 0x810e +#define WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_TUNE3 0x8111 +#define WSA885X_ANA_TOP_SPK_TOP_SPARE3 0x813c +#define WSA885X_SPK_TOP_LF_CH1_CTRL11 0x811c +#define WSA885X_SPK_TOP_LF_CH1_TUNE1 0x811d +#define WSA885X_SPK_TOP_LF_CH2_TUNE1 0x8129 +#define WSA885X_SPK_TOP_LF_CH1_CTRL9 0x811a +#define WSA885X_SPK_TOP_LF_CH2_CTRL9 0x8126 +#define WSA885X_SPK_TOP_LF_CH2_CTRL11 0x8128 +#define WSA885X_SPK_TOP_COMMON_CTRL2 0x8102 +#define WSA885X_SPK_TOP_COMMON_TUNE1 0x8103 +#define WSA885X_IVSENSE_VSNS_ISNS_CTL_CH1 0x80ba +#define WSA885X_DIG_CTRL0_TOP_CLK_CFG 0x8418 +#define WSA885X_DIG_CTRL0_SDCA_COMMIT 0x8419 +#define WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE 0x841a +#define WSA885X_DIG_CTRL0_SYS_CLK_SEL 0x841b +#define WSA885X_DIG_CTRL0_CDC_CLK_CTL 0x841c +#define WSA885X_DIG_CTRL0_PA_FSM_CTL 0x8420 +#define WSA885X_DIG_CTRL0_POWER_FSM_CTL0 0x8423 +#define WSA885X_DIG_CTRL0_POWER_FSM_CTL1 0x8424 +#define WSA885X_DIG_CTRL0_PA0_FSM_CTL1 0x842b +#define WSA885X_DIG_CTRL0_PA1_FSM_CTL1 0x8435 +#define WSA885X_DIG_CTRL0_VBAT_THRM_FLT_CTL 0x8458 +#define WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL 0x8470 +#define WSA885X_DIG_CTRL0_GAIN_RAMP0_CTL1 0x84b4 +#define WSA885X_DIG_CTRL0_GAIN_RAMP1_CTL1 0x84b7 +#define WSA885X_DIG_CTRL0_PCM_DATA_WD0_CTL1 0x84A0 +#define WSA885X_DIG_CTRL0_PCM_DATA_WD1_CTL1 0x84A4 + +/* Digital Control 1 Registers - I2S/TDM Interface */ +#define WSA885X_DIG_CTRL1_I2S_CTL0 0x85A0 +#define WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX 0x85A2 +#define WSA885X_DIG_CTRL1_I2S_CFG1_TDM_TX 0x85A3 +#define WSA885X_DIG_CTRL1_I2S_TDM_CTL0 0x85A7 +#define WSA885X_DIG_CTRL1_I2S_TDM_CTL1 0x85A9 +#define WSA885X_DIG_CTRL1_I2S_TDM_CH_RX 0x85AA +#define WSA885X_DIG_CTRL1_I2S_TDM_CH_TX 0x85AB +#define WSA885X_DIG_CTRL1_I2S_RESET_CTL 0x85AE + +/* CDC RX Path Registers - Audio Data Path */ +#define WSA885X_CDC_RX0_RX_PATH_CFG0 0x8601 +#define WSA885X_CDC_RX0_RX_PATH_CFG1 0x8602 +#define WSA885X_CDC_RX0_RX_PATH_CTL 0x8606 +#define WSA885X_RX0_RX_PATH_DSMDEM_CTL 0x8613 +#define WSA885X_CDC_RX1_RX_PATH_CFG0 0x8621 +#define WSA885X_CDC_RX1_RX_PATH_CFG1 0x8622 +#define WSA885X_CDC_RX1_RX_PATH_CTL 0x8626 +#define WSA885X_RX1_RX_PATH_DSMDEM_CTL 0x8633 + +/* CDC Compander Registers - Dynamic Range Control */ +#define WSA885X_CDC_COMPANDER0_CTL0 0x8640 +#define WSA885X_CDC_COMPANDER0_CTL7 0x8647 +#define WSA885X_CDC_COMPANDER1_CTL0 0x8660 +#define WSA885X_CDC_COMPANDER1_CTL7 0x8667 + +/* CDC Speaker Protection Registers - IV Sense */ +#define WSA885X_CDC_VSENSE0_SPKR_PROT_PATH_CTL 0x86A1 +#define WSA885X_CDC_VSENSE1_SPKR_PROT_PATH_CTL 0x86B1 +#define WSA885X_CDC_ISENSE0_SPKR_PROT_PATH_CTL 0x86A9 +#define WSA885X_CDC_ISENSE1_SPKR_PROT_PATH_CTL 0x86B9 + +/* CDC Class-H Registers - Headroom Control */ +#define WSA885X_CDC_CLSH_V1P8_BP_CTL1 0x86CD +#define WSA885X_CDC_CLSH_V1P8_BP_CTL0 0x86CC +#define WSA885X_CDC_CLSH_CLSH_SIG_DP_CTL0 0x86C7 +#define WSA885X_CDC_CLSH_CLSH_V_HD_PA 0x86C3 +#define WSA885X_CDC_CLSH_V1P8_BP_CTL2 0x86CE + +/* Driver Constants */ +#define WSA885X_CLK_RATE_FIXED 73728000 +#define WSA885X_NUM_REGS 0x03 + +/* Interrupt Registers */ +#define WSA885X_INTR_STATUS0 0x8584 +#define WSA885X_INTR_MASK0 0x8581 +#define WSA885X_INTR_CLEAR0 0x8587 + +/* Power and PA FSM Control Registers */ +#define WSA885X_PA0_FSM_CTL0 0x842A +#define WSA885X_PA1_FSM_CTL0 0x8434 + +/* Digital Control GPIO and Interrupt Registers */ +#define WSA885X_DIG_CTRL1_PIN_CT 0x8510 +#define WSA885X_DIG_CTRL1_SPMI_PAD_GPIO2_CTL 0x8518 +#define WSA885X_DIG_CTRL1_INTR_MODE 0x8580 + +#define WSA885X_I2S_CTL0_PCM_RATE_MASK GENMASK(4, 1) +#define WSA885X_I2S_CTL0_ENABLE_MASK BIT(0) +#define WSA885X_I2S_CTL0_PCM_RATE(v) \ + FIELD_PREP(WSA885X_I2S_CTL0_PCM_RATE_MASK, (v)) +#define WSA885X_I2S_CTL0_PCM_RATE_8KHZ 0x0 +#define WSA885X_I2S_CTL0_PCM_RATE_16KHZ 0x1 +#define WSA885X_I2S_CTL0_PCM_RATE_32KHZ 0x2 +#define WSA885X_I2S_CTL0_PCM_RATE_48_OR_44KHZ 0x3 +#define WSA885X_I2S_CTL0_PCM_RATE_96_OR_88KHZ 0x4 +#define WSA885X_I2S_CTL0_PCM_RATE_192_OR_176KHZ 0x5 +#define WSA885X_I2S_CTL0_PCM_RATE_384_OR_352KHZ 0x6 +#define WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK GENMASK(2, 0) +#define WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK GENMASK(6, 4) +#define WSA885X_I2S_CFG0_TDM_TX_SLOT0(v) \ + FIELD_PREP_CONST(WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK, (v)) +#define WSA885X_I2S_CFG0_TDM_TX_SLOT1(v) \ + FIELD_PREP_CONST(WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK, (v)) +#define WSA885X_I2S_CFG1_TDM_TX_SLOT2_MASK GENMASK(2, 0) +#define WSA885X_I2S_CFG1_TDM_TX_SLOT3_MASK GENMASK(6, 4) +#define WSA885X_I2S_CFG1_TDM_TX_SLOT2(v) \ + FIELD_PREP_CONST(WSA885X_I2S_CFG1_TDM_TX_SLOT2_MASK, (v)) +#define WSA885X_I2S_CFG1_TDM_TX_SLOT3(v) \ + FIELD_PREP_CONST(WSA885X_I2S_CFG1_TDM_TX_SLOT3_MASK, (v)) +#define WSA885X_I2S_TDM_CTL0_I2S_TDM_EN_MASK BIT(0) +#define WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK GENMASK(3, 2) +#define WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_2 \ + FIELD_PREP_CONST(WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK, 0) +#define WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_4 \ + FIELD_PREP_CONST(WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK, 1) +#define WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_8 \ + FIELD_PREP_CONST(WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK, 3) +#define WSA885X_I2S_TDM_CH_TX_CH0_EN BIT(0) +#define WSA885X_I2S_TDM_CH_TX_CH1_EN BIT(1) +#define WSA885X_I2S_TDM_CH_TX_CH2_EN BIT(2) +#define WSA885X_I2S_TDM_CH_TX_CH3_EN BIT(3) +#define WSA885X_I2S_TDM_CH_RX_CH0_EN BIT(0) +#define WSA885X_I2S_TDM_CH_RX_CH3_EN BIT(3) +#define WSA885X_I2S_RESET_CTL_RESET_MASK BIT(0) +#define WSA885X_PCM_DATA_WD_CTL1_PCM_DATA_WD_EN_MASK BIT(2) +#define WSA885X_POWER_FSM_CTL0_CLEAR_ERROR_MASK BIT(3) +#define WSA885X_PA_FSM_CTL0_CLEAR_ERROR_MASK BIT(2) + +#define WSA885X_I2S_TX_SLOT_ISENSE0 0x1 +#define WSA885X_I2S_TX_SLOT_ISENSE1 0x2 +#define WSA885X_I2S_TX_SLOT_CUR_SENSE0 0x5 +#define WSA885X_I2S_TX_SLOT_CUR_SENSE1 0x6 + +/* RX Sample Rate Index Values - Audio Playback Path */ +#define WSA885X_RX_RATE_8000HZ 0x00 +#define WSA885X_RX_RATE_16000HZ 0x01 +#define WSA885X_RX_RATE_32000HZ 0x02 +#define WSA885X_RX_RATE_44100HZ 0x03 +#define WSA885X_RX_RATE_48000HZ 0x04 +#define WSA885X_RX_RATE_96000HZ 0x05 +#define WSA885X_RX_RATE_192000HZ 0x06 +#define WSA885X_RX_RATE_384000HZ 0x07 + +/* VI Sample Rate Index Values - Voltage/Current Sensing Path */ +#define WSA885X_VI_RATE_8000HZ 0x00 +#define WSA885X_VI_RATE_16000HZ 0x01 +#define WSA885X_VI_RATE_44100HZ 0x02 +#define WSA885X_VI_RATE_48000HZ 0x03 +#define WSA885X_VI_RATE_96000HZ 0x04 +#define WSA885X_VI_RATE_22050HZ 0x05 +#define WSA885X_VI_RATE_24000HZ 0x06 +#define WSA885X_VI_RATE_192000HZ 0x07 +#define WSA885X_VI_RATE_384000HZ 0x08 + +/* Channel Configuration Masks */ +#define WSA885X_CHANNEL_STEREO 0x03 +#define WSA885X_CHANNEL_MONO_LEFT 0x01 +#define WSA885X_CHANNEL_MONO_RIGHT 0x02 + +#define WSA885X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) + +#define WSA885X_PLL_LOCK_BIT BIT(0) + +#define WSA885X_FU21_VOL_STEPS 124 +#define WSA885X_USAGE_MODE_MAX 8 +static const DECLARE_TLV_DB_SCALE(wsa885x_fu21_digital_gain, -8400, 100, 0); + +static bool wsa885x_is_valid_rx_slot_mask(u32 mask) +{ + return mask == WSA885X_CHANNEL_MONO_LEFT || + mask == WSA885X_CHANNEL_MONO_RIGHT || + mask == WSA885X_CHANNEL_STEREO; +} + +static const char *const wsa885x_supply_name[] = { + "vdd-1p8", + "vdd-io", +}; + +enum { + WSA885X_BATT_1S = 1, + WSA885X_BATT_2S, +}; + +enum { + WSA885X_IRQ_INT_SAF2WAR = 0, + WSA885X_IRQ_INT_WAR2SAF, + WSA885X_IRQ_INT_DISABLE, + WSA885X_IRQ_INT_PA0_OCP, + WSA885X_IRQ_INT_PA1_OCP, + WSA885X_IRQ_INT_CLIP0, + WSA885X_IRQ_INT_CLIP1, + WSA885X_IRQ_INT_CLK_WD, + WSA885X_IRQ_INT_INTR_GPIO1_PIN, + WSA885X_IRQ_INT_INTR_GPIO2_PIN, + WSA885X_IRQ_INT_UVLO, + WSA885X_IRQ_INT_BOP, + WSA885X_IRQ_INT_PA0_FSM_ERR, + WSA885X_IRQ_INT_PA1_FSM_ERR, + WSA885X_IRQ_INT_MAIN_FSM_ERR, + WSA885X_IRQ_INT_PCM_DATA0_WD, + WSA885X_IRQ_INT_PCM_DATA1_WD, + WSA885X_IRQ_INT_PCM_DATA0_DC, + WSA885X_IRQ_INT_PCM_DATA1_DC, + WSA885X_IRQ_INT_PLL_UNLOCKED, + WSA885X_IRQ_INT_PROT_MODE_CHANGE, + WSA885X_IRQ_INT_PB_CLOCK_VALID, + WSA885X_IRQ_INT_SENSE_CLOCK_VALID, + WSA885X_IRQ_MAX, +}; + +struct wsa885x_priv { + struct i2c_client *client; + struct regmap *regmap; + struct device *dev; + struct snd_soc_component *component; + struct gpio_desc *sd_n; + struct reset_control *sd_reset; + u32 usage_mode; + u32 rx_slot_mask; + u32 batt_conf; + int stereo_vol_db; + struct mutex state_lock; /* protects mutable control state */ +}; + +struct wsa885x_reg_update { + unsigned int reg; + unsigned int mask; + unsigned int val; +}; + +static const struct regmap_range_cfg wsa885x_regmap_ranges[] = { + { + .range_min = 0, + .range_max = 0x88ff, + .selector_reg = 0x0, + .selector_mask = 0xFF, + .selector_shift = 0, + .window_start = 0, + .window_len = 0x100, + }, +}; + +static const struct reg_default wsa885x_codec_reg_defaults[] = { + {WSA885X_SMP_AMP_CTRL_STEREO_STEREO_SMP_AMP_CTRL_I2S, 0x00}, + {WSA885X_SMP_AMP_CTRL_STEREO_IT21_CLUSERINDEX, 0x01}, + {WSA885X_SMP_AMP_CTRL_STEREO_CMT_GRP_MASK, 0x00}, + {WSA885X_SMP_AMP_CTRL_STEREO_OT23_USAGE, 0x00}, + {WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID, 0x00}, + {WSA885X_SMP_AMP_CTRL_STEREO_CS21_SAMPLERATEINDEX, 0x04}, + {WSA885X_SMP_AMP_CTRL_STEREO_PPU21_POSTURENUMBER, 0x01}, + {WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X0, 0x01}, + {WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X1, 0x01}, + {WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_MSB, 0xac}, + {WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_LSB, 0x00}, + {WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_MSB, 0xac}, + {WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_LSB, 0x00}, + {WSA885X_SMP_AMP_CTRL_STEREO_PDE23_REQ_PS, 0x03}, + {WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS, 0x03}, + {WSA885X_SMP_AMP_CTRL_STEREO_CS24_SAMPLERATEINDEX, 0x03}, + {WSA885X_ANA_TOP_PON_CKSK_CTL_0, 0x00}, + {WSA885X_ANA_TOP_BG_TVP_UVLO1_PROG, 0x19}, + {WSA885X_ANA_TOP_BG_TVP_UVLO2_PROG, 0x22}, + {WSA885X_ANA_PLL_DIV_CTL_0, 0x0c}, + {WSA885X_ANA_PLL_DIV_CTL_1, 0x50}, + {WSA885X_ANA_TOP_PLL_VCO_CTL, 0x00}, + {WSA885X_ANA_TOP_PLL_LOOPFILT_0, 0xb4}, + {WSA885X_ANA_TOP_PLL_OVRD_CTL, 0x00}, + {WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x00}, + {WSA885X_ANA_TOP_BOOST_STB_CTRL2, 0x03}, + {WSA885X_ANA_TOP_BOOST_STB_CTRL3, 0x3c}, + {WSA885X_ANA_TOP_BOOST_BYP_CTRL2, 0xc5}, + {WSA885X_ANA_TOP_BOOST_BYP_CTRL3, 0x13}, + {WSA885X_ANA_TOP_BOOST_MISC, 0x79}, + {WSA885X_ANA_TOP_SPK_TOP_SPARE3, 0x00}, + {WSA885X_SPK_TOP_COMMON_CTRL2, 0x08}, + {WSA885X_SPK_TOP_LF_CH1_CTRL11, 0x09}, + {WSA885X_SPK_TOP_LF_CH1_TUNE1, 0x00}, + {WSA885X_SPK_TOP_LF_CH2_TUNE1, 0x00}, + {WSA885X_SPK_TOP_LF_CH1_CTRL9, 0x00}, + {WSA885X_SPK_TOP_LF_CH2_CTRL9, 0x00}, + {WSA885X_SPK_TOP_LF_CH2_CTRL11, 0x09}, + {WSA885X_SPK_TOP_COMMON_TUNE1, 0x03}, + {WSA885X_IVSENSE_VSNS_ISNS_CTL_CH1, 0x00}, + {WSA885X_DIG_CTRL0_CDC_CLK_CTL, 0x0e}, + {WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL2, 0x40}, + {WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL4, 0xff}, + {WSA885X_ANA_TOP_PLL_STATUS_0, 0x00}, + {WSA885X_ANA_TOP_PLL_STATUS_1, 0x00}, + {WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL2, 0x84}, + {WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL3, 0x02}, + {WSA885X_ANA_TOP_IVSENSE_ADC_REF_CTL, 0x00}, + {WSA885X_ANA_TOP_IVSENSE_ADC_CDAC_CAL_CTL2, 0xe0}, + {WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_CTRL3, 0xa4}, + {WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_TUNE3, 0xc9}, + {WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_CTRL3, 0xa4}, + {WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_TUNE3, 0xc9}, + {WSA885X_DIG_CTRL0_TOP_CLK_CFG, 0x00}, + {WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x00}, + {WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE, 0x00}, + {WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x00}, + {WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x00}, + {WSA885X_DIG_CTRL0_POWER_FSM_CTL0, 0x05}, + {WSA885X_DIG_CTRL0_POWER_FSM_CTL1, 0x00}, + {WSA885X_DIG_CTRL0_PA0_FSM_CTL1, 0x45}, + {WSA885X_DIG_CTRL0_PA1_FSM_CTL1, 0x45}, + {WSA885X_DIG_CTRL0_VBAT_THRM_FLT_CTL, 0x7f}, + {WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x00}, + {WSA885X_DIG_CTRL0_GAIN_RAMP0_CTL1, 0x01}, + {WSA885X_DIG_CTRL0_GAIN_RAMP1_CTL1, 0x01}, + {WSA885X_DIG_CTRL1_I2S_CTL0, 0x06}, + {WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, 0x00}, + {WSA885X_DIG_CTRL1_I2S_CFG1_TDM_TX, 0x00}, + {WSA885X_DIG_CTRL1_I2S_TDM_CTL0, 0x00}, + {WSA885X_DIG_CTRL1_I2S_TDM_CTL1, 0x05}, + {WSA885X_DIG_CTRL1_I2S_TDM_CH_TX, 0x00}, + {WSA885X_DIG_CTRL1_I2S_RESET_CTL, 0x00}, + {WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, WSA885X_I2S_TDM_CH_RX_CH3_EN}, + {WSA885X_CDC_RX0_RX_PATH_CFG0, 0x89}, + {WSA885X_CDC_RX0_RX_PATH_CFG1, 0x64}, + {WSA885X_CDC_RX0_RX_PATH_CTL, 0x24}, + {WSA885X_RX0_RX_PATH_DSMDEM_CTL, 0x01}, + {WSA885X_CDC_RX1_RX_PATH_CFG0, 0x89}, + {WSA885X_CDC_RX1_RX_PATH_CFG1, 0x64}, + {WSA885X_CDC_RX1_RX_PATH_CTL, 0x04}, + {WSA885X_RX1_RX_PATH_DSMDEM_CTL, 0x01}, + {WSA885X_CDC_COMPANDER0_CTL0, 0x01}, + {WSA885X_CDC_COMPANDER0_CTL7, 0x2a}, + {WSA885X_CDC_COMPANDER1_CTL0, 0x01}, + {WSA885X_CDC_COMPANDER1_CTL7, 0x2a}, + {WSA885X_CDC_VSENSE0_SPKR_PROT_PATH_CTL, 0x14}, + {WSA885X_CDC_VSENSE1_SPKR_PROT_PATH_CTL, 0x14}, + {WSA885X_CDC_ISENSE0_SPKR_PROT_PATH_CTL, 0x14}, + {WSA885X_CDC_ISENSE1_SPKR_PROT_PATH_CTL, 0x14}, + {WSA885X_CDC_CLSH_V1P8_BP_CTL1, 0x50}, + {WSA885X_CDC_CLSH_V1P8_BP_CTL0, 0x6c}, + {WSA885X_CDC_CLSH_CLSH_SIG_DP_CTL0, 0x0d}, + {WSA885X_CDC_CLSH_CLSH_V_HD_PA, 0x03}, + {WSA885X_CDC_CLSH_V1P8_BP_CTL2, 0x05}, +}; + +static void wsa885x_multi_update_bits(struct regmap *regmap, + const struct wsa885x_reg_update *updates, + size_t num_updates) +{ + size_t i; + + for (i = 0; i < num_updates; i++) + regmap_update_bits(regmap, updates[i].reg, + updates[i].mask, updates[i].val); +} + +static void wsa885x_toggle_irq_bit(struct wsa885x_priv *wsa885x, + unsigned int reg, unsigned int mask) +{ + regmap_update_bits(wsa885x->regmap, reg, mask, 0); + regmap_update_bits(wsa885x->regmap, reg, mask, mask); +} + +static void wsa885x_pulse_irq_bit(struct wsa885x_priv *wsa885x, + unsigned int reg, unsigned int mask) +{ + regmap_update_bits(wsa885x->regmap, reg, mask, 0); + regmap_update_bits(wsa885x->regmap, reg, mask, mask); + regmap_update_bits(wsa885x->regmap, reg, mask, 0); +} + +static int wsa885x_tdm_ctl0_slot_num_val(int slots, unsigned int *slot_num_val) +{ + if (!slot_num_val) + return -EINVAL; + + switch (slots) { + case 2: + *slot_num_val = WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_2; + return 0; + case 4: + *slot_num_val = WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_4; + return 0; + case 8: + *slot_num_val = WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_8; + return 0; + default: + return -EINVAL; + } +} + +static int wsa885x_reg_update_sequence(struct regmap *regmap, int slots) +{ + static const struct reg_sequence regs[] = { + { WSA885X_DIG_CTRL1_I2S_TDM_CTL1, 0x15 }, + { WSA885X_DIG_CTRL1_I2S_TDM_CTL1, 0x11 }, + }; + unsigned int slot_num_val; + int ret; + + if (!regmap) + return -EINVAL; + + ret = wsa885x_tdm_ctl0_slot_num_val(slots, &slot_num_val); + if (ret) + return ret; + + regmap_multi_reg_write(regmap, regs, ARRAY_SIZE(regs)); + + regmap_update_bits(regmap, WSA885X_DIG_CTRL1_I2S_TDM_CTL0, + WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK, + slot_num_val); + regmap_update_bits(regmap, WSA885X_DIG_CTRL1_I2S_TDM_CTL0, + WSA885X_I2S_TDM_CTL0_I2S_TDM_EN_MASK, + WSA885X_I2S_TDM_CTL0_I2S_TDM_EN_MASK); + regmap_write(regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_TX, + WSA885X_I2S_TDM_CH_TX_CH0_EN); + regmap_update_bits(regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_TX, + WSA885X_I2S_TDM_CH_TX_CH1_EN, + WSA885X_I2S_TDM_CH_TX_CH1_EN); + + return 0; +} + +static int wsa885x_wait_for_pll_lock(struct wsa885x_priv *wsa885x) +{ + unsigned int status = 0; + int cnt = 0, ret = 0; + + do { + usleep_range(1000, 1100); + ret = regmap_read(wsa885x->regmap, WSA885X_ANA_TOP_PLL_STATUS_0, &status); + if (ret) { + dev_err(wsa885x->dev, "PLL status read failed: %d\n", ret); + return ret; + } + + if (status & WSA885X_PLL_LOCK_BIT) + return 0; + } while (++cnt < 20); + + dev_warn(wsa885x->dev, "PLL lock timeout after 20ms, status=0x%x\n", status); + return -ETIMEDOUT; +} + +static int wsa885x_2s_conf(struct wsa885x_priv *wsa885x) +{ + static const struct reg_sequence regs[] = { + { WSA885X_SPK_TOP_COMMON_TUNE1, 0x26 }, + { WSA885X_SPK_TOP_LF_CH1_CTRL11, 0x0d }, + { WSA885X_SPK_TOP_LF_CH2_CTRL11, 0x0d }, + { WSA885X_CDC_CLSH_V1P8_BP_CTL1, 0x71 }, + { WSA885X_CDC_CLSH_V1P8_BP_CTL0, 0xAA }, + }; + + return regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs)); +} + +static const struct reg_sequence wsa885x_reg_init[] = { + { WSA885X_CDC_RX0_RX_PATH_CTL, 0x24 }, + { WSA885X_CDC_RX1_RX_PATH_CTL, 0x24 }, + { WSA885X_RX0_RX_PATH_DSMDEM_CTL, 0x01 }, + { WSA885X_RX1_RX_PATH_DSMDEM_CTL, 0x01 }, + { WSA885X_CDC_COMPANDER0_CTL0, 0x01 }, + { WSA885X_CDC_COMPANDER1_CTL0, 0x01 }, + { WSA885X_CDC_VSENSE0_SPKR_PROT_PATH_CTL, 0x14 }, + { WSA885X_CDC_VSENSE1_SPKR_PROT_PATH_CTL, 0x14 }, + { WSA885X_CDC_ISENSE0_SPKR_PROT_PATH_CTL, 0x14 }, + { WSA885X_CDC_ISENSE1_SPKR_PROT_PATH_CTL, 0x14 }, + { WSA885X_DIG_CTRL0_CDC_CLK_CTL, 0x0f }, + { WSA885X_DIG_CTRL0_CDC_CLK_CTL, 0x4f }, + { WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x02 }, + { WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x00 }, + { WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x01 }, + { WSA885X_SMP_AMP_CTRL_STEREO_CMT_GRP_MASK, 0x01 }, + { WSA885X_CDC_RX0_RX_PATH_CFG1, 0x60 }, + { WSA885X_CDC_RX1_RX_PATH_CFG1, 0x60 }, + { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_CTRL3, 0xa5 }, + { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_CTRL3, 0xa5 }, + { WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL2, 0x85 }, + { WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL3, 0x0c }, + { WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL3, 0x0e }, + { WSA885X_ANA_TOP_IVSENSE_ADC_REF_CTL, 0x0c }, + { WSA885X_DIG_CTRL0_GAIN_RAMP0_CTL1, 0x01 }, + { WSA885X_DIG_CTRL0_GAIN_RAMP1_CTL1, 0x01 }, + { WSA885X_CDC_RX0_RX_PATH_CFG0, 0x88 }, + { WSA885X_CDC_RX0_RX_PATH_CFG0, 0x89 }, + { WSA885X_CDC_RX1_RX_PATH_CFG0, 0x88 }, + { WSA885X_CDC_RX1_RX_PATH_CFG0, 0x89 }, + { WSA885X_ANA_TOP_BOOST_STB_CTRL2, 0x82 }, + { WSA885X_ANA_TOP_BOOST_STB_CTRL3, 0x34 }, + { WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL2, 0x41 }, + { WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL4, 0x7f }, + { WSA885X_CDC_CLSH_V1P8_BP_CTL1, 0x50 }, + { WSA885X_CDC_CLSH_V1P8_BP_CTL0, 0x6c }, + { WSA885X_CDC_CLSH_CLSH_SIG_DP_CTL0, 0x0d }, + { WSA885X_CDC_CLSH_CLSH_V_HD_PA, 0x03 }, + { WSA885X_DIG_CTRL0_POWER_FSM_CTL0, 0x05 }, + { WSA885X_ANA_TOP_PON_CKSK_CTL_0, 0x20 }, + { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_TUNE3, 0x45 }, + { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_TUNE3, 0x45 }, + { WSA885X_CDC_CLSH_V1P8_BP_CTL2, 0x05 }, + { WSA885X_ANA_TOP_BG_TVP_UVLO1_PROG, 0x35 }, + { WSA885X_ANA_TOP_BG_TVP_UVLO2_PROG, 0x21 }, + { WSA885X_ANA_TOP_BOOST_BYP_CTRL2, 0xc7 }, + { WSA885X_ANA_TOP_BOOST_BYP_CTRL3, 0x11 }, + { WSA885X_ANA_TOP_IVSENSE_ADC_CDAC_CAL_CTL2, 0x80 }, + { WSA885X_ANA_TOP_SPK_TOP_SPARE3, 0x08 }, + { WSA885X_DIG_CTRL0_PA0_FSM_CTL1, 0x47 }, + { WSA885X_DIG_CTRL0_PA1_FSM_CTL1, 0x47 }, + { WSA885X_CDC_COMPANDER0_CTL7, 0x34 }, + { WSA885X_CDC_COMPANDER1_CTL7, 0x34 }, + { WSA885X_DIG_CTRL0_VBAT_THRM_FLT_CTL, 0x79 }, +}; + +static int wsa885x_hw_init(struct wsa885x_priv *wsa885x) +{ + static const struct reg_sequence regs[] = { + { WSA885X_DIG_CTRL1_SPMI_PAD_GPIO2_CTL, 0x2e }, + { WSA885X_DIG_CTRL1_INTR_MODE, 0x01 }, + { WSA885X_DIG_CTRL1_PIN_CT, 0x04 }, + }; + int ret; + + ret = regmap_multi_reg_write(wsa885x->regmap, wsa885x_reg_init, + ARRAY_SIZE(wsa885x_reg_init)); + if (ret) + return ret; + + if (wsa885x->batt_conf == WSA885X_BATT_2S) { + ret = wsa885x_2s_conf(wsa885x); + if (ret) + return ret; + } + + return regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs)); +} + +static int wsa885x_unmask_interrupts(struct wsa885x_priv *wsa885x) +{ + static const struct reg_sequence regs[] = { + { WSA885X_INTR_MASK0, 0x00 }, + { WSA885X_INTR_MASK0 + 1, 0x00 }, + { WSA885X_INTR_MASK0 + 2, 0xf8 }, + }; + + return regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs)); +} + +static int wsa885x_wait_for_pde_state(struct wsa885x_priv *wsa885x, int ps) +{ + unsigned int act_ps = 0, clock_valid = 0; + int rc = 0, cnt = 0; + + if (ps < 0 || ps > 3) + return -EINVAL; + + do { + usleep_range(1000, 1500); + rc = regmap_read(wsa885x->regmap, + WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS, + &act_ps); + if (rc) { + dev_err(wsa885x->dev, "PDE state read failed: %d\n", rc); + return rc; + } + if (act_ps == ps) + return 0; + } while (++cnt < 5); + + if (regmap_read(wsa885x->regmap, + WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID, + &clock_valid)) + dev_err(wsa885x->dev, + "PDE power state %d request failed, actual_ps %d, clock_valid read failed\n", + ps, act_ps); + else + dev_err(wsa885x->dev, + "PDE power state %d request failed, actual_ps %d, clock_valid:%d\n", + ps, act_ps, clock_valid); + + return -ETIMEDOUT; +} + +static void wsa885x_program_stereo_volume(struct wsa885x_priv *wsa885x, + int stereo_vol_db, bool commit) +{ + regmap_write(wsa885x->regmap, + WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_MSB, + (u8)(s8)stereo_vol_db); + regmap_write(wsa885x->regmap, + WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_LSB, 0x00); + regmap_write(wsa885x->regmap, + WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_MSB, + (u8)(s8)stereo_vol_db); + regmap_write(wsa885x->regmap, + WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_LSB, 0x00); + + if (commit) + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01); +} + +static int wsa885x_codec_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct wsa885x_priv *wsa885x; + u8 pcm_rate, cs21_sample_rate_idx, cs24_sample_rate_idx; + + wsa885x = snd_soc_component_get_drvdata(dai->component); + + switch (params_rate(params)) { + case 8000: + pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_8KHZ; + cs21_sample_rate_idx = WSA885X_RX_RATE_8000HZ; + cs24_sample_rate_idx = WSA885X_VI_RATE_8000HZ; + break; + case 16000: + pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_16KHZ; + cs21_sample_rate_idx = WSA885X_RX_RATE_16000HZ; + cs24_sample_rate_idx = WSA885X_VI_RATE_16000HZ; + break; + case 32000: + pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_32KHZ; + cs21_sample_rate_idx = WSA885X_RX_RATE_32000HZ; + cs24_sample_rate_idx = WSA885X_VI_RATE_48000HZ; + break; + case 44100: + pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_48_OR_44KHZ; + cs21_sample_rate_idx = WSA885X_RX_RATE_44100HZ; + cs24_sample_rate_idx = WSA885X_VI_RATE_44100HZ; + break; + case 48000: + pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_48_OR_44KHZ; + cs21_sample_rate_idx = WSA885X_RX_RATE_48000HZ; + cs24_sample_rate_idx = WSA885X_VI_RATE_48000HZ; + break; + case 88200: + case 96000: + pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_96_OR_88KHZ; + cs21_sample_rate_idx = WSA885X_RX_RATE_96000HZ; + cs24_sample_rate_idx = WSA885X_VI_RATE_96000HZ; + break; + case 176400: + case 192000: + pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_192_OR_176KHZ; + cs21_sample_rate_idx = WSA885X_RX_RATE_192000HZ; + cs24_sample_rate_idx = WSA885X_VI_RATE_192000HZ; + break; + case 352800: + case 384000: + pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_384_OR_352KHZ; + cs21_sample_rate_idx = WSA885X_RX_RATE_384000HZ; + cs24_sample_rate_idx = WSA885X_VI_RATE_384000HZ; + break; + default: + dev_err(wsa885x->dev, "sampling rate %d is not supported\n", params_rate(params)); + return -EINVAL; + } + + regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_CTL0, + WSA885X_I2S_CTL0_PCM_RATE_MASK | + WSA885X_I2S_CTL0_ENABLE_MASK, + WSA885X_I2S_CTL0_PCM_RATE(pcm_rate) | + WSA885X_I2S_CTL0_ENABLE_MASK); + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_RESET_CTL, 0x00); + regmap_write(wsa885x->regmap, WSA885X_SMP_AMP_CTRL_STEREO_CS21_SAMPLERATEINDEX, + cs21_sample_rate_idx); + regmap_write(wsa885x->regmap, WSA885X_SMP_AMP_CTRL_STEREO_CS24_SAMPLERATEINDEX, + cs24_sample_rate_idx); + + mutex_lock(&wsa885x->state_lock); + wsa885x_program_stereo_volume(wsa885x, wsa885x->stereo_vol_db, false); + mutex_unlock(&wsa885x->state_lock); + + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01); + + return 0; +} + +static int wsa885x_codec_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_slot_mask, + unsigned int rx_slot_mask, int slots, + int slot_width) +{ + static const struct wsa885x_reg_update stereo_updates[] = { + { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK, + WSA885X_I2S_CFG0_TDM_TX_SLOT0(WSA885X_I2S_TX_SLOT_ISENSE0) }, + { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK, + WSA885X_I2S_CFG0_TDM_TX_SLOT1(WSA885X_I2S_TX_SLOT_ISENSE1) }, + { WSA885X_DIG_CTRL1_I2S_CFG1_TDM_TX, WSA885X_I2S_CFG1_TDM_TX_SLOT2_MASK, + WSA885X_I2S_CFG1_TDM_TX_SLOT2(WSA885X_I2S_TX_SLOT_CUR_SENSE0) }, + { WSA885X_DIG_CTRL1_I2S_CFG1_TDM_TX, WSA885X_I2S_CFG1_TDM_TX_SLOT3_MASK, + WSA885X_I2S_CFG1_TDM_TX_SLOT3(WSA885X_I2S_TX_SLOT_CUR_SENSE1) }, + }; + static const struct wsa885x_reg_update mono_left_updates[] = { + { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK, + WSA885X_I2S_CFG0_TDM_TX_SLOT0(WSA885X_I2S_TX_SLOT_ISENSE0) }, + { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK, + WSA885X_I2S_CFG0_TDM_TX_SLOT1(WSA885X_I2S_TX_SLOT_CUR_SENSE0) }, + }; + static const struct wsa885x_reg_update mono_right_updates[] = { + { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK, + WSA885X_I2S_CFG0_TDM_TX_SLOT0(WSA885X_I2S_TX_SLOT_ISENSE1) }, + { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK, + WSA885X_I2S_CFG0_TDM_TX_SLOT1(WSA885X_I2S_TX_SLOT_CUR_SENSE1) }, + }; + struct wsa885x_priv *wsa885x; + unsigned int slot_num_val; + u32 mask; + int ret; + + wsa885x = snd_soc_component_get_drvdata(dai->component); + + ret = wsa885x_tdm_ctl0_slot_num_val(slots, &slot_num_val); + if (ret) { + dev_err(wsa885x->dev, "%s: unsupported slot count %d\n", + __func__, slots); + return ret; + } + + if (rx_slot_mask && !wsa885x_is_valid_rx_slot_mask(rx_slot_mask)) { + dev_err(wsa885x->dev, + "%s: unsupported rx_slot_mask 0x%x\n", + __func__, rx_slot_mask); + return -EINVAL; + } + + mutex_lock(&wsa885x->state_lock); + if (rx_slot_mask) + wsa885x->rx_slot_mask = rx_slot_mask; + else if (!wsa885x_is_valid_rx_slot_mask(wsa885x->rx_slot_mask)) + wsa885x->rx_slot_mask = WSA885X_CHANNEL_STEREO; + mask = wsa885x->rx_slot_mask; + + regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_RESET_CTL, + WSA885X_I2S_RESET_CTL_RESET_MASK, + WSA885X_I2S_RESET_CTL_RESET_MASK); + + if (mask == WSA885X_CHANNEL_STEREO) { + wsa885x_multi_update_bits(wsa885x->regmap, stereo_updates, + ARRAY_SIZE(stereo_updates)); + ret = wsa885x_reg_update_sequence(wsa885x->regmap, slots); + if (ret) + goto exit_unlock; + regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_TX, + WSA885X_I2S_TDM_CH_TX_CH2_EN, + WSA885X_I2S_TDM_CH_TX_CH2_EN); + regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_TX, + WSA885X_I2S_TDM_CH_TX_CH3_EN, + WSA885X_I2S_TDM_CH_TX_CH3_EN); + } else if (mask == WSA885X_CHANNEL_MONO_LEFT) { + wsa885x_multi_update_bits(wsa885x->regmap, mono_left_updates, + ARRAY_SIZE(mono_left_updates)); + ret = wsa885x_reg_update_sequence(wsa885x->regmap, slots); + if (ret) + goto exit_unlock; + } else if (mask == WSA885X_CHANNEL_MONO_RIGHT) { + wsa885x_multi_update_bits(wsa885x->regmap, mono_right_updates, + ARRAY_SIZE(mono_right_updates)); + ret = wsa885x_reg_update_sequence(wsa885x->regmap, slots); + if (ret) + goto exit_unlock; + } + + regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_CTL0, + WSA885X_I2S_CTL0_ENABLE_MASK, + WSA885X_I2S_CTL0_ENABLE_MASK); + regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_RESET_CTL, + WSA885X_I2S_RESET_CTL_RESET_MASK, 0); + + ret = 0; + +exit_unlock: + mutex_unlock(&wsa885x->state_lock); + + return ret; +} + +static int wsa885x_codec_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + static const struct reg_sequence pll_prep[] = { + { WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x03 }, + { WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x04 }, + { WSA885X_ANA_TOP_PLL_LOOPFILT_0, 0xB4 }, + { WSA885X_ANA_TOP_PLL_VCO_CTL, 0x00 }, + { WSA885X_ANA_TOP_PLL_OVRD_CTL, 0x00 }, + }; + static const struct reg_sequence pll_cleanup[] = { + { WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE, 0x00 }, + { WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x00 }, + { WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x00 }, + }; + struct wsa885x_priv *wsa885x; + u32 pll_div; + int ret = 0; + + wsa885x = snd_soc_component_get_drvdata(dai->component); + + if (!freq) + return -EINVAL; + if (WSA885X_CLK_RATE_FIXED % freq) + return -EINVAL; + pll_div = WSA885X_CLK_RATE_FIXED / freq; + if (pll_div > 0xff) + return -EINVAL; + + regmap_multi_reg_write(wsa885x->regmap, pll_prep, ARRAY_SIZE(pll_prep)); + regmap_write(wsa885x->regmap, WSA885X_ANA_PLL_DIV_CTL_0, pll_div); + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE, 0x02); + + ret = wsa885x_wait_for_pll_lock(wsa885x); + if (ret) { + dev_err(wsa885x->dev, "PLL lock failed, aborting sysclk configuration\n"); + regmap_multi_reg_write(wsa885x->regmap, pll_cleanup, + ARRAY_SIZE(pll_cleanup)); + return ret; + } + + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x00); + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_POWER_FSM_CTL1, 0x01); + regmap_write(wsa885x->regmap, WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x00); + + return 0; +} + +static int wsa885x_codec_mute_stream(struct snd_soc_dai *dai, int mute, int stream) +{ + static const struct reg_sequence mute_regs[] = { + { WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x00 }, + { WSA885X_SMP_AMP_CTRL_STEREO_PDE23_REQ_PS, 0x03 }, + }; + static const struct reg_sequence mute_commit_regs[] = { + { WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X0, 0x01 }, + { WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X1, 0x01 }, + { WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01 }, + }; + static const struct reg_sequence unmute_prep_head_regs[] = { + { WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x00 }, + }; + static const struct reg_sequence unmute_prep_tail_regs[] = { + { WSA885X_SMP_AMP_CTRL_STEREO_IT21_CLUSERINDEX, 0x01 }, + { WSA885X_SMP_AMP_CTRL_STEREO_PPU21_POSTURENUMBER, 0x01 }, + }; + static const struct reg_sequence unmute_volume_regs[] = { + { WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_LSB, 0x00 }, + { WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_LSB, 0x00 }, + }; + static const struct reg_sequence unmute_commit_regs[] = { + { WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01 }, + { WSA885X_SMP_AMP_CTRL_STEREO_PDE23_REQ_PS, 0x00 }, + }; + static const struct reg_sequence unmute_finish_regs[] = { + { WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X0, 0x00 }, + { WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X1, 0x00 }, + { WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01 }, + }; + struct wsa885x_priv *wsa885x; + int ret = 0, ps0 = 0, ps3 = 3; + + wsa885x = snd_soc_component_get_drvdata(dai->component); + + if (stream != SNDRV_PCM_STREAM_PLAYBACK) + return 0; + + mutex_lock(&wsa885x->state_lock); + + if (wsa885x->usage_mode > WSA885X_USAGE_MODE_MAX) { + ret = -EINVAL; + goto exit_unlock; + } + + if (!wsa885x_is_valid_rx_slot_mask(wsa885x->rx_slot_mask)) + wsa885x->rx_slot_mask = WSA885X_CHANNEL_STEREO; + + if (mute) { + regmap_multi_reg_write(wsa885x->regmap, mute_regs, + ARRAY_SIZE(mute_regs)); + ret = wsa885x_wait_for_pde_state(wsa885x, ps3); + if (ret) { + dev_err(wsa885x->dev, + "PS3 transition failed: %d\n", ret); + } else { + regmap_multi_reg_write(wsa885x->regmap, mute_commit_regs, + ARRAY_SIZE(mute_commit_regs)); + } + } else { + regmap_multi_reg_write(wsa885x->regmap, unmute_prep_head_regs, + ARRAY_SIZE(unmute_prep_head_regs)); + regmap_write(wsa885x->regmap, WSA885X_SMP_AMP_CTRL_STEREO_OT23_USAGE, + wsa885x->usage_mode); + regmap_multi_reg_write(wsa885x->regmap, unmute_prep_tail_regs, + ARRAY_SIZE(unmute_prep_tail_regs)); + wsa885x_program_stereo_volume(wsa885x, wsa885x->stereo_vol_db, false); + regmap_multi_reg_write(wsa885x->regmap, unmute_volume_regs, + ARRAY_SIZE(unmute_volume_regs)); + regmap_multi_reg_write(wsa885x->regmap, unmute_commit_regs, + ARRAY_SIZE(unmute_commit_regs)); + ret = wsa885x_wait_for_pde_state(wsa885x, ps0); + if (ret) + goto exit_unlock; + + if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_STEREO) { + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, + WSA885X_I2S_TDM_CH_RX_CH0_EN | + WSA885X_I2S_TDM_CH_RX_CH3_EN); + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x03); + } else if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_MONO_LEFT) { + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, + WSA885X_I2S_TDM_CH_RX_CH3_EN); + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x01); + } else if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_MONO_RIGHT) { + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, + WSA885X_I2S_TDM_CH_RX_CH0_EN); + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x02); + } + + regmap_multi_reg_write(wsa885x->regmap, unmute_finish_regs, + ARRAY_SIZE(unmute_finish_regs)); + } + +exit_unlock: + mutex_unlock(&wsa885x->state_lock); + + return ret; +} + +static int wsa885x_codec_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + static const struct reg_sequence regs[] = { + { WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x00 }, + }; + struct wsa885x_priv *wsa885x; + + wsa885x = snd_soc_component_get_drvdata(dai->component); + + if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) + return 0; + + mutex_lock(&wsa885x->state_lock); + regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs)); + mutex_unlock(&wsa885x->state_lock); + + return 0; +} + +static const struct snd_soc_dai_ops wsa885x_dai_ops = { + .hw_params = wsa885x_codec_hw_params, + .set_tdm_slot = wsa885x_codec_set_tdm_slot, + .set_sysclk = wsa885x_codec_set_sysclk, + .mute_stream = wsa885x_codec_mute_stream, + .hw_free = wsa885x_codec_hw_free, +}; + +static struct snd_soc_dai_driver wsa885x_dai[] = { + { + .name = "wsa885x_dai_drv", + .playback = { + .stream_name = "WSA885X TDM Playback", + .channels_min = 1, + .channels_max = 2, + .rates = WSA885X_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &wsa885x_dai_ops, + }, +}; + +static void wsa885x_reset_assert(void *data) +{ + struct wsa885x_priv *wsa885x = data; + + if (wsa885x->sd_reset) + reset_control_assert(wsa885x->sd_reset); + else + gpiod_direction_output(wsa885x->sd_n, 1); +} + +static void wsa885x_reset_deassert(struct wsa885x_priv *wsa885x) +{ + if (wsa885x->sd_reset) + reset_control_deassert(wsa885x->sd_reset); + else + gpiod_direction_output(wsa885x->sd_n, 0); +} + +static int wsa885x_get_reset(struct device *dev, struct wsa885x_priv *wsa885x) +{ + wsa885x->sd_reset = devm_reset_control_get_optional_shared(dev, NULL); + if (IS_ERR(wsa885x->sd_reset)) + return dev_err_probe(dev, PTR_ERR(wsa885x->sd_reset), + "Failed to get reset\n"); + else if (wsa885x->sd_reset) + return 0; + + wsa885x->sd_n = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH); + if (IS_ERR(wsa885x->sd_n)) + return dev_err_probe(dev, PTR_ERR(wsa885x->sd_n), + "Shutdown Control GPIO not found\n"); + + return 0; +} + +static bool wsa885x_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WSA885X_ANA_TOP_PLL_STATUS_0: + case WSA885X_ANA_TOP_PLL_STATUS_1: + case WSA885X_DIG_CTRL0_SDCA_COMMIT: + case WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS: + case WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID: + case WSA885X_INTR_STATUS0: + case WSA885X_INTR_STATUS0 + 1: + case WSA885X_INTR_STATUS0 + 2: + case WSA885X_INTR_CLEAR0: + case WSA885X_INTR_CLEAR0 + 1: + case WSA885X_INTR_CLEAR0 + 2: + return true; + default: + return false; + } +} + +static bool wsa885x_readable_register(struct device *dev, unsigned int reg) +{ + if (reg == WSA885X_INTR_CLEAR0 || + reg == WSA885X_INTR_CLEAR0 + 1 || + reg == WSA885X_INTR_CLEAR0 + 2) + return false; + return reg <= 0x88ff; +} + +static bool wsa885x_writeable_register(struct device *dev, unsigned int reg) +{ + if (reg > 0x88ff) + return false; + + switch (reg) { + case WSA885X_ANA_TOP_PLL_STATUS_0: + case WSA885X_ANA_TOP_PLL_STATUS_1: + case WSA885X_INTR_STATUS0: + case WSA885X_INTR_STATUS0 + 1: + case WSA885X_INTR_STATUS0 + 2: + case WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS: + case WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID: + return false; + default: + return true; + } +} + +static const struct regmap_config wsa885x_regmap_cfg = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x88FF, + .ranges = wsa885x_regmap_ranges, + .num_ranges = ARRAY_SIZE(wsa885x_regmap_ranges), + .reg_defaults = wsa885x_codec_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wsa885x_codec_reg_defaults), + .volatile_reg = wsa885x_volatile_register, + .writeable_reg = wsa885x_writeable_register, + .readable_reg = wsa885x_readable_register, + .cache_type = REGCACHE_MAPLE, + .use_single_read = true, + .use_single_write = true, +}; + +static int wsa885x_component_probe(struct snd_soc_component *component) +{ + struct wsa885x_priv *wsa885x = + snd_soc_component_get_drvdata(component); + int ret; + + wsa885x->component = component; + snd_soc_component_init_regmap(component, wsa885x->regmap); + + ret = wsa885x_hw_init(wsa885x); + if (ret) + return ret; + + return wsa885x_unmask_interrupts(wsa885x); +} + +static int wsa885x_stereo_gain_offset_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); + int val; + + mutex_lock(&wsa885x->state_lock); + val = wsa885x->stereo_vol_db + 84; + mutex_unlock(&wsa885x->state_lock); + if (val < 0 || val > WSA885X_FU21_VOL_STEPS) + return -ERANGE; + + ucontrol->value.integer.value[0] = val; + return 0; +} + +static int wsa885x_stereo_gain_offset_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); + long val; + int stereo_vol_db; + + val = ucontrol->value.integer.value[0]; + + if (val < 0 || val > WSA885X_FU21_VOL_STEPS) { + dev_err(component->dev, "%s: Invalid range, Val: %ld\n", __func__, val); + return -EINVAL; + } + + stereo_vol_db = (int)val - 84; + + mutex_lock(&wsa885x->state_lock); + if (wsa885x->stereo_vol_db == stereo_vol_db) { + mutex_unlock(&wsa885x->state_lock); + return 0; + } + + wsa885x_program_stereo_volume(wsa885x, stereo_vol_db, true); + wsa885x->stereo_vol_db = stereo_vol_db; + mutex_unlock(&wsa885x->state_lock); + + return 1; +} + +static int wsa885x_usage_modes_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); + + mutex_lock(&wsa885x->state_lock); + if (wsa885x->usage_mode > WSA885X_USAGE_MODE_MAX) { + mutex_unlock(&wsa885x->state_lock); + return -ERANGE; + } + + ucontrol->value.integer.value[0] = wsa885x->usage_mode; + mutex_unlock(&wsa885x->state_lock); + + return 0; +} + +static int wsa885x_usage_modes_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); + u32 val = ucontrol->value.integer.value[0]; + + if (val > WSA885X_USAGE_MODE_MAX) + return -EINVAL; + + mutex_lock(&wsa885x->state_lock); + if (wsa885x->usage_mode == val) { + mutex_unlock(&wsa885x->state_lock); + return 0; + } + + wsa885x->usage_mode = val; + mutex_unlock(&wsa885x->state_lock); + + return 1; +} + +static int wsa885x_rx_slot_mask_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); + u32 mask; + + mutex_lock(&wsa885x->state_lock); + mask = wsa885x->rx_slot_mask; + mutex_unlock(&wsa885x->state_lock); + if (!wsa885x_is_valid_rx_slot_mask(mask)) + return -ERANGE; + + ucontrol->value.integer.value[0] = mask; + + return 0; +} + +static int wsa885x_rx_slot_mask_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); + u32 mask = ucontrol->value.integer.value[0]; + + if (!wsa885x_is_valid_rx_slot_mask(mask)) + return -EINVAL; + + mutex_lock(&wsa885x->state_lock); + if (wsa885x->rx_slot_mask == mask) { + mutex_unlock(&wsa885x->state_lock); + return 0; + } + + wsa885x->rx_slot_mask = mask; + mutex_unlock(&wsa885x->state_lock); + + return 1; +} + +static const struct snd_kcontrol_new wsa885x_snd_controls[] = { + SOC_SINGLE_EXT("Usage Mode", SND_SOC_NOPM, 0, WSA885X_USAGE_MODE_MAX, 0, + wsa885x_usage_modes_get, + wsa885x_usage_modes_put), + + SOC_SINGLE_EXT_TLV("Speaker Volume", SND_SOC_NOPM, + 0, WSA885X_FU21_VOL_STEPS, 0, + wsa885x_stereo_gain_offset_get, + wsa885x_stereo_gain_offset_put, + wsa885x_fu21_digital_gain), + + SOC_SINGLE_EXT("Rx Slot Mask", SND_SOC_NOPM, 0, 3, 0, + wsa885x_rx_slot_mask_get, + wsa885x_rx_slot_mask_put), +}; + +static const struct snd_soc_component_driver wsa885x_component = { + .name = "wsa885x", + .probe = wsa885x_component_probe, + .controls = wsa885x_snd_controls, + .num_controls = ARRAY_SIZE(wsa885x_snd_controls), +}; + +static irqreturn_t wsa885x_handle_irq(int irq_idx, void *data) +{ + struct wsa885x_priv *wsa885x = data; + + if (irq_idx < 0 || irq_idx >= WSA885X_IRQ_MAX) + return IRQ_NONE; + + switch (irq_idx) { + case WSA885X_IRQ_INT_SAF2WAR: + case WSA885X_IRQ_INT_WAR2SAF: + case WSA885X_IRQ_INT_DISABLE: + case WSA885X_IRQ_INT_INTR_GPIO1_PIN: + case WSA885X_IRQ_INT_INTR_GPIO2_PIN: + case WSA885X_IRQ_INT_PA0_OCP: + case WSA885X_IRQ_INT_PA1_OCP: + case WSA885X_IRQ_INT_CLIP0: + case WSA885X_IRQ_INT_CLIP1: + case WSA885X_IRQ_INT_CLK_WD: + case WSA885X_IRQ_INT_BOP: + case WSA885X_IRQ_INT_UVLO: + case WSA885X_IRQ_INT_PCM_DATA0_DC: + case WSA885X_IRQ_INT_PCM_DATA1_DC: + case WSA885X_IRQ_INT_PLL_UNLOCKED: + case WSA885X_IRQ_INT_PROT_MODE_CHANGE: + case WSA885X_IRQ_INT_PB_CLOCK_VALID: + case WSA885X_IRQ_INT_SENSE_CLOCK_VALID: + break; + case WSA885X_IRQ_INT_PCM_DATA0_WD: + case WSA885X_IRQ_INT_PCM_DATA1_WD: + if (irq_idx == WSA885X_IRQ_INT_PCM_DATA0_WD) + wsa885x_toggle_irq_bit(wsa885x, WSA885X_DIG_CTRL0_PCM_DATA_WD0_CTL1, + WSA885X_PCM_DATA_WD_CTL1_PCM_DATA_WD_EN_MASK); + else + wsa885x_toggle_irq_bit(wsa885x, WSA885X_DIG_CTRL0_PCM_DATA_WD1_CTL1, + WSA885X_PCM_DATA_WD_CTL1_PCM_DATA_WD_EN_MASK); + break; + case WSA885X_IRQ_INT_PA0_FSM_ERR: + case WSA885X_IRQ_INT_PA1_FSM_ERR: + case WSA885X_IRQ_INT_MAIN_FSM_ERR: + if (irq_idx == WSA885X_IRQ_INT_MAIN_FSM_ERR) { + wsa885x_pulse_irq_bit(wsa885x, WSA885X_DIG_CTRL0_POWER_FSM_CTL0, + WSA885X_POWER_FSM_CTL0_CLEAR_ERROR_MASK); + } else if (irq_idx == WSA885X_IRQ_INT_PA0_FSM_ERR) { + wsa885x_pulse_irq_bit(wsa885x, WSA885X_PA0_FSM_CTL0, + WSA885X_PA_FSM_CTL0_CLEAR_ERROR_MASK); + } else if (irq_idx == WSA885X_IRQ_INT_PA1_FSM_ERR) { + wsa885x_pulse_irq_bit(wsa885x, WSA885X_PA1_FSM_CTL0, + WSA885X_PA_FSM_CTL0_CLEAR_ERROR_MASK); + } + break; + default: + break; + } + + return IRQ_HANDLED; +} + +static irqreturn_t wsa885x_interrupt_handler(int irq, void *data) +{ + static const unsigned int status_reg[WSA885X_NUM_REGS] = { + WSA885X_INTR_STATUS0, + WSA885X_INTR_STATUS0 + 1, + WSA885X_INTR_STATUS0 + 2, + }; + static const unsigned int clear_reg[WSA885X_NUM_REGS] = { + WSA885X_INTR_CLEAR0, + WSA885X_INTR_CLEAR0 + 1, + WSA885X_INTR_CLEAR0 + 2, + }; + unsigned int status[WSA885X_NUM_REGS] = { 0 }; + struct wsa885x_priv *wsa885x = data; + irqreturn_t handled = IRQ_NONE; + irqreturn_t irq_ret; + int i, bit, ret, irq_num; + + for (i = 0; i < WSA885X_NUM_REGS; i++) { + ret = regmap_read(wsa885x->regmap, status_reg[i], &status[i]); + if (ret) { + dev_err(wsa885x->dev, + "Failed to read status_reg[%d] (0x%x): %d\n", + i, status_reg[i], ret); + status[i] = 0; + continue; + } + } + + for (i = 0; i < WSA885X_NUM_REGS; i++) { + for (bit = 0; bit < 8; bit++) { + if (status[i] & BIT(bit)) { + irq_num = i * 8 + bit; + regmap_write(wsa885x->regmap, clear_reg[i], BIT(bit)); + regmap_write(wsa885x->regmap, clear_reg[i], 0); + if (irq_num >= WSA885X_IRQ_MAX) { + dev_warn_ratelimited(wsa885x->dev, + "Unexpected IRQ bit %d (reg %d)\n", + bit, i); + handled = IRQ_HANDLED; + continue; + } + irq_ret = wsa885x_handle_irq(irq_num, wsa885x); + if (irq_ret == IRQ_HANDLED) + handled = IRQ_HANDLED; + } + } + } + return handled; +} + +static int wsa885x_register_irq(struct wsa885x_priv *wsa885x) +{ + if (!wsa885x->client->irq) + return dev_err_probe(wsa885x->dev, -EINVAL, + "IRQ is not configured\n"); + + return devm_request_threaded_irq(wsa885x->dev, wsa885x->client->irq, NULL, + wsa885x_interrupt_handler, + IRQF_ONESHOT, + dev_name(wsa885x->dev), wsa885x); +} + +static int wsa885x_probe(struct i2c_client *client) +{ + struct wsa885x_priv *wsa885x; + const struct snd_soc_component_driver *component_driver = &wsa885x_component; + const char *battery_config; + unsigned int i; + int ret; + struct device *dev = &client->dev; + + wsa885x = devm_kzalloc(dev, sizeof(*wsa885x), GFP_KERNEL); + if (!wsa885x) + return -ENOMEM; + + wsa885x->client = client; + wsa885x->dev = dev; + wsa885x->stereo_vol_db = -84; + wsa885x->rx_slot_mask = WSA885X_CHANNEL_STEREO; + mutex_init(&wsa885x->state_lock); + wsa885x->regmap = devm_regmap_init_i2c(client, &wsa885x_regmap_cfg); + + if (IS_ERR(wsa885x->regmap)) + return PTR_ERR(wsa885x->regmap); + + ret = device_property_read_string(dev, "qcom,battery-config", + &battery_config); + if (ret) { + wsa885x->batt_conf = WSA885X_BATT_1S; + } else if (!strcmp(battery_config, "1s")) { + wsa885x->batt_conf = WSA885X_BATT_1S; + } else if (!strcmp(battery_config, "2s")) { + wsa885x->batt_conf = WSA885X_BATT_2S; + } else { + return dev_err_probe(dev, -EINVAL, + "Invalid battery config %s (expected 1s or 2s)\n", + battery_config); + } + + for (i = 0; i < ARRAY_SIZE(wsa885x_supply_name); i++) { + ret = devm_regulator_get_enable(dev, wsa885x_supply_name[i]); + if (ret) + return dev_err_probe(dev, ret, + "Failed to enable regulator %s\n", + wsa885x_supply_name[i]); + } + + ret = wsa885x_get_reset(dev, wsa885x); + if (ret) + return ret; + + wsa885x_reset_deassert(wsa885x); + usleep_range(5000, 5500); + + ret = devm_add_action_or_reset(dev, wsa885x_reset_assert, wsa885x); + if (ret) + return dev_err_probe(dev, ret, "devm_add_action_or_reset failed\n"); + + i2c_set_clientdata(client, wsa885x); + + ret = wsa885x_register_irq(wsa885x); + if (ret) + return dev_err_probe(dev, ret, "wsa885x irq registration failed\n"); + + ret = devm_snd_soc_register_component(dev, component_driver, + wsa885x_dai, + ARRAY_SIZE(wsa885x_dai)); + if (ret) + return dev_err_probe(dev, ret, "Codec component registration failed\n"); + + return 0; +} + +static const struct of_device_id wsa885x_dt_match[] = { + { + .compatible = "qcom,wsa8855", + }, + {} +}; +MODULE_DEVICE_TABLE(of, wsa885x_dt_match); + +static const struct i2c_device_id wsa885x_id[] = { + { + .name = "wsa885x", + .driver_data = 0, + }, + {} +}; +MODULE_DEVICE_TABLE(i2c, wsa885x_id); + +static struct i2c_driver wsa885x_driver = { + .driver = { + .name = "wsa885x", + .of_match_table = wsa885x_dt_match, + }, + .probe = wsa885x_probe, + .id_table = wsa885x_id, +}; + +module_i2c_driver(wsa885x_driver); + +MODULE_DESCRIPTION("ASoC WSA885X Stereo Smart PA Codec Driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/zl38060.c b/sound/soc/codecs/zl38060.c index 7de4014e626d..894b8eb42e39 100644 --- a/sound/soc/codecs/zl38060.c +++ b/sound/soc/codecs/zl38060.c @@ -162,7 +162,7 @@ static int zl38_fw_send_xaddr(struct regmap *regmap, const void *data) static int zl38_load_firmware(struct device *dev, struct regmap *regmap) { const struct ihex_binrec *rec; - const struct firmware *fw; + const struct firmware *fw __free(firmware) = NULL; u32 addr; u16 len; int err; @@ -180,7 +180,7 @@ static int zl38_load_firmware(struct device *dev, struct regmap *regmap) return err; err = zl38_fw_enter_boot_mode(regmap); if (err) - goto out; + return err; rec = (const struct ihex_binrec *)fw->data; while (rec) { addr = be32_to_cpu(rec->addr); @@ -195,15 +195,12 @@ static int zl38_load_firmware(struct device *dev, struct regmap *regmap) err = -EINVAL; } if (err) - goto out; + return err; /* next ! */ rec = ihex_next_binrec(rec); } - err = zl38_fw_go(regmap); -out: - release_firmware(fw); - return err; + return zl38_fw_go(regmap); } |
