From 3484457fc5fcdb650e03d375f1f6e66db93d6109 Mon Sep 17 00:00:00 2001 From: "G, Manjunath Kondaiah" Date: Wed, 8 Sep 2010 08:53:43 +0530 Subject: OMAP: McBSP: Fix static function warning This patch fixes sparse warning due non declaration of static function sound/soc/omap/omap-mcbsp.c:783:5: warning: symbol 'omap_mcbsp_st_info_volsw' was not declared. Should it be static? Signed-off-by: G, Manjunath Kondaiah Cc: alsa-devel@alsa-project.org Cc: Jarkko Nikula Cc: Peter Ujfalusi Cc: Liam Girdwood Cc: Mark Brown Cc: Tony Lindgren Cc: Nishanth Menon Acked-by: Peter Ujfalusi Acked-by: Jarkko Nikula Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- sound/soc/omap/omap-mcbsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 7ba5690118f8..99696187b55a 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -759,7 +759,7 @@ static struct snd_soc_dai_driver omap_mcbsp_dai = .ops = &mcbsp_dai_ops, }; -int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol, +static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct soc_mixer_control *mc = -- cgit v1.2.3 From c23fd751dc2953263be5989ca537fdee14dee46e Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 10 Sep 2010 14:23:29 +0300 Subject: ASoC: tlv320aic3x: Optimize PLL programming in aic3x_set_bias_level There is only need to enable/disable once the PLL when the bias is going between on, prepare, standby and off states. Signed-off-by: Jarkko Nikula Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- sound/soc/codecs/tlv320aic3x.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index b3175860bcb4..94dc707d9022 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1069,7 +1069,8 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_ON: break; case SND_SOC_BIAS_PREPARE: - if (aic3x->master) { + if (codec->bias_level == SND_SOC_BIAS_STANDBY && + aic3x->master) { /* enable pll */ reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); aic3x_write(codec, AIC3X_PLL_PROGA_REG, @@ -1077,15 +1078,16 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, } break; case SND_SOC_BIAS_STANDBY: - /* fall through and disable pll */ - case SND_SOC_BIAS_OFF: - if (aic3x->master) { + if (codec->bias_level == SND_SOC_BIAS_PREPARE && + aic3x->master) { /* disable pll */ reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE); } break; + case SND_SOC_BIAS_OFF: + break; } codec->bias_level = level; -- cgit v1.2.3 From 2c4ee9b579d17006ad9a83f13e3ae15c142dc41e Mon Sep 17 00:00:00 2001 From: "Matti J. Aaltonen" Date: Fri, 10 Sep 2010 10:41:30 +0300 Subject: ASoC: WL1273 FM Radio: Eliminate unnecessary error return value. With this change it's not a error to call wl1273_set_audio_route when the codec is active if the new routing value is the same as the current active setting. Signed-off-by: Matti J. Aaltonen Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- sound/soc/codecs/wl1273.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c index 0cd590970883..0c47c788ccdf 100644 --- a/sound/soc/codecs/wl1273.c +++ b/sound/soc/codecs/wl1273.c @@ -193,6 +193,9 @@ static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); + if (wl1273->mode == ucontrol->value.integer.value[0]) + return 0; + /* Do not allow changes while stream is running */ if (codec->active) return -EPERM; -- cgit v1.2.3 From e18eca4303c67ac58c75e72c7318e9709188f40d Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 14 Sep 2010 14:54:47 +0300 Subject: ASoC: tlv320aic3x: Use snd_soc_read and snd_soc_write Start phasing out aic3x_read_reg_cache, aic3x_write_reg_cache, aic3x_read and aic3x_write calls in order to switch to soc-cache helpers. This patch replaces aic3x_read_reg_cache and aic3x_write with snd_soc_read and snd_soc_write. This is basically null-op since .read and .write in soc_codec_dev_aic3x points to aic3x_read_reg_cache and aic3x_write. Signed-off-by: Jarkko Nikula Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- sound/soc/codecs/tlv320aic3x.c | 194 +++++++++++++++++++++-------------------- 1 file changed, 98 insertions(+), 96 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 94dc707d9022..138165c3a180 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -839,8 +839,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, int clk; /* select data word length */ - data = - aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); + data = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: break; @@ -854,7 +853,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, data |= (0x03 << 4); break; } - aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data); + snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, data); /* Fsref can be 44100 or 48000 */ fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000; @@ -869,17 +868,17 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, if (bypass_pll) { pll_q &= 0xf; - aic3x_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT); - aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV); + snd_soc_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT); + snd_soc_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV); /* disable PLL if it is bypassed */ - reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); - aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE); + reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); + snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE); } else { - aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV); + snd_soc_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV); /* enable PLL when it is used */ - reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); - aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE); + reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); + snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE); } /* Route Left DAC to left channel input and @@ -888,7 +887,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000; if (params_rate(params) >= 64000) data |= DUAL_RATE_MODE; - aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data); + snd_soc_write(codec, AIC3X_CODEC_DATAPATH_REG, data); /* codec sample rate select */ data = (fsref * 20) / params_rate(params); @@ -897,7 +896,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, data /= 5; data -= 2; data |= (data << 4); - aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data); + snd_soc_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data); if (bypass_pll) return 0; @@ -966,13 +965,16 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, } found: - data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); - aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT)); - aic3x_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT); - aic3x_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT); - aic3x_write(codec, AIC3X_PLL_PROGC_REG, (pll_d >> 6) << PLLD_MSB_SHIFT); - aic3x_write(codec, AIC3X_PLL_PROGD_REG, - (pll_d & 0x3F) << PLLD_LSB_SHIFT); + data = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); + snd_soc_write(codec, AIC3X_PLL_PROGA_REG, + data | (pll_p << PLLP_SHIFT)); + snd_soc_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, + pll_r << PLLR_SHIFT); + snd_soc_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT); + snd_soc_write(codec, AIC3X_PLL_PROGC_REG, + (pll_d >> 6) << PLLD_MSB_SHIFT); + snd_soc_write(codec, AIC3X_PLL_PROGD_REG, + (pll_d & 0x3F) << PLLD_LSB_SHIFT); return 0; } @@ -980,15 +982,15 @@ found: static int aic3x_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u8 ldac_reg = aic3x_read_reg_cache(codec, LDAC_VOL) & ~MUTE_ON; - u8 rdac_reg = aic3x_read_reg_cache(codec, RDAC_VOL) & ~MUTE_ON; + u8 ldac_reg = snd_soc_read(codec, LDAC_VOL) & ~MUTE_ON; + u8 rdac_reg = snd_soc_read(codec, RDAC_VOL) & ~MUTE_ON; if (mute) { - aic3x_write(codec, LDAC_VOL, ldac_reg | MUTE_ON); - aic3x_write(codec, RDAC_VOL, rdac_reg | MUTE_ON); + snd_soc_write(codec, LDAC_VOL, ldac_reg | MUTE_ON); + snd_soc_write(codec, RDAC_VOL, rdac_reg | MUTE_ON); } else { - aic3x_write(codec, LDAC_VOL, ldac_reg); - aic3x_write(codec, RDAC_VOL, rdac_reg); + snd_soc_write(codec, LDAC_VOL, ldac_reg); + snd_soc_write(codec, RDAC_VOL, rdac_reg); } return 0; @@ -1012,8 +1014,8 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, u8 iface_areg, iface_breg; int delay = 0; - iface_areg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f; - iface_breg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f; + iface_areg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f; + iface_breg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f; /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { @@ -1052,9 +1054,9 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, } /* set iface */ - aic3x_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg); - aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg); - aic3x_write(codec, AIC3X_ASD_INTF_CTRLC, delay); + snd_soc_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg); + snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg); + snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, delay); return 0; } @@ -1072,18 +1074,18 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, if (codec->bias_level == SND_SOC_BIAS_STANDBY && aic3x->master) { /* enable pll */ - reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); - aic3x_write(codec, AIC3X_PLL_PROGA_REG, - reg | PLL_ENABLE); + reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); + snd_soc_write(codec, AIC3X_PLL_PROGA_REG, + reg | PLL_ENABLE); } break; case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_PREPARE && aic3x->master) { /* disable pll */ - reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); - aic3x_write(codec, AIC3X_PLL_PROGA_REG, - reg & ~PLL_ENABLE); + reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); + snd_soc_write(codec, AIC3X_PLL_PROGA_REG, + reg & ~PLL_ENABLE); } break; case SND_SOC_BIAS_OFF: @@ -1098,8 +1100,8 @@ void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state) { u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; u8 bit = gpio ? 3: 0; - u8 val = aic3x_read_reg_cache(codec, reg) & ~(1 << bit); - aic3x_write(codec, reg, val | (!!state << bit)); + u8 val = snd_soc_read(codec, reg) & ~(1 << bit); + snd_soc_write(codec, reg, val | (!!state << bit)); } EXPORT_SYMBOL_GPL(aic3x_set_gpio); @@ -1128,7 +1130,7 @@ void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect, if (detect & AIC3X_HEADSET_DETECT_MASK) val |= AIC3X_HEADSET_DETECT_ENABLED; - aic3x_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val); + snd_soc_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val); } EXPORT_SYMBOL_GPL(aic3x_set_headset_detection); @@ -1211,81 +1213,81 @@ static int aic3x_init(struct snd_soc_codec *codec) struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); int reg; - aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); - aic3x_write(codec, AIC3X_RESET, SOFT_RESET); + snd_soc_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); + snd_soc_write(codec, AIC3X_RESET, SOFT_RESET); /* DAC default volume and mute */ - aic3x_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON); - aic3x_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON); + snd_soc_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON); + snd_soc_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON); /* DAC to HP default volume and route to Output mixer */ - aic3x_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON); - aic3x_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON); - aic3x_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON); - aic3x_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON); + snd_soc_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON); + snd_soc_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON); + snd_soc_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON); + snd_soc_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON); /* DAC to Line Out default volume and route to Output mixer */ - aic3x_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON); - aic3x_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON); + snd_soc_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON); + snd_soc_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON); /* DAC to Mono Line Out default volume and route to Output mixer */ - aic3x_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); - aic3x_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); + snd_soc_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); + snd_soc_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); /* unmute all outputs */ - reg = aic3x_read_reg_cache(codec, LLOPM_CTRL); - aic3x_write(codec, LLOPM_CTRL, reg | UNMUTE); - reg = aic3x_read_reg_cache(codec, RLOPM_CTRL); - aic3x_write(codec, RLOPM_CTRL, reg | UNMUTE); - reg = aic3x_read_reg_cache(codec, MONOLOPM_CTRL); - aic3x_write(codec, MONOLOPM_CTRL, reg | UNMUTE); - reg = aic3x_read_reg_cache(codec, HPLOUT_CTRL); - aic3x_write(codec, HPLOUT_CTRL, reg | UNMUTE); - reg = aic3x_read_reg_cache(codec, HPROUT_CTRL); - aic3x_write(codec, HPROUT_CTRL, reg | UNMUTE); - reg = aic3x_read_reg_cache(codec, HPLCOM_CTRL); - aic3x_write(codec, HPLCOM_CTRL, reg | UNMUTE); - reg = aic3x_read_reg_cache(codec, HPRCOM_CTRL); - aic3x_write(codec, HPRCOM_CTRL, reg | UNMUTE); + reg = snd_soc_read(codec, LLOPM_CTRL); + snd_soc_write(codec, LLOPM_CTRL, reg | UNMUTE); + reg = snd_soc_read(codec, RLOPM_CTRL); + snd_soc_write(codec, RLOPM_CTRL, reg | UNMUTE); + reg = snd_soc_read(codec, MONOLOPM_CTRL); + snd_soc_write(codec, MONOLOPM_CTRL, reg | UNMUTE); + reg = snd_soc_read(codec, HPLOUT_CTRL); + snd_soc_write(codec, HPLOUT_CTRL, reg | UNMUTE); + reg = snd_soc_read(codec, HPROUT_CTRL); + snd_soc_write(codec, HPROUT_CTRL, reg | UNMUTE); + reg = snd_soc_read(codec, HPLCOM_CTRL); + snd_soc_write(codec, HPLCOM_CTRL, reg | UNMUTE); + reg = snd_soc_read(codec, HPRCOM_CTRL); + snd_soc_write(codec, HPRCOM_CTRL, reg | UNMUTE); /* ADC default volume and unmute */ - aic3x_write(codec, LADC_VOL, DEFAULT_GAIN); - aic3x_write(codec, RADC_VOL, DEFAULT_GAIN); + snd_soc_write(codec, LADC_VOL, DEFAULT_GAIN); + snd_soc_write(codec, RADC_VOL, DEFAULT_GAIN); /* By default route Line1 to ADC PGA mixer */ - aic3x_write(codec, LINE1L_2_LADC_CTRL, 0x0); - aic3x_write(codec, LINE1R_2_RADC_CTRL, 0x0); + snd_soc_write(codec, LINE1L_2_LADC_CTRL, 0x0); + snd_soc_write(codec, LINE1R_2_RADC_CTRL, 0x0); /* PGA to HP Bypass default volume, disconnect from Output Mixer */ - aic3x_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL); - aic3x_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL); - aic3x_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL); - aic3x_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL); + snd_soc_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL); + snd_soc_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL); + snd_soc_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL); + snd_soc_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL); /* PGA to Line Out default volume, disconnect from Output Mixer */ - aic3x_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL); - aic3x_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL); + snd_soc_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL); + snd_soc_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL); /* PGA to Mono Line Out default volume, disconnect from Output Mixer */ - aic3x_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL); - aic3x_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL); + snd_soc_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL); + snd_soc_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL); /* Line2 to HP Bypass default volume, disconnect from Output Mixer */ - aic3x_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL); - aic3x_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL); - aic3x_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL); - aic3x_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL); + snd_soc_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL); + snd_soc_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL); + snd_soc_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL); + snd_soc_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL); /* Line2 Line Out default volume, disconnect from Output Mixer */ - aic3x_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL); - aic3x_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL); + snd_soc_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL); + snd_soc_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL); /* Line2 to Mono Out default volume, disconnect from Output Mixer */ - aic3x_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL); - aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); + snd_soc_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL); + snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); if (aic3x->model == AIC3X_MODEL_3007) { /* Class-D speaker driver init; datasheet p. 46 */ - aic3x_write(codec, AIC3X_PAGE_SELECT, 0x0D); - aic3x_write(codec, 0xD, 0x0D); - aic3x_write(codec, 0x8, 0x5C); - aic3x_write(codec, 0x8, 0x5D); - aic3x_write(codec, 0x8, 0x5C); - aic3x_write(codec, AIC3X_PAGE_SELECT, 0x00); - aic3x_write(codec, CLASSD_CTRL, 0); + snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x0D); + snd_soc_write(codec, 0xD, 0x0D); + snd_soc_write(codec, 0x8, 0x5C); + snd_soc_write(codec, 0x8, 0x5D); + snd_soc_write(codec, 0x8, 0x5C); + snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x00); + snd_soc_write(codec, CLASSD_CTRL, 0); } /* off, with power on */ @@ -1305,10 +1307,10 @@ static int aic3x_probe(struct snd_soc_codec *codec) if (aic3x->setup) { /* setup GPIO functions */ - aic3x_write(codec, AIC3X_GPIO1_REG, - (aic3x->setup->gpio_func[0] & 0xf) << 4); - aic3x_write(codec, AIC3X_GPIO2_REG, - (aic3x->setup->gpio_func[1] & 0xf) << 4); + snd_soc_write(codec, AIC3X_GPIO1_REG, + (aic3x->setup->gpio_func[0] & 0xf) << 4); + snd_soc_write(codec, AIC3X_GPIO2_REG, + (aic3x->setup->gpio_func[1] & 0xf) << 4); } snd_soc_add_controls(codec, aic3x_snd_controls, -- cgit v1.2.3 From a84a441ba3cab4a62a8ed40fbfbc112ded50f492 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 14 Sep 2010 14:54:48 +0300 Subject: ASoC: tlv320aic3x: Switch to soc-cache helpers Continue phasing out aic3x_read_reg_cache, aic3x_write_reg_cache, aic3x_read and aic3x_write calls. This patch takes the soc-cache in use and removes aic3x_read_reg_cache and aic3x_write. Signed-off-by: Jarkko Nikula Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- sound/soc/codecs/tlv320aic3x.c | 46 +++++++++--------------------------------- 1 file changed, 9 insertions(+), 37 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 138165c3a180..86e5a5868c3c 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -111,18 +111,6 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = { 0x00, 0x00, 0x02, /* 100 */ }; -/* - * read aic3x register cache - */ -static inline unsigned int aic3x_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u8 *cache = codec->reg_cache; - if (reg >= AIC3X_CACHEREGNUM) - return -1; - return cache[reg]; -} - /* * write aic3x register cache */ @@ -135,28 +123,6 @@ static inline void aic3x_write_reg_cache(struct snd_soc_codec *codec, cache[reg] = value; } -/* - * write to the aic3x register space - */ -static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[2]; - - /* data is - * D15..D8 aic3x register offset - * D7...D0 register data - */ - data[0] = reg & 0xff; - data[1] = value & 0xff; - - aic3x_write_reg_cache(codec, data[0], data[1]); - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; -} - /* * read from the aic3x register space */ @@ -1299,10 +1265,16 @@ static int aic3x_init(struct snd_soc_codec *codec) static int aic3x_probe(struct snd_soc_codec *codec) { struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); + int ret; - codec->hw_write = (hw_write_t) i2c_master_send; codec->control_data = aic3x->control_data; + ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type); + if (ret != 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + return ret; + } + aic3x_init(codec); if (aic3x->setup) { @@ -1330,8 +1302,6 @@ static int aic3x_remove(struct snd_soc_codec *codec) } static struct snd_soc_codec_driver soc_codec_dev_aic3x = { - .read = aic3x_read_reg_cache, - .write = aic3x_write, .set_bias_level = aic3x_set_bias_level, .reg_cache_size = ARRAY_SIZE(aic3x_reg), .reg_word_size = sizeof(u8), @@ -1375,6 +1345,8 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, } aic3x->control_data = i2c; + aic3x->control_type = SND_SOC_I2C; + i2c_set_clientdata(i2c, aic3x); if (pdata) { aic3x->gpio_reset = pdata->gpio_reset; -- cgit v1.2.3 From 9900daa81b9e668c28ecf568c714ee49090aa187 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 14 Sep 2010 16:59:47 +0300 Subject: ASoC: tlv320aic3x: Complete the soc-cache conversion Complete the phasing out of aic3x_read_reg_cache, aic3x_write_reg_cache, aic3x_read and aic3x_write calls. This patch uses in aic3x_read the codec->hw_read that points to a function implemented by soc-cache. Only use for aic3x_read is if wanting to read volatile bits from those registers that has both read-only and read/write bits. All other cases should use snd_soc_read. Signed-off-by: Jarkko Nikula Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- sound/soc/codecs/tlv320aic3x.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 86e5a5868c3c..7b5f159cfaf1 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -112,28 +112,21 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = { }; /* - * write aic3x register cache - */ -static inline void aic3x_write_reg_cache(struct snd_soc_codec *codec, - u8 reg, u8 value) -{ - u8 *cache = codec->reg_cache; - if (reg >= AIC3X_CACHEREGNUM) - return; - cache[reg] = value; -} - -/* - * read from the aic3x register space + * read from the aic3x register space. Only use for this function is if + * wanting to read volatile bits from those registers that has both read-only + * and read/write bits. All other cases should use snd_soc_read. */ static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg, u8 *value) { - *value = reg & 0xff; + u8 *cache = codec->reg_cache; + + if (reg >= AIC3X_CACHEREGNUM) + return -1; - value[0] = i2c_smbus_read_byte_data(codec->control_data, value[0]); + *value = codec->hw_read(codec, reg); + cache[reg] = *value; - aic3x_write_reg_cache(codec, reg, *value); return 0; } -- cgit v1.2.3 From 19f7ac5038dc11e1ee2c54bb411326d23b40ccff Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 17 Sep 2010 14:39:01 +0300 Subject: ASoC: tlv320aic3x: Add virtual output pin Detection Purpose of this virtual Detection pin is to keep codec bias on whenever the GPIO or jack detection features are needed. Jack detection needs a mic bias so machine drivers can construct a following route for instance for keeping the path and codec bias on: "Input Jack" -> "Mic Bias xV" -> "Detection" -> detection block inside codec. For the GPIO the machine driver can force the pin on with snd_soc_dapm_force_enable_pin. Signed-off-by: Jarkko Nikula Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- sound/soc/codecs/tlv320aic3x.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 94dc707d9022..92030f527d39 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -646,6 +646,14 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { SND_SOC_DAPM_INPUT("LINE1R"), SND_SOC_DAPM_INPUT("LINE2L"), SND_SOC_DAPM_INPUT("LINE2R"), + + /* + * Virtual output pin to detection block inside codec. This can be + * used to keep codec bias on if gpio or detection features are needed. + * Force pin on or construct a path with an input jack and mic bias + * widgets. + */ + SND_SOC_DAPM_OUTPUT("Detection"), }; static const struct snd_soc_dapm_widget aic3007_dapm_widgets[] = { -- cgit v1.2.3 From 2f24111a08d60e6db92ed2867a339ddde2195b88 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 20 Sep 2010 10:39:11 +0300 Subject: ASoC: tlv320aic3x: Move regulator management from i2c to soc domain It will be easier to keep regulator enable/disable calls in sync when dynamic regulator management is added if regulator management is moved from aic3x_i2c_probe/_remove to aic3x_probe/_remove. Signed-off-by: Jarkko Nikula Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- sound/soc/codecs/tlv320aic3x.c | 100 ++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 50 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 6190351965a4..c60ead948ea6 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1266,7 +1266,7 @@ static int aic3x_init(struct snd_soc_codec *codec) static int aic3x_probe(struct snd_soc_codec *codec) { struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); - int ret; + int ret, i; codec->control_data = aic3x->control_data; @@ -1276,6 +1276,35 @@ static int aic3x_probe(struct snd_soc_codec *codec) return ret; } + if (aic3x->gpio_reset >= 0) { + ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset"); + if (ret != 0) + goto err_gpio; + gpio_direction_output(aic3x->gpio_reset, 0); + } + + for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) + aic3x->supplies[i].supply = aic3x_supply_names[i]; + + ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies), + aic3x->supplies); + if (ret != 0) { + dev_err(codec->dev, "Failed to request supplies: %d\n", ret); + goto err_get; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies), + aic3x->supplies); + if (ret != 0) { + dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); + goto err_enable; + } + + if (aic3x->gpio_reset >= 0) { + udelay(1); + gpio_set_value(aic3x->gpio_reset, 1); + } + aic3x_init(codec); if (aic3x->setup) { @@ -1294,11 +1323,29 @@ static int aic3x_probe(struct snd_soc_codec *codec) aic3x_add_widgets(codec); return 0; + +err_enable: + regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); +err_get: + if (aic3x->gpio_reset >= 0) + gpio_free(aic3x->gpio_reset); +err_gpio: + kfree(aic3x); + return ret; } static int aic3x_remove(struct snd_soc_codec *codec) { + struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); + aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); + if (aic3x->gpio_reset >= 0) { + gpio_set_value(aic3x->gpio_reset, 0); + gpio_free(aic3x->gpio_reset); + } + regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); + regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); + return 0; } @@ -1336,7 +1383,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, { struct aic3x_pdata *pdata = i2c->dev.platform_data; struct aic3x_priv *aic3x; - int ret, i; + int ret; const struct i2c_device_id *tbl; aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); @@ -1356,68 +1403,21 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, aic3x->gpio_reset = -1; } - if (aic3x->gpio_reset >= 0) { - ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset"); - if (ret != 0) - goto err_gpio; - gpio_direction_output(aic3x->gpio_reset, 0); - } - for (tbl = aic3x_i2c_id; tbl->name[0]; tbl++) { if (!strcmp(tbl->name, id->name)) break; } aic3x->model = tbl - aic3x_i2c_id; - for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) - aic3x->supplies[i].supply = aic3x_supply_names[i]; - - ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(aic3x->supplies), - aic3x->supplies); - if (ret != 0) { - dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); - goto err_get; - } - - ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies), - aic3x->supplies); - if (ret != 0) { - dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); - goto err_enable; - } - - if (aic3x->gpio_reset >= 0) { - udelay(1); - gpio_set_value(aic3x->gpio_reset, 1); - } - ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_aic3x, &aic3x_dai, 1); if (ret < 0) - goto err_enable; - return ret; - -err_enable: - regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); -err_get: - if (aic3x->gpio_reset >= 0) - gpio_free(aic3x->gpio_reset); -err_gpio: - kfree(aic3x); + kfree(aic3x); return ret; } static int aic3x_i2c_remove(struct i2c_client *client) { - struct aic3x_priv *aic3x = i2c_get_clientdata(client); - - if (aic3x->gpio_reset >= 0) { - gpio_set_value(aic3x->gpio_reset, 0); - gpio_free(aic3x->gpio_reset); - } - regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); - regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); - snd_soc_unregister_codec(&client->dev); kfree(i2c_get_clientdata(client)); return 0; -- cgit v1.2.3 From 6c1a7d40c2237ff7690ca682336e22777c847ffe Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 20 Sep 2010 10:39:12 +0300 Subject: ASoC: tlv320aic3x: Add runtime regulator control to aic3x_set_bias_level Now all the regulators are disabled when entering into SND_SOC_BIAS_OFF and enabled when coming back to SND_SOC_BIAS_STANDBY state. Currently this runtime control happens only with suspend/resume as this patch does not change the default idle behavior. This patch manages all the regulators and reset since it seems that register sync is needed even if only analog supplies AVDD and DRVDD are disabled. This was noted when the system was running with idle behavior changed and IOVDD and DVDD were on. It is not known are all the registers needed to sync or only some subset of them. Therefore patch plays safe and does always full shutdown/power-up. Signed-off-by: Jarkko Nikula Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- sound/soc/codecs/tlv320aic3x.c | 83 +++++++++++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index c60ead948ea6..5f8a7c4045c2 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -70,6 +70,7 @@ struct aic3x_priv { unsigned int sysclk; int master; int gpio_reset; + int power; #define AIC3X_MODEL_3X 0 #define AIC3X_MODEL_33 1 #define AIC3X_MODEL_3007 2 @@ -1028,6 +1029,64 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, return 0; } +static int aic3x_init_3007(struct snd_soc_codec *codec) +{ + u8 tmp1, tmp2, *cache = codec->reg_cache; + + /* + * There is no need to cache writes to undocumented page 0xD but + * respective page 0 register cache entries must be preserved + */ + tmp1 = cache[0xD]; + tmp2 = cache[0x8]; + /* Class-D speaker driver init; datasheet p. 46 */ + snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x0D); + snd_soc_write(codec, 0xD, 0x0D); + snd_soc_write(codec, 0x8, 0x5C); + snd_soc_write(codec, 0x8, 0x5D); + snd_soc_write(codec, 0x8, 0x5C); + snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x00); + cache[0xD] = tmp1; + cache[0x8] = tmp2; + + return 0; +} + +static int aic3x_set_power(struct snd_soc_codec *codec, int power) +{ + struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); + int i, ret; + u8 *cache = codec->reg_cache; + + if (power) { + ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies), + aic3x->supplies); + if (ret) + goto out; + aic3x->power = 1; + if (aic3x->gpio_reset >= 0) { + udelay(1); + gpio_set_value(aic3x->gpio_reset, 1); + } + + /* Sync reg_cache with the hardware */ + codec->cache_only = 0; + for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) + snd_soc_write(codec, i, cache[i]); + if (aic3x->model == AIC3X_MODEL_3007) + aic3x_init_3007(codec); + codec->cache_sync = 0; + } else { + aic3x->power = 0; + if (aic3x->gpio_reset >= 0) + gpio_set_value(aic3x->gpio_reset, 0); + ret = regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), + aic3x->supplies); + } +out: + return ret; +} + static int aic3x_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { @@ -1047,6 +1106,8 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, } break; case SND_SOC_BIAS_STANDBY: + if (!aic3x->power) + aic3x_set_power(codec, 1); if (codec->bias_level == SND_SOC_BIAS_PREPARE && aic3x->master) { /* disable pll */ @@ -1056,6 +1117,8 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, } break; case SND_SOC_BIAS_OFF: + if (aic3x->power) + aic3x_set_power(codec, 0); break; } codec->bias_level = level; @@ -1155,17 +1218,6 @@ static int aic3x_suspend(struct snd_soc_codec *codec, pm_message_t state) static int aic3x_resume(struct snd_soc_codec *codec) { - int i; - u8 data[2]; - u8 *cache = codec->reg_cache; - - /* Sync reg_cache with the hardware */ - for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) { - data[0] = i; - data[1] = cache[i]; - codec->hw_write(codec->control_data, data, 2); - } - aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; @@ -1247,13 +1299,7 @@ static int aic3x_init(struct snd_soc_codec *codec) snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); if (aic3x->model == AIC3X_MODEL_3007) { - /* Class-D speaker driver init; datasheet p. 46 */ - snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x0D); - snd_soc_write(codec, 0xD, 0x0D); - snd_soc_write(codec, 0x8, 0x5C); - snd_soc_write(codec, 0x8, 0x5D); - snd_soc_write(codec, 0x8, 0x5C); - snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x00); + aic3x_init_3007(codec); snd_soc_write(codec, CLASSD_CTRL, 0); } @@ -1299,6 +1345,7 @@ static int aic3x_probe(struct snd_soc_codec *codec) dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); goto err_enable; } + aic3x->power = 1; if (aic3x->gpio_reset >= 0) { udelay(1); -- cgit v1.2.3 From 5a895f8a09218716654fb89e0f876e4e3ca606a8 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 20 Sep 2010 10:39:13 +0300 Subject: ASoC: tlv320aic3x: Use regulator notifiers for optimizing the cache sync There is no need to reset the codec and perform cache sync if none of the supply regulators were not disabled. Patch registers a notifier callback for each supply and callback then sets a flag to indicate when cache sync is required. HW writes are also needless when codec bias is off so cache_only flag is set independently of actual supply regulators state. Signed-off-by: Jarkko Nikula Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- sound/soc/codecs/tlv320aic3x.c | 63 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 5f8a7c4045c2..5356946fb6b2 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -61,9 +61,18 @@ static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = { "DRVDD", /* ADC Analog and Output Driver Voltage */ }; +struct aic3x_priv; + +struct aic3x_disable_nb { + struct notifier_block nb; + struct aic3x_priv *aic3x; +}; + /* codec private data */ struct aic3x_priv { + struct snd_soc_codec *codec; struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES]; + struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES]; enum snd_soc_control_type control_type; struct aic3x_setup_data *setup; void *control_data; @@ -122,6 +131,8 @@ static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg, { u8 *cache = codec->reg_cache; + if (codec->cache_only) + return -EINVAL; if (reg >= AIC3X_CACHEREGNUM) return -1; @@ -1052,6 +1063,26 @@ static int aic3x_init_3007(struct snd_soc_codec *codec) return 0; } +static int aic3x_regulator_event(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct aic3x_disable_nb *disable_nb = + container_of(nb, struct aic3x_disable_nb, nb); + struct aic3x_priv *aic3x = disable_nb->aic3x; + + if (event & REGULATOR_EVENT_DISABLE) { + /* + * Put codec to reset and require cache sync as at least one + * of the supplies was disabled + */ + if (aic3x->gpio_reset >= 0) + gpio_set_value(aic3x->gpio_reset, 0); + aic3x->codec->cache_sync = 1; + } + + return 0; +} + static int aic3x_set_power(struct snd_soc_codec *codec, int power) { struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); @@ -1064,6 +1095,13 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power) if (ret) goto out; aic3x->power = 1; + /* + * Reset release and cache sync is necessary only if some + * supply was off or if there were cached writes + */ + if (!codec->cache_sync) + goto out; + if (aic3x->gpio_reset >= 0) { udelay(1); gpio_set_value(aic3x->gpio_reset, 1); @@ -1078,8 +1116,8 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power) codec->cache_sync = 0; } else { aic3x->power = 0; - if (aic3x->gpio_reset >= 0) - gpio_set_value(aic3x->gpio_reset, 0); + /* HW writes are needless when bias is off */ + codec->cache_only = 1; ret = regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); } @@ -1315,6 +1353,7 @@ static int aic3x_probe(struct snd_soc_codec *codec) int ret, i; codec->control_data = aic3x->control_data; + aic3x->codec = codec; ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type); if (ret != 0) { @@ -1338,6 +1377,18 @@ static int aic3x_probe(struct snd_soc_codec *codec) dev_err(codec->dev, "Failed to request supplies: %d\n", ret); goto err_get; } + for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) { + aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event; + aic3x->disable_nb[i].aic3x = aic3x; + ret = regulator_register_notifier(aic3x->supplies[i].consumer, + &aic3x->disable_nb[i].nb); + if (ret) { + dev_err(codec->dev, + "Failed to request regulator notifier: %d\n", + ret); + goto err_notif; + } + } ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); @@ -1372,6 +1423,10 @@ static int aic3x_probe(struct snd_soc_codec *codec) return 0; err_enable: +err_notif: + while (i--) + regulator_unregister_notifier(aic3x->supplies[i].consumer, + &aic3x->disable_nb[i].nb); regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); err_get: if (aic3x->gpio_reset >= 0) @@ -1384,6 +1439,7 @@ err_gpio: static int aic3x_remove(struct snd_soc_codec *codec) { struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); + int i; aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); if (aic3x->gpio_reset >= 0) { @@ -1391,6 +1447,9 @@ static int aic3x_remove(struct snd_soc_codec *codec) gpio_free(aic3x->gpio_reset); } regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); + for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) + regulator_unregister_notifier(aic3x->supplies[i].consumer, + &aic3x->disable_nb[i].nb); regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); return 0; -- cgit v1.2.3 From 7d1be0a6789f7d04e5104b1d2873268369eafcc2 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 20 Sep 2010 10:39:14 +0300 Subject: ASoC: tlv320aic3x: Let the codec hit SND_SOC_BIAS_OFF when idle Now codec hits the SND_SOC_BIAS_OFF also when it is idle. This is also the default state after probing and codec is left unconfigured and unpowered by default. Initialization will happen when the bias state changes and aic3x_set_power does power-up and cache sync. Signed-off-by: Jarkko Nikula Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- sound/soc/codecs/tlv320aic3x.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 5356946fb6b2..fc687790188b 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1341,9 +1341,6 @@ static int aic3x_init(struct snd_soc_codec *codec) snd_soc_write(codec, CLASSD_CTRL, 0); } - /* off, with power on */ - aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; } @@ -1354,6 +1351,7 @@ static int aic3x_probe(struct snd_soc_codec *codec) codec->control_data = aic3x->control_data; aic3x->codec = codec; + codec->idle_bias_off = 1; ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type); if (ret != 0) { @@ -1390,19 +1388,7 @@ static int aic3x_probe(struct snd_soc_codec *codec) } } - ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies), - aic3x->supplies); - if (ret != 0) { - dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); - goto err_enable; - } - aic3x->power = 1; - - if (aic3x->gpio_reset >= 0) { - udelay(1); - gpio_set_value(aic3x->gpio_reset, 1); - } - + codec->cache_only = 1; aic3x_init(codec); if (aic3x->setup) { @@ -1422,7 +1408,6 @@ static int aic3x_probe(struct snd_soc_codec *codec) return 0; -err_enable: err_notif: while (i--) regulator_unregister_notifier(aic3x->supplies[i].consumer, @@ -1446,7 +1431,6 @@ static int aic3x_remove(struct snd_soc_codec *codec) gpio_set_value(aic3x->gpio_reset, 0); gpio_free(aic3x->gpio_reset); } - regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) regulator_unregister_notifier(aic3x->supplies[i].consumer, &aic3x->disable_nb[i].nb); -- cgit v1.2.3