/* * write to the twl6040 register space */ static int twl6040_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { u8 *cache = codec->reg_cache; struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); if (reg >= TWL6040_CACHEREGNUM) return -EIO; // If no active dl, DAC should not be set!! if( reg == TWL6040_REG_HSLCTL || reg == TWL6040_REG_HSRCTL ){ if( priv->dl_active == 0 && (value & 0x1)){ twl6040_write_reg_cache(codec, reg, (value & ~0x1)); return 0; } } if( reg == TWL6040_REG_HFLCTL || reg == TWL6040_REG_HFRCTL ){ if( priv->dl_active == 0 && (value & 0x1)){ twl6040_write_reg_cache(codec, reg, (value & ~0x1)); return 0; } } if( reg == TWL6040_REG_EARCTL ){ if( priv->dl_active == 0 && (value & 0x1)){ twl6040_write_reg_cache(codec, reg, (value & ~0x01)); return 0; } } twl6040_write_reg_cache(codec, reg, value); return twl6040_i2c_write(reg, value); }
/* * write to the twl6040 register space */ static int twl6040_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { if (reg >= TWL6040_CACHEREGNUM) return -EIO; twl6040_write_reg_cache(codec, reg, value); return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg); }
/* * write to the twl6040 register space */ static int twl6040_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { struct twl6040_codec *twl6040 = codec->control_data; if (reg >= TWL6040_CACHEREGNUM) return -EIO; twl6040_write_reg_cache(codec, reg, value); return twl6040_reg_write(twl6040, reg, value); }
/* * read from twl6040 hardware register */ static int twl6040_read_reg_volatile(struct snd_soc_codec *codec, unsigned int reg) { u8 value; if (reg >= TWL6040_CACHEREGNUM) return -EIO; twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &value, reg); twl6040_write_reg_cache(codec, reg, value); return value; }
/* * read from twl6040 hardware register */ static int twl6040_read_reg_volatile(struct snd_soc_codec *codec, unsigned int reg) { struct twl6040_codec *twl6040 = codec->control_data; u8 value = 0; if (reg >= TWL6040_CACHEREGNUM) return -EIO; value = twl6040_reg_read(twl6040, reg); twl6040_write_reg_cache(codec, reg, value); return value; }
/* * read from twl6040 hardware register */ static int twl6040_read_reg_volatile(struct snd_soc_codec *codec, unsigned int reg) { u8 value = 0; if (reg >= TWL6040_CACHEREGNUM) return -EIO; twl6040_i2c_read(reg, &value); twl6040_write_reg_cache(codec, reg, value); return value; }
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 __devinit twl6040_codec_probe(struct platform_device *pdev) { struct twl4030_codec_data *twl_codec = pdev->dev.platform_data; struct snd_soc_codec *codec; struct twl6040_data *priv; int audpwron, naudint; int ret = 0; priv = kzalloc(sizeof(struct twl6040_data), GFP_KERNEL); if (priv == NULL) return -ENOMEM; if (twl_codec) { audpwron = twl_codec->audpwron_gpio; naudint = twl_codec->naudint_irq; } else { audpwron = -EINVAL; naudint = 0; } priv->audpwron = audpwron; priv->naudint = naudint; codec = &priv->codec; codec->dev = &pdev->dev; twl6040_dai.dev = &pdev->dev; codec->name = "twl6040"; codec->owner = THIS_MODULE; codec->read = twl6040_read_reg_cache; codec->write = twl6040_write; codec->set_bias_level = twl6040_set_bias_level; snd_soc_codec_set_drvdata(codec, priv); codec->dai = &twl6040_dai; codec->num_dai = 1; codec->reg_cache_size = ARRAY_SIZE(twl6040_reg); codec->reg_cache = kmemdup(twl6040_reg, sizeof(twl6040_reg), GFP_KERNEL); if (codec->reg_cache == NULL) { ret = -ENOMEM; goto cache_err; } mutex_init(&codec->mutex); INIT_LIST_HEAD(&codec->dapm_widgets); INIT_LIST_HEAD(&codec->dapm_paths); init_completion(&priv->ready); if (gpio_is_valid(audpwron)) { ret = gpio_request(audpwron, "audpwron"); if (ret) goto gpio1_err; ret = gpio_direction_output(audpwron, 0); if (ret) goto gpio2_err; priv->codec_powered = 0; } if (naudint) { /* audio interrupt */ ret = request_threaded_irq(naudint, NULL, twl6040_naudint_handler, IRQF_TRIGGER_LOW | IRQF_ONESHOT, "twl6040_codec", codec); if (ret) goto gpio2_err; } else { if (gpio_is_valid(audpwron)) { /* enable only codec ready interrupt */ twl6040_write_reg_cache(codec, TWL6040_REG_INTMR, ~TWL6040_READYMSK & TWL6040_ALLINT_MSK); } else { /* no interrupts at all */ twl6040_write_reg_cache(codec, TWL6040_REG_INTMR, TWL6040_ALLINT_MSK); } } /* init vio registers */ twl6040_init_vio_regs(codec); /* power on device */ ret = twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY); if (ret) goto irq_err; ret = snd_soc_register_codec(codec); if (ret) goto reg_err; twl6040_codec = codec; ret = snd_soc_register_dai(&twl6040_dai); if (ret) goto dai_err; return 0; dai_err: snd_soc_unregister_codec(codec); twl6040_codec = NULL; reg_err: twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF); irq_err: if (naudint) free_irq(naudint, codec); gpio2_err: if (gpio_is_valid(audpwron)) gpio_free(audpwron); gpio1_err: kfree(codec->reg_cache); cache_err: kfree(priv); 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); #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; }