summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorZeng Zhaoming <b32542@freescale.com>2011-04-06 02:19:15 +0800
committerJason Liu <r64343@freescale.com>2012-01-09 20:07:53 +0800
commit896bfe73122099f2e7b95e15a8c40fa23aca2ed1 (patch)
treecdeb3159803731a5b8576ed5eceeba1a55e3f8c2 /sound
parent30ffc95a3e9d95e42d10f1d08213ad7b10462266 (diff)
ENGR00141647 AUDIO,SGTL5000: Fix codec error after reset
sgtl5000 codec not work after board reset, this is caused by sgtl5000 using register address step is 2, and snd-soc-core can't handle this as we expect, so we have to fill the register cache by reading register out when initialization instead of providing a default value array. Signed-off-by: Zeng Zhaoming <b32542@freescale.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/sgtl5000.c56
-rw-r--r--sound/soc/soc-core.c17
2 files changed, 42 insertions, 31 deletions
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 556fd939a05b..c324d92739f3 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -971,6 +971,11 @@ static int ldo_regulator_is_enabled(struct regulator_dev *dev)
return ldo->enabled;
}
+/*
+ * enable internal VDDD power supply. Since register
+ * cache not fill yet, we have to use hw_read and write
+ * instead of snd_soc_read and snd_soc_write.
+ */
static int ldo_regulator_enable(struct regulator_dev *dev)
{
struct ldo_regulator *ldo = rdev_get_drvdata(dev);
@@ -980,20 +985,6 @@ static int ldo_regulator_enable(struct regulator_dev *dev)
if (ldo_regulator_is_enabled(dev))
return 0;
- snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
- SGTL5000_LINREG_SIMPLE_POWERUP|
- SGTL5000_STARTUP_POWERUP|
- SGTL5000_REFTOP_POWERUP,
- 0);
- udelay(10);
- snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
- SGTL5000_LINREG_SIMPLE_POWERUP|
- SGTL5000_STARTUP_POWERUP|
- SGTL5000_REFTOP_POWERUP,
- SGTL5000_LINREG_SIMPLE_POWERUP|
- SGTL5000_STARTUP_POWERUP|
- SGTL5000_REFTOP_POWERUP);
- udelay(10);
/* set regulator value firstly */
reg = (1600 - ldo->voltage / 1000) / 50;
reg = clamp(reg, 0x0, 0xf);
@@ -1002,17 +993,17 @@ static int ldo_regulator_enable(struct regulator_dev *dev)
ldo->voltage = (1600 - reg * 50) * 1000;
/* set voltage to register */
- snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL,
- (0x1 << 4) - 1, reg);
+ codec->write(codec, SGTL5000_CHIP_LINREG_CTRL, reg);
- snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
- SGTL5000_LINEREG_D_POWERUP,
- SGTL5000_LINEREG_D_POWERUP);
+ reg = codec->hw_read(codec, SGTL5000_CHIP_ANA_POWER);
+ reg |= SGTL5000_LINEREG_D_POWERUP;
+ codec->write(codec, SGTL5000_CHIP_ANA_POWER, reg);
+ reg &= ~SGTL5000_LINREG_SIMPLE_POWERUP;
/* when internal ldo enabled, simple digital power can be disabled */
- snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
- SGTL5000_LINREG_SIMPLE_POWERUP,
- 0);
+ codec->write(codec, SGTL5000_CHIP_ANA_POWER, reg);
+
+ udelay(10);
ldo->enabled = 1;
return 0;
@@ -1532,6 +1523,22 @@ err_regulator_free:
}
+static int sgtl5000_fill_reg_cache(struct snd_soc_codec *codec)
+{
+ int reg;
+ int step = codec->driver->reg_cache_step;
+ u16 *cache = codec->reg_cache;
+
+ for (reg = SGTL5000_DAP_REG_OFFSET;
+ reg <= SGTL5000_MAX_REG_OFFSET; reg += step)
+ cache[reg] = codec->hw_read(codec, reg);
+
+ for (reg = 0; reg <= SGTL5000_CHIP_SHORT_CTRL; reg += step)
+ cache[reg] = codec->hw_read(codec, reg);
+
+ return 0;
+}
+
static int sgtl5000_probe(struct snd_soc_codec *codec)
{
int ret;
@@ -1548,6 +1555,8 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
if (ret)
return ret;
+ sgtl5000_fill_reg_cache(codec);
+
/* power up sgtl5000 */
ret = sgtl5000_set_power_regs(codec);
if (ret)
@@ -1640,10 +1649,9 @@ static struct snd_soc_codec_driver sgtl5000_driver = {
.suspend = sgtl5000_suspend,
.resume = sgtl5000_resume,
.set_bias_level = sgtl5000_set_bias_level,
- .reg_cache_size = ARRAY_SIZE(sgtl5000_regs),
+ .reg_cache_size = SGTL5000_MAX_REG_OFFSET,
.reg_word_size = sizeof(u16),
.reg_cache_step = 2,
- .reg_cache_default = sgtl5000_regs,
.volatile_register = sgtl5000_volatile_register,
};
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 493ae7c4c041..a04e003da973 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3762,13 +3762,16 @@ int snd_soc_register_codec(struct device *dev,
* kernel might have freed the array by the time we initialize
* the cache.
*/
- if (codec_drv->reg_cache_default) {
- codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default,
- reg_size, GFP_KERNEL);
- if (!codec->reg_def_copy) {
- ret = -ENOMEM;
- goto fail;
- }
+ if (codec_drv->reg_cache_default)
+ codec->reg_def_copy =
+ kmemdup(codec_drv->reg_cache_default,
+ reg_size, GFP_KERNEL);
+ else
+ codec->reg_def_copy = kzalloc(reg_size, GFP_KERNEL);
+
+ if (!codec->reg_def_copy) {
+ ret = -ENOMEM;
+ goto fail;
}
}