diff options
author | Zeng Zhaoming <b32542@freescale.com> | 2011-04-06 02:19:15 +0800 |
---|---|---|
committer | Jason Liu <r64343@freescale.com> | 2012-01-09 20:07:53 +0800 |
commit | 896bfe73122099f2e7b95e15a8c40fa23aca2ed1 (patch) | |
tree | cdeb3159803731a5b8576ed5eceeba1a55e3f8c2 /sound | |
parent | 30ffc95a3e9d95e42d10f1d08213ad7b10462266 (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.c | 56 | ||||
-rw-r--r-- | sound/soc/soc-core.c | 17 |
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; } } |