diff options
Diffstat (limited to 'sound/soc/codecs/arizona.c')
| -rw-r--r-- | sound/soc/codecs/arizona.c | 64 | 
1 files changed, 54 insertions, 10 deletions
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index ded235f3090f..846ca079845f 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -109,7 +109,7 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,  		break;  	} -	return 0; +	return arizona_out_ev(w, kcontrol, event);  }  static irqreturn_t arizona_thermal_warn(int irq, void *data) @@ -159,12 +159,14 @@ static irqreturn_t arizona_thermal_shutdown(int irq, void *data)  static const struct snd_soc_dapm_widget arizona_spkl =  	SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM,  			   ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev, -			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU); +			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | +			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD);  static const struct snd_soc_dapm_widget arizona_spkr =  	SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM,  			   ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev, -			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU); +			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | +			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD);  int arizona_init_spk(struct snd_soc_codec *codec)  { @@ -864,6 +866,7 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,  {  	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);  	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); +	struct arizona *arizona = priv->arizona;  	switch (event) {  	case SND_SOC_DAPM_PRE_PMU: @@ -877,6 +880,18 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,  			priv->out_up_pending++;  			priv->out_up_delay += 17;  			break; +		case ARIZONA_OUT4L_ENA_SHIFT: +		case ARIZONA_OUT4R_ENA_SHIFT: +			priv->out_up_pending++; +			switch (arizona->type) { +			case WM5102: +			case WM8997: +				break; +			default: +				priv->out_up_delay += 10; +				break; +			} +			break;  		default:  			break;  		} @@ -889,8 +904,12 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,  		case ARIZONA_OUT2R_ENA_SHIFT:  		case ARIZONA_OUT3L_ENA_SHIFT:  		case ARIZONA_OUT3R_ENA_SHIFT: +		case ARIZONA_OUT4L_ENA_SHIFT: +		case ARIZONA_OUT4R_ENA_SHIFT:  			priv->out_up_pending--; -			if (!priv->out_up_pending) { +			if (!priv->out_up_pending && priv->out_up_delay) { +				dev_dbg(codec->dev, "Power up delay: %d\n", +					priv->out_up_delay);  				msleep(priv->out_up_delay);  				priv->out_up_delay = 0;  			} @@ -911,6 +930,21 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,  			priv->out_down_pending++;  			priv->out_down_delay++;  			break; +		case ARIZONA_OUT4L_ENA_SHIFT: +		case ARIZONA_OUT4R_ENA_SHIFT: +			priv->out_down_pending++; +			switch (arizona->type) { +			case WM5102: +			case WM8997: +				break; +			case WM8998: +			case WM1814: +				priv->out_down_delay += 5; +				break; +			default: +				priv->out_down_delay++; +				break; +			}  		default:  			break;  		} @@ -923,8 +957,12 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,  		case ARIZONA_OUT2R_ENA_SHIFT:  		case ARIZONA_OUT3L_ENA_SHIFT:  		case ARIZONA_OUT3R_ENA_SHIFT: +		case ARIZONA_OUT4L_ENA_SHIFT: +		case ARIZONA_OUT4R_ENA_SHIFT:  			priv->out_down_pending--; -			if (!priv->out_down_pending) { +			if (!priv->out_down_pending && priv->out_down_delay) { +				dev_dbg(codec->dev, "Power down delay: %d\n", +					priv->out_down_delay);  				msleep(priv->out_down_delay);  				priv->out_down_delay = 0;  			} @@ -2188,13 +2226,13 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base,  				 ARIZONA_FLL1_CTRL_UPD | cfg->n);  } -static int arizona_is_enabled_fll(struct arizona_fll *fll) +static int arizona_is_enabled_fll(struct arizona_fll *fll, int base)  {  	struct arizona *arizona = fll->arizona;  	unsigned int reg;  	int ret; -	ret = regmap_read(arizona->regmap, fll->base + 1, ®); +	ret = regmap_read(arizona->regmap, base + 1, ®);  	if (ret != 0) {  		arizona_fll_err(fll, "Failed to read current state: %d\n",  				ret); @@ -2208,13 +2246,16 @@ static int arizona_enable_fll(struct arizona_fll *fll)  {  	struct arizona *arizona = fll->arizona;  	bool use_sync = false; -	int already_enabled = arizona_is_enabled_fll(fll); +	int already_enabled = arizona_is_enabled_fll(fll, fll->base); +	int sync_enabled = arizona_is_enabled_fll(fll, fll->base + 0x10);  	struct arizona_fll_cfg cfg;  	int i;  	unsigned int val;  	if (already_enabled < 0)  		return already_enabled; +	if (sync_enabled < 0) +		return sync_enabled;  	if (already_enabled) {  		/* Facilitate smooth refclk across the transition */ @@ -2259,6 +2300,9 @@ static int arizona_enable_fll(struct arizona_fll *fll)  		return -EINVAL;  	} +	if (already_enabled && !!sync_enabled != use_sync) +		arizona_fll_warn(fll, "Synchroniser changed on active FLL\n"); +  	/*  	 * Increase the bandwidth if we're not using a low frequency  	 * sync source. @@ -2274,12 +2318,12 @@ static int arizona_enable_fll(struct arizona_fll *fll)  	if (!already_enabled)  		pm_runtime_get_sync(arizona->dev); -	regmap_update_bits_async(arizona->regmap, fll->base + 1, -				 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);  	if (use_sync)  		regmap_update_bits_async(arizona->regmap, fll->base + 0x11,  					 ARIZONA_FLL1_SYNC_ENA,  					 ARIZONA_FLL1_SYNC_ENA); +	regmap_update_bits_async(arizona->regmap, fll->base + 1, +				 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);  	if (already_enabled)  		regmap_update_bits_async(arizona->regmap, fll->base + 1,  | 
