예제 #1
0
/*
 * 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);
}
예제 #2
0
/*
 * 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);
}
예제 #3
0
파일: twl6040.c 프로젝트: panhenry/MyTest
/*
 * 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);
}
예제 #4
0
/*
 * 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;
}
예제 #5
0
파일: twl6040.c 프로젝트: panhenry/MyTest
/*
 * 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;
}
예제 #6
0
/*
 * 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;
}
예제 #7
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);

			/* 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;
}
예제 #8
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;
}
예제 #9
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;
}