diff options
Diffstat (limited to 'sound/soc/codecs/arizona.c')
-rw-r--r-- | sound/soc/codecs/arizona.c | 153 |
1 files changed, 113 insertions, 40 deletions
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 846ca079845f..0a734d910850 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -191,6 +191,14 @@ int arizona_init_spk(struct snd_soc_codec *codec) break; } + return 0; +} +EXPORT_SYMBOL_GPL(arizona_init_spk); + +int arizona_init_spk_irqs(struct arizona *arizona) +{ + int ret; + ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN, "Thermal warning", arizona_thermal_warn, arizona); @@ -209,19 +217,16 @@ int arizona_init_spk(struct snd_soc_codec *codec) return 0; } -EXPORT_SYMBOL_GPL(arizona_init_spk); +EXPORT_SYMBOL_GPL(arizona_init_spk_irqs); -int arizona_free_spk(struct snd_soc_codec *codec) +int arizona_free_spk_irqs(struct arizona *arizona) { - struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona *arizona = priv->arizona; - arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN, arizona); arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT, arizona); return 0; } -EXPORT_SYMBOL_GPL(arizona_free_spk); +EXPORT_SYMBOL_GPL(arizona_free_spk_irqs); static const struct snd_soc_dapm_route arizona_mono_routes[] = { { "OUT1R", NULL, "OUT1L" }, @@ -252,6 +257,7 @@ EXPORT_SYMBOL_GPL(arizona_init_mono); int arizona_init_gpio(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); struct arizona *arizona = priv->arizona; int i; @@ -259,21 +265,24 @@ int arizona_init_gpio(struct snd_soc_codec *codec) switch (arizona->type) { case WM5110: case WM8280: - snd_soc_dapm_disable_pin(dapm, "DRC2 Signal Activity"); + snd_soc_component_disable_pin(component, + "DRC2 Signal Activity"); break; default: break; } - snd_soc_dapm_disable_pin(dapm, "DRC1 Signal Activity"); + snd_soc_component_disable_pin(component, "DRC1 Signal Activity"); for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) { case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT: - snd_soc_dapm_enable_pin(dapm, "DRC1 Signal Activity"); + snd_soc_component_enable_pin(component, + "DRC1 Signal Activity"); break; case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT: - snd_soc_dapm_enable_pin(dapm, "DRC2 Signal Activity"); + snd_soc_component_enable_pin(component, + "DRC2 Signal Activity"); break; default: break; @@ -1233,6 +1242,46 @@ static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk, return -EINVAL; } +int arizona_clk_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct arizona *arizona = dev_get_drvdata(codec->dev->parent); + unsigned int val; + int clk_idx; + int ret; + + ret = regmap_read(arizona->regmap, w->reg, &val); + if (ret) { + dev_err(codec->dev, "Failed to check clock source: %d\n", ret); + return ret; + } + + val = (val & ARIZONA_SYSCLK_SRC_MASK) >> ARIZONA_SYSCLK_SRC_SHIFT; + + switch (val) { + case ARIZONA_CLK_SRC_MCLK1: + clk_idx = ARIZONA_MCLK1; + break; + case ARIZONA_CLK_SRC_MCLK2: + clk_idx = ARIZONA_MCLK2; + break; + default: + return 0; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + return clk_prepare_enable(arizona->mclk[clk_idx]); + case SND_SOC_DAPM_POST_PMD: + clk_disable_unprepare(arizona->mclk[clk_idx]); + return 0; + default: + return 0; + } +} +EXPORT_SYMBOL_GPL(arizona_clk_ev); + int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir) { @@ -2242,6 +2291,42 @@ static int arizona_is_enabled_fll(struct arizona_fll *fll, int base) return reg & ARIZONA_FLL1_ENA; } +static int arizona_set_fll_clks(struct arizona_fll *fll, int base, bool ena) +{ + struct arizona *arizona = fll->arizona; + unsigned int val; + struct clk *clk; + int ret; + + ret = regmap_read(arizona->regmap, base + 6, &val); + if (ret != 0) { + arizona_fll_err(fll, "Failed to read current source: %d\n", + ret); + return ret; + } + + val &= ARIZONA_FLL1_CLK_REF_SRC_MASK; + val >>= ARIZONA_FLL1_CLK_REF_SRC_SHIFT; + + switch (val) { + case ARIZONA_FLL_SRC_MCLK1: + clk = arizona->mclk[ARIZONA_MCLK1]; + break; + case ARIZONA_FLL_SRC_MCLK2: + clk = arizona->mclk[ARIZONA_MCLK2]; + break; + default: + return 0; + } + + if (ena) { + return clk_prepare_enable(clk); + } else { + clk_disable_unprepare(clk); + return 0; + } +} + static int arizona_enable_fll(struct arizona_fll *fll) { struct arizona *arizona = fll->arizona; @@ -2264,6 +2349,10 @@ static int arizona_enable_fll(struct arizona_fll *fll) udelay(32); regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9, ARIZONA_FLL1_GAIN_MASK, 0); + + if (arizona_is_enabled_fll(fll, fll->base + 0x10) > 0) + arizona_set_fll_clks(fll, fll->base + 0x10, false); + arizona_set_fll_clks(fll, fll->base, false); } /* @@ -2318,10 +2407,13 @@ static int arizona_enable_fll(struct arizona_fll *fll) if (!already_enabled) pm_runtime_get_sync(arizona->dev); - if (use_sync) + if (use_sync) { + arizona_set_fll_clks(fll, fll->base + 0x10, true); regmap_update_bits_async(arizona->regmap, fll->base + 0x11, ARIZONA_FLL1_SYNC_ENA, ARIZONA_FLL1_SYNC_ENA); + } + arizona_set_fll_clks(fll, fll->base, true); regmap_update_bits_async(arizona->regmap, fll->base + 1, ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); @@ -2354,19 +2446,24 @@ static int arizona_enable_fll(struct arizona_fll *fll) static void arizona_disable_fll(struct arizona_fll *fll) { struct arizona *arizona = fll->arizona; - bool change; + bool ref_change, sync_change; regmap_update_bits_async(arizona->regmap, fll->base + 1, ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN); regmap_update_bits_check(arizona->regmap, fll->base + 1, - ARIZONA_FLL1_ENA, 0, &change); - regmap_update_bits(arizona->regmap, fll->base + 0x11, - ARIZONA_FLL1_SYNC_ENA, 0); + ARIZONA_FLL1_ENA, 0, &ref_change); + regmap_update_bits_check(arizona->regmap, fll->base + 0x11, + ARIZONA_FLL1_SYNC_ENA, 0, &sync_change); regmap_update_bits_async(arizona->regmap, fll->base + 1, ARIZONA_FLL1_FREERUN, 0); - if (change) + if (sync_change) + arizona_set_fll_clks(fll, fll->base + 0x10, false); + + if (ref_change) { + arizona_set_fll_clks(fll, fll->base, false); pm_runtime_put_autosuspend(arizona->dev); + } } int arizona_set_fll_refclk(struct arizona_fll *fll, int source, @@ -2598,30 +2695,6 @@ int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put); -int arizona_register_notifier(struct snd_soc_codec *codec, - struct notifier_block *nb, - int (*notify)(struct notifier_block *nb, - unsigned long action, void *data)) -{ - struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona *arizona = priv->arizona; - - nb->notifier_call = notify; - - return blocking_notifier_chain_register(&arizona->notifier, nb); -} -EXPORT_SYMBOL_GPL(arizona_register_notifier); - -int arizona_unregister_notifier(struct snd_soc_codec *codec, - struct notifier_block *nb) -{ - struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona *arizona = priv->arizona; - - return blocking_notifier_chain_unregister(&arizona->notifier, nb); -} -EXPORT_SYMBOL_GPL(arizona_unregister_notifier); - MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support"); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); MODULE_LICENSE("GPL"); |