示例#1
0
文件: twl6040.c 项目: panhenry/MyTest
/* set headset dac and driver power mode */
static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
{
	int hslctl, hsrctl;
	int mask = TWL6040_HSDRVMODEL | TWL6040_HSDACMODEL;
	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);

	/* Earphone doesn't support low power mode */
	high_perf |= priv->earpiece_used;

	hslctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSLCTL);
	hsrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSRCTL);

	if (high_perf) {
		hslctl &= ~mask;
		hsrctl &= ~mask;
	} else {
		hslctl |= mask;
		hsrctl |= mask;
	}

	twl6040_write(codec, TWL6040_REG_HSLCTL, hslctl);
	twl6040_write(codec, TWL6040_REG_HSRCTL, hsrctl);

	return 0;
}
示例#2
0
static int twl6040_mute(struct snd_soc_dai *codec_dai, int mute)
{
#if 0
	struct snd_soc_codec *codec = codec_dai->codec;
	int hs_gain, hfl_gain, hfr_gain;
	struct snd_soc_card *card = codec_dai->card;
	int idx;
	int mute_all;

	hfl_gain = twl6040_read_reg_cache(codec, TWL6040_REG_HFLGAIN);
	hfr_gain = twl6040_read_reg_cache(codec, TWL6040_REG_HFRGAIN);
	hs_gain = twl6040_read_reg_cache(codec, TWL6040_REG_HSGAIN);

	if (mute) {
		mute_all = 1;
		for( idx = 0 ; idx < TWL6040_MUTE_DATA_MAX ; idx++ )
		{
			if( s_mute_data[idx].dai == codec_dai )
			{
				s_mute_data[idx].mute = mute;
			}

			if( s_mute_data[idx].dai && s_mute_data[idx].mute == 0 )
			{
				mute_all = 0;
				break;
			}
		}

		if( mute_all )
		{
			twl6040_i2c_write(TWL6040_REG_HFLGAIN, 0x1D);
			twl6040_i2c_write(TWL6040_REG_HFRGAIN, 0x1D);
			twl6040_i2c_write(TWL6040_REG_HSGAIN, 0xFF);
		}
	} else {
		mute_all = 0;
		for( idx = 0 ; idx < TWL6040_MUTE_DATA_MAX ; idx++ )
		{
			if( s_mute_data[idx].dai == codec_dai )
			{
				s_mute_data[idx].mute = mute;
			}

			if( s_mute_data[idx].dai && s_mute_data[idx].mute )
			{
				mute_all = 1;
				break;
			}
		}

		if( mute_all == 0 ){
			twl6040_write(codec, TWL6040_REG_HFLGAIN, hfl_gain);
			twl6040_write(codec, TWL6040_REG_HFRGAIN, hfr_gain);
			twl6040_write(codec, TWL6040_REG_HSGAIN, hs_gain);
		}
	}
#endif
	return 0;
}
示例#3
0
文件: twl6040.c 项目: panhenry/MyTest
static void twl6040_init_vio_regs(struct snd_soc_codec *codec)
{
	u8 *cache = codec->reg_cache;
	int reg, i;

	for (i = 0; i < TWL6040_VIOREGNUM; i++) {
		reg = twl6040_vio_reg[i];
		/*
		 * skip read-only registers (ASICID, ASICREV, STATUS)
		 * and registers shared among MFD children
		 */
		switch (reg) {
		case TWL6040_REG_ASICID:
		case TWL6040_REG_ASICREV:
		case TWL6040_REG_INTID:
		case TWL6040_REG_INTMR:
		case TWL6040_REG_NCPCTL:
		case TWL6040_REG_LDOCTL:
		case TWL6040_REG_GPOCTL:
		case TWL6040_REG_ACCCTL:
		case TWL6040_REG_STATUS:
			continue;
		default:
			break;
		}
		twl6040_write(codec, reg, cache[reg]);
	}
}
示例#4
0
static void twl6040_init_vdd_regs(struct snd_soc_codec *codec)
{
	u8 *cache = codec->reg_cache;
	int reg, i;

	for (i = 0; i < TWL6040_VDDREGNUM; i++) {
		reg = twl6040_vdd_reg[i];
		twl6040_write(codec, reg, cache[reg]);
	}
}
示例#5
0
/* set headset dac and driver power mode */
static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
{
	int hslctl, hsrctl;
	int mask = TWL6040_HSDRVMODEL | TWL6040_HSDACMODEL;

	hslctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSLCTL);
	hsrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSRCTL);

	if (high_perf) {
		hslctl &= ~mask;
		hsrctl &= ~mask;
	} else {
		hslctl |= mask;
		hsrctl |= mask;
	}

	twl6040_write(codec, TWL6040_REG_HSLCTL, hslctl);
	twl6040_write(codec, TWL6040_REG_HSRCTL, hsrctl);

	return 0;
}
示例#6
0
static void twl6040_init_vio_regs(struct snd_soc_codec *codec)
{
	u8 *cache = codec->reg_cache;
	int reg, i;

	/* allow registers to be accessed by i2c */
	twl6040_write(codec, TWL6040_REG_ACCCTL, cache[TWL6040_REG_ACCCTL]);

	for (i = 0; i < TWL6040_VIOREGNUM; i++) {
		reg = twl6040_vio_reg[i];
		/* skip read-only registers (ASICID, ASICREV, STATUS) */
		switch (reg) {
		case TWL6040_REG_ASICID:
		case TWL6040_REG_ASICREV:
		case TWL6040_REG_STATUS:
			continue;
		default:
			break;
		}
		twl6040_write(codec, reg, cache[reg]);
	}
}
示例#7
0
void set_hook_enable(struct snd_soc_codec *codec, int on)
{
	u8 hkctl1;
	
	hkctl1 = twl6040_read_reg_cache(codec, TWL6040_REG_HKCTL1);
	
	if(on)
		hkctl1 |= TWL6040_HKEN;
	else
		hkctl1 &= ~TWL6040_HKEN;

	twl6040_write(codec, TWL6040_REG_HKCTL1, hkctl1);
}
示例#8
0
void hs_set_bias(struct snd_soc_codec *codec, int on)
{
	u8 hsbias;

	hsbias = twl6040_read_reg_cache(codec, TWL6040_REG_AMICBCTL);
	
	if(on)
		hsbias |= TWL6040_HMICENA;
	else
		hsbias &= ~TWL6040_HMICENA;

	twl6040_write(codec, TWL6040_REG_AMICBCTL, hsbias);
}
示例#9
0
/* twl6040 codec manual power-up sequence */
static void twl6040_power_up(struct snd_soc_codec *codec)
{
	u8 ncpctl, ldoctl, lppllctl, accctl;

	ncpctl = twl6040_read_reg_cache(codec, TWL6040_REG_NCPCTL);
	ldoctl = twl6040_read_reg_cache(codec, TWL6040_REG_LDOCTL);
	lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL);
	accctl = twl6040_read_reg_cache(codec, TWL6040_REG_ACCCTL);

	/* enable reference system */
	ldoctl |= TWL6040_REFENA;
	twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
	msleep(10);
	/* enable internal oscillator */
	ldoctl |= TWL6040_OSCENA;
	twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
	udelay(10);
	/* enable high-side ldo */
	ldoctl |= TWL6040_HSLDOENA;
	twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
	udelay(244);
	/* enable negative charge pump */
	ncpctl |= TWL6040_NCPENA | TWL6040_NCPOPEN;
	twl6040_write(codec, TWL6040_REG_NCPCTL, ncpctl);
	udelay(488);
	/* enable low-side ldo */
	ldoctl |= TWL6040_LSLDOENA;
	twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
	udelay(244);
	/* enable low-power pll */
	lppllctl |= TWL6040_LPLLENA;
	twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
	/* reset state machine */
	accctl |= TWL6040_RESETSPLIT;
	twl6040_write(codec, TWL6040_REG_ACCCTL, accctl);
	mdelay(5);
	accctl &= ~TWL6040_RESETSPLIT;
	twl6040_write(codec, TWL6040_REG_ACCCTL, accctl);
	/* disable internal oscillator */
	ldoctl &= ~TWL6040_OSCENA;
	twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
}
示例#10
0
static int twl6040_hw_params(struct snd_pcm_substream *substream,
			struct snd_pcm_hw_params *params,
			struct snd_soc_dai *dai)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_codec *codec = rtd->codec;
	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
	u8 lppllctl;
	int rate;

	/* nothing to do for high-perf pll, it supports only 48 kHz */
	if (priv->pll == TWL6040_HPPLL_ID)
		return 0;

	lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL);

	rate = params_rate(params);
	switch (rate) {
	case 11250:
	case 22500:
	case 44100:
	case 88200:
		lppllctl |= TWL6040_LPLLFIN;
		priv->sysclk = 17640000;
		break;
	case 8000:
	case 16000:
	case 32000:
	case 48000:
	case 96000:
		lppllctl &= ~TWL6040_LPLLFIN;
		priv->sysclk = 19200000;
		break;
	default:
		dev_err(codec->dev, "unsupported rate %d\n", rate);
		return -EINVAL;
	}

	twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);

	return 0;
}
示例#11
0
文件: twl6040.c 项目: panhenry/MyTest
static void twl6040_init_vdd_regs(struct snd_soc_codec *codec)
{
	u8 *cache = codec->reg_cache;
	int reg, i;

	for (i = 0; i < TWL6040_VDDREGNUM; i++) {
		reg = twl6040_vdd_reg[i];
		/* skip vibra and pll registers */
		switch (reg) {
		case TWL6040_REG_VIBCTLL:
		case TWL6040_REG_VIBDATL:
		case TWL6040_REG_VIBCTLR:
		case TWL6040_REG_VIBDATR:
		case TWL6040_REG_HPPLLCTL:
		case TWL6040_REG_LPPLLCTL:
		case TWL6040_REG_LPPLLDIV:
			continue;
		default:
			break;
		}
		twl6040_write(codec, reg, cache[reg]);
	}
}
示例#12
0
文件: twl6040.c 项目: panhenry/MyTest
static int twl6040_mute(struct snd_soc_dai *codec_dai, int mute)
{
	struct snd_soc_codec *codec = codec_dai->codec;
	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);

	if (mute) {
		priv->hfl_gain = twl6040_read_reg_cache(codec,
						TWL6040_REG_HFLGAIN);
		priv->hfr_gain = twl6040_read_reg_cache(codec,
						TWL6040_REG_HFRGAIN);
		priv->hs_gain = twl6040_read_reg_cache(codec,
						TWL6040_REG_HSGAIN);

		twl6040_write(codec, TWL6040_REG_HFLGAIN, 0x1D);
		twl6040_write(codec, TWL6040_REG_HFRGAIN, 0x1D);
		twl6040_write(codec, TWL6040_REG_HSGAIN, 0xFF);
	} else {
		twl6040_write(codec, TWL6040_REG_HFLGAIN, priv->hfl_gain);
		twl6040_write(codec, TWL6040_REG_HFRGAIN, priv->hfr_gain);
		twl6040_write(codec, TWL6040_REG_HSGAIN, priv->hs_gain);
	}

	return 0;
}
示例#13
0
static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
		int clk_id, unsigned int freq, int dir)
{
	struct snd_soc_codec *codec = codec_dai->codec;
	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
	u8 hppllctl, lppllctl;

	hppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_HPPLLCTL);
	lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL);

	switch (clk_id) {
	case TWL6040_SYSCLK_SEL_LPPLL:
		switch (freq) {
		case 32768:
			/* headset dac and driver must be in low-power mode */
			headset_power_mode(codec, 0);

			/* clk32k input requires low-power pll */
			lppllctl |= TWL6040_LPLLENA;
			twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
			mdelay(5);
			lppllctl &= ~TWL6040_HPLLSEL;
			twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
			hppllctl &= ~TWL6040_HPLLENA;
			twl6040_write(codec, TWL6040_REG_HPPLLCTL, hppllctl);
			break;
		default:
			dev_err(codec->dev, "unknown mclk freq %d\n", freq);
			return -EINVAL;
		}

		/* lppll divider */
		switch (priv->sysclk) {
		case 17640000:
			lppllctl |= TWL6040_LPLLFIN;
			break;
		case 19200000:
			lppllctl &= ~TWL6040_LPLLFIN;
			break;
		default:
			/* sysclk not yet configured */
			lppllctl &= ~TWL6040_LPLLFIN;
			priv->sysclk = 19200000;
			break;
		}

		twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);

		priv->pll = TWL6040_LPPLL_ID;
		priv->sysclk_constraints = &lp_constraints;
		break;
	case TWL6040_SYSCLK_SEL_HPPLL:
		hppllctl &= ~TWL6040_MCLK_MSK;

		switch (freq) {
		case 12000000:
			/* mclk input, pll enabled */
			hppllctl |= TWL6040_MCLK_12000KHZ |
				    TWL6040_HPLLSQRBP |
				    TWL6040_HPLLENA;
			break;
		case 19200000:
			/* mclk input, pll disabled */
			hppllctl |= TWL6040_MCLK_19200KHZ |
				    TWL6040_HPLLSQRENA |
				    TWL6040_HPLLBP;
			break;
		case 26000000:
			/* mclk input, pll enabled */
			hppllctl |= TWL6040_MCLK_26000KHZ |
				    TWL6040_HPLLSQRBP |
				    TWL6040_HPLLENA;
			break;
		case 38400000:
			/* clk slicer, pll disabled */
			hppllctl |= TWL6040_MCLK_38400KHZ |
				    TWL6040_HPLLSQRENA |
				    TWL6040_HPLLBP;
			break;
		default:
			dev_err(codec->dev, "unknown mclk freq %d\n", freq);
			return -EINVAL;
		}

		/* headset dac and driver must be in high-performance mode */
		headset_power_mode(codec, 1);

		twl6040_write(codec, TWL6040_REG_HPPLLCTL, hppllctl);
		udelay(500);
		lppllctl |= TWL6040_HPLLSEL;
		twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
		lppllctl &= ~TWL6040_LPLLENA;
		twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);

		/* high-performance pll can provide only 19.2 MHz */
		priv->pll = TWL6040_HPPLL_ID;
		priv->sysclk = 19200000;
		priv->sysclk_constraints = &hp_constraints;
		break;
	default:
		dev_err(codec->dev, "unknown clk_id %d\n", clk_id);
		return -EINVAL;
	}

	return 0;
}
示例#14
0
static void twl6040_hs_jack_detect_dwork(struct work_struct *dwork)
{
	struct twl6040_data *priv;
	struct snd_soc_codec *codec;
	struct twl6040_jack_data *jack;
	int status = 0;

	priv = container_of(dwork, struct twl6040_data, hsdet_dwork.work);
	codec = priv->codec;
	jack = &priv->hs_jack;

	/*
	 * Early interrupt, CODEC driver cannot report jack status
	 * since jack is not registered yet. MACHINE driver will
	 * register jack and report status through twl6040_hs_jack_detect
	 */
	if (jack->jack) {
#if defined(CONFIG_MACH_LGE_COSMO_REV_A)
		if(gpio_get_value(priv->hsjack_gpio))
#else 
		if(jack->state)
#endif
		{		
			u8 val = 0;
			if( twl6040_i2c_read(TWL6040_REG_AMICBCTL, &val) == 0 ){
				if( val != twl6040_read_reg_cache(codec, TWL6040_REG_AMICBCTL) )
					twl6040_i2c_write(TWL6040_REG_AMICBCTL, twl6040_read_reg_cache(codec, TWL6040_REG_AMICBCTL)); 
			}

			hs_set_bias(codec, 1);
			set_hook_enable(codec, 1);
			mdelay(200);

			if( twl6040_i2c_read(TWL6040_REG_MICLCTL, &val) == 0 ){
				if( val != twl6040_read_reg_cache(codec, TWL6040_REG_MICLCTL) )
					twl6040_i2c_write(TWL6040_REG_MICLCTL, twl6040_read_reg_cache(codec, TWL6040_REG_MICLCTL)); 
			}
			if( twl6040_i2c_read(TWL6040_REG_MICRCTL, &val) == 0 ){
				if( val != twl6040_read_reg_cache(codec, TWL6040_REG_MICRCTL) )
					twl6040_i2c_write(TWL6040_REG_MICRCTL, twl6040_read_reg_cache(codec, TWL6040_REG_MICRCTL)); 
			}

			if(is_without_mic()){
				set_hook_enable(codec, 0);
				hs_set_bias(codec, 0);
				jack->state = WIRED_HEADPHONE;//wired headset without MIC
				status = SND_JACK_HEADPHONE;
			}
			else{
				if(priv->intmask & TWL6040_HOOKMSK){
					priv->intmask &= ~TWL6040_HOOKMSK;
					twl6040_write(codec, TWL6040_REG_INTMR, priv->intmask);
				}
				status = jack->report;//SND_JACK_HEADSET
			}
		}
		else{
			if(!(priv->intmask & TWL6040_HOOKMSK)) {
				priv->intmask |= TWL6040_HOOKMSK;
				twl6040_write(codec, TWL6040_REG_INTMR, priv->intmask);
			}
			hs_set_bias(codec, 0);
			status = 0;
		}
		snd_soc_jack_report(jack->jack, status, jack->report);
	}
	switch_set_state(&jack->sdev, jack->state);
}
示例#15
0
static int twl6040_probe(struct snd_soc_codec *codec)
{
	struct twl4030_codec_audio_data *twl_codec = codec->dev->platform_data;
	struct twl6040_data *priv;
	struct twl6040_jack_data *jack;
	int audpwron, naudint;
	struct input_dev *ip_dev;

#if defined(CONFIG_MACH_LGE_COSMO_REV_A)
	unsigned hsjack_gpio, hsjack_irq;
	int err;
#endif
	int ret = 0;
	u8 icrev = 0, intmr = TWL6040_ALLINT_MSK;
	int idx;

	for( idx = 0 ; idx < TWL6040_MUTE_DATA_MAX ; idx++ )
	{
		s_mute_data[idx].dai = 0;
		s_mute_data[idx].mute = 0;
	}
	
	priv = kzalloc(sizeof(struct twl6040_data), GFP_KERNEL);
	if (priv == NULL)
		return -ENOMEM;
	snd_soc_codec_set_drvdata(codec, priv);

	priv->codec = codec;
	priv->dl_active = 0;
	priv->ul_active = 0;

	twl6040_i2c_read(TWL6040_REG_ASICREV, &icrev);

	if (twl_codec && (icrev > 0))
		audpwron = twl_codec->audpwron_gpio;
	else
		audpwron = -EINVAL;

#if defined(CONFIG_MACH_LGE_COSMO_REV_A)
	if (twl_codec){
		naudint = twl_codec->naudint_irq;
		hsjack_gpio = twl_codec->hsjack_gpio;
		hsjack_irq = twl_codec->hsjack_irq;
	}
	else {
		naudint = 0;
		hsjack_gpio = 0;
		hsjack_irq = 0;
	}
#else
	if (twl_codec)
		naudint = twl_codec->naudint_irq;
	else
		naudint = 0;
#endif

	priv->audpwron = audpwron;
	priv->naudint = naudint;
	
#if defined(CONFIG_MACH_LGE_COSMO_REV_A)
	priv->hsjack_gpio = hsjack_gpio;
	priv->hsjack_irq = hsjack_irq;
#endif
	init_completion(&priv->ready);

	/* Disable safe mode in SYS_NIRQ PAD */
//	omap_writew(0x0118, 0x4A1001A0);

	INIT_DELAYED_WORK(&priv->hsdet_dwork, twl6040_hs_jack_detect_dwork);
	INIT_DELAYED_WORK(&priv->hook_work, twl6040_hs_hook_detect_work);

#ifndef CONFIG_MACH_LGE_COSMOPOLITAN
	INIT_WORK(&priv->audint_work, twl6040_audint_work);
#endif

	ip_dev	= input_allocate_device();
	if(!ip_dev){
		dev_err(codec->dev, "failed to allocation hook input device");
		goto switch_err;
	}
	__set_bit(EV_KEY, ip_dev->evbit);
	__set_bit(EV_SYN, ip_dev->evbit);
	__set_bit(KEY_HOOK, ip_dev->keybit);
	ip_dev->name = "headset_hook";
	ip_dev->phys = "headset_hook/input0";
	priv->hs_jack.headset_input = ip_dev;
	input_register_device(priv->hs_jack.headset_input);

	/* switch-class based headset detection */
	jack = &priv->hs_jack;
	jack->sdev.name = "h2w";
	ret = switch_dev_register(&jack->sdev);
	if (ret) {
		dev_err(codec->dev, "error registering switch device %d\n", ret);
		goto switch_err;
	}
#if defined(CONFIG_MACH_LGE_COSMO_REV_A)
	/* GPIO request and direction set */
	if(gpio_is_valid(hsjack_gpio)) {
		err = gpio_request(hsjack_gpio, "ear_sense");
		if (err) {
			printk(KERN_ERR "%s: failed to request GPIO_%d\n",
				   __func__, hsjack_gpio);
			goto err_hs_gpio_request;
		}
		err = gpio_direction_input(hsjack_gpio);
		if (err) {
			printk(KERN_ERR "%s: failed to set direction GPIO_%d\n",
				   __func__, hsjack_gpio);
			goto err_hs_gpio_direction;
		}
	}

	/* IRQ request */
	err = request_irq(hsjack_irq,
					  hsjack_irq_handler,
					  IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
					  "headset_detect",
					  codec);
	if (err) {
		printk(KERN_ERR "%s: failed to request irq (%d)\n",
			   __func__, hsjack_irq);
		goto err_hs_request_irq;
	}
#endif

	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;

		/* enable only codec ready interrupt */
		intmr &= ~(TWL6040_READYMSK | TWL6040_PLUGMSK );
		priv->intmask = intmr; 

		/* reset interrupt status to allow correct power up sequence */
		twl6040_read_reg_volatile(codec, TWL6040_REG_INTID);
	}
	twl6040_write(codec, TWL6040_REG_INTMR, intmr);

	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;
	}

	/* init vio registers */
	twl6040_init_vio_regs(codec);

	/* power on device */
	ret = twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
	if (ret)
		goto bias_err;

	snd_soc_add_controls(codec, twl6040_snd_controls,
				ARRAY_SIZE(twl6040_snd_controls));
	twl6040_add_widgets(codec);

	wake_lock_init(&priv->wake_lock, WAKE_LOCK_SUSPEND, "twl6040");

	cdc_tcxo_set_req_int(CDC_TCXO_CLK3, 0);

	/* TODO: read HS jack insertion status */

	return 0;

bias_err:
	if (naudint)
		free_irq(naudint, codec);
#if defined(CONFIG_MACH_LGE_COSMO_REV_A)
err_hs_request_irq:
err_hs_gpio_direction:
	if (gpio_is_valid(hsjack_gpio))
		gpio_free(hsjack_gpio);
err_hs_gpio_request:
#endif
gpio2_err:
	if (gpio_is_valid(audpwron))
		gpio_free(audpwron);
gpio1_err:
	switch_dev_unregister(&jack->sdev);
switch_err:
	kfree(priv);
	return ret;
}
示例#16
0
void twl6040_hs_jack_detect(struct snd_soc_codec *codec,
			    struct snd_soc_jack *jack, int report)
{
	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
	int status, state;

	priv->hs_jack.jack = jack;
	priv->hs_jack.report = report;

#if !defined(CONFIG_MACH_LGE_COSMO_REV_A)
	/* Sync status */
	status = twl6040_read_reg_volatile(codec, TWL6040_REG_STATUS);

#if defined(CONFIG_MACH_LGE_COSMOPOLITAN)
	if(status & TWL6040_PLUGCOMP)
		priv->hs_jack.state = HEADSET_NONE;		
	else
		priv->hs_jack.state = WIRED_HEADSET;
#else
	if(status & TWL6040_PLUGCOMP)
		state = report;
	else
		state = 0;
#endif

#endif// !CONFIG_MACH_LGE_COSMO_REV_A


#if defined(CONFIG_MACH_LGE_COSMO_REV_A)
	if(gpio_get_value(priv->hsjack_gpio))
#else
	if(priv->hs_jack.state)
#endif
	{
		hs_set_bias(codec, 1);
		set_hook_enable(codec, 1);
		mdelay(200);

		if(is_without_mic()){
			set_hook_enable(codec, 0);
			hs_set_bias(codec, 0);
			state = WIRED_HEADPHONE;//wired headset without MIC
			status = SND_JACK_HEADPHONE;
		}
		else{
			 /* for wired_headset */
			if(priv->intmask & TWL6040_HOOKMSK){
				priv->intmask &= ~TWL6040_HOOKMSK;
				twl6040_write(codec, TWL6040_REG_INTMR, priv->intmask);
			}
			state = WIRED_HEADSET;//wired headset with MIC
			status = priv->hs_jack.report;//SND_JACK_HEADSET
		}
	}
	else{
		 /* when headset removed */
		if(!(priv->intmask & TWL6040_HOOKMSK)) {
			priv->intmask |= TWL6040_HOOKMSK;
			twl6040_write(codec, TWL6040_REG_INTMR, priv->intmask);
		}
		set_hook_enable(codec, 0);
		hs_set_bias(codec, 0);
		state = HEADSET_NONE;
		status = 0;
	}

	switch_set_state(&priv->hs_jack.sdev, state);
	snd_soc_jack_report(jack, status, report);
}