diff options
Diffstat (limited to 'sound/soc/codecs/cs42l51.c')
-rw-r--r-- | sound/soc/codecs/cs42l51.c | 83 |
1 files changed, 53 insertions, 30 deletions
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index 764f2ef8f59d..8083a339dc7b 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -51,11 +51,8 @@ struct cs42l51_private { struct regmap *regmap; }; -#define CS42L51_FORMATS ( \ - SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ - SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) +#define CS42L51_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE) static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -122,6 +119,9 @@ static const char *chan_mix[] = { "R L", }; +static const DECLARE_TLV_DB_SCALE(pga_tlv, -300, 50, 0); +static const DECLARE_TLV_DB_SCALE(adc_att_tlv, -9600, 100, 0); + static SOC_ENUM_SINGLE_EXT_DECL(cs42l51_chan_mix, chan_mix); static const struct snd_kcontrol_new cs42l51_snd_controls[] = { @@ -138,6 +138,12 @@ static const struct snd_kcontrol_new cs42l51_snd_controls[] = { 0, 0x19, 0x7F, adc_pcm_tlv), SOC_DOUBLE_R("ADC Mixer Switch", CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 7, 1, 1), + SOC_DOUBLE_R_SX_TLV("ADC Attenuator Volume", + CS42L51_ADCA_ATT, CS42L51_ADCB_ATT, + 0, 0xA0, 96, adc_att_tlv), + SOC_DOUBLE_R_SX_TLV("PGA Volume", + CS42L51_ALC_PGA_CTL, CS42L51_ALC_PGB_CTL, + 0, 0x1A, 30, pga_tlv), SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0), SOC_SINGLE("Auto-Mute Switch", CS42L51_DAC_CTL, 2, 1, 0), SOC_SINGLE("Soft Ramp Switch", CS42L51_DAC_CTL, 1, 1, 0), @@ -245,8 +251,28 @@ static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = { &cs42l51_adcr_mux_controls), }; +static int mclk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct cs42l51_private *cs42l51 = snd_soc_component_get_drvdata(comp); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + return clk_prepare_enable(cs42l51->mclk_handle); + case SND_SOC_DAPM_POST_PMD: + /* Delay mclk shutdown to fulfill power-down sequence requirements */ + msleep(20); + clk_disable_unprepare(cs42l51->mclk_handle); + break; + } + + return 0; +} + static const struct snd_soc_dapm_widget cs42l51_dapm_mclk_widgets[] = { - SND_SOC_DAPM_CLOCK_SUPPLY("MCLK") + SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0, mclk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), }; static const struct snd_soc_dapm_route cs42l51_routes[] = { @@ -296,10 +322,10 @@ static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai, } switch (format & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: cs42l51->func = MODE_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: cs42l51->func = MODE_SLAVE_AUTO; break; default: @@ -574,7 +600,6 @@ static const struct snd_soc_component_driver soc_component_device_cs42l51 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static bool cs42l51_writeable_reg(struct device *dev, unsigned int reg) @@ -678,7 +703,7 @@ const struct regmap_config cs42l51_regmap = { .volatile_reg = cs42l51_volatile_reg, .writeable_reg = cs42l51_writeable_reg, .max_register = CS42L51_CHARGE_FREQ, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_GPL(cs42l51_regmap); @@ -699,12 +724,9 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap) dev_set_drvdata(dev, cs42l51); cs42l51->regmap = regmap; - cs42l51->mclk_handle = devm_clk_get(dev, "MCLK"); - if (IS_ERR(cs42l51->mclk_handle)) { - if (PTR_ERR(cs42l51->mclk_handle) != -ENOENT) - return PTR_ERR(cs42l51->mclk_handle); - cs42l51->mclk_handle = NULL; - } + cs42l51->mclk_handle = devm_clk_get_optional(dev, "MCLK"); + if (IS_ERR(cs42l51->mclk_handle)) + return PTR_ERR(cs42l51->mclk_handle); for (i = 0; i < ARRAY_SIZE(cs42l51->supplies); i++) cs42l51->supplies[i].supply = cs42l51_supply_names[i]; @@ -725,8 +747,10 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap) cs42l51->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(cs42l51->reset_gpio)) - return PTR_ERR(cs42l51->reset_gpio); + if (IS_ERR(cs42l51->reset_gpio)) { + ret = PTR_ERR(cs42l51->reset_gpio); + goto error; + } if (cs42l51->reset_gpio) { dev_dbg(dev, "Release reset gpio\n"); @@ -758,24 +782,30 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap) return 0; error: + gpiod_set_value_cansleep(cs42l51->reset_gpio, 1); regulator_bulk_disable(ARRAY_SIZE(cs42l51->supplies), cs42l51->supplies); return ret; } EXPORT_SYMBOL_GPL(cs42l51_probe); -int cs42l51_remove(struct device *dev) +void cs42l51_remove(struct device *dev) { struct cs42l51_private *cs42l51 = dev_get_drvdata(dev); + int ret; gpiod_set_value_cansleep(cs42l51->reset_gpio, 1); - return regulator_bulk_disable(ARRAY_SIZE(cs42l51->supplies), - cs42l51->supplies); + ret = regulator_bulk_disable(ARRAY_SIZE(cs42l51->supplies), + cs42l51->supplies); + if (ret) + dev_warn(dev, "Failed to disable all regulators (%pe)\n", + ERR_PTR(ret)); + } EXPORT_SYMBOL_GPL(cs42l51_remove); -int __maybe_unused cs42l51_suspend(struct device *dev) +int cs42l51_suspend(struct device *dev) { struct cs42l51_private *cs42l51 = dev_get_drvdata(dev); @@ -786,7 +816,7 @@ int __maybe_unused cs42l51_suspend(struct device *dev) } EXPORT_SYMBOL_GPL(cs42l51_suspend); -int __maybe_unused cs42l51_resume(struct device *dev) +int cs42l51_resume(struct device *dev) { struct cs42l51_private *cs42l51 = dev_get_drvdata(dev); @@ -796,13 +826,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"); |