| /* |
| * Base driver for ASR NAU8810 |
| * |
| * 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/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 "nau8810.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 nau8810_id_table[] = { |
| {"nau8810", 0}, |
| {} /* NULL terminated */ |
| }; |
| MODULE_DEVICE_TABLE(i2c, nau8810_id_table); |
| |
| static const struct of_device_id nau8810_dt_ids[] = { |
| { .compatible = "marvell,nau8810", }, |
| {}, |
| }; |
| MODULE_DEVICE_TABLE(of, nau8810_dt_ids); |
| |
| struct i2c_client *g_client = NULL; |
| |
| #define PM80X_AUDIO_REG_NUM 0x50 |
| //#define NAU8810_DEBUG |
| //#define NAU8810_DEBUG_CLOSE |
| |
| static int g_8810_mclk_type = 1; /* 0: use bitclk, 1: use i2s_mclk, 2, use bitclk and turn on i2s_mclk */ |
| static int g_8810_mainmic_type = 0; /* 0: differential mode, 1: single mode */ |
| ////////////////////////////////////////////////////////////// |
| //base functions |
| |
| //read function |
| //////////////////////////////////////////////////////////////////////////////////// |
| /****************************************************************************** |
| * Function : nau8810_reg_read |
| ******************************************************************************* |
| * |
| * Description : |
| * |
| * Parameters : UINT8 RegAddr |
| * Parameters : UINT16 *value |
| * |
| * Output Param : None. |
| * |
| * Return value : |
| * |
| * Notes : |
| |
| |-----|----------------------|-----|-----------------|---|-----|-----|---------------------|... |
| | |<- slave address ->| |<- reg address ->|NA | | | <-slave address-> |... |
| |-----|----------------------|-----|-----------------|---|-----|-----|---------------------|... |
| |start|0|0|1|1|0|1|0|WRITE(0)| ACK |A6|A5|A4|A3|A2|A1| 0 | ACK |start|0|0|1|1|0|1|0|READ(1)|... |
| |----------------------------|-----|---------------------|-----|---------------------------|... |
| | master send |slave| master send |slave| master send |... |
| |----------------------------|-----|---------------------|-----|---------------------------|... |
| |
| ... |----------------|------|-----------------------|-----------| |
| ... |<- high data ->| |<- low data ->| | |
| ... |----------------|------|-----------------------|-----------| |
| ... |0|0|0|0|0|0|0|D8| ACK |D7|D6|D5|D4|D3|D2|D1|D0| NACK |stop| |
| ... |----------------|------|-----------------------|-----------| |
| ... | slave send |master| slave send | master | |
| ... |----------------|------|-----------------------|-----------| |
| |
| *******************************************************************************/ |
| static int nau8810_reg_read(struct i2c_client *client, char reg) |
| { |
| char data[2] = {0}; |
| int value = 0x0; |
| |
| data[0] = (reg << 1) & 0xFE; |
| |
| if(i2c_master_send(client, data, 1) == 1) { |
| i2c_master_recv(client, data, 2); |
| value = (((unsigned short)data[0] & 0x01) << 8) | data[1]; |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s: nau8810 read reg:[0x%02x]=0x%03x\n", __FUNCTION__, reg, value); |
| #endif |
| return value; |
| } else { |
| printk(KERN_INFO"%s: nau8810 read faile\n", __FUNCTION__); |
| return -EIO; |
| } |
| } |
| |
| |
| static int nau8810_read(char reg, unsigned short *oValue) |
| { |
| int value; |
| |
| value = nau8810_reg_read(g_client, reg); |
| |
| if (value < 0) |
| { |
| printk(KERN_INFO"%s: nau8810_reg read fail\n", __FUNCTION__); |
| |
| *oValue = 0x00; |
| return -EIO; |
| } |
| |
| *oValue = value & 0x1FF; |
| |
| return value; |
| } |
| ////////////////////////////////////////////////////////////// |
| //////////////////////////////////////////////////////////////// |
| /****************************************************************************** |
| * Function : nau8810_reg_write |
| ******************************************************************************* |
| * |
| * Description : |
| * |
| * Parameters : UINT8 RegAddr |
| * Parameters : UINT16 RegData |
| * |
| * Output Param : None. |
| * |
| * Return value : |
| * |
| * Notes : |
| |
| |-----|----------------------|-----|---------------------|-----|-----------------------|-----|------| |
| | |<- slave address ->| |<- reg address ->| D8| |<- low data ->| | | |
| |-----|----------------------|-----|---------------------|-----|-----------------------|-----|------| |
| |start|0|0|1|1|0|1|0|WRITE(0)| ACK |A6|A5|A4|A3|A2|A1| D8| ACK |D7|D6|D5|D4|D3|D2|D1|D0| ACK | stop | |
| |----------------------------|-----|---------------------|-----|-----------------------|-----|------| |
| | master send |slave| master send |slave| master send |slave|master| |
| |----------------------------|-----|---------------------|-----|-----------------------|-----|------| |
| |
| *******************************************************************************/ |
| static int nau8810_reg_write(struct i2c_client *client, char reg, unsigned short value) |
| { |
| char data[2]; |
| |
| /* data is |
| * D15..D9 NAU8810 register offset |
| * D8...D0 register data |
| */ |
| data[0] = ((reg << 1) & 0xFE) | ((value >> 8) & 0x01); |
| data[1] = (char)(value & 0xFF); |
| |
| if (i2c_master_send(client, data, 2) == 2) { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s=> reg:0x%02x,value:0x%03x success\n", __FUNCTION__, reg, value); |
| #endif |
| return 0; |
| } else { |
| printk(KERN_INFO"%s=> reg:0x%02x,value:0x%03x error\n", __FUNCTION__, reg, value); |
| return -1; |
| } |
| } |
| |
| static int nau8810_write(char reg, unsigned short value) |
| { |
| int ret; |
| |
| #ifdef NAU8810_DEBUG |
| unsigned short read_value; |
| #endif |
| |
| ret = nau8810_reg_write(g_client, reg, value); |
| if (ret < 0) |
| { |
| printk(KERN_INFO"%s:L%d: nau8810_reg_write() error.\n", __FUNCTION__, __LINE__); |
| } |
| |
| #ifdef NAU8810_DEBUG |
| //for check whether write is OK or not. |
| ret = nau8810_read(reg, &read_value); |
| if (ret < 0) |
| { |
| printk(KERN_INFO"%s:L%d: nau8810_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 nau8810_update_bit(char reg, unsigned short mask, unsigned short value) |
| { |
| int status = 0; |
| unsigned short orig = 0; |
| unsigned short tmp = 0; |
| |
| status = nau8810_read(reg, &orig); |
| if (status < 0) |
| { |
| printk(KERN_INFO"%s:L%d: nau8810_read() error.\n", __FUNCTION__, __LINE__); |
| return status; |
| } |
| else |
| { |
| tmp = orig & (~mask); |
| tmp |= (value & mask); |
| |
| if (tmp != orig) |
| { |
| status = nau8810_write(reg, tmp); |
| if (status < 0) |
| { |
| printk(KERN_INFO"%s:L%d: nau8810_write() error.\n", __FUNCTION__, __LINE__); |
| return status; |
| } |
| } |
| } |
| |
| #ifdef NAU8810_DEBUG |
| 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; |
| } |
| |
| ////////////////////////////////////////////////////////////////////////// |
| ////////////////////////////////////////////////////////////////////////// |
| |
| #define NAU8810_I2C_SLAVE_ADDR 0x34 //7-MSB bits: 0011_010 |
| |
| static char l_connect_nau8810 = 0; |
| static char l_outGain = 4; |
| static char l_inGain = 4; |
| |
| extern int IsDisableDefaultCodec(void); |
| |
| int codec_nau8810_is_connect(void) |
| { |
| return l_connect_nau8810; |
| } |
| |
| int codec_nau8810_init(void) |
| { |
| static char nau8810_init_ok = 0; |
| short value = 0; |
| |
| if(0 == nau8810_init_ok){ |
| //codec_nau8810_enable_mfpr(); |
| /* check if has codec nau8810*/ |
| nau8810_read(0x3F, &value); |
| |
| if ((NAU8810_I2C_SLAVE_ADDR >> 1) == value ) { |
| nau8810_write(0, 0x00); |
| nau8810_init_ok = 1; |
| l_connect_nau8810 = 1; |
| } |
| } |
| |
| printk(KERN_INFO"%s:L%d: nau8810_init_ok=%d, l_connect_nau8810 =%d.\n", |
| __FUNCTION__, __LINE__, nau8810_init_ok, l_connect_nau8810); |
| |
| return !nau8810_init_ok; |
| } |
| |
| void codec_nau8810_set_pll(void) |
| { |
| printk(KERN_INFO"%s:L%d: enter.\n", __FUNCTION__, __LINE__); |
| //printk(KERN_INFO"%s:L%d: enter.\n", __FUNCTION__, __LINE__); |
| |
| #ifdef CONFIG_CODEC_PCM_SLAVE |
| //codec is slave |
| printk(KERN_INFO"%s:L%d: codec slave.\n", __FUNCTION__, __LINE__); |
| |
| nau8810_update_bit(0x06, 1, 0); //nau8810 slave mode |
| |
| //NOTES:not must config 0x06 to generate BCLK, it is provided by GSSP. when code is slave. |
| nau8810_update_bit(0x06, 7 << 2, 0); //bclk = mclk |
| |
| nau8810_update_bit(0x06, 7 << 5, 0); //IMCLK = MCLK |
| nau8810_update_bit(0x06, 1 << 8, 0); //pll bypassed |
| |
| #ifdef CONFIG_CODEC_PCM_NB |
| //NB |
| printk(KERN_INFO"%s:L%d: codec slave.NB\n", __FUNCTION__, __LINE__); |
| nau8810_update_bit(0x07, 7 << 1, 5 << 1); // digital filter sample rate, 101b for 8k |
| #else |
| //WB |
| printk(KERN_INFO"%s:L%d: codec slave.WB\n", __FUNCTION__, __LINE__); |
| nau8810_update_bit(0x07, 7 << 1, 3 << 1); // digital filter sample rate, 011b for 16k |
| #endif |
| ///////////////////////////////////////////////////////////////////////////////////////////// |
| #else |
| //codec is master |
| //NOTES: MCLK needs input 2M when NB, 4M when WB. |
| printk(KERN_INFO"%s:L%d: codec master.\n", __FUNCTION__, __LINE__); |
| |
| nau8810_update_bit(0x06, 1, 1); //nau8810 master mode |
| |
| //NOTES:must config 0x06 to generate BCLK, when code is master. |
| nau8810_update_bit(0x06, 7 << 2, 0); //bclk = mclk; 256FS, N=1 |
| |
| nau8810_update_bit(0x06, 7 << 5, 0); //IMCLK = MCLK |
| nau8810_update_bit(0x06, 1 << 8, 0); //pll bypassed |
| |
| #ifdef CONFIG_CODEC_PCM_NB |
| printk(KERN_INFO"%s:L%d: codec master.NB\n", __FUNCTION__, __LINE__); |
| nau8810_update_bit(0x07, 7 << 1, 5 << 1); // digital filter sample rate, 101b for 8k |
| #else |
| printk(KERN_INFO"%s:L%d: codec master.WB\n", __FUNCTION__, __LINE__); |
| nau8810_update_bit(0x07, 7 << 1, 3 << 1); // digital filter sample rate, 011b for 16k |
| #endif |
| |
| #endif |
| ///////////////////////////////////////////////////////////////////////////////////////////// |
| |
| nau8810_write(0x24, 0x00); |
| nau8810_write(0x25, 0x00); |
| nau8810_write(0x26, 0x00); |
| nau8810_write(0x27, 0x00); |
| return; |
| } |
| |
| void codec_nau8810_set_fmt(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s:L%d: enter.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| nau8810_update_bit(0x04, 3 << 5, 0); // wlen = 16 |
| nau8810_update_bit(0x04, 3 << 3, 3 << 3); // PCM A |
| nau8810_update_bit(0x04, 1 << 8, 1 << 8); // bclk polarity interted |
| return; |
| } |
| |
| void codec_nau8810_clear_digital_filter(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s:L%d: enter.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| nau8810_update_bit(0x0e, 1 << 8, 0); // disabe high pass filter |
| //#if 0 |
| /*EQ*/ |
| nau8810_write(0x12, 0x00); |
| nau8810_write(0x13, 0x00); |
| nau8810_write(0x14, 0x00); |
| nau8810_write(0x15, 0x00); |
| nau8810_write(0x16, 0x00); |
| |
| /*notch filter*/ |
| nau8810_write(0x1b, 0x00); |
| nau8810_write(0x1c, 0x00); |
| nau8810_write(0x1d, 0x00); |
| nau8810_write(0x1e, 0x00); |
| //#endif |
| return; |
| } |
| |
| //Speaker |
| void codec_nau8810_dac_power_on(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s:L%d: enter.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| nau8810_update_bit(0x02, 1 << 2, 1 << 2); // unused input/output tie off buffer enable |
| nau8810_update_bit(0x01, 1 << 3, 1 << 3); // analogue amplifier bias control enable |
| nau8810_update_bit(0x01, 3, 1); // REFIMP |
| |
| nau8810_update_bit(0x03, 1, 1); // DAC enable |
| nau8810_update_bit(0x32, 1, 1); // DAC to speaker mixer connect |
| nau8810_update_bit(0x03, 1 << 2, 1 << 2); // speaker mixer enable |
| nau8810_update_bit(0x03, 1 << 6, 1 << 6); // speaker out nagative enable |
| nau8810_update_bit(0x03, 1 << 5, 1 << 5); // speaker out positive enable |
| //nau8810_update_bit(0x03, 1 << 4, 1 << 4); // bias enable |
| |
| nau8810_update_bit(0x19, 0xf, 0xc); // DAC limiter attack time |
| //nau8810_update_bit(0x36, 0x3f, 0x20); // SPEAKER GAIN |
| nau8810_update_bit(0x36, 0x3f, (l_outGain << 3)); // SPEAKER GAIN |
| return; |
| } |
| |
| void codec_nau8810_dac_power_off(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s:L%d: enter.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| nau8810_update_bit(0x03, 1 << 5, 0); // speaker out positive enable |
| nau8810_update_bit(0x03, 1 << 6, 0); // speaker out nagative enable |
| nau8810_update_bit(0x03, 1, 0); // DAC enable |
| nau8810_update_bit(0x03, 1 << 2, 0); // speaker mixer enable |
| nau8810_update_bit(0x03, 1 << 4, 0); // bias enable |
| |
| |
| nau8810_update_bit(0x01, 3, 0); // REFIMP |
| nau8810_update_bit(0x01, 1 << 3, 0); // analogue amplifier bias control enable |
| nau8810_update_bit(0x02, 1 << 2, 0); // unused input/output tie off buffer enable |
| |
| nau8810_update_bit(0x32, 1, 0); // DAC to speaker mixer connect |
| return; |
| } |
| |
| //MIC1 |
| void codec_nau8810_adc_power_on(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s:L%d: enter.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| nau8810_update_bit(0x02, 1 << 2, 1 << 2); // unused input/output tie off buffer enable |
| nau8810_update_bit(0x01, 1 << 3, 1 << 3); // analogue amplifier bias control enable |
| nau8810_update_bit(0x01, 3, 1); // REFIMP |
| |
| nau8810_update_bit(0x02, 1, 1); // ADC enable |
| nau8810_update_bit(0x02, 1 << 4, 1 << 4); // input Boost enable |
| nau8810_update_bit(0x02, 1 << 2, 1 << 2); // Mic PGA enable |
| nau8810_update_bit(0x2C, 1 << 1, 1 << 1); // Mic nagative to input PGA |
| nau8810_update_bit(0x2C, 1 << 0, 1 << 0); // Mic positive to input PGA |
| nau8810_update_bit(0x01, 1 << 4, 1 << 4); // Mic bias enable |
| |
| //nau8810_update_bit(0x2d, 0x3f, 0x24); // PGAGAIN |
| nau8810_update_bit(0x2d, 0x3f, l_inGain << 3); // PGAGAIN |
| |
| nau8810_update_bit(0x2f, 1 << 8, 0); // PGABST |
| return; |
| } |
| |
| void codec_nau8810_adc_power_off(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s:L%d: enter.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| nau8810_update_bit(0x01, 1 << 4, 0); // Mic bias enable |
| //nau8810_update_bit(0x2C, 1 << 0, 0); // Mic positive to input PGA |
| //nau8810_update_bit(0x2C, 1 << 1, 0); // Mic nagative to input PGA |
| nau8810_update_bit(0x02, 1 << 2, 0); // Mic PGA enable |
| nau8810_update_bit(0x02, 1 << 4, 0); // input Boost enable |
| nau8810_update_bit(0x02, 1, 0); // ADC enable |
| |
| nau8810_update_bit(0x01, 3, 0); // REFIMP |
| nau8810_update_bit(0x01, 1 << 3, 0); // analogue amplifier bias control enable |
| nau8810_update_bit(0x02, 1 << 2, 0); // unused input/output tie off buffer enable |
| return; |
| } |
| |
| void codec_nau8810_enable_path(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s:L%d: enter.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| if(!codec_nau8810_is_connect()){ |
| return; |
| } |
| |
| codec_nau8810_set_fmt(); |
| codec_nau8810_set_pll(); |
| codec_nau8810_clear_digital_filter(); |
| codec_nau8810_dac_power_on();//speaker |
| codec_nau8810_adc_power_on();//MIC1 |
| |
| |
| // remove opening codec path pop noise |
| //nau8810_reg_write(0x4f, 0x100); |
| //nau8810_reg_write(0x4b, 0x08F); |
| return; |
| } |
| |
| void codec_nau8810_disable_path(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s:L%d: enter.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| if(!codec_nau8810_is_connect()){ |
| return; |
| } |
| |
| codec_nau8810_dac_power_off(); |
| codec_nau8810_adc_power_off(); |
| return; |
| } |
| |
| void codec_nau8810_set_speaker_gain_app(char gain) |
| { |
| |
| if(!codec_nau8810_is_connect()){ |
| return; |
| } |
| |
| nau8810_write(0x36, gain); |
| |
| return; |
| } |
| |
| void codec_nau8810_set_speaker_gain(char index) |
| { |
| char gain = ((index > 7) ? 7 : index); |
| |
| if(!codec_nau8810_is_connect()){ |
| return; |
| } |
| |
| printk(KERN_INFO"%s/L%d: index - 0x%02x", __FUNCTION__, __LINE__, index); |
| |
| gain = gain << 3; |
| |
| if(0 == nau8810_update_bit(0x36, 0x3F, gain)){ |
| l_outGain = gain >> 3; |
| } |
| |
| printk(KERN_INFO"%s/L%d: index = 0x%02x, gain = 0x%02x, l_outGain = 0x%02x.", __FUNCTION__, __LINE__, index, gain, l_outGain); |
| return; |
| } |
| |
| unsigned char codec_nau8810_get_speaker_gain(void) |
| { |
| if(!codec_nau8810_is_connect()){ |
| return 0xFF; |
| } |
| |
| printk(KERN_INFO"%s/L%d: l_outGain - %x", __FUNCTION__, __LINE__, l_outGain); |
| |
| return l_outGain; |
| } |
| |
| void codec_nau8810_set_mic_gain_app(char gain) |
| { |
| if(!codec_nau8810_is_connect()){ |
| return; |
| } |
| |
| nau8810_write(0x2d, gain); |
| |
| return; |
| } |
| |
| void codec_nau8810_set_mic_gain(char index) |
| { |
| char gain = ((index > 7) ? 7 : index); |
| |
| if(!codec_nau8810_is_connect()){ |
| return; |
| } |
| |
| gain = gain << 3; |
| |
| if(0 == nau8810_update_bit(0x2d, 0x3F, gain)){ |
| l_inGain = gain >> 3; |
| } |
| |
| printk(KERN_INFO"%s/L%d: index = 0x%02x, gain = 0x%02x, l_inGain = 0x%02x.", __FUNCTION__, __LINE__, index, gain, l_inGain); |
| return; |
| } |
| |
| unsigned char codec_nau8810_get_mic_gain(void) |
| { |
| if(!codec_nau8810_is_connect()){ |
| return 0xFF; |
| } |
| |
| printk(KERN_INFO"%s/L%d: l_inGain - 0x%02x", __FUNCTION__, __LINE__, l_inGain); |
| |
| return l_inGain; |
| } |
| |
| /* |
| 0x36 0x0000, 0x2d 0x0000 //Volume 0 |
| 0x36 0x0008, 0x2d 0x0008 //Volume 1 |
| 0x36 0x0010, 0x2d 0x0010 //Volume 2 |
| 0x36 0x0018, 0x2d 0x0018 //Volume 3 |
| 0x36 0x0020, 0x2d 0x0020 //Volume 4 |
| 0x36 0x0028, 0x2d 0x0028 //Volume 5 |
| 0x36 0x0030, 0x2d 0x0030 //Volume 6 |
| 0x36 0x0038, 0x2d 0x0038 //Volume 7 |
| 0x36 0x0039, 0x2d 0x0039 //Volume 8 |
| 0x36 0x003b, 0x2d 0x003b //Volume 9 |
| 0x36 0x003f, 0x2d 0x003f //Volume 10 |
| */ |
| void codec_nau8810_set_MIC_SPK_gain_app(char gain) |
| { |
| if(!codec_nau8810_is_connect()){ |
| return; |
| } |
| |
| nau8810_write(0x2d, gain);//MIC |
| |
| nau8810_write(0x36, gain);//SPEAKER |
| |
| return; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////////////// |
| //write registers to control path for Application. |
| void codec_nau8810_set_fmt_app(void) |
| { |
| nau8810_write(0x04, 0x118); |
| return; |
| } |
| |
| void codec_nau8810_set_pll_app(void) |
| { |
| nau8810_write(0x06, 0x00); |
| nau8810_write(0x07, 0x0a); |
| |
| nau8810_write(0x24, 0x00); |
| nau8810_write(0x25, 0x00); |
| nau8810_write(0x26, 0x00); |
| nau8810_write(0x27, 0x00); |
| |
| return; |
| } |
| |
| void codec_nau8810_clear_digital_filter_app(void) |
| { |
| nau8810_write(0x0e, 0x00); |
| |
| /*EQ*/ |
| nau8810_write(0x12, 0x00); |
| nau8810_write(0x13, 0x00); |
| nau8810_write(0x14, 0x00); |
| nau8810_write(0x15, 0x00); |
| nau8810_write(0x16, 0x00); |
| |
| /*notch filter*/ |
| nau8810_write(0x1b, 0x00); |
| nau8810_write(0x1c, 0x00); |
| nau8810_write(0x1d, 0x00); |
| nau8810_write(0x1e, 0x00); |
| |
| return; |
| } |
| |
| void codec_nau8810_dac_power_on_app(void) |
| { |
| nau8810_write(0x01, 0x19); |
| nau8810_write(0x02, 0x15); |
| nau8810_write(0x03, 0x65); |
| nau8810_write(0x19, 0x0c); |
| nau8810_write(0x32, 0x01); |
| nau8810_write(0x36, 0x20); |
| |
| return; |
| } |
| |
| void codec_nau8810_adc_power_on_app(void) |
| { |
| nau8810_write(0x01, 0x19); |
| nau8810_write(0x02, 0x15); |
| nau8810_write(0x2C, 0x03); |
| nau8810_write(0x2d, 0x20); |
| nau8810_write(0x2f, 0x00); |
| return; |
| } |
| |
| //MIC disable |
| void codec_nau8810_adc_power_off_app(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s:L%d: enter.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| nau8810_write(0x01, 0x0); |
| nau8810_write(0x02, 0x0); |
| |
| return; |
| } |
| |
| //speaker disable |
| void codec_nau8810_dac_power_off_app(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s:L%d: enter.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| nau8810_write(0x01, 0x0); |
| nau8810_write(0x02, 0x0); |
| nau8810_write(0x03, 0x0); |
| nau8810_write(0x32, 0x0); |
| |
| return; |
| } |
| |
| void codec_nau8810_disable_path_app(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s:L%d: enter.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| if(!codec_nau8810_is_connect()){ |
| return; |
| } |
| |
| codec_nau8810_dac_power_off_app(); |
| codec_nau8810_adc_power_off_app(); |
| |
| return; |
| } |
| |
| void mute_input_device(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s:L%d: enter.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| nau8810_update_bit(0x02, 1 << 2, 0); // unused input/output tie off buffer enable |
| |
| nau8810_update_bit(0x2C, 1 << 1, 0); // Mic nagative to input PGA |
| nau8810_update_bit(0x2C, 1 << 0, 0); // Mic positive to input PGA |
| |
| return; |
| } |
| |
| void unmute_input_device(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s:L%d: enter.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| nau8810_update_bit(0x02, 1 << 2, 1 << 2); // Mic PGA enable |
| |
| nau8810_update_bit(0x2C, 1 << 1, 1 << 1); // Mic nagative to input PGA |
| nau8810_update_bit(0x2C, 1 << 0, 1 << 0); // Mic positive to input PGA |
| |
| return; |
| } |
| |
| //disable MIC |
| void disable_voice_input_device(void) |
| { |
| //printk(KERN_INFO"%s:L%d: enter.\n", __FUNCTION__, __LINE__); |
| nau8810_write(0x01, 0x0); |
| nau8810_write(0x02, 0x0); |
| return; |
| } |
| |
| //disable speaker |
| void disable_voice_output_device(void) |
| { |
| //printk(KERN_INFO"%s:L%d: enter.\n", __FUNCTION__, __LINE__); |
| |
| nau8810_write(0x01, 0x0); |
| nau8810_write(0x02, 0x0); |
| nau8810_write(0x03, 0x0); |
| nau8810_write(0x32, 0x0); |
| |
| return; |
| } |
| |
| //enable speaker, earphone, headphone |
| void enable_voice_output_device(void) |
| { |
| if(!codec_nau8810_is_connect()){ |
| return; |
| } |
| |
| //codec_nau8810_set_fmt_app(); |
| nau8810_write(0x04, 0x118); |
| |
| //codec_nau8810_set_pll_app(); |
| nau8810_write(0x06, 0x00); |
| nau8810_write(0x07, 0x0a); |
| |
| nau8810_write(0x24, 0x00); |
| nau8810_write(0x25, 0x00); |
| nau8810_write(0x26, 0x00); |
| nau8810_write(0x27, 0x00); |
| |
| |
| //codec_nau8810_clear_digital_filter_app(); |
| nau8810_write(0x0e, 0x00); |
| |
| /*EQ*/ |
| nau8810_write(0x12, 0x00); |
| nau8810_write(0x13, 0x00); |
| nau8810_write(0x14, 0x00); |
| nau8810_write(0x15, 0x00); |
| nau8810_write(0x16, 0x00); |
| |
| /*notch filter*/ |
| nau8810_write(0x1b, 0x00); |
| nau8810_write(0x1c, 0x00); |
| nau8810_write(0x1d, 0x00); |
| nau8810_write(0x1e, 0x00); |
| |
| //codec_nau8810_dac_power_on_app();//speaker |
| nau8810_write(0x01, 0x19); |
| nau8810_write(0x02, 0x15); |
| nau8810_write(0x03, 0x65); |
| nau8810_write(0x19, 0x0c); |
| nau8810_write(0x32, 0x01); |
| nau8810_write(0x36, 0x20); |
| |
| return; |
| } |
| |
| //enable MIC, HS |
| void enable_voice_input_device(void) |
| { |
| if(!codec_nau8810_is_connect()){ |
| return; |
| } |
| |
| //codec_nau8810_set_fmt_app(); |
| nau8810_write(0x04, 0x118); |
| |
| //codec_nau8810_set_pll_app(); |
| nau8810_write(0x06, 0x00); |
| nau8810_write(0x07, 0x0a); |
| |
| nau8810_write(0x24, 0x00); |
| nau8810_write(0x25, 0x00); |
| nau8810_write(0x26, 0x00); |
| nau8810_write(0x27, 0x00); |
| |
| |
| //codec_nau8810_clear_digital_filter_app(); |
| nau8810_write(0x0e, 0x00); |
| |
| /*EQ*/ |
| nau8810_write(0x12, 0x00); |
| nau8810_write(0x13, 0x00); |
| nau8810_write(0x14, 0x00); |
| nau8810_write(0x15, 0x00); |
| nau8810_write(0x16, 0x00); |
| |
| /*notch filter*/ |
| nau8810_write(0x1b, 0x00); |
| nau8810_write(0x1c, 0x00); |
| nau8810_write(0x1d, 0x00); |
| nau8810_write(0x1e, 0x00); |
| |
| //codec_nau8810_adc_power_on_app();//MIC1 |
| nau8810_write(0x01, 0x19); |
| nau8810_write(0x02, 0x15); |
| nau8810_write(0x2C, 0x03); |
| nau8810_write(0x2d, 0x20); |
| nau8810_write(0x2f, 0x00); |
| |
| return; |
| } |
| |
| |
| void codec_nau8810_enable_path_app(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s:L%d: enter.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| if(!codec_nau8810_is_connect()){ |
| return; |
| } |
| |
| codec_nau8810_set_fmt_app(); |
| codec_nau8810_set_pll_app(); |
| codec_nau8810_clear_digital_filter_app(); |
| codec_nau8810_dac_power_on_app();//speaker |
| codec_nau8810_adc_power_on_app();//MIC1 |
| |
| return; |
| } |
| |
| void codec_nau8810_test(void) |
| { |
| printk(KERN_INFO"%s/L%d: enter.", __FUNCTION__, __LINE__); |
| |
| //power managerment |
| nau8810_write(0x00, 0x0); |
| nau8810_write(0x01, 0x19); |
| nau8810_write(0x02, 0x15); |
| nau8810_write(0x03, 0x65); |
| |
| //audio control |
| nau8810_write(0x04, 0x118); |
| nau8810_write(0x05, 0x0); |
| nau8810_write(0x06, 0x0); |
| nau8810_write(0x07, 0xa); |
| |
| nau8810_write(0x08, 0x0); |
| nau8810_write(0x09, 0x0); |
| |
| nau8810_write(0x0a, 0x0); |
| nau8810_write(0x0b, 0xff); |
| nau8810_write(0x0c, 0x0); |
| nau8810_write(0x0d, 0x0); |
| nau8810_write(0x0e, 0x0); |
| nau8810_write(0x0f, 0xff); |
| |
| //equalizer |
| |
| nau8810_write(0x10, 0x0); |
| nau8810_write(0x11, 0x0); |
| nau8810_write(0x12, 0x0); |
| nau8810_write(0x13, 0x0); |
| nau8810_write(0x14, 0x0); |
| nau8810_write(0x15, 0x0); |
| nau8810_write(0x16, 0x0); |
| nau8810_write(0x17, 0x0); |
| |
| //dac limiter |
| nau8810_write(0x18, 0x32); |
| nau8810_write(0x19, 0xc); |
| |
| //notch filter |
| nau8810_write(0x1a, 0x0); |
| nau8810_write(0x1b, 0x0); |
| nau8810_write(0x1c, 0x0); |
| nau8810_write(0x1d, 0x0); |
| nau8810_write(0x1e, 0x0); |
| nau8810_write(0x1f, 0x0); |
| |
| //alc control |
| nau8810_write(0x20, 0x38); |
| nau8810_write(0x21, 0xb); |
| nau8810_write(0x22, 0x32); |
| nau8810_write(0x23, 0x0); |
| |
| //pll contrl |
| nau8810_write(0x24, 0x0); |
| nau8810_write(0x25, 0x0); |
| nau8810_write(0x26, 0x0); |
| nau8810_write(0x27, 0x0); |
| |
| //byp control |
| nau8810_write(0x28, 0x0); |
| nau8810_write(0x29, 0x0); |
| nau8810_write(0x2a, 0x0); |
| nau8810_write(0x2b, 0x0); |
| |
| // input output mixer |
| nau8810_write(0x2c, 0x3); |
| nau8810_write(0x2d, 0x20); |
| nau8810_write(0x2e, 0x0); |
| nau8810_write(0x2f, 0x0); |
| nau8810_write(0x30, 0x0); |
| nau8810_write(0x31, 0x2); |
| nau8810_write(0x32, 0x1); |
| nau8810_write(0x33, 0x0); |
| nau8810_write(0x34, 0x0); |
| nau8810_write(0x35, 0x0); |
| nau8810_write(0x36, 0x20); |
| nau8810_write(0x37, 0x0); |
| nau8810_write(0x38, 0x1); |
| nau8810_write(0x39, 0x0); |
| nau8810_write(0x3a, 0x0); |
| nau8810_write(0x3b, 0x0); |
| nau8810_write(0x3c, 0x20); |
| nau8810_write(0x3d, 0x0); |
| nau8810_write(0x3e, 0xee); |
| nau8810_write(0x3f, 0x1a); |
| /* |
| nau8810_write(0x40, 0x0ca); |
| nau8810_write(0x41, 0x124); |
| nau8810_write(0x42, 0x000); |
| nau8810_write(0x43, 0x000); |
| nau8810_write(0x44, 0x000); |
| nau8810_write(0x45, 0x000); |
| nau8810_write(0x46, 0x020); |
| nau8810_write(0x47, 0x000); |
| nau8810_write(0x48, 0x006); |
| nau8810_write(0x49, 0x000); |
| nau8810_write(0x4a, 0x000); |
| nau8810_write(0x4b, 0x000); |
| nau8810_write(0x4c, 0x004); |
| nau8810_write(0x4d, 0x000); |
| nau8810_write(0x4e, 0x000); |
| nau8810_write(0x4f, 0x000); |
| */ |
| //------------------------- |
| /*nau8810_reg_write(0x3b, 0x00); |
| nau8810_reg_write(0x3c, 0x20); |
| nau8810_reg_write(0x3a, 0x00); |
| nau8810_reg_write(0x3a, 0x00); |
| nau8810_reg_write(0x3a, 0x00); |
| nau8810_reg_write(0x3a, 0x00);*/ |
| return; |
| } |
| |
| ///////////////////////////////////////////////////////////// |
| ///////////////////////////////////////////////////////////// |
| //debug fs for nau8810 register interface of read and write. |
| static int reg_nau8810 = 0xffff; |
| struct dentry *nau8810_dump_reg = NULL; |
| |
| static ssize_t nau8810_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; |
| char str[100] = {0}; |
| |
| if (reg_nau8810 == 0xffff) { |
| len = snprintf(str, sizeof(str) - 1, "%s\n", |
| "nau8810: register dump:"); |
| for (i = 0; i < PM80X_AUDIO_REG_NUM; i++) { |
| reg_val = nau8810_read(i, &out_val); |
| pr_info("%s: [0x%02x]=0x%03x\n", __FUNCTION__, i, out_val); |
| } |
| } else { |
| |
| //0xFF:get MIC Gain and Speaker Gain |
| //echo 0xFF 4 > /sys/kernel/debug/nau8810_reg |
| //cat /sys/kernel/debug/nau8810_reg |
| if (0xFF == reg_nau8810) |
| { |
| |
| codec_nau8810_get_speaker_gain(); |
| codec_nau8810_get_mic_gain(); |
| } |
| else |
| { |
| reg_val = nau8810_read(reg_nau8810, &out_val); |
| len = snprintf(str, sizeof(str), "reg_nau8810=0x%02x, val=0x%03x\n", |
| reg_nau8810, out_val); |
| printk(KERN_INFO"%s:%s", __FUNCTION__, str); |
| |
| } |
| } |
| |
| return 0; |
| } |
| |
| //read example: |
| // echo 0x90 > /sys/kernel/debug/nau8810_reg |
| // cat /sys/kernel/debug/nau8810_reg |
| //read all register: |
| // echo + > /sys/kernel/debug/nau8810_reg |
| // cat /sys/kernel/debug/nau8810_reg |
| //write example: echo 0x90 0x10 > /sys/kernel/debug/nau8810_reg |
| /* |
| //read register example: |
| echo 0x3F > /sys/kernel/debug/nau8810_reg |
| cat /sys/kernel/debug/nau8810_reg |
| |
| //read all registers example: |
| echo + > /sys/kernel/debug/nau8810_reg |
| cat /sys/kernel/debug/nau8810_reg |
| |
| //config Gain example: |
| echo 0xFF 0x00 > /sys/kernel/debug/nau8810_reg |
| echo 0xFF 0x01 > /sys/kernel/debug/nau8810_reg |
| echo 0xFF 0x02 > /sys/kernel/debug/nau8810_reg |
| echo 0xFF 0x03 > /sys/kernel/debug/nau8810_reg |
| echo 0xFF 0x04 > /sys/kernel/debug/nau8810_reg |
| echo 0xFF 0x05 > /sys/kernel/debug/nau8810_reg |
| echo 0xFF 0x06 > /sys/kernel/debug/nau8810_reg |
| echo 0xFF 0x07 > /sys/kernel/debug/nau8810_reg |
| cat /sys/kernel/debug/nau8810_reg |
| |
| //write the register example: |
| echo 0x2C 0x01 > /sys/kernel/debug/nau8810_reg |
| cat /sys/kernel/debug/nau8810_reg |
| */ |
| static ssize_t nau8810_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_nau8810 = 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, ®_nau8810) < 0) |
| return -EINVAL; |
| i++; |
| if (kstrtouint(messages + i, 16, ®_val) < 0) |
| return -EINVAL; |
| |
| //0xFF:set MIC Gain and Speaker Gain |
| //value(0x00~0x07) |
| //echo 0xFF value > /sys/kernel/debug/nau8810_reg |
| //cat /sys/kernel/debug/nau8810_reg |
| if (0xFF == reg_nau8810) |
| { |
| codec_nau8810_set_speaker_gain(reg_val & 0xff); |
| codec_nau8810_set_mic_gain(reg_val & 0xff); |
| } |
| else |
| { |
| //config the registers |
| ret = nau8810_write(reg_nau8810, 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%03x.\n", __FUNCTION__, __LINE__, reg_nau8810, reg_val); |
| |
| } |
| |
| } else { |
| //point out the register address for read. |
| if (kstrtouint(messages, 16, ®_nau8810) < 0) |
| return -EINVAL; |
| } |
| } |
| |
| return count; |
| } |
| |
| static const struct file_operations nau8810_dump_ops = { |
| .owner = THIS_MODULE, |
| .open = simple_open, |
| .read = nau8810_dump_read, |
| .write = nau8810_dump_write, |
| }; |
| |
| static inline int nau8810_dump_debugfs_init(struct pm80x_chip *chip) |
| { |
| |
| nau8810_dump_reg = debugfs_create_file("nau8810_reg", S_IRUGO | S_IFREG, |
| NULL, NULL, &nau8810_dump_ops); |
| |
| if (nau8810_dump_reg == NULL) { |
| pr_err("create nau8810 debugfs error!\n"); |
| return -ENOENT; |
| } else if (nau8810_dump_reg == ERR_PTR(-ENODEV)) { |
| pr_err("CONFIG_DEBUG_FS is not enabled!\n"); |
| return -ENOENT; |
| } |
| |
| return 0; |
| } |
| |
| static void nau8810_dump_debugfs_remove(struct pm80x_chip *chip) |
| { |
| if (NULL != nau8810_dump_reg){ |
| debugfs_remove_recursive(nau8810_dump_reg); |
| } |
| |
| return; |
| } |
| |
| ////////////////////////////////////////////////////////////// |
| ////////////////////////////////////////////////////////////// |
| //audio control functions |
| void enable_voice_earphone(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| enable_voice_output_device(); |
| return; |
| } |
| |
| void enable_voice_speaker(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| enable_voice_output_device(); |
| return; |
| } |
| |
| void enable_voice_headphone(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| enable_voice_output_device(); |
| |
| return; |
| } |
| |
| void enable_voice_MIC1(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| enable_voice_input_device(); |
| return; |
| } |
| |
| void enable_voice_HSMIC(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| enable_voice_input_device(); |
| return; |
| } |
| |
| void disable_voice_earphone(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| disable_voice_output_device(); |
| return; |
| } |
| |
| void disable_voice_speaker(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| disable_voice_output_device(); |
| return; |
| } |
| |
| void disable_voice_headphone(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| disable_voice_output_device(); |
| return; |
| } |
| |
| |
| void disable_voice_MIC1(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| disable_voice_input_device(); |
| return; |
| } |
| |
| void disable_voice_HSMIC(void) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| disable_voice_input_device(); |
| return; |
| } |
| ///////////////////////////////////////////////////////////// |
| ///////////////////////////////////////////////////////////// |
| //debug fs for nau8810 audio control of Earphone, speaker or HS... |
| |
| struct dentry *nau8810_audio_control = NULL; |
| |
| static ssize_t nau8810_audio_read(struct file *file, char __user *user_buf, |
| size_t count, loff_t *ppos) |
| { |
| |
| #ifdef NAU8810_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/nau8810_audio |
| //disable earphone and MIC1: echo 2 > /sys/kernel/debug/nau8810_audio |
| |
| //enable speaker and MIC1: echo 3 > /sys/kernel/debug/nau8810_audio |
| //disable speaker and MIC1: echo 4 > /sys/kernel/debug/nau8810_audio |
| |
| //enable Headphone and HSMIC echo 5 > /sys/kernel/debug/nau8810_audio |
| //disable Headphone and HSMIC echo 6 > /sys/kernel/debug/nau8810_audio |
| /////////////////////////////////////////////////////////////////////////// |
| static char msg[10]; |
| |
| static ssize_t nau8810_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/nau8810_audio |
| //Debug interface for enable earphone and MIC1 |
| printk(KERN_INFO "input %c. \n", msg[0]); |
| //enable_voice_earphone(); |
| //enable_voice_MIC1(); |
| |
| //enable the path. |
| |
| //codec_nau8810_enable_path(); |
| //codec_nau8810_enable_path_app(); |
| |
| enable_voice_input_device(); |
| enable_voice_output_device(); |
| |
| break; |
| |
| case '2'://input command# echo 2 > /sys/kernel/debug/nau8810_audio |
| //Debug interface for disable earphone and MIC1 |
| printk(KERN_INFO "input %c. \n", msg[0]); |
| //disable_voice_earphone(); |
| //disable_voice_MIC1(); |
| |
| //disable the path. |
| |
| //codec_nau8810_disable_path(); |
| //codec_nau8810_disable_path_app(); |
| |
| disable_voice_input_device(); |
| disable_voice_output_device(); |
| break; |
| |
| case '3'://input command# echo 3 > /sys/kernel/debug/nau8810_audio |
| //Debug interface for enable speaker and MIC1 |
| printk(KERN_INFO "input %c. \n", msg[0]); |
| |
| enable_voice_speaker(); |
| enable_voice_MIC1(); |
| |
| break; |
| |
| case '4'://input command# echo 4 > /sys/kernel/debug/nau8810_audio |
| //Debug interface for the disable speaker and MIC1 |
| printk(KERN_INFO "input %c. \n", msg[0]); |
| |
| //disable the path. |
| |
| disable_voice_speaker(); |
| disable_voice_MIC1(); |
| |
| break; |
| |
| case '5'://input command# echo 5 > /sys/kernel/debug/nau8810_audio |
| //Debug interface for the enable Headphone and HSMIC |
| printk(KERN_INFO "input %c. \n", msg[0]); |
| |
| //enable_voice_headphone(); |
| //enable_voice_HSMIC(); |
| mute_input_device(); |
| |
| break; |
| |
| case '6'://input command# echo 6 > /sys/kernel/debug/nau8810_audio |
| //Debug interface for disable Headphone and HSMIC |
| printk(KERN_INFO "input %c. \n", msg[0]); |
| |
| //disable_voice_headphone(); |
| //disable_voice_HSMIC(); |
| unmute_input_device(); |
| |
| break; |
| |
| default://input command# |
| printk(KERN_INFO "input invalid. \n"); |
| break; |
| } |
| |
| return tmp_count; |
| } |
| |
| static const struct file_operations nau8810_audio_ops = { |
| .owner = THIS_MODULE, |
| .open = simple_open, |
| .read = nau8810_audio_read, |
| .write = nau8810_audio_write, |
| }; |
| |
| static inline int nau8810_audio_debugfs_init(struct pm80x_chip *chip) |
| { |
| |
| nau8810_audio_control = debugfs_create_file("nau8810_audio", S_IRUGO | S_IFREG, |
| NULL, NULL, &nau8810_audio_ops); |
| |
| if (nau8810_audio_control == NULL) { |
| pr_err("create nau8810 debugfs error!\n"); |
| return -ENOENT; |
| } else if (nau8810_audio_control == ERR_PTR(-ENODEV)) { |
| pr_err("CONFIG_DEBUG_FS is not enabled!\n"); |
| return -ENOENT; |
| } |
| |
| return 0; |
| } |
| |
| static void nau8810_audio_debugfs_remove(struct pm80x_chip *chip) |
| { |
| if (NULL != nau8810_audio_control){ |
| debugfs_remove_recursive(nau8810_audio_control); |
| } |
| |
| return; |
| } |
| |
| /////////////////////////////////////////////////////////////// |
| //register codec to ALSA. |
| //////////////////////////////////////////////////////////////////// |
| //soc_codec_dev_nau8810 |
| |
| static const struct snd_kcontrol_new nau8810_snd_controls[] = { |
| |
| SOC_SINGLE("Software Reset", NAU8810_SW_RESET, 0, 0x1FF, 0), //0x0 |
| SOC_SINGLE("Power Management 1", NAU8810_POWER_MGR1, 0, 0x1FF, 0), //0x1 |
| SOC_SINGLE("Power Management 2", NAU8810_POWER_MGR2, 0, 0x1FF, 0), //0x2 |
| SOC_SINGLE("Power Management 3", NAU8810_POWER_MGR3, 0, 0x1FF, 0), //0x3 |
| SOC_SINGLE("Audio Interface", NAU8810_AUDIO_IFACE, 0, 0x1FF, 0), //0x4 |
| SOC_SINGLE("Companding", NAU8810_COMPANDING, 0, 0x1FF, 0), //0x5 |
| SOC_SINGLE("Clock Control 1", NAU8810_CLOCK_CTRL1, 0, 0x1FF, 0), //0x6 |
| SOC_SINGLE("Clock Control 2", NAU8810_CLOCK_CTRL2, 0, 0x1FF, 0), //0x7 |
| ////0x8 |
| ////0x9 |
| SOC_SINGLE("DAC CTRL", NAU8810_DAC_CTRL, 0, 0x1FF, 0), //0xa |
| SOC_SINGLE("DAC Volume", NAU8810_DAC_VOL, 0, 0x1FF, 0), //0xb |
| ////0xc |
| ////0xd |
| SOC_SINGLE("ADC CTRL", NAU8810_ADC_CTRL, 0, 0x1FF, 0), //0xe |
| SOC_SINGLE("ADC Volume", NAU8810_ADC_VOL, 0, 0x1FF, 0), //0xf |
| |
| ////0x10 |
| ////0x11 |
| SOC_SINGLE("EQ1-Low Cutoff", NAU8810_EQ1, 0, 0x1FF, 0), //0x12 |
| SOC_SINGLE("EQ2-Peak 1", NAU8810_EQ2, 0, 0x1FF, 0), //0x13 |
| SOC_SINGLE("EQ3-Peak 2", NAU8810_EQ3, 0, 0x1FF, 0), //0x14 |
| SOC_SINGLE("EQ4-Peak 3", NAU8810_EQ4, 0, 0x1FF, 0), //0x15 |
| SOC_SINGLE("EQ5-High Cutoff", NAU8810_EQ5, 0, 0x1FF, 0), //0x16 |
| ////0x17 |
| SOC_SINGLE("DAC Limiter 1", NAU8810_DAC_LIMITER1, 0, 0x1FF, 0), //0x18 |
| SOC_SINGLE("DAC Limiter 2", NAU8810_DAC_LIMITER2, 0, 0x1FF, 0), //0x19 |
| ////0x1a |
| SOC_SINGLE("Notch Filter High 1", NAU8810_NOTCH_HIGH1, 0, 0x1FF, 0), //0x1b |
| SOC_SINGLE("Notch Filter Low 1", NAU8810_NOTCH_LOW1, 0, 0x1FF, 0), //0x1c |
| SOC_SINGLE("Notch Filter High 2", NAU8810_NOTCH_HIGH2, 0, 0x1FF, 0), //0x1d |
| SOC_SINGLE("Notch Filter Low 2", NAU8810_NOTCH_LOW2, 0, 0x1FF, 0), //0x1e |
| ////0x1f |
| |
| SOC_SINGLE("ALC CTRL 1", NAU8810_ALC_CTRL1, 0, 0x1FF, 0), //0x20 |
| SOC_SINGLE("ALC CTRL 2", NAU8810_ALC_CTRL2, 0, 0x1FF, 0), //0x21 |
| SOC_SINGLE("ALC CTRL 3", NAU8810_ALC_CTRL3, 0, 0x1FF, 0), //0x22 |
| SOC_SINGLE("Noise Gate", NAU8810_NOISE_GATE, 0, 0x1FF, 0), //0x23 |
| SOC_SINGLE("PLL N CTRL", NAU8810_PLLN_CTRL, 0, 0x1FF, 0), //0x24 |
| SOC_SINGLE("PLL K 1", NAU8810_PLLK1, 0, 0x1FF, 0), //0x25 |
| SOC_SINGLE("PLL K 2", NAU8810_PLLK2, 0, 0x1FF, 0), //0x26 |
| SOC_SINGLE("PLL K 3", NAU8810_PLLK3, 0, 0x1FF, 0), //0x27 |
| SOC_SINGLE("Attenuation CTRL", NAU8810_ATTEN_CTRL, 0, 0x1FF, 0), //0x28 |
| ////0x29 |
| ////0x2a |
| ////0x2b |
| SOC_SINGLE("Input CTRL", NAU8810_INPUT_CTRL, 0, 0x1FF, 0), //0x2c |
| SOC_SINGLE("PGA Gain", NAU8810_PGA_GAIN, 0, 0x1FF, 0), //0x2d |
| ////0x2e |
| SOC_SINGLE("ADC Boost", NAU8810_ADC_BOOST, 0, 0x1FF, 0), //0x2f |
| |
| ////0x30 |
| SOC_SINGLE("Output CTRL", NAU8810_OUTPUT_CTRL, 0, 0x1FF, 0), //0x31 |
| SOC_SINGLE("Mixer CTRL", NAU8810_MIXER_CTRL, 0, 0x1FF, 0), //0x32 |
| ////0x33 |
| ////0x34 |
| ////0x35 |
| SOC_SINGLE("SPKOUT Volume", NAU8810_SPKOUT_VOL, 0, 0x1FF, 0), //0x36 |
| ////0x37 |
| SOC_SINGLE("MONO Mixer Control", NAU8810_MONO_MIXER_CTRL, 0, 0x1FF, 0), //0x38 |
| ////0x39 |
| SOC_SINGLE("Power Management 4", NAU8810_PWR_MGR4, 0, 0x1FF, 0), //0x3a |
| SOC_SINGLE("Time Slot", NAU8810_TIMESLOT, 0, 0x1FF, 0), //0x3b |
| SOC_SINGLE("ADCOUT Drive", NAU8810_ADCOUT_DRV, 0, 0x1FF, 0), //0x3c |
| ////0x3d |
| SOC_SINGLE("Silicon Revision", NAU8810_SILICON_REVISION, 0, 0x1FF, 0), //0x3e |
| SOC_SINGLE("NAU8810 2-Wire ID", NAU8810_2WIRE_ID, 0, 0x1FF, 0), //0x3f |
| |
| SOC_SINGLE("Additional ID", NAU8810_ADDITIONAL_ID, 0, 0x1FF, 0), //0x40 |
| SOC_SINGLE("Reserved", NAU8810_RESERVED, 0, 0x1FF, 0), //0x41 |
| ////0x42 |
| ////0x43 |
| ////0x44 |
| SOC_SINGLE("High Voltage CTRL", NAU8810_HIGH_VOL_CTRL, 0, 0x1FF, 0), //0x45 |
| SOC_SINGLE("ALC Enhancements 1", NAU8810_ALC_ENHANCEMENT1, 0, 0x1FF, 0), //0x46 |
| SOC_SINGLE("ALC Enhancements 2", NAU8810_ALC_ENHANCEMENT2, 0, 0x1FF, 0), //0x47 |
| ////0x48 |
| SOC_SINGLE("Additional IF CTRL", NAU8810_ADDITIONAL_IF_CTRL, 0, 0x1FF, 0), //0x49 |
| ////0x4a |
| SOC_SINGLE("Power/Tie-off CTRL", NAU8810_PWR_CTRL, 0, 0x1FF, 0), //0x4b |
| SOC_SINGLE("AGC P2P Detector", NAU8810_AGC_P2P_DETECTOR, 0, 0x1FF, 0), //0x4c |
| SOC_SINGLE("AGC Peak Detector", NAU8810_AGC_PEAK_DETECTOR, 0, 0x1FF, 0), //0x4d |
| SOC_SINGLE("Control and Status", NAU8810_CTRL_STATUS, 0, 0x1FF, 0), //0x4e |
| SOC_SINGLE("Output tie-off CTRL", NAU8810_OUTPUT_TIEOFF_CTRL, 0, 0x1FF, 0),//0x4f |
| |
| }; |
| |
| |
| |
| static int nau8810_codec_probe(struct snd_soc_component *component) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| snd_soc_add_component_controls(component, nau8810_snd_controls, ARRAY_SIZE(nau8810_snd_controls)); |
| |
| return 0; |
| } |
| |
| |
| extern char * get_MCLK_start_addr(void); |
| #ifdef CONFIG_CPU_ASR1901 |
| extern int enable_pmu_audio_clk(void); |
| #endif |
| |
| void enable_8810_MClock(void) |
| { |
| #ifdef NAU8810_DEBUG_CLOSE |
| int reg_value = 0; |
| |
| printk(KERN_INFO"enable_8810_MClock, g_8810_mclk_type=%d, Audio_Codec_Fsync_Rate=%d\n", g_8810_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 */ |
| __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 |
| |
| nau8810_write(0x73, 0x1002); |
| nau8810_write(0x80, 0x4000);//2.MCLK 3.84MHz for PLL |
| //nau8810_write(0x80, 0x5000);//3.BCLK 3.84MHz for PLL |
| nau8810_write(0x81, 0x3F02); |
| nau8810_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__); |
| |
| struct clk * mclk = devm_clk_get(&g_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_8810_mclk_type){ |
| |
| if(0 == Audio_Codec_Fsync_Rate){ |
| /*i2s_sysclk = 2M for 8k*/ |
| |
| #ifdef NAU8810_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 |
| clk_set_rate(mclk, 12000000); |
| int rate = clk_get_rate(mclk); |
| printk(KERN_INFO"mclk rate is %d", rate); |
| /* write value to register */ |
| //*(volatile unsigned int *)i2s_clk_reg = 0xF820130B; |
| |
| #ifdef NAU8810_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 NAU8810_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, 12000000); |
| int rate = clk_get_rate(mclk); |
| printk(KERN_INFO"mclk rate is %d", rate); |
| #ifdef NAU8810_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_8810_MClock); |
| |
| void nau8810_codec_remove(struct snd_soc_component *codec) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| } |
| |
| static unsigned int nau8810_codec_read(struct snd_soc_component *codec, unsigned int reg) |
| { |
| unsigned short out_val = 0; |
| |
| nau8810_read(reg, &out_val); |
| |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s/L%d.[0x%02x]=[0x%03x]\n", __FUNCTION__, __LINE__, reg, out_val); |
| #endif |
| |
| return out_val; |
| } |
| |
| static int nau8810_codec_write(struct snd_soc_component *codec, |
| unsigned int reg, unsigned int value) |
| { |
| int ret = 0; |
| |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s/L%d.[0x%02x]=[0x%03x]\n", __FUNCTION__, __LINE__, reg, value); |
| #endif |
| |
| ret = nau8810_write(reg, value & 0x1FF); |
| return ret; |
| } |
| |
| /////////////////////////////////////////////////////////////////////// |
| //nau8810_dai_ops |
| |
| static int nau8810_digital_mute(struct snd_soc_dai *codec_dai, int mute) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| return 0; |
| } |
| |
| static int nau8810_hw_params(struct snd_pcm_substream *substream, |
| struct snd_pcm_hw_params *params, |
| struct snd_soc_dai *dai) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| return 0; |
| } |
| |
| static int nau8810_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| return 0; |
| } |
| |
| |
| static int nau8810_set_dai_sysclk(struct snd_soc_dai *dai, |
| int clk_id, unsigned int freq, int dir) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| return 0; |
| } |
| |
| /////////////////////////////////////////////////////////////////////// |
| static struct snd_soc_component_driver soc_codec_dev_nau8810 = { |
| .probe = nau8810_codec_probe, |
| .remove = nau8810_codec_remove, |
| .read = nau8810_codec_read, |
| .write = nau8810_codec_write, |
| }; |
| |
| static struct snd_soc_dai_ops nau8810_dai_ops = { |
| .digital_mute = nau8810_digital_mute, |
| .hw_params = nau8810_hw_params, |
| .set_fmt = nau8810_set_dai_fmt, |
| .set_sysclk = nau8810_set_dai_sysclk, |
| }; |
| |
| static struct snd_soc_dai_driver nau8810_dai[] ={ |
| { |
| /* DAI I2S(SAI1) */ |
| .name = "nau8810-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 = &nau8810_dai_ops, |
| }, { |
| /* DAI PCM(SAI2) */ |
| .name = "nau8810-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 = &nau8810_dai_ops, |
| }, |
| }; |
| |
| |
| /////////////////////////////////////////////////////////////// |
| //i2c driver |
| static int nau8810_probe(struct i2c_client *client, |
| const struct i2c_device_id *id) |
| { |
| int ret = 0; |
| |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| g_client = client; |
| nau8810_dump_debugfs_init(NULL); |
| |
| nau8810_audio_debugfs_init(NULL); |
| |
| //initiate the NAU8810 codec. |
| codec_nau8810_init(); |
| |
| if (!codec_nau8810_is_connect()) { |
| printk(KERN_INFO"Please check codec nau8810 OK or not.\n"); |
| return 0; |
| } |
| |
| //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_nau8810, |
| // nau8810_dai, ARRAY_SIZE(nau8810_dai)); |
| |
| //int snd_soc_register_card(struct snd_soc_card *card) |
| ret = devm_snd_soc_register_component(&client->dev, &soc_codec_dev_nau8810, |
| nau8810_dai, ARRAY_SIZE(nau8810_dai)); |
| |
| if (ret < 0) { |
| printk(KERN_INFO"Failed to register codec nau8810.\n"); |
| } |
| |
| //enable the path. |
| //codec_nau8810_enable_path(); |
| //codec_nau8810_enable_path_app(); |
| enable_8810_MClock(); |
| return 0; |
| } |
| |
| static int nau8810_remove(struct i2c_client *client) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| nau8810_dump_debugfs_remove(NULL); |
| g_client = NULL; |
| |
| nau8810_audio_debugfs_remove(NULL); |
| |
| //disable the path. |
| //codec_nau8810_disable_path(); |
| //codec_nau8810_disable_path_app(); |
| |
| return 0; |
| } |
| |
| void nau8810_shutdown(struct i2c_client *client) |
| { |
| #ifdef NAU8810_DEBUG |
| printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__); |
| #endif |
| |
| return; |
| } |
| |
| static struct i2c_driver nau8810_driver = { |
| .driver = { |
| .name = "nau8810", |
| .owner = THIS_MODULE, |
| //.pm = &pm80x_pm_ops, |
| .of_match_table = of_match_ptr(nau8810_dt_ids), |
| }, |
| .probe = nau8810_probe, |
| .remove = nau8810_remove, |
| .shutdown = nau8810_shutdown, |
| .id_table = nau8810_id_table, |
| }; |
| |
| static int nau8810_i2c_init(void) |
| { |
| return i2c_add_driver(&nau8810_driver); |
| } |
| module_init(nau8810_i2c_init); |
| |
| static void nau8810_i2c_exit(void) |
| { |
| i2c_del_driver(&nau8810_driver); |
| } |
| module_exit(nau8810_i2c_exit); |
| |
| MODULE_DESCRIPTION("Driver for nau8810"); |
| MODULE_AUTHOR("wenchen@asrmicro.com"); |
| MODULE_LICENSE("GPL"); |