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@gmail.com
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);
break; case UDA1380_DAC_CLK_WSPLL:uda1380_write_reg_cache(codec, UDA1380_CLK, 0);
uda1380_write(codec, UDA1380_CLK, R00_DAC_CLK);
uda1380_write_reg_cache(codec, UDA1380_CLK,
break; }R00_DAC_CLK);
@@ -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