diff options
Diffstat (limited to 'sound/soc/codecs')
61 files changed, 1963 insertions, 436 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 7022e6286e6c..0f9d71490075 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -199,6 +199,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT715_SDCA_SDW imply SND_SOC_RT1308_SDW imply SND_SOC_RT1316_SDW + imply SND_SOC_RT1318_SDW imply SND_SOC_RT9120 imply SND_SOC_SDW_MOCKUP imply SND_SOC_SGTL5000 @@ -348,7 +349,7 @@ config SND_SOC_WM_HUBS config SND_SOC_WM_ADSP tristate - select CS_DSP + select FW_CS_DSP select SND_SOC_COMPRESS default y if SND_SOC_MADERA=y default y if SND_SOC_CS47L24=y @@ -1311,6 +1312,11 @@ config SND_SOC_RT1316_SDW depends on SOUNDWIRE select REGMAP_SOUNDWIRE +config SND_SOC_RT1318_SDW + tristate "Realtek RT1318 Codec - SDW" + depends on SOUNDWIRE + select REGMAP_SOUNDWIRE + config SND_SOC_RT5514 tristate depends on I2C @@ -1930,7 +1936,7 @@ config SND_SOC_WM8960 depends on I2C config SND_SOC_WM8961 - tristate + tristate "Wolfson Microelectronics WM8961 CODEC" depends on I2C config SND_SOC_WM8962 diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 9170ee1447dd..71d3ce5867e4 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -196,6 +196,7 @@ snd-soc-rt1305-objs := rt1305.o snd-soc-rt1308-objs := rt1308.o snd-soc-rt1308-sdw-objs := rt1308-sdw.o snd-soc-rt1316-sdw-objs := rt1316-sdw.o +snd-soc-rt1318-sdw-objs := rt1318-sdw.o snd-soc-rt274-objs := rt274.o snd-soc-rt286-objs := rt286.o snd-soc-rt298-objs := rt298.o @@ -551,6 +552,7 @@ obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o obj-$(CONFIG_SND_SOC_RT1308) += snd-soc-rt1308.o obj-$(CONFIG_SND_SOC_RT1308_SDW) += snd-soc-rt1308-sdw.o obj-$(CONFIG_SND_SOC_RT1316_SDW) += snd-soc-rt1316-sdw.o +obj-$(CONFIG_SND_SOC_RT1318_SDW) += snd-soc-rt1318-sdw.o obj-$(CONFIG_SND_SOC_RT274) += snd-soc-rt274.o obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o diff --git a/sound/soc/codecs/adau1372.c b/sound/soc/codecs/adau1372.c index a9f89e8565ec..d9bde7eb043a 100644 --- a/sound/soc/codecs/adau1372.c +++ b/sound/soc/codecs/adau1372.c @@ -8,7 +8,6 @@ #include <linux/clk.h> #include <linux/delay.h> -#include <linux/gcd.h> #include <linux/gpio/consumer.h> #include <linux/init.h> #include <linux/module.h> @@ -25,7 +24,6 @@ #include "adau-utils.h" struct adau1372 { - struct clk *clk; struct regmap *regmap; void (*switch_mode)(struct device *dev); bool use_pll; @@ -207,10 +205,10 @@ static const struct snd_kcontrol_new adau1372_controls[] = { 2, 1, 0, adau1372_pga_boost_tlv), SOC_SINGLE_TLV("PGA 3 Boost Capture Volume", ADAU1372_REG_PGA_BOOST, 3, 1, 0, adau1372_pga_boost_tlv), - SOC_SINGLE("PGA 0 Capture Switch", ADAU1372_REG_PGA_CTRL(0), 7, 1, 1), - SOC_SINGLE("PGA 1 Capture Switch", ADAU1372_REG_PGA_CTRL(1), 7, 1, 1), - SOC_SINGLE("PGA 2 Capture Switch", ADAU1372_REG_PGA_CTRL(2), 7, 1, 1), - SOC_SINGLE("PGA 3 Capture Switch", ADAU1372_REG_PGA_CTRL(3), 7, 1, 1), + SOC_SINGLE("PGA 0 Capture Switch", ADAU1372_REG_PGA_CTRL(0), 7, 1, 0), + SOC_SINGLE("PGA 1 Capture Switch", ADAU1372_REG_PGA_CTRL(1), 7, 1, 0), + SOC_SINGLE("PGA 2 Capture Switch", ADAU1372_REG_PGA_CTRL(2), 7, 1, 0), + SOC_SINGLE("PGA 3 Capture Switch", ADAU1372_REG_PGA_CTRL(3), 7, 1, 0), SOC_SINGLE_TLV("DAC 0 Playback Volume", ADAU1372_REG_DAC_VOL(0), 0, 0xff, 1, adau1372_digital_tlv), @@ -370,10 +368,10 @@ static const struct snd_soc_dapm_widget adau1372_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("MICBIAS0", ADAU1372_REG_MICBIAS, 4, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("MICBIAS1", ADAU1372_REG_MICBIAS, 5, 0, NULL, 0), - SND_SOC_DAPM_PGA("PGA0", ADAU1372_REG_PGA_CTRL(0), 6, 0, NULL, 0), - SND_SOC_DAPM_PGA("PGA1", ADAU1372_REG_PGA_CTRL(1), 6, 0, NULL, 0), - SND_SOC_DAPM_PGA("PGA2", ADAU1372_REG_PGA_CTRL(2), 6, 0, NULL, 0), - SND_SOC_DAPM_PGA("PGA3", ADAU1372_REG_PGA_CTRL(3), 6, 0, NULL, 0), + SND_SOC_DAPM_PGA("PGA0", ADAU1372_REG_PGA_CTRL(0), 6, 1, NULL, 0), + SND_SOC_DAPM_PGA("PGA1", ADAU1372_REG_PGA_CTRL(1), 6, 1, NULL, 0), + SND_SOC_DAPM_PGA("PGA2", ADAU1372_REG_PGA_CTRL(2), 6, 1, NULL, 0), + SND_SOC_DAPM_PGA("PGA3", ADAU1372_REG_PGA_CTRL(3), 6, 1, NULL, 0), SND_SOC_DAPM_ADC("ADC0", NULL, ADAU1372_REG_ADC_CTRL2, 0, 0), SND_SOC_DAPM_ADC("ADC1", NULL, ADAU1372_REG_ADC_CTRL2, 1, 0), SND_SOC_DAPM_ADC("ADC2", NULL, ADAU1372_REG_ADC_CTRL3, 0, 0), @@ -663,6 +661,7 @@ static int adau1372_hw_params(struct snd_pcm_substream *substream, case 16: sai1 = ADAU1372_SAI1_BCLKRATE; break; + case 24: case 32: sai1 = 0; break; @@ -700,6 +699,7 @@ static int adau1372_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, case 16: sai1 = ADAU1372_SAI1_BCLK_TDMC; break; + case 24: case 32: sai1 = 0; break; @@ -870,7 +870,9 @@ static const struct snd_soc_dai_ops adau1372_dai_ops = { .startup = adau1372_startup, }; -#define ADAU1372_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) +#define ADAU1372_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) static struct snd_soc_dai_driver adau1372_dai_driver = { .name = "adau1372", @@ -925,9 +927,9 @@ int adau1372_probe(struct device *dev, struct regmap *regmap, if (!adau1372) return -ENOMEM; - adau1372->clk = devm_clk_get(dev, "mclk"); - if (IS_ERR(adau1372->clk)) - return PTR_ERR(adau1372->clk); + adau1372->mclk = devm_clk_get(dev, "mclk"); + if (IS_ERR(adau1372->mclk)) + return PTR_ERR(adau1372->mclk); adau1372->pd_gpio = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH); if (IS_ERR(adau1372->pd_gpio)) @@ -947,7 +949,7 @@ int adau1372_probe(struct device *dev, struct regmap *regmap, * 12.288MHz. Automatically choose a valid configuration from the * external clock. */ - rate = clk_get_rate(adau1372->clk); + rate = clk_get_rate(adau1372->mclk); switch (rate) { case 12288000: diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 7f832d00ab17..37e178e8a1d0 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -12,7 +12,6 @@ #include <linux/pm.h> #include <linux/i2c.h> #include <linux/slab.h> -#include <linux/gcd.h> #include <sound/core.h> #include <sound/pcm.h> diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index c0f44ecef606..634d4dbca5ec 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c @@ -16,7 +16,6 @@ #include <sound/pcm_params.h> #include <sound/soc.h> #include <sound/tlv.h> -#include <linux/gcd.h> #include <linux/i2c.h> #include <linux/spi/spi.h> #include <linux/regmap.h> diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index 1db73552c746..8c69c8cf9b67 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -13,6 +13,7 @@ #include <linux/of_gpio.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/reset.h> #include <linux/slab.h> #include <sound/initval.h> #include <sound/pcm_params.h> @@ -46,6 +47,7 @@ struct ak4458_priv { struct device *dev; struct regmap *regmap; struct gpio_desc *reset_gpiod; + struct reset_control *reset; struct gpio_desc *mute_gpiod; int digfil; /* SSLOW, SD, SLOW bits */ int fs; /* sampling rate */ @@ -633,6 +635,12 @@ static void ak4458_reset(struct ak4458_priv *ak4458, bool active) if (ak4458->reset_gpiod) { gpiod_set_value_cansleep(ak4458->reset_gpiod, active); usleep_range(1000, 2000); + } else if (!IS_ERR_OR_NULL(ak4458->reset)) { + if (active) + reset_control_assert(ak4458->reset); + else + reset_control_deassert(ak4458->reset); + usleep_range(1000, 2000); } } @@ -668,7 +676,6 @@ static int __maybe_unused ak4458_runtime_resume(struct device *dev) if (ak4458->mute_gpiod) gpiod_set_value_cansleep(ak4458->mute_gpiod, 1); - ak4458_reset(ak4458, true); ak4458_reset(ak4458, false); regcache_cache_only(ak4458->regmap, false); @@ -748,6 +755,10 @@ static int ak4458_i2c_probe(struct i2c_client *i2c) ak4458->drvdata = of_device_get_match_data(&i2c->dev); + ak4458->reset = devm_reset_control_get_optional_shared(ak4458->dev, NULL); + if (IS_ERR(ak4458->reset)) + return PTR_ERR(ak4458->reset); + ak4458->reset_gpiod = devm_gpiod_get_optional(ak4458->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ak4458->reset_gpiod)) diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c index 31ae752e242f..a078dd422ea1 100644 --- a/sound/soc/codecs/cs35l36.c +++ b/sound/soc/codecs/cs35l36.c @@ -918,8 +918,8 @@ static int cs35l36_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, fs1 = CS35L36_FS1_DEFAULT_VAL; fs2 = CS35L36_FS2_DEFAULT_VAL; } else { - fs1 = 3 * ((CS35L36_FS_NOM_6MHZ * 4 + freq - 1) / freq) + 4; - fs2 = 5 * ((CS35L36_FS_NOM_6MHZ * 4 + freq - 1) / freq) + 4; + fs1 = 3 * DIV_ROUND_UP(CS35L36_FS_NOM_6MHZ * 4, freq) + 4; + fs2 = 5 * DIV_ROUND_UP(CS35L36_FS_NOM_6MHZ * 4, freq) + 4; } regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL, diff --git a/sound/soc/codecs/cs42l83-i2c.c b/sound/soc/codecs/cs42l83-i2c.c index f90d43996a51..37629ebd90e0 100644 --- a/sound/soc/codecs/cs42l83-i2c.c +++ b/sound/soc/codecs/cs42l83-i2c.c @@ -145,7 +145,7 @@ static const struct reg_default cs42l83_reg_defaults[] = { * This is all the same as for CS42L42 but we * replace the on-reset register defaults. */ -const struct regmap_config cs42l83_regmap = { +static const struct regmap_config cs42l83_regmap = { .reg_bits = 8, .val_bits = 8, diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c index bd80e9fc907f..052ffb7dcfc6 100644 --- a/sound/soc/codecs/cs42xx8-i2c.c +++ b/sound/soc/codecs/cs42xx8-i2c.c @@ -12,15 +12,30 @@ #include <linux/i2c.h> #include <linux/module.h> +#include <linux/of_device.h> #include <linux/pm_runtime.h> #include <sound/soc.h> #include "cs42xx8.h" +static const struct of_device_id cs42xx8_of_match[]; + static int cs42xx8_i2c_probe(struct i2c_client *i2c) { - int ret = cs42xx8_probe(&i2c->dev, - devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config)); + int ret; + struct cs42xx8_driver_data *drvdata; + const struct of_device_id *of_id; + + of_id = of_match_device(cs42xx8_of_match, &i2c->dev); + if (!of_id) { + dev_err(&i2c->dev, "failed to find driver data\n"); + return -EINVAL; + } + + drvdata = (struct cs42xx8_driver_data *)of_id->data; + + ret = cs42xx8_probe(&i2c->dev, + devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config), drvdata); if (ret) return ret; @@ -35,7 +50,14 @@ static void cs42xx8_i2c_remove(struct i2c_client *i2c) pm_runtime_disable(&i2c->dev); } -static struct i2c_device_id cs42xx8_i2c_id[] = { +static const struct of_device_id cs42xx8_of_match[] = { + { .compatible = "cirrus,cs42448", .data = &cs42448_data, }, + { .compatible = "cirrus,cs42888", .data = &cs42888_data, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, cs42xx8_of_match); + +static const struct i2c_device_id cs42xx8_i2c_id[] = { {"cs42448", (kernel_ulong_t)&cs42448_data}, {"cs42888", (kernel_ulong_t)&cs42888_data}, {} diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index d14eb2f6e1dd..4558ec38a7ac 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -13,7 +13,6 @@ #include <linux/clk.h> #include <linux/delay.h> #include <linux/module.h> -#include <linux/of_device.h> #include <linux/gpio/consumer.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> @@ -511,17 +510,8 @@ const struct cs42xx8_driver_data cs42888_data = { }; EXPORT_SYMBOL_GPL(cs42888_data); -const struct of_device_id cs42xx8_of_match[] = { - { .compatible = "cirrus,cs42448", .data = &cs42448_data, }, - { .compatible = "cirrus,cs42888", .data = &cs42888_data, }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, cs42xx8_of_match); -EXPORT_SYMBOL_GPL(cs42xx8_of_match); - -int cs42xx8_probe(struct device *dev, struct regmap *regmap) +int cs42xx8_probe(struct device *dev, struct regmap *regmap, struct cs42xx8_driver_data *drvdata) { - const struct of_device_id *of_id; struct cs42xx8_priv *cs42xx8; int ret, val, i; @@ -535,17 +525,11 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap) if (cs42xx8 == NULL) return -ENOMEM; - cs42xx8->regmap = regmap; dev_set_drvdata(dev, cs42xx8); - of_id = of_match_device(cs42xx8_of_match, dev); - if (of_id) - cs42xx8->drvdata = of_id->data; + cs42xx8->regmap = regmap; - if (!cs42xx8->drvdata) { - dev_err(dev, "failed to find driver data\n"); - return -EINVAL; - } + cs42xx8->drvdata = drvdata; cs42xx8->gpiod_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); diff --git a/sound/soc/codecs/cs42xx8.h b/sound/soc/codecs/cs42xx8.h index d36c61b6df74..342389e8b1a8 100644 --- a/sound/soc/codecs/cs42xx8.h +++ b/sound/soc/codecs/cs42xx8.h @@ -22,8 +22,7 @@ extern const struct dev_pm_ops cs42xx8_pm; extern const struct cs42xx8_driver_data cs42448_data; extern const struct cs42xx8_driver_data cs42888_data; extern const struct regmap_config cs42xx8_regmap_config; -extern const struct of_device_id cs42xx8_of_match[]; -int cs42xx8_probe(struct device *dev, struct regmap *regmap); +int cs42xx8_probe(struct device *dev, struct regmap *regmap, struct cs42xx8_driver_data *drvdata); /* CS42888 register map */ #define CS42XX8_CHIPID 0x01 /* Chip ID */ diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c index bba73c44c219..c55b033d89da 100644 --- a/sound/soc/codecs/da7219-aad.c +++ b/sound/soc/codecs/da7219-aad.c @@ -43,7 +43,6 @@ void da7219_aad_jack_det(struct snd_soc_component *component, struct snd_soc_jac DA7219_ACCDET_EN_MASK, (jack ? DA7219_ACCDET_EN_MASK : 0)); } -EXPORT_SYMBOL_GPL(da7219_aad_jack_det); /* * Button/HPTest work @@ -352,9 +351,14 @@ static irqreturn_t da7219_aad_irq_thread(int irq, void *data) struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); u8 events[DA7219_AAD_IRQ_REG_MAX]; - u8 statusa; + u8 statusa, srm_st; int i, report = 0, mask = 0; + srm_st = snd_soc_component_read(component, DA7219_PLL_SRM_STS) & DA7219_PLL_SRM_STS_MCLK; + msleep(da7219_aad->gnd_switch_delay * ((srm_st == 0x0) ? 2 : 1) - 4); + /* Enable ground switch */ + snd_soc_component_update_bits(component, 0xFB, 0x01, 0x01); + /* Read current IRQ events */ regmap_bulk_read(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A, events, DA7219_AAD_IRQ_REG_MAX); @@ -454,8 +458,8 @@ static irqreturn_t da7219_aad_irq_thread(int irq, void *data) snd_soc_dapm_disable_pin(dapm, "Mic Bias"); snd_soc_dapm_sync(dapm); - /* Enable ground switch */ - snd_soc_component_update_bits(component, 0xFB, 0x01, 0x01); + /* Disable ground switch */ + snd_soc_component_update_bits(component, 0xFB, 0x01, 0x00); } } @@ -831,6 +835,32 @@ static void da7219_aad_handle_pdata(struct snd_soc_component *component) } } +static void da7219_aad_handle_gnd_switch_time(struct snd_soc_component *component) +{ + struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); + struct da7219_aad_priv *da7219_aad = da7219->aad; + u8 jack_det; + + jack_det = snd_soc_component_read(component, DA7219_ACCDET_CONFIG_2) + & DA7219_JACK_DETECT_RATE_MASK; + switch (jack_det) { + case 0x00: + da7219_aad->gnd_switch_delay = 32; + break; + case 0x10: + da7219_aad->gnd_switch_delay = 64; + break; + case 0x20: + da7219_aad->gnd_switch_delay = 128; + break; + case 0x30: + da7219_aad->gnd_switch_delay = 256; + break; + default: + da7219_aad->gnd_switch_delay = 32; + break; + } +} /* * Suspend/Resume @@ -908,9 +938,6 @@ int da7219_aad_init(struct snd_soc_component *component) snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1, DA7219_BUTTON_CONFIG_MASK, 0); - /* Enable ground switch */ - snd_soc_component_update_bits(component, 0xFB, 0x01, 0x01); - INIT_WORK(&da7219_aad->btn_det_work, da7219_aad_btn_det_work); INIT_WORK(&da7219_aad->hptest_work, da7219_aad_hptest_work); @@ -928,9 +955,10 @@ int da7219_aad_init(struct snd_soc_component *component) regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_MASK_A, &mask, DA7219_AAD_IRQ_REG_MAX); + da7219_aad_handle_gnd_switch_time(component); + return 0; } -EXPORT_SYMBOL_GPL(da7219_aad_init); void da7219_aad_exit(struct snd_soc_component *component) { @@ -948,7 +976,6 @@ void da7219_aad_exit(struct snd_soc_component *component) cancel_work_sync(&da7219_aad->btn_det_work); cancel_work_sync(&da7219_aad->hptest_work); } -EXPORT_SYMBOL_GPL(da7219_aad_exit); /* * AAD related I2C probe handling @@ -972,7 +999,6 @@ int da7219_aad_probe(struct i2c_client *i2c) return 0; } -EXPORT_SYMBOL_GPL(da7219_aad_probe); MODULE_DESCRIPTION("ASoC DA7219 AAD Driver"); MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>"); diff --git a/sound/soc/codecs/da7219-aad.h b/sound/soc/codecs/da7219-aad.h index f48a12012ef3..21fdf53095cc 100644 --- a/sound/soc/codecs/da7219-aad.h +++ b/sound/soc/codecs/da7219-aad.h @@ -187,6 +187,7 @@ enum da7219_aad_event_regs { struct da7219_aad_priv { struct snd_soc_component *component; int irq; + int gnd_switch_delay; u8 micbias_pulse_lvl; u32 micbias_pulse_time; diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 4746c8700451..7468ee4af2ea 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -2633,11 +2633,20 @@ static int da7219_resume(struct snd_soc_component *component) #define da7219_resume NULL #endif +static int da7219_set_jack(struct snd_soc_component *component, struct snd_soc_jack *jack, + void *data) +{ + da7219_aad_jack_det(component, jack); + + return 0; +} + static const struct snd_soc_component_driver soc_component_dev_da7219 = { .probe = da7219_probe, .remove = da7219_remove, .suspend = da7219_suspend, .resume = da7219_resume, + .set_jack = da7219_set_jack, .set_bias_level = da7219_set_bias_level, .controls = da7219_snd_controls, .num_controls = ARRAY_SIZE(da7219_snd_controls), diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index 87c1cc16592b..9ddf6a35e91c 100755 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -814,8 +814,7 @@ static const struct snd_soc_component_driver soc_component_dev_es8326 = { .endianness = 1, }; -static int es8326_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int es8326_i2c_probe(struct i2c_client *i2c) { struct es8326_priv *es8326; int ret; @@ -895,7 +894,7 @@ static struct i2c_driver es8326_i2c_driver = { .acpi_match_table = ACPI_PTR(es8326_acpi_match), .of_match_table = of_match_ptr(es8326_of_match), }, - .probe = es8326_i2c_probe, + .probe_new = es8326_i2c_probe, .id_table = es8326_i2c_id, }; module_i2c_driver(es8326_i2c_driver); diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c index 61e8e9be6b8d..4b8ec6f77337 100644 --- a/sound/soc/codecs/hda.c +++ b/sound/soc/codecs/hda.c @@ -130,10 +130,8 @@ static void hda_codec_unregister_dais(struct hda_codec *codec, if (strcmp(dai->driver->name, pcm->name)) continue; - if (dai->playback_widget) - snd_soc_dapm_free_widget(dai->playback_widget); - if (dai->capture_widget) - snd_soc_dapm_free_widget(dai->capture_widget); + snd_soc_dapm_free_widget(dai->playback_widget); + snd_soc_dapm_free_widget(dai->capture_widget); snd_soc_unregister_dai(dai); break; } @@ -181,7 +179,7 @@ static int hda_codec_probe(struct snd_soc_component *component) !pm_runtime_status_suspended(&hdev->dev)); #endif - hlink = snd_hdac_ext_bus_link_at(bus, hdev->addr); + hlink = snd_hdac_ext_bus_get_hlink_by_addr(bus, hdev->addr); if (!hlink) { dev_err(&hdev->dev, "hdac link not found\n"); return -EIO; @@ -213,7 +211,7 @@ static int hda_codec_probe(struct snd_soc_component *component) patch = (hda_codec_patch_t)codec->preset->driver_data; if (!patch) { - dev_err(&hdev->dev, "no patch specified?\n"); + dev_err(&hdev->dev, "no patch specified\n"); ret = -EINVAL; goto err; } @@ -289,7 +287,7 @@ static void hda_codec_remove(struct snd_soc_component *component) if (hda_codec_is_display(codec)) snd_hdac_display_power(bus, hdev->addr, false); - hlink = snd_hdac_ext_bus_link_at(bus, hdev->addr); + hlink = snd_hdac_ext_bus_get_hlink_by_addr(bus, hdev->addr); if (hlink) snd_hdac_ext_bus_link_put(bus, hlink); /* diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 8af434e14bfb..be66853afbe2 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -400,7 +400,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) hda_codec_patch_t patch; int ret; - hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev)); + hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev)); if (!hlink) { dev_err(&hdev->dev, "hdac link not found\n"); return -EIO; @@ -516,7 +516,7 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component) struct hda_codec *codec = hda_pvt->codec; struct hdac_ext_link *hlink = NULL; - hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev)); + hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev)); if (!hlink) { dev_err(&hdev->dev, "hdac link not found\n"); return; @@ -584,7 +584,7 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev) int ret; /* hold the ref while we probe */ - hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev)); + hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev)); if (!hlink) { dev_err(&hdev->dev, "hdac link not found\n"); return -EIO; diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index cb23650ad522..ed4f7cdda04f 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1967,7 +1967,7 @@ static int hdmi_codec_probe(struct snd_soc_component *component) * hold the ref while we probe, also no need to drop the ref on * exit, we call pm_runtime_suspend() so that will do for us */ - hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev)); + hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev)); if (!hlink) { dev_err(&hdev->dev, "hdac link not found\n"); return -EIO; @@ -2144,7 +2144,7 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) const struct hda_device_id *hdac_id = hdac_get_device_id(hdev, hdrv); /* hold the ref while we probe */ - hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev)); + hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev)); if (!hlink) { dev_err(&hdev->dev, "hdac link not found\n"); return -EIO; @@ -2244,7 +2244,7 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - hlink = snd_hdac_ext_bus_get_link(bus, dev_name(dev)); + hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, dev_name(dev)); if (!hlink) { dev_err(dev, "hdac link not found\n"); return -EIO; @@ -2270,7 +2270,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev) if (!bus) return 0; - hlink = snd_hdac_ext_bus_get_link(bus, dev_name(dev)); + hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, dev_name(dev)); if (!hlink) { dev_err(dev, "hdac link not found\n"); return -EIO; diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 0b1cdb2d6049..74cbbe16f9ae 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -816,12 +816,19 @@ static int hdmi_dai_probe(struct snd_soc_dai *dai) .source = "RX", }, }; - int ret; + int ret, i; dapm = snd_soc_component_get_dapm(dai->component); - ret = snd_soc_dapm_add_routes(dapm, route, 2); - if (ret) - return ret; + + /* One of the directions might be omitted for unidirectional DAIs */ + for (i = 0; i < ARRAY_SIZE(route); i++) { + if (!route[i].source || !route[i].sink) + continue; + + ret = snd_soc_dapm_add_routes(dapm, &route[i], 1); + if (ret) + return ret; + } daifmt = devm_kzalloc(dai->dev, sizeof(*daifmt), GFP_KERNEL); if (!daifmt) @@ -1009,11 +1016,24 @@ static int hdmi_codec_probe(struct platform_device *pdev) if (hcd->i2s) { daidrv[i] = hdmi_i2s_dai; daidrv[i].playback.channels_max = hcd->max_i2s_channels; + if (hcd->no_i2s_playback) + memset(&daidrv[i].playback, 0, + sizeof(daidrv[i].playback)); + if (hcd->no_i2s_capture) + memset(&daidrv[i].capture, 0, + sizeof(daidrv[i].capture)); i++; } - if (hcd->spdif) + if (hcd->spdif) { daidrv[i] = hdmi_spdif_dai; + if (hcd->no_spdif_playback) + memset(&daidrv[i].playback, 0, + sizeof(daidrv[i].playback)); + if (hcd->no_spdif_capture) + memset(&daidrv[i].capture, 0, + sizeof(daidrv[i].capture)); + } dev_set_drvdata(dev, hcp); diff --git a/sound/soc/codecs/jz4725b.c b/sound/soc/codecs/jz4725b.c index 71ea576f7e67..39cebaa167be 100644 --- a/sound/soc/codecs/jz4725b.c +++ b/sound/soc/codecs/jz4725b.c @@ -136,6 +136,24 @@ enum { #define REG_CGR3_GO1L_OFFSET 0 #define REG_CGR3_GO1L_MASK (0x1f << REG_CGR3_GO1L_OFFSET) +#define REG_CGR4_GO2R_OFFSET 0 +#define REG_CGR4_GO2R_MASK (0x1f << REG_CGR4_GO2R_OFFSET) + +#define REG_CGR5_GO2L_OFFSET 0 +#define REG_CGR5_GO2L_MASK (0x1f << REG_CGR5_GO2L_OFFSET) + +#define REG_CGR6_GO3R_OFFSET 0 +#define REG_CGR6_GO3R_MASK (0x1f << REG_CGR6_GO3R_OFFSET) + +#define REG_CGR7_GO3L_OFFSET 0 +#define REG_CGR7_GO3L_MASK (0x1f << REG_CGR7_GO3L_OFFSET) + +#define REG_CGR8_GOR_OFFSET 0 +#define REG_CGR8_GOR_MASK (0x1f << REG_CGR8_GOR_OFFSET) + +#define REG_CGR9_GOL_OFFSET 0 +#define REG_CGR9_GOL_MASK (0x1f << REG_CGR9_GOL_OFFSET) + #define REG_CGR10_GIL_OFFSET 0 #define REG_CGR10_GIR_OFFSET 4 @@ -147,9 +165,28 @@ struct jz_icdc { static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_adc_tlv, 0, 150, 0); static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_dac_tlv, -2250, 150, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(jz4725b_mix_tlv, + 0, 11, TLV_DB_SCALE_ITEM(-2250, 0, 0), + 12, 31, TLV_DB_SCALE_ITEM(-2250, 150, 0), +); + +static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(jz4725b_out_tlv, + 0, 11, TLV_DB_SCALE_ITEM(-3350, 200, 0), + 12, 23, TLV_DB_SCALE_ITEM(-1050, 100, 0), + 24, 31, TLV_DB_SCALE_ITEM( 100, 50, 0), +); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_mic_boost_tlv, 0, 2000, 0); + +static const char * const jz4725b_mic_mode_texts[] = { + "Single Ended", "Differential", +}; + +static const struct soc_enum jz4725b_mic_mode_enum = + SOC_ENUM_SINGLE(JZ4725B_CODEC_REG_CR3, REG_CR3_MICDIFF_OFFSET, + 2, jz4725b_mic_mode_texts); static const struct snd_kcontrol_new jz4725b_codec_controls[] = { - SOC_DOUBLE_TLV("Master Playback Volume", + SOC_DOUBLE_TLV("DAC Playback Volume", JZ4725B_CODEC_REG_CGR1, REG_CGR1_GODL_OFFSET, REG_CGR1_GODR_OFFSET, @@ -159,8 +196,29 @@ static const struct snd_kcontrol_new jz4725b_codec_controls[] = { REG_CGR10_GIL_OFFSET, REG_CGR10_GIR_OFFSET, 0xf, 0, jz4725b_adc_tlv), - - SOC_SINGLE("Master Playback Switch", JZ4725B_CODEC_REG_CR1, + SOC_DOUBLE_R_TLV("Mixer Line In Bypass Playback Volume", + JZ4725B_CODEC_REG_CGR3, + JZ4725B_CODEC_REG_CGR2, + REG_CGR2_GO1R_OFFSET, + 0x1f, 1, jz4725b_mix_tlv), + SOC_DOUBLE_R_TLV("Mixer Mic 1 Bypass Playback Volume", + JZ4725B_CODEC_REG_CGR5, + JZ4725B_CODEC_REG_CGR4, + REG_CGR4_GO2R_OFFSET, + 0x1f, 1, jz4725b_mix_tlv), + SOC_DOUBLE_R_TLV("Mixer Mic 2 Bypass Playback Volume", + JZ4725B_CODEC_REG_CGR7, + JZ4725B_CODEC_REG_CGR6, + REG_CGR6_GO3R_OFFSET, + 0x1f, 1, jz4725b_mix_tlv), + + SOC_DOUBLE_R_TLV("Master Playback Volume", + JZ4725B_CODEC_REG_CGR9, + JZ4725B_CODEC_REG_CGR8, + REG_CGR8_GOR_OFFSET, + 0x1f, 1, jz4725b_out_tlv), + + SOC_SINGLE("DAC Playback Switch", JZ4725B_CODEC_REG_CR1, REG_CR1_DAC_MUTE_OFFSET, 1, 1), SOC_SINGLE("Deemphasize Filter Playback Switch", @@ -170,6 +228,13 @@ static const struct snd_kcontrol_new jz4725b_codec_controls[] = { SOC_SINGLE("High-Pass Filter Capture Switch", JZ4725B_CODEC_REG_CR2, REG_CR2_ADC_HPF_OFFSET, 1, 0), + + SOC_ENUM("Mic Mode Capture Switch", jz4725b_mic_mode_enum), + + SOC_SINGLE_TLV("Mic1 Boost Capture Volume", + JZ4725B_CODEC_REG_PMR2, + REG_PMR2_GIM_OFFSET, + 1, 0, jz4725b_mic_boost_tlv), }; static const char * const jz4725b_codec_adc_src_texts[] = { @@ -186,8 +251,12 @@ static const struct snd_kcontrol_new jz4725b_codec_adc_src_ctrl = SOC_DAPM_ENUM("ADC Source Capture Route", jz4725b_codec_adc_src_enum); static const struct snd_kcontrol_new jz4725b_codec_mixer_controls[] = { - SOC_DAPM_SINGLE("Line In Bypass", JZ4725B_CODEC_REG_CR1, + SOC_DAPM_SINGLE("Line In Bypass Playback Switch", JZ4725B_CODEC_REG_CR1, REG_CR1_BYPASS_OFFSET, 1, 0), + SOC_DAPM_SINGLE("Mic 1 Bypass Playback Switch", JZ4725B_CODEC_REG_CR3, + REG_CR3_SIDETONE1_OFFSET, 1, 0), + SOC_DAPM_SINGLE("Mic 2 Bypass Playback Switch", JZ4725B_CODEC_REG_CR3, + REG_CR3_SIDETONE2_OFFSET, 1, 0), }; static int jz4725b_out_stage_enable(struct snd_soc_dapm_widget *w, @@ -282,7 +351,9 @@ static const struct snd_soc_dapm_route jz4725b_codec_dapm_routes[] = { {"Line In", NULL, "LLINEIN"}, {"Line In", NULL, "RLINEIN"}, - {"Mixer", "Line In Bypass", "Line In"}, + {"Mixer", "Mic 1 Bypass Playback Switch", "Mic 1"}, + {"Mixer", "Mic 2 Bypass Playback Switch", "Mic 2"}, + {"Mixer", "Line In Bypass Playback Switch", "Line In"}, {"DAC to Mixer", NULL, "DAC"}, {"Mixer", NULL, "DAC to Mixer"}, diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index ee15cf6b98bb..2ef62d6edc30 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -46,6 +46,7 @@ #define CDC_TX_TOP_CSR_SWR_AMIC1_CTL (0x00D4) #define CDC_TX_INP_MUX_ADC_MUXn_CFG0(n) (0x0100 + 0x8 * n) #define CDC_TX_MACRO_SWR_MIC_MUX_SEL_MASK GENMASK(3, 0) +#define CDC_TX_MACRO_DMIC_MUX_SEL_MASK GENMASK(7, 4) #define CDC_TX_INP_MUX_ADC_MUX0_CFG0 (0x0100) #define CDC_TX_INP_MUX_ADC_MUXn_CFG1(n) (0x0104 + 0x8 * n) #define CDC_TX_INP_MUX_ADC_MUX0_CFG1 (0x0104) @@ -774,7 +775,10 @@ static int tx_macro_put_dec_enum(struct snd_kcontrol *kcontrol, } if (val != 0) { - if (val < 5) { + if (widget->shift) { /* MSM DMIC */ + snd_soc_component_write_field(component, mic_sel_reg, + CDC_TXn_ADC_DMIC_SEL_MASK, 1); + } else if (val < 5) { snd_soc_component_write_field(component, mic_sel_reg, CDC_TXn_ADC_DMIC_SEL_MASK, 0); } else { @@ -1272,6 +1276,52 @@ static const struct snd_kcontrol_new tx_smic6_mux = SOC_DAPM_ENUM_EXT("tx_smic6" static const struct snd_kcontrol_new tx_smic7_mux = SOC_DAPM_ENUM_EXT("tx_smic7", tx_smic7_enum, snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum); +static const char * const dmic_mux_text[] = { + "ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3", + "DMIC4", "DMIC5", "DMIC6", "DMIC7" +}; + +static SOC_ENUM_SINGLE_DECL(tx_dmic0_enum, CDC_TX_INP_MUX_ADC_MUX0_CFG0, + 4, dmic_mux_text); + +static SOC_ENUM_SINGLE_DECL(tx_dmic1_enum, CDC_TX_INP_MUX_ADC_MUX1_CFG0, + 4, dmic_mux_text); + +static SOC_ENUM_SINGLE_DECL(tx_dmic2_enum, CDC_TX_INP_MUX_ADC_MUX2_CFG0, + 4, dmic_mux_text); + +static SOC_ENUM_SINGLE_DECL(tx_dmic3_enum, CDC_TX_INP_MUX_ADC_MUX3_CFG0, + 4, dmic_mux_text); + +static SOC_ENUM_SINGLE_DECL(tx_dmic4_enum, CDC_TX_INP_MUX_ADC_MUX4_CFG0, + 4, dmic_mux_text); + +static SOC_ENUM_SINGLE_DECL(tx_dmic5_enum, CDC_TX_INP_MUX_ADC_MUX5_CFG0, + 4, dmic_mux_text); + +static SOC_ENUM_SINGLE_DECL(tx_dmic6_enum, CDC_TX_INP_MUX_ADC_MUX6_CFG0, + 4, dmic_mux_text); + +static SOC_ENUM_SINGLE_DECL(tx_dmic7_enum, CDC_TX_INP_MUX_ADC_MUX7_CFG0, + 4, dmic_mux_text); + +static const struct snd_kcontrol_new tx_dmic0_mux = SOC_DAPM_ENUM_EXT("tx_dmic0", tx_dmic0_enum, + snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum); +static const struct snd_kcontrol_new tx_dmic1_mux = SOC_DAPM_ENUM_EXT("tx_dmic1", tx_dmic1_enum, + snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum); +static const struct snd_kcontrol_new tx_dmic2_mux = SOC_DAPM_ENUM_EXT("tx_dmic2", tx_dmic2_enum, + snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum); +static const struct snd_kcontrol_new tx_dmic3_mux = SOC_DAPM_ENUM_EXT("tx_dmic3", tx_dmic3_enum, + snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum); +static const struct snd_kcontrol_new tx_dmic4_mux = SOC_DAPM_ENUM_EXT("tx_dmic4", tx_dmic4_enum, + snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum); +static const struct snd_kcontrol_new tx_dmic5_mux = SOC_DAPM_ENUM_EXT("tx_dmic5", tx_dmic5_enum, + snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum); +static const struct snd_kcontrol_new tx_dmic6_mux = SOC_DAPM_ENUM_EXT("tx_dmic6", tx_dmic6_enum, + snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum); +static const struct snd_kcontrol_new tx_dmic7_mux = SOC_DAPM_ENUM_EXT("tx_dmic7", tx_dmic7_enum, + snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum); + static const char * const dec_mode_mux_text[] = { "ADC_DEFAULT", "ADC_LOW_PWR", "ADC_HIGH_PERF", }; @@ -1380,6 +1430,15 @@ static const struct snd_soc_dapm_widget tx_macro_dapm_widgets[] = { SND_SOC_DAPM_MUX("TX SMIC MUX6", SND_SOC_NOPM, 0, 0, &tx_smic6_mux), SND_SOC_DAPM_MUX("TX SMIC MUX7", SND_SOC_NOPM, 0, 0, &tx_smic7_mux), + SND_SOC_DAPM_MUX("TX DMIC MUX0", SND_SOC_NOPM, 4, 0, &tx_dmic0_mux), + SND_SOC_DAPM_MUX("TX DMIC MUX1", SND_SOC_NOPM, 4, 0, &tx_dmic1_mux), + SND_SOC_DAPM_MUX("TX DMIC MUX2", SND_SOC_NOPM, 4, 0, &tx_dmic2_mux), + SND_SOC_DAPM_MUX("TX DMIC MUX3", SND_SOC_NOPM, 4, 0, &tx_dmic3_mux), + SND_SOC_DAPM_MUX("TX DMIC MUX4", SND_SOC_NOPM, 4, 0, &tx_dmic4_mux), + SND_SOC_DAPM_MUX("TX DMIC MUX5", SND_SOC_NOPM, 4, 0, &tx_dmic5_mux), + SND_SOC_DAPM_MUX("TX DMIC MUX6", SND_SOC_NOPM, 4, 0, &tx_dmic6_mux), + SND_SOC_DAPM_MUX("TX DMIC MUX7", SND_SOC_NOPM, 4, 0, &tx_dmic7_mux), + SND_SOC_DAPM_INPUT("TX SWR_ADC0"), SND_SOC_DAPM_INPUT("TX SWR_ADC1"), SND_SOC_DAPM_INPUT("TX SWR_ADC2"), @@ -1392,6 +1451,14 @@ static const struct snd_soc_dapm_widget tx_macro_dapm_widgets[] = { SND_SOC_DAPM_INPUT("TX SWR_DMIC5"), SND_SOC_DAPM_INPUT("TX SWR_DMIC6"), SND_SOC_DAPM_INPUT("TX SWR_DMIC7"), + SND_SOC_DAPM_INPUT("TX DMIC0"), + SND_SOC_DAPM_INPUT("TX DMIC1"), + SND_SOC_DAPM_INPUT("TX DMIC2"), + SND_SOC_DAPM_INPUT("TX DMIC3"), + SND_SOC_DAPM_INPUT("TX DMIC4"), + SND_SOC_DAPM_INPUT("TX DMIC5"), + SND_SOC_DAPM_INPUT("TX DMIC6"), + SND_SOC_DAPM_INPUT("TX DMIC7"), SND_SOC_DAPM_MUX_E("TX DEC0 MUX", SND_SOC_NOPM, TX_MACRO_DEC0, 0, @@ -1495,6 +1562,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = { {"TX DEC6 MUX", NULL, "TX_MCLK"}, {"TX DEC7 MUX", NULL, "TX_MCLK"}, + {"TX DEC0 MUX", "MSM_DMIC", "TX DMIC MUX0"}, + {"TX DMIC MUX0", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX0", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX0", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX0", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX0", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX0", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX0", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX0", "DMIC7", "TX DMIC7"}, + {"TX DEC0 MUX", "SWR_MIC", "TX SMIC MUX0"}, {"TX SMIC MUX0", NULL, "TX_SWR_CLK"}, {"TX SMIC MUX0", "ADC0", "TX SWR_ADC0"}, @@ -1510,6 +1587,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = { {"TX SMIC MUX0", "SWR_DMIC6", "TX SWR_DMIC6"}, {"TX SMIC MUX0", "SWR_DMIC7", "TX SWR_DMIC7"}, + {"TX DEC1 MUX", "MSM_DMIC", "TX DMIC MUX1"}, + {"TX DMIC MUX1", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX1", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX1", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX1", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX1", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX1", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX1", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX1", "DMIC7", "TX DMIC7"}, + {"TX DEC1 MUX", "SWR_MIC", "TX SMIC MUX1"}, {"TX SMIC MUX1", NULL, "TX_SWR_CLK"}, {"TX SMIC MUX1", "ADC0", "TX SWR_ADC0"}, @@ -1525,6 +1612,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = { {"TX SMIC MUX1", "SWR_DMIC6", "TX SWR_DMIC6"}, {"TX SMIC MUX1", "SWR_DMIC7", "TX SWR_DMIC7"}, + {"TX DEC2 MUX", "MSM_DMIC", "TX DMIC MUX2"}, + {"TX DMIC MUX2", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX2", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX2", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX2", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX2", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX2", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX2", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX2", "DMIC7", "TX DMIC7"}, + {"TX DEC2 MUX", "SWR_MIC", "TX SMIC MUX2"}, {"TX SMIC MUX2", NULL, "TX_SWR_CLK"}, {"TX SMIC MUX2", "ADC0", "TX SWR_ADC0"}, @@ -1540,6 +1637,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = { {"TX SMIC MUX2", "SWR_DMIC6", "TX SWR_DMIC6"}, {"TX SMIC MUX2", "SWR_DMIC7", "TX SWR_DMIC7"}, + {"TX DEC3 MUX", "MSM_DMIC", "TX DMIC MUX3"}, + {"TX DMIC MUX3", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX3", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX3", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX3", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX3", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX3", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX3", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX3", "DMIC7", "TX DMIC7"}, + {"TX DEC3 MUX", "SWR_MIC", "TX SMIC MUX3"}, {"TX SMIC MUX3", NULL, "TX_SWR_CLK"}, {"TX SMIC MUX3", "ADC0", "TX SWR_ADC0"}, @@ -1555,6 +1662,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = { {"TX SMIC MUX3", "SWR_DMIC6", "TX SWR_DMIC6"}, {"TX SMIC MUX3", "SWR_DMIC7", "TX SWR_DMIC7"}, + {"TX DEC4 MUX", "MSM_DMIC", "TX DMIC MUX4"}, + {"TX DMIC MUX4", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX4", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX4", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX4", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX4", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX4", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX4", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX4", "DMIC7", "TX DMIC7"}, + {"TX DEC4 MUX", "SWR_MIC", "TX SMIC MUX4"}, {"TX SMIC MUX4", NULL, "TX_SWR_CLK"}, {"TX SMIC MUX4", "ADC0", "TX SWR_ADC0"}, @@ -1570,6 +1687,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = { {"TX SMIC MUX4", "SWR_DMIC6", "TX SWR_DMIC6"}, {"TX SMIC MUX4", "SWR_DMIC7", "TX SWR_DMIC7"}, + {"TX DEC5 MUX", "MSM_DMIC", "TX DMIC MUX5"}, + {"TX DMIC MUX5", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX5", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX5", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX5", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX5", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX5", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX5", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX5", "DMIC7", "TX DMIC7"}, + {"TX DEC5 MUX", "SWR_MIC", "TX SMIC MUX5"}, {"TX SMIC MUX5", NULL, "TX_SWR_CLK"}, {"TX SMIC MUX5", "ADC0", "TX SWR_ADC0"}, @@ -1585,6 +1712,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = { {"TX SMIC MUX5", "SWR_DMIC6", "TX SWR_DMIC6"}, {"TX SMIC MUX5", "SWR_DMIC7", "TX SWR_DMIC7"}, + {"TX DEC6 MUX", "MSM_DMIC", "TX DMIC MUX6"}, + {"TX DMIC MUX6", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX6", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX6", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX6", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX6", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX6", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX6", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX6", "DMIC7", "TX DMIC7"}, + {"TX DEC6 MUX", "SWR_MIC", "TX SMIC MUX6"}, {"TX SMIC MUX6", NULL, "TX_SWR_CLK"}, {"TX SMIC MUX6", "ADC0", "TX SWR_ADC0"}, @@ -1600,6 +1737,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = { {"TX SMIC MUX6", "SWR_DMIC6", "TX SWR_DMIC6"}, {"TX SMIC MUX6", "SWR_DMIC7", "TX SWR_DMIC7"}, + {"TX DEC7 MUX", "MSM_DMIC", "TX DMIC MUX7"}, + {"TX DMIC MUX7", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX7", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX7", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX7", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX7", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX7", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX7", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX7", "DMIC7", "TX DMIC7"}, + {"TX DEC7 MUX", "SWR_MIC", "TX SMIC MUX7"}, {"TX SMIC MUX7", NULL, "TX_SWR_CLK"}, {"TX SMIC MUX7", "ADC0", "TX SWR_ADC0"}, diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index 5e0abefe7cce..5cfe96f6e430 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -4,6 +4,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/of_clk.h> @@ -2350,14 +2351,15 @@ static int wsa_macro_register_mclk_output(struct wsa_macro *wsa) { struct device *dev = wsa->dev; const char *parent_clk_name; - const char *clk_name = "mclk"; struct clk_hw *hw; struct clk_init_data init; int ret; parent_clk_name = __clk_get_name(wsa->npl); - init.name = clk_name; + init.name = "mclk"; + of_property_read_string(dev_of_node(dev), "clock-output-names", + &init.name); init.ops = &swclk_gate_ops; init.flags = 0; init.parent_names = &parent_clk_name; diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index 899965b19d12..3cd1be743d9e 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -10,6 +10,7 @@ #include <linux/slab.h> #include <sound/pcm.h> #include <sound/pcm_params.h> +#include <sound/sdw.h> #include <sound/soc.h> #include <sound/tlv.h> #include <linux/of.h> @@ -533,10 +534,8 @@ static int max98373_sdw_dai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct max98373_priv *max98373 = 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_config stream_config = {0}; + struct sdw_port_config port_config = {0}; struct sdw_stream_data *stream; int ret, chan_sz, sampling_rate; @@ -548,28 +547,20 @@ static int max98373_sdw_dai_hw_params(struct snd_pcm_substream *substream, if (!max98373->slave) return -EINVAL; + snd_sdw_params_to_config(substream, params, &stream_config, &port_config); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - direction = SDW_DATA_DIR_RX; port_config.num = 1; + + if (max98373->slot) { + stream_config.ch_count = max98373->slot; + port_config.ch_mask = max98373->rx_mask; + } } else { - direction = SDW_DATA_DIR_TX; port_config.num = 3; - } - stream_config.frame_rate = params_rate(params); - stream_config.bps = snd_pcm_format_width(params_format(params)); - stream_config.direction = direction; - - if (max98373->slot && direction == SDW_DATA_DIR_RX) { - stream_config.ch_count = max98373->slot; - port_config.ch_mask = max98373->rx_mask; - } else { /* only IV are supported by capture */ - if (direction == SDW_DATA_DIR_TX) - stream_config.ch_count = 2; - else - stream_config.ch_count = params_channels(params); - + stream_config.ch_count = 2; port_config.ch_mask = GENMASK((int)stream_config.ch_count - 1, 0); } diff --git a/sound/soc/codecs/max98396.c b/sound/soc/codecs/max98396.c index a7b6a23f2cd8..db3de41f10e0 100644 --- a/sound/soc/codecs/max98396.c +++ b/sound/soc/codecs/max98396.c @@ -1731,9 +1731,9 @@ static void max98396_supply_disable(void *r) regulator_disable((struct regulator *) r); } -static int max98396_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int max98396_i2c_probe(struct i2c_client *i2c) { + const struct i2c_device_id *id = i2c_client_get_device_id(i2c); struct max98396_priv *max98396 = NULL; int i, ret, reg; @@ -1907,7 +1907,7 @@ static struct i2c_driver max98396_i2c_driver = { .acpi_match_table = ACPI_PTR(max98396_acpi_match), .pm = &max98396_pm, }, - .probe = max98396_i2c_probe, + .probe_new = max98396_i2c_probe, .id_table = max98396_i2c_id, }; diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index 6d2941a9dbd6..e161ab037bf7 100644 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c @@ -323,7 +323,7 @@ static int max9867_startup(struct snd_pcm_substream *substream, static int max9867_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - int value; + int value, freq = 0; unsigned long int rate, ratio; struct snd_soc_component *component = dai->component; struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); @@ -373,6 +373,35 @@ static int max9867_dai_hw_params(struct snd_pcm_substream *substream, } regmap_update_bits(max9867->regmap, MAX9867_IFC1B, MAX9867_IFC1B_BCLK_MASK, value); + + /* Exact integer mode available for 8kHz and 16kHz sample rates + * and certain PCLK (prescaled MCLK) values. + */ + if (params_rate(params) == 8000 || + params_rate(params) == 16000) { + switch (max9867->pclk) { + case 12000000: + freq = 0x08; + break; + case 13000000: + freq = 0x0A; + break; + case 16000000: + freq = 0x0C; + break; + case 19200000: + freq = 0x0E; + break; + } + } + if (freq && params_rate(params) == 16000) + freq++; + + /* If exact integer mode not available, the freq value + * remains zero, i.e. normal mode is used. + */ + regmap_update_bits(max9867->regmap, MAX9867_SYSCLK, + MAX9867_FREQ_MASK, freq); } else { /* * digital pll locks on to any externally supplied LRCLK signal @@ -428,8 +457,6 @@ static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai, freq); max9867->sysclk = freq; value = value << MAX9867_PSCLK_SHIFT; - /* exact integer mode is not supported */ - value &= ~MAX9867_FREQ_MASK; regmap_update_bits(max9867->regmap, MAX9867_SYSCLK, MAX9867_PSCLK_MASK, value); return 0; diff --git a/sound/soc/codecs/nau8315.c b/sound/soc/codecs/nau8315.c index ad4dce9e5080..125742601f88 100644 --- a/sound/soc/codecs/nau8315.c +++ b/sound/soc/codecs/nau8315.c @@ -137,6 +137,7 @@ static int nau8315_platform_probe(struct platform_device *pdev) #ifdef CONFIG_OF static const struct of_device_id nau8315_device_id[] = { { .compatible = "nuvoton,nau8315" }, + { .compatible = "nuvoton,nau8318" }, {} }; MODULE_DEVICE_TABLE(of, nau8315_device_id); @@ -145,6 +146,7 @@ MODULE_DEVICE_TABLE(of, nau8315_device_id); #ifdef CONFIG_ACPI static const struct acpi_device_id nau8315_acpi_match[] = { { "NVTN2010", 0 }, + { "NVTN2012", 0}, {}, }; MODULE_DEVICE_TABLE(acpi, nau8315_acpi_match); diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 3eac7c92df88..4bffa9c20f2b 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -1686,6 +1686,9 @@ static void nau8825_setup_auto_irq(struct nau8825 *nau8825) /* Enable internal VCO needed for interruptions */ nau8825_configure_sysclk(nau8825, NAU8825_CLK_INTERNAL, 0); + /* Raise up the internal clock for jack detection */ + regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER, + NAU8825_CLK_MCLK_SRC_MASK, 0); /* Enable ADC needed for interruptions */ regmap_update_bits(regmap, NAU8825_REG_ENA_CTRL, @@ -1733,6 +1736,121 @@ static int nau8825_button_decode(int value) return buttons; } +static int nau8825_high_imped_detection(struct nau8825 *nau8825) +{ + struct regmap *regmap = nau8825->regmap; + struct snd_soc_dapm_context *dapm = nau8825->dapm; + unsigned int adc_mg1, adc_mg2; + + /* Initial phase */ + regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL, + NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 | NAU8825_SPKR_DWN1R | + NAU8825_SPKR_DWN1L, NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2); + regmap_update_bits(regmap, NAU8825_REG_ANALOG_CONTROL_1, + NAU8825_TESTDACIN_MASK, NAU8825_TESTDACIN_GND); + regmap_write(regmap, NAU8825_REG_TRIM_SETTINGS, 0x6); + regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS, + NAU8825_MICBIAS_LOWNOISE_MASK | NAU8825_MICBIAS_VOLTAGE_MASK, + NAU8825_MICBIAS_LOWNOISE_EN); + regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL, + NAU8825_SAR_INPUT_MASK | NAU8825_SAR_TRACKING_GAIN_MASK | + NAU8825_SAR_HV_SEL_MASK | NAU8825_SAR_RES_SEL_MASK | + NAU8825_SAR_COMPARE_TIME_MASK | NAU8825_SAR_SAMPLING_TIME_MASK, + NAU8825_SAR_HV_SEL_VDDMIC | NAU8825_SAR_RES_SEL_70K); + + snd_soc_dapm_force_enable_pin(dapm, "MICBIAS"); + snd_soc_dapm_force_enable_pin(dapm, "SAR"); + snd_soc_dapm_sync(dapm); + + /* Configure settings for first reading of SARADC */ + regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL, + NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 | NAU8825_SPKR_DWN1R | + NAU8825_SPKR_DWN1L, NAU8825_SPKR_ENGND2); + regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS, + NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2, + NAU8825_MICBIAS_JKR2); + regmap_read(regmap, NAU8825_REG_SARDOUT_RAM_STATUS, &adc_mg1); + + /* Configure settings for second reading of SARADC */ + regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS, + NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2, 0); + regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL, + NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 | NAU8825_SPKR_DWN1R | + NAU8825_SPKR_DWN1L, NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 | + NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L); + regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL, + NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 | NAU8825_SPKR_DWN1R | + NAU8825_SPKR_DWN1L, NAU8825_SPKR_ENGND1); + regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS, + NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2, + NAU8825_MICBIAS_JKSLV); + regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL, + NAU8825_SAR_INPUT_MASK, NAU8825_SAR_INPUT_JKSLV); + regmap_read(regmap, NAU8825_REG_SARDOUT_RAM_STATUS, &adc_mg2); + + /* Disable phase */ + snd_soc_dapm_disable_pin(dapm, "SAR"); + snd_soc_dapm_disable_pin(dapm, "MICBIAS"); + snd_soc_dapm_sync(dapm); + + regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS, + NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_LOWNOISE_MASK | + NAU8825_MICBIAS_VOLTAGE_MASK, nau8825->micbias_voltage); + regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL, + NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 | NAU8825_SPKR_DWN1R | + NAU8825_SPKR_DWN1L, NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 | + NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L); + regmap_update_bits(regmap, NAU8825_REG_ANALOG_CONTROL_1, + NAU8825_TESTDACIN_MASK, NAU8825_TESTDACIN_GND); + regmap_write(regmap, NAU8825_REG_TRIM_SETTINGS, 0); + regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL, + NAU8825_SAR_TRACKING_GAIN_MASK | NAU8825_SAR_HV_SEL_MASK, + nau8825->sar_voltage << NAU8825_SAR_TRACKING_GAIN_SFT); + regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL, + NAU8825_SAR_COMPARE_TIME_MASK | NAU8825_SAR_SAMPLING_TIME_MASK, + (nau8825->sar_compare_time << NAU8825_SAR_COMPARE_TIME_SFT) | + (nau8825->sar_sampling_time << NAU8825_SAR_SAMPLING_TIME_SFT)); + dev_dbg(nau8825->dev, "adc_mg1:%x, adc_mg2:%x\n", adc_mg1, adc_mg2); + + /* Confirmation phase */ + if (adc_mg1 > adc_mg2) { + dev_dbg(nau8825->dev, "OMTP (micgnd1) mic connected\n"); + + /* Unground MICGND1 */ + regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL, + NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2, + NAU8825_SPKR_ENGND2); + /* Attach 2kOhm Resistor from MICBIAS to MICGND1 */ + regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS, + NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2, + NAU8825_MICBIAS_JKR2); + /* Attach SARADC to MICGND1 */ + regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL, + NAU8825_SAR_INPUT_MASK, + NAU8825_SAR_INPUT_JKR2); + } else if (adc_mg1 < adc_mg2) { + dev_dbg(nau8825->dev, "CTIA (micgnd2) mic connected\n"); + + /* Unground MICGND2 */ + regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL, + NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2, + NAU8825_SPKR_ENGND1); + /* Attach 2kOhm Resistor from MICBIAS to MICGND2 */ + regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS, + NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2, + NAU8825_MICBIAS_JKSLV); + /* Attach SARADC to MICGND2 */ + regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL, + NAU8825_SAR_INPUT_MASK, + NAU8825_SAR_INPUT_JKSLV); + } else { + dev_err(nau8825->dev, "Jack broken.\n"); + return -EINVAL; + } + + return 0; +} + static int nau8825_jack_insert(struct nau8825 *nau8825) { struct regmap *regmap = nau8825->regmap; @@ -1794,12 +1912,23 @@ static int nau8825_jack_insert(struct nau8825 *nau8825) snd_soc_dapm_sync(dapm); break; case 3: - /* detect error case */ - dev_err(nau8825->dev, "detection error; disable mic function\n"); - type = SND_JACK_HEADPHONE; + /* Detection failure case */ + dev_warn(nau8825->dev, + "Detection failure. Try the manually mechanism for jack type checking.\n"); + if (!nau8825_high_imped_detection(nau8825)) { + type = SND_JACK_HEADSET; + snd_soc_dapm_force_enable_pin(dapm, "MICBIAS"); + snd_soc_dapm_force_enable_pin(dapm, "SAR"); + snd_soc_dapm_sync(dapm); + } else + type = SND_JACK_HEADPHONE; break; } + /* Update to the default divider of internal clock for power saving */ + regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER, + NAU8825_CLK_MCLK_SRC_MASK, 0xf); + /* Leaving HPOL/R grounded after jack insert by default. They will be * ungrounded as part of the widget power up sequence at the beginning * of playback to reduce pop. diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h index d84191a7beb2..0c3a446e0e1a 100644 --- a/sound/soc/codecs/nau8825.h +++ b/sound/soc/codecs/nau8825.h @@ -155,6 +155,8 @@ /* HSD_CTRL (0xc) */ #define NAU8825_HSD_AUTO_MODE (1 << 6) /* 0 - open, 1 - short to GND */ +#define NAU8825_SPKR_ENGND1 (1 << 3) +#define NAU8825_SPKR_ENGND2 (1 << 2) #define NAU8825_SPKR_DWN1R (1 << 1) #define NAU8825_SPKR_DWN1L (1 << 0) @@ -207,6 +209,17 @@ #define NAU8825_SAR_INPUT_JKR2 (0 << 11) #define NAU8825_SAR_TRACKING_GAIN_SFT 8 #define NAU8825_SAR_TRACKING_GAIN_MASK (0x7 << NAU8825_SAR_TRACKING_GAIN_SFT) +#define NAU8825_SAR_HV_SEL_SFT 7 +#define NAU8825_SAR_HV_SEL_MASK (1 << NAU8825_SAR_HV_SEL_SFT) +#define NAU8825_SAR_HV_SEL_MICBIAS (0 << NAU8825_SAR_HV_SEL_SFT) +#define NAU8825_SAR_HV_SEL_VDDMIC (1 << NAU8825_SAR_HV_SEL_SFT) +#define NAU8825_SAR_RES_SEL_SFT 4 +#define NAU8825_SAR_RES_SEL_MASK (0x7 << NAU8825_SAR_RES_SEL_SFT) +#define NAU8825_SAR_RES_SEL_35K (0 << NAU8825_SAR_RES_SEL_SFT) +#define NAU8825_SAR_RES_SEL_70K (1 << NAU8825_SAR_RES_SEL_SFT) +#define NAU8825_SAR_RES_SEL_170K (2 << NAU8825_SAR_RES_SEL_SFT) +#define NAU8825_SAR_RES_SEL_360K (3 << NAU8825_SAR_RES_SEL_SFT) +#define NAU8825_SAR_RES_SEL_SHORTED (4 << NAU8825_SAR_RES_SEL_SFT) #define NAU8825_SAR_COMPARE_TIME_SFT 2 #define NAU8825_SAR_COMPARE_TIME_MASK (3 << 2) #define NAU8825_SAR_SAMPLING_TIME_SFT 0 @@ -385,6 +398,13 @@ #define NAU8825_BIAS_VMID_SEL_SFT 4 #define NAU8825_BIAS_VMID_SEL_MASK (3 << NAU8825_BIAS_VMID_SEL_SFT) +/* ANALOG_CONTROL_1 (0x69) */ +#define NAU8825_TESTDACIN_SFT 14 +#define NAU8825_TESTDACIN_MASK (0x3 << NAU8825_TESTDACIN_SFT) +#define NAU8825_TESTDACIN_HIGH (1 << NAU8825_TESTDACIN_SFT) +#define NAU8825_TESTDACIN_LOW (2 << NAU8825_TESTDACIN_SFT) +#define NAU8825_TESTDACIN_GND (3 << NAU8825_TESTDACIN_SFT) + /* ANALOG_CONTROL_2 (0x6a) */ #define NAU8825_HP_NON_CLASSG_CURRENT_2xADJ (1 << 12) #define NAU8825_DAC_CAPACITOR_MSB (1 << 1) @@ -412,6 +432,9 @@ /* MIC_BIAS (0x74) */ #define NAU8825_MICBIAS_JKSLV (1 << 14) #define NAU8825_MICBIAS_JKR2 (1 << 12) +#define NAU8825_MICBIAS_LOWNOISE_SFT 10 +#define NAU8825_MICBIAS_LOWNOISE_MASK (0x1 << NAU8825_MICBIAS_LOWNOISE_SFT) +#define NAU8825_MICBIAS_LOWNOISE_EN (0x1 << NAU8825_MICBIAS_LOWNOISE_SFT) #define NAU8825_MICBIAS_POWERUP_SFT 8 #define NAU8825_MICBIAS_VOLTAGE_SFT 0 #define NAU8825_MICBIAS_VOLTAGE_MASK 0x7 diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 767463e82665..89059a673cf0 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -1634,7 +1634,7 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap) if (val > 6) { dev_err(dev, "Invalid pll-in\n"); ret = -EINVAL; - goto err_clk; + goto err_pm; } pcm512x->pll_in = val; } @@ -1643,7 +1643,7 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap) if (val > 6) { dev_err(dev, "Invalid pll-out\n"); ret = -EINVAL; - goto err_clk; + goto err_pm; } pcm512x->pll_out = val; } @@ -1652,12 +1652,12 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap) dev_err(dev, "Error: both pll-in and pll-out, or none\n"); ret = -EINVAL; - goto err_clk; + goto err_pm; } if (pcm512x->pll_in && pcm512x->pll_in == pcm512x->pll_out) { dev_err(dev, "Error: pll-in == pll-out\n"); ret = -EINVAL; - goto err_clk; + goto err_pm; } } #endif diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index f99aed353f10..ca2790d63b71 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -17,6 +17,7 @@ #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> +#include <sound/sdw.h> #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/initval.h> @@ -197,6 +198,17 @@ static void rt1308_apply_calib_params(struct rt1308_sdw_priv *rt1308) efuse_c_btl_l, efuse_c_btl_r); } +static void rt1308_apply_bq_params(struct rt1308_sdw_priv *rt1308) +{ + unsigned int i, reg, data; + + for (i = 0; i < rt1308->bq_params_cnt; i += 3) { + reg = rt1308->bq_params[i] | (rt1308->bq_params[i + 1] << 8); + data = rt1308->bq_params[i + 2]; + regmap_write(rt1308->regmap, reg, data); + } +} + static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) { struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev); @@ -542,11 +554,10 @@ static int rt1308_sdw_hw_params(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct rt1308_sdw_priv *rt1308 = 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_config stream_config = {0}; + struct sdw_port_config port_config = {0}; struct sdw_stream_data *stream; - int retval, port, num_channels, ch_mask; + int retval; dev_dbg(dai->dev, "%s %s", __func__, dai->name); stream = snd_soc_dai_get_dma_data(dai, substream); @@ -558,30 +569,19 @@ static int rt1308_sdw_hw_params(struct snd_pcm_substream *substream, return -EINVAL; /* SoundWire specific configuration */ + snd_sdw_params_to_config(substream, params, &stream_config, &port_config); + /* port 1 for playback */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - direction = SDW_DATA_DIR_RX; - port = 1; - } else { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + port_config.num = 1; + else return -EINVAL; - } if (rt1308->slots) { - num_channels = rt1308->slots; - ch_mask = rt1308->rx_mask; - } else { - num_channels = params_channels(params); - ch_mask = (1 << num_channels) - 1; + stream_config.ch_count = rt1308->slots; + port_config.ch_mask = rt1308->rx_mask; } - stream_config.frame_rate = params_rate(params); - stream_config.ch_count = num_channels; - stream_config.bps = snd_pcm_format_width(params_format(params)); - stream_config.direction = direction; - - port_config.ch_mask = ch_mask; - port_config.num = port; - retval = sdw_stream_add_slave(rt1308->sdw_slave, &stream_config, &port_config, 1, stream->sdw_stream); if (retval) { @@ -619,14 +619,42 @@ static const struct sdw_slave_ops rt1308_slave_ops = { .bus_config = rt1308_bus_config, }; +static int rt1308_sdw_parse_dt(struct rt1308_sdw_priv *rt1308, struct device *dev) +{ + int ret = 0; + + device_property_read_u32(dev, "realtek,bq-params-cnt", &rt1308->bq_params_cnt); + if (rt1308->bq_params_cnt) { + rt1308->bq_params = devm_kzalloc(dev, rt1308->bq_params_cnt, GFP_KERNEL); + if (!rt1308->bq_params) { + dev_err(dev, "Could not allocate bq_params memory\n"); + ret = -ENOMEM; + } else { + ret = device_property_read_u8_array(dev, "realtek,bq-params", rt1308->bq_params, rt1308->bq_params_cnt); + if (ret < 0) + dev_err(dev, "Could not read list of realtek,bq-params\n"); + } + } + + dev_dbg(dev, "bq_params_cnt=%d\n", rt1308->bq_params_cnt); + return ret; +} + static int rt1308_sdw_component_probe(struct snd_soc_component *component) { + struct rt1308_sdw_priv *rt1308 = snd_soc_component_get_drvdata(component); int ret; + rt1308->component = component; + rt1308_sdw_parse_dt(rt1308, &rt1308->sdw_slave->dev); + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; + /* apply BQ params */ + rt1308_apply_bq_params(rt1308); + return 0; } diff --git a/sound/soc/codecs/rt1308-sdw.h b/sound/soc/codecs/rt1308-sdw.h index 62ce27799307..1eaaef9f351b 100644 --- a/sound/soc/codecs/rt1308-sdw.h +++ b/sound/soc/codecs/rt1308-sdw.h @@ -166,6 +166,8 @@ struct rt1308_sdw_priv { int rx_mask; int slots; int hw_ver; + unsigned char *bq_params; + unsigned int bq_params_cnt; }; struct sdw_stream_data { diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c index ed0a11436362..e6294cc7a995 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -14,6 +14,7 @@ #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> +#include <sound/sdw.h> #include <sound/soc-dapm.h> #include <sound/initval.h> #include "rt1316-sdw.h" @@ -254,6 +255,17 @@ static int rt1316_read_prop(struct sdw_slave *slave) return 0; } +static void rt1316_apply_bq_params(struct rt1316_sdw_priv *rt1316) +{ + unsigned int i, reg, data; + + for (i = 0; i < rt1316->bq_params_cnt; i += 3) { + reg = rt1316->bq_params[i] | (rt1316->bq_params[i + 1] << 8); + data = rt1316->bq_params[i + 2]; + regmap_write(rt1316->regmap, reg, data); + } +} + static int rt1316_io_init(struct device *dev, struct sdw_slave *slave) { struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(dev); @@ -519,11 +531,10 @@ static int rt1316_sdw_hw_params(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct rt1316_sdw_priv *rt1316 = 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_config stream_config = {0}; + struct sdw_port_config port_config = {0}; struct sdw_stream_data *stream; - int retval, port, num_channels, ch_mask; + int retval; dev_dbg(dai->dev, "%s %s", __func__, dai->name); stream = snd_soc_dai_get_dma_data(dai, substream); @@ -535,25 +546,13 @@ static int rt1316_sdw_hw_params(struct snd_pcm_substream *substream, return -EINVAL; /* SoundWire specific configuration */ - /* port 1 for playback */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - direction = SDW_DATA_DIR_RX; - port = 1; - } else { - direction = SDW_DATA_DIR_TX; - port = 2; - } - - num_channels = params_channels(params); - ch_mask = (1 << num_channels) - 1; + snd_sdw_params_to_config(substream, params, &stream_config, &port_config); - stream_config.frame_rate = params_rate(params); - stream_config.ch_count = num_channels; - stream_config.bps = snd_pcm_format_width(params_format(params)); - stream_config.direction = direction; - - port_config.ch_mask = ch_mask; - port_config.num = port; + /* port 1 for playback */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + port_config.num = 1; + else + port_config.num = 2; retval = sdw_stream_add_slave(rt1316->sdw_slave, &stream_config, &port_config, 1, stream->sdw_stream); @@ -590,14 +589,42 @@ static struct sdw_slave_ops rt1316_slave_ops = { .update_status = rt1316_update_status, }; +static int rt1316_sdw_parse_dt(struct rt1316_sdw_priv *rt1316, struct device *dev) +{ + int ret = 0; + + device_property_read_u32(dev, "realtek,bq-params-cnt", &rt1316->bq_params_cnt); + if (rt1316->bq_params_cnt) { + rt1316->bq_params = devm_kzalloc(dev, rt1316->bq_params_cnt, GFP_KERNEL); + if (!rt1316->bq_params) { + dev_err(dev, "Could not allocate bq_params memory\n"); + ret = -ENOMEM; + } else { + ret = device_property_read_u8_array(dev, "realtek,bq-params", rt1316->bq_params, rt1316->bq_params_cnt); + if (ret < 0) + dev_err(dev, "Could not read list of realtek,bq-params\n"); + } + } + + dev_dbg(dev, "bq_params_cnt=%d\n", rt1316->bq_params_cnt); + return ret; +} + static int rt1316_sdw_component_probe(struct snd_soc_component *component) { + struct rt1316_sdw_priv *rt1316 = snd_soc_component_get_drvdata(component); int ret; + rt1316->component = component; + rt1316_sdw_parse_dt(rt1316, &rt1316->sdw_slave->dev); + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; + /* apply BQ params */ + rt1316_apply_bq_params(rt1316); + return 0; } diff --git a/sound/soc/codecs/rt1316-sdw.h b/sound/soc/codecs/rt1316-sdw.h index cbcdaa8f8cfa..57dbd49993b0 100644 --- a/sound/soc/codecs/rt1316-sdw.h +++ b/sound/soc/codecs/rt1316-sdw.h @@ -46,6 +46,8 @@ struct rt1316_sdw_priv { struct sdw_bus_params params; bool hw_init; bool first_hw_init; + unsigned char *bq_params; + unsigned int bq_params_cnt; }; struct sdw_stream_data { diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c new file mode 100644 index 000000000000..f85f5ab2c6d0 --- /dev/null +++ b/sound/soc/codecs/rt1318-sdw.c @@ -0,0 +1,884 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt1318-sdw.c -- rt1318 SDCA ALSA SoC amplifier audio driver +// +// Copyright(c) 2022 Realtek Semiconductor Corp. +// +// +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/pm_runtime.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/dmi.h> +#include <linux/firmware.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include "rt1318-sdw.h" + +static const struct reg_sequence rt1318_blind_write[] = { + { 0xc001, 0x43 }, + { 0xc003, 0xa2 }, + { 0xc004, 0x44 }, + { 0xc005, 0x44 }, + { 0xc006, 0x33 }, + { 0xc007, 0x64 }, + { 0xc320, 0x20 }, + { 0xf203, 0x18 }, + { 0xf211, 0x00 }, + { 0xf212, 0x26 }, + { 0xf20d, 0x17 }, + { 0xf214, 0x06 }, + { 0xf20e, 0x00 }, + { 0xf223, 0x7f }, + { 0xf224, 0xdb }, + { 0xf225, 0xee }, + { 0xf226, 0x3f }, + { 0xf227, 0x0f }, + { 0xf21a, 0x78 }, + { 0xf242, 0x3c }, + { 0xc321, 0x0b }, + { 0xc200, 0xd8 }, + { 0xc201, 0x27 }, + { 0xc202, 0x0f }, + { 0xf800, 0x20 }, + { 0xdf00, 0x10 }, + { 0xdf5f, 0x01 }, + { 0xdf60, 0xa7 }, + { 0xc400, 0x0e }, + { 0xc401, 0x43 }, + { 0xc402, 0xe0 }, + { 0xc403, 0x00 }, + { 0xc404, 0x4c }, + { 0xc407, 0x02 }, + { 0xc408, 0x3f }, + { 0xc300, 0x01 }, + { 0xc206, 0x78 }, + { 0xc203, 0x84 }, + { 0xc120, 0xc0 }, + { 0xc121, 0x03 }, + { 0xe000, 0x88 }, + { 0xc321, 0x09 }, + { 0xc322, 0x01 }, + { 0xe706, 0x0f }, + { 0xe707, 0x30 }, + { 0xe806, 0x0f }, + { 0xe807, 0x30 }, + { 0xed00, 0xb0 }, + { 0xce04, 0x02 }, + { 0xce05, 0x63 }, + { 0xce06, 0x68 }, + { 0xce07, 0x07 }, + { 0xcf04, 0x02 }, + { 0xcf05, 0x63 }, + { 0xcf06, 0x68 }, + { 0xcf07, 0x07 }, + { 0xce60, 0xe3 }, + { 0xc130, 0x51 }, + { 0xf102, 0x00 }, + { 0xf103, 0x00 }, + { 0xf104, 0xf5 }, + { 0xf105, 0x06 }, + { 0xf109, 0x9b }, + { 0xf10a, 0x0b }, + { 0xf10b, 0x4c }, + { 0xf10b, 0x5c }, + { 0xf102, 0x00 }, + { 0xf103, 0x00 }, + { 0xf104, 0xf5 }, + { 0xf105, 0x0b }, + { 0xf109, 0x03 }, + { 0xf10a, 0x0b }, + { 0xf10b, 0x4c }, + { 0xf10b, 0x5c }, + { 0xf102, 0x00 }, + { 0xf103, 0x00 }, + { 0xf104, 0xf5 }, + { 0xf105, 0x0c }, + { 0xf109, 0x7f }, + { 0xf10a, 0x0b }, + { 0xf10b, 0x4c }, + { 0xf10b, 0x5c }, + + { 0xe604, 0x00 }, + { 0xdb00, 0x0c }, + { 0xdd00, 0x0c }, + { 0xdc19, 0x00 }, + { 0xdc1a, 0xff }, + { 0xdc1b, 0xff }, + { 0xdc1c, 0xff }, + { 0xdc1d, 0x00 }, + { 0xdc1e, 0x00 }, + { 0xdc1f, 0x00 }, + { 0xdc20, 0xff }, + { 0xde19, 0x00 }, + { 0xde1a, 0xff }, + { 0xde1b, 0xff }, + { 0xde1c, 0xff }, + { 0xde1d, 0x00 }, + { 0xde1e, 0x00 }, + { 0xde1f, 0x00 }, + { 0xde20, 0xff }, + { 0xdb32, 0x00 }, + { 0xdd32, 0x00 }, + { 0xdb33, 0x0a }, + { 0xdd33, 0x0a }, + { 0xdb34, 0x1a }, + { 0xdd34, 0x1a }, + { 0xdb17, 0xef }, + { 0xdd17, 0xef }, + { 0xdba7, 0x00 }, + { 0xdba8, 0x64 }, + { 0xdda7, 0x00 }, + { 0xdda8, 0x64 }, + { 0xdb19, 0x40 }, + { 0xdd19, 0x40 }, + { 0xdb00, 0x4c }, + { 0xdb01, 0x79 }, + { 0xdd01, 0x79 }, + { 0xdb04, 0x05 }, + { 0xdb05, 0x03 }, + { 0xdd04, 0x05 }, + { 0xdd05, 0x03 }, + { 0xdbbb, 0x09 }, + { 0xdbbc, 0x30 }, + { 0xdbbd, 0xf0 }, + { 0xdbbe, 0xf1 }, + { 0xddbb, 0x09 }, + { 0xddbc, 0x30 }, + { 0xddbd, 0xf0 }, + { 0xddbe, 0xf1 }, + { 0xdb01, 0x79 }, + { 0xdd01, 0x79 }, + { 0xdc52, 0xef }, + { 0xde52, 0xef }, + { 0x2f55, 0x22 }, +}; + +static const struct reg_default rt1318_reg_defaults[] = { + { 0x3000, 0x00 }, + { 0x3004, 0x01 }, + { 0x3005, 0x23 }, + { 0x3202, 0x00 }, + { 0x3203, 0x01 }, + { 0x3206, 0x00 }, + { 0xc000, 0x00 }, + { 0xc001, 0x43 }, + { 0xc003, 0x22 }, + { 0xc004, 0x44 }, + { 0xc005, 0x44 }, + { 0xc006, 0x33 }, + { 0xc007, 0x64 }, + { 0xc008, 0x05 }, + { 0xc00a, 0xfc }, + { 0xc00b, 0x0f }, + { 0xc00c, 0x0e }, + { 0xc00d, 0xef }, + { 0xc00e, 0xe5 }, + { 0xc00f, 0xff }, + { 0xc120, 0xc0 }, + { 0xc121, 0x00 }, + { 0xc122, 0x00 }, + { 0xc123, 0x14 }, + { 0xc125, 0x00 }, + { 0xc200, 0x00 }, + { 0xc201, 0x00 }, + { 0xc202, 0x00 }, + { 0xc203, 0x04 }, + { 0xc204, 0x00 }, + { 0xc205, 0x00 }, + { 0xc206, 0x68 }, + { 0xc207, 0x70 }, + { 0xc208, 0x00 }, + { 0xc20a, 0x00 }, + { 0xc20b, 0x01 }, + { 0xc20c, 0x7f }, + { 0xc20d, 0x01 }, + { 0xc20e, 0x7f }, + { 0xc300, 0x00 }, + { 0xc301, 0x00 }, + { 0xc303, 0x80 }, + { 0xc320, 0x00 }, + { 0xc321, 0x09 }, + { 0xc322, 0x02 }, + { 0xc410, 0x04 }, + { 0xc430, 0x00 }, + { 0xc431, 0x00 }, + { 0xca00, 0x10 }, + { 0xca01, 0x00 }, + { 0xca02, 0x0b }, + { 0xca10, 0x10 }, + { 0xca11, 0x00 }, + { 0xca12, 0x0b }, + { 0xdd93, 0x00 }, + { 0xdd94, 0x64 }, + { 0xe300, 0xa0 }, + { 0xed00, 0x80 }, + { 0xed01, 0x0f }, + { 0xed02, 0xff }, + { 0xed03, 0x00 }, + { 0xed04, 0x00 }, + { 0xed05, 0x0f }, + { 0xed06, 0xff }, + { 0xf010, 0x10 }, + { 0xf011, 0xec }, + { 0xf012, 0x68 }, + { 0xf013, 0x21 }, + { 0xf800, 0x00 }, + { 0xf801, 0x12 }, + { 0xf802, 0xe0 }, + { 0xf803, 0x2f }, + { 0xf804, 0x00 }, + { 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_CS21, RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, +}; + +static bool rt1318_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2f55: + case 0x3000: + case 0x3004 ... 0x3005: + case 0x3202 ... 0x3203: + case 0x3206: + case 0xc000 ... 0xc00f: + case 0xc120 ... 0xc125: + case 0xc200 ... 0xc20e: + case 0xc300 ... 0xc303: + case 0xc320 ... 0xc322: + case 0xc410: + case 0xc430 ... 0xc431: + case 0xca00 ... 0xca02: + case 0xca10 ... 0xca12: + case 0xcb00 ... 0xcb0b: + case 0xcc00 ... 0xcce5: + case 0xcd00 ... 0xcde5: + case 0xce00 ... 0xce6a: + case 0xcf00 ... 0xcf53: + case 0xd000 ... 0xd0cc: + case 0xd100 ... 0xd1b9: + case 0xdb00 ... 0xdc53: + case 0xdd00 ... 0xde53: + case 0xdf00 ... 0xdf6b: + case 0xe300: + case 0xeb00 ... 0xebcc: + case 0xec00 ... 0xecb9: + case 0xed00 ... 0xed06: + case 0xf010 ... 0xf014: + case 0xf800 ... 0xf807: + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_UDMPU21, RT1318_SDCA_CTL_UDMPU_CLUSTER, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_L): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_R): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23, RT1318_SDCA_CTL_REQ_POWER_STATE, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_CS21, RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_SAPU, RT1318_SDCA_CTL_SAPU_PROTECTION_MODE, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_SAPU, RT1318_SDCA_CTL_SAPU_PROTECTION_STATUS, 0): + return true; + default: + return false; + } +} + +static bool rt1318_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2f55: + case 0x3000 ... 0x3001: + case 0xc000: + case 0xc301: + case 0xc410: + case 0xc430 ... 0xc431: + case 0xdb06: + case 0xdb12: + case 0xdb1d ... 0xdb1f: + case 0xdb35: + case 0xdb37: + case 0xdb8a ... 0xdb92: + case 0xdbc5 ... 0xdbc8: + case 0xdc2b ... 0xdc49: + case 0xdd0b: + case 0xdd12: + case 0xdd1d ... 0xdd1f: + case 0xdd35: + case 0xdd8a ... 0xdd92: + case 0xddc5 ... 0xddc8: + case 0xde2b ... 0xde44: + case 0xdf4a ... 0xdf55: + case 0xe224 ... 0xe23b: + case 0xea01: + case 0xebc5: + case 0xebc8: + case 0xebcb ... 0xebcc: + case 0xed03 ... 0xed06: + case 0xf010 ... 0xf014: + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_SAPU, RT1318_SDCA_CTL_SAPU_PROTECTION_MODE, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_SAPU, RT1318_SDCA_CTL_SAPU_PROTECTION_STATUS, 0): + return true; + default: + return false; + } +} + +static const struct regmap_config rt1318_sdw_regmap = { + .reg_bits = 32, + .val_bits = 8, + .readable_reg = rt1318_readable_register, + .volatile_reg = rt1318_volatile_register, + .max_register = 0x41081488, + .reg_defaults = rt1318_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(rt1318_reg_defaults), + .cache_type = REGCACHE_RBTREE, + .use_single_read = true, + .use_single_write = true, +}; + +static int rt1318_read_prop(struct sdw_slave *slave) +{ + struct sdw_slave_prop *prop = &slave->prop; + int nval; + int i, j; + u32 bit; + unsigned long addr; + struct sdw_dpn_prop *dpn; + + prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; + prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; + prop->is_sdca = true; + + prop->paging_support = true; + + /* first we need to allocate memory for set bits in port lists */ + prop->source_ports = BIT(2); + prop->sink_ports = BIT(1); + + nval = hweight32(prop->source_ports); + prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->src_dpn_prop), GFP_KERNEL); + if (!prop->src_dpn_prop) + return -ENOMEM; + + i = 0; + dpn = prop->src_dpn_prop; + addr = prop->source_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[i].num = bit; + dpn[i].type = SDW_DPN_FULL; + dpn[i].simple_ch_prep_sm = true; + dpn[i].ch_prep_timeout = 10; + i++; + } + + /* do this again for sink now */ + nval = hweight32(prop->sink_ports); + prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->sink_dpn_prop), GFP_KERNEL); + if (!prop->sink_dpn_prop) + return -ENOMEM; + + j = 0; + dpn = prop->sink_dpn_prop; + addr = prop->sink_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[j].num = bit; + dpn[j].type = SDW_DPN_FULL; + dpn[j].simple_ch_prep_sm = true; + dpn[j].ch_prep_timeout = 10; + j++; + } + + /* set the timeout values */ + prop->clk_stop_timeout = 20; + + return 0; +} + +static int rt1318_io_init(struct device *dev, struct sdw_slave *slave) +{ + struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(dev); + + if (rt1318->hw_init) + return 0; + + if (rt1318->first_hw_init) { + regcache_cache_only(rt1318->regmap, false); + regcache_cache_bypass(rt1318->regmap, true); + } else { + /* + * PM runtime is only enabled when a Slave reports as Attached + */ + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(&slave->dev, 3000); + pm_runtime_use_autosuspend(&slave->dev); + + /* update count of parent 'active' children */ + pm_runtime_set_active(&slave->dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(&slave->dev); + + pm_runtime_enable(&slave->dev); + } + + pm_runtime_get_noresume(&slave->dev); + + /* blind write */ + regmap_multi_reg_write(rt1318->regmap, rt1318_blind_write, + ARRAY_SIZE(rt1318_blind_write)); + + if (rt1318->first_hw_init) { + regcache_cache_bypass(rt1318->regmap, false); + regcache_mark_dirty(rt1318->regmap); + } + + /* Mark Slave initialization complete */ + rt1318->first_hw_init = true; + rt1318->hw_init = true; + + pm_runtime_mark_last_busy(&slave->dev); + pm_runtime_put_autosuspend(&slave->dev); + + dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); + return 0; +} + +static int rt1318_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(&slave->dev); + + /* Update the status */ + rt1318->status = status; + + if (status == SDW_SLAVE_UNATTACHED) + rt1318->hw_init = false; + + /* + * Perform initialization only if slave status is present and + * hw_init flag is false + */ + if (rt1318->hw_init || rt1318->status != SDW_SLAVE_ATTACHED) + return 0; + + /* perform I/O transfers required for Slave initialization */ + return rt1318_io_init(&slave->dev, slave); +} + +static int rt1318_classd_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 rt1318_sdw_priv *rt1318 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt1318->regmap, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23, + RT1318_SDCA_CTL_REQ_POWER_STATE, 0), + ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt1318->regmap, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23, + RT1318_SDCA_CTL_REQ_POWER_STATE, 0), + ps3); + break; + + default: + break; + } + + return 0; +} + +static const char * const rt1318_rx_data_ch_select[] = { + "L,R", + "L,L", + "L,R", + "L,L+R", + "R,L", + "R,R", + "R,L+R", + "L+R,L", + "L+R,R", + "L+R,L+R", +}; + +static SOC_ENUM_SINGLE_DECL(rt1318_rx_data_ch_enum, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_UDMPU21, RT1318_SDCA_CTL_UDMPU_CLUSTER, 0), 0, + rt1318_rx_data_ch_select); + +static const struct snd_kcontrol_new rt1318_snd_controls[] = { + + /* UDMPU Cluster Selection */ + SOC_ENUM("RX Channel Select", rt1318_rx_data_ch_enum), +}; + +static const struct snd_kcontrol_new rt1318_sto_dac = + SOC_DAPM_DOUBLE_R("Switch", + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_L), + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_R), + 0, 1, 1); + +static const struct snd_soc_dapm_widget rt1318_dapm_widgets[] = { + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0), + + /* Digital Interface */ + SND_SOC_DAPM_SWITCH("DAC", SND_SOC_NOPM, 0, 0, &rt1318_sto_dac), + + /* Output */ + SND_SOC_DAPM_PGA_E("CLASS D", SND_SOC_NOPM, 0, 0, NULL, 0, + rt1318_classd_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_OUTPUT("SPOL"), + SND_SOC_DAPM_OUTPUT("SPOR"), + /* Input */ + SND_SOC_DAPM_PGA("FB Data", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SIGGEN("FB Gen"), +}; + +static const struct snd_soc_dapm_route rt1318_dapm_routes[] = { + { "DAC", "Switch", "DP1RX" }, + { "CLASS D", NULL, "DAC" }, + { "SPOL", NULL, "CLASS D" }, + { "SPOR", NULL, "CLASS D" }, + + { "FB Data", NULL, "FB Gen" }, + { "DP2TX", NULL, "FB Data" }, +}; + +static int rt1318_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, + int direction) +{ + struct sdw_stream_data *stream; + + if (!sdw_stream) + return 0; + + stream = kzalloc(sizeof(*stream), GFP_KERNEL); + if (!stream) + return -ENOMEM; + + stream->sdw_stream = sdw_stream; + + /* Use tx_mask or rx_mask to configure stream tag and set dma_data */ + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + dai->playback_dma_data = stream; + else + dai->capture_dma_data = stream; + + return 0; +} + +static void rt1318_sdw_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sdw_stream_data *stream; + + stream = snd_soc_dai_get_dma_data(dai, substream); + snd_soc_dai_set_dma_data(dai, substream, NULL); + kfree(stream); +} + +static int rt1318_sdw_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 rt1318_sdw_priv *rt1318 = + 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_data *stream; + int retval, port, num_channels, ch_mask; + unsigned int sampling_rate; + + dev_dbg(dai->dev, "%s %s", __func__, dai->name); + stream = snd_soc_dai_get_dma_data(dai, substream); + + if (!stream) + return -EINVAL; + + if (!rt1318->sdw_slave) + return -EINVAL; + + /* SoundWire specific configuration */ + /* port 1 for playback */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + direction = SDW_DATA_DIR_RX; + port = 1; + } else { + direction = SDW_DATA_DIR_TX; + port = 2; + } + + num_channels = params_channels(params); + ch_mask = (1 << num_channels) - 1; + + stream_config.frame_rate = params_rate(params); + stream_config.ch_count = num_channels; + stream_config.bps = snd_pcm_format_width(params_format(params)); + stream_config.direction = direction; + + port_config.ch_mask = ch_mask; + port_config.num = port; + + retval = sdw_stream_add_slave(rt1318->sdw_slave, &stream_config, + &port_config, 1, stream->sdw_stream); + if (retval) { + dev_err(dai->dev, "Unable to configure port\n"); + return retval; + } + + /* sampling rate configuration */ + switch (params_rate(params)) { + case 16000: + sampling_rate = RT1318_SDCA_RATE_16000HZ; + break; + case 32000: + sampling_rate = RT1318_SDCA_RATE_32000HZ; + break; + case 44100: + sampling_rate = RT1318_SDCA_RATE_44100HZ; + break; + case 48000: + sampling_rate = RT1318_SDCA_RATE_48000HZ; + break; + case 96000: + sampling_rate = RT1318_SDCA_RATE_96000HZ; + break; + case 192000: + sampling_rate = RT1318_SDCA_RATE_192000HZ; + break; + default: + dev_err(component->dev, "Rate %d is not supported\n", + params_rate(params)); + return -EINVAL; + } + + /* set sampling frequency */ + regmap_write(rt1318->regmap, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_CS21, RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), + sampling_rate); + + return 0; +} + +static int rt1318_sdw_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt1318_sdw_priv *rt1318 = + snd_soc_component_get_drvdata(component); + struct sdw_stream_data *stream = + snd_soc_dai_get_dma_data(dai, substream); + + if (!rt1318->sdw_slave) + return -EINVAL; + + sdw_stream_remove_slave(rt1318->sdw_slave, stream->sdw_stream); + return 0; +} + +/* + * slave_ops: callbacks for get_clock_stop_mode, clock_stop and + * port_prep are not defined for now + */ +static struct sdw_slave_ops rt1318_slave_ops = { + .read_prop = rt1318_read_prop, + .update_status = rt1318_update_status, +}; + +static int rt1318_sdw_component_probe(struct snd_soc_component *component) +{ + int ret; + struct rt1318_sdw_priv *rt1318 = snd_soc_component_get_drvdata(component); + + rt1318->component = component; + + ret = pm_runtime_resume(component->dev); + dev_dbg(&rt1318->sdw_slave->dev, "%s pm_runtime_resume, ret=%d", __func__, ret); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + +static const struct snd_soc_component_driver soc_component_sdw_rt1318 = { + .probe = rt1318_sdw_component_probe, + .controls = rt1318_snd_controls, + .num_controls = ARRAY_SIZE(rt1318_snd_controls), + .dapm_widgets = rt1318_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt1318_dapm_widgets), + .dapm_routes = rt1318_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt1318_dapm_routes), + .endianness = 1, +}; + +static const struct snd_soc_dai_ops rt1318_aif_dai_ops = { + .hw_params = rt1318_sdw_hw_params, + .hw_free = rt1318_sdw_pcm_hw_free, + .set_stream = rt1318_set_sdw_stream, + .shutdown = rt1318_sdw_shutdown, +}; + +#define RT1318_STEREO_RATES (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +#define RT1318_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver rt1318_sdw_dai[] = { + { + .name = "rt1318-aif", + .playback = { + .stream_name = "DP1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT1318_STEREO_RATES, + .formats = RT1318_FORMATS, + }, + .capture = { + .stream_name = "DP2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT1318_STEREO_RATES, + .formats = RT1318_FORMATS, + }, + .ops = &rt1318_aif_dai_ops, + }, +}; + +static int rt1318_sdw_init(struct device *dev, struct regmap *regmap, + struct sdw_slave *slave) +{ + struct rt1318_sdw_priv *rt1318; + int ret; + + rt1318 = devm_kzalloc(dev, sizeof(*rt1318), GFP_KERNEL); + if (!rt1318) + return -ENOMEM; + + dev_set_drvdata(dev, rt1318); + rt1318->sdw_slave = slave; + rt1318->regmap = regmap; + + /* + * Mark hw_init to false + * HW init will be performed when device reports present + */ + rt1318->hw_init = false; + rt1318->first_hw_init = false; + + ret = devm_snd_soc_register_component(dev, + &soc_component_sdw_rt1318, + rt1318_sdw_dai, + ARRAY_SIZE(rt1318_sdw_dai)); + + dev_dbg(&slave->dev, "%s\n", __func__); + + return ret; +} + +static int rt1318_sdw_probe(struct sdw_slave *slave, + const struct sdw_device_id *id) +{ + struct regmap *regmap; + + /* Regmap Initialization */ + regmap = devm_regmap_init_sdw(slave, &rt1318_sdw_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return rt1318_sdw_init(&slave->dev, regmap, slave); +} + +static int rt1318_sdw_remove(struct sdw_slave *slave) +{ + struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(&slave->dev); + + if (rt1318->first_hw_init) + pm_runtime_disable(&slave->dev); + + return 0; +} + +static const struct sdw_device_id rt1318_id[] = { + SDW_SLAVE_ENTRY_EXT(0x025d, 0x1318, 0x3, 0x1, 0), + {}, +}; +MODULE_DEVICE_TABLE(sdw, rt1318_id); + +static int __maybe_unused rt1318_dev_suspend(struct device *dev) +{ + struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(dev); + + if (!rt1318->hw_init) + return 0; + + regcache_cache_only(rt1318->regmap, true); + return 0; +} + +#define RT1318_PROBE_TIMEOUT 5000 + +static int __maybe_unused rt1318_dev_resume(struct device *dev) +{ + struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(dev); + unsigned long time; + + if (!rt1318->first_hw_init) + return 0; + + if (!slave->unattach_request) + goto regmap_sync; + + time = wait_for_completion_timeout(&slave->initialization_complete, + msecs_to_jiffies(RT1318_PROBE_TIMEOUT)); + if (!time) { + dev_err(&slave->dev, "Initialization not complete, timed out\n"); + return -ETIMEDOUT; + } + +regmap_sync: + slave->unattach_request = 0; + regcache_cache_only(rt1318->regmap, false); + regcache_sync(rt1318->regmap); + + return 0; +} + +static const struct dev_pm_ops rt1318_pm = { + SET_SYSTEM_SLEEP_PM_OPS(rt1318_dev_suspend, rt1318_dev_resume) + SET_RUNTIME_PM_OPS(rt1318_dev_suspend, rt1318_dev_resume, NULL) +}; + +static struct sdw_driver rt1318_sdw_driver = { + .driver = { + .name = "rt1318-sdca", + .owner = THIS_MODULE, + .pm = &rt1318_pm, + }, + .probe = rt1318_sdw_probe, + .remove = rt1318_sdw_remove, + .ops = &rt1318_slave_ops, + .id_table = rt1318_id, +}; +module_sdw_driver(rt1318_sdw_driver); + +MODULE_DESCRIPTION("ASoC RT1318 driver SDCA SDW"); +MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt1318-sdw.h b/sound/soc/codecs/rt1318-sdw.h new file mode 100644 index 000000000000..4d7ac9c4bd8d --- /dev/null +++ b/sound/soc/codecs/rt1318-sdw.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt1318-sdw.h -- RT1318 SDCA ALSA SoC audio driver header + * + * Copyright(c) 2022 Realtek Semiconductor Corp. + */ + +#ifndef __RT1318_SDW_H__ +#define __RT1318_SDW_H__ + +#include <linux/regmap.h> +#include <linux/soundwire/sdw.h> +#include <linux/soundwire/sdw_type.h> +#include <linux/soundwire/sdw_registers.h> +#include <sound/soc.h> + +/* imp-defined registers */ +#define RT1318_SAPU_SM 0x3203 + +#define R1318_TCON 0xc203 +#define R1318_TCON_RELATED_1 0xc206 + +#define R1318_SPK_TEMPERATRUE_PROTECTION_0 0xdb00 +#define R1318_SPK_TEMPERATRUE_PROTECTION_L_4 0xdb08 +#define R1318_SPK_TEMPERATRUE_PROTECTION_R_4 0xdd08 + +#define R1318_SPK_TEMPERATRUE_PROTECTION_L_6 0xdb12 +#define R1318_SPK_TEMPERATRUE_PROTECTION_R_6 0xdd12 + +#define RT1318_INIT_RECIPROCAL_REG_L_24 0xdbb5 +#define RT1318_INIT_RECIPROCAL_REG_L_23_16 0xdbb6 +#define RT1318_INIT_RECIPROCAL_REG_L_15_8 0xdbb7 +#define RT1318_INIT_RECIPROCAL_REG_L_7_0 0xdbb8 +#define RT1318_INIT_RECIPROCAL_REG_R_24 0xddb5 +#define RT1318_INIT_RECIPROCAL_REG_R_23_16 0xddb6 +#define RT1318_INIT_RECIPROCAL_REG_R_15_8 0xddb7 +#define RT1318_INIT_RECIPROCAL_REG_R_7_0 0xddb8 + +#define RT1318_INIT_R0_RECIPROCAL_SYN_L_24 0xdbc5 +#define RT1318_INIT_R0_RECIPROCAL_SYN_L_23_16 0xdbc6 +#define RT1318_INIT_R0_RECIPROCAL_SYN_L_15_8 0xdbc7 +#define RT1318_INIT_R0_RECIPROCAL_SYN_L_7_0 0xdbc8 +#define RT1318_INIT_R0_RECIPROCAL_SYN_R_24 0xddc5 +#define RT1318_INIT_R0_RECIPROCAL_SYN_R_23_16 0xddc6 +#define RT1318_INIT_R0_RECIPROCAL_SYN_R_15_8 0xddc7 +#define RT1318_INIT_R0_RECIPROCAL_SYN_R_7_0 0xddc8 + +#define RT1318_R0_COMPARE_FLAG_L 0xdb35 +#define RT1318_R0_COMPARE_FLAG_R 0xdd35 + +#define RT1318_STP_INITIAL_RS_TEMP_H 0xdd93 +#define RT1318_STP_INITIAL_RS_TEMP_L 0xdd94 + +/* RT1318 SDCA Control - function number */ +#define FUNC_NUM_SMART_AMP 0x04 + +/* RT1318 SDCA entity */ +#define RT1318_SDCA_ENT_PDE23 0x31 +#define RT1318_SDCA_ENT_XU24 0x24 +#define RT1318_SDCA_ENT_FU21 0x03 +#define RT1318_SDCA_ENT_UDMPU21 0x02 +#define RT1318_SDCA_ENT_CS21 0x21 +#define RT1318_SDCA_ENT_SAPU 0x29 + +/* RT1318 SDCA control */ +#define RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX 0x10 +#define RT1318_SDCA_CTL_REQ_POWER_STATE 0x01 +#define RT1318_SDCA_CTL_FU_MUTE 0x01 +#define RT1318_SDCA_CTL_FU_VOLUME 0x02 +#define RT1318_SDCA_CTL_UDMPU_CLUSTER 0x10 +#define RT1318_SDCA_CTL_SAPU_PROTECTION_MODE 0x10 +#define RT1318_SDCA_CTL_SAPU_PROTECTION_STATUS 0x11 + +/* RT1318 SDCA channel */ +#define CH_L 0x01 +#define CH_R 0x02 + +/* sample frequency index */ +#define RT1318_SDCA_RATE_16000HZ 0x04 +#define RT1318_SDCA_RATE_32000HZ 0x07 +#define RT1318_SDCA_RATE_44100HZ 0x08 +#define RT1318_SDCA_RATE_48000HZ 0x09 +#define RT1318_SDCA_RATE_96000HZ 0x0b +#define RT1318_SDCA_RATE_192000HZ 0x0d + + +struct rt1318_sdw_priv { + struct snd_soc_component *component; + struct regmap *regmap; + struct sdw_slave *sdw_slave; + enum sdw_slave_status status; + struct sdw_bus_params params; + bool hw_init; + bool first_hw_init; +}; + +struct sdw_stream_data { + struct sdw_stream_runtime *sdw_stream; +}; + +#endif /* __RT1318_SDW_H__ */ diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index a2ce52dafea8..cea26f3a02b6 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -1166,6 +1166,13 @@ static const struct dmi_system_id force_combo_jack_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Geminilake") } }, + { + .ident = "Intel Kabylake R RVP", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "Kabylake Client platform") + } + }, { } }; diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 0f8e6dd214b0..708e55b7431a 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2792,6 +2792,11 @@ static int rt5640_suspend(struct snd_soc_component *component) { struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); + if (rt5640->irq) { + /* disable jack interrupts during system suspend */ + disable_irq(rt5640->irq); + } + rt5640_cancel_work(rt5640); snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF); rt5640_reset(component); @@ -2815,6 +2820,9 @@ static int rt5640_resume(struct snd_soc_component *component) regcache_cache_only(rt5640->regmap, false); regcache_sync(rt5640->regmap); + if (rt5640->irq) + enable_irq(rt5640->irq); + if (rt5640->jack) { if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER) { snd_soc_component_update_bits(component, diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index c1a94229dc7e..d8a573dcb771 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -24,6 +24,7 @@ #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/jack.h> +#include <sound/sdw.h> #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/initval.h> @@ -130,11 +131,10 @@ static int rt5682_sdw_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct rt5682_priv *rt5682 = 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_config stream_config = {0}; + struct sdw_port_config port_config = {0}; struct sdw_stream_data *stream; - int retval, port, num_channels; + int retval; unsigned int val_p = 0, val_c = 0, osr_p = 0, osr_c = 0; dev_dbg(dai->dev, "%s %s", __func__, dai->name); @@ -147,22 +147,12 @@ static int rt5682_sdw_hw_params(struct snd_pcm_substream *substream, return -EINVAL; /* SoundWire specific configuration */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - direction = SDW_DATA_DIR_RX; - port = 1; - } else { - direction = SDW_DATA_DIR_TX; - port = 2; - } + snd_sdw_params_to_config(substream, params, &stream_config, &port_config); - stream_config.frame_rate = params_rate(params); - stream_config.ch_count = params_channels(params); - stream_config.bps = snd_pcm_format_width(params_format(params)); - stream_config.direction = direction; - - num_channels = params_channels(params); - port_config.ch_mask = (1 << (num_channels)) - 1; - port_config.num = port; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + port_config.num = 1; + else + port_config.num = 2; retval = sdw_stream_add_slave(rt5682->slave, &stream_config, &port_config, 1, stream->sdw_stream); diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 2df95e792900..7e3eb65afe16 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -35,6 +35,8 @@ const char *rt5682_supply_names[RT5682_NUM_SUPPLIES] = { "AVDD", "MICVDD", "VBAT", + "DBVDD", + "LDO1-IN", }; EXPORT_SYMBOL_GPL(rt5682_supply_names); diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h index 52ff0d9c36c5..d568c6993c33 100644 --- a/sound/soc/codecs/rt5682.h +++ b/sound/soc/codecs/rt5682.h @@ -1424,7 +1424,7 @@ enum { RT5682_CLK_SEL_I2S2_ASRC, }; -#define RT5682_NUM_SUPPLIES 3 +#define RT5682_NUM_SUPPLIES 5 struct rt5682_priv { struct snd_soc_component *component; diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index 80c673aa14db..f5e5dbc3b0f0 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -44,6 +44,8 @@ static const struct rt5682s_platform_data i2s_default_platform_data = { static const char *rt5682s_supply_names[RT5682S_NUM_SUPPLIES] = { [RT5682S_SUPPLY_AVDD] = "AVDD", [RT5682S_SUPPLY_MICVDD] = "MICVDD", + [RT5682S_SUPPLY_DBVDD] = "DBVDD", + [RT5682S_SUPPLY_LDO1_IN] = "LDO1-IN", }; static const struct reg_sequence patch_list[] = { @@ -3089,6 +3091,14 @@ static void rt5682s_i2c_disable_regulators(void *data) if (ret) dev_err(dev, "Failed to disable supply AVDD: %d\n", ret); + ret = regulator_disable(rt5682s->supplies[RT5682S_SUPPLY_DBVDD].consumer); + if (ret) + dev_err(dev, "Failed to disable supply DBVDD: %d\n", ret); + + ret = regulator_disable(rt5682s->supplies[RT5682S_SUPPLY_LDO1_IN].consumer); + if (ret) + dev_err(dev, "Failed to disable supply LDO1-IN: %d\n", ret); + usleep_range(1000, 1500); ret = regulator_disable(rt5682s->supplies[RT5682S_SUPPLY_MICVDD].consumer); @@ -3150,6 +3160,18 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c) return ret; } + ret = regulator_enable(rt5682s->supplies[RT5682S_SUPPLY_DBVDD].consumer); + if (ret) { + dev_err(&i2c->dev, "Failed to enable supply DBVDD: %d\n", ret); + return ret; + } + + ret = regulator_enable(rt5682s->supplies[RT5682S_SUPPLY_LDO1_IN].consumer); + if (ret) { + dev_err(&i2c->dev, "Failed to enable supply LDO1-IN: %d\n", ret); + return ret; + } + if (gpio_is_valid(rt5682s->pdata.ldo1_en)) { if (devm_gpio_request_one(&i2c->dev, rt5682s->pdata.ldo1_en, GPIOF_OUT_INIT_HIGH, "rt5682s")) diff --git a/sound/soc/codecs/rt5682s.h b/sound/soc/codecs/rt5682s.h index 45464a041765..67f86a38a1cc 100644 --- a/sound/soc/codecs/rt5682s.h +++ b/sound/soc/codecs/rt5682s.h @@ -1438,6 +1438,8 @@ struct pll_calc_map { enum { RT5682S_SUPPLY_AVDD, RT5682S_SUPPLY_MICVDD, + RT5682S_SUPPLY_DBVDD, + RT5682S_SUPPLY_LDO1_IN, RT5682S_NUM_SUPPLIES, }; diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c index 055c3ae974d8..6534c9b51442 100644 --- a/sound/soc/codecs/rt700.c +++ b/sound/soc/codecs/rt700.c @@ -19,6 +19,7 @@ #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> +#include <sound/sdw.h> #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/initval.h> @@ -910,11 +911,10 @@ static int rt700_pcm_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct rt700_priv *rt700 = 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_config stream_config = {0}; + struct sdw_port_config port_config = {0}; struct sdw_stream_data *stream; - int retval, port, num_channels; + int retval; unsigned int val = 0; dev_dbg(dai->dev, "%s %s", __func__, dai->name); @@ -927,35 +927,25 @@ static int rt700_pcm_hw_params(struct snd_pcm_substream *substream, return -EINVAL; /* SoundWire specific configuration */ + snd_sdw_params_to_config(substream, params, &stream_config, &port_config); + /* This code assumes port 1 for playback and port 2 for capture */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - direction = SDW_DATA_DIR_RX; - port = 1; - } else { - direction = SDW_DATA_DIR_TX; - port = 2; - } + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + port_config.num = 1; + else + port_config.num = 2; switch (dai->id) { case RT700_AIF1: break; case RT700_AIF2: - port += 2; + port_config.num += 2; break; default: dev_err(component->dev, "Invalid DAI id %d\n", dai->id); return -EINVAL; } - stream_config.frame_rate = params_rate(params); - stream_config.ch_count = params_channels(params); - stream_config.bps = snd_pcm_format_width(params_format(params)); - stream_config.direction = direction; - - num_channels = params_channels(params); - port_config.ch_mask = (1 << (num_channels)) - 1; - port_config.num = port; - retval = sdw_stream_add_slave(rt700->slave, &stream_config, &port_config, 1, stream->sdw_stream); if (retval) { diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c index 925268121901..b78dd5994edb 100644 --- a/sound/soc/codecs/rt711-sdca.c +++ b/sound/soc/codecs/rt711-sdca.c @@ -18,6 +18,7 @@ #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> +#include <sound/sdw.h> #include <sound/soc-dapm.h> #include <sound/initval.h> #include <sound/tlv.h> @@ -1257,11 +1258,10 @@ static int rt711_sdca_pcm_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct rt711_sdca_priv *rt711 = 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_config stream_config = {0}; + struct sdw_port_config port_config = {0}; struct sdw_stream_data *stream; - int retval, port, num_channels; + int retval; unsigned int sampling_rate; dev_dbg(dai->dev, "%s %s", __func__, dai->name); @@ -1274,28 +1274,19 @@ static int rt711_sdca_pcm_hw_params(struct snd_pcm_substream *substream, return -EINVAL; /* SoundWire specific configuration */ + snd_sdw_params_to_config(substream, params, &stream_config, &port_config); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - direction = SDW_DATA_DIR_RX; - port = 3; + port_config.num = 3; } else { - direction = SDW_DATA_DIR_TX; if (dai->id == RT711_AIF1) - port = 2; + port_config.num = 2; else if (dai->id == RT711_AIF2) - port = 4; + port_config.num = 4; else return -EINVAL; } - stream_config.frame_rate = params_rate(params); - stream_config.ch_count = params_channels(params); - stream_config.bps = snd_pcm_format_width(params_format(params)); - stream_config.direction = direction; - - num_channels = params_channels(params); - port_config.ch_mask = GENMASK(num_channels - 1, 0); - port_config.num = port; - retval = sdw_stream_add_slave(rt711->slave, &stream_config, &port_config, 1, stream->sdw_stream); if (retval) { diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index 1bf618089194..78e1da9b0738 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -19,6 +19,7 @@ #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> +#include <sound/sdw.h> #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/initval.h> @@ -999,11 +1000,10 @@ static int rt711_pcm_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct rt711_priv *rt711 = 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_config stream_config = {0}; + struct sdw_port_config port_config = {0}; struct sdw_stream_data *stream; - int retval, port, num_channels; + int retval; unsigned int val = 0; dev_dbg(dai->dev, "%s %s", __func__, dai->name); @@ -1016,28 +1016,19 @@ static int rt711_pcm_hw_params(struct snd_pcm_substream *substream, return -EINVAL; /* SoundWire specific configuration */ + snd_sdw_params_to_config(substream, params, &stream_config, &port_config); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - direction = SDW_DATA_DIR_RX; - port = 3; + port_config.num = 3; } else { - direction = SDW_DATA_DIR_TX; if (dai->id == RT711_AIF1) - port = 4; + port_config.num = 4; else if (dai->id == RT711_AIF2) - port = 2; + port_config.num = 2; else return -EINVAL; } - stream_config.frame_rate = params_rate(params); - stream_config.ch_count = params_channels(params); - stream_config.bps = snd_pcm_format_width(params_format(params)); - stream_config.direction = direction; - - num_channels = params_channels(params); - port_config.ch_mask = (1 << (num_channels)) - 1; - port_config.num = port; - retval = sdw_stream_add_slave(rt711->slave, &stream_config, &port_config, 1, stream->sdw_stream); if (retval) { diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c index ce8bbc76199a..1fca7a3f46ea 100644 --- a/sound/soc/codecs/rt715-sdca.c +++ b/sound/soc/codecs/rt715-sdca.c @@ -20,6 +20,7 @@ #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> +#include <sound/sdw.h> #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/initval.h> @@ -820,11 +821,10 @@ static int rt715_sdca_pcm_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct rt715_sdca_priv *rt715 = 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_config stream_config = {0}; + struct sdw_port_config port_config = {0}; struct rt715_sdw_stream_data *stream; - int retval, port, num_channels; + int retval; unsigned int val; stream = snd_soc_dai_get_dma_data(dai, substream); @@ -835,16 +835,16 @@ static int rt715_sdca_pcm_hw_params(struct snd_pcm_substream *substream, if (!rt715->slave) return -EINVAL; + snd_sdw_params_to_config(substream, params, &stream_config, &port_config); + switch (dai->id) { case RT715_AIF1: - direction = SDW_DATA_DIR_TX; - port = 6; + port_config.num = 6; rt715_sdca_index_write(rt715, RT715_VENDOR_REG, RT715_SDW_INPUT_SEL, 0xa500); break; case RT715_AIF2: - direction = SDW_DATA_DIR_TX; - port = 4; + port_config.num = 4; rt715_sdca_index_write(rt715, RT715_VENDOR_REG, RT715_SDW_INPUT_SEL, 0xaf00); break; @@ -853,15 +853,6 @@ static int rt715_sdca_pcm_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - stream_config.frame_rate = params_rate(params); - stream_config.ch_count = params_channels(params); - stream_config.bps = snd_pcm_format_width(params_format(params)); - stream_config.direction = direction; - - num_channels = params_channels(params); - port_config.ch_mask = GENMASK(num_channels - 1, 0); - port_config.num = port; - retval = sdw_stream_add_slave(rt715->slave, &stream_config, &port_config, 1, stream->sdw_stream); if (retval) { diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index e93240521c74..1a2036ccfbac 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -28,6 +28,7 @@ #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> +#include <sound/sdw.h> #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/initval.h> @@ -203,12 +204,12 @@ static int rt715_set_main_switch_put(struct snd_kcontrol *kcontrol, struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); - unsigned int capture_reg_H[] = {RT715_SET_GAIN_MIC_ADC_H, - RT715_SET_GAIN_LINE_ADC_H, RT715_SET_GAIN_MIX_ADC_H, - RT715_SET_GAIN_MIX_ADC2_H}; - unsigned int capture_reg_L[] = {RT715_SET_GAIN_MIC_ADC_L, - RT715_SET_GAIN_LINE_ADC_L, RT715_SET_GAIN_MIX_ADC_L, - RT715_SET_GAIN_MIX_ADC2_L}; + static const unsigned int capture_reg_H[] = { + RT715_SET_GAIN_MIC_ADC_H, RT715_SET_GAIN_LINE_ADC_H, + RT715_SET_GAIN_MIX_ADC_H, RT715_SET_GAIN_MIX_ADC2_H }; + static const unsigned int capture_reg_L[] = { + RT715_SET_GAIN_MIC_ADC_L, RT715_SET_GAIN_LINE_ADC_L, + RT715_SET_GAIN_MIX_ADC_L, RT715_SET_GAIN_MIX_ADC2_L }; unsigned int addr_h, addr_l, val_h = 0x0, val_ll, val_lr; unsigned int k_shift = RT715_DIR_IN_SFT, k_changed = 0; unsigned int read_ll, read_rl, i, j, loop_cnt = 4; @@ -283,12 +284,12 @@ static int rt715_set_main_switch_get(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); - unsigned int capture_reg_H[] = {RT715_SET_GAIN_MIC_ADC_H, - RT715_SET_GAIN_LINE_ADC_H, RT715_SET_GAIN_MIX_ADC_H, - RT715_SET_GAIN_MIX_ADC2_H}; - unsigned int capture_reg_L[] = {RT715_SET_GAIN_MIC_ADC_L, - RT715_SET_GAIN_LINE_ADC_L, RT715_SET_GAIN_MIX_ADC_L, - RT715_SET_GAIN_MIX_ADC2_L}; + static const unsigned int capture_reg_H[] = { + RT715_SET_GAIN_MIC_ADC_H, RT715_SET_GAIN_LINE_ADC_H, + RT715_SET_GAIN_MIX_ADC_H, RT715_SET_GAIN_MIX_ADC2_H }; + static const unsigned int capture_reg_L[] = { + RT715_SET_GAIN_MIC_ADC_L, RT715_SET_GAIN_LINE_ADC_L, + RT715_SET_GAIN_MIX_ADC_L, RT715_SET_GAIN_MIX_ADC2_L }; unsigned int addr_h, addr_l, val_h = 0x0, i, loop_cnt = 4; unsigned int read_ll, read_rl; @@ -311,12 +312,12 @@ static int rt715_set_main_vol_put(struct snd_kcontrol *kcontrol, struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); - unsigned int capture_reg_H[] = {RT715_SET_GAIN_MIC_ADC_H, - RT715_SET_GAIN_LINE_ADC_H, RT715_SET_GAIN_MIX_ADC_H, - RT715_SET_GAIN_MIX_ADC2_H}; - unsigned int capture_reg_L[] = {RT715_SET_GAIN_MIC_ADC_L, - RT715_SET_GAIN_LINE_ADC_L, RT715_SET_GAIN_MIX_ADC_L, - RT715_SET_GAIN_MIX_ADC2_L}; + static const unsigned int capture_reg_H[] = { + RT715_SET_GAIN_MIC_ADC_H, RT715_SET_GAIN_LINE_ADC_H, + RT715_SET_GAIN_MIX_ADC_H, RT715_SET_GAIN_MIX_ADC2_H }; + static const unsigned int capture_reg_L[] = { + RT715_SET_GAIN_MIC_ADC_L, RT715_SET_GAIN_LINE_ADC_L, + RT715_SET_GAIN_MIX_ADC_L, RT715_SET_GAIN_MIX_ADC2_L}; unsigned int addr_h, addr_l, val_h = 0x0, val_ll, val_lr; unsigned int read_ll, read_rl, i, j, loop_cnt = 4, k_changed = 0; unsigned int k_shift = RT715_DIR_IN_SFT, k_max = 0x3f; @@ -392,12 +393,12 @@ static int rt715_set_main_vol_get(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); - unsigned int capture_reg_H[] = {RT715_SET_GAIN_MIC_ADC_H, - RT715_SET_GAIN_LINE_ADC_H, RT715_SET_GAIN_MIX_ADC_H, - RT715_SET_GAIN_MIX_ADC2_H}; - unsigned int capture_reg_L[] = {RT715_SET_GAIN_MIC_ADC_L, - RT715_SET_GAIN_LINE_ADC_L, RT715_SET_GAIN_MIX_ADC_L, - RT715_SET_GAIN_MIX_ADC2_L}; + static const unsigned int capture_reg_H[] = { + RT715_SET_GAIN_MIC_ADC_H, RT715_SET_GAIN_LINE_ADC_H, + RT715_SET_GAIN_MIX_ADC_H, RT715_SET_GAIN_MIX_ADC2_H }; + static const unsigned int capture_reg_L[] = { + RT715_SET_GAIN_MIC_ADC_L, RT715_SET_GAIN_LINE_ADC_L, + RT715_SET_GAIN_MIX_ADC_L, RT715_SET_GAIN_MIX_ADC2_L }; unsigned int addr_h, addr_l, val_h = 0x0, i, loop_cnt = 4; unsigned int read_ll, read_rl; @@ -801,11 +802,10 @@ static int rt715_pcm_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct rt715_priv *rt715 = 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_config stream_config = {0}; + struct sdw_port_config port_config = {0}; struct sdw_stream_data *stream; - int retval, port, num_channels; + int retval; unsigned int val = 0; stream = snd_soc_dai_get_dma_data(dai, substream); @@ -816,15 +816,15 @@ static int rt715_pcm_hw_params(struct snd_pcm_substream *substream, if (!rt715->slave) return -EINVAL; + snd_sdw_params_to_config(substream, params, &stream_config, &port_config); + switch (dai->id) { case RT715_AIF1: - direction = SDW_DATA_DIR_TX; - port = 6; + port_config.num = 6; rt715_index_write(rt715->regmap, RT715_SDW_INPUT_SEL, 0xa500); break; case RT715_AIF2: - direction = SDW_DATA_DIR_TX; - port = 4; + port_config.num = 4; rt715_index_write(rt715->regmap, RT715_SDW_INPUT_SEL, 0xa000); break; default: @@ -832,15 +832,6 @@ static int rt715_pcm_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - stream_config.frame_rate = params_rate(params); - stream_config.ch_count = params_channels(params); - stream_config.bps = snd_pcm_format_width(params_format(params)); - stream_config.direction = direction; - - num_channels = params_channels(params); - port_config.ch_mask = (1 << (num_channels)) - 1; - port_config.num = port; - retval = sdw_stream_add_slave(rt715->slave, &stream_config, &port_config, 1, stream->sdw_stream); if (retval) { diff --git a/sound/soc/codecs/sdw-mockup.c b/sound/soc/codecs/sdw-mockup.c index 288b55368d2a..af52f2728854 100644 --- a/sound/soc/codecs/sdw-mockup.c +++ b/sound/soc/codecs/sdw-mockup.c @@ -16,6 +16,7 @@ #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> +#include <sound/sdw.h> #include <sound/soc.h> struct sdw_mockup_priv { @@ -80,12 +81,9 @@ static int sdw_mockup_pcm_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct sdw_mockup_priv *sdw_mockup = 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_config stream_config = {0}; + struct sdw_port_config port_config = {0}; struct sdw_stream_data *stream; - int num_channels; - int port; int ret; stream = snd_soc_dai_get_dma_data(dai, substream); @@ -96,22 +94,12 @@ static int sdw_mockup_pcm_hw_params(struct snd_pcm_substream *substream, return -EINVAL; /* SoundWire specific configuration */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - direction = SDW_DATA_DIR_RX; - port = 1; - } else { - direction = SDW_DATA_DIR_TX; - port = 8; - } - - stream_config.frame_rate = params_rate(params); - stream_config.ch_count = params_channels(params); - stream_config.bps = snd_pcm_format_width(params_format(params)); - stream_config.direction = direction; + snd_sdw_params_to_config(substream, params, &stream_config, &port_config); - num_channels = params_channels(params); - port_config.ch_mask = (1 << num_channels) - 1; - port_config.num = port; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + port_config.num = 1; + else + port_config.num = 8; ret = sdw_stream_add_slave(sdw_mockup->slave, &stream_config, &port_config, 1, stream->sdw_stream); diff --git a/sound/soc/codecs/simple-mux.c b/sound/soc/codecs/simple-mux.c index d30c0d24d90a..bf67de12d20b 100644 --- a/sound/soc/codecs/simple-mux.c +++ b/sound/soc/codecs/simple-mux.c @@ -55,6 +55,14 @@ static int simple_mux_control_put(struct snd_kcontrol *kcontrol, e, NULL); } +static unsigned int simple_mux_read(struct snd_soc_component *component, + unsigned int reg) +{ + struct simple_mux *priv = snd_soc_component_get_drvdata(component); + + return priv->mux; +} + static const struct snd_kcontrol_new simple_mux_mux = SOC_DAPM_ENUM_EXT("Muxer", simple_mux_enum, simple_mux_control_get, simple_mux_control_put); @@ -76,6 +84,7 @@ static const struct snd_soc_component_driver simple_mux_component_driver = { .num_dapm_widgets = ARRAY_SIZE(simple_mux_dapm_widgets), .dapm_routes = simple_mux_dapm_routes, .num_dapm_routes = ARRAY_SIZE(simple_mux_dapm_routes), + .read = simple_mux_read, }; static int simple_mux_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/src4xxx-i2c.c b/sound/soc/codecs/src4xxx-i2c.c index 43daa9dc8ab5..27026030704a 100644 --- a/sound/soc/codecs/src4xxx-i2c.c +++ b/sound/soc/codecs/src4xxx-i2c.c @@ -12,8 +12,7 @@ #include "src4xxx.h" -static int src4xxx_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int src4xxx_i2c_probe(struct i2c_client *i2c) { return src4xxx_probe(&i2c->dev, devm_regmap_init_i2c(i2c, &src4xxx_regmap_config), NULL); @@ -37,7 +36,7 @@ static struct i2c_driver src4xxx_i2c_driver = { .name = "src4xxx", .of_match_table = of_match_ptr(src4xxx_of_match), }, - .probe = src4xxx_i2c_probe, + .probe_new = src4xxx_i2c_probe, .id_table = src4xxx_i2c_ids, }; module_i2c_driver(src4xxx_i2c_driver); diff --git a/sound/soc/codecs/tas2780.c b/sound/soc/codecs/tas2780.c index afdf0c863aa1..09e7ada1bca4 100644 --- a/sound/soc/codecs/tas2780.c +++ b/sound/soc/codecs/tas2780.c @@ -591,8 +591,7 @@ static int tas2780_parse_dt(struct device *dev, struct tas2780_priv *tas2780) return 0; } -static int tas2780_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tas2780_i2c_probe(struct i2c_client *client) { struct tas2780_priv *tas2780; int result; @@ -646,7 +645,7 @@ static struct i2c_driver tas2780_i2c_driver = { .name = "tas2780", .of_match_table = of_match_ptr(tas2780_of_match), }, - .probe = tas2780_i2c_probe, + .probe_new = tas2780_i2c_probe, .id_table = tas2780_i2c_id, }; module_i2c_driver(tas2780_i2c_driver); diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 08938801daec..56e795a00e22 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -32,12 +32,12 @@ #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/err.h> #include <linux/pm.h> #include <linux/i2c.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/regulator/consumer.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/slab.h> #include <sound/core.h> #include <sound/pcm.h> @@ -45,7 +45,6 @@ #include <sound/soc.h> #include <sound/initval.h> #include <sound/tlv.h> -#include <sound/tlv320aic3x.h> #include "tlv320aic3x.h" @@ -57,8 +56,6 @@ static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = { "DRVDD", /* ADC Analog and Output Driver Voltage */ }; -static LIST_HEAD(reset_list); - struct aic3x_priv; struct aic3x_disable_nb { @@ -66,6 +63,10 @@ struct aic3x_disable_nb { struct aic3x_priv *aic3x; }; +struct aic3x_setup_data { + unsigned int gpio_func[2]; +}; + /* codec private data */ struct aic3x_priv { struct snd_soc_component *component; @@ -77,9 +78,9 @@ struct aic3x_priv { unsigned int dai_fmt; unsigned int tdm_delay; unsigned int slot_width; - struct list_head list; int master; - int gpio_reset; + struct gpio_desc *gpio_reset; + bool shared_reset; int power; u16 model; @@ -1366,8 +1367,8 @@ static int aic3x_regulator_event(struct notifier_block *nb, * Put codec to reset and require cache sync as at least one * of the supplies was disabled */ - if (gpio_is_valid(aic3x->gpio_reset)) - gpio_set_value(aic3x->gpio_reset, 0); + if (aic3x->gpio_reset) + gpiod_set_value(aic3x->gpio_reset, 1); regcache_mark_dirty(aic3x->regmap); } @@ -1387,9 +1388,9 @@ static int aic3x_set_power(struct snd_soc_component *component, int power) goto out; aic3x->power = 1; - if (gpio_is_valid(aic3x->gpio_reset)) { + if (aic3x->gpio_reset) { udelay(1); - gpio_set_value(aic3x->gpio_reset, 1); + gpiod_set_value(aic3x->gpio_reset, 0); } /* Sync reg_cache with the hardware */ @@ -1595,19 +1596,6 @@ static int aic3x_init(struct snd_soc_component *component) return 0; } -static bool aic3x_is_shared_reset(struct aic3x_priv *aic3x) -{ - struct aic3x_priv *a; - - list_for_each_entry(a, &reset_list, list) { - if (gpio_is_valid(aic3x->gpio_reset) && - aic3x->gpio_reset == a->gpio_reset) - return true; - } - - return false; -} - static int aic3x_component_probe(struct snd_soc_component *component) { struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component); @@ -1748,7 +1736,6 @@ static const struct reg_sequence aic3007_class_d[] = { int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver_data) { - struct aic3x_pdata *pdata = dev->platform_data; struct aic3x_priv *aic3x; struct aic3x_setup_data *ai3x_setup; struct device_node *np = dev->of_node; @@ -1768,28 +1755,11 @@ int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver regcache_cache_only(aic3x->regmap, true); dev_set_drvdata(dev, aic3x); - if (pdata) { - aic3x->gpio_reset = pdata->gpio_reset; - aic3x->setup = pdata->setup; - aic3x->micbias_vg = pdata->micbias_vg; - } else if (np) { + if (np) { ai3x_setup = devm_kzalloc(dev, sizeof(*ai3x_setup), GFP_KERNEL); if (!ai3x_setup) return -ENOMEM; - ret = of_get_named_gpio(np, "reset-gpios", 0); - if (ret >= 0) { - aic3x->gpio_reset = ret; - } else { - ret = of_get_named_gpio(np, "gpio-reset", 0); - if (ret > 0) { - dev_warn(dev, "Using deprecated property \"gpio-reset\", please update your DT"); - aic3x->gpio_reset = ret; - } else { - aic3x->gpio_reset = -1; - } - } - if (of_property_read_u32_array(np, "ai3x-gpio-func", ai3x_setup->gpio_func, 2) >= 0) { aic3x->setup = ai3x_setup; @@ -1814,29 +1784,43 @@ int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver } else { aic3x->micbias_vg = AIC3X_MICBIAS_OFF; } - - } else { - aic3x->gpio_reset = -1; } aic3x->model = driver_data; - if (gpio_is_valid(aic3x->gpio_reset) && - !aic3x_is_shared_reset(aic3x)) { - ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset"); - if (ret != 0) - goto err; - gpio_direction_output(aic3x->gpio_reset, 0); + aic3x->gpio_reset = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + ret = PTR_ERR_OR_ZERO(aic3x->gpio_reset); + if (ret) { + if (ret != -EBUSY) + return ret; + + /* + * Apparently there are setups where the codec is sharing + * its reset line. Try to get it non-exclusively, although + * the utility of this is unclear: how do we make sure that + * resetting one chip will not disturb the others that share + * the same line? + */ + aic3x->gpio_reset = devm_gpiod_get(dev, "reset", + GPIOD_ASIS | GPIOD_FLAGS_BIT_NONEXCLUSIVE); + ret = PTR_ERR_OR_ZERO(aic3x->gpio_reset); + if (ret) + return ret; + + aic3x->shared_reset = true; } + gpiod_set_consumer_name(aic3x->gpio_reset, "tlv320aic3x reset"); + for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) aic3x->supplies[i].supply = aic3x_supply_names[i]; ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(aic3x->supplies), aic3x->supplies); - if (ret != 0) { + if (ret) { dev_err(dev, "Failed to request supplies: %d\n", ret); - goto err_gpio; + return ret; } aic3x_configure_ocmv(dev, aic3x); @@ -1845,26 +1829,14 @@ int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver ret = regmap_register_patch(aic3x->regmap, aic3007_class_d, ARRAY_SIZE(aic3007_class_d)); if (ret != 0) - dev_err(dev, "Failed to init class D: %d\n", - ret); + dev_err(dev, "Failed to init class D: %d\n", ret); } ret = devm_snd_soc_register_component(dev, &soc_component_dev_aic3x, &aic3x_dai, 1); - - if (ret != 0) - goto err_gpio; - - INIT_LIST_HEAD(&aic3x->list); - list_add(&aic3x->list, &reset_list); + if (ret) + return ret; return 0; - -err_gpio: - if (gpio_is_valid(aic3x->gpio_reset) && - !aic3x_is_shared_reset(aic3x)) - gpio_free(aic3x->gpio_reset); -err: - return ret; } EXPORT_SYMBOL(aic3x_probe); @@ -1872,13 +1844,9 @@ void aic3x_remove(struct device *dev) { struct aic3x_priv *aic3x = dev_get_drvdata(dev); - list_del(&aic3x->list); - - if (gpio_is_valid(aic3x->gpio_reset) && - !aic3x_is_shared_reset(aic3x)) { - gpio_set_value(aic3x->gpio_reset, 0); - gpio_free(aic3x->gpio_reset); - } + /* Leave the codec in reset state */ + if (aic3x->gpio_reset && !aic3x->shared_reset) + gpiod_set_value(aic3x->gpio_reset, 1); } EXPORT_SYMBOL(aic3x_remove); diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index 14298f9e6d9b..066e5a6322b8 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h @@ -298,4 +298,47 @@ enum { #define AIC3X_BUTTON_DEBOUNCE_SHIFT 0 #define AIC3X_BUTTON_DEBOUNCE_MASK 3 +/* GPIO API */ +enum { + AIC3X_GPIO1_FUNC_DISABLED = 0, + AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC = 1, + AIC3X_GPIO1_FUNC_CLOCK_MUX = 2, + AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2 = 3, + AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4 = 4, + AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8 = 5, + AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ = 6, + AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ = 7, + AIC3X_GPIO1_FUNC_INPUT = 8, + AIC3X_GPIO1_FUNC_OUTPUT = 9, + AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK = 10, + AIC3X_GPIO1_FUNC_AUDIO_WORDCLK = 11, + AIC3X_GPIO1_FUNC_BUTTON_IRQ = 12, + AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ = 13, + AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 14, + AIC3X_GPIO1_FUNC_ALL_IRQ = 16 +}; + +enum { + AIC3X_GPIO2_FUNC_DISABLED = 0, + AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ = 2, + AIC3X_GPIO2_FUNC_INPUT = 3, + AIC3X_GPIO2_FUNC_OUTPUT = 4, + AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT = 5, + AIC3X_GPIO2_FUNC_AUDIO_BITCLK = 8, + AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9, + AIC3X_GPIO2_FUNC_ALL_IRQ = 10, + AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11, + AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12, + AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ = 13, + AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ = 14, + AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ = 15 +}; + +enum aic3x_micbias_voltage { + AIC3X_MICBIAS_OFF = 0, + AIC3X_MICBIAS_2_0V = 1, + AIC3X_MICBIAS_2_5V = 2, + AIC3X_MICBIAS_AVDDV = 3, +}; + #endif /* _AIC3X_H */ diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index e48768233e20..9c50ac356c89 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -700,8 +700,10 @@ static void headset_ramp(struct snd_soc_component *component, int ramp) struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component); struct twl4030_board_params *board_params = twl4030->board_params; /* Base values for ramp delay calculation: 2^19 - 2^26 */ - unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304, - 8388608, 16777216, 33554432, 67108864}; + static const unsigned int ramp_base[] = { + 524288, 1048576, 2097152, 4194304, + 8388608, 16777216, 33554432, 67108864 + }; unsigned int delay; hs_gain = twl4030_read(component, TWL4030_REG_HS_GAIN_SET); diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c index 4c7ebc7fb400..a75db27e5205 100644 --- a/sound/soc/codecs/wcd-clsh-v2.c +++ b/sound/soc/codecs/wcd-clsh-v2.c @@ -130,12 +130,6 @@ static inline void wcd_enable_clsh_block(struct wcd_clsh_ctrl *ctrl, ctrl->clsh_users = 0; } -static inline bool wcd_clsh_enable_status(struct snd_soc_component *comp) -{ - return snd_soc_component_read(comp, WCD9XXX_A_CDC_CLSH_CRC) & - WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK; -} - static inline void wcd_clsh_set_buck_mode(struct snd_soc_component *comp, int mode) { diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index aca06a4026f3..fcac763b04d1 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -3128,8 +3128,8 @@ static inline void wcd938x_mbhc_get_result_params(struct wcd938x_priv *wcd938x, s16 c1; s32 x1, d1; int32_t denom; - int minCode_param[] = { - 3277, 1639, 820, 410, 205, 103, 52, 26 + static const int minCode_param[] = { + 3277, 1639, 820, 410, 205, 103, 52, 26 }; regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MBHC_ZDET, 0x20, 0x20); diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index 7dc6aaf65576..a4857024711d 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -971,9 +971,16 @@ static const struct i2c_device_id wm8961_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, wm8961_i2c_id); +static const struct of_device_id wm8961_of_match[] __maybe_unused = { + { .compatible = "wlf,wm8961", }, + { } +}; +MODULE_DEVICE_TABLE(of, wm8961_of_match); + static struct i2c_driver wm8961_i2c_driver = { .driver = { .name = "wm8961", + .of_match_table = of_match_ptr(wm8961_of_match), }, .probe_new = wm8961_i2c_probe, .id_table = wm8961_i2c_id, diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index a682f8020eb6..aa2f55401a88 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -498,7 +498,7 @@ static int wm8978_configure_pll(struct snd_soc_component *component) if (4 * f_opclk < 3 * f_mclk) /* Have to use OPCLKDIV */ - opclk_div = (3 * f_mclk / 4 + f_opclk - 1) / f_opclk; + opclk_div = DIV_ROUND_UP(3 * f_mclk / 4, f_opclk); else opclk_div = 1; diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 8a2e9771bb50..ea0dbc634ecf 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -19,6 +19,7 @@ #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> +#include <linux/vmalloc.h> #include <linux/workqueue.h> #include <linux/debugfs.h> #include <sound/core.h> @@ -419,16 +420,21 @@ static int wm_coeff_tlv_put(struct snd_kcontrol *kctl, (struct soc_bytes_ext *)kctl->private_value; struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl; + void *scratch; int ret = 0; - mutex_lock(&cs_ctl->dsp->pwr_lock); + scratch = vmalloc(size); + if (!scratch) + return -ENOMEM; - if (copy_from_user(cs_ctl->cache, bytes, size)) + if (copy_from_user(scratch, bytes, size)) { ret = -EFAULT; - else - ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, cs_ctl->cache, size); - - mutex_unlock(&cs_ctl->dsp->pwr_lock); + } else { + mutex_lock(&cs_ctl->dsp->pwr_lock); + ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, scratch, size); + mutex_unlock(&cs_ctl->dsp->pwr_lock); + } + vfree(scratch); return ret; } @@ -455,7 +461,10 @@ static int wm_coeff_put_acked(struct snd_kcontrol *kctl, mutex_unlock(&cs_ctl->dsp->pwr_lock); - return ret; + if (ret < 0) + return ret; + + return 1; } static int wm_coeff_get(struct snd_kcontrol *kctl, @@ -682,10 +691,10 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type, int ret; ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len); - if (ret) + if (ret < 0) return ret; - if (cs_ctl->flags & WMFW_CTL_FLAG_SYS) + if (ret == 0 || (cs_ctl->flags & WMFW_CTL_FLAG_SYS)) return 0; ctl = cs_ctl->priv; @@ -1035,6 +1044,16 @@ int wm_adsp_early_event(struct snd_soc_dapm_widget *w, } EXPORT_SYMBOL_GPL(wm_adsp_early_event); +static int wm_adsp_pre_run(struct cs_dsp *cs_dsp) +{ + struct wm_adsp *dsp = container_of(cs_dsp, struct wm_adsp, cs_dsp); + + if (!dsp->pre_run) + return 0; + + return (*dsp->pre_run)(dsp); +} + static int wm_adsp_event_post_run(struct cs_dsp *cs_dsp) { struct wm_adsp *dsp = container_of(cs_dsp, struct wm_adsp, cs_dsp); @@ -2043,9 +2062,11 @@ static const struct cs_dsp_client_ops wm_adsp1_client_ops = { static const struct cs_dsp_client_ops wm_adsp2_client_ops = { .control_add = wm_adsp_control_add, .control_remove = wm_adsp_control_remove, + .pre_run = wm_adsp_pre_run, .post_run = wm_adsp_event_post_run, .post_stop = wm_adsp_event_post_stop, .watchdog_expired = wm_adsp_fatal_error, }; MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(FW_CS_DSP); diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 375009a65828..dc2f7a096e26 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -36,6 +36,7 @@ struct wm_adsp { int fw; struct work_struct boot_work; + int (*pre_run)(struct wm_adsp *dsp); bool preloaded; bool fatal_error; diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index c7b10bbfba7e..966ba4909204 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -7,7 +7,7 @@ #include <linux/debugfs.h> #include <linux/delay.h> #include <linux/device.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> @@ -1380,22 +1380,19 @@ static int wsa883x_probe(struct sdw_slave *pdev, return -ENOMEM; wsa883x->vdd = devm_regulator_get(dev, "vdd"); - if (IS_ERR(wsa883x->vdd)) { - dev_err(dev, "No vdd regulator found\n"); - return PTR_ERR(wsa883x->vdd); - } + if (IS_ERR(wsa883x->vdd)) + return dev_err_probe(dev, PTR_ERR(wsa883x->vdd), + "No vdd regulator found\n"); ret = regulator_enable(wsa883x->vdd); - if (ret) { - dev_err(dev, "Failed to enable vdd regulator (%d)\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to enable vdd regulator\n"); wsa883x->sd_n = devm_gpiod_get_optional(&pdev->dev, "powerdown", - GPIOD_FLAGS_BIT_NONEXCLUSIVE); + GPIOD_FLAGS_BIT_NONEXCLUSIVE | GPIOD_OUT_HIGH); if (IS_ERR(wsa883x->sd_n)) { - dev_err(&pdev->dev, "Shutdown Control GPIO not found\n"); - ret = PTR_ERR(wsa883x->sd_n); + ret = dev_err_probe(&pdev->dev, PTR_ERR(wsa883x->sd_n), + "Shutdown Control GPIO not found\n"); goto err; } @@ -1411,12 +1408,13 @@ static int wsa883x_probe(struct sdw_slave *pdev, pdev->prop.simple_clk_stop_capable = true; pdev->prop.sink_dpn_prop = wsa_sink_dpn_prop; pdev->prop.scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; - gpiod_direction_output(wsa883x->sd_n, 1); + gpiod_direction_output(wsa883x->sd_n, 0); wsa883x->regmap = devm_regmap_init_sdw(pdev, &wsa883x_regmap_config); if (IS_ERR(wsa883x->regmap)) { - dev_err(&pdev->dev, "regmap_init failed\n"); - ret = PTR_ERR(wsa883x->regmap); + gpiod_direction_output(wsa883x->sd_n, 1); + ret = dev_err_probe(&pdev->dev, PTR_ERR(wsa883x->regmap), + "regmap_init failed\n"); goto err; } pm_runtime_set_autosuspend_delay(dev, 3000); |