From: Marek Vasut <marek.vasut@gmail.com>
To: Vasily Khoruzhick <anarsoul@gmail.com>
Cc: alsa-devel <alsa-devel@alsa-project.org>,
Mark Brown <broonie@opensource.wolfsonmicro.com>,
Ben Dooks <ben-linux@fluff.org>,
Philipp Zabel <philipp.zabel@gmail.com>,
Liam Girdwood <lrg@slimlogic.co.uk>
Subject: Re: [PATCH RESEND v6 1/3] ASoC: uda1380: make driver more powersave-friendly
Date: Mon, 30 Aug 2010 10:43:22 +0200 [thread overview]
Message-ID: <201008301043.22165.marek.vasut@gmail.com> (raw)
In-Reply-To: <1283156889-5544-2-git-send-email-anarsoul@gmail.com>
Dne Po 30. srpna 2010 10:28:07 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@gmail.com>
Please have my:
Acked-by: Marek Vasut <marek.vasut@gmail.com>
> ---
> sound/soc/codecs/uda1380.c | 145
> ++++++++++++++++++++++++++++++++------------ 1 files changed, 105
> insertions(+), 40 deletions(-)
>
> diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
> index 1a51c81..488f801 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;
> };
>
> /*
> @@ -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 (gpio_is_valid(pdata->gpio_reset)) {
> + 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)
> {
> @@ -560,18 +600,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);
> + int reg;
> + 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 (gpio_is_valid(pdata->gpio_power)) {
> + gpio_set_value(pdata->gpio_power, 1);
> + uda1380_reset(codec);
> + }
> +
> + uda1380_sync_cache(codec);
> + }
> uda1380_write(codec, UDA1380_PM, 0x0);
> break;
> + case SND_SOC_BIAS_OFF:
> + if (!gpio_is_valid(pdata->gpio_power))
> + break;
> +
> + 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 +713,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 +723,36 @@ 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(pdata->gpio_reset)) {
> + ret = gpio_request(pdata->gpio_reset, "uda1380 reset");
> + if (ret)
> + goto err_out;
> + ret = gpio_direction_output(pdata->gpio_reset, 0);
> + if (ret)
> + goto err_gpio_reset_conf;
> + }
>
> - ret = uda1380_reset(codec);
> - if (ret < 0) {
> - dev_err(codec->dev, "Failed to issue reset\n");
> - goto err_reset;
> + if (gpio_is_valid(pdata->gpio_power)) {
> + ret = gpio_request(pdata->gpio_power, "uda1380 power");
> + if (ret)
> + goto err_gpio;
> + ret = gpio_direction_output(pdata->gpio_power, 0);
> + if (ret)
> + goto err_gpio_power_conf;
> + } else {
> + ret = uda1380_reset(codec);
> + if (ret) {
> + dev_err(codec->dev, "Failed to issue reset\n");
> + goto err_reset;
> + }
> }
>
> INIT_WORK(&uda1380->work, uda1380_flush_work);
> @@ -703,10 +762,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 +777,15 @@ 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);
> +err_gpio_power_conf:
> + if (gpio_is_valid(pdata->gpio_power))
> + gpio_free(pdata->gpio_power);
> +
> +err_gpio_reset_conf:
> err_gpio:
> - gpio_free(pdata->gpio_power);
> + if (gpio_is_valid(pdata->gpio_reset))
> + gpio_free(pdata->gpio_reset);
> +err_out:
> return ret;
> }
>
> @@ -731,7 +796,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 +807,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,6 +828,7 @@ static __devinit int uda1380_i2c_probe(struct
> i2c_client *i2c, return -ENOMEM;
>
> i2c_set_clientdata(i2c, uda1380);
> + uda1380->control_data = i2c;
>
> ret = snd_soc_register_codec(&i2c->dev,
> &soc_codec_dev_uda1380, uda1380_dai,
ARRAY_SIZE(uda1380_dai));
next prev parent reply other threads:[~2010-08-30 8:44 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-08-30 8:28 [PATCH RESEND v6 0/3] ASoC: Add iPAQ RX1950 support Vasily Khoruzhick
2010-08-30 8:28 ` [PATCH RESEND v6 1/3] ASoC: uda1380: make driver more powersave-friendly Vasily Khoruzhick
2010-08-30 8:43 ` Marek Vasut [this message]
2010-08-30 9:18 ` Vasily Khoruzhick
2010-08-30 9:31 ` Liam Girdwood
2010-08-30 8:28 ` [PATCH RESEND v6 2/3] ASoC: Add HP iPAQ RX1950 support Vasily Khoruzhick
2010-08-30 8:28 ` [PATCH RESEND v6 3/3] ARM: S3C24XX: I2S multi-component-related fixes Vasily Khoruzhick
2010-08-30 9:24 ` [PATCH RESEND v6 0/3] ASoC: Add iPAQ RX1950 support Liam Girdwood
2010-08-31 12:25 ` Mark Brown
2010-08-31 17:49 ` Vasily Khoruzhick
2010-08-31 17:52 ` Mark Brown
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=201008301043.22165.marek.vasut@gmail.com \
--to=marek.vasut@gmail.com \
--cc=alsa-devel@alsa-project.org \
--cc=anarsoul@gmail.com \
--cc=ben-linux@fluff.org \
--cc=broonie@opensource.wolfsonmicro.com \
--cc=lrg@slimlogic.co.uk \
--cc=philipp.zabel@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.