When the codec is powered-up through external AUDPWRON line it starts its power-up sequence. The completion of the sequence is signaled through the audio interrupt, and then codec is operational. CODEC driver starts a wait_for_completion just after AUDPWRON line transitions from low to high. It's signaled as complete when servicing READYINT interrupt. Signed-off-by: Misael Lopez Cruz <x0052729@xxxxxx> --- sound/soc/codecs/twl6030.c | 46 ++++++++++++++++++++++++++++--------------- 1 files changed, 30 insertions(+), 16 deletions(-) diff --git a/sound/soc/codecs/twl6030.c b/sound/soc/codecs/twl6030.c index 5cf2099..f8bd8ee 100644 --- a/sound/soc/codecs/twl6030.c +++ b/sound/soc/codecs/twl6030.c @@ -48,6 +48,7 @@ struct twl6030_data { int codec_powered; unsigned int sysclk; struct work_struct audint_work; + struct completion ready_completion; }; /* @@ -58,7 +59,7 @@ static const u8 twl6030_reg[TWL6030_CACHEREGNUM] = { 0x4B, /* TWL6030_ASICID (ro) 0x01 */ 0x00, /* TWL6030_ASICREV (ro) 0x02 */ 0x00, /* TWL6030_INTID 0x03 */ - 0x41, /* TWL6030_INTMR 0x04 */ + 0x00, /* TWL6030_INTMR 0x04 */ 0x00, /* TWL6030_NCPCTRL 0x05 */ 0x00, /* TWL6030_LDOCTL 0x06 */ 0x00, /* TWL6030_HPPLLCTL 0x07 */ @@ -186,6 +187,23 @@ static inline void twl6030_write_reg_cache(struct snd_soc_codec *codec, } /* + * read from twl6030 hardware register + */ +static int twl6030_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + u8 value; + + if (reg > TWL6030_CACHEREGNUM) + return -EIO; + + twl_i2c_read_u8(TWL6030_MODULE_AUDIO, &value, reg); + twl6030_write_reg_cache(codec, reg, value); + + return value; +} + +/* * write to the twl6030 register space */ static int twl6030_write(struct snd_soc_codec *codec, @@ -372,7 +390,8 @@ void twl6030_naudint_work(struct work_struct *work) dev_alert(codec->dev, "vib drivers over current detection\n"); break; case TWL6030_READYINT: - dev_alert(codec->dev, "codec is ready\n"); + priv->codec_powered = 1; + complete(&priv->ready_completion); break; default: dev_err(codec->dev, "unknown audio interrupt %d\n", intid); @@ -617,25 +636,21 @@ static int twl6030_set_bias_level(struct snd_soc_codec *codec, /* use AUDPWRON line */ gpio_set_value(audpwron_gpio, 1); - /* power-up sequence latency */ - mdelay(16); + /* wait for ready interrupt */ + wait_for_completion(&priv->ready_completion); /* sync registers updated during power-up sequence */ - twl6030_write_reg_cache(codec, TWL6030_REG_NCPCTL, - 0x81); - twl6030_write_reg_cache(codec, TWL6030_REG_LDOCTL, - 0x45); - twl6030_write_reg_cache(codec, TWL6030_REG_LPPLLCTL, - 0x01); + twl6030_read(codec, TWL6030_REG_NCPCTL); + twl6030_read(codec, TWL6030_REG_LDOCTL); + twl6030_read(codec, TWL6030_REG_LPPLLCTL); } else { /* use manual power-up sequence */ twl6030_power_up(codec); + priv->codec_powered = 1; } /* initialize vdd/vss registers with reg_cache */ twl6030_init_vdd_regs(codec); - - priv->codec_powered = 1; break; case SND_SOC_BIAS_OFF: if (!priv->codec_powered) @@ -649,10 +664,8 @@ static int twl6030_set_bias_level(struct snd_soc_codec *codec, udelay(500); /* sync registers updated during power-down sequence */ - twl6030_write_reg_cache(codec, TWL6030_REG_NCPCTL, - 0x00); - twl6030_write_reg_cache(codec, TWL6030_REG_LDOCTL, - 0x00); + twl6030_read(codec, TWL6030_REG_NCPCTL); + twl6030_read(codec, TWL6030_REG_LDOCTL); twl6030_write_reg_cache(codec, TWL6030_REG_LPPLLCTL, 0x00); } else { @@ -1061,6 +1074,7 @@ static int __devinit twl6030_codec_probe(struct platform_device *pdev) /* audio interrupt */ INIT_WORK(&priv->audint_work, twl6030_naudint_work); + init_completion(&priv->ready_completion); ret = request_irq(naudint_irq, twl6030_naudint_handler, -- 1.5.4.3 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html