Dne Ne 29. srpna 2010 19:11:10 Vasily Khoruzhick napsal(a): > Disable some codec modules in standby mode, completely disable > codec in off mode to save some power. > Fix suspend/resume: mark mixer regs as dirty on resume to > restore mixer values, otherwise driver produces no sound > (master is muted by default). > > Signed-off-by: Vasily Khoruzhick <anarsoul@xxxxxxxxx> > --- > sound/soc/codecs/uda1380.c | 140 > +++++++++++++++++++++++++++++++------------- 1 files changed, 99 > insertions(+), 41 deletions(-) > > diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c > index 1a51c81..8646cb3 100644 > --- a/sound/soc/codecs/uda1380.c > +++ b/sound/soc/codecs/uda1380.c > @@ -39,6 +39,7 @@ struct uda1380_priv { > u16 reg_cache[UDA1380_CACHEREGNUM]; > unsigned int dac_clk; > struct work_struct work; > + void *control_data; It's already in codec->control_data, isn't it ? > }; > > /* > @@ -129,7 +130,46 @@ static int uda1380_write(struct snd_soc_codec *codec, > unsigned int reg, return -EIO; > } > > -#define uda1380_reset(c) uda1380_write(c, UDA1380_RESET, 0) > +static void uda1380_sync_cache(struct snd_soc_codec *codec) > +{ > + int reg; > + u8 data[3]; > + u16 *cache = codec->reg_cache; > + > + /* Sync reg_cache with the hardware */ > + for (reg = 0; reg < UDA1380_MVOL; reg++) { > + data[0] = reg; > + data[1] = (cache[reg] & 0xff00) >> 8; > + data[2] = cache[reg] & 0x00ff; > + if (codec->hw_write(codec->control_data, data, 3) != 3) > + dev_err(codec->dev, "%s: write to reg 0x%x failed\n", > + __func__, reg); > + } > +} > + > +static int uda1380_reset(struct snd_soc_codec *codec) > +{ > + struct uda1380_platform_data *pdata = codec->dev->platform_data; > + > + if (pdata->gpio_reset != -EINVAL) { > + gpio_set_value(pdata->gpio_reset, 1); > + mdelay(1); > + gpio_set_value(pdata->gpio_reset, 0); > + } else { > + u8 data[3]; > + > + data[0] = UDA1380_RESET; > + data[1] = 0; > + data[2] = 0; > + > + if (codec->hw_write(codec->control_data, data, 3) != 3) { > + dev_err(codec->dev, "%s: failed\n", __func__); > + return -EIO; > + } > + } > + > + return 0; > +} > > static void uda1380_flush_work(struct work_struct *work) > { > @@ -145,7 +185,6 @@ static void uda1380_flush_work(struct work_struct > *work) uda1380_read_reg_cache(uda1380_codec, reg)); > clear_bit(bit, &uda1380_cache_dirty); > } > - Remove > } > > /* declarations of ALSA reg_elem_REAL controls */ > @@ -560,18 +599,40 @@ static int uda1380_set_bias_level(struct > snd_soc_codec *codec, enum snd_soc_bias_level level) > { > int pm = uda1380_read_reg_cache(codec, UDA1380_PM); > + struct uda1380_platform_data *pdata = codec->dev->platform_data; > + > + if (codec->bias_level == level) > + return 0; > > switch (level) { > case SND_SOC_BIAS_ON: > case SND_SOC_BIAS_PREPARE: > + /* ADC, DAC on */ > uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm); > break; > case SND_SOC_BIAS_STANDBY: > - uda1380_write(codec, UDA1380_PM, R02_PON_BIAS); > - break; > - case SND_SOC_BIAS_OFF: > + if (codec->bias_level == SND_SOC_BIAS_OFF) { > + if (pdata->gpio_power != -EINVAL) { > + gpio_set_value(pdata->gpio_power, 1); > + uda1380_reset(codec); > + } > + > + uda1380_sync_cache(codec); > + } > uda1380_write(codec, UDA1380_PM, 0x0); Maybe some comment won't hurt here about what that 0x0 does. > break; > + case SND_SOC_BIAS_OFF: if (pdata->gpio_power == -EINVAL) break; ...code... might help your alignment below. > + if (pdata->gpio_power != -EINVAL) { > + int reg; > + gpio_set_value(pdata->gpio_power, 0); > + > + /* Mark mixer regs cache dirty to sync them with > + * codec regs on power on. > + */ > + for (reg = UDA1380_MVOL; reg < UDA1380_CACHEREGNUM; > + reg++) > + set_bit(reg - 0x10, &uda1380_cache_dirty); > + } > } > codec->bias_level = level; > return 0; > @@ -651,16 +712,6 @@ static int uda1380_suspend(struct snd_soc_codec > *codec, pm_message_t state) > > static int uda1380_resume(struct snd_soc_codec *codec) > { > - int i; > - u8 data[2]; > - u16 *cache = codec->reg_cache; > - > - /* Sync reg_cache with the hardware */ > - for (i = 0; i < ARRAY_SIZE(uda1380_reg); i++) { > - data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); > - data[1] = cache[i] & 0x00ff; > - codec->hw_write(codec->control_data, data, 2); > - } > uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY); > return 0; > } > @@ -671,29 +722,32 @@ static int uda1380_probe(struct snd_soc_codec *codec) > struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec); > int ret; > > + uda1380->codec = codec; > + > codec->hw_write = (hw_write_t)i2c_master_send; > + codec->control_data = uda1380->control_data; > > - if (!pdata || !pdata->gpio_power || !pdata->gpio_reset) > + if (!pdata) > return -EINVAL; > > - ret = gpio_request(pdata->gpio_power, "uda1380 power"); > - if (ret) > - return ret; > - ret = gpio_request(pdata->gpio_reset, "uda1380 reset"); > - if (ret) > - goto err_gpio; > - > - gpio_direction_output(pdata->gpio_power, 1); > - > - /* we may need to have the clock running here - pH5 */ > - gpio_direction_output(pdata->gpio_reset, 1); > - udelay(5); > - gpio_set_value(pdata->gpio_reset, 0); if (gpio_is_valid(...gpio...)) { } > + if (pdata->gpio_reset != -EINVAL) { > + ret = gpio_request(pdata->gpio_reset, "uda1380 reset"); > + if (ret) > + goto err_out; > + gpio_direction_output(pdata->gpio_reset, 0); Handle return value and dont depend on this setting the GPIO value, use gpio_set_value() too please. > + } > > - ret = uda1380_reset(codec); > - if (ret < 0) { > - dev_err(codec->dev, "Failed to issue reset\n"); > - goto err_reset; > + if (pdata->gpio_power != -EINVAL) { > + ret = gpio_request(pdata->gpio_power, "uda1380 power"); > + if (ret) > + goto err_gpio; > + gpio_direction_output(pdata->gpio_power, 0); > + } else { > + ret = uda1380_reset(codec); > + if (ret) { > + dev_err(codec->dev, "Failed to issue reset\n"); > + goto err_reset; > + } > } Ditto. > > INIT_WORK(&uda1380->work, uda1380_flush_work); > @@ -703,10 +757,11 @@ static int uda1380_probe(struct snd_soc_codec *codec) > /* set clock input */ > switch (pdata->dac_clk) { > case UDA1380_DAC_CLK_SYSCLK: > - uda1380_write(codec, UDA1380_CLK, 0); > + uda1380_write_reg_cache(codec, UDA1380_CLK, 0); > break; > case UDA1380_DAC_CLK_WSPLL: > - uda1380_write(codec, UDA1380_CLK, R00_DAC_CLK); > + uda1380_write_reg_cache(codec, UDA1380_CLK, > + R00_DAC_CLK); > break; > } > > @@ -717,10 +772,12 @@ static int uda1380_probe(struct snd_soc_codec *codec) > return 0; > > err_reset: > - gpio_set_value(pdata->gpio_power, 0); > - gpio_free(pdata->gpio_reset); > + if (pdata->gpio_reset != -EINVAL) > + gpio_free(pdata->gpio_reset); Ditto > err_gpio: > - gpio_free(pdata->gpio_power); > + if (pdata->gpio_power != -EINVAL) > + gpio_free(pdata->gpio_power); Ditto > +err_out: > return ret; > } > > @@ -731,7 +788,6 @@ static int uda1380_remove(struct snd_soc_codec *codec) > > uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); > > - gpio_set_value(pdata->gpio_power, 0); > gpio_free(pdata->gpio_reset); > gpio_free(pdata->gpio_power); > > @@ -743,8 +799,8 @@ static struct snd_soc_codec_driver > soc_codec_dev_uda1380 = { .remove = uda1380_remove, > .suspend = uda1380_suspend, > .resume = uda1380_resume, > - .read = uda1380_read_reg_cache, > - .write = uda1380_write, > + .read = uda1380_read_reg_cache, > + .write = uda1380_write, > .set_bias_level = uda1380_set_bias_level, > .reg_cache_size = ARRAY_SIZE(uda1380_reg), > .reg_word_size = sizeof(u16), > @@ -764,11 +820,13 @@ static __devinit int uda1380_i2c_probe(struct > i2c_client *i2c, return -ENOMEM; > > i2c_set_clientdata(i2c, uda1380); > + uda1380->control_data = i2c; So is this needed ? Can't you access codec->control_data ? > > ret = snd_soc_register_codec(&i2c->dev, > &soc_codec_dev_uda1380, uda1380_dai, ARRAY_SIZE(uda1380_dai)); > if (ret < 0) > kfree(uda1380); > + Remove > return ret; > } Cheers _______________________________________________ Alsa-devel mailing list Alsa-devel@xxxxxxxxxxxxxxxx http://mailman.alsa-project.org/mailman/listinfo/alsa-devel