blob: 53789891a485098cb4385d93c7c8eb2a53b65dd8 [file] [log] [blame]
/*
* Base driver for ASR tlv320aic3x
*
* Copyright (C) 2019 ASR.
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file "COPYING" in the main directory of this
* archive for more details.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/mfd/core.h>
#include <linux/mfd/88pm80x.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/of_device.h>
#include <linux/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/fs.h>
#include <linux/debugfs.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <linux/gpio.h>
//#include <plat/mfp.h>
#include <linux/regulator/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <linux/cputype.h>
#include <soc/asr/addr-map.h>
#include "tlv320aic3x.h"
#include <linux/clk.h>
#ifndef APB_VIRT_BASE
#define APB_VIRT_BASE IOMEM(0xfe000000)
#endif
#define SSP1_I2S_CLOCK_REG_ADDR (0xD4050044)
#ifdef Kestrel_Z2
//Kestrel Z2
static void __iomem *VCXO_OUT_MFPR_reg = APB_VIRT_BASE + 0x1E000 + 0x208;/* 0xD401E000+0x208 */
static void __iomem *PM_MN_CLK_reg = APB_VIRT_BASE + 0x51000 + 0xA4;/* 0xD4051000+0xA4 */
static void __iomem *GPCR_reg = APB_VIRT_BASE + 0x50000 + 0x30;/* 0xD4050030 */
#else
//Kestrel A0
static void __iomem *MCLK_CLK_CTRL_reg = NULL;/* 0xD6800000+0x4C */
static void __iomem *MCLK_MN_DIV_reg = NULL;/* 0xD6800000+0x50 */
#endif
//NezhaC/Falcon
static void __iomem *SSP1_I2S_CLOCK_reg = APB_VIRT_BASE + 0x50000 + 0x44;/* 0xD4050000+0x44 */
#if defined(CONFIG_CODEC_PCM_NB)
/* Narrowband */
char Audio_Codec_Fsync_Rate = 0;
#elif defined(CONFIG_CODEC_PCM_WB)
/* Wideband */
char Audio_Codec_Fsync_Rate = 1;
#elif defined(CONFIG_CODEC_PCM_32KHz)
/* 32KHz */
char Audio_Codec_Fsync_Rate = 2;
#elif defined(CONFIG_CODEC_PCM_48KHz)
/* 48KHz */
char Audio_Codec_Fsync_Rate = 3;
#else
/* Narrowband */
char Audio_Codec_Fsync_Rate = 0;
#endif
#ifdef CONFIG_CODEC_PCM_MASTER
/* CODEC is master, GSSP is slave. */
char G_AudioModemMaster = 0;
#else
/* CODEC PCM config is slave in config/defconfig_asr1802sp201
CODEC is slave, GSSP is master. */
char G_AudioModemMaster = 1;
#endif
static const struct i2c_device_id tlv320aic3x_dt_table[] = {
{"tlv320aic3x", 0},
{} /* NULL terminated */
};
MODULE_DEVICE_TABLE(i2c, tlv320aic3x_dt_table);
static const struct of_device_id tlv320aic3x_dt_ids[] = {
{ .compatible = "ti,tlv320aic3104", },
{},
};
MODULE_DEVICE_TABLE(of, tlv320aic3x_dt_ids);
static struct i2c_client *g_tlv320aic3x_client = NULL;
static struct pinctrl *g_tlv320aic3x_pinctrl = NULL;
static struct device_node *g_tlv320aic3x_node = NULL;
static void __iomem *i2s_clk_reg = NULL;
static int gpio_tds_dio10 = 0; /* GPIO[78] */
static int gpio_vcxo_out = 0; /* GPIO[126] */
static int gpio_31_CODEC_1V8_EN = 0; /* GPIO[31] */
static int gpio_32_CODEC_3V3_EN = 0; /* GPIO[32] */
static int g_reset_gpio = -1;
static struct regulator *tlv320aic3x_regulator_vdd_1v8 = NULL;
static struct regulator *tlv320aic3x_regulator_vdd_3v3 = NULL;
#ifdef HEADSET_DETECTION
static int gpio_CODEC_IRQ = 0; /* GPIO[1] */
static int irq_codec;
#endif
//#define HEADSET_DETECTION
//#define TLV320AIC3X_DEBUG
//#define TLV320AIC3X_DEBUG_CLOSE
#define tlv320aic3x_reg_NUM 0xFF
/* base functions */
static unsigned short tlv320aic3x_readable_register(unsigned int reg)
{
switch (reg) {
case TLV320AIC3X_RESET_REG00:
case TLV320AIC3X_CLK_MANAGER_REG01:
case TLV320AIC3X_CLK_MANAGER_REG02:
case TLV320AIC3X_CLK_MANAGER_REG03:
case TLV320AIC3X_CLK_MANAGER_REG04:
case TLV320AIC3X_CLK_MANAGER_REG05:
case TLV320AIC3X_CLK_MANAGER_REG06:
case TLV320AIC3X_CLK_MANAGER_REG07:
case TLV320AIC3X_CLK_MANAGER_REG08:
case TLV320AIC3X_SDPIN_REG09:
case TLV320AIC3X_SDPOUT_REG0A:
case TLV320AIC3X_SYSTEM_REG0B:
case TLV320AIC3X_SYSTEM_REG0C:
case TLV320AIC3X_SYSTEM_REG0D:
case TLV320AIC3X_SYSTEM_REG0E:
case TLV320AIC3X_SYSTEM_REG0F:
case TLV320AIC3X_SYSTEM_REG10:
case TLV320AIC3X_SYSTEM_REG11:
case TLV320AIC3X_SYSTEM_REG12:
case TLV320AIC3X_SYSTEM_REG13:
case TLV320AIC3X_SYSTEM_REG14:
case TLV320AIC3X_ADC_REG15:
case TLV320AIC3X_ADC_REG16:
case TLV320AIC3X_ADC_REG17:
case TLV320AIC3X_ADC_REG18:
case TLV320AIC3X_ADC_REG19:
case TLV320AIC3X_ADC_REG1A:
case TLV320AIC3X_ADC_REG1B:
case TLV320AIC3X_ADC_REG1C:
case TLV320AIC3X_ADC_REG1E:
case TLV320AIC3X_DAC_REG31:
case TLV320AIC3X_DAC_REG32:
case TLV320AIC3X_DAC_REG33:
case TLV320AIC3X_PRIV_INDEX:
case TLV320AIC3X_PRIV_DATA:
case TLV320AIC3X_DAC_REG34:
case TLV320AIC3X_DAC_REG35:
case TLV320AIC3X_DAC_REG37:
case TLV320AIC3X_GPIO_REG44:
case TLV320AIC3X_GP_REG45:
case TLV320AIC3X_CHD1_REGFD:
case TLV320AIC3X_CHD2_REGFE:
case TLV320AIC3X_CHVER_REGFF:
return 1;
default:
return 0;
}
}
/******************************************************************************
* Function : tlv320aic3x_reg_read
*******************************************************************************
*
* Description :
*
* Parameters : char RegAddr
* Parameters : unsigned short *value
*
* Output Param : None.
*
* Return value :
*
* Notes :
*******************************************************************************/
static int tlv320aic3x_reg_read(struct i2c_client *client, unsigned char reg)
{
unsigned char data[1] = {0};
int value = 0x0;
data[0] = reg & 0xFF;
if (data[0] > 0x00)
{
data[0] -= 1;
}
if(i2c_master_send(client, data, 1) == 1) {
i2c_master_recv(client, data, 1);
value = data[0];
#ifdef TLV320AIC3X_DEBUG
printk(KERN_INFO"%s: tlv320aic3x read reg:[0x%02x]=0x%02x\n", __FUNCTION__, reg, value);
#endif
return value;
} else {
printk(KERN_INFO"%s: tlv320aic3x read failed.\n", __FUNCTION__);
return -EIO;
}
}
static int tlv320aic3x_read(unsigned char reg, unsigned short *oValue)
{
int value;
value = tlv320aic3x_reg_read(g_tlv320aic3x_client, reg);
if (value < 0)
{
printk(KERN_INFO"%s: tlv320aic3x_reg read failed.\n", __FUNCTION__);
*oValue = 0x00;
return -EIO;
}
*oValue = value & 0xFF;
return 0;
}
/******************************************************************************
* Function : tlv320aic3x_write
*******************************************************************************
*
* Description :
*
* Parameters : char RegAddr
* Parameters : unsigned short RegData
*
* Output Param : None.
*
* Return value :
*
* Notes :
*******************************************************************************/
static int tlv320aic3x_reg_write(struct i2c_client *client, char reg, unsigned short value)
{
char data[3] = {0};
data[0] = reg & 0xFF;
// data[1] = (char)((value >> 8) & 0xFF);
data[1] = (char)(value & 0xFF);
if (i2c_master_send(client, data, 2) == 2) {
#ifdef TLV320AIC3X_DEBUG
printk(KERN_INFO"%s=> reg:0x%02x,value:0x%02x success\n", __FUNCTION__, reg, value);
#endif
return 0;
} else {
printk(KERN_INFO"%s=> reg:0x%02x,value:0x%02x error\n", __FUNCTION__, reg, value);
return -1;
}
}
static int tlv320aic3x_write(unsigned char reg, unsigned short value)
{
int ret;
#ifdef TLV320AIC3X_DEBUG_CLOSE
unsigned short read_value;
#endif
ret = tlv320aic3x_reg_write(g_tlv320aic3x_client, reg, value);
if (ret < 0)
{
printk(KERN_INFO"%s:L%d: tlv320aic3x_write() error.\n", __FUNCTION__, __LINE__);
}
#ifdef TLV320AIC3X_DEBUG_CLOSE
//for check whether write is OK or not.
ret = tlv320aic3x_read(reg, &read_value);
if (ret < 0)
{
printk(KERN_INFO"%s:L%d: tlv320aic3x_read() error.\n", __FUNCTION__, __LINE__);
}
printk(KERN_INFO"%s:L%d: reg=0x%02x, value=0x%04x, read_value=0x%04x. Please check it:%s.\n",
__FUNCTION__, __LINE__, reg, value, read_value, (value == read_value)?"OK":"FAIL");
#endif
return ret;
}
static int tlv320aic3x_update_bit(unsigned char reg, unsigned short mask, unsigned short value)
{
int status = 0;
unsigned short orig = 0;
unsigned short tmp = 0;
status = tlv320aic3x_read(reg, &orig);
if (status < 0)
{
printk(KERN_INFO"%s:L%d: tlv320aic3x_read() error.\n", __FUNCTION__, __LINE__);
return status;
}
else
{
tmp = orig & (~mask);
tmp |= (value & mask);
if (tmp != orig)
{
status = tlv320aic3x_write(reg, tmp);
if (status < 0)
{
printk(KERN_INFO"%s:L%d: tlv320aic3x_write() error.\n", __FUNCTION__, __LINE__);
return status;
}
}
}
#ifdef TLV320AIC3X_DEBUG_CLOSE
printk(KERN_INFO"%s:L%d: reg=0x%02x, mask=0x%02x, value=0x%04x, orig=0x%04x, last_value=0x%04x, please check it:%s.\n",
__FUNCTION__, __LINE__, reg, mask, value, orig, tmp, (orig == tmp)?"EQUAL":"UNEQUAL");
#endif
return status;
}
static int tlv320aic3x_index_read(unsigned char RegAddr, unsigned short *value)
{
int status = -1;
status = tlv320aic3x_write(TLV320AIC3X_PRIV_INDEX, RegAddr);
if (status != 0)
{
printk(KERN_INFO"status: %d, RegAddr: 0x%04x\n", status, RegAddr);
return status;
}
status = tlv320aic3x_read(TLV320AIC3X_PRIV_DATA, value);
if (status != 0)
{
printk(KERN_INFO"status: %d, RegAddr: 0x%04x\n", status, RegAddr);
return status;
}
return status;
}
static int tlv320aic3x_index_write(char RegAddr, unsigned short value)
{
int status = -1;
status = tlv320aic3x_write(TLV320AIC3X_PRIV_INDEX, RegAddr);
if (status != 0)
{
printk(KERN_INFO"status: %d, RegAddr: 0x%04x\n", status, RegAddr);
return status;
}
status = tlv320aic3x_write(TLV320AIC3X_PRIV_DATA, value);
if (status != 0)
{
printk(KERN_INFO"status: %d, RegAddr: 0x%04x\n", status, RegAddr);
return status;
}
return status;
}
static int tlv320aic3x_index_update_bits(char RegAddr, unsigned short mask, unsigned short value)
{
int status = -1;
unsigned short orig;
unsigned short tmp;
status = tlv320aic3x_index_read(RegAddr, &orig);
if (status != 0)
{
printk(KERN_INFO"status: %d, RegAddr: 0x%04x\n", status, RegAddr);
}
else
{
tmp = orig & (~mask);
tmp |= (value & mask);;
if (tmp != orig)
{
status = tlv320aic3x_index_write(RegAddr, tmp);
if (status != 0)
{
printk(KERN_INFO"status: %d, RegAddr: 0x%04x\n", status, RegAddr);
}
}
}
return status;
}
#define TLV320AIC3X_STATE_OFF 0x00
static char tlv320aic3x_init_ok = 0;
static char connect_TLV320AIC3X = 0;
static char TLV320AIC3X_work_state = TLV320AIC3X_STATE_OFF;
static char l_connect_tlv320aic3x = 0;
int tlv320aic3x_is_connect(void)
{
return l_connect_tlv320aic3x;
}
int codec_tlv320aic3x_init(void)
{
static char tlv320aic3x_init_ok = 0;
short value = 0;
if(0 == tlv320aic3x_init_ok){
//codec_tlv320aic3x_enable_mfpr();
/* check if has codec tlv320aic3x*/
tlv320aic3x_read(0xFE, &value);
if (0x10EC == value) {
tlv320aic3x_write(0x00, 0x00);
tlv320aic3x_init_ok = 1;
l_connect_tlv320aic3x = 1;
tlv320aic3x_init_ok = 1;
connect_TLV320AIC3X = 1;
}
}
printk(KERN_INFO"%s:L%d: tlv320aic3x_init_ok=%d, l_connect_tlv320aic3x =%d.\n",
__FUNCTION__, __LINE__, tlv320aic3x_init_ok, l_connect_tlv320aic3x);
return !tlv320aic3x_init_ok;
}
static int g_tlv320aic3x_mclk_type = 1; /* 0: use bitclk, 1: use i2s_mclk, 2, use bitclk and turn on i2s_mclk */
static int g_tlv320aic3xmainmic_type = 0; /* 0: differential mode, 1: single mode */
/***********************************************************************
INTCBind() could only use one lisr for ***all*** GPIOs,
So, headset detection is disabled by default on ASR1802S EVB.
So, we need to set g_tlv320aic3xheadset_plugged=1 by default;
thus user just need to plugin headset and no other operation/command is needed.
************************************************************************/
static int g_tlv320aic3xheadset_plugged = 1; /* 0: headset plug out, 1: headset plug in */
static int g_tlv320aic3xheadset_mic = 0; /* 0: without HS_MIC, 1: with HS_MIC */
/***********************************************************************
When we enable headset detection, could not power off codec
i.e could not call codec_tlv320aic3x_power_on/codec_tlv320aic3x_power_off
************************************************************************/
int g_tlv320aic3xheadset_detection_enabled = 0; /* 0: disable, 1: enable */
#define is_speaker_on() (TLV320AIC3X_work_state & 0x01)
#define is_headphone_on() (TLV320AIC3X_work_state & 0x02)
#define is_main_mic_on() (TLV320AIC3X_work_state & 0x04)
#define is_headset_mic_on() (TLV320AIC3X_work_state & 0x08)
struct reg_value_group {
char reg;
unsigned short mask;
unsigned short value;
};
void disable_tlv320aic3x_MClock(void);
void enable_tlv320aic3x_MClock(void);
static int disableTLV320AIC3X = 0;
static int disableTLV320AIC3XHsMic = 0;
void disableCodecTLV320AIC3X(void)
{
disableTLV320AIC3X = 1;
}
static int disableTLV320AIC3XDefaultPower = 0;
void disableCodecTLV320AIC3XPower(void)
{
disableTLV320AIC3XDefaultPower = 1;
}
void disableCodecTLV320AIC3XHsMic(void)
{
disableTLV320AIC3XHsMic = 1;
}
int codec_tlv320aic3x_is_connect(void)
{
return connect_TLV320AIC3X;
}
static void TLV320AIC3X_set_work_state(char device, char onoff)
{
if (device == TLV320AIC3X_OUTPUT_DEVICE_SPEAKER)
{
if (onoff == TLV320AIC3X_DEVICE_OFF)
{
TLV320AIC3X_work_state &= 0xFE;
}
else if (onoff == TLV320AIC3X_DEVICE_ON)
{
TLV320AIC3X_work_state |= 0x01;
}
}
else if (device == TLV320AIC3X_OUTPUT_DEVICE_HEADPHONE)
{
if (onoff == TLV320AIC3X_DEVICE_OFF)
{
TLV320AIC3X_work_state &= 0xFD;
}
else if (onoff == TLV320AIC3X_DEVICE_ON)
{
TLV320AIC3X_work_state |= 0x02;
}
}
else if (device == TLV320AIC3X_INPUT_DEVICE_MAIN_MIC)
{
if (onoff == TLV320AIC3X_DEVICE_OFF)
{
TLV320AIC3X_work_state &= 0xFB;
}
else if (onoff == TLV320AIC3X_DEVICE_ON)
{
TLV320AIC3X_work_state |= 0x04;
}
}
else if (device == TLV320AIC3X_INPUT_DEVICE_HEADSET_MIC)
{
if (onoff == TLV320AIC3X_DEVICE_OFF)
{
TLV320AIC3X_work_state &= 0xF7;
}
else if (onoff == TLV320AIC3X_DEVICE_ON)
{
TLV320AIC3X_work_state |= 0x08;
}
}
}
/* audio control functions */
static void tlv320aic3x_speaker_on(void)
{
#if 1
tlv320aic3x_index_write(0x3D, 0x3600); /*DAC Clock1 Generator Enable*/
tlv320aic3x_write(0x63, 0xf8de); /*LOUTMIX Power On*/
tlv320aic3x_write(0x61, 0x9804); /*DACL1 Power On*/
tlv320aic3x_write(0x62, 0x8800); /*Stereo1 DAC Digital Filter Power On*/
tlv320aic3x_write(0x65, 0xc800); /*OUTMIXL Power On*/
tlv320aic3x_write(0x66, 0x3000); /*OUTVOLL Power On*/
tlv320aic3x_write(0x8F, 0x3100); /*HP Deop Mode mode 2*/
tlv320aic3x_write(0x2A, 0x1250); /*DACL1 to Stereo DAC left Mixer*/
tlv320aic3x_write(0x4F, 0x0278); /*DACL1 to OUTMIXL*/
tlv320aic3x_write(0x52, 0x0278); /*DACR1 to OUTMIXR*/
tlv320aic3x_write(0x53, 0xc000); /*OUTVOLL to LOUTMIX Unmute*/
tlv320aic3x_write(0x03, 0x0808); /*LOUTL Unmute*/
tlv320aic3x_write(0x73, 0x0102); /*Stereo DAC sample Rate 128 FS*/
tlv320aic3x_write(0x05, 0x8000); /*enable Differential Line Output*/
#else
tlv320aic3x_index_update_bits(0x3D, 1 << 10, 1 << 10); /*DAC Clock1 Generator Enable*/
tlv320aic3x_index_update_bits(0x3D, 1 << 9, 1 << 9); /*DAC Clock2 Generator Enable*/
tlv320aic3x_update_bit(0x63, 1 << 12, 1 << 12); /*LOUTMIX Power On*/
tlv320aic3x_update_bit(0x61, 1 << 12, 1 << 12); /*DACL1 Power On*/
tlv320aic3x_update_bit(0x61, 1 << 11, 1 << 11); /*DACR1 Power On*/
tlv320aic3x_update_bit(0x62, 1 << 11, 1 << 11); /*Stereo1 DAC Digital Filter Power On*/
tlv320aic3x_update_bit(0x65, 1 << 15, 1 << 15); /*OUTMIXL Power On*/
tlv320aic3x_update_bit(0x65, 1 << 14, 1 << 14); /*OUTMIXR Power On*/
tlv320aic3x_update_bit(0x66, 1 << 13, 1 << 13); /*OUTVOLL Power On*/
tlv320aic3x_update_bit(0x66, 1 << 12, 1 << 12); /*OUTVOLR Power On*/
tlv320aic3x_update_bit(0x8F, 1 << 13, 1 << 13); /*HP Deop Mode mode 2*/
tlv320aic3x_update_bit(0x2A, 1 << 14, 0); /*DACL1 to Stereo DAC left Mixer*/
tlv320aic3x_update_bit(0x2A, 1 << 1, 0); /*DACL1 to Stereo DAC Right Mixer*/
tlv320aic3x_update_bit(0x4F, 1, 0); /*DACL1 to OUTMIXL*/
tlv320aic3x_update_bit(0x52, 1, 0); /*DACR1 to OUTMIXR*/
tlv320aic3x_update_bit(0x53, 1 << 13, 0); /*OUTVOLL to LOUTMIX Unmute*/
tlv320aic3x_update_bit(0x53, 1 << 12, 0); /*OUTVOLR to LOUTMIX Unmute*/
tlv320aic3x_update_bit(0x03, 1 << 15, 0); /*LOUTL Unmute*/
tlv320aic3x_update_bit(0x03, 1 << 14, 0); /*OUTVOLL Unmute*/
tlv320aic3x_update_bit(0x03, 1 << 7, 0); /*LOUTR Unmute*/
tlv320aic3x_update_bit(0x03, 1 << 6, 0); /*OUTVOLR Unmute*/
tlv320aic3x_update_bit(0x73, 3 << 2, 0 << 2); /*Stereo DAC sample Rate 128 FS*/
tlv320aic3x_update_bit(0x05, 1 << 15, 1 << 15); /*enable Differential Line Output*/
#endif
}
static void tlv320aic3x_speaker_off(void)
{
#if 1
tlv320aic3x_index_write(0x3D, 0x2000); /*DAC Clock1 Generator Enable*/
tlv320aic3x_write(0x63, 0xe8de); /*LOUTMIX Power Off*/
tlv320aic3x_write(0x61, 0x8000); /*DACL1 Power On*/
tlv320aic3x_write(0x62, 0x0000); /*Stereo1 DAC Digital Filter Power On*/
tlv320aic3x_write(0x65, 0x0000); /*OUTMIXL Power On*/
tlv320aic3x_write(0x66, 0x0000); /*OUTVOLL Power On*/
tlv320aic3x_write(0x8F, 0x1100); /*HP Deop Mode mode 2*/
tlv320aic3x_write(0x2A, 0x5250); /*DACL1 to Stereo DAC left Mixer*/
tlv320aic3x_write(0x4F, 0x0279); /*DACL1 to OUTMIXL*/
tlv320aic3x_write(0x52, 0x0279); /*DACR1 to OUTMIXR*/
tlv320aic3x_write(0x53, 0xf000); /*OUTVOLL to LOUTMIX Unmute*/
tlv320aic3x_write(0x03, 0xc8c8); /*LOUTL Unmute*/
tlv320aic3x_write(0x73, 0x0102); /*Stereo DAC sample Rate 128 FS*/
tlv320aic3x_write(0x05, 0x0000); /*disable Differential Line Output*/
#else
tlv320aic3x_index_update_bits(0x3D, 1 << 10, 0); /*DAC Clock1 Generator Enable*/
tlv320aic3x_index_update_bits(0x3D, 1 << 9, 0); /*DAC Clock2 Generator Enable*/
tlv320aic3x_update_bit(0x63, 1 << 12, 0); /*LOUTMIX Power Off*/
tlv320aic3x_update_bit(0x61, 1 << 12, 0); /*DACL1 Power On*/
tlv320aic3x_update_bit(0x61, 1 << 11, 0); /*DACR1 Power On*/
tlv320aic3x_update_bit(0x62, 1 << 11, 0); /*Stereo1 DAC Digital Filter Power On*/
tlv320aic3x_update_bit(0x65, 1 << 15, 0); /*OUTMIXL Power On*/
tlv320aic3x_update_bit(0x65, 1 << 14, 0); /*OUTMIXR Power On*/
tlv320aic3x_update_bit(0x66, 1 << 13, 0); /*OUTVOLL Power On*/
tlv320aic3x_update_bit(0x66, 1 << 12, 0); /*OUTVOLR Power On*/
tlv320aic3x_update_bit(0x8F, 1 << 13, 0); /*HP Deop Mode mode 2*/
tlv320aic3x_update_bit(0x2A, 1 << 14, 1 << 14); /*DACL1 to Stereo DAC left Mixer*/
tlv320aic3x_update_bit(0x2A, 1 << 6, 1 << 6); /*DACR1 to Stereo DAC Right Mixer*/
tlv320aic3x_update_bit(0x4F, 1, 1); /*DACL1 to OUTMIXL*/
tlv320aic3x_update_bit(0x52, 1, 1); /*DACR1 to OUTMIXR*/
tlv320aic3x_update_bit(0x53, 1 << 13, 1 << 13); /*OUTVOLL to LOUTMIX Unmute*/
tlv320aic3x_update_bit(0x53, 1 << 12, 1 << 12); /*OUTVOLR to LOUTMIX Unmute*/
tlv320aic3x_update_bit(0x03, 1 << 15, 1 << 15); /*LOUTL Unmute*/
tlv320aic3x_update_bit(0x03, 1 << 14, 1 << 14); /*OUTVOLL Unmute*/
tlv320aic3x_update_bit(0x03, 1 << 7, 1 << 7); /*LOUTR Unmute*/
tlv320aic3x_update_bit(0x03, 1 << 6, 1 << 6); /*OUTVOLR Unmute*/
tlv320aic3x_update_bit(0x73, 3 << 2, 0 << 2); /*Stereo DAC sample Rate 128 FS*/
tlv320aic3x_update_bit(0x05, 1 << 15, 0 << 15); /*disable Differential Line Output*/
#endif
}
static void tlv320aic3x_headphone_on(void)
{
#if 1
tlv320aic3x_index_write(0x3D, 0x3600); /*DAC Clock1 Generator Enable*/
tlv320aic3x_write(0x61, 0x9804); /*DACL1 Power On*/
tlv320aic3x_write(0x62, 0x8800); /*Stereo1 DAC Digital Filter Power On*/
tlv320aic3x_write(0x65, 0xcc00); /*OUTMIXL Power On*/
tlv320aic3x_write(0x66, 0x0c00); /*HPOVOLL Power On*/
tlv320aic3x_write(0x8E, 0x001d); /*Enable Headphone Output*/
tlv320aic3x_write(0x8F, 0x3100); /*HP Deop Mode mode 2*/
tlv320aic3x_write(0x2A, 0x1250); /*DACL1 to Stereo DAC left Mixer*/
tlv320aic3x_write(0x4F, 0x0278); /*DACL1 to OUTMIXL*/
tlv320aic3x_write(0x52, 0x0278); /*DACR1 to OUTMIXR*/
tlv320aic3x_write(0x45, 0x5000); /*HPOVOL to HPOMIX Unmute*/
tlv320aic3x_write(0x02, 0x0808); /*HPOL UnMute*/
tlv320aic3x_write(0x73, 0x0102); /*Stereo DAC sample Rate 128 FS*/
#else
tlv320aic3x_index_update_bits(0x3D, 1 << 10, 1 << 10); /*DAC Clock1 Generator Enable*/
tlv320aic3x_index_update_bits(0x3D, 1 << 9, 1 << 9); /*DAC Clock2 Generator Enable*/
tlv320aic3x_update_bit(0x61, 1 << 12, 1 << 12); /*DACL1 Power On*/
tlv320aic3x_update_bit(0x61, 1 << 11, 1 << 11); /*DACR1 Power On*/
tlv320aic3x_update_bit(0x62, 1 << 11, 1 << 11); /*Stereo1 DAC Digital Filter Power On*/
tlv320aic3x_update_bit(0x65, 1 << 15, 1 << 15); /*OUTMIXL Power On*/
tlv320aic3x_update_bit(0x65, 1 << 14, 1 << 14); /*OUTMIXR Power On*/
tlv320aic3x_update_bit(0x66, 1 << 11, 1 << 11); /*HPOVOLL Power On*/
tlv320aic3x_update_bit(0x66, 1 << 10, 1 << 10); /*HPOVOLR Power On*/
tlv320aic3x_update_bit(0x8E, 1 << 4, 1 << 4); /*Enable Headphone Output*/
tlv320aic3x_update_bit(0x8E, 1, 1); /*HP Amp All Power On*/
tlv320aic3x_update_bit(0x8F, 1 << 13, 1 << 13); /*HP Deop Mode mode 2*/
tlv320aic3x_update_bit(0x2A, 1 << 14, 0); /*DACL1 to Stereo DAC left Mixer*/
tlv320aic3x_update_bit(0x2A, 1 << 1, 0); /*DACL1 to Stereo DAC Right Mixer*/
tlv320aic3x_update_bit(0x4F, 1, 0); /*DACL1 to OUTMIXL*/
tlv320aic3x_update_bit(0x52, 1, 0); /*DACR1 to OUTMIXR*/
tlv320aic3x_update_bit(0x45, 1 << 13, 0); /*HPOVOL to HPOMIX Unmute*/
tlv320aic3x_update_bit(0x02, 1 << 15, 0); /*HPOL UnMute*/
tlv320aic3x_update_bit(0x02, 1 << 14, 0); /*HPOVOLL Unmute*/
tlv320aic3x_update_bit(0x02, 1 << 7, 0); /*HPOR UnMute*/
tlv320aic3x_update_bit(0x02, 1 << 6, 0); /*HPOVOLR Unmute*/
tlv320aic3x_update_bit(0x73, 3 << 2, 0 << 2); /*Stereo DAC sample Rate 128 FS*/
#endif
}
static void tlv320aic3x_headphone_off(void)
{
#if 1
tlv320aic3x_index_write(0x3D, 0x2000); /*DAC Clock1 Generator Enable*/
tlv320aic3x_write(0x61, 0x8000); /*DACL1 Power On*/
tlv320aic3x_write(0x62, 0x0000); /*Stereo1 DAC Digital Filter Power On*/
tlv320aic3x_write(0x65, 0x0000); /*OUTMIXL Power On*/
tlv320aic3x_write(0x66, 0x0000); /*HPOVOLL Power On*/
tlv320aic3x_write(0x8E, 0x000c); /*Enable Headphone Output*/
tlv320aic3x_write(0x8F, 0x1100); /*HP Deop Mode mode 2*/
tlv320aic3x_write(0x2A, 0x5252); /*DACR1 to Stereo DAC left Mixer*/
tlv320aic3x_write(0x4F, 0x0279); /*DACL1 to OUTMIXL*/
tlv320aic3x_write(0x52, 0x0279); /*DACR1 to OUTMIXR*/
tlv320aic3x_write(0x45, 0x7000); /*HPOVOL to HPOMIX Unmute*/
tlv320aic3x_write(0x02, 0xc8c8); /*HPOL UnMute*/
tlv320aic3x_write(0x73, 0x0102); /*Stereo DAC sample Rate 128 FS*/
#else
tlv320aic3x_index_update_bits(0x3D, 1 << 10, 0); /*DAC Clock1 Generator Enable*/
tlv320aic3x_index_update_bits(0x3D, 1 << 9, 0); /*DAC Clock2 Generator Enable*/
tlv320aic3x_update_bit(0x61, 1 << 12, 0); /*DACL1 Power On*/
tlv320aic3x_update_bit(0x61, 1 << 11, 0); /*DACR1 Power On*/
tlv320aic3x_update_bit(0x62, 1 << 11, 0); /*Stereo1 DAC Digital Filter Power On*/
tlv320aic3x_update_bit(0x65, 1 << 15, 0); /*OUTMIXL Power On*/
tlv320aic3x_update_bit(0x65, 1 << 14, 0); /*OUTMIXR Power On*/
tlv320aic3x_update_bit(0x66, 1 << 11, 0); /*HPOVOLL Power On*/
tlv320aic3x_update_bit(0x66, 1 << 10, 0); /*HPOVOLR Power On*/
tlv320aic3x_update_bit(0x8E, 1 << 4, 0); /*Enable Headphone Output*/
tlv320aic3x_update_bit(0x8E, 1, 0); /*HP Amp All Power On*/
tlv320aic3x_update_bit(0x8F, 1 << 13, 0); /*HP Deop Mode mode 2*/
tlv320aic3x_update_bit(0x2A, 1 << 14, 1 << 14); /*DACR1 to Stereo DAC left Mixer*/
tlv320aic3x_update_bit(0x2A, 1 << 1, 1 << 1); /*DACL1 to Stereo DAC Right Mixer*/
tlv320aic3x_update_bit(0x4F, 1, 1); /*DACL1 to OUTMIXL*/
tlv320aic3x_update_bit(0x52, 1, 1); /*DACR1 to OUTMIXR*/
tlv320aic3x_update_bit(0x45, 1 << 13, 1 << 13); /*HPOVOL to HPOMIX Unmute*/
tlv320aic3x_update_bit(0x02, 1 << 15, 1 << 15); /*HPOL UnMute*/
tlv320aic3x_update_bit(0x02, 1 << 14, 1 << 14); /*HPOVOLL Unmute*/
tlv320aic3x_update_bit(0x02, 1 << 7, 1 << 7); /*HPOR UnMute*/
tlv320aic3x_update_bit(0x02, 1 << 6, 1 << 6); /*HPOVOLR Unmute*/
tlv320aic3x_update_bit(0x73, 3 << 2, 0 << 2); /*Stereo DAC sample Rate 128 FS*/
#endif
}
static void tlv320aic3x_main_mic_on(void)
{
#if 1
tlv320aic3x_index_write(0x3D, 0x3600); /*ADC Clock Genaral Enable*/
tlv320aic3x_write(0x65, 0xc800); /*RECMIXL Power On*/
tlv320aic3x_write(0x61, 0x9804); /*ADCL Power On*/
tlv320aic3x_write(0x62, 0x8800); /*Stereo ADC Digital Filter Power On*/
tlv320aic3x_write(0x64, 0x4a00); /*BST2 Power On*/
tlv320aic3x_write(0x0D, 0x0540); /*IN2 Boost Control +40dB*/
tlv320aic3x_write(0x73, 0x0102); /*Stereo ADC Over Sample Rate 32 Fs*/
tlv320aic3x_write(0x3C, 0x006b); /*BST2 to RECMIXL Unmute*/
tlv320aic3x_write(0x3E, 0x006b); /*BST1 to RECMIXR Unmute*/
tlv320aic3x_write(0x27, 0x3860); /*Stereo ADC1 Left Channel Unmute*/
#else
tlv320aic3x_index_update_bits(0x3D, 1 << 12, 1 << 12); /*ADC Clock Genaral Enable*/
tlv320aic3x_update_bit(0x65, 1 << 11, 1 << 11); /*RECMIXL Power On*/
tlv320aic3x_update_bit(0x61, 1 << 2, 1 << 2); /*ADCL Power On*/
tlv320aic3x_update_bit(0x62, 1 << 15, 1 << 15); /*Stereo ADC Digital Filter Power On*/
tlv320aic3x_update_bit(0x64, 1 << 14, 1 << 14); /*BST2 Power On*/
tlv320aic3x_update_bit(0x0D, 0xF << 8, 5 << 8); /*IN2 Boost Control +40dB*/
tlv320aic3x_update_bit(0x0D, 1 << 6, 1 << 6); /*IN2 Differential Mode*/
tlv320aic3x_update_bit(0x73, 3, 2); /*Stereo ADC Over Sample Rate 32 Fs*/
tlv320aic3x_update_bit(0x3C, 1 << 2, 0); /*BST2 to RECMIXL Unmute*/
tlv320aic3x_update_bit(0x3E, 1 << 2, 0); /*BST1 to RECMIXR Unmute*/
tlv320aic3x_update_bit(0x27, 1 << 14, 0); /*Stereo ADC1 Left Channel Unmute*/
#endif
}
static void tlv320aic3x_main_mic_off(void)
{
#if 1
tlv320aic3x_index_write(0x3D, 0x2000); /*ADC Clock Genaral Enable*/
tlv320aic3x_write(0x65, 0x0000); /*RECMIXL Power On*/
tlv320aic3x_write(0x61, 0x8000); /*ADCL Power On*/
tlv320aic3x_write(0x62, 0x0000); /*Stereo ADC Digital Filter Power On*/
tlv320aic3x_write(0x64, 0x0a00); /*BST2 Power On*/
tlv320aic3x_write(0x0D, 0x0000); /*IN2 Boost Control +40dB*/
tlv320aic3x_write(0x73, 0x0102); /*Stereo ADC Over Sample Rate 128 Fs*/
tlv320aic3x_write(0x3C, 0x006f); /*BST2 to RECMIXL Unmute*/
tlv320aic3x_write(0x3E, 0x006f); /*BST2 to RECMIXL Unmute*/
tlv320aic3x_write(0x27, 0x7860); /*Stereo ADC1 Left Channel Unmute*/
#else
tlv320aic3x_index_update_bits(0x3D, 1 << 12, 0); /*ADC Clock Genaral Enable*/
tlv320aic3x_update_bit(0x65, 1 << 11, 0); /*RECMIXL Power On*/
tlv320aic3x_update_bit(0x61, 1 << 2, 0); /*ADCL Power On*/
tlv320aic3x_update_bit(0x62, 1 << 15, 0); /*Stereo ADC Digital Filter Power On*/
tlv320aic3x_update_bit(0x64, 1 << 14, 0); /*BST2 Power On*/
tlv320aic3x_update_bit(0x0D, 0xF << 8, 0); /*IN2 Boost Control +40dB*/
tlv320aic3x_update_bit(0x0D, 1 << 6, 0); /*IN2 Differential Mode*/
tlv320aic3x_update_bit(0x73, 3, 2); /*Stereo ADC Over Sample Rate 128 Fs*/
tlv320aic3x_update_bit(0x3C, 1 << 2, 1 << 2); /*BST2 to RECMIXL Unmute*/
tlv320aic3x_update_bit(0x3E, 1 << 2, 1 << 2); /*BST2 to RECMIXL Unmute*/
tlv320aic3x_update_bit(0x27, 1 << 14, 1 << 14); /*Stereo ADC1 Left Channel Unmute*/
#endif
}
static void tlv320aic3x_headset_mic_on(void)
{
#if 1
tlv320aic3x_index_write(0x3D, 0x3600); /*ADC Clock Genaral Enable*/
tlv320aic3x_write(0x65, 0xcc00); /*RECMIXL Power On*/
tlv320aic3x_write(0x61, 0x9804); /*ADCL Power On*/
tlv320aic3x_write(0x62, 0x8800); /*Stereo ADC Digital Filter Power On*/
tlv320aic3x_write(0x0D, 0x5000); /*IN1 Boost Control +40dB*/
tlv320aic3x_write(0x64, 0x4a04); /*BST1 Power On*/
tlv320aic3x_write(0x73, 0x0102); /*Stereo ADC Over Sample Rate 128 Fs*/
tlv320aic3x_write(0x3C, 0x006D); /*BST1 to RECMIXL Unmute*/
tlv320aic3x_write(0x3E, 0x006D); /*BST1 to RECMIXR Unmute*/
tlv320aic3x_write(0x27, 0x3820); /*Stereo ADC1 Left Channel Unmute*/
#else
tlv320aic3x_index_update_bits(0x3D, 1 << 12, 1 << 12); /*ADC Clock Genaral Enable*/
tlv320aic3x_update_bit(0x65, 1 << 11, 1 << 11); /*RECMIXL Power On*/
tlv320aic3x_update_bit(0x65, 1 << 10, 1 << 10); /*RECMIXR Power On*/
tlv320aic3x_update_bit(0x61, 1 << 2, 1 << 2); /*ADCL Power On*/
tlv320aic3x_update_bit(0x61, 1 << 1, 1 << 1); /*ADCR Power On*/
tlv320aic3x_update_bit(0x62, 1 << 15, 1 << 15); /*Stereo ADC Digital Filter Power On*/
tlv320aic3x_update_bit(0x0D, 0xF << 12, 5 << 12); /*IN1 Boost Control +40dB*/
tlv320aic3x_update_bit(0x64, 1 << 15, 0 << 15); /*BST1 Power On*/
tlv320aic3x_update_bit(0x64, 1 << 4, 1 << 4); /*MIC2 SE Mode single-end mode*/
tlv320aic3x_update_bit(0x73, 3, 2); /*Stereo ADC Over Sample Rate 128 Fs*/
tlv320aic3x_update_bit(0x3C, 1 << 1, 0); /*BST1 to RECMIXL Unmute*/
tlv320aic3x_update_bit(0x3E, 1 << 1, 0); /*BST1 to RECMIXR Unmute*/
tlv320aic3x_update_bit(0x27, 1 << 14, 0); /*Stereo ADC1 Left Channel Unmute*/
tlv320aic3x_update_bit(0x27, 1 << 6, 0); /*Stereo ADC1 Right Channel Unmute*/
#endif
}
static void tlv320aic3x_headset_mic_off(void)
{
#if 1
tlv320aic3x_index_write(0x3D, 0x2000); /*ADC Clock Genaral Enable*/
tlv320aic3x_write(0x65, 0x0000); /*recmixl power on*/
tlv320aic3x_write(0x61, 0x8000); /*adcl power on*/
tlv320aic3x_write(0x62, 0x0000); /*stereo adc digital filter power on*/
tlv320aic3x_write(0x0d, 0x0540); /*in1 boost control +40db*/
tlv320aic3x_write(0x64, 0x4a00); /*bst1 power on*/
tlv320aic3x_write(0x73, 0x0102); /*stereo adc over sample rate 128 fs*/
tlv320aic3x_write(0x3c, 0x006b); /*bst1 to recmixl unmute*/
tlv320aic3x_write(0x3e, 0x006b); /*bst1 to recmixr unmute*/
tlv320aic3x_write(0x27, 0x7860); /*stereo adc1 left channel unmute*/
#else
tlv320aic3x_index_update_bits(0x3D, 1 << 12, 0); /*ADC Clock Genaral Enable*/
tlv320aic3x_update_bit(0x65, 1 << 11, 0); /*RECMIXL Power On*/
tlv320aic3x_update_bit(0x65, 1 << 10, 0); /*RECMIXR Power On*/
tlv320aic3x_update_bit(0x61, 1 << 2, 0); /*ADCL Power On*/
tlv320aic3x_update_bit(0x61, 1 << 1, 0); /*ADCR Power On*/
tlv320aic3x_update_bit(0x62, 1 << 15, 0); /*Stereo ADC Digital Filter Power On*/
tlv320aic3x_update_bit(0x0D, 0xF << 12, 0); /*IN1 Boost Control +40dB*/
tlv320aic3x_update_bit(0x64, 1 << 15, 0); /*BST1 Power On*/
tlv320aic3x_update_bit(0x64, 1 << 4, 0); /*MIC2 SE Mode single-end mode*/
tlv320aic3x_update_bit(0x73, 3, 2); /*Stereo ADC Over Sample Rate 128 Fs*/
tlv320aic3x_update_bit(0x3C, 1 << 1, 1 << 1); /*BST1 to RECMIXL Unmute*/
tlv320aic3x_update_bit(0x3E, 1 << 1, 1 << 1); /*BST1 to RECMIXR Unmute*/
tlv320aic3x_update_bit(0x27, 1 << 14, 1 << 14); /*Stereo ADC1 Left Channel Unmute*/
tlv320aic3x_update_bit(0x27, 1 << 6, 1 << 6); /*Stereo ADC1 Right Channel Unmute*/
#endif
}
void tlv320aic3x_mute_mic(int mute)
{
#if 1
if (mute) {
tlv320aic3x_write(0x1c, 0xafaf);
} else {
tlv320aic3x_write(0x1c, 0x2f2f);
}
#else
if (mute) {
tlv320aic3x_update_bit(0x1c, (1 << 15), (1 << 15));
tlv320aic3x_update_bit(0x1c, (1 << 7), (1 << 7));
} else {
tlv320aic3x_update_bit(0x1c, (1 << 15), (0 << 15));
tlv320aic3x_update_bit(0x1c, (1 << 7), (0 << 7));
}
#endif
return;
}
/*volume level: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 */
int gain_output_ctrl[11] = { 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00};
int gain_digital_vol[11] = { 0xAFAF, 0xB7B7, 0xBFBF, 0xC7C7, 0xCFCF, 0xD7D7, 0xDDDD, 0xE5E5, 0xEDED, 0xF5F5, 0xFFFF};
void tlv320aic3x_adjust_gain(int gain)
{
/* gain is within 0~10 */
#if 1
tlv320aic3x_update_bit(0x02, (0x3F << 8), (gain_output_ctrl[gain] << 8));/* Headphone output control */
tlv320aic3x_update_bit(0x02, (0x3F << 0), (gain_output_ctrl[gain] << 0));
tlv320aic3x_update_bit(0x03, (0x3F << 8), (gain_output_ctrl[gain] << 8));/* Line Output Control 1 */
tlv320aic3x_update_bit(0x03, (0x3F << 0), (gain_output_ctrl[gain] << 0));
tlv320aic3x_write(0x19, gain_digital_vol[gain]); /* DACL1/R1 Digital Volume */
#else
tlv320aic3x_update_bit(0x02, (0x3F << 8), (gain_output_ctrl[gain] << 8));/* Headphone output control */
tlv320aic3x_update_bit(0x02, (0x3F << 0), (gain_output_ctrl[gain] << 0));
tlv320aic3x_update_bit(0x03, (0x3F << 8), (gain_output_ctrl[gain] << 8));/* Line Output Control 1 */
tlv320aic3x_update_bit(0x03, (0x3F << 0), (gain_output_ctrl[gain] << 0));
tlv320aic3x_write(0x19, gain_digital_vol[gain]); /* DACL1/R1 Digital Volume */
#endif
return;
}
void tlv320aic3x_check_HS_mic(void)
{
/* Enable MICBIAS1 Short Current Detector, Threshold:1500uA */
tlv320aic3x_update_bit(0x93, (7 << 9), (5 << 9));
return;
}
#define tlv320aic3x_speaker_on_REG_GROUP_NUM 23
static struct reg_value_group tlv320aic3x_speaker_on_reg_group[] = {
{0x3D, 1 << 10, 1 << 10}, /*DAC Clock1 Generator Enable*/
{0x3D, 1 << 9, 1 << 9}, /*DAC Clock2 Generator Enable*/
{0x63, 1 << 12, 1 << 12}, /*LOUTMIX Power On*/
{0x61, 1 << 12, 1 << 12}, /*DACL1 Power On*/
{0x61, 1 << 11, 1 << 11}, /*DACR1 Power On*/
{0x62, 1 << 11, 1 << 11}, /*Stereo1 DAC Digital Filter Power On*/
{0x65, 1 << 15, 1 << 15}, /*OUTMIXL Power On*/
{0x65, 1 << 14, 1 << 14}, /*OUTMIXR Power On*/
{0x66, 1 << 13, 1 << 13}, /*OUTVOLL Power On*/
{0x66, 1 << 12, 1 << 12}, /*OUTVOLR Power On*/
{0x8F, 1 << 13, 1 << 13}, /*HP Deop Mode mode 2*/
{0x2A, 1 << 14, 0}, /*DACL1 to Stereo DAC left Mixer*/
{0x2A, 1 << 1, 0}, /*DACL1 to Stereo DAC Right Mixer*/
{0x4F, 1, 0}, /*DACL1 to OUTMIXL*/
{0x52, 1, 0}, /*DACR1 to OUTMIXR*/
{0x53, 1 << 13, 0}, /*OUTVOLL to LOUTMIX Unmute*/
{0x53, 1 << 12, 0}, /*OUTVOLR to LOUTMIX Unmute*/
{0x03, 1 << 15, 0}, /*LOUTL Unmute*/
{0x03, 1 << 14, 0}, /*OUTVOLL Unmute*/
{0x03, 1 << 7, 0}, /*LOUTR Unmute*/
{0x03, 1 << 6, 0}, /*OUTVOLR Unmute*/
{0x73, 3 << 2, 0 << 2}, /*Stereo DAC sample Rate 128 FS*/
{0x05, 1 << 15, 1 << 15}, /*enable Differential Line Output*/
};
#define TLV320AIC3X_SPEAKER_OFF_REG_GROUP_NUM 23
static struct reg_value_group TLV320AIC3X_speaker_off_reg_group[] = {
{0x3D, 1 << 10, 0}, /*DAC Clock1 Generator Enable*/
{0x3D, 1 << 9, 0}, /*DAC Clock2 Generator Enable*/
{0x63, 1 << 12, 0}, /*LOUTMIX Power Off*/
{0x61, 1 << 12, 0}, /*DACL1 Power On*/
{0x61, 1 << 11, 0}, /*DACR1 Power On*/
{0x62, 1 << 11, 0}, /*Stereo1 DAC Digital Filter Power On*/
{0x65, 1 << 15, 0}, /*OUTMIXL Power On*/
{0x65, 1 << 14, 0}, /*OUTMIXR Power On*/
{0x66, 1 << 13, 0}, /*OUTVOLL Power On*/
{0x66, 1 << 12, 0}, /*OUTVOLR Power On*/
{0x8F, 1 << 13, 0}, /*HP Deop Mode mode 2*/
{0x2A, 1 << 14, 1 << 14}, /*DACL1 to Stereo DAC left Mixer*/
{0x2A, 1 << 6, 1 << 6}, /*DACR1 to Stereo DAC Right Mixer*/
{0x4F, 1, 1}, /*DACL1 to OUTMIXL*/
{0x52, 1, 1}, /*DACR1 to OUTMIXR*/
{0x53, 1 << 13, 1 << 13}, /*OUTVOLL to LOUTMIX Unmute*/
{0x53, 1 << 12, 1 << 12}, /*OUTVOLR to LOUTMIX Unmute*/
{0x03, 1 << 15, 1 << 15}, /*LOUTL Unmute*/
{0x03, 1 << 14, 1 << 14}, /*OUTVOLL Unmute*/
{0x03, 1 << 7, 1 << 7}, /*LOUTR Unmute*/
{0x03, 1 << 6, 1 << 6}, /*OUTVOLR Unmute*/
{0x73, 3 << 2, 0 << 2}, /*Stereo DAC sample Rate 128 FS*/
{0x05, 1 << 15, 0 << 15}, /*disable Differential Line Output*/
};
#define tlv320aic3x_headphone_on_REG_GROUP_NUM 22
static struct reg_value_group tlv320aic3x_headphone_on_reg_group[] = {
{0x3D, 1 << 10, 1 << 10}, /*DAC Clock1 Generator Enable*/
{0x3D, 1 << 9, 1 << 9}, /*DAC Clock2 Generator Enable*/
{0x61, 1 << 12, 1 << 12}, /*DACL1 Power On*/
{0x61, 1 << 11, 1 << 11}, /*DACR1 Power On*/
{0x62, 1 << 11, 1 << 11}, /*Stereo1 DAC Digital Filter Power On*/
{0x65, 1 << 15, 1 << 15}, /*OUTMIXL Power On*/
{0x65, 1 << 14, 1 << 14}, /*OUTMIXR Power On*/
{0x66, 1 << 11, 1 << 11}, /*HPOVOLL Power On*/
{0x66, 1 << 10, 1 << 10}, /*HPOVOLR Power On*/
{0x8E, 1 << 4, 1 << 4}, /*Enable Headphone Output*/
{0x8E, 1, 1}, /*HP Amp All Power On*/
{0x8F, 1 << 13, 1 << 13}, /*HP Deop Mode mode 2*/
{0x2A, 1 << 14, 0}, /*DACL1 to Stereo DAC left Mixer*/
{0x2A, 1 << 1, 0}, /*DACL1 to Stereo DAC Right Mixer*/
{0x4F, 1, 0}, /*DACL1 to OUTMIXL*/
{0x52, 1, 0}, /*DACR1 to OUTMIXR*/
{0x45, 1 << 13, 0}, /*HPOVOL to HPOMIX Unmute*/
{0x02, 1 << 15, 0}, /*HPOL UnMute*/
{0x02, 1 << 14, 0}, /*HPOVOLL Unmute*/
{0x02, 1 << 7, 0}, /*HPOR UnMute*/
{0x02, 1 << 6, 0}, /*HPOVOLR Unmute*/
{0x73, 3 << 2, 0 << 2}, /*Stereo DAC sample Rate 128 FS*/
};
#define TLV320AIC3X_HEADPHONE_OFF_REG_GROUP_NUM 22
static struct reg_value_group TLV320AIC3X_headphone_off_reg_group[] = {
{0x3D, 1 << 10, 0}, /*DAC Clock1 Generator Enable*/
{0x3D, 1 << 9, 0}, /*DAC Clock2 Generator Enable*/
{0x61, 1 << 12, 0}, /*DACL1 Power On*/
{0x61, 1 << 11, 0}, /*DACR1 Power On*/
{0x62, 1 << 11, 0}, /*Stereo1 DAC Digital Filter Power On*/
{0x65, 1 << 15, 0}, /*OUTMIXL Power On*/
{0x65, 1 << 14, 0}, /*OUTMIXR Power On*/
{0x66, 1 << 11, 0}, /*HPOVOLL Power On*/
{0x66, 1 << 10, 0}, /*HPOVOLR Power On*/
{0x8E, 1 << 4, 0}, /*Enable Headphone Output*/
{0x8E, 1, 0}, /*HP Amp All Power On*/
{0x8F, 1 << 13, 0}, /*HP Deop Mode mode 2*/
{0x2A, 1 << 14, 1 << 14}, /*DACR1 to Stereo DAC left Mixer*/
{0x2A, 1 << 1, 1 << 1}, /*DACL1 to Stereo DAC Right Mixer*/
{0x4F, 1, 1}, /*DACL1 to OUTMIXL*/
{0x52, 1, 1}, /*DACR1 to OUTMIXR*/
{0x45, 1 << 13, 1 << 13}, /*HPOVOL to HPOMIX Unmute*/
{0x02, 1 << 15, 1 << 15}, /*HPOL UnMute*/
{0x02, 1 << 14, 1 << 14}, /*HPOVOLL Unmute*/
{0x02, 1 << 7, 1 << 7}, /*HPOR UnMute*/
{0x02, 1 << 6, 1 << 6}, /*HPOVOLR Unmute*/
{0x73, 3 << 2, 0 << 2}, /*Stereo DAC sample Rate 128 FS*/
};
#define tlv320aic3x_main_mic_on_REG_GROUP_NUM 11
static struct reg_value_group tlv320aic3x_main_mic_on_reg_group[] = {
{0x3D, 1 << 12, 1 << 12}, /*ADC Clock Genaral Enable*/
{0x65, 1 << 11, 1 << 11}, /*RECMIXL Power On*/
{0x61, 1 << 2, 1 << 2}, /*ADCL Power On*/
{0x62, 1 << 15, 1 << 15}, /*Stereo ADC Digital Filter Power On*/
{0x64, 1 << 14, 1 << 14}, /*BST2 Power On*/
{0x0D, 0xF << 8, 5 << 8}, /*IN2 Boost Control +40dB*/
{0x0D, 1 << 6, 1 << 6}, /*IN2 Differential Mode*/
{0x73, 3, 2}, /*Stereo ADC Over Sample Rate 32 Fs*/
{0x3C, 1 << 2, 0}, /*BST2 to RECMIXL Unmute*/
{0x3E, 1 << 2, 0}, /*BST1 to RECMIXR Unmute*/
{0x27, 1 << 14, 0}, /*Stereo ADC1 Left Channel Unmute*/
};
static struct reg_value_group tlv320aic3x_main_mic_on_reg_group_singlemode[] = {
{0x3D, 1 << 12, 1 << 12}, /*ADC Clock Genaral Enable*/
{0x65, 1 << 11, 1 << 11}, /*RECMIXL Power On*/
{0x61, 1 << 2, 1 << 2}, /*ADCL Power On*/
{0x62, 1 << 15, 1 << 15}, /*Stereo ADC Digital Filter Power On*/
{0x64, 1 << 14, 1 << 14}, /*BST2 Power On*/
{0x0D, 0xF << 8, 5 << 8}, /*IN2 Boost Control +40dB*/
{0x0D, 1 << 6, 0}, /*IN2 Single Mode*/
{0x73, 3, 2}, /*Stereo ADC Over Sample Rate 32 Fs*/
{0x3C, 1 << 2, 0}, /*BST2 to RECMIXL Unmute*/
{0x3E, 1 << 2, 0}, /*BST1 to RECMIXR Unmute*/
{0x27, 1 << 14, 0}, /*Stereo ADC1 Left Channel Unmute*/
};
#define TLV320AIC3X_MAIN_MIC_OFF_REG_GROUP_NUM 11
static struct reg_value_group TLV320AIC3X_main_mic_off_reg_group[] = {
{0x3D, 1 << 12, 0}, /*ADC Clock Genaral Enable*/
{0x65, 1 << 11, 0}, /*RECMIXL Power On*/
{0x61, 1 << 2, 0}, /*ADCL Power On*/
{0x62, 1 << 15, 0}, /*Stereo ADC Digital Filter Power On*/
{0x64, 1 << 14, 0}, /*BST2 Power On*/
{0x0D, 0xF << 8, 0}, /*IN2 Boost Control +40dB*/
{0x0D, 1 << 6, 0}, /*IN2 Differential Mode*/
{0x73, 3, 2}, /*Stereo ADC Over Sample Rate 128 Fs*/
{0x3C, 1 << 2, 1 << 2}, /*BST2 to RECMIXL Unmute*/
{0x3E, 1 << 2, 1 << 2}, /*BST2 to RECMIXL Unmute*/
{0x27, 1 << 14, 1 << 14}, /*Stereo ADC1 Left Channel Unmute*/
};
#define tlv320aic3x_headset_mic_on_REG_GROUP_NUM 14
static struct reg_value_group tlv320aic3x_headset_mic_on_reg_group[] = {
{0x3D, 1 << 12, 1 << 12}, /*ADC Clock Genaral Enable*/
{0x65, 1 << 11, 1 << 11}, /*RECMIXL Power On*/
{0x65, 1 << 10, 1 << 10}, /*RECMIXR Power On*/
{0x61, 1 << 2, 1 << 2}, /*ADCL Power On*/
{0x61, 1 << 1, 1 << 1}, /*ADCR Power On*/
{0x62, 1 << 15, 1 << 15}, /*Stereo ADC Digital Filter Power On*/
{0x0D, 0xF << 12, 5 << 12}, /*IN1 Boost Control +40dB*/
{0x64, 1 << 15, 0 << 15}, /*BST1 Power On*/
{0x64, 1 << 4, 1 << 4}, /*MIC2 SE Mode single-end mode*/
{0x73, 3, 2}, /*Stereo ADC Over Sample Rate 128 Fs*/
{0x3C, 1 << 1, 0}, /*BST1 to RECMIXL Unmute*/
{0x3E, 1 << 1, 0}, /*BST1 to RECMIXR Unmute*/
{0x27, 1 << 14, 0}, /*Stereo ADC1 Left Channel Unmute*/
{0x27, 1 << 6, 0}, /*Stereo ADC1 Right Channel Unmute*/
};
#define TLV320AIC3X_HEADSET_MIC_OFF_REG_GROUP_NUM 14
static struct reg_value_group TLV320AIC3X_headset_mic_off_reg_group[] = {
{0x3D, 1 << 12, 0}, /*ADC Clock Genaral Enable*/
{0x65, 1 << 11, 0}, /*RECMIXL Power On*/
{0x65, 1 << 10, 0}, /*RECMIXR Power On*/
{0x61, 1 << 2, 0}, /*ADCL Power On*/
{0x61, 1 << 1, 0}, /*ADCR Power On*/
{0x62, 1 << 15, 0}, /*Stereo ADC Digital Filter Power On*/
{0x0D, 0xF << 12, 0}, /*IN1 Boost Control +40dB*/
{0x64, 1 << 15, 0}, /*BST1 Power On*/
{0x64, 1 << 4, 0}, /*MIC2 SE Mode single-end mode*/
{0x73, 3, 2}, /*Stereo ADC Over Sample Rate 128 Fs*/
{0x3C, 1 << 1, 1 << 1}, /*BST1 to RECMIXL Unmute*/
{0x3E, 1 << 1, 1 << 1}, /*BST1 to RECMIXR Unmute*/
{0x27, 1 << 14, 1 << 14}, /*Stereo ADC1 Left Channel Unmute*/
{0x27, 1 << 6, 1 << 6}, /*Stereo ADC1 Right Channel Unmute*/
};
/////////////////////////////////////////////////////////////////////////////////
#define TLV320AIC3X_HEADSET_DETECT_ON_REG_GROUP_NUM 3
static struct reg_value_group TLV320AIC3X_headset_detect_on_reg_group[] = {
{0x64, 1 << 2, 1 << 2}, /*JD1 Multilevel Power on*/
{0xC0, 1 << 15, 1 << 15}, /*GPIO1 Pin as IRQ output*/
{0xBD, 7 << 7, 4 << 7}, /*jd1_1, jd1_1_stricky disable, Polarity Normal*/
};
#define TLV320AIC3X_HEADSET_DETECT_OFF_REG_GROUP_NUM 3
static struct reg_value_group TLV320AIC3X_headset_detect_off_reg_group[] = {
{0x64, 1 << 2, 0 << 2}, /*JD1 Multilevel Power off*/
{0xC0, 1 << 15, 0 << 15}, /*GPIO1 Pin as IRQ output*/
{0xBD, 7 << 7, 0 << 7}, /*jd1_1, jd1_1_stricky disable, Polarity Normal*/
};
int tlv320aic3x_reg_dump(void)
{
unsigned char index;
unsigned short value;
int status = -1;
printk(KERN_INFO"tlv320aic3x_reg_dump_enter\n");
for (index = 0; index < 0xFF; index++)
{
// if (tlv320aic3x_readable_register(index))
// {
status = tlv320aic3x_read(index, &value);
if (status != 0)
{
printk(KERN_INFO"status: 0x%x\n", status);
return -1;
}
printk(KERN_INFO"index: 0x%x, value: 0x%x\n", index, value);
// }
}
return 0;
}
/*
I2S1 BCLK Polarity Invert
I2S1 PCM Mode A
*/
static void TLV320AIC3X_set_dai_fmt(char enable)
{
#if 0
if (TLV320AIC3X_DEVICE_ON == enable)
{
if(0 == G_AudioModemMaster){
/* GSSP is slave, tlv320aic3x is master */
tlv320aic3x_write(0x70, 0x0082);
} else {
/* GSSP is master, tlv320aic3x is slave */
tlv320aic3x_write(0x70, 0x8082);
}
}
else if (TLV320AIC3X_DEVICE_OFF == enable)
{
if(0 == G_AudioModemMaster){
/* GSSP is slave, tlv320aic3x is master */
tlv320aic3x_write(0x70, 0x0000);
} else {
/* GSSP is master, tlv320aic3x is slave */
tlv320aic3x_write(0x70, 0x8000);
}
}
#else
if (TLV320AIC3X_DEVICE_ON == enable)
{
tlv320aic3x_update_bit(0x70, (1 << 7) | 3, (1 << 7) | 2);
if(0 == G_AudioModemMaster){// gssp slave, tlv320aic3x master
tlv320aic3x_update_bit(0x70, (1 << 15) , (0 << 15) );// set tlv320aic3x master
}
}
else if (TLV320AIC3X_DEVICE_OFF == enable)
{
tlv320aic3x_update_bit(0x70, (1 << 7) | 3, 0);
}
#endif
}
/*FS = bitrate = 8K
BCLK = 512K = 64FS , 0x73
FOUT = (sysclk * (N + 2)) / ((M + 2) / (K + 2))
SYSCLK = PLL = 26M
FOUT = (26 * 34) / (9 * 4) = 24.555
CLK = FOUT / 12 = 2048K = 256 * FS
*/
static void tlv320aic3x_set_sysclk(char enable)
{
#if 1
if (TLV320AIC3X_DEVICE_ON == enable)
{
tlv320aic3x_write(0xFA, 0x0001); /*Enable MCLK Input*/
tlv320aic3x_write(0x73, 0x0002); /*DAC Over Sample Rate: 128Fs, ADC Over Sample Rate: 32Fs*/
if (3 == Audio_Codec_Fsync_Rate)
{
printk(KERN_INFO"%s, sys clock comes from PLL when Fsync = 48K.\n", __FUNCTION__);
tlv320aic3x_update_bit(0x64, 1 << 9, 1 << 9); /*PLL Power On*/
tlv320aic3x_update_bit(0x73, 7 << 12, 1 << 12); /*sel_i2s_pre_div1 = 1/2*/
}
}
else if (TLV320AIC3X_DEVICE_OFF == enable)
{
tlv320aic3x_write(0xFA, 0x0000); /*Disable MCLK Input*/
if (3 == Audio_Codec_Fsync_Rate)
{
printk(KERN_INFO"%s, sys clock comes from PLL when Fsync = 48K.\n", __FUNCTION__);
tlv320aic3x_update_bit(0x64, 1 << 9, 0); /*PLL Power Off*/
}
}
#else
int bclk_type = BCLK_256_FS;
if (TLV320AIC3X_DEVICE_ON == enable)
{
tlv320aic3x_update_bit(0xFA, 1, 1); /*Enable MCLK Input*/
tlv320aic3x_update_bit(0x64, 1 << 9, 1 << 9); /*PLL Power On*/
tlv320aic3x_update_bit(0x73, 3 << 2, 0 << 2); /*128Fs*/
tlv320aic3x_update_bit(0x73, 3, 2); /*32Fs*/
if(1 == g_tlv320aic3x_mclk_type){/*use I2S_SYSCLK as MCLK , 2.048M/4.096M*/
tlv320aic3x_update_bit(0x73, 7 << 12, 0 << 12); /*I2S Clock Pre-Divider = 0 for divide 1*/
}
else if(0 == g_tlv320aic3x_mclk_type){//using bitclk as tlv320aic3x mclk
tlv320aic3x_update_bit(0x73, 7 << 12, 0 << 12); /*I2S Clock Pre-Divider = 0 for divide 1*/
tlv320aic3x_update_bit(0x80, 3 << 14, 1 << 14); /*System Clock from PLL*/
tlv320aic3x_update_bit(0x80, 3 << 12, 1 << 12); /*PLL from bclk*/
tlv320aic3x_update_bit(0x82, 1 << 11, 1 << 11); /*PLL M bypass */
if(BCLK_64_FS == bclk_type){ // 64fs
tlv320aic3x_update_bit(0x81, 0x1FF << 7 , 6 << 7);/*PLL K = 0,PLL N = 6*/
}
else if(BCLK_128_FS == bclk_type){// 128fs
tlv320aic3x_update_bit(0x81, 0x1FF << 7 , 2 << 7);/*PLL K = 0,PLL N = 2*/
}
else if(BCLK_256_FS == bclk_type){// 256fs
tlv320aic3x_update_bit(0x81, 0x1FF << 7 , 0 << 7);/*PLL K = 0,PLL N = 0*/
}
else if(BCLK_32_FS == bclk_type){// 32fs
tlv320aic3x_update_bit(0x81, 0x1FF << 7 , 14 << 7);/*PLL K = 0,PLL N = 14*/
}
}
}
else if (TLV320AIC3X_DEVICE_OFF == enable)
{
tlv320aic3x_update_bit(0xFA, 1, 0); /*disable MCLK Input*/
tlv320aic3x_update_bit(0x64, 1 << 9, 0); /*PLL Power off*/
}
#endif
}
static void TLV320AIC3X_set_sys_power(char enable)
{
if (TLV320AIC3X_DEVICE_ON == enable)
{
tlv320aic3x_update_bit(0x63, 1 << 11, 1 << 11); /*MICBIAS Bandgap Power On*/
tlv320aic3x_update_bit(0x63, 1 << 15, 1 << 15); /*VREF1 Power On*/
tlv320aic3x_update_bit(0x63, 1 << 14, 1 << 14); /*VREF Slow*/
tlv320aic3x_update_bit(0x63, 1 << 4, 1 << 4); /*VREF2 Power On*/
tlv320aic3x_update_bit(0x63, 1 << 3, 1 << 3); /*VREF2 Slow*/
tlv320aic3x_update_bit(0x63, 1 << 13, 1 << 13); /*MBIAS Power On*/
tlv320aic3x_update_bit(0x61, 1 << 15, 1 << 15); /*I2S Power On*/
tlv320aic3x_update_bit(0x8E, 1 << 3, 1 << 3); /*Charge Pump Power On*/
tlv320aic3x_update_bit(0x64, 1 << 11, 1 << 11); /*MICBIAS1 Power On*/
}
else if (TLV320AIC3X_DEVICE_OFF == enable)
{
tlv320aic3x_update_bit(0x63, 1 << 11, 0); /*MICBIAS Bandgap Power Off*/
tlv320aic3x_update_bit(0x63, 1 << 15, 0); /*VREF1 Power Off*/
tlv320aic3x_update_bit(0x63, 1 << 14, 0); /*VREF Slow*/
tlv320aic3x_update_bit(0x63, 1 << 4, 0); /*VREF2 Power Off*/
tlv320aic3x_update_bit(0x63, 1 << 3, 0); /*VREF2 Slow*/
tlv320aic3x_update_bit(0x63, 1 << 13, 0); /*MBIAS Power Off*/
tlv320aic3x_update_bit(0x61, 1 << 15, 0); /*I2S Power Off*/
tlv320aic3x_update_bit(0x8E, 1 << 3, 0); /*Charge Pump Power Off*/
tlv320aic3x_update_bit(0x64, 1 << 11, 0); /*MICBIAS1 Power Off*/
}
}
static void TLV320AIC3X_device_enable(char device, char enable)
{
int length;
int index;
struct reg_value_group *reg_group = NULL;
if ((device == TLV320AIC3X_OUTPUT_DEVICE_SPEAKER) && (enable == TLV320AIC3X_DEVICE_ON))
{
reg_group = tlv320aic3x_speaker_on_reg_group;
length = tlv320aic3x_speaker_on_REG_GROUP_NUM;
}
else if ((device == TLV320AIC3X_OUTPUT_DEVICE_SPEAKER) && (enable == TLV320AIC3X_DEVICE_OFF))
{
reg_group = TLV320AIC3X_speaker_off_reg_group;
length = TLV320AIC3X_SPEAKER_OFF_REG_GROUP_NUM;
}
else if ((device == TLV320AIC3X_OUTPUT_DEVICE_HEADPHONE) && (enable == TLV320AIC3X_DEVICE_ON))
{
reg_group = tlv320aic3x_headphone_on_reg_group;
length = tlv320aic3x_headphone_on_REG_GROUP_NUM;
}
else if ((device == TLV320AIC3X_OUTPUT_DEVICE_HEADPHONE) && (enable == TLV320AIC3X_DEVICE_OFF))
{
reg_group = TLV320AIC3X_headphone_off_reg_group;
length = TLV320AIC3X_HEADPHONE_OFF_REG_GROUP_NUM;
}
else if ((device == TLV320AIC3X_INPUT_DEVICE_MAIN_MIC) && (enable == TLV320AIC3X_DEVICE_ON))
{
if(g_tlv320aic3xmainmic_type == 0)
reg_group = tlv320aic3x_main_mic_on_reg_group;
else
reg_group = tlv320aic3x_main_mic_on_reg_group_singlemode;
length = tlv320aic3x_main_mic_on_REG_GROUP_NUM;
}
else if ((device == TLV320AIC3X_INPUT_DEVICE_MAIN_MIC) && (enable == TLV320AIC3X_DEVICE_OFF))
{
reg_group = TLV320AIC3X_main_mic_off_reg_group;
length = TLV320AIC3X_MAIN_MIC_OFF_REG_GROUP_NUM;
}
else if ((device == TLV320AIC3X_INPUT_DEVICE_HEADSET_MIC) && (enable == TLV320AIC3X_DEVICE_ON))
{
reg_group = tlv320aic3x_headset_mic_on_reg_group;
length = tlv320aic3x_headset_mic_on_REG_GROUP_NUM;
}
else if ((device == TLV320AIC3X_INPUT_DEVICE_HEADSET_MIC) && (enable == TLV320AIC3X_DEVICE_OFF))
{
reg_group = TLV320AIC3X_headset_mic_off_reg_group;
length = TLV320AIC3X_HEADSET_MIC_OFF_REG_GROUP_NUM;
}
else if ((device == TLV320AIC3X_INPUT_DEVICE_HEADSET_DETECT) && (enable == TLV320AIC3X_DEVICE_ON))
{
reg_group = TLV320AIC3X_headset_detect_on_reg_group;
length = TLV320AIC3X_HEADSET_DETECT_ON_REG_GROUP_NUM;
}
else if ((device == TLV320AIC3X_INPUT_DEVICE_HEADSET_DETECT) && (enable == TLV320AIC3X_DEVICE_OFF))
{
reg_group = TLV320AIC3X_headset_detect_off_reg_group;
length = TLV320AIC3X_HEADSET_DETECT_OFF_REG_GROUP_NUM;
}
if (reg_group == NULL)
return;
if (enable == TLV320AIC3X_DEVICE_ON)
{
for (index = 0; index < length; index++)
{
if (reg_group[index].reg != 0x3D)
tlv320aic3x_update_bit(reg_group[index].reg, reg_group[index].mask, reg_group[index].value);
else
tlv320aic3x_index_update_bits(reg_group[index].reg, reg_group[index].mask, reg_group[index].value);
}
TLV320AIC3X_set_work_state(device, enable);
//printk(KERN_INFO"device enabled:%e{TLV320AIC3X_DEVICE}", device);
}
else if (enable == TLV320AIC3X_DEVICE_OFF)
{
for (index = 0; index < length; index++)
{
if (reg_group[index].reg != 0x3D)
tlv320aic3x_update_bit(reg_group[index].reg, reg_group[index].mask, reg_group[index].value);
else
tlv320aic3x_index_update_bits(reg_group[index].reg, reg_group[index].mask, reg_group[index].value);
}
TLV320AIC3X_set_work_state(device, enable);
//printk(KERN_INFO"device disabled:%e{TLV320AIC3X_DEVICE}", device);
}
}
static void TLV320AIC3X_speaker_enable(char enable)
{
#ifdef RECONFIGURE_POWER_INCALL
TLV320AIC3X_set_dai_fmt(enable);
tlv320aic3x_set_sysclk(enable);
TLV320AIC3X_set_sys_power(enable);
#endif
TLV320AIC3X_device_enable(TLV320AIC3X_OUTPUT_DEVICE_SPEAKER, enable);
return;
}
static void TLV320AIC3X_headphone_enable(char enable)
{
#ifdef RECONFIGURE_POWER_INCALL
TLV320AIC3X_set_dai_fmt(enable);
tlv320aic3x_set_sysclk(enable);
TLV320AIC3X_set_sys_power(enable);
#endif
TLV320AIC3X_device_enable(TLV320AIC3X_OUTPUT_DEVICE_HEADPHONE, enable);
return;
}
static void TLV320AIC3X_main_mic_enable(char enable)
{
#ifdef RECONFIGURE_POWER_INCALL
TLV320AIC3X_set_dai_fmt(enable);
tlv320aic3x_set_sysclk(enable);
TLV320AIC3X_set_sys_power(enable);
#endif
TLV320AIC3X_device_enable(TLV320AIC3X_INPUT_DEVICE_MAIN_MIC, enable);
return;
}
static void TLV320AIC3X_headset_mic_enable(char enable)
{
#ifdef RECONFIGURE_POWER_INCALL
TLV320AIC3X_set_dai_fmt(enable);
tlv320aic3x_set_sysclk(enable);
TLV320AIC3X_set_sys_power(enable);
#endif
TLV320AIC3X_device_enable(TLV320AIC3X_INPUT_DEVICE_HEADSET_MIC, enable);
return;
}
static void TLV320AIC3X_device_select(char device, char onoff)
{
if (tlv320aic3x_init_ok == 0)
{
printk(KERN_INFO"TLV320AIC3X not init\n");
return;
}
switch (onoff)
{
case TLV320AIC3X_DEVICE_ON:
if (device == TLV320AIC3X_OUTPUT_DEVICE_SPEAKER)
{
if (is_speaker_on())
{
printk(KERN_INFO"already enabled\n");
return;
}
else
{
if (is_headphone_on())
{
TLV320AIC3X_headphone_enable(TLV320AIC3X_DEVICE_OFF);
}
TLV320AIC3X_speaker_enable(TLV320AIC3X_DEVICE_ON);
}
}
else if (device == TLV320AIC3X_OUTPUT_DEVICE_HEADPHONE)
{
if (is_headphone_on())
{
printk(KERN_INFO"already enabled\n");
return;
}
else
{
if (is_speaker_on())
{
TLV320AIC3X_speaker_enable(TLV320AIC3X_DEVICE_OFF);
}
TLV320AIC3X_headphone_enable(TLV320AIC3X_DEVICE_ON);
}
}
else if (device == TLV320AIC3X_INPUT_DEVICE_MAIN_MIC)
{
if (is_main_mic_on())
{
printk(KERN_INFO"already enabled\n");
return;
}
else
{
if (is_headset_mic_on())
{
TLV320AIC3X_headset_mic_enable(TLV320AIC3X_DEVICE_OFF);
}
TLV320AIC3X_main_mic_enable(TLV320AIC3X_DEVICE_ON);
}
}
else if (device == TLV320AIC3X_INPUT_DEVICE_HEADSET_MIC)
{
if (is_headset_mic_on())
{
printk(KERN_INFO"already enabled\n");
return;
}
else
{
if (is_main_mic_on())
{
TLV320AIC3X_main_mic_enable(TLV320AIC3X_DEVICE_OFF);
}
TLV320AIC3X_headset_mic_enable(TLV320AIC3X_DEVICE_ON);
}
}
break;
case TLV320AIC3X_DEVICE_OFF:
if (device == TLV320AIC3X_OUTPUT_DEVICE_SPEAKER)
{
if (!is_speaker_on())
{
printk(KERN_INFO"already disabled\n");
return;
}
else
{
TLV320AIC3X_speaker_enable(TLV320AIC3X_DEVICE_OFF);
}
}
else if (device == TLV320AIC3X_OUTPUT_DEVICE_HEADPHONE)
{
if (!is_headphone_on())
{
printk(KERN_INFO"already disabled\n");
return;
}
else
{
TLV320AIC3X_headphone_enable(TLV320AIC3X_DEVICE_OFF);
}
}
else if (device == TLV320AIC3X_INPUT_DEVICE_MAIN_MIC)
{
if (!is_main_mic_on())
{
printk(KERN_INFO"already disabled\n");
return;
}
else
{
TLV320AIC3X_main_mic_enable(TLV320AIC3X_DEVICE_OFF);
}
}
else if (device == TLV320AIC3X_INPUT_DEVICE_HEADSET_MIC)
{
if (!is_headset_mic_on())
{
printk(KERN_INFO"already disabled\n");
return;
}
else
{
TLV320AIC3X_headset_mic_enable(TLV320AIC3X_DEVICE_OFF);
}
}
if (is_speaker_on())
TLV320AIC3X_speaker_enable(TLV320AIC3X_DEVICE_ON);
if (is_headphone_on())
TLV320AIC3X_headphone_enable(TLV320AIC3X_DEVICE_ON);
if (is_main_mic_on())
TLV320AIC3X_main_mic_enable(TLV320AIC3X_DEVICE_ON);
if (is_headset_mic_on())
TLV320AIC3X_headset_mic_enable(TLV320AIC3X_DEVICE_ON);
break;
default:
break;
}
}
void codec_tlv320aic3x_set_headphone_gain(void)
{
#if 0
// -6db
tlv320aic3x_update_bit(0x45, (1 << 12), (1 << 12));
#else
tlv320aic3x_write(0x45, 0x5000);
#endif
return;
}
void codec_tlv320aic3x_set_headphone_mic_gain(void)
{
#if 0
// +24db
tlv320aic3x_update_bit(0x1c, (0x7F << 8), (0x6F << 8));
tlv320aic3x_update_bit(0x1c, (0x7F << 0), (0x6F << 0));
// +24db: Boost will cause something like white noise in background, so just remove it.
//tlv320aic3x_update_bit(0x1E, (3 << 14), (2 << 14));
//tlv320aic3x_update_bit(0x1E, (3 << 12), (2 << 12));
#else
tlv320aic3x_write(0x1c, 0x6f6f);
#endif
return;
}
void codec_TLV320AIC3X_mute_headphone(int mute)
{
if(mute){
tlv320aic3x_update_bit(0x02, (1 << 15), (1 << 15));
tlv320aic3x_update_bit(0x02, (1 << 7), (1 << 7));
}
else{
tlv320aic3x_update_bit(0x02, (1 << 15), (0 << 15));
tlv320aic3x_update_bit(0x02, (1 << 7), (0 << 7));
}
return;
}
void codec_TLV320AIC3X_mute_speaker(int mute)
{
if(mute){
tlv320aic3x_update_bit(0x03, (1 << 15), (1 << 15));
tlv320aic3x_update_bit(0x03, (1 << 7), (1 << 7));
}
else{
tlv320aic3x_update_bit(0x03, (1 << 15), (0 << 15));
tlv320aic3x_update_bit(0x03, (1 << 7), (0 << 7));
}
return;
}
void codec_TLV320AIC3X_set_speaker_mic_gain(void)
{
// +0db
tlv320aic3x_update_bit(0x1c, (0x7F << 8), (0x2F << 8));
tlv320aic3x_update_bit(0x1c, (0x7F << 0), (0x2F << 0));
return;
}
void codec_tlv320aic3x_enable_headphone_main_mic(void)
{
if(!codec_tlv320aic3x_is_connect()) {return;}
printk(KERN_INFO"codec_tlv320aic3x_enable_headphone_main_mic\n");
#ifdef RECONFIGURE_POWER_INCALL
enable_tlv320aic3x_MClock();
#endif
TLV320AIC3X_device_select(TLV320AIC3X_OUTPUT_DEVICE_HEADPHONE, TLV320AIC3X_DEVICE_ON);
TLV320AIC3X_device_select(TLV320AIC3X_INPUT_DEVICE_MAIN_MIC, TLV320AIC3X_DEVICE_ON);
codec_tlv320aic3x_set_headphone_gain();
return;
}
void codec_TLV320AIC3X_enable_headphone(void)
{
if(disableTLV320AIC3XHsMic){
return codec_tlv320aic3x_enable_headphone_main_mic();
}
if(!codec_tlv320aic3x_is_connect()) {return;}
printk(KERN_INFO"codec_TLV320AIC3X_enable_headphone\n");
#ifdef RECONFIGURE_POWER_INCALL
enable_tlv320aic3x_MClock();
#endif
TLV320AIC3X_device_select(TLV320AIC3X_OUTPUT_DEVICE_HEADPHONE, TLV320AIC3X_DEVICE_ON);
TLV320AIC3X_device_select(TLV320AIC3X_INPUT_DEVICE_HEADSET_MIC, TLV320AIC3X_DEVICE_ON);
codec_tlv320aic3x_set_headphone_gain();
codec_tlv320aic3x_set_headphone_mic_gain();
return;
}
void codec_TLV320AIC3X_enable_headphone_only(void)
{
if(!codec_tlv320aic3x_is_connect()) {return;}
printk(KERN_INFO"codec_TLV320AIC3X_enable_headphone_only\n");
#ifdef RECONFIGURE_POWER_INCALL
enable_tlv320aic3x_MClock();
#endif
TLV320AIC3X_device_select(TLV320AIC3X_OUTPUT_DEVICE_HEADPHONE, TLV320AIC3X_DEVICE_ON);
return;
}
void codec_TLV320AIC3X_enable_main_mic_only(void)
{
if(!codec_tlv320aic3x_is_connect()) {return;}
printk(KERN_INFO"codec_TLV320AIC3X_enable_main_mic_only\n");
#ifdef RECONFIGURE_POWER_INCALL
enable_tlv320aic3x_MClock();
#endif
TLV320AIC3X_device_select(TLV320AIC3X_INPUT_DEVICE_HEADSET_MIC, TLV320AIC3X_DEVICE_ON);
return;
}
void codec_TLV320AIC3X_enable_speaker(void)
{
if(!codec_tlv320aic3x_is_connect()) {return;}
printk(KERN_INFO"codec_TLV320AIC3X_enable_speaker\n");
#ifdef RECONFIGURE_POWER_INCALL
enable_tlv320aic3x_MClock();
#endif
TLV320AIC3X_device_select(TLV320AIC3X_OUTPUT_DEVICE_SPEAKER, TLV320AIC3X_DEVICE_ON);
TLV320AIC3X_device_select(TLV320AIC3X_INPUT_DEVICE_MAIN_MIC, TLV320AIC3X_DEVICE_ON);
codec_TLV320AIC3X_set_speaker_mic_gain();
return;
}
void codec_TLV320AIC3X_enable_speaker_only(void)
{
if(!codec_tlv320aic3x_is_connect()) {return;}
printk(KERN_INFO"codec_TLV320AIC3X_enable_speaker_only\n");
TLV320AIC3X_device_select(TLV320AIC3X_OUTPUT_DEVICE_SPEAKER, TLV320AIC3X_DEVICE_ON);
return;
}
void codec_TLV320AIC3X_disable_path(void)
{
if(!codec_tlv320aic3x_is_connect()) {return;}
printk(KERN_INFO"codec_TLV320AIC3X_disable_path\n");
if(is_speaker_on()){
TLV320AIC3X_device_select(TLV320AIC3X_OUTPUT_DEVICE_SPEAKER, TLV320AIC3X_DEVICE_OFF);
}
if(is_headphone_on()){
TLV320AIC3X_device_select(TLV320AIC3X_OUTPUT_DEVICE_HEADPHONE, TLV320AIC3X_DEVICE_OFF);
}
if(is_main_mic_on()){
TLV320AIC3X_device_select(TLV320AIC3X_INPUT_DEVICE_MAIN_MIC, TLV320AIC3X_DEVICE_OFF);
}
if(is_headset_mic_on()){
TLV320AIC3X_device_select(TLV320AIC3X_INPUT_DEVICE_HEADSET_MIC, TLV320AIC3X_DEVICE_OFF);
}
#ifdef RECONFIGURE_POWER_INCALL
disable_tlv320aic3x_MClock();
#endif
return;
}
//Kestrel/Falcon/NezhaC
void disable_tlv320aic3x_MClock(void)
{
printk(KERN_INFO"disable_tlv320aic3x_MClock, g_tlv320aic3x_mclk_type=%d\n", g_tlv320aic3x_mclk_type);
#if 0 //yjg
if(g_tlv320aic3x_mclk_type){
/*GPIO-20 function 0 (default), GPIO-20*/
/* *(volatile unsigned long *)(SSP1_I2S_CLOCK_REG_ADDR) = 0x7820130B; *//*8k, sysclk_en = 0*/
/* *(volatile unsigned long *)(MFPRX_GPIO_20) = 0xB0C0; */
iounmap(i2s_clk_reg);
release_mem_region(SSP1_I2S_CLOCK_REG_ADDR, 4);
}
#endif
return;
}
extern char * get_MCLK_start_addr(void);
#ifdef CONFIG_CPU_ASR1901
extern int enable_pmu_audio_clk(void);
#endif
//Kestrel/Flacon/NezhaC
void enable_tlv320aic3x_MClock(void)
{
#ifdef TLV320AIC3X_DEBUG_CLOSE
int reg_value = 0;
printk(KERN_INFO"enable_tlv320aic3x_MClock, g_tlv320aic3x_mclk_type=%d, Audio_Codec_Fsync_Rate=%d\n", g_tlv320aic3x_mclk_type, Audio_Codec_Fsync_Rate);
printk("enable_tlv320aic3x_MClock, g_tlv320aic3x_mclk_type=%d, Audio_Codec_Fsync_Rate=%d\n", g_tlv320aic3x_mclk_type, Audio_Codec_Fsync_Rate);
if (cpu_is_asr1803()) {
printk(KERN_INFO"%s, platform is Falcon.\n", __FUNCTION__);
} else if (cpu_is_asr1806()) {
printk(KERN_INFO"%s, platform is Falcon-T.\n", __FUNCTION__);
} else if (cpu_is_asr1901() || cpu_is_asr1906()) {
printk(KERN_INFO"%s, platform is Kestrel.\n", __FUNCTION__);
} else if (cpu_is_asr1903()) {
printk(KERN_INFO"%s, platform is Lapwing.\n", __FUNCTION__);
} else {
printk(KERN_INFO"%s, platform is Nezhac or Nezha3.\n", __FUNCTION__);
}
#endif
if (cpu_is_asr1901() || cpu_is_asr1906()) {
printk(KERN_INFO"%s, platform is kestrel.\n", __FUNCTION__);
#ifdef Kestrel_Z2
__raw_writel(0x1043, VCXO_OUT_MFPR_reg);
__raw_writel(0x3, PM_MN_CLK_reg);
if(0 == Audio_Codec_Fsync_Rate){
/* config 2.048MHz MCLK for 8KHz Fsync of PCM */
__raw_writel(0x00980001, GPCR_reg);
} else {
/* config 4.096MHz MCLK for 16KHz Fsync of PCM */
__raw_writel(0x004c0001, GPCR_reg);
}
printk(KERN_INFO"%s, VCXO_OUT_MFPR_reg is 0x%0x, PM_MN_CLK_reg is 0x%0x, GPCR_reg is 0x%0x.\n",
__FUNCTION__, *(unsigned int *)VCXO_OUT_MFPR_reg, *(unsigned int *)PM_MN_CLK_reg, *(unsigned int *)GPCR_reg);
#else
MCLK_CLK_CTRL_reg = get_MCLK_start_addr();
if (NULL == MCLK_CLK_CTRL_reg) {
printk(KERN_INFO"%s, MCLK_CLK_CTRL_reg is NULL.\n", __FUNCTION__, MCLK_CLK_CTRL_reg);
return;
}
MCLK_MN_DIV_reg = (char *)MCLK_CLK_CTRL_reg + 4;
__raw_writel(0x3, MCLK_CLK_CTRL_reg);
if(0 == Audio_Codec_Fsync_Rate){
/* config 2.048MHz MCLK for 8KHz Fsync of PCM */
printk("--->%s%d\n", __FUNCTION__, __LINE__);
__raw_writel(0x004b0004, MCLK_MN_DIV_reg);
} else if (1 == Audio_Codec_Fsync_Rate){
/* config 4.096MHz MCLK for 16KHz Fsync of PCM */
__raw_writel(0x004b0008, MCLK_MN_DIV_reg);
} else if (3 == Audio_Codec_Fsync_Rate) {
/* config 12.288MHz MCLK for 48KHz Fsync of PCM */
//__raw_writel(0x004b0018, MCLK_MN_DIV_reg);//1.MCLK 12.288MHz direct connection
__raw_writel(0x000a0001, MCLK_MN_DIV_reg);//MCLK 3.84MHz for PLL and for HP detection
tlv320aic3x_write(0x73, 0x1002);
tlv320aic3x_write(0x80, 0x4000);//2.MCLK 3.84MHz for PLL
//tlv320aic3x_write(0x80, 0x5000);//3.BCLK 3.84MHz for PLL
tlv320aic3x_write(0x81, 0x3F02);
tlv320aic3x_write(0x82, 0x3000);
} else {
printk(KERN_INFO"%s, please check Audio_Codec_Fsync_Rate = %d.\n",__FUNCTION__, Audio_Codec_Fsync_Rate);
}
printk(KERN_INFO"%s, Audio_Codec_Fsync_Rate = %d.\n",__FUNCTION__, Audio_Codec_Fsync_Rate);
printk(KERN_INFO"%s, MCLK_CLK_CTRL_reg is 0x%0x, MCLK_MN_DIV_reg is 0x%0x.\n",
__FUNCTION__, *(unsigned int *)MCLK_CLK_CTRL_reg, *(unsigned int *)MCLK_MN_DIV_reg);
#endif
} else {
printk(KERN_INFO"%s, platform is NezhaC, Falcon, .etc.\n", __FUNCTION__);
printk("--->%s%d\n", __FUNCTION__, __LINE__);
struct clk * mclk = devm_clk_get(&g_tlv320aic3x_client->dev, "i2s_sys_clk");
if(IS_ERR(mclk)){
printk(KERN_INFO"mclk get failed\n");
return;
}
int ret = clk_prepare_enable(mclk);
if(ret){
printk(KERN_INFO"mclk prepare enable failed");
return;
}
if(g_tlv320aic3x_mclk_type){
printk("--->%s%d\n", __FUNCTION__, __LINE__);
if(0 == Audio_Codec_Fsync_Rate){
/*i2s_sysclk = 2M for 8k*/
#ifdef TLV320AIC3X_DEBUG_CLOSE
reg_value = ioread32(SSP1_I2S_CLOCK_reg);
//reg_value = *(volatile int*)(i2s_clk_reg);
printk(KERN_INFO"read: reg_value=0x%x\n", reg_value);
//printk(KERN_INFO"read: *register_address = 0x%x, reg_value=0x%x\n",
//*(unsigned int *)i2s_clk_reg, reg_value);
#endif
printk("--->%s%d\n", __FUNCTION__, __LINE__);
clk_set_rate(mclk, 2048000);
// clk_set_rate(mclk, 10000000);
int rate = clk_get_rate(mclk);
printk(KERN_INFO"mclk rate is %d", rate);
printk("--->%s%d mclk rate is %d\n", __FUNCTION__, __LINE__, rate);
/* write value to register */
//*(volatile unsigned int *)i2s_clk_reg = 0xF820130B;
#ifdef TLV320AIC3X_DEBUG_CLOSE
/* read value from register */
printk(KERN_INFO"NB, write:0xF820130B(Nezhac, Nezha3),0xE0C472D8(Falcon),*register_address = 0x%x\n", *(unsigned int *)SSP1_I2S_CLOCK_reg);
#endif
}
else{
/*i2s_sysclk = 4M for 16k*/
#ifdef TLV320AIC3X_DEBUG_CLOSE
reg_value = ioread32(SSP1_I2S_CLOCK_reg);
printk(KERN_INFO"read: reg_value=0x%x\n", reg_value);
//printk(KERN_INFO"read: *register_address = %x\n", *(unsigned int *)i2s_clk_reg);
//reg_value = *(volatile int*)(i2s_clk_reg);
//printk(KERN_INFO"read: *register_address = 0x%x, reg_value=0x%x\n",
//*(unsigned int *)i2s_clk_reg, reg_value);
#endif
clk_set_rate(mclk, 4096000);
int rate = clk_get_rate(mclk);
printk(KERN_INFO"mclk rate is %d", rate);
#ifdef TLV320AIC3X_DEBUG_CLOSE
/* write value to register */
//*(volatile unsigned int *)i2s_clk_reg = 0xF840130B;
/* read value from register */
printk(KERN_INFO"WB, write: 0xF840130B(Nezhac, Nezha3),0xE18872D8(Falcon), *register_address = %x\n", *(unsigned int *)SSP1_I2S_CLOCK_reg);
#endif
}
}
}
return;
}
EXPORT_SYMBOL_GPL(enable_tlv320aic3x_MClock);
void codec_tlv320aic3x_power_on(void)
{
printk(KERN_INFO"codec_tlv320aic3x_power_on\n");
enable_tlv320aic3x_MClock();
TLV320AIC3X_set_dai_fmt(1);
tlv320aic3x_set_sysclk(1);
TLV320AIC3X_set_sys_power(1);
}
void codec_tlv320aic3x_power_off(void)
{
printk(KERN_INFO"codec_tlv320aic3x_power_off\n");
TLV320AIC3X_set_dai_fmt(0);
tlv320aic3x_set_sysclk(0);
TLV320AIC3X_set_sys_power(0);
disable_tlv320aic3x_MClock();
}
void codec_tlv320aic3x_enable_headset_detect(void)
{
if(!codec_tlv320aic3x_is_connect()) {return;}
printk(KERN_INFO"codec_tlv320aic3x_enable_headset_detect\n");
g_tlv320aic3xheadset_detection_enabled = 1;
g_tlv320aic3xheadset_plugged = 0;
TLV320AIC3X_device_enable(TLV320AIC3X_INPUT_DEVICE_HEADSET_DETECT, 1);
return;
}
void codec_tlv320aic3x_disable_headset_detect(void)
{
if(!codec_tlv320aic3x_is_connect()) {return;}
printk(KERN_INFO"codec_tlv320aic3x_disable_headset_detect\n");
TLV320AIC3X_device_enable(TLV320AIC3X_INPUT_DEVICE_HEADSET_DETECT, 0);
g_tlv320aic3xheadset_detection_enabled = 0;
return;
}
/* HS Detection */
static struct mfd_cell headset_devs_tlv320aic3x[] = {
{
.name = "tlv320aic3x-headset",
.id = -1,
},
};
static void tlv320aic3x_headset_detection_init(struct i2c_client *client)
{
int ret = 0;
headset_devs_tlv320aic3x[0].platform_data = client;
headset_devs_tlv320aic3x[0].pdata_size = sizeof(struct i2c_client);
ret = mfd_add_devices(&client->dev, 0, &headset_devs_tlv320aic3x[0],
ARRAY_SIZE(headset_devs_tlv320aic3x), NULL,
0,
NULL);
if (ret) {
printk(KERN_INFO"Failed to add headset subdev\n");
return;
}
return;
}
void codec_tlv320aic3x_switch_headset(char on)
{
if(on == 1)
{
//codec_TLV320AIC3X_disable_path();
//msleep(10);
//ACMSetMSAVoicePath(ATC_HEADSET);
codec_TLV320AIC3X_enable_headphone();
}
else
{
//codec_TLV320AIC3X_disable_path();
//msleep(10);
//ACMSetMSAVoicePath(ATC_HANDSET);
codec_TLV320AIC3X_enable_speaker();
}
return;
}
/* Headset function and report to userspace for ACM */
void tlv320aic3x_get_headset_status(void)
{
unsigned short value = 0;
int status = -1;
if(!codec_tlv320aic3x_is_connect()) {return;}
status = tlv320aic3x_read(0xBF, &value);
if(0 != status)
{
printk(KERN_INFO"%s: Read register [0xBF] error = 0x%x\n", __FUNCTION__, status);
return;
}
if((value & 0x3000) == 0)
{/* headset plug in: bit 12 & 13 is 1 */
g_tlv320aic3xheadset_plugged = 1;
/* Enable MICBIAS1 Short Current Detector, Threshold:1500uA */
tlv320aic3x_update_bit(0x93, (7 << 9), (5 << 9));
/* wait mic bias stable*/
mdelay(100);
value = 0;
status = tlv320aic3x_read(0xBE, &value);
if(0 != status)
{
printk(KERN_INFO"%s: Read register [0xBE] error = 0x%x\n", __FUNCTION__, status);
return;
}
/* MICBIAS1 Over Current status */
if((1 == g_tlv320aic3xheadset_plugged) && ((value & (1 << 3)) == 0))
{
/* Headset with mic */
g_tlv320aic3xheadset_mic = 1;
printk(KERN_INFO"Headset(with mic) plugin!\n");
}
else if((1 == g_tlv320aic3xheadset_plugged) && ((value & (1 << 3)) != 0))
{
/* Headset without mic */
g_tlv320aic3xheadset_mic = 0;
printk(KERN_INFO"Headset(without mic) plugin!\n");
}
}
else if((value & 0x3000) == 0x3000)
{/* headset plug out: bit 12 & 13 is 0 */
g_tlv320aic3xheadset_plugged = 0;
g_tlv320aic3xheadset_mic = 0;
/* Disable MICBIAS1 Short Current Detector */
tlv320aic3x_update_bit(0x93, (7 << 9), (0 << 9));
printk(KERN_INFO"Headset plugout!\n");
}
return;
}
int tlv320aic3x_get_headset_mic_status(void)
{
return g_tlv320aic3xheadset_mic;
}
EXPORT_SYMBOL_GPL(tlv320aic3x_get_headset_mic_status);
int tlv320aic3x_get_headset_plugged_status(void)
{
return g_tlv320aic3xheadset_plugged;
}
EXPORT_SYMBOL_GPL(tlv320aic3x_get_headset_plugged_status);
void codec_tlv320aic3x_clear_headset_status(void)
{
if(!codec_tlv320aic3x_is_connect()) {return;}
printk(KERN_INFO"codec_tlv320aic3x_clear_headset_status\n");
tlv320aic3x_write(0xBF, 0);
return;
}
void codec_tlv320aic3x_use_bitclk(void)
{
printk(KERN_INFO"codec_tlv320aic3x_use_bitclk\n");
g_tlv320aic3x_mclk_type = 0;
return;
}
void codec_tlv320aic3x_use_bitclk_with_mclk_on(void)
{
printk(KERN_INFO"codec_tlv320aic3x_use_bitclk_with_mclk_on\n");
g_tlv320aic3x_mclk_type = 2;
return;
}
void codec_tlv320aic3x_set_mainmic_singlemode(void)
{
printk(KERN_INFO"codec_tlv320aic3x_set_mainmic_singlemode\n");
g_tlv320aic3xmainmic_type = 1;
return;
}
void tlv320aic3x_Enable_Headsetdetection(void)
{
/* Init headset detection for tlv320aic3x */
if(codec_tlv320aic3x_is_connect() && (g_tlv320aic3xheadset_detection_enabled == 0))
{
codec_tlv320aic3x_enable_headset_detect();
}
}
EXPORT_SYMBOL_GPL(tlv320aic3x_Enable_Headsetdetection);
void tlv320aic3x_Disable_Headsetdetection(void)
{
/* Init headset detection for tlv320aic3x */
if(codec_tlv320aic3x_is_connect() && (g_tlv320aic3xheadset_detection_enabled == 1))
{
codec_tlv320aic3x_disable_headset_detect();
}
}
EXPORT_SYMBOL_GPL(tlv320aic3x_Disable_Headsetdetection);
void codec_tlv320aic3x_dump(void)
{
tlv320aic3x_reg_dump();
}
/* debug fs for tlv320aic3x register interface of read and write. */
static int reg_tlv320aic3x = 0xffff;
struct dentry *tlv320aic3x_dump_reg = NULL;
static ssize_t tlv320aic3x_dump_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
unsigned short reg_val = 0;
unsigned short out_val = 0;
int i;
int len = 0;
unsigned char str[255] = {0};
if (reg_tlv320aic3x == 0xffff)
{
len = snprintf(str, sizeof(str) - 1, "%s\n",
"tlv320aic3x: register dump:");
for (i = 0; i < tlv320aic3x_reg_NUM; i++)
{
reg_val = tlv320aic3x_read(i, &out_val);
pr_info("%s: [0x%02x]=0x%02x\n", __FUNCTION__, i, out_val);
}
}
else
{
reg_val = tlv320aic3x_read(reg_tlv320aic3x, &out_val);
len = snprintf(str, sizeof(str), "reg_tlv320aic3x=0x%02x, val=0x%04x\n",
reg_tlv320aic3x, out_val);
printk(KERN_INFO"%s:%s\n", __FUNCTION__, str);
}
return 0;
}
/*
read example:
echo 0x90 > /sys/kernel/debug/tlv320aic3x_reg
cat /sys/kernel/debug/tlv320aic3x_reg
read all register:
echo + > /sys/kernel/debug/tlv320aic3x_reg
cat /sys/kernel/debug/tlv320aic3x_reg
write example: echo 0x90 0x10 > /sys/kernel/debug/tlv320aic3x_reg
read register example:
echo 0x3F > /sys/kernel/debug/tlv320aic3x_reg
cat /sys/kernel/debug/tlv320aic3x_reg
read all registers example:
echo + > /sys/kernel/debug/tlv320aic3x_reg
cat /sys/kernel/debug/tlv320aic3x_reg
config Gain example:
echo 0xFF 0x00 > /sys/kernel/debug/tlv320aic3x_reg
echo 0xFF 0x01 > /sys/kernel/debug/tlv320aic3x_reg
echo 0xFF 0x02 > /sys/kernel/debug/tlv320aic3x_reg
echo 0xFF 0x03 > /sys/kernel/debug/tlv320aic3x_reg
echo 0xFF 0x04 > /sys/kernel/debug/tlv320aic3x_reg
echo 0xFF 0x05 > /sys/kernel/debug/tlv320aic3x_reg
echo 0xFF 0x06 > /sys/kernel/debug/tlv320aic3x_reg
echo 0xFF 0x07 > /sys/kernel/debug/tlv320aic3x_reg
cat /sys/kernel/debug/tlv320aic3x_reg
write the register example:
echo 0x2C 0x01 > /sys/kernel/debug/tlv320aic3x_reg
cat /sys/kernel/debug/tlv320aic3x_reg
*/
static ssize_t tlv320aic3x_dump_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
int reg_val;
//struct pm80x_chip *chip = file->private_data;
int i = 0;
int ret;
char messages[20];
memset(messages, '\0', 20);
if (copy_from_user(messages, user_buf, count))
return -EFAULT;
if ('+' == messages[0]) {
/* enable to get all the reg value */
reg_tlv320aic3x = 0xffff;
pr_info("%s: read all reg enabled!\n", __FUNCTION__);
} else {
if (messages[1] != 'x') {
pr_err("Right format: 0x[addr]\n");
return -EINVAL;
}
if (strlen(messages) > 5) {
while (messages[i] != ' ')
i++;
messages[i] = '\0';
if (kstrtouint(messages, 16, &reg_tlv320aic3x) < 0)
return -EINVAL;
i++;
if (kstrtouint(messages + i, 16, &reg_val) < 0)
return -EINVAL;
{
/* config the registers */
ret = tlv320aic3x_write(reg_tlv320aic3x, reg_val & 0xffff);
if (ret < 0) {
pr_err("write reg error!\n");
return -EINVAL;
}
printk(KERN_INFO"%s/L%d: addr=0x%02x, val=0x%04x.\n", __FUNCTION__, __LINE__, reg_tlv320aic3x, reg_val);
}
} else {
/* point out the register address for read. */
if (kstrtouint(messages, 16, &reg_tlv320aic3x) < 0)
return -EINVAL;
}
}
return count;
}
static const struct file_operations tlv320aic3x_dump_ops = {
.open = simple_open,
.read = tlv320aic3x_dump_read,
.write = tlv320aic3x_dump_write,
};
static inline int tlv320aic3x_dump_debugfs_init(struct pm80x_chip *chip)
{
tlv320aic3x_dump_reg = debugfs_create_file("tlv320aic3x_dump_reg", S_IRUGO | S_IFREG,
NULL, NULL, &tlv320aic3x_dump_ops);
if (tlv320aic3x_dump_reg == NULL) {
pr_err("create tlv320aic3x debugfs error!\n");
return -ENOENT;
} else if (tlv320aic3x_dump_reg == ERR_PTR(-ENODEV)) {
pr_err("CONFIG_DEBUG_FS is not enabled!\n");
return -ENOENT;
}
return 0;
}
static void tlv320aic3x_dump_debugfs_remove(struct pm80x_chip *chip)
{
if (NULL != tlv320aic3x_dump_reg){
debugfs_remove_recursive(tlv320aic3x_dump_reg);
}
return;
}
/* debug fs for tlv320aic3x audio control of Earphone, speaker or HS... */
struct dentry *tlv320aic3x_audio_control = NULL;
static ssize_t tlv320aic3x_audio_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
#ifdef TLV320AIC3X_DEBUG
printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__);
#endif
return 0;
}
/*
1:enable earphone, enable MIC1
2:disable earphone, enable MIC1
3:enable speaker, enable MIC1
4:disable speaker, enable MIC1
5:enable Headphone, enable HSMIC
6:disable Headphone, enable HSMIC
control command:
enable earphone and MIC1: echo 1 > /sys/kernel/debug/tlv320aic3x_audio
disable earphone and MIC1: echo 2 > /sys/kernel/debug/tlv320aic3x_audio
enable speaker and MIC1: echo 3 > /sys/kernel/debug/tlv320aic3x_audio
disable speaker and MIC1: echo 4 > /sys/kernel/debug/tlv320aic3x_audio
enable Headphone and HSMIC echo 5 > /sys/kernel/debug/tlv320aic3x_audio
disable Headphone and HSMIC echo 6 > /sys/kernel/debug/tlv320aic3x_audio
*/
static char msg[10];
static ssize_t tlv320aic3x_audio_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
int ret = 0;
size_t tmp_count = 0;
printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__);
memset(msg, 0x00, sizeof(msg));
tmp_count = count;
if (tmp_count >= sizeof(msg)){
tmp_count = sizeof(msg) - 1;
}
/* copy the content from user space to kernel space */
ret = copy_from_user(msg, user_buf, tmp_count);
if (ret){
printk(KERN_ALERT"copy from user fail \n");
return -EFAULT;
}
switch (msg[0]){
case '1':/* input command# echo 1 > /sys/kernel/debug/tlv320aic3x_audio */
printk(KERN_INFO "input %c. \n", msg[0]);
tlv320aic3x_check_HS_mic();
break;
case '2':/* input command# echo 2 > /sys/kernel/debug/tlv320aic3x_audio */
printk(KERN_INFO "input %c. \n", msg[0]);
enable_tlv320aic3x_MClock();
tlv320aic3x_speaker_off();
tlv320aic3x_main_mic_off();
break;
case '3':/* input command# echo 3 > /sys/kernel/debug/tlv320aic3x_audio */
printk(KERN_INFO "input %c. \n", msg[0]);
enable_tlv320aic3x_MClock();
tlv320aic3x_headphone_on();
tlv320aic3x_headset_mic_on();
break;
case '4':/* input command# echo 4 > /sys/kernel/debug/tlv320aic3x_audio */
printk(KERN_INFO "input %c. \n", msg[0]);
codec_tlv320aic3x_enable_headset_detect();
break;
case '5':/* input command# echo 5 > /sys/kernel/debug/tlv320aic3x_audio */
printk(KERN_INFO "input %c. \n", msg[0]);
enable_tlv320aic3x_MClock();
tlv320aic3x_headphone_off();
tlv320aic3x_headset_mic_off();
break;
case '6':/* input command# echo 6 > /sys/kernel/debug/tlv320aic3x_audio */
printk(KERN_INFO "input %c. \n", msg[0]);
tlv320aic3x_mute_mic(1);
break;
case '7':/* input command# echo 7 > /sys/kernel/debug/tlv320aic3x_audio */
enable_tlv320aic3x_MClock();
tlv320aic3x_speaker_on();
tlv320aic3x_main_mic_on();
break;
case '8':/* input command# echo 8 > /sys/kernel/debug/tlv320aic3x_audio */
enable_tlv320aic3x_MClock();
tlv320aic3x_speaker_off();
tlv320aic3x_main_mic_off();
break;
case '9':/* input command# echo 9 > /sys/kernel/debug/tlv320aic3x_audio */
enable_tlv320aic3x_MClock();
codec_tlv320aic3x_enable_headphone_main_mic();
break;
default:/* input command# */
printk(KERN_INFO "input invalid. \n");
break;
}
return tmp_count;
}
static const struct file_operations tlv320aic3x_audio_ops = {
.open = simple_open,
.read = tlv320aic3x_audio_read,
.write = tlv320aic3x_audio_write,
};
static inline int tlv320aic3x_audio_debugfs_init(struct pm80x_chip *chip)
{
tlv320aic3x_audio_control = debugfs_create_file("tlv320aic3x_audio", S_IRUGO | S_IFREG,
NULL, NULL, &tlv320aic3x_audio_ops);
if (tlv320aic3x_audio_control == NULL) {
pr_err("create tlv320aic3x debugfs error!\n");
return -ENOENT;
} else if (tlv320aic3x_audio_control == ERR_PTR(-ENODEV)) {
pr_err("CONFIG_DEBUG_FS is not enabled!\n");
return -ENOENT;
}
return 0;
}
static void tlv320aic3x_audio_debugfs_remove(struct pm80x_chip *chip)
{
if (NULL != tlv320aic3x_audio_control){
debugfs_remove_recursive(tlv320aic3x_audio_control);
}
return;
};
/* register codec to ALSA. */
static const struct snd_kcontrol_new tlv320aic3x_snd_controls[] = {
SOC_SINGLE("Reset Register", TLV320AIC3X_RESET_REG00, 0, 0xff, 0), //0x00
SOC_SINGLE("Clock Manager 1", TLV320AIC3X_CLK_MANAGER_REG01, 0, 0xff, 0), //0x01
SOC_SINGLE("Clock Manager 2", TLV320AIC3X_CLK_MANAGER_REG02, 0, 0xff, 0), //0x02
SOC_SINGLE("Clock Manager 3", TLV320AIC3X_CLK_MANAGER_REG03, 0, 0xff, 0), //0x03
SOC_SINGLE("Clock Manager 4", TLV320AIC3X_CLK_MANAGER_REG04, 0, 0xff, 0), //0x04
SOC_SINGLE("Clock Manager 5", TLV320AIC3X_CLK_MANAGER_REG05, 0, 0xff, 0), //0x05
SOC_SINGLE("Clock Manager 6", TLV320AIC3X_CLK_MANAGER_REG06, 0, 0xff, 0), //0x06
SOC_SINGLE("Clock Manager 7", TLV320AIC3X_CLK_MANAGER_REG07, 0, 0xff, 0), //0x07
SOC_SINGLE("Clock Manager 8", TLV320AIC3X_CLK_MANAGER_REG08, 0, 0xff, 0), //0x08
SOC_SINGLE("ADC SDP Register", TLV320AIC3X_SDPIN_REG09, 0, 0xff, 0), //0x09
SOC_SINGLE("DAC SDP Register", TLV320AIC3X_SDPOUT_REG0A, 0, 0xff, 0), //0x0A
SOC_SINGLE("System Manager 1", TLV320AIC3X_SYSTEM_REG0B, 0, 0xff, 0), //0x0B
SOC_SINGLE("System Manager 2", TLV320AIC3X_SYSTEM_REG0C, 0, 0xff, 0), //0x0C
SOC_SINGLE("System Manager 3", TLV320AIC3X_SYSTEM_REG0D, 0, 0xff, 0), //0x0D
SOC_SINGLE("System Manager 4", TLV320AIC3X_SYSTEM_REG0E, 0, 0xff, 0), //0x0E
SOC_SINGLE("System Manager 5", TLV320AIC3X_SYSTEM_REG0F, 0, 0xff, 0), //0x0F
SOC_SINGLE("System Manager 6", TLV320AIC3X_SYSTEM_REG10, 0, 0xff, 0), //0x10
SOC_SINGLE("System Manager 7", TLV320AIC3X_SYSTEM_REG11, 0, 0xff, 0), //0x11
SOC_SINGLE("System Manager 8", TLV320AIC3X_SYSTEM_REG12, 0, 0xff, 0), //0x12
SOC_SINGLE("System Manager 9", TLV320AIC3X_SYSTEM_REG13, 0, 0xff, 0), //0x13
SOC_SINGLE("System Manager 10", TLV320AIC3X_SYSTEM_REG14, 0, 0xff, 0), //0x14
SOC_SINGLE("ADC RAMP Register", TLV320AIC3X_ADC_REG15, 0, 0xff, 0), //0x15
SOC_SINGLE("ADC Register", TLV320AIC3X_ADC_REG16, 0, 0xff, 0), //0x16
SOC_SINGLE("ADC Volume Register", TLV320AIC3X_ADC_REG17, 0, 0xff, 0), //0x17
SOC_SINGLE("ADC ALC Register1", TLV320AIC3X_ADC_REG18, 0, 0xff, 0), //0x18
SOC_SINGLE("ADC ALC Register2", TLV320AIC3X_ADC_REG19, 0, 0xff, 0), //0x19
SOC_SINGLE("ADC Mute Register1", TLV320AIC3X_ADC_REG1A, 0, 0xff, 0), //0x1A
SOC_SINGLE("ADC Mute Register2", TLV320AIC3X_ADC_REG1B, 0, 0xff, 0), //0x1B
SOC_SINGLE("ADC EQ Register1", TLV320AIC3X_ADC_REG1C, 0, 0xff, 0), //0x1C
SOC_SINGLE("ADC EQ Register2", TLV320AIC3X_ADC_REG1E, 0, 0xff, 0), //0x1E
SOC_SINGLE("DAC Mute Register", TLV320AIC3X_DAC_REG31, 0, 0xff, 0), //0x31
SOC_SINGLE("DAC Volume Register", TLV320AIC3X_DAC_REG32, 0, 0xff, 0), //0x32
SOC_SINGLE("DAC Offset Register", TLV320AIC3X_DAC_REG33, 0, 0xff, 0), //0x33
SOC_SINGLE("DAC DRC Register1", TLV320AIC3X_DAC_REG34, 0, 0xff, 0), //0x34
SOC_SINGLE("DAC DRC Register2", TLV320AIC3X_DAC_REG35, 0, 0xff, 0), //0x35
SOC_SINGLE("DAC RAMP Register", TLV320AIC3X_DAC_REG37, 0, 0xff, 0), //0x37
SOC_SINGLE("GPIO AFSEL Register", TLV320AIC3X_GPIO_REG44, 0, 0xff, 0), //0x44
SOC_SINGLE("GPIO CTL Register", TLV320AIC3X_GP_REG45, 0, 0xff, 0), //0x45
};
void tlv320aic3x_register_init(void)
{
tlv320aic3x_write( 0x00, 0x00);
tlv320aic3x_write( 0x01, 0x80);
tlv320aic3x_write( 0x07, 0x02);
tlv320aic3x_write( 0x65, 0x00);
tlv320aic3x_write( 0x02, 0xaa);
tlv320aic3x_write( 0x03, 0x91);
tlv320aic3x_write( 0x04, 0xc0);
tlv320aic3x_write( 0x05, 0x00);
tlv320aic3x_write( 0x06, 0x00);
tlv320aic3x_write( 0x0b, 0x01);
tlv320aic3x_write( 0x09, 0xc0);
tlv320aic3x_write( 0x10, 0x00);
tlv320aic3x_write( 0x15, 0xf8);
tlv320aic3x_write( 0x16, 0xb4);
tlv320aic3x_write( 0x25, 0xc0);
tlv320aic3x_write( 0x2c, 0x00);
tlv320aic3x_write( 0x5c, 0x80);
tlv320aic3x_write( 0x5d, 0x01);
tlv320aic3x_write( 0x5d, 0x09);
tlv320aic3x_write( 0x2c, 0x32);
}
static int tlv320aic3x_codec_probe(struct snd_soc_component *component)
{
#ifdef TLV320AIC3X_DEBUG
printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__);
#endif
// tlv320aic3x_write(TLV320AIC3X_RESET_REG00, 0x1f);
// tlv320aic3x_write(TLV320AIC3X_RESET_REG00, 0x80);
printk("%s, wait for codec internal init\n", __func__);
msleep(5);
tlv320aic3x_register_init();
// tlv320aic3x_write(TLV320AIC3X_SYSTEM_REG0D, 0x01);
// tlv320aic3x_write(TLV320AIC3X_RESET_REG00, 0x1f);
enable_tlv320aic3x_MClock();
snd_soc_add_component_controls(component, tlv320aic3x_snd_controls, ARRAY_SIZE(tlv320aic3x_snd_controls));
return 0;
}
static unsigned int tlv320aic3x_codec_read(struct snd_soc_component *component, unsigned int reg)
{
unsigned short out_val = 0;
int ret;
ret = tlv320aic3x_read(reg, &out_val);
if(ret)
{
printk("%s, read reg[0x%02x] fail\n", __func__, reg);
return -EIO;
}
out_val = out_val & 0xff;
#ifdef TLV320AIC3X_DEBUG
printk(KERN_INFO"%s/L%d.[0x%02x]=[0x%04x]\n", __FUNCTION__, __LINE__, reg, out_val);
#endif
return out_val;
}
static int tlv320aic3x_codec_write(struct snd_soc_component *component,
unsigned int reg, unsigned int value)
{
int ret = 0;
#ifdef TLV320AIC3X_DEBUG
printk(KERN_INFO"%s/L%d.[0x%02x]=[0x%04x]\n", __FUNCTION__, __LINE__, reg, value);
#endif
ret = tlv320aic3x_write(reg, value & 0xFFFF);
return ret;
}
/* tlv320aic3x_dai_ops */
static int tlv320aic3x_digital_mute(struct snd_soc_dai *codec_dai, int mute)
{
#ifdef TLV320AIC3X_DEBUG
printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__);
#endif
return 0;
}
static int tlv320aic3x_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
#ifdef TLV320AIC3X_DEBUG
printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__);
#endif
return 0;
}
static int tlv320aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
#ifdef TLV320AIC3X_DEBUG
printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__);
#endif
return 0;
}
static int tlv320aic3x_set_dai_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir)
{
#ifdef TLV320AIC3X_DEBUG
printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__);
#endif
return 0;
}
static const struct snd_soc_component_driver soc_component_dev_tlv320aic3x = {
.probe = tlv320aic3x_codec_probe,
.read = tlv320aic3x_codec_read,
.write = tlv320aic3x_codec_write,
#if 0
.suspend_bias_off = 1,
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
#endif
};
static struct snd_soc_dai_ops tlv320aic3x_dai_ops = {
.digital_mute = tlv320aic3x_digital_mute,
.hw_params = tlv320aic3x_hw_params,
.set_fmt = tlv320aic3x_set_dai_fmt,
.set_sysclk = tlv320aic3x_set_dai_sysclk,
};
static struct snd_soc_dai_driver tlv320aic3x_dai[] ={
{
/* DAI I2S(SAI1) */
.name = "tlv320aic3x-i2s",
.id = 1,
.playback = {
.stream_name = "I2S Playback",
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FORMAT_S16_LE | \
SNDRV_PCM_FORMAT_S18_3LE,
},
.capture = {
.stream_name = "I2S Capture",
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FORMAT_S16_LE | \
SNDRV_PCM_FORMAT_S18_3LE,
},
.ops = &tlv320aic3x_dai_ops,
}, {
/* DAI PCM(SAI2) */
.name = "tlv320aic3x-pcm",
.id = 2,
.playback = {
.stream_name = "PCM Playback",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FORMAT_S8| \
SNDRV_PCM_FORMAT_S16_LE | \
SNDRV_PCM_FORMAT_S20_3LE | \
SNDRV_PCM_FORMAT_S24,
},
.capture = {
.stream_name = "PCM Capture",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FORMAT_S8| \
SNDRV_PCM_FORMAT_S16_LE | \
SNDRV_PCM_FORMAT_S20_3LE | \
SNDRV_PCM_FORMAT_S24,
},
.ops = &tlv320aic3x_dai_ops,
},
};
#ifdef HEADSET_DETECTION
irqreturn_t codec_irq_handler(int irq, void *dev_id)
{
printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__);
/* check the headset plug in/out */
tlv320aic3x_get_headset_status();
return IRQ_HANDLED;
}
#endif
//Kestrel
void audio_set_codec_vdd(int on_off)
{
struct regulator *vdd_1v8 = NULL;
struct regulator *vdd_3v3 = NULL;
static int codec_on_off = 0;
printk(KERN_INFO"%s: codec now:%d, to be:%d\n", __FUNCTION__, codec_on_off, on_off);
if (!(cpu_is_asr1901() || cpu_is_asr1906()) || codec_on_off == on_off)
{
return;
}
if(on_off) {
/* 1V8 */
vdd_1v8 = regulator_get(&g_tlv320aic3x_client->dev, "vdd18");
if (IS_ERR_OR_NULL(vdd_1v8)) {
if (PTR_ERR(vdd_1v8) < 0) {
printk(KERN_INFO"%s: the regulator for vdd_1v8 not found.\n", __FUNCTION__);
}
} else {
tlv320aic3x_regulator_vdd_1v8 = vdd_1v8;
printk(KERN_INFO"%s: the regulator for vdd_1v8 is OK.\n", __FUNCTION__);
}
if (tlv320aic3x_regulator_vdd_1v8 > 0) {
if (regulator_set_voltage(tlv320aic3x_regulator_vdd_1v8, 1800000, 1800000))
printk(KERN_INFO"fail to set regulator with 1.8v.\n");
if (regulator_enable(tlv320aic3x_regulator_vdd_1v8))
printk(KERN_INFO"fail to enable regulator vdd_1v8.\n");
}
/* 3V3 */
vdd_3v3 = regulator_get(&g_tlv320aic3x_client->dev, "vdd33");
if (IS_ERR_OR_NULL(vdd_3v3)) {
if (PTR_ERR(vdd_3v3) < 0) {
printk(KERN_INFO"%s: the regulator for vdd_3v3 not found.\n", __FUNCTION__);
}
} else {
tlv320aic3x_regulator_vdd_3v3 = vdd_3v3;
printk(KERN_INFO"%s: the regulator for vdd_3v3 is OK.\n", __FUNCTION__);
}
if (tlv320aic3x_regulator_vdd_3v3 > 0) {
if (regulator_set_voltage(tlv320aic3x_regulator_vdd_3v3, 3300000, 3300000))
printk(KERN_INFO"fail to set regulator with 3.3v.\n");
if (regulator_enable(tlv320aic3x_regulator_vdd_3v3))
printk(KERN_INFO"fail to enable regulator vdd_3v3.\n");
}
codec_on_off = 1;
}
else {
if (tlv320aic3x_regulator_vdd_1v8 > 0) {
if (regulator_disable(tlv320aic3x_regulator_vdd_1v8))
printk(KERN_INFO"fail to disable regulator vdd_1v8\n");
}
if (tlv320aic3x_regulator_vdd_3v3 > 0) {
if (regulator_disable(tlv320aic3x_regulator_vdd_3v3))
printk(KERN_INFO"fail to disable regulator vdd_3v3\n");
}
codec_on_off = 0;
}
}
EXPORT_SYMBOL_GPL(audio_set_codec_vdd);
//Kestrel/NezhaC/Falcon
static void tlv320aic3x_config_init(void)
{
struct pinctrl_state *pin_AUDIO = NULL;
int gpio_1V8 = 0;
int gpio_3V3 = 0;
#ifdef HEADSET_DETECTION
int ret = -1;
#endif
#ifdef TLV320AIC3X_DEBUG
printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__);
#endif
if (cpu_is_asr1803()) {
printk(KERN_INFO"%s, platform is Falcon.\n", __FUNCTION__);
} else if (cpu_is_asr1806()) {
printk(KERN_INFO"%s, platform is Falcon-T.\n", __FUNCTION__);
} else if (cpu_is_asr1901() || cpu_is_asr1906()) {
printk(KERN_INFO"%s, platform is Kestrel.\n", __FUNCTION__);
} else if (cpu_is_asr1903()) {
printk(KERN_INFO"%s, platform is Lapwing.\n", __FUNCTION__);
} else if (cpu_is_asr1802s()) {
printk(KERN_INFO"%s, platform is Nezhac.\n", __FUNCTION__);
} else {
printk(KERN_INFO"%s, please check the platform.\n", __FUNCTION__);
}
/*
NezhaC AUDIO_PIN_CTRL = TDS_DIO10 = function 1 , GPIO-78
Config MPFR in arch/arm/boot/dts/asr1802s-p201.dts
*/
pin_AUDIO = pinctrl_lookup_state(g_tlv320aic3x_pinctrl, "default");
pinctrl_select_state(g_tlv320aic3x_pinctrl, pin_AUDIO);
/* config MPFR of device node "asrmicro,tlv320aic3x" */
if (cpu_is_asr1802s()) {
gpio_tds_dio10 = of_get_named_gpio(g_tlv320aic3x_node, "tds_dio10-gpio", 0);/* GPIO[78] */
gpio_vcxo_out = of_get_named_gpio(g_tlv320aic3x_node, "vcxo_out-gpio", 0);/* GPIO[126] */
}
printk(KERN_INFO"%s/L%d, gpio_tds_dio10 = %d, gpio_vcxo_out = %d\n", __FUNCTION__, __LINE__, gpio_tds_dio10, gpio_vcxo_out);
/* TDS_DIO10 */
//gpio_request(gpio_tds_dio10, "TDS_DIO10");
//gpio_direction_output(gpio_tds_dio10, 0);
/* VCXO_OUT */
if (cpu_is_asr1802s()) {
gpio_request(gpio_vcxo_out, "VCXO_OUT");
gpio_direction_input(gpio_vcxo_out);
}
/* config VDD */
if (cpu_is_asr1802s()) {
gpio_1V8 = of_get_named_gpio(g_tlv320aic3x_node, "1V8-gpio", 0);
}
gpio_3V3 = of_get_named_gpio(g_tlv320aic3x_node, "3V3-gpio", 0);
printk(KERN_INFO"%s/L%d, gpio_1V8=%d, gpio_3V3=%d.\n", __FUNCTION__, __LINE__, gpio_1V8, gpio_3V3);
/* GPIO_31 for CODEC_1V8_EN.
GPIO_32 for CODEC_3V3_EN. */
//gpio_31_CODEC_1V8_EN = mfp_to_gpio(MFP_PIN_GPIO31);
//gpio_32_CODEC_3V3_EN = mfp_to_gpio(MFP_PIN_GPIO32);
if (cpu_is_asr1802s()) {
gpio_31_CODEC_1V8_EN = gpio_1V8;
}
gpio_32_CODEC_3V3_EN = gpio_3V3;
if (cpu_is_asr1802s()) {
if (gpio_31_CODEC_1V8_EN) {
if (gpio_request(gpio_31_CODEC_1V8_EN, "power on/off 1V8")) {
gpio_31_CODEC_1V8_EN = 0;
} else {
gpio_direction_output(gpio_31_CODEC_1V8_EN, 0);
}
}
}
if (gpio_32_CODEC_3V3_EN >= 0) {
if (gpio_request(gpio_32_CODEC_3V3_EN, "power on/off 3V3")) {
gpio_32_CODEC_3V3_EN = 0;
} else {
gpio_direction_output(gpio_32_CODEC_3V3_EN, 0);
}
}
if (cpu_is_asr1802s()) {
gpio_direction_output(gpio_31_CODEC_1V8_EN, 1);
}
if (gpio_32_CODEC_3V3_EN >= 0) {
gpio_direction_output(gpio_32_CODEC_3V3_EN, 1);
}
/* Power on for ASR1901 kestrel */
audio_set_codec_vdd(1);
#ifdef HEADSET_DETECTION
/* CODEC_IRQ */
gpio_CODEC_IRQ = of_get_named_gpio(g_tlv320aic3x_node, "irq-gpio", 0); //GPIO[1]
printk(KERN_INFO"%s/L%d, gpio_CODEC_IRQ=%d.\n", __FUNCTION__, __LINE__, gpio_CODEC_IRQ);
gpio_request(gpio_CODEC_IRQ, "CODEC_IRQ");
gpio_direction_input(gpio_CODEC_IRQ);
irq_codec = gpio_to_irq(gpio_CODEC_IRQ);
printk(KERN_INFO"%s/L%d, irq_codec=%d.\n", __FUNCTION__, __LINE__, irq_codec);
/* request irq */
ret = request_threaded_irq(irq_codec, NULL, codec_irq_handler,
IRQF_SHARED | IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "tlv320aic3x-headset_detection",
g_tlv320aic3x_client);
if (ret < 0) {
printk(KERN_INFO"%s: request irq failed!\n",__FUNCTION__);
}
#endif
#if 0 //The vdds should be supplied
/* Power off for ASR1901 kestrel */
audio_set_codec_vdd(0);
#endif
return;
}
static int g_fsync_rate = 0;
static ssize_t tlv320aic3x_switch_rate_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
int s = 0;
s += sprintf(buf, "%d", g_fsync_rate);
return s;
}
static ssize_t tlv320aic3x_switch_rate_set(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int ret;
ret = kstrtoint(buf, 10, &g_fsync_rate);
if (ret)
return ret;
Audio_Codec_Fsync_Rate = g_fsync_rate;
enable_tlv320aic3x_MClock();
printk(KERN_INFO"%s, Audio_Codec_Fsync_Rate=%d\n", __FUNCTION__, Audio_Codec_Fsync_Rate);
return count;
}
static DEVICE_ATTR(tlv320aic3x_switch_rate, 0644, tlv320aic3x_switch_rate_show, tlv320aic3x_switch_rate_set);
/* i2c driver */
static int tlv320aic3x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret = 0;
printk(KERN_INFO"[tlv320aic3x codec-dai probe: begin] %s/L%d.\n", __FUNCTION__, __LINE__);
printk("--->%s/L%d\n", __FUNCTION__, __LINE__);
if (NULL == client) {
printk(KERN_INFO"Please check codec input parameter for client.\n");
return 0;
}
g_tlv320aic3x_client = client;
g_tlv320aic3x_pinctrl = devm_pinctrl_get(&client->dev);
if (NULL == g_tlv320aic3x_pinctrl){
printk(KERN_INFO"Please check codec input parameter for g_tlv320aic3x_pinctrl.\n");
return 0;
}
g_tlv320aic3x_node = client->dev.of_node;
if (NULL == g_tlv320aic3x_node){
printk(KERN_INFO"Please check codec input parameter for g_tlv320aic3x_node.\n");
return 0;
}
g_reset_gpio = of_get_named_gpio(g_tlv320aic3x_node, "reset-gpio", 0);/* GPIO[120] */
if (unlikely(g_reset_gpio < 0)) {
printk("g_reset_gpio undefined\n");
}
else
{
printk("g_reset_gpio get success \n");
gpio_request(g_reset_gpio, "g_eth_0v9_pin");
gpio_direction_output(g_reset_gpio, 1);
mdelay(50);
gpio_direction_output(g_reset_gpio, 0);
mdelay(50);
gpio_direction_output(g_reset_gpio, 1);
}
tlv320aic3x_dump_debugfs_init(NULL);
// tlv320aic3x_audio_debugfs_init(NULL);
/* Power on the tlv320aic3x. */
//tlv320aic3x_config_init();
/* initiate the TLV320AIC3X codec. */
// codec_tlv320aic3x_init();
// if (!tlv320aic3x_is_connect()) {
// printk(KERN_INFO"Please check codec tlv320aic3x OK or not.\n");
// return 0;
// }
#ifdef CONFIG_CPU_ASR1901
if(!enable_pmu_audio_clk())
{
#endif
// enable_tlv320aic3x_MClock();
// tlv320aic3x_set_sysclk(1);
#ifdef CONFIG_CPU_ASR1901
}
#endif
#if 0
/* if debug the codec in kernel, could open the procedure */
/* enable the path. */
codec_tlv320aic3x_power_on();
//codec_tlv320aic3x_enable_headphone_main_mic();
//codec_tlv320aic3x_switch_headset(1);
tlv320aic3x_headphone_on();
tlv320aic3x_headset_mic_on();
codec_tlv320aic3x_set_headphone_gain();
codec_tlv320aic3x_set_headphone_mic_gain();
#endif
#if 0
/* if debug the codec in kernel, could open the procedure for spk */
/* enable the path. */
codec_tlv320aic3x_power_on();
tlv320aic3x_speaker_on();
tlv320aic3x_main_mic_on();
/* Enable the speaker path using the command:echo 7 > /sys/kernel/debug/tlv320aic3x_audio */
/* Enable PA from CP or Enable PA using the command:echo 0 > /sys/kernel/debug/tlv320aic3x_audio */
#endif
/*
create the platform device, and platform driver will register codec to ALSA.
which will be for device node, such as /dev/snd/timer, control0, ...
snd_soc_register_codec(&client->dev, &soc_codec_dev_tlv320aic3x,
tlv320aic3x_dai, ARRAY_SIZE(tlv320aic3x_dai));
int snd_soc_register_card(struct snd_soc_card *card)
*/
ret = devm_snd_soc_register_component(&client->dev, &soc_component_dev_tlv320aic3x,
tlv320aic3x_dai, ARRAY_SIZE(tlv320aic3x_dai));
if (ret < 0) {
printk(KERN_INFO"Failed to register codec tlv320aic3x: %d.\n", ret);
return ret;
}
/* Headset detection platform device */
//tlv320aic3x_headset_detection_init(client);
/* create the interface for audio_if command "config_pcm" */
ret = device_create_file(&client->dev, &dev_attr_tlv320aic3x_switch_rate);
if (ret < 0) {
printk(KERN_INFO"attr tlv320aic3x_switch_rate create fail: %d.\n", ret);
return ret;
printk(KERN_INFO"[tlvv320aic3x codec-dai probe: end] %s/L%d.\n", __FUNCTION__, __LINE__);
}
return 0;
}
static int tlv320aic3x_remove(struct i2c_client *client)
{
#ifdef TLV320AIC3X_DEBUG
printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__);
#endif
tlv320aic3x_dump_debugfs_remove(NULL);
// tlv320aic3x_audio_debugfs_remove(NULL);
/* free gpio resource. */
//gpio_free(gpio_tds_dio10);
if (cpu_is_asr1802s()) {
gpio_free(gpio_vcxo_out);
}
if (cpu_is_asr1802s()) {
gpio_free(gpio_31_CODEC_1V8_EN);
}
if (gpio_32_CODEC_3V3_EN >= 0) {
gpio_free(gpio_32_CODEC_3V3_EN);
}
/* Power off for ASR1901 kestrel */
audio_set_codec_vdd(0);
#ifdef HEADSET_DETECTION
gpio_free(gpio_CODEC_IRQ);
free_irq(irq_codec, g_tlv320aic3x_client);
#endif
/* disable the path. */
//codec_tlv320aic3x_disable_path();
//codec_tlv320aic3x_disable_path_app();
codec_tlv320aic3x_power_off();
g_tlv320aic3x_client = NULL;
mfd_remove_devices(&client->dev);
return 0;
}
void tlv320aic3x_shutdown(struct i2c_client *client)
{
#ifdef TLV320AIC3X_DEBUG
printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__);
#endif
return;
}
static struct i2c_driver tlv320aic3x_driver = {
.driver = {
.name = "tlv320aic3x",
.of_match_table = of_match_ptr(tlv320aic3x_dt_ids),
},
.probe = tlv320aic3x_probe,
.remove = tlv320aic3x_remove,
//.shutdown = tlv320aic3x_shutdown,
.id_table = tlv320aic3x_dt_table,
};
static int tlv320aic3x_i2c_init(void)
{
return i2c_add_driver(&tlv320aic3x_driver);
}
module_init(tlv320aic3x_i2c_init);
static void tlv320aic3x_i2c_exit(void)
{
i2c_del_driver(&tlv320aic3x_driver);
}
module_exit(tlv320aic3x_i2c_exit);
MODULE_DESCRIPTION("Driver for tlv320aic3x");
MODULE_AUTHOR("wenchen@asrmicro.com");
MODULE_LICENSE("GPL");