diff options
Diffstat (limited to 'sound/soc/codecs')
26 files changed, 315 insertions, 96 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 2a62dbd5339e..c2de4ee72183 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -715,6 +715,7 @@ config SND_SOC_CS35L41_I2C config SND_SOC_CS35L45 tristate + select REGMAP_IRQ config SND_SOC_CS35L45_SPI tristate "Cirrus Logic CS35L45 CODEC (SPI)" @@ -1942,6 +1943,7 @@ config SND_SOC_WCD934X tristate "WCD9340/WCD9341 Codec" depends on COMMON_CLK depends on SLIMBUS + select REGMAP_IRQ select REGMAP_SLIMBUS select SND_SOC_WCD_MBHC depends on MFD_WCD934X || COMPILE_TEST diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index 6ac501f008ec..8a879b6f4829 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -168,7 +168,7 @@ static int cs35l41_get_fs_mon_config_index(int freq) static const DECLARE_TLV_DB_RANGE(dig_vol_tlv, 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), 1, 913, TLV_DB_MINMAX_ITEM(-10200, 1200)); -static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 0, 1, 1); +static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 50, 100, 0); static const struct snd_kcontrol_new dre_ctrl = SOC_DAPM_SINGLE("Switch", CS35L41_PWR_CTRL3, 20, 1, 0); diff --git a/sound/soc/codecs/cs35l56-i2c.c b/sound/soc/codecs/cs35l56-i2c.c index ed2a41943d97..40666e6698ba 100644 --- a/sound/soc/codecs/cs35l56-i2c.c +++ b/sound/soc/codecs/cs35l56-i2c.c @@ -62,10 +62,19 @@ static const struct i2c_device_id cs35l56_id_i2c[] = { }; MODULE_DEVICE_TABLE(i2c, cs35l56_id_i2c); +#ifdef CONFIG_ACPI +static const struct acpi_device_id cs35l56_asoc_acpi_match[] = { + { "CSC355C", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, cs35l56_asoc_acpi_match); +#endif + static struct i2c_driver cs35l56_i2c_driver = { .driver = { .name = "cs35l56", .pm = &cs35l56_pm_ops_i2c_spi, + .acpi_match_table = ACPI_PTR(cs35l56_asoc_acpi_match), }, .id_table = cs35l56_id_i2c, .probe = cs35l56_i2c_probe, diff --git a/sound/soc/codecs/cs35l56-spi.c b/sound/soc/codecs/cs35l56-spi.c index 996aab10500e..302f9c47407a 100644 --- a/sound/soc/codecs/cs35l56-spi.c +++ b/sound/soc/codecs/cs35l56-spi.c @@ -59,10 +59,19 @@ static const struct spi_device_id cs35l56_id_spi[] = { }; MODULE_DEVICE_TABLE(spi, cs35l56_id_spi); +#ifdef CONFIG_ACPI +static const struct acpi_device_id cs35l56_asoc_acpi_match[] = { + { "CSC355C", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, cs35l56_asoc_acpi_match); +#endif + static struct spi_driver cs35l56_spi_driver = { .driver = { .name = "cs35l56", .pm = &cs35l56_pm_ops_i2c_spi, + .acpi_match_table = ACPI_PTR(cs35l56_asoc_acpi_match), }, .id_table = cs35l56_id_spi, .probe = cs35l56_spi_probe, diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index c03f9d3c9a13..fd06b9f9d496 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -5,7 +5,6 @@ // Copyright (C) 2023 Cirrus Logic, Inc. and // Cirrus Logic International Semiconductor Ltd. -#include <linux/acpi.h> #include <linux/completion.h> #include <linux/debugfs.h> #include <linux/delay.h> @@ -1354,26 +1353,22 @@ static int cs35l56_dsp_init(struct cs35l56_private *cs35l56) return 0; } -static int cs35l56_acpi_get_name(struct cs35l56_private *cs35l56) +static int cs35l56_get_firmware_uid(struct cs35l56_private *cs35l56) { - acpi_handle handle = ACPI_HANDLE(cs35l56->dev); - const char *sub; + struct device *dev = cs35l56->dev; + const char *prop; + int ret; - /* If there is no ACPI_HANDLE, there is no ACPI for this system, return 0 */ - if (!handle) + ret = device_property_read_string(dev, "cirrus,firmware-uid", &prop); + /* If bad sw node property, return 0 and fallback to legacy firmware path */ + if (ret < 0) return 0; - sub = acpi_get_subsystem_id(handle); - if (IS_ERR(sub)) { - /* If bad ACPI, return 0 and fallback to legacy firmware path, otherwise fail */ - if (PTR_ERR(sub) == -ENODATA) - return 0; - else - return PTR_ERR(sub); - } + cs35l56->dsp.system_name = devm_kstrdup(dev, prop, GFP_KERNEL); + if (cs35l56->dsp.system_name == NULL) + return -ENOMEM; - cs35l56->dsp.system_name = sub; - dev_dbg(cs35l56->dev, "Subsystem ID: %s\n", cs35l56->dsp.system_name); + dev_dbg(dev, "Firmware UID: %s\n", cs35l56->dsp.system_name); return 0; } @@ -1417,7 +1412,7 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56) gpiod_set_value_cansleep(cs35l56->reset_gpio, 1); } - ret = cs35l56_acpi_get_name(cs35l56); + ret = cs35l56_get_firmware_uid(cs35l56); if (ret != 0) goto err; @@ -1604,8 +1599,6 @@ void cs35l56_remove(struct cs35l56_private *cs35l56) regcache_cache_only(cs35l56->regmap, true); - kfree(cs35l56->dsp.system_name); - gpiod_set_value_cansleep(cs35l56->reset_gpio, 0); regulator_bulk_disable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies); } diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c index b2106ff6a7cb..e7db7bcd0296 100644 --- a/sound/soc/codecs/cs42l51-i2c.c +++ b/sound/soc/codecs/cs42l51-i2c.c @@ -19,6 +19,12 @@ static struct i2c_device_id cs42l51_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, cs42l51_i2c_id); +const struct of_device_id cs42l51_of_match[] = { + { .compatible = "cirrus,cs42l51", }, + { } +}; +MODULE_DEVICE_TABLE(of, cs42l51_of_match); + static int cs42l51_i2c_probe(struct i2c_client *i2c) { struct regmap_config config; diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index a67cd3ee84e0..a7079ae0ca09 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -823,13 +823,6 @@ int __maybe_unused cs42l51_resume(struct device *dev) } EXPORT_SYMBOL_GPL(cs42l51_resume); -const struct of_device_id cs42l51_of_match[] = { - { .compatible = "cirrus,cs42l51", }, - { } -}; -MODULE_DEVICE_TABLE(of, cs42l51_of_match); -EXPORT_SYMBOL_GPL(cs42l51_of_match); - MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>"); MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs42l51.h b/sound/soc/codecs/cs42l51.h index a79343e8a54e..125703ede113 100644 --- a/sound/soc/codecs/cs42l51.h +++ b/sound/soc/codecs/cs42l51.h @@ -16,7 +16,6 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap); void cs42l51_remove(struct device *dev); int __maybe_unused cs42l51_suspend(struct device *dev); int __maybe_unused cs42l51_resume(struct device *dev); -extern const struct of_device_id cs42l51_of_match[]; #define CS42L51_CHIP_ID 0x1B #define CS42L51_CHIP_REV_A 0x00 diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c index c65256bd526d..581b334a6631 100644 --- a/sound/soc/codecs/da7219-aad.c +++ b/sound/soc/codecs/da7219-aad.c @@ -361,11 +361,15 @@ static irqreturn_t da7219_aad_irq_thread(int irq, void *data) struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); u8 events[DA7219_AAD_IRQ_REG_MAX]; u8 statusa; - int i, report = 0, mask = 0; + int i, ret, report = 0, mask = 0; /* Read current IRQ events */ - regmap_bulk_read(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A, - events, DA7219_AAD_IRQ_REG_MAX); + ret = regmap_bulk_read(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A, + events, DA7219_AAD_IRQ_REG_MAX); + if (ret) { + dev_warn_ratelimited(component->dev, "Failed to read IRQ events: %d\n", ret); + return IRQ_NONE; + } if (!events[DA7219_AAD_IRQ_REG_A] && !events[DA7219_AAD_IRQ_REG_B]) return IRQ_NONE; @@ -944,6 +948,8 @@ void da7219_aad_suspend(struct snd_soc_component *component) } } } + + synchronize_irq(da7219_aad->irq); } void da7219_aad_resume(struct snd_soc_component *component) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 34cf60769b62..65e497b455d3 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -153,7 +153,7 @@ static const char * const es8316_dmic_txt[] = { "dmic data at high level", "dmic data at low level", }; -static const unsigned int es8316_dmic_values[] = { 0, 1, 2 }; +static const unsigned int es8316_dmic_values[] = { 0, 2, 3 }; static const struct soc_enum es8316_dmic_src_enum = SOC_VALUE_ENUM_SINGLE(ES8316_ADC_DMIC, 0, 3, ARRAY_SIZE(es8316_dmic_txt), diff --git a/sound/soc/codecs/max98363.c b/sound/soc/codecs/max98363.c index b5c69bba0e48..2dfaf4fcfbd3 100644 --- a/sound/soc/codecs/max98363.c +++ b/sound/soc/codecs/max98363.c @@ -185,10 +185,10 @@ static int max98363_io_init(struct sdw_slave *slave) pm_runtime_get_noresume(dev); ret = regmap_read(max98363->regmap, MAX98363_R21FF_REV_ID, ®); - if (!ret) { + if (!ret) dev_info(dev, "Revision ID: %X\n", reg); - return ret; - } + else + goto out; if (max98363->first_hw_init) { regcache_cache_bypass(max98363->regmap, false); @@ -198,10 +198,11 @@ static int max98363_io_init(struct sdw_slave *slave) max98363->first_hw_init = true; max98363->hw_init = true; +out: pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); - return 0; + return ret; } #define MAX98363_RATES SNDRV_PCM_RATE_8000_192000 diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c index 96d75882b33a..ca6beb2d2649 100644 --- a/sound/soc/codecs/nau8821.c +++ b/sound/soc/codecs/nau8821.c @@ -10,6 +10,7 @@ #include <linux/acpi.h> #include <linux/clk.h> #include <linux/delay.h> +#include <linux/dmi.h> #include <linux/init.h> #include <linux/i2c.h> #include <linux/module.h> @@ -25,6 +26,13 @@ #include <sound/tlv.h> #include "nau8821.h" +#define NAU8821_JD_ACTIVE_HIGH BIT(0) + +static int nau8821_quirk; +static int quirk_override = -1; +module_param_named(quirk, quirk_override, uint, 0444); +MODULE_PARM_DESC(quirk, "Board-specific quirk override"); + #define NAU_FREF_MAX 13500000 #define NAU_FVCO_MAX 100000000 #define NAU_FVCO_MIN 90000000 @@ -1792,6 +1800,33 @@ static int nau8821_setup_irq(struct nau8821 *nau8821) return 0; } +/* Please keep this list alphabetically sorted */ +static const struct dmi_system_id nau8821_quirk_table[] = { + { + /* Positivo CW14Q01P-V2 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Positivo Tecnologia SA"), + DMI_MATCH(DMI_BOARD_NAME, "CW14Q01P-V2"), + }, + .driver_data = (void *)(NAU8821_JD_ACTIVE_HIGH), + }, + {} +}; + +static void nau8821_check_quirks(void) +{ + const struct dmi_system_id *dmi_id; + + if (quirk_override != -1) { + nau8821_quirk = quirk_override; + return; + } + + dmi_id = dmi_first_match(nau8821_quirk_table); + if (dmi_id) + nau8821_quirk = (unsigned long)dmi_id->driver_data; +} + static int nau8821_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; @@ -1812,6 +1847,12 @@ static int nau8821_i2c_probe(struct i2c_client *i2c) nau8821->dev = dev; nau8821->irq = i2c->irq; + + nau8821_check_quirks(); + + if (nau8821_quirk & NAU8821_JD_ACTIVE_HIGH) + nau8821->jkdet_polarity = 0; + nau8821_print_device_properties(nau8821); nau8821_reset_chip(nau8821->regmap); diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index f43520ca3187..e566c8ddd3e9 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -52,6 +52,7 @@ static bool rt1308_volatile_register(struct device *dev, unsigned int reg) case 0x300a: case 0xc000: case 0xc710: + case 0xcf01: case 0xc860 ... 0xc863: case 0xc870 ... 0xc873: return true; @@ -213,7 +214,7 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) { struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev); int ret = 0; - unsigned int tmp; + unsigned int tmp, hibernation_flag; if (rt1308->hw_init) return 0; @@ -242,6 +243,10 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) pm_runtime_get_noresume(&slave->dev); + regmap_read(rt1308->regmap, 0xcf01, &hibernation_flag); + if ((hibernation_flag != 0x00) && rt1308->first_hw_init) + goto _preset_ready_; + /* sw reset */ regmap_write(rt1308->regmap, RT1308_SDW_RESET, 0); @@ -282,6 +287,12 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) regmap_write(rt1308->regmap, 0xc100, 0xd7); regmap_write(rt1308->regmap, 0xc101, 0xd7); + /* apply BQ params */ + rt1308_apply_bq_params(rt1308); + + regmap_write(rt1308->regmap, 0xcf01, 0x01); + +_preset_ready_: if (rt1308->first_hw_init) { regcache_cache_bypass(rt1308->regmap, false); regcache_mark_dirty(rt1308->regmap); diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 0ed4fa261abf..eceed8209787 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -53,7 +53,6 @@ static const struct reg_sequence init_list[] = { {RT5640_PR_BASE + 0x3d, 0x3600}, {RT5640_PR_BASE + 0x12, 0x0aa8}, {RT5640_PR_BASE + 0x14, 0x0aaa}, - {RT5640_PR_BASE + 0x20, 0x6110}, {RT5640_PR_BASE + 0x21, 0xe0e0}, {RT5640_PR_BASE + 0x23, 0x1804}, }; @@ -2567,9 +2566,10 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component, if (jack_data && jack_data->use_platform_clock) rt5640->use_platform_clock = jack_data->use_platform_clock; - ret = request_irq(rt5640->irq, rt5640_irq, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - "rt5640", rt5640); + ret = devm_request_threaded_irq(component->dev, rt5640->irq, + NULL, rt5640_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "rt5640", rt5640); if (ret) { dev_warn(component->dev, "Failed to reguest IRQ %d: %d\n", rt5640->irq, ret); rt5640_disable_jack_detect(component); @@ -2622,8 +2622,9 @@ static void rt5640_enable_hda_jack_detect( rt5640->jack = jack; - ret = request_irq(rt5640->irq, rt5640_irq, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, "rt5640", rt5640); + ret = devm_request_threaded_irq(component->dev, rt5640->irq, + NULL, rt5640_irq, IRQF_TRIGGER_RISING | IRQF_ONESHOT, + "rt5640", rt5640); if (ret) { dev_warn(component->dev, "Failed to reguest IRQ %d: %d\n", rt5640->irq, ret); rt5640->irq = -ENXIO; diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index acc7fb1581b2..a506d940a2ea 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3950,7 +3950,11 @@ static int rt5645_i2c_probe(struct i2c_client *i2c) * read and power On. */ msleep(TIME_TO_POWER_MS); - regmap_read(regmap, RT5645_VENDOR_ID2, &val); + ret = regmap_read(regmap, RT5645_VENDOR_ID2, &val); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to read: 0x%02X\n, ret = %d", RT5645_VENDOR_ID2, ret); + goto err_enable; + } switch (val) { case RT5645_DEVICE_ID: diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 83c367af91da..525713c33d71 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -4472,6 +4472,8 @@ static void rt5665_remove(struct snd_soc_component *component) struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component); regmap_write(rt5665->regmap, RT5665_RESET, 0); + + regulator_bulk_disable(ARRAY_SIZE(rt5665->supplies), rt5665->supplies); } #ifdef CONFIG_PM diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index 67404f45389f..4968a8c0064d 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -750,8 +750,15 @@ static int __maybe_unused rt5682_dev_resume(struct device *dev) if (!rt5682->first_hw_init) return 0; - if (!slave->unattach_request) + if (!slave->unattach_request) { + if (rt5682->disable_irq == true) { + mutex_lock(&rt5682->disable_irq_lock); + sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF); + rt5682->disable_irq = false; + mutex_unlock(&rt5682->disable_irq_lock); + } goto regmap_sync; + } time = wait_for_completion_timeout(&slave->initialization_complete, msecs_to_jiffies(RT5682_PROBE_TIMEOUT)); diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c index 119e1f9605d7..23f23f714b39 100644 --- a/sound/soc/codecs/rt711-sdca-sdw.c +++ b/sound/soc/codecs/rt711-sdca-sdw.c @@ -438,8 +438,16 @@ static int __maybe_unused rt711_sdca_dev_resume(struct device *dev) if (!rt711->first_hw_init) return 0; - if (!slave->unattach_request) + if (!slave->unattach_request) { + if (rt711->disable_irq == true) { + mutex_lock(&rt711->disable_irq_lock); + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); + rt711->disable_irq = false; + mutex_unlock(&rt711->disable_irq_lock); + } goto regmap_sync; + } time = wait_for_completion_timeout(&slave->initialization_complete, msecs_to_jiffies(RT711_PROBE_TIMEOUT)); diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index 87dafcb4545d..33dced388f9e 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -538,8 +538,15 @@ static int __maybe_unused rt711_dev_resume(struct device *dev) if (!rt711->first_hw_init) return 0; - if (!slave->unattach_request) + if (!slave->unattach_request) { + if (rt711->disable_irq == true) { + mutex_lock(&rt711->disable_irq_lock); + sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF); + rt711->disable_irq = false; + mutex_unlock(&rt711->disable_irq_lock); + } goto regmap_sync; + } time = wait_for_completion_timeout(&slave->initialization_complete, msecs_to_jiffies(RT711_PROBE_TIMEOUT)); diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c index ad06267b0ea0..6bc50396a0f6 100644 --- a/sound/soc/codecs/rt712-sdca-sdw.c +++ b/sound/soc/codecs/rt712-sdca-sdw.c @@ -438,8 +438,16 @@ static int __maybe_unused rt712_sdca_dev_resume(struct device *dev) if (!rt712->first_hw_init) return 0; - if (!slave->unattach_request) + if (!slave->unattach_request) { + if (rt712->disable_irq == true) { + mutex_lock(&rt712->disable_irq_lock); + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); + rt712->disable_irq = false; + mutex_unlock(&rt712->disable_irq_lock); + } goto regmap_sync; + } time = wait_for_completion_timeout(&slave->initialization_complete, msecs_to_jiffies(RT712_PROBE_TIMEOUT)); diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c index cc57e4e27805..e9103ffb3f50 100644 --- a/sound/soc/codecs/rt722-sdca-sdw.c +++ b/sound/soc/codecs/rt722-sdca-sdw.c @@ -463,8 +463,16 @@ static int __maybe_unused rt722_sdca_dev_resume(struct device *dev) if (!rt722->first_hw_init) return 0; - if (!slave->unattach_request) + if (!slave->unattach_request) { + if (rt722->disable_irq == true) { + mutex_lock(&rt722->disable_irq_lock); + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_6); + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); + rt722->disable_irq = false; + mutex_unlock(&rt722->disable_irq_lock); + } goto regmap_sync; + } time = wait_for_completion_timeout(&slave->initialization_complete, msecs_to_jiffies(RT722_PROBE_TIMEOUT)); diff --git a/sound/soc/codecs/tas2781-comlib.c b/sound/soc/codecs/tas2781-comlib.c index a88c6c28a394..ffb26e4a7e2f 100644 --- a/sound/soc/codecs/tas2781-comlib.c +++ b/sound/soc/codecs/tas2781-comlib.c @@ -57,16 +57,17 @@ static int tasdevice_change_chn_book(struct tasdevice_priv *tas_priv, if (client->addr != tasdev->dev_addr) { client->addr = tasdev->dev_addr; - if (tasdev->cur_book == book) { - ret = regmap_write(map, - TASDEVICE_PAGE_SELECT, 0); - if (ret < 0) { - dev_err(tas_priv->dev, "%s, E=%d\n", - __func__, ret); - goto out; - } + /* All tas2781s share the same regmap, clear the page + * inside regmap once switching to another tas2781. + * Register 0 at any pages and any books inside tas2781 + * is the same one for page-switching. + */ + ret = regmap_write(map, TASDEVICE_PAGE_SELECT, 0); + if (ret < 0) { + dev_err(tas_priv->dev, "%s, E=%d\n", + __func__, ret); + goto out; } - goto out; } if (tasdev->cur_book != book) { diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index 1911750f7445..5da1934527f3 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -1454,7 +1454,7 @@ struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component, return ERR_PTR(-EINVAL); } - mbhc = devm_kzalloc(dev, sizeof(*mbhc), GFP_KERNEL); + mbhc = kzalloc(sizeof(*mbhc), GFP_KERNEL); if (!mbhc) return ERR_PTR(-ENOMEM); @@ -1474,61 +1474,76 @@ struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component, INIT_WORK(&mbhc->correct_plug_swch, wcd_correct_swch_plug); - ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_sw_intr, NULL, + ret = request_threaded_irq(mbhc->intr_ids->mbhc_sw_intr, NULL, wcd_mbhc_mech_plug_detect_irq, IRQF_ONESHOT | IRQF_TRIGGER_RISING, "mbhc sw intr", mbhc); if (ret) - goto err; + goto err_free_mbhc; - ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_btn_press_intr, NULL, + ret = request_threaded_irq(mbhc->intr_ids->mbhc_btn_press_intr, NULL, wcd_mbhc_btn_press_handler, IRQF_ONESHOT | IRQF_TRIGGER_RISING, "Button Press detect", mbhc); if (ret) - goto err; + goto err_free_sw_intr; - ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_btn_release_intr, NULL, + ret = request_threaded_irq(mbhc->intr_ids->mbhc_btn_release_intr, NULL, wcd_mbhc_btn_release_handler, IRQF_ONESHOT | IRQF_TRIGGER_RISING, "Button Release detect", mbhc); if (ret) - goto err; + goto err_free_btn_press_intr; - ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_hs_ins_intr, NULL, + ret = request_threaded_irq(mbhc->intr_ids->mbhc_hs_ins_intr, NULL, wcd_mbhc_adc_hs_ins_irq, IRQF_ONESHOT | IRQF_TRIGGER_RISING, "Elect Insert", mbhc); if (ret) - goto err; + goto err_free_btn_release_intr; disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr); - ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_hs_rem_intr, NULL, + ret = request_threaded_irq(mbhc->intr_ids->mbhc_hs_rem_intr, NULL, wcd_mbhc_adc_hs_rem_irq, IRQF_ONESHOT | IRQF_TRIGGER_RISING, "Elect Remove", mbhc); if (ret) - goto err; + goto err_free_hs_ins_intr; disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr); - ret = devm_request_threaded_irq(dev, mbhc->intr_ids->hph_left_ocp, NULL, + ret = request_threaded_irq(mbhc->intr_ids->hph_left_ocp, NULL, wcd_mbhc_hphl_ocp_irq, IRQF_ONESHOT | IRQF_TRIGGER_RISING, "HPH_L OCP detect", mbhc); if (ret) - goto err; + goto err_free_hs_rem_intr; - ret = devm_request_threaded_irq(dev, mbhc->intr_ids->hph_right_ocp, NULL, + ret = request_threaded_irq(mbhc->intr_ids->hph_right_ocp, NULL, wcd_mbhc_hphr_ocp_irq, IRQF_ONESHOT | IRQF_TRIGGER_RISING, "HPH_R OCP detect", mbhc); if (ret) - goto err; + goto err_free_hph_left_ocp; return mbhc; -err: + +err_free_hph_left_ocp: + free_irq(mbhc->intr_ids->hph_left_ocp, mbhc); +err_free_hs_rem_intr: + free_irq(mbhc->intr_ids->mbhc_hs_rem_intr, mbhc); +err_free_hs_ins_intr: + free_irq(mbhc->intr_ids->mbhc_hs_ins_intr, mbhc); +err_free_btn_release_intr: + free_irq(mbhc->intr_ids->mbhc_btn_release_intr, mbhc); +err_free_btn_press_intr: + free_irq(mbhc->intr_ids->mbhc_btn_press_intr, mbhc); +err_free_sw_intr: + free_irq(mbhc->intr_ids->mbhc_sw_intr, mbhc); +err_free_mbhc: + kfree(mbhc); + dev_err(dev, "Failed to request mbhc interrupts %d\n", ret); return ERR_PTR(ret); @@ -1537,9 +1552,19 @@ EXPORT_SYMBOL(wcd_mbhc_init); void wcd_mbhc_deinit(struct wcd_mbhc *mbhc) { + free_irq(mbhc->intr_ids->hph_right_ocp, mbhc); + free_irq(mbhc->intr_ids->hph_left_ocp, mbhc); + free_irq(mbhc->intr_ids->mbhc_hs_rem_intr, mbhc); + free_irq(mbhc->intr_ids->mbhc_hs_ins_intr, mbhc); + free_irq(mbhc->intr_ids->mbhc_btn_release_intr, mbhc); + free_irq(mbhc->intr_ids->mbhc_btn_press_intr, mbhc); + free_irq(mbhc->intr_ids->mbhc_sw_intr, mbhc); + mutex_lock(&mbhc->lock); wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch); mutex_unlock(&mbhc->lock); + + kfree(mbhc); } EXPORT_SYMBOL(wcd_mbhc_deinit); diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index c0d1fa36d841..1b6e376f3833 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -2642,7 +2642,7 @@ static int wcd934x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *compon return rc; } -static inline void wcd934x_mbhc_get_result_params(struct wcd934x_codec *wcd934x, +static void wcd934x_mbhc_get_result_params(struct wcd934x_codec *wcd934x, s16 *d1_a, u16 noff, int32_t *zdet) { @@ -2683,7 +2683,7 @@ static inline void wcd934x_mbhc_get_result_params(struct wcd934x_codec *wcd934x, else if (x1 < minCode_param[noff]) *zdet = WCD934X_ZDET_FLOATING_IMPEDANCE; - dev_info(wcd934x->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d(milliOhm)\n", + dev_dbg(wcd934x->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%di (milliohm)\n", __func__, d1, c1, x1, *zdet); ramp_down: i = 0; @@ -2740,8 +2740,8 @@ z_right: *zr = zdet; } -static inline void wcd934x_wcd_mbhc_qfuse_cal(struct snd_soc_component *component, - int32_t *z_val, int flag_l_r) +static void wcd934x_wcd_mbhc_qfuse_cal(struct snd_soc_component *component, + int32_t *z_val, int flag_l_r) { s16 q1; int q1_cal; @@ -3044,6 +3044,17 @@ static int wcd934x_mbhc_init(struct snd_soc_component *component) return 0; } + +static void wcd934x_mbhc_deinit(struct snd_soc_component *component) +{ + struct wcd934x_codec *wcd = snd_soc_component_get_drvdata(component); + + if (!wcd->mbhc) + return; + + wcd_mbhc_deinit(wcd->mbhc); +} + static int wcd934x_comp_probe(struct snd_soc_component *component) { struct wcd934x_codec *wcd = dev_get_drvdata(component->dev); @@ -3077,6 +3088,7 @@ static void wcd934x_comp_remove(struct snd_soc_component *comp) { struct wcd934x_codec *wcd = dev_get_drvdata(comp->dev); + wcd934x_mbhc_deinit(comp); wcd_clsh_ctrl_free(wcd->clsh_ctrl); } diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index e7d6a02cdec0..a3c680661377 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -210,7 +210,7 @@ struct wcd938x_priv { }; static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800); -static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(line_gain, 600, -3000); +static const DECLARE_TLV_DB_SCALE(line_gain, -3000, 150, -3000); static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(analog_gain, 0, 3000); struct wcd938x_mbhc_zdet_param { @@ -2124,10 +2124,11 @@ static int wcd938x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *compon return wcd938x_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2); } -static inline void wcd938x_mbhc_get_result_params(struct wcd938x_priv *wcd938x, +static void wcd938x_mbhc_get_result_params(struct snd_soc_component *component, s16 *d1_a, u16 noff, int32_t *zdet) { + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); int i; int val, val1; s16 c1; @@ -2154,8 +2155,8 @@ static inline void wcd938x_mbhc_get_result_params(struct wcd938x_priv *wcd938x, usleep_range(5000, 5050); if (!c1 || !x1) { - pr_err("%s: Impedance detect ramp error, c1=%d, x1=0x%x\n", - __func__, c1, x1); + dev_err(component->dev, "Impedance detect ramp error, c1=%d, x1=0x%x\n", + c1, x1); goto ramp_down; } d1 = d1_a[c1]; @@ -2165,7 +2166,7 @@ static inline void wcd938x_mbhc_get_result_params(struct wcd938x_priv *wcd938x, else if (x1 < minCode_param[noff]) *zdet = WCD938X_ZDET_FLOATING_IMPEDANCE; - pr_err("%s: d1=%d, c1=%d, x1=0x%x, z_val=%d(milliOhm)\n", + dev_dbg(component->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d (milliohm)\n", __func__, d1, c1, x1, *zdet); ramp_down: i = 0; @@ -2210,7 +2211,7 @@ static void wcd938x_mbhc_zdet_ramp(struct snd_soc_component *component, WCD938X_ANA_MBHC_ZDET, 0x80, 0x80); dev_dbg(component->dev, "%s: ramp for HPH_L, noff = %d\n", __func__, zdet_param->noff); - wcd938x_mbhc_get_result_params(wcd938x, d1_a, zdet_param->noff, &zdet); + wcd938x_mbhc_get_result_params(component, d1_a, zdet_param->noff, &zdet); regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MBHC_ZDET, 0x80, 0x00); @@ -2224,15 +2225,15 @@ z_right: WCD938X_ANA_MBHC_ZDET, 0x40, 0x40); dev_dbg(component->dev, "%s: ramp for HPH_R, noff = %d\n", __func__, zdet_param->noff); - wcd938x_mbhc_get_result_params(wcd938x, d1_a, zdet_param->noff, &zdet); + wcd938x_mbhc_get_result_params(component, d1_a, zdet_param->noff, &zdet); regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MBHC_ZDET, 0x40, 0x00); *zr = zdet; } -static inline void wcd938x_wcd_mbhc_qfuse_cal(struct snd_soc_component *component, - int32_t *z_val, int flag_l_r) +static void wcd938x_wcd_mbhc_qfuse_cal(struct snd_soc_component *component, + int32_t *z_val, int flag_l_r) { s16 q1; int q1_cal; @@ -2625,6 +2626,8 @@ static int wcd938x_mbhc_init(struct snd_soc_component *component) WCD938X_IRQ_HPHR_OCP_INT); wcd938x->wcd_mbhc = wcd_mbhc_init(component, &mbhc_cb, intr_ids, wcd_mbhc_fields, true); + if (IS_ERR(wcd938x->wcd_mbhc)) + return PTR_ERR(wcd938x->wcd_mbhc); snd_soc_add_component_controls(component, impedance_detect_controls, ARRAY_SIZE(impedance_detect_controls)); @@ -2633,6 +2636,14 @@ static int wcd938x_mbhc_init(struct snd_soc_component *component) return 0; } + +static void wcd938x_mbhc_deinit(struct snd_soc_component *component) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + wcd_mbhc_deinit(wcd938x->wcd_mbhc); +} + /* END MBHC */ static const struct snd_kcontrol_new wcd938x_snd_controls[] = { @@ -2652,8 +2663,8 @@ static const struct snd_kcontrol_new wcd938x_snd_controls[] = { wcd938x_get_swr_port, wcd938x_set_swr_port), SOC_SINGLE_EXT("DSD_R Switch", WCD938X_DSD_R, 0, 1, 0, wcd938x_get_swr_port, wcd938x_set_swr_port), - SOC_SINGLE_TLV("HPHL Volume", WCD938X_HPH_L_EN, 0, 0x18, 0, line_gain), - SOC_SINGLE_TLV("HPHR Volume", WCD938X_HPH_R_EN, 0, 0x18, 0, line_gain), + SOC_SINGLE_TLV("HPHL Volume", WCD938X_HPH_L_EN, 0, 0x18, 1, line_gain), + SOC_SINGLE_TLV("HPHR Volume", WCD938X_HPH_R_EN, 0, 0x18, 1, line_gain), WCD938X_EAR_PA_GAIN_TLV("EAR_PA Volume", WCD938X_ANA_EAR_COMPANDER_CTL, 2, 0x10, 0, ear_pa_gain), SOC_SINGLE_EXT("ADC1 Switch", WCD938X_ADC1, 1, 1, 0, @@ -3080,16 +3091,33 @@ static int wcd938x_irq_init(struct wcd938x_priv *wcd, struct device *dev) static int wcd938x_soc_codec_probe(struct snd_soc_component *component) { struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + struct sdw_slave *tx_sdw_dev = wcd938x->tx_sdw_dev; struct device *dev = component->dev; + unsigned long time_left; int ret, i; + time_left = wait_for_completion_timeout(&tx_sdw_dev->initialization_complete, + msecs_to_jiffies(2000)); + if (!time_left) { + dev_err(dev, "soundwire device init timeout\n"); + return -ETIMEDOUT; + } + snd_soc_component_init_regmap(component, wcd938x->regmap); + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return ret; + wcd938x->variant = snd_soc_component_read_field(component, WCD938X_DIGITAL_EFUSE_REG_0, WCD938X_ID_MASK); wcd938x->clsh_info = wcd_clsh_ctrl_alloc(component, WCD938X); + if (IS_ERR(wcd938x->clsh_info)) { + pm_runtime_put(dev); + return PTR_ERR(wcd938x->clsh_info); + } wcd938x_io_init(wcd938x); /* Set all interrupts as edge triggered */ @@ -3098,6 +3126,8 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component) (WCD938X_DIGITAL_INTR_LEVEL_0 + i), 0); } + pm_runtime_put(dev); + wcd938x->hphr_pdm_wd_int = regmap_irq_get_virq(wcd938x->irq_chip, WCD938X_IRQ_HPHR_PDM_WD_INT); wcd938x->hphl_pdm_wd_int = regmap_irq_get_virq(wcd938x->irq_chip, @@ -3109,20 +3139,26 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component) ret = request_threaded_irq(wcd938x->hphr_pdm_wd_int, NULL, wcd938x_wd_handle_irq, IRQF_ONESHOT | IRQF_TRIGGER_RISING, "HPHR PDM WD INT", wcd938x); - if (ret) + if (ret) { dev_err(dev, "Failed to request HPHR WD interrupt (%d)\n", ret); + goto err_free_clsh_ctrl; + } ret = request_threaded_irq(wcd938x->hphl_pdm_wd_int, NULL, wcd938x_wd_handle_irq, IRQF_ONESHOT | IRQF_TRIGGER_RISING, "HPHL PDM WD INT", wcd938x); - if (ret) + if (ret) { dev_err(dev, "Failed to request HPHL WD interrupt (%d)\n", ret); + goto err_free_hphr_pdm_wd_int; + } ret = request_threaded_irq(wcd938x->aux_pdm_wd_int, NULL, wcd938x_wd_handle_irq, IRQF_ONESHOT | IRQF_TRIGGER_RISING, "AUX PDM WD INT", wcd938x); - if (ret) + if (ret) { dev_err(dev, "Failed to request Aux WD interrupt (%d)\n", ret); + goto err_free_hphl_pdm_wd_int; + } /* Disable watchdog interrupt for HPH and AUX */ disable_irq_nosync(wcd938x->hphr_pdm_wd_int); @@ -3137,7 +3173,7 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component) dev_err(component->dev, "%s: Failed to add snd ctrls for variant: %d\n", __func__, wcd938x->variant); - goto err; + goto err_free_aux_pdm_wd_int; } break; case WCD9385: @@ -3147,7 +3183,7 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component) dev_err(component->dev, "%s: Failed to add snd ctrls for variant: %d\n", __func__, wcd938x->variant); - goto err; + goto err_free_aux_pdm_wd_int; } break; default: @@ -3155,12 +3191,38 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component) } ret = wcd938x_mbhc_init(component); - if (ret) + if (ret) { dev_err(component->dev, "mbhc initialization failed\n"); -err: + goto err_free_aux_pdm_wd_int; + } + + return 0; + +err_free_aux_pdm_wd_int: + free_irq(wcd938x->aux_pdm_wd_int, wcd938x); +err_free_hphl_pdm_wd_int: + free_irq(wcd938x->hphl_pdm_wd_int, wcd938x); +err_free_hphr_pdm_wd_int: + free_irq(wcd938x->hphr_pdm_wd_int, wcd938x); +err_free_clsh_ctrl: + wcd_clsh_ctrl_free(wcd938x->clsh_info); + return ret; } +static void wcd938x_soc_codec_remove(struct snd_soc_component *component) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + wcd938x_mbhc_deinit(component); + + free_irq(wcd938x->aux_pdm_wd_int, wcd938x); + free_irq(wcd938x->hphl_pdm_wd_int, wcd938x); + free_irq(wcd938x->hphr_pdm_wd_int, wcd938x); + + wcd_clsh_ctrl_free(wcd938x->clsh_info); +} + static int wcd938x_codec_set_jack(struct snd_soc_component *comp, struct snd_soc_jack *jack, void *data) { @@ -3177,6 +3239,7 @@ static int wcd938x_codec_set_jack(struct snd_soc_component *comp, static const struct snd_soc_component_driver soc_codec_dev_wcd938x = { .name = "wcd938x_codec", .probe = wcd938x_soc_codec_probe, + .remove = wcd938x_soc_codec_remove, .controls = wcd938x_snd_controls, .num_controls = ARRAY_SIZE(wcd938x_snd_controls), .dapm_widgets = wcd938x_dapm_widgets, diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 068e610b1b4c..f2baee7c332e 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -2308,6 +2308,9 @@ static int wm8904_i2c_probe(struct i2c_client *i2c) regmap_update_bits(wm8904->regmap, WM8904_BIAS_CONTROL_0, WM8904_POBCTRL, 0); + /* Fill the cache for the ADC test register */ + regmap_read(wm8904->regmap, WM8904_ADC_TEST_0, &val); + /* Can leave the device powered off until we need it */ regcache_cache_only(wm8904->regmap, true); regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); |