static int twl6040_power(struct twl6040_codec *twl6040, int enable) { int audpwron = twl6040->audpwron; int naudint = twl6040->irq; int ret = 0; if (enable) { if (gpio_is_valid(audpwron)) { /* use AUDPWRON line */ gpio_set_value(audpwron, 1); /* wait for power-up completion */ ret = twl6040_power_up_completion(twl6040, naudint); if (ret) { dev_err(&twl6040_codec_dev->dev, "automatic power-down failed\n"); return ret; } } else { /* use manual power-up sequence */ ret = twl6040_power_up(twl6040); if (ret) { dev_err(&twl6040_codec_dev->dev, "manual power-up failed\n"); return ret; } } twl6040->pll = TWL6040_LPPLL_ID; twl6040->sysclk = 19200000; } else { if (gpio_is_valid(audpwron)) { /* use AUDPWRON line */ gpio_set_value(audpwron, 0); /* power-down sequence latency */ udelay(500); } else { /* use manual power-down sequence */ ret = twl6040_power_down(twl6040); if (ret) { dev_err(&twl6040_codec_dev->dev, "manual power-down failed\n"); return ret; } } twl6040->pll = TWL6040_NOPLL_ID; twl6040->sysclk = 0; } twl6040->powered = enable; return ret; }
static int twl6040_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); int audpwron = priv->audpwron; int naudint = priv->naudint; int ret; switch (level) { case SND_SOC_BIAS_ON: break; case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: if (priv->codec_powered) break; if (gpio_is_valid(audpwron)) { /* use AUDPWRON line */ gpio_set_value(audpwron, 1); /* wait for power-up completion */ ret = twl6040_power_up_completion(codec, naudint); if (ret) return ret; /* sync registers updated during power-up sequence */ twl6040_read_reg_volatile(codec, TWL6040_REG_NCPCTL); twl6040_read_reg_volatile(codec, TWL6040_REG_LDOCTL); twl6040_read_reg_volatile(codec, TWL6040_REG_LPPLLCTL); } else { /* use manual power-up sequence */ twl6040_power_up(codec); priv->codec_powered = 1; } /* initialize vdd/vss registers with reg_cache */ twl6040_init_vdd_regs(codec); break; case SND_SOC_BIAS_OFF: if (!priv->codec_powered) break; if (gpio_is_valid(audpwron)) { /* use AUDPWRON line */ gpio_set_value(audpwron, 0); /* power-down sequence latency */ udelay(500); /* sync registers updated during power-down sequence */ twl6040_read_reg_volatile(codec, TWL6040_REG_NCPCTL); twl6040_read_reg_volatile(codec, TWL6040_REG_LDOCTL); twl6040_write_reg_cache(codec, TWL6040_REG_LPPLLCTL, 0x00); } else { /* use manual power-down sequence */ twl6040_power_down(codec); } priv->codec_powered = 0; break; } codec->bias_level = level; return 0; }
static int twl6040_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); int audpwron = priv->audpwron; int naudint = priv->naudint; int ret; switch (level) { case SND_SOC_BIAS_ON: break; case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: if (priv->codec_powered) break; if (gpio_is_valid(audpwron)) { /* use AUDPWRON line */ gpio_set_value(audpwron, 1); #if defined(CONFIG_MACH_LGE_COSMO_REV_C) mdelay(50); #endif /* wait for power-up completion */ ret = twl6040_power_up_completion(codec, naudint); if (ret) return ret; /* sync registers updated during power-up sequence */ twl6040_read_reg_volatile(codec, TWL6040_REG_NCPCTL); twl6040_read_reg_volatile(codec, TWL6040_REG_LDOCTL); twl6040_read_reg_volatile(codec, TWL6040_REG_LPPLLCTL); } else { /* use manual power-up sequence */ twl6040_power_up(codec); priv->codec_powered = 1; } /* initialize vdd/vss registers with reg_cache */ twl6040_init_vdd_regs(codec); break; case SND_SOC_BIAS_OFF: if (!priv->codec_powered) break; if (gpio_is_valid(audpwron)) { // Headset Left Driver make pop-noise when twl6040 enter into sleep mode. u8 val; val = twl6040_read_reg_cache(codec, TWL6040_REG_HSLCTL); if( val & 0x04 ) // temp disableed. It will be recovered when power-on. { twl6040_i2c_write(TWL6040_REG_HSLCTL, (val & (~0x04))); msleep(1); // delay;; } /* use AUDPWRON line */ gpio_set_value(audpwron, 0); /* power-down sequence latency */ mdelay(1); // more more... /* sync registers updated during power-down sequence */ twl6040_read_reg_volatile(codec, TWL6040_REG_NCPCTL); twl6040_read_reg_volatile(codec, TWL6040_REG_LDOCTL); twl6040_write_reg_cache(codec, TWL6040_REG_LPPLLCTL, 0x00); } else { /* use manual power-down sequence */ twl6040_power_down(codec); } priv->codec_powered = 0; break; } codec->dapm->bias_level = level; return 0; }
static int twl6040_power(struct twl6040 *twl6040, int enable) { struct twl4030_codec_data *pdata = dev_get_platdata(twl6040->dev); int audpwron = twl6040->audpwron; int naudint = twl6040->irq; int ret = 0; if (enable) { /* enable 32kHz external clock */ if (pdata->set_ext_clk32k) { ret = pdata->set_ext_clk32k(true); if (ret) { dev_err(twl6040->dev, "failed to enable CLK32K %d\n", ret); return ret; } } /* disable internal 32kHz oscillator */ twl6040_clear_bits(twl6040, TWL6040_REG_ACCCTL, TWL6040_CLK32KSEL); if (gpio_is_valid(audpwron)) { /* wait for power-up completion */ ret = twl6040_power_up_completion(twl6040, naudint); if (ret) { dev_err(twl6040->dev, "automatic power-down failed\n"); return ret; } } else { /* use manual power-up sequence */ ret = twl6040_power_up(twl6040); if (ret) { dev_err(twl6040->dev, "manual power-up failed\n"); return ret; } } /* Errata: PDMCLK can fail to generate at cold temperatures * The workaround consists of resetting HPPLL and LPPLL * after Sleep/Deep-Sleep mode and before application mode. */ twl6040_set_bits(twl6040, TWL6040_REG_HPPLLCTL, TWL6040_HPLLRST); twl6040_clear_bits(twl6040, TWL6040_REG_HPPLLCTL, TWL6040_HPLLRST); twl6040_set_bits(twl6040, TWL6040_REG_LPPLLCTL, TWL6040_LPLLRST); twl6040_clear_bits(twl6040, TWL6040_REG_LPPLLCTL, TWL6040_LPLLRST); twl6040->pll = TWL6040_LPPLL_ID; twl6040->sysclk = 19200000; } else { if (gpio_is_valid(audpwron)) { /* use AUDPWRON line */ gpio_set_value(audpwron, 0); /* power-down sequence latency */ udelay(500); } else { /* use manual power-down sequence */ ret = twl6040_power_down(twl6040); if (ret) { dev_err(twl6040->dev, "manual power-down failed\n"); return ret; } } /* enable internal 32kHz oscillator */ twl6040_set_bits(twl6040, TWL6040_REG_ACCCTL, TWL6040_CLK32KSEL); /* disable 32kHz external clock */ if (pdata->set_ext_clk32k) { ret = pdata->set_ext_clk32k(false); if (ret) dev_err(twl6040->dev, "failed to disable CLK32K %d\n", ret); } twl6040->pll = TWL6040_NOPLL_ID; twl6040->sysclk = 0; } twl6040->powered = enable; return ret; }
int twl6040_power(struct twl6040 *twl6040, int on) { int audpwron = twl6040->audpwron; int naudint = twl6040->irq; int ret = 0; mutex_lock(&twl6040->mutex); if (on) { /* already powered-up */ if (twl6040->power_count++) goto out; if (gpio_is_valid(audpwron)) { /* use AUDPWRON line */ gpio_set_value(audpwron, 1); /* wait for power-up completion */ ret = twl6040_power_up_completion(twl6040, naudint); if (ret) { dev_err(&twl6040_dev->dev, "automatic power-down failed\n"); twl6040->power_count = 0; goto out; } } else { /* use manual power-up sequence */ ret = twl6040_power_up(twl6040); if (ret) { dev_err(&twl6040_dev->dev, "manual power-up failed\n"); twl6040->power_count = 0; goto out; } } /* Default PLL configuration after power up */ twl6040->pll = TWL6040_SYSCLK_SEL_LPPLL; twl6040->sysclk = 19200000; } else { /* already powered-down */ if (!twl6040->power_count) { dev_err(&twl6040_dev->dev, "device is already powered-off\n"); ret = -EPERM; goto out; } if (--twl6040->power_count) goto out; if (gpio_is_valid(audpwron)) { /* use AUDPWRON line */ gpio_set_value(audpwron, 0); /* power-down sequence latency */ usleep_range(500, 700); } else { /* use manual power-down sequence */ twl6040_power_down(twl6040); } twl6040->sysclk = 0; } out: mutex_unlock(&twl6040->mutex); return ret; }