diff options
Diffstat (limited to 'sound/soc/codecs/cs42l43.c')
-rw-r--r-- | sound/soc/codecs/cs42l43.c | 124 |
1 files changed, 70 insertions, 54 deletions
diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c index 860d5cda67bf..ea84ac64c775 100644 --- a/sound/soc/codecs/cs42l43.c +++ b/sound/soc/codecs/cs42l43.c @@ -7,11 +7,12 @@ #include <linux/bitops.h> #include <linux/bits.h> +#include <linux/build_bug.h> #include <linux/clk.h> #include <linux/device.h> #include <linux/err.h> #include <linux/errno.h> -#include <linux/find.h> +#include <linux/bitmap.h> #include <linux/gcd.h> #include <linux/irq.h> #include <linux/irqdomain.h> @@ -252,24 +253,20 @@ CS42L43_IRQ_COMPLETE(load_detect) static irqreturn_t cs42l43_mic_shutter(int irq, void *data) { struct cs42l43_codec *priv = data; - static const char * const controls[] = { - "Decimator 1 Switch", - "Decimator 2 Switch", - "Decimator 3 Switch", - "Decimator 4 Switch", - }; - int i, ret; + struct snd_soc_component *component = priv->component; + int i; dev_dbg(priv->dev, "Microphone shutter changed\n"); - if (!priv->component) + if (!component) return IRQ_NONE; - for (i = 0; i < ARRAY_SIZE(controls); i++) { - ret = snd_soc_component_notify_control(priv->component, - controls[i]); - if (ret) + for (i = 1; i < ARRAY_SIZE(priv->kctl); i++) { + if (!priv->kctl[i]) return IRQ_NONE; + + snd_ctl_notify(component->card->snd_card, + SNDRV_CTL_EVENT_MASK_VALUE, &priv->kctl[i]->id); } return IRQ_HANDLED; @@ -278,18 +275,19 @@ static irqreturn_t cs42l43_mic_shutter(int irq, void *data) static irqreturn_t cs42l43_spk_shutter(int irq, void *data) { struct cs42l43_codec *priv = data; - int ret; + struct snd_soc_component *component = priv->component; dev_dbg(priv->dev, "Speaker shutter changed\n"); - if (!priv->component) + if (!component) return IRQ_NONE; - ret = snd_soc_component_notify_control(priv->component, - "Speaker Digital Switch"); - if (ret) + if (!priv->kctl[0]) return IRQ_NONE; + snd_ctl_notify(component->card->snd_card, + SNDRV_CTL_EVENT_MASK_VALUE, &priv->kctl[0]->id); + return IRQ_HANDLED; } @@ -310,8 +308,9 @@ static int cs42l43_startup(struct snd_pcm_substream *substream, struct snd_soc_d struct snd_soc_component *component = dai->component; struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); struct cs42l43 *cs42l43 = priv->core; - int provider = !!regmap_test_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG2, - CS42L43_ASP_MASTER_MODE_MASK); + int provider = !dai->id || !!regmap_test_bits(cs42l43->regmap, + CS42L43_ASP_CLK_CONFIG2, + CS42L43_ASP_MASTER_MODE_MASK); if (provider) priv->constraint.mask = CS42L43_PROVIDER_RATE_MASK; @@ -589,7 +588,46 @@ static int cs42l43_asp_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mas return 0; } +static int cs42l43_dai_probe(struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + static const char * const controls[] = { + "Speaker Digital Switch", + "Decimator 1 Switch", + "Decimator 2 Switch", + "Decimator 3 Switch", + "Decimator 4 Switch", + }; + int i; + + static_assert(ARRAY_SIZE(controls) == ARRAY_SIZE(priv->kctl)); + + for (i = 0; i < ARRAY_SIZE(controls); i++) { + if (priv->kctl[i]) + continue; + + priv->kctl[i] = snd_soc_component_get_kcontrol(component, controls[i]); + } + + return 0; +} + +static int cs42l43_dai_remove(struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + int i; + + for (i = 0; i < ARRAY_SIZE(priv->kctl); i++) + priv->kctl[i] = NULL; + + return 0; +} + static const struct snd_soc_dai_ops cs42l43_asp_ops = { + .probe = cs42l43_dai_probe, + .remove = cs42l43_dai_remove, .startup = cs42l43_startup, .hw_params = cs42l43_asp_hw_params, .set_fmt = cs42l43_asp_set_fmt, @@ -607,9 +645,11 @@ static int cs42l43_sdw_hw_params(struct snd_pcm_substream *substream, return ret; return cs42l43_set_sample_rate(substream, params, dai); -}; +} static const struct snd_soc_dai_ops cs42l43_sdw_ops = { + .probe = cs42l43_dai_probe, + .remove = cs42l43_dai_remove, .startup = cs42l43_startup, .set_stream = cs42l43_sdw_set_stream, .hw_params = cs42l43_sdw_hw_params, @@ -1106,7 +1146,7 @@ static const struct snd_kcontrol_new cs42l43_controls[] = { SOC_DOUBLE_R_SX_TLV("ADC Volume", CS42L43_ADC_B_CTRL1, CS42L43_ADC_B_CTRL2, CS42L43_ADC_PGA_GAIN_SHIFT, - 0xF, 5, cs42l43_adc_tlv), + 0xF, 4, cs42l43_adc_tlv), SOC_DOUBLE("PDM1 Invert Switch", CS42L43_DMIC_PDM_CTRL, CS42L43_PDM1L_INV_SHIFT, CS42L43_PDM1R_INV_SHIFT, 1, 0), @@ -2362,46 +2402,22 @@ static int cs42l43_codec_runtime_resume(struct device *dev) return 0; } -static int cs42l43_codec_suspend(struct device *dev) -{ - struct cs42l43 *cs42l43 = dev_get_drvdata(dev); - - disable_irq(cs42l43->irq); - - return 0; -} - -static int cs42l43_codec_suspend_noirq(struct device *dev) +static int cs42l43_codec_runtime_force_suspend(struct device *dev) { - struct cs42l43 *cs42l43 = dev_get_drvdata(dev); - - enable_irq(cs42l43->irq); - - return 0; -} - -static int cs42l43_codec_resume(struct device *dev) -{ - struct cs42l43 *cs42l43 = dev_get_drvdata(dev); + struct cs42l43_codec *priv = dev_get_drvdata(dev); - enable_irq(cs42l43->irq); + dev_dbg(priv->dev, "Runtime suspend\n"); - return 0; -} - -static int cs42l43_codec_resume_noirq(struct device *dev) -{ - struct cs42l43 *cs42l43 = dev_get_drvdata(dev); + priv->suspend_jack_debounce = true; - disable_irq(cs42l43->irq); + pm_runtime_force_suspend(dev); return 0; } static const struct dev_pm_ops cs42l43_codec_pm_ops = { - SYSTEM_SLEEP_PM_OPS(cs42l43_codec_suspend, cs42l43_codec_resume) - NOIRQ_SYSTEM_SLEEP_PM_OPS(cs42l43_codec_suspend_noirq, cs42l43_codec_resume_noirq) RUNTIME_PM_OPS(NULL, cs42l43_codec_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(cs42l43_codec_runtime_force_suspend, pm_runtime_force_resume) }; static const struct platform_device_id cs42l43_codec_id_table[] = { @@ -2417,12 +2433,12 @@ static struct platform_driver cs42l43_codec_driver = { }, .probe = cs42l43_codec_probe, - .remove_new = cs42l43_codec_remove, + .remove = cs42l43_codec_remove, .id_table = cs42l43_codec_id_table, }; module_platform_driver(cs42l43_codec_driver); -MODULE_IMPORT_NS(SND_SOC_CS42L43); +MODULE_IMPORT_NS("SND_SOC_CS42L43"); MODULE_DESCRIPTION("CS42L43 CODEC Driver"); MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>"); |