⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 omap2-audio-twl4030.c

📁 omap3 linux 2.6 用nocc去除了冗余代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * sound/arm/omap/omap-audio-twl4030.c * * Codec driver for TWL4030 for OMAP processors * * Copyright (C) 2007 Texas Instruments, Inc. * * This package is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * History: *  ------- *  2006-01-18 Nishanth Menon - Created *  2006-09-15 Jian Zhang - Ported to ALSA *  2007-04-16 Leonides Martinez - Added ALSA controls *//***************************** INCLUDES ************************************/#include <linux/module.h>#include <linux/init.h>#include <linux/types.h>#include <linux/fs.h>#include <linux/delay.h>#include <linux/pm.h>#include <linux/errno.h>#include <linux/sound.h>#include <linux/soundcard.h>#include <linux/bitops.h>#include <linux/interrupt.h>#include <linux/device.h>#include <asm/semaphore.h>#include <asm/uaccess.h>#include <asm/hardware.h>#include <asm/arch/dma.h>#include <asm/io.h>#include <asm/arch/mux.h>#include <asm/arch/io.h>#include <asm/mach-types.h>#include <sound/driver.h>#include <sound/core.h>#include <sound/initval.h>#include <sound/pcm.h>#include <sound/control.h>#include "omap2-audio_if.h"#include <asm/arch/omap2_mcbsp.h>#include <asm/arch/clock.h>#include <asm/arch/twl4030.h>#include "omap2-audio-twl4030.h"/*********** Debug Macros ********//* Change to define if required *//* To Generate a rather shrill tone -test the entire path */#undef TONE_GEN/* To dump the twl registers for debug */#undef TWL_DUMP_REGISTERS#undef TWL_DUMP_REGISTERS_MCBSP#undef DEBUG#undef DPRINTK#define DPRINTK( x... )#define FN_IN#define FN_OUT(n)static int codec_configured = 0;static int mcbsp_interface_acquired = 0;/****************                                          ************** * ***************************** COMM APIS ******************************** * *//** * @brief audio_twl4030_write * * @param address * @param data * * @return  0 if successful */static inline int audio_twl4030_write(u8 address, u8 data){	int ret = 0;	/* DEBUG */	DPRINTK("add[0x%02x]<=0x%02x\n", address, data);	ret = twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, data, address);	if (ret >= 0) {		ret = 0;	} else {		DPRINTK("TWL4030:Audio:Write[0x%x]"			" Error %d\n", address, ret);	}	FN_OUT(ret);	return ret;}/** * @brief audio_twl4030_read * * @param address * * @return  data if successful else return negative error value */static inline int audio_twl4030_read(u8 address){	u8 data;	int ret = 0;	ret = twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &data, address);	if (ret >= 0) {		ret = data;	} else {		DPRINTK("TWL4030:Audio:Read[0x%x] Error %d\n", address,			ret);	}	return ret;}/****************                                          ************** * ***************************** CODEC UTIL APIS ************************** * *//** * @brief twl4030_ext_mut_conf - configure GPIO for data out * * @return error in case of failure else 0 */static inline int twl4030_ext_mut_conf(void){	int ret;	u8 data;	ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, &data , GPIO_DATA_DIR);	if (ret)		return ret;	data |= 0x1<< T2_AUD_EXT_MUT_GPIO;	//ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, data , GPIO_DATA_DIR);	return ret;}/** * @brief twl4030_ext_mut_off - disable mute also handle time of wait * * @return error in case of failure else 0 */static inline int twl4030_ext_mut_off(void){	int ret;	u8 data;	ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, &data , GPIO_CLR);	if (ret)		return ret;	/* Wait for ramp duration.. settling time for signal */	udelay(1);	data |= 0x1<< T2_AUD_EXT_MUT_GPIO;	//ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, data, GPIO_CLR); //Clear mute	return ret;}/** * @brief twl4030_ext_mut_on - enable mute * * @return error in case of failure else 0 */static inline int twl4030_ext_mut_on(void){	int ret;	u8 data;	ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, &data , GPIO_SET);	if (ret)		return ret;	data |= 0x1<< T2_AUD_EXT_MUT_GPIO;	//ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, data, GPIO_SET); //Set mute	return ret;}/** * @brief twl4030_codec_on * * @return 0 if success, else error value */static inline int twl4030_codec_on(void){	int data = audio_twl4030_read(REG_CODEC_MODE);	FN_IN;	if (unlikely(data < 0)) {		printk(KERN_ERR "Reg read failed\n");		return data;	}	if (unlikely(data & BIT_CODEC_MODE_CODECPDZ_M)) {		DPRINTK("Codec already powered on??\n");		FN_OUT(0);		return 0;	}	data |= BIT_CODEC_MODE_CODECPDZ_M;	FN_OUT(0);	return audio_twl4030_write(REG_CODEC_MODE, (u8) data);}/** * @brief twl4030_codec_off - Switch off the codec * * @return 0 if success, else error value */static inline int twl4030_codec_off(void){	int data = audio_twl4030_read(REG_CODEC_MODE);	FN_IN;	if (unlikely(data < 0)) {		printk(KERN_ERR "Reg read failed\n");		return data;	}	/* Expected to be already off at bootup - but	 * we do not know the status of the device	 * hence would like to force a shut down	 */	if (unlikely(!(data & BIT_CODEC_MODE_CODECPDZ_M))) {		DPRINTK("Codec already powered off??\n");		FN_OUT(0);		return 0;	}	data &= ~BIT_CODEC_MODE_CODECPDZ_M;	FN_OUT(0);	return audio_twl4030_write(REG_CODEC_MODE, (u8) data);}/** * @brief twl4030_codec_tog_on - set the power to on after toggle to off *                               and then on * * @return 0 if success, else error value */static int twl4030_codec_tog_on(void){	int ret = 0;	int data = audio_twl4030_read(REG_CODEC_MODE);	FN_IN;	if (unlikely(data < 0)) {		printk(KERN_ERR "Reg read failed\n");		return data;	}	data &= ~BIT_CODEC_MODE_CODECPDZ_M;	ret =  audio_twl4030_write(REG_CODEC_MODE, (u8) data);	if (ret) {		printk(KERN_ERR "CODEC WRITE failed ! %d\n",ret);		FN_OUT(ret);		return ret;	}	udelay(10); /* 10 ms delay for power settling */	data |= BIT_CODEC_MODE_CODECPDZ_M;	ret =  audio_twl4030_write(REG_CODEC_MODE, (u8) data);	udelay(10); /* 10 ms delay for power settling */	FN_OUT(ret);	return ret;}/** * @brief twl_mcbsp_irq - the Interrupt handler for mcbsp events * * @param arg  - ignored * @param irq_status -mcbsp interrupt status * @param regs -ignored */static void twl_mcbsp_irq(void *arg, u32 irq_status, struct pt_regs *regs){	/* In case of errors - we need to reset the reciever to ensure	 * recovery	 */	if ((irq_status &		(OMAP2_MCBSP_IRQSTAT_XSYNCERR | OMAP2_MCBSP_IRQSTAT_XUNDFL |		 OMAP2_MCBSP_IRQSTAT_XOVFL))) {		/* We will handle this when we attempt a transfer */		tx_err = 1;	}	if ((irq_status &		(OMAP2_MCBSP_IRQSTAT_RSYNCERR | OMAP2_MCBSP_IRQSTAT_RUNDFL |		 OMAP2_MCBSP_IRQSTAT_ROVFL))) {		/* We will handle this when we attempt a transfer */		rx_err = 1;	}}/** * @brief twl4030_enable_output - enable the output path *  * NOTE * Codec power must be shut down during before this call *  * NOTE * This does not take care of gain settings *           for the specified output * @return 0 if successful */static int twl4030_enable_output(void){	u8 ear_ctl = 0;	u8 hs_ctl = 0;	u8 hs_pop = 0;	u8 hf_ctll = 0;	u8 hf_ctlr = 0;	u8 dac_ctl = 0;	u8 ck_ctll = 0;	u8 ck_ctlr = 0;	u8 opt = 0;	u32 line = 0;	int ret = 0;	FN_IN;	opt =	    audio_twl4030_read(REG_OPTION) & ~(BIT_OPTION_ARXR2_EN_M |					       BIT_OPTION_ARXL2_EN_M);	/* AR2 and AL2 are active for I2S */	if ((current_output & OUTPUT_STEREO_HEADSET) == OUTPUT_STEREO_HEADSET) {		hs_ctl |= BIT_HS_SEL_HSOR_AR2_EN_M | BIT_HS_SEL_HSOL_AL2_EN_M;		/* POP control - VMID? */		hs_pop = BIT_HS_POPN_SET_VMID_EN_M;		dac_ctl = BIT_AVDAC_CTL_ADACL2_EN_M | BIT_AVDAC_CTL_ADACR2_EN_M;		opt |= BIT_OPTION_ARXR2_EN_M | BIT_OPTION_ARXL2_EN_M;	}	if ((current_output & OUTPUT_HANDS_FREE_CLASSD) ==	    OUTPUT_HANDS_FREE_CLASSD) {		if (handsfree_en) {			hf_ctll |=			    HANDS_FREEL_AL2 << BIT_HFL_CTL_HFL_INPUT_SEL |			    BIT_HFL_CTL_HFL_REF_EN_M;			hf_ctlr |=			    HANDS_FREER_AR2 << BIT_HFR_CTL_HFR_INPUT_SEL |			    BIT_HFR_CTL_HFR_REF_EN_M;		}		dac_ctl = BIT_AVDAC_CTL_ADACL2_EN_M | BIT_AVDAC_CTL_ADACR2_EN_M;		opt |= BIT_OPTION_ARXR2_EN_M | BIT_OPTION_ARXL2_EN_M;	}	if ((current_output & OUTPUT_MONO_EARPIECE) == OUTPUT_MONO_EARPIECE) {		/* only AL2 comes in case of i2s */		ear_ctl |= BIT_EAR_CTL_EAR_AL2_EN_M;		dac_ctl = BIT_AVDAC_CTL_ADACL2_EN_M;		opt |= BIT_OPTION_ARXL2_EN_M;	}	if ((current_output & OUTPUT_CARKIT) == OUTPUT_CARKIT) {		ck_ctll |= BIT_PRECKL_CTL_PRECKL_AL2_EN_M					| BIT_PRECKL_CTL_PRECKL_EN_M;		ck_ctlr |= BIT_PRECKR_CTL_PRECKR_AR2_EN_M					| BIT_PRECKR_CTL_PRECKR_EN_M;		dac_ctl = BIT_AVDAC_CTL_ADACL2_EN_M					| BIT_AVDAC_CTL_ADACR2_EN_M;		opt |= BIT_OPTION_ARXL2_EN_M | BIT_OPTION_ARXR2_EN_M;	}	if (opt) {		ret = audio_twl4030_write(REG_OPTION, opt);		if (ret) {			line = __LINE__;			goto enable_op_exit;		}	}	if (ear_ctl) {		u8 temp;		temp = audio_twl4030_read(REG_EAR_CTL);		ear_ctl |= temp;		ret = audio_twl4030_write(REG_EAR_CTL, ear_ctl);		if (ret) {			line = __LINE__;			goto enable_op_exit;		}	}	if (hs_ctl) {		ret = audio_twl4030_write(REG_HS_SEL, hs_ctl);		if (ret) {			line = __LINE__;			goto enable_op_exit;		}	}	if (hs_pop) {		/* IMPORTANT: The following sequence is *required*		 * for starting the headset- esp for		 * ensuring the existance of the negative phase of		 * analog signal		 */		ret = audio_twl4030_write(REG_HS_POPN_SET, hs_pop);		if (ret) {			line = __LINE__;			goto enable_op_exit;		}		hs_pop |= BIT_HS_POPN_SET_RAMP_EN_M;		udelay(1); /* require a short delay before enabling ramp */		ret = audio_twl4030_write(REG_HS_POPN_SET, hs_pop);		if (ret) {			line = __LINE__;			goto enable_op_exit;		}	}	/* IMPORTANT: The following sequence is *required*	 * for starting the speakers!	 */	if (hf_ctll) {		ret = audio_twl4030_write(REG_HFL_CTL, hf_ctll);		if (ret) {			line = __LINE__;			goto enable_op_exit;		}		hf_ctll |= BIT_HFL_CTL_HFL_RAMP_EN_M;		ret = audio_twl4030_write(REG_HFL_CTL, hf_ctll);		if (ret) {			line = __LINE__;			goto enable_op_exit;		}		hf_ctll |= BIT_HFL_CTL_HFL_LOOP_EN_M;		ret = audio_twl4030_write(REG_HFL_CTL, hf_ctll);		if (ret) {			line = __LINE__;			goto enable_op_exit;		}		hf_ctll |= BIT_HFL_CTL_HFL_HB_EN_M;		ret = audio_twl4030_write(REG_HFL_CTL, hf_ctll);		if (ret) {			line = __LINE__;			goto enable_op_exit;		}	}	if (hf_ctlr) {		ret = audio_twl4030_write(REG_HFR_CTL, hf_ctlr);		if (ret) {			line = __LINE__;			goto enable_op_exit;		}		hf_ctlr |= BIT_HFR_CTL_HFR_RAMP_EN_M;		ret = audio_twl4030_write(REG_HFR_CTL, hf_ctlr);		if (ret) {			line = __LINE__;			goto enable_op_exit;		}		hf_ctlr |= BIT_HFR_CTL_HFR_LOOP_EN_M;		ret = audio_twl4030_write(REG_HFR_CTL, hf_ctlr);		if (ret) {			line = __LINE__;			goto enable_op_exit;		}		hf_ctlr |= BIT_HFR_CTL_HFR_HB_EN_M;		ret = audio_twl4030_write(REG_HFR_CTL, hf_ctlr);		if (ret) {			line = __LINE__;			goto enable_op_exit;		}	}	if (dac_ctl) {		/* I2S should go thru DACR2, DACL2- unless we are on mono */		if (current_stereomode == MONO_MODE) {			dac_ctl &= ~BIT_AVDAC_CTL_ADACR2_EN_M;		}		ret = audio_twl4030_write(REG_AVDAC_CTL, dac_ctl);		if (ret) {			line = __LINE__;			goto enable_op_exit;		}	}	if (ck_ctll) {		ret = audio_twl4030_write(REG_PRECKL_CTL, ck_ctll);		if (ret) {			line = __LINE__;			goto enable_op_exit;		}	}	if (ck_ctlr) {		ret = audio_twl4030_write(REG_PRECKR_CTL, ck_ctlr);	}      enable_op_exit:	if (ret)		printk(KERN_ERR "Error in Enable output[%d] in Line %d\n", ret,		       line);	FN_OUT(ret);	return ret;}/** * @brief twl4030_disable_output - remove the output path * *NOTE* shut down the codec before attempting this * * @return 0 if successful */static int twl4030_disable_output(void){	int ret = 0;	int line = 0;	u8 RdReg;	FN_IN;	RdReg = audio_twl4030_read(REG_PRECKR_CTL);	RdReg &= BIT_PRECKR_CTL_PRECKR_GAIN_M;  /* To preserve gain settings */	ret = audio_twl4030_write(REG_PRECKR_CTL, 0x0);	if (ret) {		line = __LINE__;		goto disable_op_exit;	}	RdReg = audio_twl4030_read(REG_PRECKL_CTL);	RdReg &= BIT_PRECKL_CTL_PRECKL_GAIN_M;  /* To preserve gain settings */	ret = audio_twl4030_write(REG_PRECKL_CTL, 0x0);	if (ret) {		line = __LINE__;		goto disable_op_exit;	}	ret = audio_twl4030_write(REG_PREDR_CTL, 0x0);	if (ret) {		line = __LINE__;		goto disable_op_exit;	}	ret = audio_twl4030_write(REG_PREDL_CTL, 0x0);	if (ret) {		line = __LINE__;		goto disable_op_exit;	}	RdReg = audio_twl4030_read(REG_EAR_CTL);	RdReg &= BIT_EAR_CTL_EAR_GAIN_M;	/* To preserve gain settings */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -