diff options
author | Manoj Gangwal <mgangwal@nvidia.com> | 2012-08-22 15:28:01 +0530 |
---|---|---|
committer | Simone Willett <swillett@nvidia.com> | 2012-08-27 19:08:52 -0700 |
commit | e9d6b70e5987491b9ae033e0553ea4f13824ff7e (patch) | |
tree | fd1790dbdeea29032caae5e05cb1ac91dccdb2a2 /sound | |
parent | 812e6d344d35d7ef6df9ccbeed5f6a65c53e7977 (diff) |
asoc: codecs: Add TI aic326x driver
Add latest TI aic326x driver.
Bug 1034241
Change-Id: I8457538025b2989c4baa5eaefef48bdd5535def9
Signed-off-by: Manoj Gangwal <mgangwal@nvidia.com>
Reviewed-on: http://git-master/r/125167
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Lokesh Pathak <lpathak@nvidia.com>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/codecs/Kconfig | 1 | ||||
-rw-r--r-- | sound/soc/codecs/Makefile | 3 | ||||
-rw-r--r-- | sound/soc/codecs/aic3262_codec_ops.c | 424 | ||||
-rw-r--r-- | sound/soc/codecs/aic3262_codec_ops.h | 44 | ||||
-rw-r--r-- | sound/soc/codecs/aic326x_tiload.c | 231 | ||||
-rw-r--r-- | sound/soc/codecs/aic326x_tiload.h | 5 | ||||
-rw-r--r-- | sound/soc/codecs/aic3xxx_cfw.h | 427 | ||||
-rw-r--r-- | sound/soc/codecs/aic3xxx_cfw_ops.c | 922 | ||||
-rw-r--r-- | sound/soc/codecs/aic3xxx_cfw_ops.h | 76 | ||||
-rw-r--r-- | sound/soc/codecs/tlv320aic3262_default_fw.h | 330 | ||||
-rw-r--r-- | sound/soc/codecs/tlv320aic326x.c | 5581 | ||||
-rw-r--r-- | sound/soc/codecs/tlv320aic326x.h | 645 |
12 files changed, 4168 insertions, 4521 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 7d5a66122eec..8946925ae41a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -256,6 +256,7 @@ config SND_SOC_TLV320AIC3X tristate config SND_SOC_TLV320AIC326X + select AIC3262_CODEC tristate "TI AIC326x Codec" config SND_SOC_TLV320DAC33 diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index d80b7bbff2e8..dc89ee430031 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -35,7 +35,8 @@ snd-soc-stac9766-objs := stac9766.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic26-objs := tlv320aic26.o snd-soc-tlv320aic3x-objs := tlv320aic3x.o -snd-soc-tlv320aic326x-objs := tlv320aic326x.o +snd-soc-tlv320aic326x-objs := tlv320aic326x.o aic3xxx_cfw_ops.o +snd-soc-tlv320aic326x-objs += aic3262_codec_ops.o aic326x_tiload.o snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o snd-soc-tlv320dac33-objs := tlv320dac33.o snd-soc-twl4030-objs := twl4030.o diff --git a/sound/soc/codecs/aic3262_codec_ops.c b/sound/soc/codecs/aic3262_codec_ops.c new file mode 100644 index 000000000000..45686c7aa460 --- /dev/null +++ b/sound/soc/codecs/aic3262_codec_ops.c @@ -0,0 +1,424 @@ +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/mutex.h> +#include <linux/mfd/tlv320aic3262-core.h> +#include <linux/mfd/tlv320aic3262-registers.h> +#include <sound/soc.h> +#include "aic3xxx_cfw.h" +#include "aic3xxx_cfw_ops.h" +#include "tlv320aic326x.h" +#include "aic3262_codec_ops.h" + +int aic3262_ops_reg_read(void *p, unsigned int reg) +{ + struct aic3262_priv *ps = p; + union cfw_register *c = (union cfw_register *) ® + union aic326x_reg_union mreg; + + mreg.aic326x_register.offset = c->offset; + mreg.aic326x_register.page = c->page; + mreg.aic326x_register.book = c->book; + mreg.aic326x_register.reserved = 0; + + return aic3262_reg_read(ps->codec->control_data, + mreg.aic326x_register_int); + +} +int aic3262_ops_reg_write(void *p, unsigned int reg, unsigned char mval) +{ + struct aic3262_priv *ps = p; + union aic326x_reg_union mreg; + union cfw_register *c = (union cfw_register *) ® + + mreg.aic326x_register.offset = c->offset; + mreg.aic326x_register.page = c->page; + mreg.aic326x_register.book = c->book; + mreg.aic326x_register.reserved = 0; + mval = c->data; + DBG("reg_write:page %d book %d offset %d mval : %#x\n", + mreg.aic326x_register.page, mreg.aic326x_register.book, + mreg.aic326x_register.offset, mval); + return aic3262_reg_write(ps->codec->control_data, + mreg.aic326x_register_int, mval); +} + +int aic3262_ops_set_bits(void *p, unsigned int reg, + unsigned char mask, unsigned char val) +{ + struct aic3262_priv *ps = p; + + union aic326x_reg_union mreg; + union cfw_register *c = (union cfw_register *) ® + mreg.aic326x_register.offset = c->offset; + mreg.aic326x_register.page = c->page; + mreg.aic326x_register.book = c->book; + mreg.aic326x_register.reserved = 0; + DBG("set_bits:page %d book %d offset %d mask %#x val %#x\n", + mreg.aic326x_register.page, mreg.aic326x_register.book, + mreg.aic326x_register.offset, mask, val); + + return aic3262_set_bits(ps->codec->control_data, + mreg.aic326x_register_int, mask, val); + +} + +int aic3262_ops_bulk_read(void *p, unsigned int reg, int count, u8 *buf) +{ + struct aic3262_priv *ps = p; + + union aic326x_reg_union mreg; + union cfw_register *c = (union cfw_register *) ® + mreg.aic326x_register.offset = c->offset; + mreg.aic326x_register.page = c->page; + mreg.aic326x_register.book = c->book; + mreg.aic326x_register.reserved = 0; + + return aic3262_bulk_read(ps->codec->control_data, + mreg.aic326x_register_int, count, buf); +} + +int aic3262_ops_bulk_write(void *p, unsigned int reg, int count, const u8 *buf) +{ + struct aic3262_priv *ps = p; + union aic326x_reg_union mreg; + union cfw_register *c = (union cfw_register *) ® + + mreg.aic326x_register.offset = c->offset; + mreg.aic326x_register.page = c->page; + mreg.aic326x_register.book = c->book; + mreg.aic326x_register.reserved = 0; + DBG("bulk_write: ncmd %d page %d book %d offset %d data[0] %d\n", + count, mreg.aic326x_register.page, mreg.aic326x_register.book, + mreg.aic326x_register.offset, buf[0]); + + return aic3262_bulk_write(ps->codec->control_data, + mreg.aic326x_register_int, count, buf); +} +/***************************************************************************** +Function Name : aic3262_ops_dlock_lock +Argument : pointer argument to the codec +Return value : Integer +Purpose : To Read the run state of the DAC and ADC +by reading the codec and returning the run state + +Run state Bit format + +------------------------------------------------------ +D31|..........| D7 | D6| D5 | D4 | D3 | D2 | D1 | D0 | +R R R LADC RADC R R LDAC RDAC +------------------------------------------------------ + +*******************************************************************************/ + +int aic3262_ops_lock(void *pv) +{ + int run_state = 0; + struct aic3262_priv *aic3262 = (struct aic3262_priv *)pv; + mutex_lock(&aic3262->codec->mutex); + + /* Reading the run state of adc and dac */ + run_state = get_runstate(aic3262->codec->control_data); + + return run_state; +} +/******************************************************************************* +Function name : aic3262_ops_dlock_unlock +Argument : pointer argument to the codec +Return Value : integer returning 0 +Purpose : To unlock the mutex acqiured for reading +run state of the codec + ******************************************************************************/ +int aic3262_ops_unlock(void *pv) +{ + /*Releasing the lock of mutex */ + struct aic3262_priv *aic3262 = (struct aic3262_priv *)pv; + + mutex_unlock(&aic3262->codec->mutex); + return 0; +} +/******************************************************************************* +Function Name : aic3262_ops_dlock_stop +Argument : pointer Argument to the codec +mask tells us the bit format of the +codec running state + +Bit Format: +------------------------------------------------------ +D31|..........| D7 | D6| D5 | D4 | D3 | D2 | D1 | D0 | +R R R AL AR R R DL DR +------------------------------------------------------ +R - Reserved +A - minidsp_A +D - minidsp_D + ******************************************************************************/ +int aic3262_ops_stop(void *pv, int mask) +{ + int run_state = 0; + int limask = 0; + struct aic3262_priv *aic3262 = (struct aic3262_priv *)pv; + int ret_wbits = 0; + + mutex_lock(&aic3262->codec->mutex); + run_state = get_runstate(aic3262->codec->control_data); + + limask = mask & AIC3XX_COPS_MDSP_A; + if (limask != 0) + aic3262_set_bits(aic3262->codec->control_data, + AIC3262_ADC_DATAPATH_SETUP, 0xC0, 0); + + limask = mask & AIC3XX_COPS_MDSP_D; + if (limask != 0) + aic3262_set_bits(aic3262->codec->control_data, + AIC3262_DAC_DATAPATH_SETUP, 0xC0, 0); + + limask = mask & AIC3XX_COPS_MDSP_A; + if (limask != 0) { + ret_wbits = + aic3262_wait_bits(aic3262->codec->control_data, + AIC3262_ADC_FLAG, AIC3262_ADC_POWER_MASK, + 0, TIME_DELAY, DELAY_COUNTER); + if (!ret_wbits) + dev_err(aic3262->codec->dev, + "at line %d function %s, ADC powerdown" + "wait_bits timedout\n", + __LINE__, __func__); + } + + limask = mask & AIC3XX_COPS_MDSP_D; + if (limask != 0) { + ret_wbits = + aic3262_wait_bits(aic3262->codec->control_data, + AIC3262_DAC_FLAG, AIC3262_DAC_POWER_MASK, + 0, TIME_DELAY, DELAY_COUNTER); + if (!ret_wbits) + dev_err(aic3262->codec->dev, + "at line %d function %s, DAC powerdown" + "wait_bits timedout\n", + __LINE__, __func__); + } + + return run_state; + +} +/**************************************************************************** +Function name : aic3262_ops_dlock_restore +Argument : pointer argument to the codec,run_state +Return Value : integer returning 0 +Purpose : To unlock the mutex acqiured for reading +run state of the codec and to restore the states of the dsp +******************************************************************************/ +int aic3262_ops_restore(void *pv, int run_state) +{ + int sync_state; + struct aic3262_priv *aic3262 = (struct aic3262_priv *)pv; + + /* This is for read the sync mode register state */ + sync_state = SYNC_STATE(aic3262); + + /*checking whether the sync mode has been set or + not and checking the current state */ + if (((run_state & 0x30) && (run_state & 0x03)) && (sync_state & 0x80)) + aic3262_restart_dsps_sync(pv, run_state); + else + aic3262_dsp_pwrup(pv, run_state); + + mutex_unlock(&aic3262->codec->mutex); + + return 0; +} + +/***************************************************************************** +Function name : aic3262_ops_adaptivebuffer_swap +Argument : pointer argument to the codec,mask tells us which dsp has to +be chosen for swapping +Return Value : integer returning 0 +Purpose : To swap the coefficient buffers of minidsp according to mask +******************************************************************************/ + +int aic3262_ops_adaptivebuffer_swap(void *pv, int mask) +{ + struct aic3262_priv *aic3262 = (struct aic3262_priv *)pv; + int ret_wbits = 0; + + if (mask & AIC3XX_ABUF_MDSP_A) { + aic3262_set_bits(aic3262->codec->control_data, + AIC3262_ADC_ADAPTIVE_CRAM_REG, 0x1, 0x1); + ret_wbits = + aic3262_wait_bits(aic3262->codec->control_data, + AIC3262_ADC_ADAPTIVE_CRAM_REG, 0x1, 0, 15, + 1); + if (!ret_wbits) + dev_err(aic3262->codec->dev, + "at line %d function %s, miniDSP_A buffer swap failed\n", + __LINE__, __func__); + } + + if (mask & AIC3XX_ABUF_MDSP_D1) { + aic3262_set_bits(aic3262->codec->control_data, + AIC3262_DAC_ADAPTIVE_BANK1_REG, 0x1, 0x1); + ret_wbits = + aic3262_wait_bits(aic3262->codec->control_data, + AIC3262_DAC_ADAPTIVE_BANK1_REG, 0x1, 0, + 15, 1); + if (!ret_wbits) + dev_err(aic3262->codec->dev, + "at line %d function %s, miniDSP_D buffer1 swap failed\n", + __LINE__, __func__); + } + + if (mask & AIC3XX_ABUF_MDSP_D2) { + aic3262_set_bits(aic3262->codec->control_data, + AIC3262_DAC_ADAPTIVE_BANK2_REG, 0x1, 0x1); + ret_wbits = + aic3262_wait_bits(aic3262->codec->control_data, + AIC3262_DAC_ADAPTIVE_BANK2_REG, 0x1, 0, + 15, 1); + if (!ret_wbits) + dev_err(aic3262->codec->dev, + "at line %d function %s, miniDSP_D buffer2 swap failed\n", + __LINE__, __func__); + } + + return 0; +} + +/***************************************************************************** +Function name : get_runstate +Argument : pointer argument to the codec +Return Value : integer returning the runstate +Purpose : To read the current state of the dac's and adc's +******************************************************************************/ + +int get_runstate(void *ps) +{ + struct aic3262 *pr = ps; + int run_state = 0; + int DAC_state = 0, ADC_state = 0; + /* Read the run state */ + DAC_state = aic3262_reg_read(pr, AIC3262_DAC_FLAG); + ADC_state = aic3262_reg_read(pr, AIC3262_ADC_FLAG); + + DSP_STATUS(run_state, ADC_state, 6, 5); + DSP_STATUS(run_state, ADC_state, 2, 4); + DSP_STATUS(run_state, DAC_state, 7, 1); + DSP_STATUS(run_state, DAC_state, 3, 0); + + return run_state; + +} +/**************************************************************************** +Function name : aic3262_dsp_pwrdwn_status +Argument : pointer argument to the codec , cur_state of dac's and adc's +Return Value : integer returning 0 +Purpose : To read the status of dsp's +******************************************************************************/ + +int aic3262_dsp_pwrdwn_status(void *pv) +{ + struct aic3262_priv *aic3262 = pv; + int ret_wbits = 0; + + aic3262_set_bits(aic3262->codec->control_data, + AIC3262_ADC_DATAPATH_SETUP, 0XC0, 0); + aic3262_set_bits(aic3262->codec->control_data, + AIC3262_DAC_DATAPATH_SETUP, 0XC0, 0); + + ret_wbits = + aic3262_wait_bits(aic3262->codec->control_data, AIC3262_ADC_FLAG, + AIC3262_ADC_POWER_MASK, 0, TIME_DELAY, + DELAY_COUNTER); + if (!ret_wbits) + dev_err(aic3262->codec->dev, "ADC Power down timedout\n"); + + aic3262_wait_bits(aic3262->codec->control_data, AIC3262_DAC_FLAG, + AIC3262_DAC_POWER_MASK, 0, TIME_DELAY, DELAY_COUNTER); + if (!ret_wbits) + dev_err(aic3262->codec->dev, "DAC Power down timedout\n"); + + return 0; +} + +int aic3262_dsp_pwrup(void *pv, int state) +{ + struct aic3262_priv *aic3262 = (struct aic3262_priv *)pv; + int adc_reg_mask = 0; + int adc_power_mask = 0; + int dac_reg_mask = 0; + int dac_power_mask = 0; + int ret_wbits; + + if (state & AIC3262_COPS_MDSP_A_L) { + adc_reg_mask |= 0x80; + adc_power_mask |= AIC3262_LADC_POWER_MASK; + } + if (state & AIC3262_COPS_MDSP_A_R) { + adc_reg_mask |= 0x40; + adc_power_mask |= AIC3262_RADC_POWER_MASK; + } + + if (state & AIC3262_COPS_MDSP_A) + aic3262_set_bits(aic3262->codec->control_data, + AIC3262_ADC_DATAPATH_SETUP, 0XC0, + adc_reg_mask); + + if (state & AIC3262_COPS_MDSP_D_L) { + dac_reg_mask |= 0x80; + dac_power_mask |= AIC3262_LDAC_POWER_MASK; + } + if (state & AIC3262_COPS_MDSP_D_R) { + dac_reg_mask |= 0x40; + dac_power_mask |= AIC3262_RDAC_POWER_MASK; + } + + if (state & AIC3262_COPS_MDSP_D) + aic3262_set_bits(aic3262->codec->control_data, + AIC3262_DAC_DATAPATH_SETUP, 0XC0, + dac_reg_mask); + + if (state & AIC3262_COPS_MDSP_A) { + ret_wbits = + aic3262_wait_bits(aic3262->codec->control_data, + AIC3262_ADC_FLAG, AIC3262_ADC_POWER_MASK, + adc_power_mask, TIME_DELAY, + DELAY_COUNTER); + if (!ret_wbits) + dev_err(aic3262->codec->dev, + "ADC Power down timedout\n"); + } + + if (state & AIC3262_COPS_MDSP_D) { + ret_wbits = + aic3262_wait_bits(aic3262->codec->control_data, + AIC3262_DAC_FLAG, AIC3262_DAC_POWER_MASK, + dac_power_mask, TIME_DELAY, + DELAY_COUNTER); + if (!ret_wbits) + dev_err(aic3262->codec->dev, + "ADC Power down timedout\n"); + } + + return 0; +} + +int aic3262_restart_dsps_sync(void *pv, int run_state) +{ + + aic3262_dsp_pwrdwn_status(pv); + aic3262_dsp_pwrup(pv, run_state); + + return 0; +} + +const struct aic3xxx_codec_ops aic3262_cfw_codec_ops = { + .reg_read = aic3262_ops_reg_read, + .reg_write = aic3262_ops_reg_write, + .set_bits = aic3262_ops_set_bits, + .bulk_read = aic3262_ops_bulk_read, + .bulk_write = aic3262_ops_bulk_write, + .lock = aic3262_ops_lock, + .unlock = aic3262_ops_unlock, + .stop = aic3262_ops_stop, + .restore = aic3262_ops_restore, + .bswap = aic3262_ops_adaptivebuffer_swap, +}; + diff --git a/sound/soc/codecs/aic3262_codec_ops.h b/sound/soc/codecs/aic3262_codec_ops.h new file mode 100644 index 000000000000..bec0dc817e34 --- /dev/null +++ b/sound/soc/codecs/aic3262_codec_ops.h @@ -0,0 +1,44 @@ +#define SYNC_STATE(p) aic3262_reg_read(p->codec->control_data, AIC3262_DAC_PRB) + +#define DSP_STATUS(rs, adc_dac, rpos, rspos) (rs |= \ + (((adc_dac>>rpos) & 1) << rspos)) + +#define AIC3262_COPS_MDSP_A 0x30 +#define AIC3262_COPS_MDSP_A_L 0x20 +#define AIC3262_COPS_MDSP_A_R 0x10 + +#define AIC3262_COPS_MDSP_D 0x03 +#define AIC3262_COPS_MDSP_D_L 0x02 +#define AIC3262_COPS_MDSP_D_R 0x01 + +int get_runstate(void *); + +int aic3262_dsp_pwrup(void *, int); + +int aic3262_pwr_down(void *, int, int, int, int); + +int aic3262_dsp_pwrdwn_status(void *); + +int aic3262_ops_reg_read(void *p, unsigned int reg); + +int aic3262_ops_reg_write(void *p, unsigned int reg, unsigned char mval); + +int aic3262_ops_set_bits(void *p, unsigned int reg, unsigned char mask, + unsigned char val); + +int aic3262_ops_bulk_read(void *p, unsigned int reg, int count, u8 *buf); + +int aic3262_ops_bulk_write(void *p, unsigned int reg, int count, + const u8 *buf); + +int aic3262_ops_lock(void *pv); + +int aic3262_ops_unlock(void *pv); + +int aic3262_ops_stop(void *pv, int mask); + +int aic3262_ops_restore(void *pv, int run_state); + +int aic3262_ops_adaptivebuffer_swap(void *pv, int mask); + +int aic3262_restart_dsps_sync(void *pv, int run_state); diff --git a/sound/soc/codecs/aic326x_tiload.c b/sound/soc/codecs/aic326x_tiload.c index 07615dc5ebd7..781a6cb3456e 100644 --- a/sound/soc/codecs/aic326x_tiload.c +++ b/sound/soc/codecs/aic326x_tiload.c @@ -16,9 +16,9 @@ * * History: * - * Rev 0.1 Tiload support 16-09-2010 + * Rev 0.1 Tiload support TI 16-09-2010 * - * The Tiload programming support is added to AIC3262. + * The Tiload programming support is added to AIC3262. * */ @@ -37,16 +37,21 @@ #include <linux/platform_device.h> #include <sound/soc.h> #include <sound/control.h> +#include <linux/switch.h> +#include <sound/jack.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/mfd/tlv320aic3262-core.h> #include "tlv320aic326x.h" #include "aic326x_tiload.h" /* enable debug prints in the driver */ -#define DEBUG -//#undef DEBUG +/*#define DEBUG */ +#undef DEBUG #ifdef DEBUG -#define dprintk(x...) printk(x) +#define dprintk(x...) printk(x) #else #define dprintk(x...) #endif @@ -58,17 +63,12 @@ static void aic3262_dump_page(struct i2c_client *i2c, u8 page); #endif -/* externs */ -extern int aic3262_change_page(struct snd_soc_codec *codec, u8 new_page); -extern int aic3262_change_book(struct snd_soc_codec *codec, u8 new_book); -extern int aic3262_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value); -int aic3262_driver_init(struct snd_soc_codec *codec); /************** Dynamic aic3262 driver, TI LOAD support ***************/ static struct cdev *aic3262_cdev; -static int aic3262_major = 0; /* Dynamic allocation of Mjr No. */ -static int aic3262_opened = 0; /* Dynamic allocation of Mjr No. */ +static union aic326x_reg_union aic_reg; +static int aic3262_major; /* Dynamic allocation of Mjr No. */ +static int aic3262_opened; /* Dynamic allocation of Mjr No. */ static struct snd_soc_codec *aic3262_codec; struct class *tiload_class; static unsigned int magic_num = 0xE0; @@ -77,10 +77,12 @@ static unsigned int magic_num = 0xE0; #ifdef REG_DUMP_aic3262 /* - *---------------------------------------------------------------------------- - * Function : aic3262_dump_page - * Purpose : Read and display one codec register page, for debugging purpose - *---------------------------------------------------------------------------- + * aic3262_dump_page: Read and display one codec register page, for + debugging purpose + * @i2c; i2c_client identifies a single device (i.e. aic3262) connected + to an i2c bus. + * @page: page number + * */ static void aic3262_dump_page(struct i2c_client *i2c, u8 page) { @@ -88,103 +90,99 @@ static void aic3262_dump_page(struct i2c_client *i2c, u8 page) u8 data; u8 test_page_array[8]; - dprintk("TiLoad DRIVER : %s\n", __FUNCTION__); - aic3262_change_page(codec, page); + dprintk("TiLoad DRIVER : %s\n", __func__); data = 0x0; - i2c_master_send(i2c, data, 1); i2c_master_recv(i2c, test_page_array, 8); - printk("\n------- aic3262 PAGE %d DUMP --------\n", page); - for (i = 0; i < 8; i++) { - printk(" [ %d ] = 0x%x\n", i, test_page_array[i]); - } + dprintk("\n------- aic3262 PAGE %d DUMP --------\n", page); + for (i = 0; i < 8; i++) + dprintk(" [ %d ] = 0x%x\n", i, test_page_array[i]); } #endif -/* - *---------------------------------------------------------------------------- - * Function : tiload_open +/** + * tiload_open: open method for aic3262-tiload programming interface + * @in: Pointer to inode + * @filp: pointer to file * - * Purpose : open method for aic3262-tiload programming interface - *---------------------------------------------------------------------------- + * Return: Return 0 if success. */ static int tiload_open(struct inode *in, struct file *filp) { - dprintk("TiLoad DRIVER : %s\n", __FUNCTION__); + dprintk("TiLoad DRIVER : %s\n", __func__); if (aic3262_opened) { - printk("%s device is already opened\n", "aic3262"); - printk("%s: only one instance of driver is allowed\n", - "aic3262"); + dprintk("%s device is already opened\n", "aic3262"); + dprintk("%s: only one instance of driver is allowed\n", + "aic3262"); return -1; } aic3262_opened++; return 0; } -/* - *---------------------------------------------------------------------------- - * Function : tiload_release +/** + * tiload_release close method for aic3262_tilaod programming interface + * @in: Pointer to inode + * @filp: pointer to file * - * Purpose : close method for aic3262_tilaod programming interface - *---------------------------------------------------------------------------- + * Return: Return 0 if success. */ static int tiload_release(struct inode *in, struct file *filp) { - dprintk("TiLoad DRIVER : %s\n", __FUNCTION__); + dprintk("TiLoad DRIVER : %s\n", __func__); aic3262_opened--; return 0; } -/* - *---------------------------------------------------------------------------- - * Function : tiload_read +/** + * tiload_read: read method for mini dsp programming interface + * @file: pointer to file + * @buf: pointer to user + * @count: number of byte to be read + * @offset: offset address * - * Purpose : read method for mini dsp programming interface - *---------------------------------------------------------------------------- + * Return: return value read */ -static ssize_t tiload_read(struct file *file, char __user * buf, - size_t count, loff_t * offset) +static ssize_t tiload_read(struct file *file, char __user *buf, + size_t count, loff_t *offset) { - static char rd_data[8]; + static char rd_data[128]; char reg_addr; size_t size; - #ifdef DEBUG +#ifdef DEBUG int i; - #endif - struct i2c_client *i2c = aic3262_codec->control_data; +#endif + struct aic3262 *control = aic3262_codec->control_data; - dprintk("TiLoad DRIVER : %s\n", __FUNCTION__); + dprintk("TiLoad DRIVER : %s\n", __func__); if (count > 128) { - printk("Max 128 bytes can be read\n"); + dprintk("Max 128 bytes can be read\n"); count = 128; } /* copy register address from user space */ size = copy_from_user(®_addr, buf, 1); if (size != 0) { - printk("read: copy_from_user failure\n"); + dprintk("read: copy_from_user failure\n"); return -1; } /* Send the address to device thats is to be read */ - if (i2c_master_send(i2c, ®_addr, 1) != 1) { - dprintk("Can not write register address\n"); - return -1; - } - /* read the codec device registers */ - size = i2c_master_recv(i2c, rd_data, count); + aic_reg.aic326x_register.offset = reg_addr; + size = + aic3262_bulk_read(control, aic_reg.aic326x_register_int, count, + rd_data); + #ifdef DEBUG - printk(KERN_ERR "read size = %d, reg_addr= %x , count = %d\n", - (int)size, reg_addr, (int)count); - for (i = 0; i < (int)size; i++) { - printk(KERN_ERR "rd_data[%d]=%x\n", i, rd_data[i]); - } + pr_err(KERN_ERR "read size = %d, reg_addr= %x , count = %d\n", + (int)size, reg_addr, (int)count); + for (i = 0; i < (int)size; i++) + dprintk("rd_data[%d]=%x\n", i, rd_data[i]); #endif - if (size != count) { - printk("read %d registers from the codec\n", size); - } + if (size != count) + dprintk("read %d registers from the codec\n", size); if (copy_to_user(buf, rd_data, size) != 0) { dprintk("copy_to_user failed\n"); @@ -194,58 +192,71 @@ static ssize_t tiload_read(struct file *file, char __user * buf, return size; } -/* - *---------------------------------------------------------------------------- - * Function : tiload_write +/** + * tiload_write: write method for aic3262_tiload programming interface + * @file: pointer to file + * @buf: pointer to user + * @count: number of byte to be read + * @offset: offset address * - * Purpose : write method for aic3262_tiload programming interface - *---------------------------------------------------------------------------- + * Return: return byte written */ -static ssize_t tiload_write(struct file *file, const char __user * buf, - size_t count, loff_t * offset) +static ssize_t tiload_write(struct file *file, const char __user *buf, + size_t count, loff_t *offset) { - static char wr_data[8]; - u8 pg_no; - #ifdef DEBUG + static char wr_data[128]; +#ifdef DEBUG int i; - #endif - struct i2c_client *i2c = aic3262_codec->control_data; - struct aic3262_priv *aic3262_private = snd_soc_codec_get_drvdata(aic3262_codec); +#endif + struct aic3262 *control = aic3262_codec->control_data; - dprintk("TiLoad DRIVER : %s\n", __FUNCTION__); + dprintk("TiLoad DRIVER : %s\n", __func__); /* copy buffer from user space */ if (copy_from_user(wr_data, buf, count)) { - printk("copy_from_user failure\n"); + dprintk("copy_from_user failure\n"); return -1; } #ifdef DEBUG - printk(KERN_ERR "write size = %d\n", (int)count); - for (i = 0; i < (int)count; i++) { - printk(KERN_INFO "\nwr_data[%d]=%x\n", i, wr_data[i]); - } + dprintk("write size = %d\n", (int)count); + for (i = 0; i < (int)count; i++) + dprintk("\nwr_data[%d]=%x\n", i, wr_data[i]); #endif if (wr_data[0] == 0) { - aic3262_change_page(aic3262_codec, wr_data[1]); + /*change of page seen, but will only be registered */ + aic_reg.aic326x_register.page = wr_data[1]; + return count; + + } else + if (wr_data[0] == 127) { + /* change of book seen, but will not be sent for I2C write */ + aic_reg.aic326x_register.book = wr_data[1]; return count; - } - pg_no = aic3262_private->page_no; - if ((wr_data[0] == 127) && (pg_no == 0)) { - aic3262_change_book(aic3262_codec, wr_data[1]); + } else { + aic_reg.aic326x_register.offset = wr_data[0]; + aic3262_bulk_write(control, aic_reg.aic326x_register_int, + count - 1, &wr_data[1]); return count; } - return i2c_master_send(i2c, wr_data, count); } -static long tiload_ioctl(struct file *filp, - unsigned int cmd, unsigned long arg) +/** + * tiload_ioctl: copy data to user and from user + * @filp: pointer to file + * @cmd: integer of type command + * @arg: argument type + * + * Return: Return 0 on success + */ +static long tiload_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int num = 0; void __user *argp = (void __user *)arg; + if (_IOC_TYPE(cmd) != aic3262_IOC_MAGIC) return -ENOTTY; - dprintk("TiLoad DRIVER : %s\n", __FUNCTION__); + dprintk("TiLoad DRIVER : %s\n", __func__); switch (cmd) { case aic3262_IOMAGICNUM_GET: num = copy_to_user(argp, &magic_num, sizeof(int)); @@ -257,7 +268,7 @@ static long tiload_ioctl(struct file *filp, return num; } -/*********** File operations structure for aic3262-tiload programming *************/ +/******* File operations structure for aic3262-tiload programming *********/ static struct file_operations aic3262_fops = { .owner = THIS_MODULE, .open = tiload_open, @@ -267,46 +278,48 @@ static struct file_operations aic3262_fops = { .unlocked_ioctl = tiload_ioctl, }; -/* - *---------------------------------------------------------------------------- - * Function : aic3262_driver_init +/** + * aic3262_driver_init: Register a char driver for dynamic aic3262-tiload programming + * @codec: pointer variable to codec having codec information * - * Purpose : Register a char driver for dynamic aic3262-tiload programming - *---------------------------------------------------------------------------- + * Return: Return 0 on seccess */ int aic3262_driver_init(struct snd_soc_codec *codec) { int result; dev_t dev = MKDEV(aic3262_major, 0); - printk("TiLoad DRIVER : %s\n", __FUNCTION__); + dprintk("TiLoad DRIVER : %s\n", __func__); aic3262_codec = codec; - printk("allocating dynamic major number\n"); + dprintk("allocating dynamic major number\n"); result = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME); if (result < 0) { - printk("cannot allocate major number %d\n", aic3262_major); + dprintk("cannot allocate major number %d\n", aic3262_major); return result; } + tiload_class = class_create(THIS_MODULE, DEVICE_NAME); aic3262_major = MAJOR(dev); - printk("allocated Major Number: %d\n", aic3262_major); + dprintk("allocated Major Number: %d\n", aic3262_major); aic3262_cdev = cdev_alloc(); cdev_init(aic3262_cdev, &aic3262_fops); aic3262_cdev->owner = THIS_MODULE; aic3262_cdev->ops = &aic3262_fops; + aic_reg.aic326x_register.page = 0; + aic_reg.aic326x_register.book = 0; + if (cdev_add(aic3262_cdev, dev, 1) < 0) { - dprintk("aic3262_driver: cdev_add failed \n"); + dprintk("aic3262_driver: cdev_add failed\n"); unregister_chrdev_region(dev, 1); aic3262_cdev = NULL; return 1; } - printk("Registered aic3262 TiLoad driver, Major number: %d \n", - aic3262_major); - //class_device_create(tiload_class, NULL, dev, NULL, DEVICE_NAME, 0); + dprintk("Registered aic3262 TiLoad driver, Major number: %d\n", + aic3262_major); return 0; } diff --git a/sound/soc/codecs/aic326x_tiload.h b/sound/soc/codecs/aic326x_tiload.h index 6621a4127b16..c11d8a2d06f7 100644 --- a/sound/soc/codecs/aic326x_tiload.h +++ b/sound/soc/codecs/aic326x_tiload.h @@ -2,7 +2,7 @@ * linux/sound/soc/codecs/aic3262_tiload.h * * - * Copyright (C) 2012 Texas Instruments, Inc. + * Copyright (C) 2011 Texas Instruments Inc. * * * @@ -24,9 +24,6 @@ #ifndef _AIC3262_TILOAD_H #define _AIC3262_TILOAD_H -/* typedefs required for the included header files */ -typedef char *string; - /* defines */ #define DEVICE_NAME "tiload_node" #define aic3262_IOC_MAGIC 0xE0 diff --git a/sound/soc/codecs/aic3xxx_cfw.h b/sound/soc/codecs/aic3xxx_cfw.h new file mode 100644 index 000000000000..12bc85575195 --- /dev/null +++ b/sound/soc/codecs/aic3xxx_cfw.h @@ -0,0 +1,427 @@ +/** + * \file Codec Firmware Declarations + */ + +#ifndef CFW_FIRMWARE_H_ +#define CFW_FIRMWARE_H_ +/** \defgroup bt Basic Types */ +/* @{ */ +#ifndef AIC3XXX_CFW_HOST_BLD +#include <asm-generic/int-ll64.h> +#else +typedef unsigned char u8; +typedef unsigned short int u16; +typedef unsigned long int u32; +#endif + +#define CFW_FW_MAGIC 0xC0D1F1ED + +/** defgroup pd Arbitrary Limitations */ + +#ifndef CFW_MAX_ID +#define CFW_MAX_ID (64) /* Max length of string identifies */ +#endif + +#ifndef CFW_MAX_DESC +#define CFW_MAX_DESC (512) /* Max length of description */ +#endif +/* <Max number of overlays per PFW */ +#ifndef CFW_MAX_NOVLY +#define CFW_MAX_NOVLY (4) +#endif + +#ifndef CFW_MAX_NCFG +#define CFW_MAX_NCFG (16) /* Max number of configurations per PFW */ +#endif + +#ifndef CFW_MAX_TRANSITIONS +#define CFW_MAX_TRANSITIONS (32) /* max number of pre-defined transition */ +#endif + +#ifndef CFW_MAX_NPFW +#define CFW_MAX_NPFW (16) /* Max number fo process flows */ +#endif + +#ifndef CFW_MAX_MODES +#define CFW_MAX_MODES (32) /* Max number of modes */ +#endif + +#ifndef CFW_MAX_ASI +#define CFW_MAX_ASI (4) /* Max number ASIs in a single device */ +#endif + + +#ifndef CFW_MAX_CTRL +#define CFW_MAX_CTRL (16) /* Max number of control per pfw */ +#endif + +/** defgroup st Enums, Flags, Macros and Supporting Types */ + +/** + * Sample rate bitmask + * + */ +enum cfw_fs { + CFW_FS_8KHZ = 0x0001u, + CFW_FS_11KHZ = 0x0002u, + CFW_FS_16KHZ = 0x0004u, + CFW_FS_22KHZ = 0x0008u, + CFW_FS_24KHZ = 0x0010u, + CFW_FS_32KHZ = 0x0020u, + CFW_FS_44KHZ = 0x0040u, + CFW_FS_48KHZ = 0x0080u, + CFW_FS_88KHZ = 0x0100u, + CFW_FS_96KHZ = 0x0200u, + CFW_FS_176KHZ = 0x0400u, + CFW_FS_192KHZ = 0x0800u, + CFW_FS_ANY = 0x8000u, + CFW_FS_ALL = 0x0FFFu, +}; + +/** + * Sample rate index + * + */ +enum cfw_fsi { + CFW_FSI_8KHZ, + CFW_FSI_11KHZ, + CFW_FSI_16KHZ, + CFW_FSI_22KHZ, + CFW_FSI_24KHZ, + CFW_FSI_32KHZ, + CFW_FSI_44KHZ, + CFW_FSI_48KHZ, + CFW_FSI_88KHZ, + CFW_FSI_96KHZ, + CFW_FSI_176KHZ, + CFW_FSI_192KHZ, + CFW_FSI_ANY = 15, +}; + +/** + * Device Family Identifier + * + */ +enum __attribute__ ((__packed__)) cfw_dfamily { + CFW_DFM_TYPE_A, + CFW_DFM_TYPE_B, + CFW_DFM_TYPE_C +}; + +/** + * Device Identifier + * + */ +enum __attribute__ ((__packed__)) cfw_device { + CFW_DEV_DAC3120, + CFW_DEV_DAC3100, + + CFW_DEV_AIC3120, + CFW_DEV_AIC3100, + CFW_DEV_AIC3110, + CFW_DEV_AIC3111, + + CFW_DEV_AIC36, + + CFW_DEV_AIC3206, + CFW_DEV_AIC3204, + CFW_DEV_AIC3254, + CFW_DEV_AIC3256, + CFW_DEV_AIC3253, + + CFW_DEV_AIC3212, + CFW_DEV_AIC3262, + CFW_DEV_AIC3017, + CFW_DEV_AIC3008, + +}; + +/** + * Transition Sequence Identifier + * + */ +enum cfw_transition_t { + CFW_TRN_INIT, + CFW_TRN_RESUME, + CFW_TRN_NEUTRAL, + CFW_TRN_A_MUTE, + CFW_TRN_D_MUTE, + CFW_TRN_AD_MUTE, + CFW_TRN_A_UNMUTE, + CFW_TRN_D_UNMUTE, + CFW_TRN_AD_UNMUTE, + CFW_TRN_SUSPEND, + CFW_TRN_EXIT, + CFW_TRN_N +}; + +static const char * const cfw_transition_id[] = { + [CFW_TRN_INIT] "INIT", + [CFW_TRN_RESUME] "RESUME", + [CFW_TRN_NEUTRAL] "NEUTRAL", + [CFW_TRN_A_MUTE] "A_MUTE", + [CFW_TRN_D_MUTE] "D_MUTE", + [CFW_TRN_AD_MUTE] "AD_MUTE", + [CFW_TRN_A_UNMUTE] "A_UNMUTE", + [CFW_TRN_D_UNMUTE] "D_UNMUTE", + [CFW_TRN_AD_UNMUTE] "AD_UNMUTE", + [CFW_TRN_SUSPEND] "SUSPEND", + [CFW_TRN_EXIT] "EXIT", +}; + +/** defgroup ds Data Structures */ + +/** +* CFW Meta Command +* These commands do not appear in the register +* set of the device. +* Mainly delay, wait and set_bits. +*/ +enum __attribute__ ((__packed__)) cfw_meta_cmd { + CFW_META_DELAY = 0x80, + CFW_META_UPDTBITS, + CFW_META_WAITBITS, + CFW_META_LOCK, +}; + +/** +* CFW Delay +* Used for the meta command delay +* Has one parameter of delay time in ms +*/ +struct cfw_meta_delay { + u16 delay; + enum cfw_meta_cmd mcmd; + u8 unused1; +}; + +/** +* CFW set_bits or wait +* Both these meta commands have same arguments +* mcmd will be used to specify which command it is +* has parameters of book, page, offset and mask +*/ +struct cfw_meta_bitop { + u16 unused1; + enum cfw_meta_cmd mcmd; + u8 mask; +}; + +/** +* CFW meta register +* Contains the data structures for the meta commands +*/ +union cfw_meta_register { + struct { + u16 unused1; + enum cfw_meta_cmd mcmd; + u8 unused2; + }; + struct cfw_meta_delay delay; + struct cfw_meta_bitop bitop; +}; + +/** + * CFW Register + * + * A single reg write + * + */ +union cfw_register { + struct { + u8 book; + u8 page; + u8 offset; + u8 data; + }; + u32 bpod; + union cfw_meta_register meta; +}; + +/** + * CFW Burst + * + * A single I2C/SPI burst write sequence + * + */ +struct cfw_burst { + u32 length; + union { + union cfw_register reg; + struct { + u8 bpo[3]; + u8 data[1]; + }; + }; +}; + +/** + * CFW Command + * + * Can be a either a + * -# single register write, + * -# a burst write, or + * -# meta-command + * + */ +union cfw_cmd { + union cfw_register reg; + struct cfw_burst *burst; +}; + +/** + * CFW Block Type + * + * Block identifier + * + */ +enum __attribute__ ((__packed__)) cfw_block_t { + CFW_BLOCK_SYSTEM_PRE, + CFW_BLOCK_A_INST, + CFW_BLOCK_A_A_COEF, + CFW_BLOCK_A_B_COEF, + CFW_BLOCK_A_F_COEF, + CFW_BLOCK_D_INST, + CFW_BLOCK_D_A1_COEF, + CFW_BLOCK_D_B1_COEF, + CFW_BLOCK_D_A2_COEF, + CFW_BLOCK_D_B2_COEF, + CFW_BLOCK_D_F_COEF, + CFW_BLOCK_SYSTEM_POST, + CFW_BLOCK_N, + CFW_BLOCK_INVALID, + CFW_BLOCK_BURSTS = 0x80 +}; +#define CFW_BLOCK_BURSTS(x) ((x)&CFW_BLOCK_BURSTS) +#define CFW_BLOCK_TYPE(x) ((x)&(~CFW_BLOCK_BURSTS)) +#define CFW_BLOCK_D_A_COEF CFW_BLOCK_D_A1_COEF +#define CFW_BLOCK_D_B_COEF CFW_BLOCK_D_B1_COEF + +/** + * CFW Block + * + * A block of logically grouped sequences/commands/meta-commands + * + */ +struct cfw_block { + enum cfw_block_t type; + int ncmds; + union cfw_cmd cmd[]; +}; + +/** + * CFW Image + * + * A downloadable image + */ +struct cfw_image { + char name[CFW_MAX_ID]; /* Name of the pfw/overlay/configuration */ + char desc[CFW_MAX_DESC]; /* User string */ + int mute_flags; + struct cfw_block *block[CFW_BLOCK_N]; +}; + +struct cfw_control { + char name[CFW_MAX_ID]; /* Control identifier */ + char desc[CFW_MAX_DESC];/* User string */ + int mute_flags; + + int min; /* Min value of control (*100) */ + int max; /* Max value of control (*100) */ + int step; /* Control step size (*100) */ + + int imax; /* Max index into controls array */ + int ireset; /* Reset control to defaults */ + int icur; /* Last value set */ + struct cfw_block **output; /* Array of sequences to send */ +}; + +/** + * Process flow + * + * Complete description of a process flow + */ +struct cfw_pfw { + char name[CFW_MAX_ID]; /* Name of the process flow */ + char desc[CFW_MAX_DESC]; /* User string */ + u32 version; + u8 prb_a; + u8 prb_d; + int novly; /* Number of overlays (1 or more) */ + int ncfg; /* Number of configurations (0 or more) */ + int nctrl; /* Number of run-time controls */ + struct cfw_block *pll; + struct cfw_image *base; /* Base sequence */ + /* Overlay and cfg */ + struct cfw_image *ovly_cfg[CFW_MAX_NOVLY][CFW_MAX_NCFG]; + /* Array of run-time controls */ + struct cfw_control *ctrl[CFW_MAX_CTRL]; +}; + +/** + * Process transition + * + * Sequence for specific state transisitions within the driver + * + */ +struct cfw_transition { + char name[CFW_MAX_ID]; /* Name of the transition */ + char desc[CFW_MAX_DESC]; /* User string */ + struct cfw_block *block; +}; + +/** + * Device audio mode + * + * Structure linking various operating modes to process flows, + * configurations and sequences + * + */ +struct cfw_mode { + char name[CFW_MAX_ID]; + char desc[CFW_MAX_DESC]; /* User string */ + u32 flags; + u8 pfw; + u8 ovly; + u8 cfg; + struct cfw_block *entry; + struct cfw_block *exit; +}; + +struct cfw_asoc_toc_entry { + char etext[CFW_MAX_ID]; + int mode; + int cfg; +}; + +struct cfw_asoc_toc { + int nentries; + struct cfw_asoc_toc_entry entry[]; +}; + +/** + * CFW Project + * + * Top level structure describing the CFW project + */ +struct cfw_project { + u32 magic; + u32 bmagic; + u32 size; + u32 cksum; + u32 version; + u32 tstamp; + char name[CFW_MAX_ID]; /* Project name */ + char desc[CFW_MAX_DESC]; /* User string */ + enum cfw_dfamily dfamily; + enum cfw_device device; + u32 flags; + struct cfw_transition *transition[CFW_MAX_TRANSITIONS]; + u16 npfw; /* Number of process flows */ + u16 nmode; /* Number of operating modes */ + struct cfw_pfw *pfw[CFW_MAX_NPFW]; /* Indices to PFW locations */ + struct cfw_mode *mode[CFW_MAX_MODES]; + struct cfw_asoc_toc *asoc_toc; +}; + +#endif /* CFW_FIRMWARE_H_ */ diff --git a/sound/soc/codecs/aic3xxx_cfw_ops.c b/sound/soc/codecs/aic3xxx_cfw_ops.c new file mode 100644 index 000000000000..83bcdf1d69bc --- /dev/null +++ b/sound/soc/codecs/aic3xxx_cfw_ops.c @@ -0,0 +1,922 @@ +#ifndef AIC3XXX_CFW_HOST_BLD +# include <linux/module.h> +# include <linux/delay.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <linux/slab.h> +#include <sound/tlv.h> +# define warn(fmt, ...) printk(fmt "\n", ##__VA_ARGS__) +# define error(fmt, ...) printk(fmt "\n", ##__VA_ARGS__) + +#else +# define _GNU_SOURCE +# include <stdlib.h> +# include "utils.h" +# include <string.h> +# include <assert.h> +# define EINVAL 1 + +#endif + +#include "aic3xxx_cfw.h" +#include "aic3xxx_cfw_ops.h" +#ifndef AIC3XXX_CFW_HOST_BLD +static struct cfw_project *aic3xxx_cfw_unpickle(void *pcfw, int n); +#endif + + +/* + * Firmware version numbers are used to make sure that the + * host and target code stay in sync. It is _not_ recommended + * to provide this number from the outside (E.g., from a makefile) + * Instead, a set of automated tools are relied upon to keep the numbers + * in sync at the time of host testing. + */ +#define CFW_FW_VERSION 0x000100B3 + +static int aic3xxx_cfw_dlimage(struct cfw_state *ps, struct cfw_image *pim); +static int aic3xxx_cfw_dlcfg(struct cfw_state *ps, struct cfw_image *pim); +static int aic3xxx_cfw_dlctl(struct cfw_state *ps, struct cfw_block *pb, + u32 mute_flags); +static void aic3xxx_cfw_dlcmds(struct cfw_state *ps, struct cfw_block *pb); +static void aic3xxx_wait(struct cfw_state *ps, unsigned int reg, u8 mask, + u8 data); +static int aic3xxx_cfw_set_mode_id(struct cfw_state *ps); +static int aic3xxx_cfw_mute(struct cfw_state *ps, int mute, u32 flags); +static int aic3xxx_cfw_setmode_cfg_u(struct cfw_state *ps, int mode, int cfg); +static int aic3xxx_cfw_setcfg_u(struct cfw_state *ps, int cfg); +static int aic3xxx_cfw_transition_u(struct cfw_state *ps, char *ttype); +static int aic3xxx_cfw_set_pll_u(struct cfw_state *ps, int asi); +static int aic3xxx_cfw_control_u(struct cfw_state *ps, char *cname, int param); + + +#if defined(AIC3XXX_CFW_HOST_BLD) + +static int mutex_init(struct mutex *m) +{ + m->lock = 0; + return 0; +} + +static int mutex_lock(struct mutex *m) +{ + assert(m->lock == 0); + m->lock = 1; + return 0; +} + +static int mutex_unlock(struct mutex *m) +{ + assert(m->lock == 1); + m->lock = 0; + return 0; +} +/* +static void mdelay(int val) +{ + int i; + for (i = 0; i < (val * 10); i++); +} +*/ +#endif + +int aic3xxx_cfw_init(struct cfw_state *ps, struct aic3xxx_codec_ops const *ops, + void *ops_obj) +{ + ps->ops = ops; + ps->ops_obj = ops_obj; + ps->pjt = NULL; + mutex_init(&ps->mutex); + return 0; +} + +int aic3xxx_cfw_lock(struct cfw_state *ps, int lock) +{ + if (lock) + mutex_lock(&ps->mutex); + else + mutex_unlock(&ps->mutex); + return 0; +} + +int aic3xxx_cfw_reload(struct cfw_state *ps, void *pcfw, int n) +{ + ps->pjt = aic3xxx_cfw_unpickle(pcfw, n); + ps->cur_mode_id = + ps->cur_mode = ps->cur_pfw = ps->cur_ovly = ps->cur_cfg = -1; + if (ps->pjt == NULL) + return -1; + return 0; +} + +int aic3xxx_cfw_setmode(struct cfw_state *ps, int mode) +{ + struct cfw_project *pjt; + int ret; + + aic3xxx_cfw_lock(ps, 1); + pjt = ps->pjt; + if (pjt == NULL) { + aic3xxx_cfw_lock(ps, 0); + return -1; + } + ret = aic3xxx_cfw_setmode_cfg_u(ps, mode, pjt->mode[mode]->cfg); + aic3xxx_cfw_lock(ps, 0); + return ret; +} + +int aic3xxx_cfw_setcfg(struct cfw_state *ps, int cfg) +{ + int ret; + + aic3xxx_cfw_lock(ps, 1); + ret = aic3xxx_cfw_setcfg_u(ps, cfg); + aic3xxx_cfw_lock(ps, 0); + return ret; +} + +static int aic3xxx_cfw_setcfg_u(struct cfw_state *ps, int cfg) +{ + struct cfw_project *pjt = ps->pjt; + struct cfw_pfw *pfw; + + if (pjt == NULL) + return -1; + if (ps->cur_pfw < 0 || ps->cur_pfw >= pjt->npfw) + return -1; + if (ps->cur_cfg == cfg) + return 0; + pfw = pjt->pfw[ps->cur_pfw]; + if (pfw->ncfg == 0 && cfg != 0) + return -1; + if (cfg > 0 && cfg >= pfw->ncfg) + return -1; + ps->cur_cfg = cfg; + aic3xxx_cfw_set_mode_id(ps); + if (pfw->ncfg != 0) + return aic3xxx_cfw_dlcfg(ps, + pfw->ovly_cfg[ps->cur_ovly][ps-> + cur_cfg]); + return 0; +} + +int aic3xxx_cfw_setmode_cfg(struct cfw_state *ps, int mode, int cfg) +{ + int ret; + + aic3xxx_cfw_lock(ps, 1); + ret = aic3xxx_cfw_setmode_cfg_u(ps, mode, cfg); + aic3xxx_cfw_lock(ps, 0); + return ret; +} + +static int aic3xxx_cfw_setmode_cfg_u(struct cfw_state *ps, int mode, int cfg) +{ + struct cfw_project *pjt = ps->pjt; + int which = 0; + struct cfw_pfw *pfw; + struct cfw_image *im; + + if (pjt == NULL) + return -1; + if ((mode < 0) || (mode >= pjt->nmode)) + return -1; + if (cfg < 0) + return -1; + if (mode == ps->cur_mode) + return aic3xxx_cfw_setcfg_u(ps, cfg); + + /* Apply exit sequence for previous mode if present */ + if (ps->cur_mode >= 0 && pjt->mode[ps->cur_mode]->exit) + aic3xxx_cfw_dlcmds(ps, pjt->mode[ps->cur_mode]->exit); + + if (pjt->mode[mode]->pfw < pjt->npfw) { + /* New mode uses miniDSP */ + pfw = pjt->pfw[pjt->mode[mode]->pfw]; + /* Make sure cfg is valid and supported in this mode */ + if (pfw->ncfg == 0 && cfg != 0) + return -1; + if (cfg > 0 && cfg >= pfw->ncfg) + return -1; + /* + * Decisions about which miniDSP to stop/restart are taken + * on the basis of sections present in the _base_ image + * This allows for correct sync mode operation even in cases + * where the base PFW uses both miniDSPs where a particular + * overlay applies only to one + */ + im = pfw->base; + if (im->block[CFW_BLOCK_A_INST]) + which |= AIC3XX_COPS_MDSP_A; + if (im->block[CFW_BLOCK_D_INST]) + which |= AIC3XX_COPS_MDSP_D; + + /* New mode requires different PFW */ + if (pjt->mode[mode]->pfw != ps->cur_pfw) { + ps->cur_pfw = pjt->mode[mode]->pfw; + ps->cur_ovly = 0; + ps->cur_cfg = 0; + + which = ps->ops->stop(ps->ops_obj, which); + aic3xxx_cfw_dlimage(ps, im); + if (pjt->mode[mode]->ovly + && pjt->mode[mode]->ovly < pfw->novly) { + /* New mode uses ovly */ + if (pfw->ovly_cfg[pjt->mode[mode] + ->ovly][cfg] != NULL) + aic3xxx_cfw_dlimage(ps, + pfw->ovly_cfg[pjt-> + mode[mode]-> + ovly][cfg]); + } else if (pfw->ncfg > 0) { + /* new mode needs only a cfg change */ + aic3xxx_cfw_dlimage(ps, pfw->ovly_cfg[0][cfg]); + } + ps->ops->restore(ps->ops_obj, which); + + } else if (pjt->mode[mode]->ovly != ps->cur_ovly) { + /* New mode requires only an ovly change */ + which = ps->ops->stop(ps->ops_obj, which); + aic3xxx_cfw_dlimage(ps, + pfw->ovly_cfg[pjt->mode[mode]-> + ovly][cfg]); + ps->ops->restore(ps->ops_obj, which); + } else if (pfw->ncfg > 0 && cfg != ps->cur_cfg) { + /* New mode requires only a cfg change */ + aic3xxx_cfw_dlcfg(ps, + pfw->ovly_cfg[pjt->mode[mode]-> + ovly][cfg]); + } + ps->cur_ovly = pjt->mode[mode]->ovly; + ps->cur_cfg = cfg; + + ps->cur_mode = mode; + aic3xxx_cfw_set_pll_u(ps, 0); + + } else if (pjt->mode[mode]->pfw != 0xFF) { + warn("Bad pfw setting detected (%d). Max pfw=%d", + pjt->mode[mode]->pfw, pjt->npfw); + } + ps->cur_mode = mode; + aic3xxx_cfw_set_mode_id(ps); + /* Transition to netural mode */ + aic3xxx_cfw_transition_u(ps, "NEUTRAL"); + /* Apply entry sequence if present */ + if (pjt->mode[mode]->entry) + aic3xxx_cfw_dlcmds(ps, pjt->mode[mode]->entry); + DBG("setmode_cfg: DONE (mode=%d pfw=%d ovly=%d cfg=%d)", ps->cur_mode, + ps->cur_pfw, ps->cur_ovly, ps->cur_cfg); + return 0; +} + +int aic3xxx_cfw_transition(struct cfw_state *ps, char *ttype) +{ + int ret; + + aic3xxx_cfw_lock(ps, 1); + ret = aic3xxx_cfw_transition_u(ps, ttype); + aic3xxx_cfw_lock(ps, 0); + return ret; +} + +static int aic3xxx_cfw_transition_u(struct cfw_state *ps, char *ttype) +{ + int i; + + if (ps->pjt == NULL) + return -1; + for (i = 0; i < CFW_TRN_N; ++i) { + if (!strcasecmp(ttype, cfw_transition_id[i])) { + DBG("Sending transition %s[%d]", ttype, i); + if (ps->pjt->transition[i]) { + aic3xxx_cfw_dlcmds(ps, + ps->pjt->transition[i]-> + block); + } + return 0; + } + } + warn("Transition %s not present or invalid", ttype); + return 0; +} + +int aic3xxx_cfw_set_pll(struct cfw_state *ps, int asi) +{ + int ret; + + aic3xxx_cfw_lock(ps, 1); + ret = aic3xxx_cfw_set_pll_u(ps, asi); + aic3xxx_cfw_lock(ps, 0); + return ret; +} + +static int aic3xxx_cfw_set_pll_u(struct cfw_state *ps, int asi) +{ + struct cfw_project *pjt = ps->pjt; + struct cfw_pfw *pfw; + + if (pjt == NULL) + return -1; + if (ps->cur_mode < 0) + return -EINVAL; + pfw = pjt->pfw[pjt->mode[ps->cur_mode]->pfw]; + if (pfw->pll) { + DBG("Configuring PLL for ASI%d using PFW%d", asi, + pjt->mode[ps->cur_mode]->pfw); + aic3xxx_cfw_dlcmds(ps, pfw->pll); + } + return 0; +} + +int aic3xxx_cfw_control(struct cfw_state *ps, char *cname, int param) +{ + int ret; + + aic3xxx_cfw_lock(ps, 1); + ret = aic3xxx_cfw_control_u(ps, cname, param); + aic3xxx_cfw_lock(ps, 0); + return ret; +} + +static int aic3xxx_cfw_control_u(struct cfw_state *ps, char *cname, int param) +{ + struct cfw_pfw *pfw; + int i; + + if (ps->cur_pfw < 0 || ps->cur_pfw >= ps->pjt->npfw) { + warn("Not in MiniDSP mode"); + return 0; + } + pfw = ps->pjt->pfw[ps->cur_pfw]; + for (i = 0; i < pfw->nctrl; ++i) { + if (!strcasecmp(cname, pfw->ctrl[i]->name)) { + struct cfw_control *pc = pfw->ctrl[i]; + if (param < 0 || param > pc->imax) { + warn("Parameter out of range\n"); + return -EINVAL; + } + DBG("Sending control %s[%d]", cname, param); + pc->icur = param; + aic3xxx_cfw_dlctl(ps, pc->output[param], + pc->mute_flags); + return 0; + } + } + warn("Control named %s nort found in pfw %s", cname, pfw->name); + + return 0; +} + +static void aic3xxx_cfw_dlcmds(struct cfw_state *ps, struct cfw_block *pb) +{ + int i = 0, lock = 0; + + while (i < pb->ncmds) { + if (CFW_BLOCK_BURSTS(pb->type)) + ps->ops->bulk_write(ps->ops_obj, + pb->cmd[i].burst->reg.bpod, + pb->cmd[i].burst->length, + pb->cmd[i].burst->data); + else { + struct cfw_meta_delay d = pb->cmd[i].reg.meta.delay; + struct cfw_meta_bitop b = pb->cmd[i].reg.meta.bitop; + switch (pb->cmd[i].reg.meta.mcmd) { + case CFW_META_DELAY: + mdelay(d.delay); + break; + case CFW_META_UPDTBITS: + ps->ops->set_bits(ps->ops_obj, + pb->cmd[i + 1].reg.bpod, + b.mask, + pb->cmd[i + 1].reg.data); + i++; + break; + case CFW_META_WAITBITS: + aic3xxx_wait(ps, pb->cmd[i + 1].reg.bpod, + b.mask, pb->cmd[i + 1].reg.data); + i++; + break; + case CFW_META_LOCK: + if (d.delay) { + ps->ops->lock(ps->ops_obj); + lock = 1; + } else { + if (!lock) + error("already lock\n"); + ps->ops->unlock(ps->ops_obj); + lock = 0; + } + break; + default: + ps->ops->reg_write(ps->ops_obj, + pb->cmd[i].reg.bpod, + pb->cmd[i].reg.data); + } + } + ++i; + } + if (lock) + error("exiting blkcmds with lock ON"); +} + +static void aic3xxx_wait(struct cfw_state *ps, unsigned int reg, u8 mask, + u8 data) +{ + while ((ps->ops->reg_read(ps->ops_obj, reg) & mask) != data) + mdelay(2); +} + +static const struct { + u32 mdsp; + int buf_a, buf_b; + u32 swap; +} csecs[] = { + { + .mdsp = AIC3XX_COPS_MDSP_A, + .swap = AIC3XX_ABUF_MDSP_A, + .buf_a = CFW_BLOCK_A_A_COEF, + .buf_b = CFW_BLOCK_A_B_COEF + }, + { + .mdsp = AIC3XX_COPS_MDSP_D, + .swap = AIC3XX_ABUF_MDSP_D1, + .buf_a = CFW_BLOCK_D_A1_COEF, + .buf_b = CFW_BLOCK_D_B1_COEF + }, + { + .mdsp = AIC3XX_COPS_MDSP_D, + .swap = AIC3XX_ABUF_MDSP_D2, + .buf_a = CFW_BLOCK_D_A2_COEF, + .buf_b = CFW_BLOCK_D_B2_COEF + }, +}; + +static int aic3xxx_cfw_dlctl(struct cfw_state *ps, struct cfw_block *pb, + u32 mute_flags) +{ + int i, btype = CFW_BLOCK_TYPE(pb->type); + int run_state = ps->ops->lock(ps->ops_obj); + + DBG("Download CTL"); + for (i = 0; i < sizeof(csecs) / sizeof(csecs[0]); ++i) { + if (csecs[i].buf_a == btype || csecs[i].buf_b == btype) { + DBG("\tDownload once to %d", btype); + aic3xxx_cfw_dlcmds(ps, pb); + if (run_state & csecs[i].mdsp) { + DBG("Download again %d", btype); + aic3xxx_cfw_mute(ps, 1, run_state & mute_flags); + ps->ops->bswap(ps->ops_obj, csecs[i].swap); + aic3xxx_cfw_mute(ps, 0, run_state & mute_flags); + aic3xxx_cfw_dlcmds(ps, pb); + } + break; + } + } + ps->ops->unlock(ps->ops_obj); + return 0; +} + +static int aic3xxx_cfw_dlcfg(struct cfw_state *ps, struct cfw_image *pim) +{ + int i, run_state, swap; + + DBG("Download CFG %s", pim->name); + run_state = ps->ops->lock(ps->ops_obj); + swap = 0; + for (i = 0; i < sizeof(csecs) / sizeof(csecs[0]); ++i) { + if (pim->block[csecs[i].buf_a]) { + if (run_state & csecs[i].mdsp) { + aic3xxx_cfw_dlcmds(ps, + pim->block[csecs[i].buf_a]); + swap |= csecs[i].swap; + } else { + aic3xxx_cfw_dlcmds(ps, + pim->block[csecs[i].buf_a]); + aic3xxx_cfw_dlcmds(ps, + pim->block[csecs[i].buf_b]); + } + } + } + if (swap) { + aic3xxx_cfw_mute(ps, 1, run_state & pim->mute_flags); + ps->ops->bswap(ps->ops_obj, swap); + aic3xxx_cfw_mute(ps, 0, run_state & pim->mute_flags); + for (i = 0; i < sizeof(csecs) / sizeof(csecs[0]); ++i) { + if (pim->block[csecs[i].buf_a]) { + if (run_state & csecs[i].mdsp) + aic3xxx_cfw_dlcmds(ps, + pim->block[csecs[i]. + buf_a]); + } + } + } + ps->ops->unlock(ps->ops_obj); + return 0; +} + +static int aic3xxx_cfw_dlimage(struct cfw_state *ps, struct cfw_image *pim) +{ + int i; + + DBG("Download IMAGE %s", pim->name); + for (i = 0; i < CFW_BLOCK_N; ++i) + if (pim->block[i]) + aic3xxx_cfw_dlcmds(ps, pim->block[i]); + return 0; +} + +static int aic3xxx_cfw_mute(struct cfw_state *ps, int mute, u32 flags) +{ + if ((flags & AIC3XX_COPS_MDSP_D) && (flags & AIC3XX_COPS_MDSP_A)) + aic3xxx_cfw_transition_u(ps, mute ? "AD_MUTE" : "AD_UNMUTE"); + else if (flags & AIC3XX_COPS_MDSP_D) + aic3xxx_cfw_transition_u(ps, mute ? "D_MUTE" : "D_UNMUTE"); + else if (flags & AIC3XX_COPS_MDSP_A) + aic3xxx_cfw_transition_u(ps, mute ? "A_MUTE" : "A_UNMUTE"); + return 0; +} + +#define FW_NDX2PTR(x, b) do { \ +x = (void *)((u8 *)(b) + ((int)(x))); \ +} while (0) + +static void aic3xxx_cfw_unpickle_block(struct cfw_block *pb, void *p) +{ + int i; + + if (CFW_BLOCK_BURSTS(pb->type)) + for (i = 0; i < pb->ncmds; ++i) + FW_NDX2PTR(pb->cmd[i].burst, p); +} + +static void aic3xxx_cfw_unpickle_image(struct cfw_image *im, void *p) +{ + int i; + for (i = 0; i < CFW_BLOCK_N; ++i) + if (im->block[i]) { + FW_NDX2PTR(im->block[i], p); + aic3xxx_cfw_unpickle_block(im->block[i], p); + } +} + +static void aic3xxx_cfw_unpickle_control(struct cfw_control *ct, void *p) +{ + int i; + FW_NDX2PTR(ct->output, p); + for (i = 0; i <= ct->imax; ++i) { + FW_NDX2PTR(ct->output[i], p); + aic3xxx_cfw_unpickle_block(ct->output[i], p); + } +} +#ifndef AIC3XXX_CFW_HOST_BLD +static +#endif +unsigned int crc32(unsigned int *pdata, int n) +{ + u32 crc = 0, i, crc_poly = 0x04C11DB7; /* CRC - 32 */ + u32 msb; + u32 residue_value; + int bits; + + for (i = 0; i < (n >> 2); i++) { + bits = 32; + while (--bits >= 0) { + msb = crc & 0x80000000; + crc = (crc << 1) ^ ((*pdata >> bits) & 1); + if (msb) + crc = crc ^ crc_poly; + } + pdata++; + } + + switch (n & 3) { + case 0: + break; + case 1: + residue_value = (*pdata & 0xFF); + bits = 8; + break; + case 2: + residue_value = (*pdata & 0xFFFF); + bits = 16; + break; + case 3: + residue_value = (*pdata & 0xFFFFFF); + bits = 24; + break; + } + + if (n & 3) { + while (--bits >= 0) { + msb = crc & 0x80000000; + crc = (crc << 1) ^ ((residue_value >> bits) & 1); + if (msb) + crc = crc ^ crc_poly; + } + } + return crc; +} + +static int crc_chk(void *p, int n) +{ + struct cfw_project *pjt = (void *)p; + u32 crc = pjt->cksum, crc_comp; + + pjt->cksum = 0; + DBG("Entering crc %d", n); + crc_comp = crc32(p, n); + if (crc_comp != crc) { + DBG("CRC mismatch 0x%08X != 0x%08X", crc, crc_comp); + return 0; + } + DBG("CRC pass"); + pjt->cksum = crc; + return 1; +} +#ifndef AIC3XXX_CFW_HOST_BLD +static +#endif +struct cfw_project *aic3xxx_cfw_unpickle(void *p, int n) +{ + struct cfw_project *pjt = p; + int i, j, k; + + if (pjt->magic != CFW_FW_MAGIC || + pjt->size != n || pjt->bmagic != CFW_FW_VERSION || + !crc_chk(p, n)) { + error + ("magic:0x%08X!=0x%08X || size:%d!=%d ||version:0x%08X!=0x%08X", + pjt->magic, CFW_FW_MAGIC, pjt->size, n, pjt->cksum, + CFW_FW_VERSION); + + return NULL; + } + DBG("Loaded firmware inside unpickle\n"); + + for (i = 0; i < CFW_MAX_TRANSITIONS; i++) { + if (pjt->transition[i]) { + FW_NDX2PTR(pjt->transition[i], p); + FW_NDX2PTR(pjt->transition[i]->block, p); + aic3xxx_cfw_unpickle_block(pjt->transition[i]->block, + p); + } + } + + for (i = 0; i < pjt->npfw; i++) { + DBG("loading pfw %d\n", i); + FW_NDX2PTR(pjt->pfw[i], p); + if (pjt->pfw[i]->base) { + FW_NDX2PTR(pjt->pfw[i]->base, p); + aic3xxx_cfw_unpickle_image(pjt->pfw[i]->base, p); + } + if (pjt->pfw[i]->pll) { + FW_NDX2PTR(pjt->pfw[i]->pll, p); + aic3xxx_cfw_unpickle_block(pjt->pfw[i]->pll, p); + } + for (j = 0; j < pjt->pfw[i]->novly; ++j) + for (k = 0; k < pjt->pfw[i]->ncfg; ++k) { + FW_NDX2PTR(pjt->pfw[i]->ovly_cfg[j][k], p); + aic3xxx_cfw_unpickle_image(pjt->pfw[i]-> + ovly_cfg[j][k], p); + } + for (j = 0; j < pjt->pfw[i]->nctrl; ++j) { + FW_NDX2PTR(pjt->pfw[i]->ctrl[j], p); + aic3xxx_cfw_unpickle_control(pjt->pfw[i]->ctrl[j], p); + } + } + + DBG("loaded pfw's\n"); + for (i = 0; i < pjt->nmode; i++) { + FW_NDX2PTR(pjt->mode[i], p); + if (pjt->mode[i]->entry) { + FW_NDX2PTR(pjt->mode[i]->entry, p); + aic3xxx_cfw_unpickle_block(pjt->mode[i]->entry, p); + } + if (pjt->mode[i]->exit) { + FW_NDX2PTR(pjt->mode[i]->exit, p); + aic3xxx_cfw_unpickle_block(pjt->mode[i]->exit, p); + } + } + if (pjt->asoc_toc) + FW_NDX2PTR(pjt->asoc_toc, p); + else { + warn("asoc_toc not defined. FW version mismatch?"); + return NULL; + } + DBG("loaded modes"); + return pjt; +} + +#ifndef AIC3XXX_CFW_HOST_BLD +static int aic3xxx_get_control(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct cfw_state *ps = + (struct cfw_state *) kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct cfw_pfw *pfw; + int i; + + if (ps->cur_pfw >= ps->pjt->npfw) { + DBG("Not in MiniDSP mode"); + return 0; + } + pfw = ps->pjt->pfw[ps->cur_pfw]; + for (i = 0; i < pfw->nctrl; ++i) { + if (!strcasecmp(kcontrol->id.name, pfw->ctrl[i]->name)) { + struct cfw_control *pc = pfw->ctrl[i]; + ucontrol->value.integer.value[0] = pc->icur; + return 0; + } + } + return 0; +} + +static int aic3xxx_put_control(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct cfw_state *ps = + (struct cfw_state *) kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + + aic3xxx_cfw_control(ps, kcontrol->id.name, + ucontrol->value.integer.value[0]); + return 0; +} + +static int aic3xxx_info_control(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *ucontrol) +{ + struct cfw_state *ps = + (struct cfw_state *) kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct cfw_pfw *pfw; + int i; + + if (ps->cur_pfw >= ps->pjt->npfw) { + DBG("Not in MiniDSP mode"); + return 0; + } + pfw = ps->pjt->pfw[ps->cur_pfw]; + for (i = 0; i < pfw->nctrl; ++i) { + if (!strcasecmp(kcontrol->id.name, pfw->ctrl[i]->name)) { + struct cfw_control *pc = pfw->ctrl[i]; + ucontrol->value.integer.min = 0; + ucontrol->value.integer.max = pc->imax; + if (pc->imax == 1) + ucontrol->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + else + ucontrol->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + } + } + + ucontrol->count = 1; + return 0; +} +#endif +int aic3xxx_cfw_add_controls(struct snd_soc_codec *codec, struct cfw_state *ps) +{ + int i, j; + struct cfw_pfw *pfw; + + for (j = 0; j < ps->pjt->npfw; ++j) { + pfw = ps->pjt->pfw[j]; + + for (i = 0; i < pfw->nctrl; ++i) { + struct cfw_control *pc = pfw->ctrl[i]; +#ifndef AIC3XXX_CFW_HOST_BLD + struct snd_kcontrol_new *generic_control = + kzalloc(sizeof(struct snd_kcontrol_new), + GFP_KERNEL); + unsigned int *tlv_array = + kzalloc(4 * sizeof(unsigned int), GFP_KERNEL); + + if (generic_control == NULL) + return -ENOMEM; + generic_control->access = + SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_READWRITE; + tlv_array[0] = SNDRV_CTL_TLVT_DB_SCALE; + tlv_array[1] = 2 * sizeof(unsigned int); + tlv_array[2] = pc->min; + tlv_array[3] = ((pc->step) & TLV_DB_SCALE_MASK); + if (pc->step > 0) + generic_control->tlv.p = tlv_array; + generic_control->name = pc->name; + generic_control->private_value = (unsigned long) ps; + generic_control->get = aic3xxx_get_control; + generic_control->put = aic3xxx_put_control; + generic_control->info = aic3xxx_info_control; + generic_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER; +#endif + DBG("Adding control %s", pc->name); +#ifndef AIC3XXX_CFW_HOST_BLD + snd_soc_add_controls(codec, generic_control, 1); +#endif + } + } + return 0; + +} + +static int aic3xxx_cfw_set_mode_id(struct cfw_state *ps) +{ + struct cfw_asoc_toc *toc = ps->pjt->asoc_toc; + int i; + + for (i = 0; i < toc->nentries; ++i) { + if (toc->entry[i].cfg == ps->cur_cfg && + toc->entry[i].mode == ps->cur_mode) { + ps->cur_mode_id = i; + return 0; + } + } + DBG("Unknown mode, cfg combination [%d, %d]", + ps->cur_mode, ps->cur_cfg); + return -1; +} +#ifndef AIC3XXX_CFW_HOST_BLD +static int aic3xxx_get_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + struct cfw_state *ps = (struct cfw_state *)e->mask; + + ucontrol->value.enumerated.item[0] = ps->cur_mode_id; + + return 0; +} +#endif +#ifndef AIC3XXX_CFW_HOST_BLD +static int aic3xxx_put_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + struct cfw_state *ps = (struct cfw_state *)e->mask; + struct cfw_asoc_toc *toc; + int index, ret; + + aic3xxx_cfw_lock(ps, 1); + toc = ps->pjt->asoc_toc; + + index = ucontrol->value.enumerated.item[0]; + if (index < 0 || index >= toc->nentries) { + aic3xxx_cfw_lock(ps, 0); + return -EINVAL; + } + ret = + aic3xxx_cfw_setmode_cfg_u(ps, toc->entry[index].mode, + toc->entry[index].cfg); + aic3xxx_cfw_lock(ps, 0); + return ret; +} +#endif + +int aic3xxx_cfw_add_modes(struct snd_soc_codec *codec, struct cfw_state *ps) +{ +#ifndef AIC3XXX_CFW_HOST_BLD + int j; + struct cfw_asoc_toc *toc = ps->pjt->asoc_toc; + struct soc_enum *mode_cfg_enum = + kzalloc(sizeof(struct soc_enum), GFP_KERNEL); + struct snd_kcontrol_new *mode_cfg_control = + kzalloc(sizeof(struct snd_kcontrol_new), GFP_KERNEL); + char **enum_texts; + + if (mode_cfg_enum == NULL) + goto mem_err; + if (mode_cfg_control == NULL) + goto mem_err; + + mode_cfg_enum->texts = + kzalloc(toc->nentries * sizeof(char *), GFP_KERNEL); + if (mode_cfg_enum->texts == NULL) + goto mem_err; + /* Hack to overwrite the const * const pointer */ + enum_texts = (char **)mode_cfg_enum->texts; + + for (j = 0; j < toc->nentries; j++) + enum_texts[j] = toc->entry[j].etext; + mode_cfg_enum->reg = j; + mode_cfg_enum->max = toc->nentries; + mode_cfg_enum->mask = (unsigned int)ps; + mode_cfg_control->name = "Codec Firmware Setmode"; + mode_cfg_control->get = aic3xxx_get_mode; + mode_cfg_control->put = aic3xxx_put_mode; + mode_cfg_control->info = snd_soc_info_enum_ext; + mode_cfg_control->private_value = (unsigned long)mode_cfg_enum; + mode_cfg_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER; + snd_soc_add_controls(codec, mode_cfg_control, 1); + return 0; +mem_err: + kfree(mode_cfg_control); + kfree(mode_cfg_enum); + kfree(mode_cfg_enum->texts); + return -ENOMEM; +#else + return 0; +#endif + +} diff --git a/sound/soc/codecs/aic3xxx_cfw_ops.h b/sound/soc/codecs/aic3xxx_cfw_ops.h new file mode 100644 index 000000000000..81f6bda3581b --- /dev/null +++ b/sound/soc/codecs/aic3xxx_cfw_ops.h @@ -0,0 +1,76 @@ +#ifndef AIC3XXX_CFW_OPS_H_ +#define AIC3XXX_CFW_OPS_H_ +#define DEBUG +#ifdef AIC3XXX_CFW_HOST_BLD +struct mutex { + int lock; +}; +#endif + +struct cfw_state { + struct cfw_project *pjt; + struct aic3xxx_codec_ops const *ops; + void *ops_obj; + struct mutex mutex; + int cur_mode_id; + int cur_mode; + int cur_pfw; + int cur_ovly; + int cur_cfg; +}; + +#ifdef AIC3XXX_CFW_HOST_BLD +struct cfw_project *aic3xxx_cfw_unpickle(void *pcfw, int n); +unsigned int crc32(unsigned int *pdata, int n); +struct snd_soc_codec; +#else +#ifdef DEBUG +#define DBG(fmt, ...) printk(KERN_DEBUG "CFW[%s:%d]: " fmt "\n", \ + __FILE__, __LINE__, ##__VA_ARGS__) +#else + #define DBG(fmt, ...) +#endif +#endif +int aic3xxx_cfw_init(struct cfw_state *ps, struct aic3xxx_codec_ops const *ops, + void *ops_obj); +int aic3xxx_cfw_lock(struct cfw_state *ps, int lock); +int aic3xxx_cfw_reload(struct cfw_state *ps, void *pcfw, int n); +int aic3xxx_cfw_setmode(struct cfw_state *ps, int mode); +int aic3xxx_cfw_setmode_cfg(struct cfw_state *ps, int mode, int cfg); +int aic3xxx_cfw_setcfg(struct cfw_state *ps, int cfg); +int aic3xxx_cfw_transition(struct cfw_state *ps, char *ttype); +int aic3xxx_cfw_set_pll(struct cfw_state *ps, int asi); +int aic3xxx_cfw_control(struct cfw_state *ps, char *cname, int param); +int aic3xxx_cfw_add_controls(struct snd_soc_codec *codec, struct cfw_state *ps); +int aic3xxx_cfw_add_modes(struct snd_soc_codec *codec, struct cfw_state *ps); + + +#define AIC3XX_COPS_MDSP_D (0x00000003u) +#define AIC3XX_COPS_MDSP_A (0x00000030u) +#define AIC3XX_COPS_MDSP_ALL (AIC3XX_COPS_MDSP_D|AIC3XX_COPS_MDSP_A) + +#define AIC3XX_ABUF_MDSP_D1 (0x00000001u) +#define AIC3XX_ABUF_MDSP_D2 (0x00000002u) +#define AIC3XX_ABUF_MDSP_A (0x00000010u) +#define AIC3XX_ABUF_MDSP_ALL \ + (AIC3XX_ABUF_MDSP_D1 | AIC3XX_ABUF_MDSP_D2 | AIC3XX_ABUF_MDSP_A) + +struct aic3xxx_codec_ops { + int (*reg_read)(void *p, unsigned int reg); + int (*reg_write)(void *p, unsigned int reg, + unsigned int val); + int (*set_bits)(void *p, unsigned int reg, + unsigned char mask, unsigned char val); + int (*bulk_read)(void *p, unsigned int reg, + int count, u8 *buf); + int (*bulk_write)(void *p, unsigned int reg, + int count, const u8 *buf); + + int (*lock) (void *p); + int (*unlock) (void *p); + int (*stop) (void *p, int mask); + int (*restore) (void *p, int runstate); + int (*bswap) (void *p, int mask); +}; + +#endif diff --git a/sound/soc/codecs/tlv320aic3262_default_fw.h b/sound/soc/codecs/tlv320aic3262_default_fw.h new file mode 100644 index 000000000000..55606d76f854 --- /dev/null +++ b/sound/soc/codecs/tlv320aic3262_default_fw.h @@ -0,0 +1,330 @@ +unsigned char default_firmware[] = { + 237, 241, 209, 192, 179, 0, 1, 0, 123, 20, 0, 0, 238, 201, 253, 6, + 0, 0, 0, 0, 12, 220, 206, 79, 70, 105, 114, 109, 119, 97, 114, 101, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2, 13, 0, 0, 8, 2, 0, 0, + 168, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 1, 0, 16, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 151, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 231, 19, 0, 0, 105, 110, 105, 116, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 73, 110, 105, 116, 105, 97, 108, 105, + 122, 97, 116, 105, 111, 110, 32, 115, 101, 113, 117, 101, 110, + 99, 101, 32, 40, 97, 112, 112, 108, 105, 101, 100, 32, 111, 110, + 108, 121, 32, 111, 110, 32, 115, 121, 115, 116, 101, 109, 32, 98, + 111, 111, 116, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 236, 5, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 100, 0, 128, 0, 0, 1, 1, 0, 0, 1, 122, 1, + 0, 0, 4, 51, 0, 0, 82, 0, 0, 0, 67, 151, 0, 1, 119, 127, + 100, 101, 102, 97, 117, 108, 116, 0, 98, 97, 115, 101, 95, 109, 97, + 105, 110, 95, 82, 97, 116, 101, 52, 56, 46, 99, 102, 103, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 53, 12, 0, 0, 172, 9, 0, 0, 133, 12, 0, 0, + 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 101, 102, 97, + 117, 108, 116, 47, 98, 97, 115, 101, 95, 109, 97, 105, 110, 95, 82, 97, + 116, 101, 52, 56, 46, 99, 102, 103, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 32, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 128, 0, 0, 0, 1, 0, 0, 0, 44, 12, 0, 0, 2, 0, 0, 0, + 0, 0, 60, 1, 1, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 129, + 112, 0, 0, 6, 16, 0, 0, 129, 15, 0, 0, 6, 1, 0, 0, 7, + 8, 0, 0, 8, 0, 0, 0, 9, 0, 0, 0, 129, 127, 0, 0, 11, + 2, 0, 0, 129, 127, 0, 0, 12, 8, 0, 0, 129, 127, 0, 0, 18, + 2, 0, 0, 129, 127, 0, 0, 19, 16, 0, 0, 20, 64, 0, 0, 13, + 0, 0, 0, 14, 128, 98, 97, 115, 101, 95, 109, 97, 105, 110, 0, 116, + 99, 104, 95, 98, 97, 115, 101, 95, 109, 97, 105, 110, 95, 82, 97, 116, + 101, 52, 56, 46, 99, 102, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 249, 14, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 1, 0, 0, + 0, 5, 15, 0, 0, 2, 0, 0, 0, 0, 0, 60, 1, 1, 98, 97, + 115, 101, 95, 115, 112, 107, 0, 97, 116, 99, 104, 95, 98, 97, 115, 101, + 95, 115, 112, 107, 95, 82, 97, 116, 101, 52, 56, 46, 99, 102, 103, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 130, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 128, 0, 0, 0, 1, 0, 0, 0, 142, 17, 0, 0, 2, 0, + 0, 0, 0, 0, 60, 1, 1, 100, 101, 102, 97, 117, 108, 116, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 100, 101, 102, 97, 117, + 108, 116, 32, 98, 97, 115, 101, 95, 109, 97, 105, 110, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 100, 101, 102, 97, 117, 108, 116, 32, 98, 97, 115, 101, 95, + 115, 112, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, +}; diff --git a/sound/soc/codecs/tlv320aic326x.c b/sound/soc/codecs/tlv320aic326x.c index 5d6b92904d56..06f813bbc0ca 100644 --- a/sound/soc/codecs/tlv320aic326x.c +++ b/sound/soc/codecs/tlv320aic326x.c @@ -1,636 +1,198 @@ /* -* linux/sound/soc/codecs/tlv320aic3262.c -* -* Copyright (C) 2012 Texas Instruments, Inc. -* -* Based on sound/soc/codecs/tlv320aic3262.c -* -* This package is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* -* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR -* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED -* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. -* -* The TLV320AIC3262 is a flexible, low-power, low-voltage stereo audio -* codec with digital microphone inputs and programmable outputs. -* -* History: -* -* Rev 0.1 ASoC driver support 20-01-2011 -* -* The AIC325x ASoC driver is ported for the codec AIC3262. -* Rev 0.2 ASoC driver support 21-03-2011 -* The AIC326x ASoC driver is updated abe changes. -* -* Rev 0.3 ASoC driver support 12.09.2011 -* fixed the compilation issues for Whistler support -* -* Rev 0.4 ASoC driver support 27.09.2011 -* The AIC326x driver ported for Nvidia cardhu. -* -* Rev 0.5 Modified to support Multiple ASI Ports 08-Nov-2011 -* Driver updated to support ASI Ports of AIC3262 -* -* Modified by Nvidia 23-Nov-2011 for K39 ASoC changes. -*/ + * linux/sound/soc/codecs/tlv320aic326x.c + * + * Copyright (C) 2011 Texas Instruments Inc., + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * The TLV320AIC3262 is a flexible, low-power, low-voltage stereo audio + * codec with digital microphone inputs and programmable outputs. + * + * History: + * + * Rev 0.1 ASoC driver support TI 20-01-2011 + * + * The AIC325x ASoC driver is ported for the codec AIC3262. + * Rev 0.2 ASoC driver support TI 21-03-2011 + * The AIC326x ASoC driver is updated for linux 2.6.32 Kernel. + * Rev 0.3 ASoC driver support TI 20-04-2011 + * The AIC326x ASoC driver is ported to 2.6.35 omap4 kernel + */ /* ***************************************************************************** * INCLUDES ***************************************************************************** */ + #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/pm.h> #include <linux/i2c.h> +#include <linux/spi/spi.h> #include <linux/platform_device.h> +#include <linux/switch.h> +#include <sound/jack.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/cdev.h> #include <linux/slab.h> +#include <linux/firmware.h> +#include <linux/input.h> + +#include <sound/tlv.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/initval.h> -#include <sound/tlv.h> -#include <asm/div64.h> -#include <sound/tlv320aic326x.h> -#include <sound/jack.h> -#include <linux/spi/spi.h> +#include <linux/mfd/tlv320aic3262-registers.h> +#include <linux/mfd/tlv320aic3262-core.h> +#include "aic3xxx_cfw.h" +#include "aic3xxx_cfw_ops.h" #include "tlv320aic326x.h" -#include <linux/gpio.h> -/* - ***************************************************************************** - * Global Variable - ***************************************************************************** - */ -static u8 aic3262_reg_ctl; - -#ifdef AIC3262_TiLoad - extern int aic3262_driver_init(struct snd_soc_codec *codec); -#endif - +#include "aic3262_codec_ops.h" +#include "tlv320aic3262_default_fw.h" -/* whenever aplay/arecord is run, aic3262_hw_params() function gets called. - * This function reprograms the clock dividers etc. this flag can be used to - * disable this when the clock dividers are programmed by pps config file - */ -static struct snd_soc_codec *aic3262_codec; - -/* - ***************************************************************************** - * Macros - ***************************************************************************** - */ - -/* ASoC Widget Control definition for a single Register based Control */ -#define SOC_SINGLE_AIC3262(xname) \ -{\ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .info = __new_control_info, .get = __new_control_get,\ - .put = __new_control_put, \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ -} -#define SOC_SINGLE_N(xname, xreg, xshift, xmax, xinvert) \ -{\ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .info = n_control_info, .get = n_control_get,\ - .put = n_control_put, \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ - .private_value = ((unsigned long)&(struct soc_mixer_control)) \ - {.reg = xreg, .shift = xshift, .rshift = xshift, .max = xmax, \ - .invert = xinvert} } - -/* ASoC Widget Control definition for a Double Register based Control */ - -#define SOC_DOUBLE_R_N(xname, reg_left, reg_right, xshift, xmax, xinvert) \ +#define SOC_DOUBLE_R_SX_TLV3262(xname, xreg_left, xreg_right, xshift,\ + xmin, xmax, tlv_array) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ - .info = snd_soc_info_volsw_2r_n, \ - .get = snd_soc_get_volsw_2r_n, .put = snd_soc_put_volsw_2r_n, \ - .private_value = (unsigned long)&(struct soc_mixer_control) \ - {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ - .max = xmax, .invert = xinvert} } - -#define SND_SOC_DAPM_SWITCH_N(wname, wreg, wshift, winvert) \ -{ .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift,\ - .invert = winvert, .kcontrols = NULL, .num_kcontrols = 0} -/* - ***************************************************************************** - * Function Prototype - ***************************************************************************** - */ -static int aic3262_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level); - -static int __new_control_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo); - -static int __new_control_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); - -static int __new_control_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); - -static inline int aic3262_get_divs(int mclk, int rate); - -static int aic3262_multi_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai); - -static int aic3262_multi_i2s_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir); -static int aic3262_multi_i2s_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, int source, unsigned int freq_in, - unsigned int freq_out); - -static int aic3262_multi_i2s_asi1_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt); - -static int aic3262_multi_i2s_asi2_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt); - -static int aic3262_multi_i2s_asi3_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt); - -static int aic3262_multi_i2s_asi1_mute(struct snd_soc_dai *dai, int mute); - -static int aic3262_multi_i2s_asi2_mute(struct snd_soc_dai *dai, int mute); - -static int aic3262_multi_i2s_asi3_mute(struct snd_soc_dai *dai, int mute); - -#if 0 -static const char *wclk1_pincontrol[] = { - "ASI1 Word Clock Input/Output", "CLKOUT output"}; -static const char *dout1_pincontrol[] = { - "disabled", "ASI1 data output", "gpio", "clock out", - "INT1", "INT2", "SAR ADC interrupt"}; + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .tlv.p = (tlv_array), \ + .info = snd_soc_info_volsw_2r_sx, \ + .get = snd_soc_get_volsw_2r_sx, \ + .put = snd_soc_put_volsw_2r_sx_aic3262, \ + .private_value = (unsigned long) &(struct soc_mixer_control) \ + {.reg = xreg_left, \ + .rreg = xreg_right, .shift = xshift, \ + .min = xmin, .max = xmax} } -static const char *din1_pincontrol[] = {"disabled", "enabled"}; +/***************************************************************************** + Macros +****************************************************************************** -static const char *wclk2_pincontrol[] = { - "diabled", "ASI1 secondary wclk", "general purpose input", - "general purpose output", "clkout", "INT1 interrupt", - "IN2 interrupt", "output digital microphone", - "SAR ADC interrupt", "data output for ASI1"}; +****************************************************************************** + Function Prototype +******************************************************************************/ -static const char *bclk2_pincontrol[] = { - "diabled", "ASI1 secondary wclk", "general purpose input", - "general purpose output", "clkout", "INT1 interrupt", - "IN2 interrupt", "output digital microphone", - "SAR ADC interrupt", "data output for ASI1"}; +static int aic3262_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); -static const char *dout2_pincontrol[] = { - "disabled", "ASI2 Data Output", "General Purpose Output", - "INT1 Interrupt", "INT2 Interrupt", "SAR ADC interrupt", - "Output for digital microphone", "Data Output for ASI1"}; +static int aic3262_mute(struct snd_soc_dai *dai, int mute); -static const char *din2_pincontrol[] = {"disabled", "enabled"}; +static int aic3262_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir); -static const char *wclk3_pincontrol[] = { - "Disabled", "ASI3 WCLK", "General Purpose Input", - "General Purpose output", "Data Output for ASI1"}; +static int aic3262_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt); -static const char *bclk3_pincontrol[] = { - "Disabled", "ASI3 BCLK", "General Purpose Input", - "General Purpose output", "Data Output for ASI1"}; +static int aic3262_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int Fin, unsigned int Fout); -static const char *dout3_pincontrol[] = { - "disabled", "ASI3 data ooutput", "General Purpose Output", - "ASI1 Word Clock Output", "Data Output for ASI1"}; - -static const char *din3_pincontrol[] = {"disabled", "enabled"}; - -static const char *clkin[] = { - "mclk1", "bclk1", "gpio1", "pll_clk", "bclk2", "gpi1", - "hf_ref_clk", "hf_osc_clk", "mclk2", "gpio2", "gpi2"}; - -#endif -#ifdef DAC_INDEPENDENT_VOL -/* - *---------------------------------------------------------------------------- - * Function : n_control_info - * Purpose : This function is to initialize data for new control required to - * program the AIC3262 registers. - * - *---------------------------------------------------------------------------- - */ -static int n_control_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - int max = mc->max; - unsigned int shift = mc->shift; - unsigned int rshift = mc->rshift; - - if (max == 1) - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - else - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - - uinfo->count = shift == rshift ? 1 : 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = max; - return 0; -} - -/* - *---------------------------------------------------------------------------- - * Function : n_control_get - * Purpose : This function is to read data of new control for - * program the AIC3262 registers. - * - *---------------------------------------------------------------------------- - */ -static int n_control_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - u32 val; - unsigned short mask, shift; - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - if (!strcmp(kcontrol->id.name, "Left DAC Volume")) { - mask = AIC3262_8BITS_MASK; - shift = 0; - val = snd_soc_read(codec, mc->reg); - ucontrol->value.integer.value[0] = - (val <= 48) ? (val + 127) : (val - 129); - } - if (!strcmp(kcontrol->id.name, "Right DAC Volume")) { - mask = AIC3262_8BITS_MASK; - shift = 0; - val = snd_soc_read(codec, mc->reg); - ucontrol->value.integer.value[0] = - (val <= 48) ? (val + 127) : (val - 129); - } +static int aic3262_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level); - return 0; -} +static int aic3262_set_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int aic3262_set_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); -/* - *---------------------------------------------------------------------------- - * Function : __new_control_put - * Purpose : new_control_put is called to pass data from user/application to - * the driver. - * - *---------------------------------------------------------------------------- - */ -static int n_control_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - u8 val, val_mask; - int reg, err; - unsigned int invert = mc->invert; - int max = mc->max; - DBG("n_control_put\n"); - reg = mc->reg; - val = ucontrol->value.integer.value[0]; - if (invert) - val = max - val; - if (!strcmp(kcontrol->id.name, "Left DAC Volume")) { - DBG("LDAC\n"); - val = (val >= 127) ? (val - 127) : (val + 129); - val_mask = AIC3262_8BITS_MASK; - } - if (!strcmp(kcontrol->id.name, "Right DAC Volume")) { - DBG("RDAC\n"); - val = (val >= 127) ? (val - 127) : (val + 129); - val_mask = AIC3262_8BITS_MASK; - } +static int aic326x_adc_dsp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event); - err = snd_soc_update_bits_locked(codec, reg, val_mask, val); - if (err < 0) { - printk(KERN_ERR "Error while updating bits\n"); - return err; - } +static long debug_level; +module_param(debug_level, long, 0); +MODULE_PARM_DESC(debug_level, "Debug level for printing"); - return 0; -} -#endif /*#ifdef DAC_INDEPENDENT_VOL*/ -/* - *------------------------------------------------------------------------------ - * snd_soc_info_volsw_2r_n - double mixer info callback +/** + * snd_soc_put_volsw_2r_sx - double with tlv and variable data size + * mixer put callback * @kcontrol: mixer control * @uinfo: control element information * - * Callback to provide information about a double mixer control that - * spans 2 codec registers. - * * Returns 0 for success. - *------------------------------------------------------------------------------ */ -int snd_soc_info_volsw_2r_n(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) +int snd_soc_put_volsw_2r_sx_aic3262(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - int max = mc->max; - - if (max == 1) - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - else - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = max; - return 0; -} - -/* - *------------------------------------------------------------------------------ - * snd_soc_get_volsw_2r_n - double mixer get callback - * @kcontrol: mixer control - * @ucontrol: control element information - * - * Callback to get the value of a double mixer control that spans 2 registers. - * - * Returns 0 for success. - *------------------------------------------------------------------------------ - */ -int snd_soc_get_volsw_2r_n(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; + (struct soc_mixer_control *)kcontrol->private_value; struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int reg = mc->reg; - unsigned int reg2 = mc->rreg; - unsigned int shift = mc->shift; - int max = mc->max; - unsigned int mask; - unsigned int invert = mc->invert; - unsigned short val, val2; - - if (!strcmp(kcontrol->id.name, "PCM Playback Volume")) { - mask = AIC3262_8BITS_MASK; - shift = 0; - } else if (!strcmp(kcontrol->id.name, "HP Driver Gain")) { - mask = 0x3F; - shift = 0; - } else if (!strcmp(kcontrol->id.name, "PGA Capture Volume")) { - mask = 0x7F; - shift = 0; - } else if (!strcmp(kcontrol->id.name, "REC Driver Volume")) { - mask = 0x3F; - shift = 0; - } else if (!strcmp(kcontrol->id.name, "LO to HP Volume")) { - mask = 0x7F; - shift = 0; - } else if (!strcmp(kcontrol->id.name, "MA Volume")) { - mask = 0x7F; - shift = 0; - } else { - printk(KERN_ERR "Invalid kcontrol name\n"); - return -1; - } - - /* Read, update the corresponding Registers */ - val = (snd_soc_read(codec, reg) >> shift) & mask; - val2 = (snd_soc_read(codec, reg2) >> shift) & mask; - - if (!strcmp(kcontrol->id.name, "PCM Playback Volume")) { - ucontrol->value.integer.value[0] = - (val <= 48) ? (val + 127) : (val - 129); - ucontrol->value.integer.value[1] = - (val2 <= 48) ? (val2 + 127) : (val2 - 129); - } else if (!strcmp(kcontrol->id.name, "HP Driver Gain")) { - ucontrol->value.integer.value[0] = - (val >= 57) ? (val - 57) : (val + 7); - ucontrol->value.integer.value[1] = - (val2 >= 57) ? (val2 - 57) : (val2 + 7); - } else if (!strcmp(kcontrol->id.name, "PGA Capture Volume")) { - ucontrol->value.integer.value[0] = - (val <= 40) ? (val + 24) : (val - 104); - ucontrol->value.integer.value[1] = - (val2 <= 40) ? (val2 + 24) : (val2 - 104); - } else if (!strcmp(kcontrol->id.name, "REC Driver Volume")) { - ucontrol->value.integer.value[0] = ((val >= 0) & (val <= 29)) ? - (val + 7) : (val - 57); - ucontrol->value.integer.value[1] = ((val2 >= 0) & - (val2 <= 29)) ? (val2 + 7) : (val2 - 57); - - } else if (!strcmp(kcontrol->id.name, "LO to HP Volume")) { - ucontrol->value.integer.value[0] = ((val >= 0) & (val <= 116)) ? - (val + 1) : ((val == 127) ? (0) : (117)); - ucontrol->value.integer.value[1] = ((val2 >= 0) & (val2 <= 116)) - ? (val2 + 1) : ((val2 == 127) ? (0) : (117)); - - } else if (!strcmp(kcontrol->id.name, "MA Volume")) { - ucontrol->value.integer.value[0] = (val <= 40) ? - (41 - val) : (val = 0); - ucontrol->value.integer.value[1] = (val2 <= 40) ? - (41 - val2) : (val2 = 0); - } - - if (invert) { - ucontrol->value.integer.value[0] = - max - ucontrol->value.integer.value[0]; - ucontrol->value.integer.value[1] = - max - ucontrol->value.integer.value[1]; - } - - return 0; -} -/* -*------------------------------------------------------------------------------- -* snd_soc_put_volsw_2r_n - double mixer set callback -* @kcontrol: mixer control -* @ucontrol: control element information -* -* Callback to set the value of a double mixer control that spans 2 registers. -* -* Returns 0 for success. -*------------------------------------------------------------------------------- -*/ -int snd_soc_put_volsw_2r_n(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int reg = mc->reg; - unsigned int reg2 = mc->rreg; - unsigned int shift = mc->shift; - int max = mc->max; - unsigned int mask; - unsigned int invert = mc->invert; - int err; - unsigned short val, val2, val_mask; - - mask = 0x00FF; - - val = (ucontrol->value.integer.value[0] & mask); - val2 = (ucontrol->value.integer.value[1] & mask); - if (invert) { - val = max - val; - val2 = max - val2; - } - - /* Check for the string name of the kcontrol */ - if (!strcmp(kcontrol->id.name, "PCM Playback Volume")) { - val = (val >= 127) ? (val - 127) : (val + 129); - val2 = (val2 >= 127) ? (val2 - 127) : (val2 + 129); - val_mask = AIC3262_8BITS_MASK; /* 8 bits */ - } else if ((!strcmp(kcontrol->id.name, "HP Driver Gain")) || - (!strcmp(kcontrol->id.name, "LO Driver Gain"))) { - val = (val <= 6) ? (val + 57) : (val - 7); - val2 = (val2 <= 6) ? (val2 + 57) : (val2 - 7); - val_mask = 0x3F; /* 6 bits */ - DBG("val=%d, val2=%d", val, val2); - } else if (!strcmp(kcontrol->id.name, "PGA Capture Volume")) { - val = (val >= 24) ? ((val <= 64) ? - (val-24) : (40)) : (val + 104); - val2 = (val2 >= 24) ? - ((val2 <= 64) ? (val2 - 24) : (40)) : (val2 + 104); - val_mask = 0x7F; /* 7 bits */ - } else if (!strcmp(kcontrol->id.name, "LO to REC Volume")) { - - val = (val <= 116) ? - (val % 116) : ((val == 117) ? (127) : (117)); - val2 = (val2 <= 116) ? - (val2 % 116) : ((val2 == 117) ? (127) : (117)); - val_mask = 0x7F; - } else if (!strcmp(kcontrol->id.name, "REC Driver Volume")) { - - val = (val <= 7) ? (val + 57) : ((val < 36) ? (val - 7) : (29)); - val2 = (val2 <= 7) ? - (val2 + 57) : ((val2 < 36) ? (val2 - 7) : (29)); - val_mask = 0x3F; - } else if (!strcmp(kcontrol->id.name, "LO to HP Volume")) { - - val = ((val > 0) & (val <= 117)) ? - (val - 1) : ((val == 0) ? (127) : (116)); - val2 = ((val2 > 0) & (val2 <= 117)) ? - (val2 - 1) : ((val2 == 0) ? (127) : (116)); - val_mask = 0x7F; - } else if (!strcmp(kcontrol->id.name, "MA Volume")) { - - val = ((val <= 41) & (val > 0)) ? - (41 - val) : ((val > 41) ? (val = 41) : (63)); - val2 = ((val2 <= 41) & (val2 > 0)) ? - (41 - val2) : ((val2 > 41) ? (val2 = 41) : (63)); - val_mask = 0x7F; - } else { - printk(KERN_ERR "Invalid control name\n"); - return -1; - } - - val = val << shift; - val2 = val2 << shift; - - err = snd_soc_update_bits_locked(codec, reg, val_mask, val); - if (err < 0) - return err; + unsigned int mask = (1 << mc->shift) - 1; + int min = mc->min; + int ret; + unsigned int val, valr; - err = snd_soc_update_bits_locked(codec, reg2, val_mask, val2); - return err; -} - -static int __new_control_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 65535; + val = ((ucontrol->value.integer.value[0] + min) & 0xff); + val &= mask; + valr = ((ucontrol->value.integer.value[1] + min) & 0xff); + valr &= mask; + ret = 0; + ret = snd_soc_update_bits_locked(codec, mc->reg, mask, val); + if (ret < 0) + return ret; + ret = snd_soc_update_bits_locked(codec, mc->rreg, mask, valr); + if (ret < 0) + return ret; return 0; } -/* - *---------------------------------------------------------------------------- - * Function : __new_control_get - * Purpose : This function is to read data of new control for - * program the AIC3262 registers. - * - *---------------------------------------------------------------------------- - */ -static int __new_control_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static ssize_t debug_level_show(struct device *dev, + struct device_attribute *attr, + char *buf, size_t count) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - u32 val; - val = snd_soc_read(codec, aic3262_reg_ctl); - ucontrol->value.integer.value[0] = val; - return 0; + return sprintf(buf, "%ld\n", debug_level); } -/* - *---------------------------------------------------------------------------- - * Function : __new_control_put - * Purpose : new_control_put is called to pass data from user/application to - * the driver. - * - *---------------------------------------------------------------------------- - */ -static int __new_control_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static ssize_t debug_level_set(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - u8 data[2]; - int ret = 0; - - u32 data_from_user = ucontrol->value.integer.value[0]; - - aic3262_change_book(codec, 0); - aic3262_reg_ctl = data[0] = (u8) ((data_from_user & 0xFF00) >> 8); - data[1] = (u8) ((data_from_user & 0x00FF)); - - if (!data[0]) - aic3262->page_no = data[1]; + int ret; - DBG("reg = %d val = %x\n", data[0], data[1]); -#if defined(LOCAL_REG_ACCESS) - if (codec->hw_write(codec->control_data, data, 2) != 2) - ret = -EIO; -#else - ret = snd_soc_write(codec, data[0], data[1]); -#endif + ret = kstrtol(buf, 10, &debug_level); if (ret) - printk(KERN_ERR "Error in i2c write\n"); - - return ret; + return ret; + return count; } +static DEVICE_ATTR(debug_level, 0644, debug_level_show, debug_level_set); -/* - ***************************************************************************** - * Structure Initialization - ***************************************************************************** - */ static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6350, 50, 0); static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1200, 50, 0); static const DECLARE_TLV_DB_SCALE(spk_gain_tlv, 600, 600, 0); -static const DECLARE_TLV_DB_SCALE(output_gain_tlv, -600, 100, 0); +static const DECLARE_TLV_DB_SCALE(output_gain_tlv, -600, 100, 1); static const DECLARE_TLV_DB_SCALE(micpga_gain_tlv, 0, 50, 0); static const DECLARE_TLV_DB_SCALE(adc_fine_gain_tlv, -40, 10, 0); static const DECLARE_TLV_DB_SCALE(beep_gen_volume_tlv, -6300, 100, 0); /* Chip-level Input and Output CM Mode Controls */ -static const char *input_common_mode_text[] = { - "0.9v", "0.75v" }; +static const char * const input_common_mode_text[] = { + "0.9v", "0.75v" +}; -static const char *output_common_mode_text[] = { - "Input CM", "1.25v", "1.5v", "1.65v" }; +static const char * const output_common_mode_text[] = { + "Input CM", "1.25v", "1.5v", "1.65v" +}; static const struct soc_enum input_cm_mode = - SOC_ENUM_SINGLE(CM_REG, 2, 2, input_common_mode_text); +SOC_ENUM_SINGLE(AIC3262_CM_REG, 2, 2, input_common_mode_text); static const struct soc_enum output_cm_mode = - SOC_ENUM_SINGLE(CM_REG, 0, 4, output_common_mode_text); - +SOC_ENUM_SINGLE(AIC3262_CM_REG, 0, 4, output_common_mode_text); /* ***************************************************************************** * Structure Initialization @@ -641,2388 +203,874 @@ static const struct snd_kcontrol_new aic3262_snd_controls[] = { #ifndef DAC_INDEPENDENT_VOL /* sound new kcontrol for PCM Playback volume control */ - SOC_DOUBLE_R_SX_TLV("PCM Playback Volume", - DAC_LVOL, DAC_RVOL, 8,0xffffff81, 0x30, dac_vol_tlv), + SOC_DOUBLE_R_SX_TLV3262("PCM Playback Volume", + AIC3262_DAC_LVOL, AIC3262_DAC_RVOL, 8, + 0xffffff81, + 0x30, dac_vol_tlv), #endif - /*HP Driver Gain Control*/ - SOC_DOUBLE_R_SX_TLV("HeadPhone Driver Amplifier Volume", - HPL_VOL, HPR_VOL, 6, 0xfffffffa, 0xe, output_gain_tlv), - - /*LO Driver Gain Control*/ - SOC_DOUBLE_TLV("Speaker Amplifier Volume", - SPK_AMP_CNTL_R4, 4, 0, 5, 0, spk_gain_tlv), + /*HP Driver Gain Control */ + SOC_DOUBLE_R_SX_TLV3262("HeadPhone Driver Amplifier Volume", + AIC3262_HPL_VOL, AIC3262_HPR_VOL, 6, 0xffffffb9, + 0xffffffce, output_gain_tlv), + /*LO Driver Gain Control */ + SOC_DOUBLE_TLV("Speaker Amplifier Volume", AIC3262_SPK_AMP_CNTL_R4, 4, + 0, 5, 0, spk_gain_tlv), - SOC_DOUBLE_R_SX_TLV("Receiver Amplifier Volume", - REC_AMP_CNTL_R5, RAMPR_VOL, 6, 0xfffffffa, 0x1d, output_gain_tlv), + SOC_DOUBLE_R_SX_TLV3262("Receiver Amplifier Volume", + AIC3262_REC_AMP_CNTL_R5, AIC3262_RAMPR_VOL, 6, + 0xffffffb9, 0xffffffd6, output_gain_tlv), - SOC_DOUBLE_R_SX_TLV("PCM Capture Volume", - LADC_VOL, RADC_VOL, 7,0xffffff68, 0x24, adc_vol_tlv), + SOC_DOUBLE_R_SX_TLV3262("PCM Capture Volume", AIC3262_LADC_VOL, + AIC3262_RADC_VOL, 7, 0xffffff68, 0xffffffa8, + adc_vol_tlv), + SOC_DOUBLE_R_TLV("MicPGA Volume Control", AIC3262_MICL_PGA, + AIC3262_MICR_PGA, 0, 0x5F, 0, micpga_gain_tlv), - SOC_DOUBLE_R_TLV ("MicPGA Volume Control", - MICL_PGA, MICR_PGA, 0, 0x5F, 0, micpga_gain_tlv), - SOC_DOUBLE_TLV("PCM Capture Fine Gain Volume", - ADC_FINE_GAIN, 4, 0, 5, 1, adc_fine_gain_tlv), + SOC_DOUBLE_TLV("PCM Capture Fine Gain Volume", AIC3262_ADC_FINE_GAIN, + 4, 0, 5, 1, adc_fine_gain_tlv), - SOC_DOUBLE("ADC channel mute", ADC_FINE_GAIN, 7, 3, 1, 0), + SOC_DOUBLE("ADC channel mute", AIC3262_ADC_FINE_GAIN, 7, 3, 1, 0), - SOC_DOUBLE("DAC MUTE", DAC_MVOL_CONF, 2, 3, 1, 1), - - /* sound new kcontrol for Programming the registers from user space */ - SOC_SINGLE_AIC3262("Program Registers"), - - SOC_SINGLE("RESET", RESET_REG, 0,1,0), - - SOC_SINGLE("DAC VOL SOFT STEPPING", DAC_MVOL_CONF, 0, 2, 0), - -#ifdef DAC_INDEPENDENT_VOL - /*SOC_SINGLE_N("Left DAC Volume", DAC_LVOL, 0, 0xAF, 0), - SOC_SINGLE_N("Right DAC Volume", DAC_RVOL, 0, 0xAF, 0),*/ -#endif + SOC_DOUBLE("DAC MUTE", AIC3262_DAC_MVOL_CONF, 2, 3, 1, 1), - SOC_SINGLE("DAC AUTO MUTE CONTROL", DAC_MVOL_CONF, 4, 7, 0), - SOC_SINGLE("RIGHT MODULATOR SETUP", DAC_MVOL_CONF, 7, 1, 0), + SOC_SINGLE("RESET", AIC3262_RESET_REG, 0, 1, 0), - SOC_SINGLE("ADC Volume soft stepping", ADC_CHANNEL_POW, 0, 3, 0), + SOC_SINGLE("DAC VOL SOFT STEPPING", AIC3262_DAC_MVOL_CONF, 0, 2, 0), - SOC_DOUBLE_R("MICPGA enable/disable",MICL_PGA,MICR_PGA,7, 1, 0), + SOC_SINGLE("DAC AUTO MUTE CONTROL", AIC3262_DAC_MVOL_CONF, 4, 7, 0), - SOC_SINGLE("Mic Bias ext independent enable", MIC_BIAS_CNTL, 7, 1, 0), - SOC_SINGLE("MICBIAS_EXT ON", MIC_BIAS_CNTL, 6, 1, 0), - SOC_SINGLE("MICBIAS EXT Power Level", MIC_BIAS_CNTL, 4, 3, 0), + SOC_SINGLE("RIGHT MODULATOR SETUP", AIC3262_DAC_MVOL_CONF, 7, 1, 0), - SOC_SINGLE("MICBIAS_INT ON", MIC_BIAS_CNTL, 2, 1, 0), - SOC_SINGLE("MICBIAS INT Power Level", MIC_BIAS_CNTL, 0, 3, 0), + SOC_SINGLE("ADC Volume soft stepping", AIC3262_ADC_CHANNEL_POW, + 0, 3, 0), - SOC_DOUBLE("DRC_EN_CTL", DRC_CNTL_R1, 6, 5, 1, 0), - SOC_SINGLE("DRC_THRESHOLD_LEVEL", DRC_CNTL_R1, 2, 7, 1), - SOC_SINGLE("DRC_HYSTERISIS_LEVEL", DRC_CNTL_R1, 0, 7, 0), + SOC_SINGLE("Mic Bias ext independent enable", AIC3262_MIC_BIAS_CNTL, + 7, 1, 0), - SOC_SINGLE("DRC_HOLD_LEVEL", DRC_CNTL_R2, 3, 0x0F, 0), - SOC_SINGLE("DRC_GAIN_RATE", DRC_CNTL_R2, 0, 4, 0), - SOC_SINGLE("DRC_ATTACK_RATE", DRC_CNTL_R3, 4, 0x0F, 1), - SOC_SINGLE("DRC_DECAY_RATE", DRC_CNTL_R3, 0, 0x0F, 1), + SOC_SINGLE("MICBIAS EXT Power Level", AIC3262_MIC_BIAS_CNTL, 4, 3, 0), - SOC_SINGLE("BEEP_GEN_EN", BEEP_CNTL_R1, 7, 1, 0), - SOC_DOUBLE_R("BEEP_VOL_CNTL", BEEP_CNTL_R1, BEEP_CNTL_R2, 0, 0x0F, 1), - SOC_SINGLE("BEEP_MAS_VOL", BEEP_CNTL_R2, 6, 3, 0), + SOC_SINGLE("MICBIAS INT Power Level", AIC3262_MIC_BIAS_CNTL, 0, 3, 0), - SOC_DOUBLE_R("AGC_EN", LAGC_CNTL, RAGC_CNTL, 7, 1, 0), - SOC_DOUBLE_R("AGC_TARGET_LEVEL", LAGC_CNTL, RAGC_CNTL, 4, 7, 1), + SOC_SINGLE("BEEP_GEN_EN", AIC3262_BEEP_CNTL_R1, 7, 1, 0), - SOC_DOUBLE_R("AGC_GAIN_HYSTERESIS", LAGC_CNTL, RAGC_CNTL, 0, 3, 0), - SOC_DOUBLE_R("AGC_HYSTERESIS", LAGC_CNTL_R2, RAGC_CNTL_R2, 6, 3, 0), - SOC_DOUBLE_R("AGC_NOISE_THRESHOLD", LAGC_CNTL_R2, - RAGC_CNTL_R2, 1, 31, 1), + SOC_DOUBLE_R("BEEP_VOL_CNTL", AIC3262_BEEP_CNTL_R1, + AIC3262_BEEP_CNTL_R2, 0, 0x0F, 1), - SOC_DOUBLE_R("AGC_MAX_GAIN", LAGC_CNTL_R3, RAGC_CNTL_R3, 0, 116, 0), - SOC_DOUBLE_R("AGC_ATCK_TIME", LAGC_CNTL_R4, RAGC_CNTL_R4, 3, 31, 0), - SOC_DOUBLE_R("AGC_ATCK_SCALE_FACTOR", - LAGC_CNTL_R4, RAGC_CNTL_R4, 0, 7, 0), + SOC_SINGLE("BEEP_MAS_VOL", AIC3262_BEEP_CNTL_R2, 6, 3, 0), - SOC_DOUBLE_R("AGC_DECAY_TIME", LAGC_CNTL_R5, RAGC_CNTL_R5, 3, 31, 0), - SOC_DOUBLE_R("AGC_DECAY_SCALE_FACTOR", - LAGC_CNTL_R5, RAGC_CNTL_R5, 0, 7, 0), - SOC_DOUBLE_R("AGC_NOISE_DEB_TIME", LAGC_CNTL_R6, - RAGC_CNTL_R6, 0, 31, 0), + SOC_SINGLE("DAC PRB Selection", AIC3262_DAC_PRB, 0, 26, 0), - SOC_DOUBLE_R("AGC_SGL_DEB_TIME", LAGC_CNTL_R7, - RAGC_CNTL_R7, 0, 0x0F, 0), + SOC_SINGLE("ADC PRB Selection", AIC3262_ADC_PRB, 0, 18, 0), - SOC_SINGLE("DAC PRB Selection",DAC_PRB, 0, 25, 0), - SOC_SINGLE("HP_DEPOP", HP_DEPOP, 0, 255,0), - SOC_DOUBLE("IN1 LO BYPASS VOLUME" , LINE_AMP_CNTL_R2, 3, 0, 3, 1), SOC_ENUM("Input CM mode", input_cm_mode), - SOC_ENUM("Output CM mode", output_cm_mode), -}; - -/* the sturcture contains the different values for mclk */ -static const struct aic3262_rate_divs aic3262_divs[] = { -/* - * mclk, rate, p_val, pll_j, pll_d, dosr, ndac, mdac, aosr, nadc, madc, blck_N, - * codec_speficic_initializations - */ - /* 8k rate */ -#ifdef CONFIG_MINI_DSP - {12000000, 8000, 1, 8, 1920, 768, 8, 2, 128, 8, 12, 4, - {{0, 60, 0}, {0, 61, 0} } }, -#else - {12000000, 8000, 1, 8, 1920, 128, 12, 8, 128, 8, 6, 4, - {{0, 60, 1}, {0, 61, 1} } }, - {12288000, 8000, 1, 1, 3333, 128, 12, 8, 128, 8, 6, 4, - {{0, 60, 1}, {0, 61, 1} } }, - {24000000, 8000, 1, 4, 96, 128, 12, 8, 128, 12, 8, 4, - {{0, 60, 1}, {0, 61, 1} } }, -#endif - /* 11.025k rate */ - {12000000, 11025, 1, 1, 8816, 1024, 8, 2, 128, 8, 2, 48, - {{0, 60, 1}, {0, 61, 1} } }, - {12288000, 11025, 1, 1, 8375, 1024, 8, 2, 128, 8, 2, 48, - {{0, 60, 1}, {0, 61, 1} } }, - {24000000, 11025, 1, 3, 7632, 128, 8, 8, 128, 8, 8, 4, - {{0, 60, 1}, {0, 61, 1} } }, - - /* 16k rate */ -#ifdef CONFIG_MINI_DSP - {12000000, 16000, 1, 8, 1920, 384, 4, 4, 128, 4, 12, 12, - {{0, 60, 0}, {0, 61, 0} } }, - {12288000, 16000, 1, 9, 0, 216, 2, 16, 72, 2, 48, 27, - {{0, 60, 0}, {0, 61, 0} } }, -#else - {12000000, 16000, 1, 8, 1920, 128, 8, 6, 128, 8, 6, 4, - {{0, 60, 1}, {0, 61, 1} } }, - {12288000, 16000, 1, 2, 6667, 128, 8, 6, 128, 8, 6, 4, - {{0, 60, 1}, {0, 61, 1} } }, - {24000000, 16000, 1, 4, 96, 128, 8, 6, 128, 8, 6, 4, - {{0, 60, 1}, {0, 61, 1} } }, -#endif - /* 22.05k rate */ - {12000000, 22050, 1, 3, 7632, 128, 8, 2, 128, 8, 2, 4, - {{0, 60, 1}, {0, 61, 1} } }, - {12288000, 22050, 1, 3, 675, 128, 8, 2, 128, 8, 2, 4, - {{0, 60, 1}, {0, 61, 1} } }, - {24000000, 22050, 1, 3, 7632, 128, 8, 3, 128, 8, 3, 4, - {{0, 60, 1}, {0, 61, 1} } }, - /* 32k rate */ - {12000000, 32000, 1, 5, 4613, 128, 8, 2, 128, 8, 2, 4, - {{0, 60, 1}, {0, 61, 1} } }, - {12288000, 32000, 1, 5, 3333, 128, 8, 2, 128, 8, 2, 4, - {{0, 60, 1}, {0, 61, 1} } }, - {24000000, 32000, 1, 4, 96, 128, 6, 4, 128, 6, 4, 4, - {{0, 60, 1}, {0, 61, 1} } }, - -#ifdef CONFIG_MINI_DSP - {12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4, - {{0, 60, 0}, {0, 61, 0} } }, - {12288000, 44100, 1, 7, 3548, 128, 2, 8, 128, 8, 2, 4, - {{0, 60, 0}, {0, 61, 0} } }, -#else - /* 44.1k rate */ - {12000000, 44100, 1, 7, 5264, 128, 8, 2, 128, 8, 2, 4, - {{0, 60, 1}, {0, 61, 1} } }, - {12288000, 44100, 1, 7, 3548, 128, 8, 2, 128, 8, 2, 4, - {{0, 60, 1}, {0, 61, 1} } }, - {24000000, 44100, 1, 3, 7632, 128, 4, 4, 64, 4, 4, 4, - {{0, 60, 1}, {0, 61, 1} } }, -#endif - -#ifdef CONFIG_MINI_DSP - {12288000, 48000, 1, 8, 52, 128, 2, 8, 128, 2, 8, 4, - {{0, 60, 0}, {0, 61, 0} } }, - {12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4, - {{0, 60, 0}, {0, 61, 0}}}, -#else - /* 48k rate */ - {12000000, 48000, 1, 8, 1920, 128, 8, 2, 128, 8, 2, 4, - {{0, 60, 1}, {0, 61, 1} } }, - {12288000, 48000, 1, 8, 52, 128, 8, 2, 128, 8, 2, 4, - {{0, 60, 1}, {0, 61, 1} } }, - {24000000, 48000, 1, 4, 960, 128, 4, 4, 128, 4, 4, 4, - {{0, 60, 1}, {0, 61, 1} } }, -#endif + SOC_ENUM("Output CM mode", output_cm_mode), - /*96k rate */ - {12000000, 96000, 1, 16, 3840, 128, 8, 2, 128, 8, 2 , 4, - {{0, 60, 7}, {0, 61, 7} } }, - {24000000, 96000, 1, 4, 960, 128, 4, 2, 128, 4, 2, 2, - {{0, 60, 7}, {0, 61, 7} } }, - /*192k */ - {12000000, 192000, 1, 32, 7680, 128, 8, 2, 128, 8, 2, 4, - {{0, 60, 17}, {0, 61, 13} } }, - {24000000, 192000, 1, 4, 960, 128, 2, 2, 128, 2, 2, 4, - {{0, 60, 17}, {0, 61, 13} } }, + SOC_SINGLE_EXT("FIRMWARE SET MODE", SND_SOC_NOPM, 0, 0xffff, 0, + aic3262_set_mode_get, aic3262_set_mode_put), }; - - -/* -*---------------------------------------------------------------------------- -* Function : aic3262_multi_i2s_dump_regs -* Purpose : This function is to mute or unmute the left and right DAC -* -*---------------------------------------------------------------------------- -*/ -static void aic3262_multi_i2s_dump_regs(struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - unsigned int counter; - - DBG(KERN_INFO "#%s: Dai Active %d ASI%d REGS DUMP\n", - __func__, aic3262->active_count, dai->id); - - aic3262_change_page(codec, 0); - aic3262_change_book(codec, 0); - - DBG(KERN_INFO "#Page0 REGS..\n"); - for (counter = 0; counter < 85; counter++) { - DBG(KERN_INFO "#%2d -> 0x%x\n", counter, - snd_soc_read(codec, counter)); - } - - DBG(KERN_INFO "#Page1 REGS..\n"); - for (counter = 128; counter < 176; counter++) { - DBG(KERN_INFO "#%2d -> 0x%x\n", (counter % 128), - snd_soc_read(codec, counter)); - } - - DBG(KERN_INFO "#Page4 REGS..\n"); - for (counter = 512; counter < 631; counter++) { - DBG(KERN_INFO "#%2d -> 0x%x\n", - (counter % 128), snd_soc_read(codec, counter)); - } - - for (counter = 0; counter < MAX_ASI_COUNT; counter++) { - DBG(KERN_INFO "#ASI%d Frame %s @ %dHz Playback %d Record %d\n", - (counter + 1), - (aic3262->asiCtxt[counter].master == 1) ? "Master" : "Slave", - aic3262->asiCtxt[counter].sampling_rate, - aic3262->asiCtxt[counter].playback_mode, - aic3262->asiCtxt[counter].capture_mode); - DBG(KERN_INFO "#DAC Option [%d,%d] ADC Option %d WLEN %d\n\n", - aic3262->asiCtxt[counter].left_dac_output, - aic3262->asiCtxt[counter].right_dac_output, - aic3262->asiCtxt[counter].adc_input, - aic3262->asiCtxt[counter].word_len); - } - return; -} - -/* - *---------------------------------------------------------------------------- - * Function : aic3262_multi_i2s_mute - * Purpose : This function is to mute or unmute the left and right DAC - * - *---------------------------------------------------------------------------- - */ -static int aic3262_multi_i2s_mute(struct snd_soc_dai *dai, int mute) -{ - struct snd_soc_codec *codec = dai->codec; - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - - DBG(KERN_INFO "#%s : mute entered with %d\n", __func__, mute); - - /* If we are doing both Recording and Playback on this DAI interface, - * do not MUTE the Codec. - */ - if (mute && (aic3262->asiCtxt[dai->id - 1].asi_active > 1)) { - DBG("#%s Cannot Mute the ASI%d Now..\n", - __func__, dai->id); - } else { - switch (dai->id) { - case 1: - aic3262_multi_i2s_asi1_mute(dai, mute); - break; - case 2: - aic3262_multi_i2s_asi2_mute(dai, mute); - break; - case 3: - aic3262_multi_i2s_asi3_mute(dai, mute); - break; - default: - printk(KERN_ERR "#%s: Invalid DAI id\n", __func__); - return -EINVAL; - } - } - DBG(KERN_INFO "#%s : mute ended\n", __func__); - return 0; -} - - -/* -*---------------------------------------------------------------------------- -* Function : aic3262_multi_i2s_asi1_mute -* Purpose : This function is to mute or unmute the left and right DAC -* -*---------------------------------------------------------------------------- -*/ -static int aic3262_multi_i2s_asi1_mute(struct snd_soc_dai *dai, int mute) -{ - struct snd_soc_codec *codec = dai->codec; - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - - DBG(KERN_INFO "#%s : mute %d started\n", __func__, mute); - - if (mute && !aic3262->asiCtxt[0].port_muted ) { - DBG(KERN_INFO "Mute if part\n"); - - - snd_soc_update_bits(codec, DAC_MVOL_CONF, DAC_LR_MUTE_MASK,DAC_LR_MUTE); - - /* First check if both Playback and Recording is going on - * this interface. - */ - if (aic3262->asiCtxt[0].asi_active > 1) { - DBG("#%s Cannot Mute the ASI Now..\n", __func__); - } else if (!(aic3262->asiCtxt[1].playback_mode) && - !(aic3262->asiCtxt[2].playback_mode)) { - /* Before Muting, please check if any other - * ASI is active. if so, we cannot simply mute the - * DAC and ADC Registers. - */ - DBG("#%s None of the ASI's are active now..\n", __func__); - snd_soc_write(codec, DAC_MVOL_CONF, - ((aic3262->dac_reg & 0xF3) | 0x0C)); - snd_soc_write(codec, ADC_FINE_GAIN, - ((aic3262->adc_gain & 0x77) | 0x88)); - snd_soc_write(codec, HPL_VOL, 0xB9); - snd_soc_write(codec, HPR_VOL, 0xB9); - snd_soc_write(codec, REC_AMP_CNTL_R5, 0x39); - snd_soc_write(codec, RAMPR_VOL, 0x39); - snd_soc_write(codec, SPK_AMP_CNTL_R4, 0x00); - aic3262->asiCtxt[0].port_muted = 1; - } - } else { - DBG(KERN_INFO "Mute else part\n"); - snd_soc_update_bits(codec, DAC_MVOL_CONF, - DAC_LR_MUTE_MASK, 0x0); - snd_soc_write(codec, ADC_FINE_GAIN,(0X00 & 0x77) | 0x0); - aic3262_multi_i2s_dump_regs(dai); - } - - DBG(KERN_INFO "#%s : mute %d ended\n", __func__, mute); - - return 0; -} - -/* -*---------------------------------------------------------------------------- -* Function : aic3262_multi_i2s_asi2_maic3262_asi3_clk_configute -* Purpose : This function is to mute or unmute the left and right DAC -* -*---------------------------------------------------------------------------- -*/ -static int aic3262_multi_i2s_asi2_mute(struct snd_soc_dai *dai, int mute) -{ - struct snd_soc_codec *codec = dai->codec; - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - - DBG(KERN_INFO "#%s : mute %d started\n", __func__, mute); - - if (mute && !aic3262->asiCtxt[1].port_muted ) { - DBG(KERN_INFO "Mute if part\n"); - snd_soc_update_bits(codec, DAC_MVOL_CONF, DAC_LR_MUTE_MASK,DAC_LR_MUTE); - - /* First check if both Playback and Recording is going on - * this interface. - */ - if (aic3262->asiCtxt[1].asi_active > 1) { - DBG("#%s Cannot Mute the ASI Now..\n", __func__); - } else if (!(aic3262->asiCtxt[0].playback_mode) && - !(aic3262->asiCtxt[2].playback_mode)) { - /* Before Muting, please check if any other - * ASI is active. if so, we cannot simply mute the - * DAC and ADC Registers. - */ - snd_soc_write(codec, DAC_MVOL_CONF, - ((aic3262->dac_reg & 0xF3) | 0x0C)); - snd_soc_write(codec, ADC_FINE_GAIN, - ((aic3262->adc_gain & 0x77) | 0x88)); - snd_soc_write(codec, HPL_VOL, 0xB9); - snd_soc_write(codec, HPR_VOL, 0xB9); - snd_soc_write(codec, REC_AMP_CNTL_R5, 0x39); - snd_soc_write(codec, RAMPR_VOL, 0x39); - snd_soc_write(codec, SPK_AMP_CNTL_R4, 0x00); - aic3262->asiCtxt[1].port_muted = 1; - } - } else { - DBG(KERN_INFO "Mute else part\n"); - snd_soc_update_bits(codec, DAC_MVOL_CONF, - DAC_LR_MUTE_MASK, 0x0); - - /*aic3262_multi_i2s_dump_regs(dai);*/ - } - - DBG(KERN_INFO "#%s : mute %d ended\n", __func__, mute); - - return 0; -} - -/* -*---------------------------------------------------------------------------- -* Function : aic3262_multi_i2s_asi3_mute -* Purpose : This function is to mute or unmute the left and right DAC -* -*---------------------------------------------------------------------------- -*/ -static int aic3262_multi_i2s_asi3_mute(struct snd_soc_dai *dai, int mute) -{ - struct snd_soc_codec *codec = dai->codec; - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - - DBG(KERN_INFO "#%s : mute %d started\n", __func__, mute); - - if (mute && !aic3262->asiCtxt[2].port_muted) { - DBG("Mute if part\n"); - snd_soc_update_bits(codec, DAC_MVOL_CONF, DAC_LR_MUTE_MASK,DAC_LR_MUTE); - - /* First check if both Playback and Recording is going on - * this interface. - */ - if (aic3262->asiCtxt[2].asi_active > 1) { - DBG("#%s Cannot Mute the ASI Now..\n", __func__); - } else if (!(aic3262->asiCtxt[0].playback_mode) && - !(aic3262->asiCtxt[1].playback_mode)) { - /* Before Muting, please check if any other - * ASI is active. if so, we cannot simply mute the - * DAC and ADC Registers. - */ - snd_soc_write(codec, DAC_MVOL_CONF, - ((aic3262->dac_reg & 0xF3) | 0x0C)); - snd_soc_write(codec, ADC_FINE_GAIN, - ((aic3262->adc_gain & 0x77) | 0x88)); - snd_soc_write(codec, HPL_VOL, 0xB9); - snd_soc_write(codec, HPR_VOL, 0xB9); - snd_soc_write(codec, REC_AMP_CNTL_R5, 0x39); - snd_soc_write(codec, RAMPR_VOL, 0x39); - snd_soc_write(codec, SPK_AMP_CNTL_R4, 0x00); - aic3262->asiCtxt[2].port_muted = 1; - } - } else { - DBG("Mute else part\n"); - snd_soc_update_bits(codec, DAC_MVOL_CONF, - DAC_LR_MUTE_MASK, 0x0); - - /*aic3262_multi_i2s_dump_regs(dai);*/ - - } - - DBG(KERN_INFO "#%s : mute %d ended\n", __func__, mute); - - return 0; -} - -/* - *---------------------------------------------------------------------------- - * Function : aic3262_multi_i2s_set_dai_fmt - * Purpose : This function is to set the DAI format - * - *---------------------------------------------------------------------------- - */ -static int aic3262_multi_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - /* Check the DAI Id and based on that switch the configuration for - * the Individual ASI Port. - */ - switch (codec_dai->id) { - case 1: - aic3262_multi_i2s_asi1_set_dai_fmt(codec_dai, fmt); - break; - case 2: - aic3262_multi_i2s_asi2_set_dai_fmt(codec_dai, fmt); - break; - case 3: - aic3262_multi_i2s_asi3_set_dai_fmt(codec_dai, fmt); - break; - default: - printk(KERN_ERR - "#%s: Invalid DAI interface format\n", __func__); - return -EINVAL; - } - return 0; -} - - - -/* -*---------------------------------------------------------------------------- -* Function : aic3262_multi_i2s_asi1_set_dai_fmt -* Purpose : This function is to set the DAI format for ASI1 Port -* -*---------------------------------------------------------------------------- -*/ -static int aic3262_multi_i2s_asi1_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - u8 iface_reg, clk_reg; - u8 regvalue; - - DBG(KERN_INFO "%s: DAI_ID %d fmt %d\n", - __func__, codec_dai->id, fmt); - - /* Read the B0_P4_R4 and B0_P4_R10 Registers to configure the - * ASI1 Bus and Clock Formats depending on the PCM Format. - */ - iface_reg = snd_soc_read(codec, ASI1_BUS_FMT); - clk_reg = snd_soc_read(codec, ASI1_BWCLK_CNTL_REG); - - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - DBG(KERN_INFO "#%s: Configuring ASI%d as Frame Master..\n", - __func__, codec_dai->id); - aic3262->asiCtxt[0].master = 1; - clk_reg |= (BIT5 | BIT2); /* Codec Interface as Master */ - break; - case SND_SOC_DAIFMT_CBS_CFS: - DBG(KERN_INFO "#%s: Configuring ASI%d as Frame Slave..\n", - __func__, codec_dai->id); - clk_reg &= ~0xFC; /* Reset bits D[7:5] and D[4:2] to zero */ - aic3262->asiCtxt[0].master = 0; - break; - case SND_SOC_DAIFMT_CBS_CFM: - /* new case..just for debugging */ - DBG(KERN_INFO "%s: SND_SOC_DAIFMT_CBS_CFM\n", __func__); - aic3262->asiCtxt[0].master = 0; - clk_reg |= BIT5; /* Only WCLK1 Output from Codec */ - clk_reg &= ~0x1C; /* BCLK1 Input to Codec */ - break; - default: - printk(KERN_ERR "#%s: Invalid DAI master/slave interface\n", - __func__); - return -EINVAL; - } - aic3262->asiCtxt[0].pcm_format = (fmt & SND_SOC_DAIFMT_FORMAT_MASK); - /* interface format */ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - DBG(KERN_INFO "#%s: Configuring ASI%d for I2s Mode..\n", - __func__, codec_dai->id); - iface_reg = (iface_reg & 0x1f); - break; - case SND_SOC_DAIFMT_DSP_A: - DBG(KERN_INFO "#%s: Configuring ASI%d for DSP_A Mode..\n", - __func__, codec_dai->id); - iface_reg = (iface_reg & 0x1f) | 0x20; - break; - case SND_SOC_DAIFMT_RIGHT_J: - iface_reg = (iface_reg & 0x1f) | 0x40; - break; - case SND_SOC_DAIFMT_LEFT_J: - iface_reg = (iface_reg & 0x1f) | 0x60; - break; - case SND_SOC_DAIFMT_DSP_B: - DBG(KERN_INFO "#%s: Configuring ASI%d for DSP_B Mode..\n", - __func__, codec_dai->id); - iface_reg = (iface_reg & 0x1f) | 0x80; - /* voice call need data offset in 1 bitclock */ - snd_soc_write(codec, ASI1_LCH_OFFSET, 1); - break; - default: - printk(KERN_ERR - "#%s: Invalid DAI interface format\n", __func__); - return -EINVAL; - } - /* Also Configure the Pin Control Registers before writing into - * the ASI specific Clock Control and Format Registers - */ - - /* Configure B0_P4_R65_D[5:2] to 001 This configures the - * WCLK1 Pin to ASI1 - */ - regvalue = snd_soc_read(codec, WCLK1_PIN_CNTL_REG); - snd_soc_write(codec, WCLK1_PIN_CNTL_REG, (regvalue | BIT2)); - - /* Configure B0_P4_R68_d[6:5] = 01 and B0_P4_R67_D[4:1] to 0001 - * to ensure that the DIN1 and DOUT1 Pins are configured - * correctly - */ - regvalue = snd_soc_read(codec, DIN1_PIN_CNTL_REG); - snd_soc_write(codec, DIN1_PIN_CNTL_REG, (regvalue | BIT5)); - regvalue = snd_soc_read(codec, DOUT1_PIN_CNTL_REG); - snd_soc_write(codec, DOUT1_PIN_CNTL_REG, (regvalue | BIT1)); - - snd_soc_write(codec, ASI1_BWCLK_CNTL_REG, clk_reg); - - snd_soc_write(codec, ASI1_BUS_FMT, iface_reg); - - return 0; -} - - -/* -*---------------------------------------------------------------------------- -* Function : aic3262_multi_i2s_asi2_set_dai_fmt -* Purpose : This function is to set the DAI format for ASI2 Port -* -*---------------------------------------------------------------------------- -*/ -static int aic3262_multi_i2s_asi2_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - u8 iface_reg, clk_reg; - u8 regvalue; - - DBG(KERN_INFO "%s: DAI_ID %d fmt %d\n", - __func__, codec_dai->id, fmt); - - /* Read the B0_P4_R17 and B0_P4_R26 Registers to configure the - * ASI1 Bus and Clock Formats depending on the PCM Format. - */ - iface_reg = snd_soc_read(codec, ASI2_BUS_FMT); - clk_reg = snd_soc_read(codec, ASI2_BWCLK_CNTL_REG); - - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - DBG(KERN_INFO "#%s: Configuring ASI%d as Frame Master..\n", - __func__, codec_dai->id); - aic3262->asiCtxt[1].master = 1; - clk_reg |= (BIT5 | BIT2); - break; - case SND_SOC_DAIFMT_CBS_CFS: - DBG(KERN_INFO "#%s: Configuring ASI%d as Frame Slave..\n", - __func__, codec_dai->id); - - clk_reg &= ~0xFC; - aic3262->asiCtxt[1].master = 0; - break; - case SND_SOC_DAIFMT_CBS_CFM: - /*new case..just for debugging */ - DBG(KERN_INFO "%s: SND_SOC_DAIFMT_CBS_CFM\n", __func__); - aic3262->asiCtxt[1].master = 0; - clk_reg |= BIT5; - clk_reg &= ~0x1C; - break; - default: - printk(KERN_ERR "#%s:Invalid DAI master/slave interface\n", - __func__); - return -EINVAL; - } - aic3262->asiCtxt[1].pcm_format = (fmt & SND_SOC_DAIFMT_FORMAT_MASK); - /* interface format */ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - DBG(KERN_INFO "#%s: Configuring ASI%d for I2S Mode..\n", - __func__, codec_dai->id); - iface_reg = (iface_reg & 0x1f); - break; - case SND_SOC_DAIFMT_DSP_A: - DBG(KERN_INFO "#%s: Configuring ASI%d for DSP_A Mode..\n", - __func__, codec_dai->id); - iface_reg = (iface_reg & 0x1f) | 0x20; - break; - case SND_SOC_DAIFMT_RIGHT_J: - iface_reg = (iface_reg & 0x1f) | 0x40; - break; - case SND_SOC_DAIFMT_LEFT_J: - iface_reg = (iface_reg & 0x1f) | 0x60; - break; - case SND_SOC_DAIFMT_DSP_B: - DBG(KERN_INFO "#%s: Configuring ASI%d for DSP Mode..\n", - __func__, codec_dai->id); - iface_reg = (iface_reg & 0x1f) | 0x80; - /* voice call need data offset in 1 bitclock */ - snd_soc_write(codec, ASI2_LCH_OFFSET, 1); - break; - default: - printk(KERN_ERR "#%s:Invalid DAI interface format\n", __func__); - return -EINVAL; - } - - /* Also Configure the Pin Control Registers before writing into - * the ASI2 specific Clock Control and Format Registers - */ - - /* Configure B0_P4_R69_D[5:2] to 001 This configures the - * WCLK2 Pin to ASI2 - */ - - regvalue = snd_soc_read(codec, WCLK2_PIN_CNTL_REG); - snd_soc_write(codec, WCLK2_PIN_CNTL_REG, (regvalue | BIT2)); - - regvalue = snd_soc_read(codec, BCLK2_PIN_CNTL_REG); - snd_soc_write(codec, BCLK2_PIN_CNTL_REG, (regvalue | BIT2)); - - /* Configure B0_P4_R72_d[6:5] = 01 and B0_P4_R71_D[4:1] to 0001 - * to ensure that the DIN2 and DOUT2 Pins are configured - * correctly - */ - regvalue = snd_soc_read(codec, DIN2_PIN_CNTL_REG); - snd_soc_write(codec, DIN2_PIN_CNTL_REG, (regvalue | BIT5)); - - regvalue = snd_soc_read(codec, DOUT2_PIN_CNTL_REG); - snd_soc_write(codec, DOUT2_PIN_CNTL_REG, (regvalue | BIT5 | BIT1)); - - snd_soc_write(codec, ASI2_BWCLK_CNTL_REG, clk_reg); - - snd_soc_write(codec, ASI2_BUS_FMT, iface_reg); - - return 0; -} - -/* -*---------------------------------------------------------------------------- -* Function : aic3262_multi_i2s_asi3_set_dai_fmt -* Purpose : This function is to set the DAI format for ASI3 Port -* -*---------------------------------------------------------------------------- -*/ -static int aic3262_multi_i2s_asi3_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - u8 iface_reg, clk_reg; - u8 regvalue; - - DBG(KERN_INFO "%s: DAI_ID %d fmt %d\n", - __func__, codec_dai->id, fmt); - - /* Read the B0_P4_R33 and B0_P4_R42 Registers to configure the - * ASI1 Bus and Clock Formats depending on the PCM Format. - */ - iface_reg = snd_soc_read(codec, ASI3_BUS_FMT); - clk_reg = snd_soc_read(codec, ASI3_BWCLK_CNTL_REG); - - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - DBG(KERN_INFO "#%s: Configuring ASI%d as Frame Master..\n", - __func__, codec_dai->id); - aic3262->asiCtxt[2].master = 1; - clk_reg |= (BIT5 | BIT2); - break; - case SND_SOC_DAIFMT_CBS_CFS: - DBG(KERN_INFO "#%s: Configuring ASI%d as Frame Slave..\n", - __func__, codec_dai->id); - clk_reg &= ~0xFC; - aic3262->asiCtxt[2].master = 0; - break; - case SND_SOC_DAIFMT_CBS_CFM: - /* new case..just for debugging */ - DBG(KERN_INFO "%s: SND_SOC_DAIFMT_CBS_CFM\n", __func__); - aic3262->asiCtxt[2].master = 0; - clk_reg |= BIT5; - clk_reg &= ~0x1C; - break; - default: - printk(KERN_ERR "Invalid DAI master/slave interface\n"); - return -EINVAL; - } - aic3262->asiCtxt[2].pcm_format = (fmt & SND_SOC_DAIFMT_FORMAT_MASK); - /* interface format */ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - DBG(KERN_INFO "#%s: Configuring ASI%d for I2S Mode..\n", - __func__, codec_dai->id); - iface_reg = (iface_reg & 0x1f); - break; - case SND_SOC_DAIFMT_DSP_A: - DBG(KERN_INFO "#%s: Configuring ASI%d for DSP_A Mode..\n", - __func__, codec_dai->id); - iface_reg = (iface_reg & 0x1f) | 0x20; - break; - case SND_SOC_DAIFMT_RIGHT_J: - iface_reg = (iface_reg & 0x1f) | 0x40; - break; - case SND_SOC_DAIFMT_LEFT_J: - iface_reg = (iface_reg & 0x1f) | 0x60; - break; - case SND_SOC_DAIFMT_DSP_B: - DBG(KERN_INFO "#%s: Configuring ASI%d for DSP Mode..\n", - __func__, codec_dai->id); - iface_reg = (iface_reg & 0x1f) | 0x80; - /* voice call need data offset in 1 bitclock */ - snd_soc_write(codec, ASI3_LCH_OFFSET, 1); - break; - default: - printk(KERN_ERR - "#%s: Invalid DAI interface format\n", __func__); - return -EINVAL; - } - - /* Also Configure the Pin Control Registers before writing into - * the ASI specific Clock Control and Format Registers - */ - /* Configure B0_P4_R73_D[5:2] to 0001 This configures the - * WCLK1 Pin to ASI1 - */ - regvalue = snd_soc_read(codec, WCLK3_PIN_CNTL_REG); - snd_soc_write(codec, WCLK3_PIN_CNTL_REG, (regvalue | BIT2)); - - regvalue = snd_soc_read(codec, BCLK3_PIN_CNTL_REG); - snd_soc_write(codec, BCLK3_PIN_CNTL_REG, (regvalue | BIT2)); - - /* Configure B0_P4_R76_d[6:5] = 01 and B0_P4_R75_D[4:1] to 0001 - * to ensure that the DIN1 and DOUT1 Pins are configured - * correctly - */ - regvalue = snd_soc_read(codec, DIN3_PIN_CNTL_REG); - snd_soc_write(codec, DIN3_PIN_CNTL_REG, (regvalue | BIT5)); - regvalue = snd_soc_read(codec, DOUT3_PIN_CNTL_REG); - snd_soc_write(codec, DOUT3_PIN_CNTL_REG, (regvalue | BIT1)); - - snd_soc_write(codec, ASI3_BWCLK_CNTL_REG, clk_reg); - - snd_soc_write(codec, ASI3_BUS_FMT, iface_reg); - - return 0; -} - -/* - * Clock after PLL and dividers - */ -static int aic3262_multi_i2s_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - - DBG(KERN_INFO "#%s: DAI ID %d Freq %d Direction %d\n", - __func__, codec_dai->id, freq, dir); - switch (freq) { - case AIC3262_FREQ_12000000: - case AIC3262_FREQ_12288000: - case AIC3262_FREQ_24000000: - aic3262->sysclk = freq; - return 0; - break; - } - printk(KERN_ERR "Invalid frequency to set DAI system clock\n"); - return -EINVAL; -} - -/* -* aic3262_multi_i2s_set_pll -* -* This function is invoked as part of the PLL call-back -* handler from the ALSA layer. -*/ -static int aic3262_multi_i2s_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, int source, unsigned int freq_in, - unsigned int freq_out) -{ - - printk(KERN_INFO "%s: DAI ID %d PLL_ID %d InFreq %d OutFreq %d\n", - __func__, pll_id, codec_dai->id, freq_in, freq_out); - - return 0; -} - -/* -* aic3262_asi1_clk_config -* -* This function is used to configure the BCLK1, WCLK1 pins which -* are specific to ASI1 Interface. This function just enables the -* BCLk and WCLK along with the miniDSP Port Control Registers. -* However, depending on the user requirement, this function can also be -* extended to configure the sourc for the BCLK and WCLK on a ASI basis. -*/ -static int aic3262_asi1_clk_config(struct snd_soc_codec *codec, - struct snd_pcm_hw_params *params) -{ - u8 bclk_N_value, wclk_N_value; - u8 minidspD_data, minidspA_data; - u8 regval; - - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - - DBG(KERN_INFO "%s: Invoked\n", __func__); - - /* Configure the BCLK and WCLK Output Mux Options */ - regval = snd_soc_read(codec, ASI1_BWCLK_OUT_CNTL); - regval &= ~(AIC3262_ASI_BCLK_MUX_MASK | AIC3262_ASI_WCLK_MUX_MASK); - - regval |= (aic3262->asiCtxt[0].bclk_output << - AIC3262_ASI_BCLK_MUX_SHIFT); - regval |= aic3262->asiCtxt[0].wclk_output; - snd_soc_write(codec, ASI1_BWCLK_OUT_CNTL, regval); - - /* Configure the corresponding miniDSP Data Ports */ - minidspD_data = snd_soc_read(codec, MINIDSP_PORT_CNTL_REG); - minidspD_data &= ~(BIT5 | BIT4); - snd_soc_write(codec, MINIDSP_PORT_CNTL_REG, minidspD_data); - - minidspA_data = snd_soc_read(codec, ASI1_ADC_INPUT_CNTL); - minidspA_data &= ~(BIT2 | BIT1 | BIT0); - minidspA_data |= aic3262->asiCtxt[0].adc_input; - snd_soc_write(codec, ASI1_ADC_INPUT_CNTL, minidspA_data); - - - if (aic3262->asiCtxt[0].master == 1) { - DBG(KERN_INFO - "#%s: Codec Master on ASI1 Port. Enabling BCLK WCLK Divider.\n", - __func__); - bclk_N_value = aic3262->asiCtxt[0].bclk_div; - snd_soc_write(codec, ASI1_BCLK_N, (bclk_N_value | 0x80)); - - wclk_N_value = snd_soc_read(codec, ASI1_WCLK_N); - snd_soc_write(codec, ASI1_WCLK_N, (wclk_N_value | 0xA0)); - } - return 0; - -} - -/* -* aic3262_asi2_clk_config -* -* This function is used to configure the BCLK2, WCLK2 pins which -* are specific to ASI2 Interface. This function just enables the -* BCLk and WCLK along with the miniDSP Port Control Registers. -* However, depending on the user requirement, this function can also be -* extended to configure the sourc for the BCLK and WCLK on a ASI basis. -*/ -static int aic3262_asi2_clk_config(struct snd_soc_codec *codec, - struct snd_pcm_hw_params *params) -{ - u8 bclk_N_value, wclk_N_value, minidspD_data, minidspA_data; - u8 regval; - - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - - DBG(KERN_INFO "%s: Invoked\n", __func__); - - - /* Configure the BCLK and WCLK Output Mux Options */ - regval = snd_soc_read(codec, ASI2_BWCLK_OUT_CNTL); - regval &= ~(AIC3262_ASI_BCLK_MUX_MASK | AIC3262_ASI_WCLK_MUX_MASK); - regval |= (aic3262->asiCtxt[1].bclk_output << - AIC3262_ASI_BCLK_MUX_SHIFT); - regval |= aic3262->asiCtxt[1].wclk_output; - - snd_soc_write(codec, ASI2_BWCLK_OUT_CNTL, regval); - /* Configure the corresponding miniDSP Data Ports */ - minidspD_data = snd_soc_read(codec, MINIDSP_PORT_CNTL_REG); - minidspD_data |= (BIT2); - snd_soc_write(codec, MINIDSP_PORT_CNTL_REG, minidspD_data); - - minidspA_data = snd_soc_read(codec, ASI2_ADC_INPUT_CNTL); - minidspA_data &= ~(BIT2 | BIT1 | BIT0); - minidspA_data |= aic3262->asiCtxt[1].adc_input; - snd_soc_write(codec, ASI2_ADC_INPUT_CNTL, minidspA_data); - - /* NO Manual configuration of WCLK and BCLK for Master Mode. - * DAPM Handles all the required modifications. - */ - if (aic3262->asiCtxt[1].master == 1) { - DBG(KERN_INFO - "#%s: Codec Master on ASI2 Port. Enabling BCLK WCLK Divider.\n", - __func__); - bclk_N_value = aic3262->asiCtxt[1].bclk_div; - snd_soc_write(codec, ASI2_BCLK_N, (bclk_N_value | 0x80)); - - wclk_N_value = snd_soc_read(codec, ASI2_WCLK_N); - snd_soc_write(codec, ASI2_WCLK_N, (wclk_N_value | 0xA0)); - } - - return 0; - -} - -/* -* aic3262_asi3_clk_config -* -* This function is used to configure the BCLK3, WCLK3 pins which -* are specific to ASI3 Interface. This function just enables the -* BCLk and WCLK along with the miniDSP Port Control Registers. -* However, depending on the user requirement, this function can also be -* extended to configure the sourc for the BCLK and WCLK on a ASI basis. -*/ -static int aic3262_asi3_clk_config(struct snd_soc_codec *codec, - struct snd_pcm_hw_params *params) -{ - u8 bclk_N_value, wclk_N_value, minidspD_data, minidspA_data; - u8 regval; - - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - - DBG(KERN_INFO "%s:\n", __func__); - - - /* Configure the BCLK and WCLK Output Mux Options */ - regval = snd_soc_read(codec, ASI3_BWCLK_OUT_CNTL); - regval &= ~(AIC3262_ASI_BCLK_MUX_MASK | AIC3262_ASI_WCLK_MUX_MASK); - regval |= (aic3262->asiCtxt[2].bclk_output << - AIC3262_ASI_BCLK_MUX_SHIFT); - regval |= aic3262->asiCtxt[2].wclk_output; - snd_soc_write(codec, ASI3_BWCLK_OUT_CNTL, regval); - - minidspD_data = snd_soc_read(codec, MINIDSP_PORT_CNTL_REG); - minidspD_data |= (BIT1); - snd_soc_write(codec, MINIDSP_PORT_CNTL_REG, minidspD_data); - - minidspA_data = snd_soc_read(codec, ASI3_ADC_INPUT_CNTL); - minidspA_data &= ~(BIT2 | BIT1 | BIT0); - minidspA_data |= aic3262->asiCtxt[2].adc_input; - snd_soc_write(codec, ASI3_ADC_INPUT_CNTL, minidspA_data); - - if (aic3262->asiCtxt[2].master == 1) { - DBG(KERN_INFO - "#%s: Codec Master on ASI3 Port. Enabling BCLK WCLK Divider.\n", - __func__); - bclk_N_value = aic3262->asiCtxt[2].bclk_div; - snd_soc_write(codec, ASI2_BCLK_N, (bclk_N_value | 0x80)); - - wclk_N_value = snd_soc_read(codec, ASI3_WCLK_N); - snd_soc_write(codec, ASI3_WCLK_N, (wclk_N_value | 0xA0)); - } - return 0; - -} - -/* -* aic3262_multi_i2s_hw_params -* -* This function is used to configure the individual ASI port registers -* depending on the configuration passed on by the snd_pcm_hw_params -* structure. -* This function internally configures the ASI specific pins and clock -* Control Registers. -*/ -static int aic3262_multi_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - int i, j; - u8 data; - u16 regoffset = 0; - u8 dacpath = 0; - u8 adcpath = 0; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->codec; - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - - DBG(KERN_INFO "#%s: Invoked for ASI%d Port for %s Mode\n", - __func__, dai->id, - (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - ? "Playback" : "Record"); - - i = aic3262_get_divs(aic3262->sysclk, params_rate(params)); - - i2c_verify_book0(codec); - - if (i < 0) { - printk(KERN_ERR "#%s: Sampling rate %d not supported\n", - __func__, params_rate(params)); - return i; - } - - aic3262_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - /* Configure the PLL J, R D values only if none of the ASI - * Interfaces are Active. - */ - - if (1) { - DBG(KERN_INFO "#%s: None of the ASIs active yet...\n", - __func__); - /*We will fix R value to 1 and make P & J=K.D as variable */ - /* Setting P & R values are set to 1 and 1 at init*/ - - /* J value */ - snd_soc_write(codec, PLL_J_REG, aic3262_divs[i].pll_j); - - /* MSB & LSB for D value */ - - snd_soc_write(codec, PLL_D_MSB, (aic3262_divs[i].pll_d >> 8)); - snd_soc_write(codec, PLL_D_LSB, - (aic3262_divs[i].pll_d & AIC3262_8BITS_MASK)); - - /* NDAC divider value */ - data = snd_soc_read(codec, NDAC_DIV_POW_REG); - DBG(KERN_INFO "# reading NDAC = %d , NDAC_DIV_POW_REG = %x\n", - aic3262_divs[i].ndac, data); - snd_soc_write(codec, NDAC_DIV_POW_REG, - ((data & 0x80)|(aic3262_divs[i].ndac))); - DBG(KERN_INFO "# writing NDAC = %d , NDAC_DIV_POW_REG = %x\n", - aic3262_divs[i].ndac, - ((data & 0x80)|(aic3262_divs[i].ndac))); - - /* MDAC divider value */ - data = snd_soc_read(codec, MDAC_DIV_POW_REG); - DBG(KERN_INFO "# reading MDAC = %d , MDAC_DIV_POW_REG = %x\n", - aic3262_divs[i].mdac, data); - snd_soc_write(codec, MDAC_DIV_POW_REG, - ((data & 0x80)|(aic3262_divs[i].mdac))); - DBG(KERN_INFO "# writing MDAC = %d , MDAC_DIV_POW_REG = %x\n", - aic3262_divs[i].mdac, ((data & 0x80)|(aic3262_divs[i].mdac))); - - /* DOSR MSB & LSB values */ - snd_soc_write(codec, DOSR_MSB_REG, aic3262_divs[i].dosr >> 8); - DBG(KERN_INFO "# writing DOSR_MSB_REG = %d\n", - (aic3262_divs[i].dosr >> 8)); - snd_soc_write(codec, DOSR_LSB_REG, - aic3262_divs[i].dosr & AIC3262_8BITS_MASK); - DBG(KERN_INFO "# writing DOSR_LSB_REG = %d\n", - (aic3262_divs[i].dosr & AIC3262_8BITS_MASK)); - - /* NADC divider value */ - data = snd_soc_read(codec, NADC_DIV_POW_REG); - snd_soc_write(codec, NADC_DIV_POW_REG, - ((data & 0x80)|(aic3262_divs[i].nadc))); - DBG(KERN_INFO "# writing NADC_DIV_POW_REG = %d\n", - aic3262_divs[i].nadc); - - /* MADC divider value */ - data = snd_soc_read(codec, MADC_DIV_POW_REG); - snd_soc_write(codec, MADC_DIV_POW_REG, - ((data & 0x80)|(aic3262_divs[i].madc))); - DBG(KERN_INFO "# writing MADC_DIV_POW_REG = %d\n", - aic3262_divs[i].madc); - - /* AOSR value */ - snd_soc_write(codec, AOSR_REG, aic3262_divs[i].aosr); - DBG(KERN_INFO "# writing AOSR = %d\n", aic3262_divs[i].aosr); - } else { - DBG(KERN_INFO "#Atleast 1 ASI Active. Cannot Program PLL..\n"); - } - /* Check for the DAI ID to know which ASI needs - * Configuration. - */ - switch (dai->id) { - case 1: - regoffset = ASI1_BUS_FMT; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - DBG(KERN_INFO "#%s: ASI1 DAC Inputs enabled..\n", - __func__); - /* Read the DAC Control Register and configure it - * as per the ASIContext Structure Settings. - */ - dacpath = snd_soc_read(codec, ASI1_DAC_OUT_CNTL); - dacpath &= ~(AIC3262_ASI_LDAC_PATH_MASK | - AIC3262_ASI_RDAC_PATH_MASK); - dacpath |= (aic3262->asiCtxt[0].left_dac_output - << AIC3262_ASI_LDAC_PATH_SHIFT); - - dacpath |= (aic3262->asiCtxt[0].right_dac_output - << AIC3262_ASI_RDAC_PATH_SHIFT); - snd_soc_write(codec, ASI1_DAC_OUT_CNTL, dacpath); - - aic3262->asiCtxt[0].playback_mode = 1; - aic3262->asiCtxt[0].bclk_div = - aic3262_divs[i].blck_N; - } else { - /* For Recording, Configure the DOUT Pin as per - * ASIContext Structure Settings. - */ - adcpath = snd_soc_read(codec, ASI1_DATA_OUT); - adcpath &= ~(AIC3262_ASI_DOUT_MASK); - - adcpath |= aic3262->asiCtxt[0].dout_option; - snd_soc_write(codec, ASI1_DATA_OUT, adcpath); - - aic3262->asiCtxt[0].capture_mode = 1; - } - break; - case 2: - regoffset = ASI2_BUS_FMT; - - /* Since we are configuring ASI2, please check if Playback - * is expected. If so, enable ASI2 Inputs to Left and - * Right DACs - */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - DBG(KERN_INFO "#%s: ASI2 DAC Inputs enabled..\n", - __func__); - /* Read the DAC Control Register and configure it - * as per theASIContext Structure Settings. - */ - dacpath = snd_soc_read(codec, ASI2_DAC_OUT_CNTL); - dacpath &= ~(AIC3262_ASI_LDAC_PATH_MASK | - AIC3262_ASI_RDAC_PATH_MASK); - dacpath |= (aic3262->asiCtxt[1].left_dac_output - << AIC3262_ASI_LDAC_PATH_SHIFT); - - dacpath |= (aic3262->asiCtxt[1].right_dac_output - << AIC3262_ASI_RDAC_PATH_SHIFT); - snd_soc_write(codec, ASI2_DAC_OUT_CNTL, dacpath); - aic3262->asiCtxt[1].playback_mode = 1; - - aic3262->asiCtxt[1].bclk_div = - aic3262_divs[i].blck_N; - } else { - /* For Recording, Configure the DOUT Pin as per - * ASIContext Structure Settings. - */ - adcpath = snd_soc_read(codec, ASI2_DATA_OUT); - adcpath &= ~(AIC3262_ASI_DOUT_MASK); - adcpath |= aic3262->asiCtxt[1].dout_option; - snd_soc_write(codec, ASI2_DATA_OUT, adcpath); - - aic3262->asiCtxt[1].capture_mode = 1; - } - break; - case 3: - regoffset = ASI3_BUS_FMT; - /* Since we are configuring ASI3, please check if Playback - * is expected. If so, enable ASI3 Inputs to Left and - * Right DACs - */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - DBG(KERN_INFO "#%s:ASI3 DAC Inputs enabled.\n", - __func__); - /* Read the DAC Control Register and configure - * it as per the ASIContext Structure Settings. - */ - dacpath = snd_soc_read(codec, ASI3_DAC_OUT_CNTL); - dacpath &= ~(AIC3262_ASI_LDAC_PATH_MASK | - AIC3262_ASI_RDAC_PATH_MASK); - dacpath |= (aic3262->asiCtxt[2].left_dac_output - << AIC3262_ASI_LDAC_PATH_SHIFT); - dacpath |= (aic3262->asiCtxt[2].right_dac_output - << AIC3262_ASI_RDAC_PATH_SHIFT); - snd_soc_write(codec, - ASI3_DAC_OUT_CNTL, dacpath); - - aic3262->asiCtxt[2].playback_mode = 1; - - aic3262->asiCtxt[2].bclk_div = - aic3262_divs[i].blck_N; - } else { - /* For Recording, Configure the DOUT Pin as per - * ASIContext Structure Settings. - */ - adcpath &= ~(AIC3262_ASI_DOUT_MASK); - adcpath |= aic3262->asiCtxt[2].dout_option; - snd_soc_write(codec, ASI3_DATA_OUT, adcpath); - - aic3262->asiCtxt[2].capture_mode = 1; - } - break; - default: - printk(KERN_ERR "Invalid Dai ID %d in %s", - dai->id, __func__); - break; - } - DBG(KERN_INFO "#%s: Reading Pg %d Reg %d for Bus Format Control.\n", - __func__, (regoffset/128), (regoffset % 128)); - - /* Read the correspondig ASI DAI Interface Register */ - data = snd_soc_read(codec, regoffset); - - data = data & 0xe7; - - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - DBG(KERN_INFO "#%s: Configuring ASI%d S16_LE Fmt..\n", - __func__, dai->id); - data = data | 0x00; - aic3262->asiCtxt[dai->id - 1].word_len = 16; - break; - case SNDRV_PCM_FORMAT_S20_3LE: - data |= (0x08); - aic3262->asiCtxt[dai->id - 1].word_len = 20; - break; - case SNDRV_PCM_FORMAT_S24_LE: - DBG(KERN_INFO "#%s: Configuring ASI%d S24_LE Fmt..\n", - __func__, dai->id); - data |= (0x10); - aic3262->asiCtxt[dai->id - 1].word_len = 24; - break; - case SNDRV_PCM_FORMAT_S32_LE: - DBG(KERN_INFO "#%s: Configuring ASI%d S32_LE Fmt..\n", - __func__, dai->id); - data |= (0x18); - aic3262->asiCtxt[dai->id - 1].word_len = 32; - break; - } - - /* configure the respective Registers for the above configuration */ - snd_soc_write(codec, regoffset, data); - - for (j = 0; j < NO_FEATURE_REGS; j++) { - snd_soc_write(codec, - aic3262_divs[i].codec_specific_regs[j].reg_offset, - aic3262_divs[i].codec_specific_regs[j].reg_val); - } - - /* Enable the PLL, MDAC, NDAC, NADC, MADC and BCLK Dividers */ - aic3262_set_bias_level(codec, SND_SOC_BIAS_ON); - - /* Based on the DAI ID we enable the corresponding pins related to the - * ASI Port. - */ - switch (dai->id) { - case 1: - aic3262_asi1_clk_config(codec, params); - break; - case 2: - aic3262_asi2_clk_config(codec, params); - break; - case 3: - aic3262_asi3_clk_config(codec, params); - break; - default: - printk(KERN_ERR "Invalid Dai ID %d in %s", - dai->id, __func__); - break; - } - /* Depending on the DAI->ID update the local Flags */ - aic3262->asiCtxt[dai->id - 1].asi_active++; - aic3262->asiCtxt[dai->id - 1].sampling_rate = params_rate(params); - /* Update the active_count flag */ - aic3262->active_count++; - - return 0; -} - -/* -* -* aic3262_multi_i2s_hw_free -* -* This function is used to configure the Codec after the usage is completed. -* We can use this function to disable the DAC and ADC specific inputs from the -* individual ASI Ports of the Audio Codec. -*/ -static void aic3262_multi_i2s_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->codec; - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - - u8 value; - u8 dacpath; - u8 adcpath; - u16 dacregoffset = 0; - u16 adcregoffset = 0; - - DBG(KERN_INFO "#%s: ASI%d Port for %s Mode\n", - __func__, dai->id, - (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? - "Playback" : "Record"); - - /* Check if this function was already executed earlier for the same - * ASI Port - */ - if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) && - (aic3262->asiCtxt[dai->id - 1].playback_mode == 0)) { - DBG(KERN_INFO "#%s: Function Already Executed. Exiting..\n", - __func__); - goto err; - } else if ((substream->stream != SNDRV_PCM_STREAM_PLAYBACK) && - (aic3262->asiCtxt[dai->id - 1].capture_mode == 0)) { - DBG(KERN_INFO "#%s: Function Already Executed. Exiting..\n", - __func__); - goto err; - } - - switch (dai->id) { - case 1: - /* In case we are Frame Master on this Interface, Switch off - * the Bit Clock Divider and Word Clock Dividers - */ - if (aic3262->asiCtxt[0].master == 1) { - /* Also check if either Playback or Recording is still - * going on this ASI Interface - */ - - value = snd_soc_read(codec, ASI1_BCLK_N); - snd_soc_write(codec, ASI1_BCLK_N, (value & 0x7f)); - - value = snd_soc_read(codec, ASI1_WCLK_N); - snd_soc_write(codec, ASI1_WCLK_N, (value & 0x7f)); - } - - dacregoffset = ASI1_DAC_OUT_CNTL; - adcregoffset = ASI1_ADC_INPUT_CNTL; - break; - case 2: - /* In case we are Frame Master on this Interface, Switch off - * the Bit Clock Divider and Word Clock Dividers - */ - if (aic3262->asiCtxt[1].master == 1) { - value = snd_soc_read(codec, ASI2_BCLK_N); - snd_soc_write(codec, ASI2_BCLK_N, (value & 0x7f)); - - value = snd_soc_read(codec, ASI2_WCLK_N); - snd_soc_write(codec, ASI2_WCLK_N, (value & 0x7f)); - } - dacregoffset = ASI2_DAC_OUT_CNTL; - adcregoffset = ASI2_ADC_INPUT_CNTL; - break; - case 3: - /* In case we are Frame Master on this Interface, Switch off - * the Bit Clock Divider and Word Clock Dividers - */ - if (aic3262->asiCtxt[2].master == 1) { - value = snd_soc_read(codec, ASI3_BCLK_N); - snd_soc_write(codec, ASI3_BCLK_N, (value & 0x7f)); - - value = snd_soc_read(codec, ASI3_WCLK_N); - snd_soc_write(codec, ASI3_WCLK_N, (value & 0x7f)); - } - dacregoffset = ASI3_DAC_OUT_CNTL; - adcregoffset = ASI3_ADC_INPUT_CNTL; - break; - default: - printk(KERN_ERR "#%s: Invalid dai id\n", __func__); - } - /* If this was a Playback Stream Stop, then only - * switch off the DAC Inputs - */ - if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) && - (dacregoffset != 0)) { - DBG(KERN_INFO "#%s: Disabling Pg %d Reg %d DAC Inputs ..\n", - __func__, (dacregoffset/128), (dacregoffset % 128)); - - dacpath = snd_soc_read(codec, dacregoffset); - snd_soc_write(codec, dacregoffset, (dacpath & ~(BIT6 | BIT4))); - - aic3262->asiCtxt[dai->id - 1].playback_mode = 0; - } else { - /* Switch off the ADC Input Control Registers here */ - DBG(KERN_INFO "#%s: Disabling Pg %d Reg %d for ADC Inputs..\n", - __func__, (adcregoffset/128), (adcregoffset % 128)); - - adcpath = snd_soc_read(codec, adcregoffset); - snd_soc_write(codec, adcregoffset, - (adcpath & ~(BIT2 | BIT1 | BIT0))); - - aic3262->asiCtxt[dai->id - 1].capture_mode = 0; - } - - /* If we were configured in mono PCM Mode earlier, then reset the - * Left Channel and Right Channel offset Registers here. - */ - switch (dai->id) { - case 1: - if (aic3262->asiCtxt[0].pcm_format == SND_SOC_DAIFMT_DSP_B) { - snd_soc_write(codec, ASI1_LCH_OFFSET, 0x00); - snd_soc_write(codec, ASI1_RCH_OFFSET, 0x00); - } - break; - case 2: - if (aic3262->asiCtxt[1].pcm_format == SND_SOC_DAIFMT_DSP_B) { - snd_soc_write(codec, ASI2_LCH_OFFSET, 0x00); - snd_soc_write(codec, ASI2_RCH_OFFSET, 0x00); - } - - break; - case 3: - if (aic3262->asiCtxt[2].pcm_format == SND_SOC_DAIFMT_DSP_B) { - snd_soc_write(codec, ASI3_LCH_OFFSET, 0x00); - snd_soc_write(codec, ASI3_RCH_OFFSET, 0x00); - } - break; - } - /* Depending on the DAI->ID update the asi_active Flags */ - if (aic3262->asiCtxt[dai->id - 1].asi_active) { - aic3262->asiCtxt[dai->id - 1].asi_active--; - - /* Update the active_count flag */ - if (aic3262->active_count) - aic3262->active_count--; - } -err: - return; -} - - -/* -* -* aic3262_multi_i2s_set_clkdiv -* -*/ -static int aic3262_multi_i2s_set_clkdiv(struct snd_soc_dai *codec_dai, int div_id, int div) -{ - int value; - struct snd_soc_codec *codec = codec_dai->codec; - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - - - value = snd_soc_read(codec, div_id); - snd_soc_write(codec, div_id, (value | div)); - - printk(KERN_INFO "#%s: DAI ID %d Page %d Register %d Divider_Val %d Final_Value 0x%x\n", - __func__, codec_dai->id, (div_id /128), (div_id%128), div, - (value | div)); - - /* Store the Clock Divider inside the Private Structure */ - switch(codec_dai->id) { - case 1: - if (div_id == ASI1_BCLK_N) - aic3262->asiCtxt[0].bclk_div = div; - if (div_id == ASI1_WCLK_N) - aic3262->asiCtxt[0].wclk_div = div; - break; - case 2: - if (div_id == ASI2_BCLK_N) - aic3262->asiCtxt[1].bclk_div = div; - if (div_id == ASI2_WCLK_N) - aic3262->asiCtxt[1].wclk_div = div; - break; - case 3: - if (div_id == ASI3_BCLK_N) - aic3262->asiCtxt[2].bclk_div = div; - if (div_id == ASI3_WCLK_N) - aic3262->asiCtxt[2].wclk_div = div; - break; - } - return 0; -} - - /* *---------------------------------------------------------------------------- * @struct snd_soc_codec_dai | - * It is SoC Codec DAI structure which has DAI capabilities viz., - * playback and capture, DAI runtime information viz. state of DAI + * It is SoC Codec DAI structure which has DAI capabilities viz., + * playback and capture, DAI runtime information viz. state of DAI * and pop wait state, and DAI private data. - * The AIC3262 rates ranges from 8k to 192k - * The PCM bit format supported are 16, 20, 24 and 32 bits + * The AIC3262 rates ranges from 8k to 192k + * The PCM bit format supported are 16, 20, 24 and 32 bits *---------------------------------------------------------------------------- */ -struct snd_soc_dai_ops aic3262_multi_i2s_dai_ops = { - .hw_params = aic3262_multi_i2s_hw_params, - .digital_mute = aic3262_multi_i2s_mute, - .set_fmt = aic3262_multi_i2s_set_dai_fmt, - .set_pll = aic3262_multi_i2s_set_dai_pll, - .set_sysclk = aic3262_multi_i2s_set_dai_sysclk, - .shutdown = aic3262_multi_i2s_shutdown, - .set_clkdiv = aic3262_multi_i2s_set_clkdiv, +struct snd_soc_dai_ops aic3262_asi1_dai_ops = { + .hw_params = aic3262_hw_params, + .digital_mute = aic3262_mute, + .set_sysclk = aic3262_set_dai_sysclk, + .set_fmt = aic3262_set_dai_fmt, + .set_pll = aic3262_dai_set_pll, }; - -static struct snd_soc_dai_driver tlv320aic3262_dai[] = { -/* AIC3262 ASI1 DAI */ -{ - .name = "aic3262-asi1", - .id = 1, - .playback = { - .stream_name = "ASI1 Playback", - .channels_min = 1, - .channels_max = 2, - .rates = AIC3262_RATES, - .formats = AIC3262_FORMATS}, - .capture = { /* dummy for fast DAI switching */ - .stream_name = "ASI1 Capture", - .channels_min = 1, - .channels_max = 2, - .rates = AIC3262_RATES, - .formats = AIC3262_FORMATS}, - .ops = &aic3262_multi_i2s_dai_ops, -}, -/* AIC3262 ASI2 DAI */ -{ - .name = "aic3262-asi2", - .id = 2, - .playback = { - .stream_name = "ASI2 Playback", - .channels_min = 1, - .channels_max = 2, - .rates = AIC3262_RATES, - .formats = AIC3262_FORMATS,}, - .capture = { - .stream_name = "ASI2 Capture", - .channels_min = 1, - .channels_max = 2, - .rates = AIC3262_RATES, - .formats = AIC3262_FORMATS,}, - .ops = &aic3262_multi_i2s_dai_ops, - -}, -/* AIC3262 ASI3 DAI */ -{ - .name = "aic3262-asi3", - .id = 3, - .playback = { - .stream_name = "ASI3 Playback", - .channels_min = 1, - .channels_max = 2, - .rates = AIC3262_RATES, - .formats = AIC3262_FORMATS, }, - .capture = { - .stream_name = "ASI3 Capture", - .channels_min = 1, - .channels_max = 2, - .rates = AIC3262_RATES, - .formats = AIC3262_FORMATS, }, - .ops = &aic3262_multi_i2s_dai_ops, - -}, +struct snd_soc_dai_ops aic3262_asi2_dai_ops = { + .hw_params = aic3262_hw_params, + .digital_mute = aic3262_mute, + .set_sysclk = aic3262_set_dai_sysclk, + .set_fmt = aic3262_set_dai_fmt, + .set_pll = aic3262_dai_set_pll, }; -/* - ***************************************************************************** - * Initializations - ***************************************************************************** - */ -/* - * AIC3262 register cache - * We are caching the registers here. - * There is no point in caching the reset register. - * - * NOTE: In AIC3262, there are 127 registers supported in both page0 and page1 - * The following table contains the page0 and page 1 and page 3 - * registers values. - */ -static const u8 aic3262_reg[AIC3262_CACHEREGNUM] = { - 0x00, 0x00, 0x10, 0x00, /* 0 */ - 0x03, 0x40, 0x11, 0x08, /* 4 */ - 0x00, 0x00, 0x00, 0x82, /* 8 */ - 0x88, 0x00, 0x80, 0x02, /* 12 */ - 0x00, 0x08, 0x01, 0x01, /* 16 */ - 0x80, 0x01, 0x00, 0x04, /* 20 */ - 0x00, 0x00, 0x01, 0x00, /* 24 */ - 0x00, 0x00, 0x01, 0x00, /* 28 */ - 0x00, 0x00, 0x00, 0x00, /* 32 */ - 0x00, 0x00, 0x00, 0x00, /* 36 */ - 0x00, 0x00, 0x00, 0x00, /* 40 */ - 0x00, 0x00, 0x00, 0x00, /* 44 */ - 0x00, 0x00, 0x00, 0x00, /* 48 */ - 0x00, 0x42, 0x02, 0x02, /* 52 */ - 0x42, 0x02, 0x02, 0x02, /* 56 */ - 0x00, 0x00, 0x00, 0x01, /* 60 */ - 0x01, 0x00, 0x14, 0x00, /* 64 */ - 0x0C, 0x00, 0x00, 0x00, /* 68 */ - 0x00, 0x00, 0x00, 0xEE, /* 72 */ - 0x10, 0xD8, 0x10, 0xD8, /* 76 */ - 0x00, 0x00, 0x88, 0x00, /* 80 */ - 0x00, 0x00, 0x00, 0x00, /* 84 */ - 0x7F, 0x00, 0x00, 0x00, /* 88 */ - 0x00, 0x00, 0x00, 0x00, /* 92 */ - 0x7F, 0x00, 0x00, 0x00, /* 96 */ - 0x00, 0x00, 0x00, 0x00, /* 100 */ - 0x00, 0x00, 0x00, 0x00, /* 104 */ - 0x00, 0x00, 0x00, 0x00, /* 108 */ - 0x00, 0x00, 0x00, 0x00, /* 112 */ - 0x00, 0x00, 0x00, 0x00, /* 116 */ - 0x00, 0x00, 0x00, 0x00, /* 120 */ - 0x00, 0x00, 0x00, 0x00, /* 124 - PAGE0 Registers(127) ends here */ - 0x01, 0x00, 0x08, 0x00, /* 128, PAGE1-0 */ - 0x00, 0x00, 0x00, 0x00, /* 132, PAGE1-4 */ - 0x00, 0x00, 0x00, 0x10, /* 136, PAGE1-8 */ - 0x00, 0x00, 0x00, 0x00, /* 140, PAGE1-12 */ - 0x40, 0x40, 0x40, 0x40, /* 144, PAGE1-16 */ - 0x00, 0x00, 0x00, 0x00, /* 148, PAGE1-20 */ - 0x00, 0x00, 0x00, 0x00, /* 152, PAGE1-24 */ - 0x00, 0x00, 0x00, 0x00, /* 156, PAGE1-28 */ - 0x00, 0x00, 0x00, 0x00, /* 160, PAGE1-32 */ - 0x00, 0x00, 0x00, 0x00, /* 164, PAGE1-36 */ - 0x00, 0x00, 0x00, 0x00, /* 168, PAGE1-40 */ - 0x00, 0x00, 0x00, 0x00, /* 172, PAGE1-44 */ - 0x00, 0x00, 0x00, 0x00, /* 176, PAGE1-48 */ - 0x00, 0x00, 0x00, 0x00, /* 180, PAGE1-52 */ - 0x00, 0x00, 0x00, 0x80, /* 184, PAGE1-56 */ - 0x80, 0x00, 0x00, 0x00, /* 188, PAGE1-60 */ - 0x00, 0x00, 0x00, 0x00, /* 192, PAGE1-64 */ - 0x00, 0x00, 0x00, 0x00, /* 196, PAGE1-68 */ - 0x00, 0x00, 0x00, 0x00, /* 200, PAGE1-72 */ - 0x00, 0x00, 0x00, 0x00, /* 204, PAGE1-76 */ - 0x00, 0x00, 0x00, 0x00, /* 208, PAGE1-80 */ - 0x00, 0x00, 0x00, 0x00, /* 212, PAGE1-84 */ - 0x00, 0x00, 0x00, 0x00, /* 216, PAGE1-88 */ - 0x00, 0x00, 0x00, 0x00, /* 220, PAGE1-92 */ - 0x00, 0x00, 0x00, 0x00, /* 224, PAGE1-96 */ - 0x00, 0x00, 0x00, 0x00, /* 228, PAGE1-100 */ - 0x00, 0x00, 0x00, 0x00, /* 232, PAGE1-104 */ - 0x00, 0x00, 0x00, 0x00, /* 236, PAGE1-108 */ - 0x00, 0x00, 0x00, 0x00, /* 240, PAGE1-112 */ - 0x00, 0x00, 0x00, 0x00, /* 244, PAGE1-116 */ - 0x00, 0x00, 0x00, 0x00, /* 248, PAGE1-120 */ - 0x00, 0x00, 0x00, 0x00, /* 252, PAGE1-124 Page 1 Registers Ends Here */ - 0x00, 0x00, 0x00, 0x00, /* 256, PAGE2-0 */ - 0x00, 0x00, 0x00, 0x00, /* 260, PAGE2-4 */ - 0x00, 0x00, 0x00, 0x00, /* 264, PAGE2-8 */ - 0x00, 0x00, 0x00, 0x00, /* 268, PAGE2-12 */ - 0x00, 0x00, 0x00, 0x00, /* 272, PAGE2-16 */ - 0x00, 0x00, 0x00, 0x00, /* 276, PAGE2-20 */ - 0x00, 0x00, 0x00, 0x00, /* 280, PAGE2-24 */ - 0x00, 0x00, 0x00, 0x00, /* 284, PAGE2-28 */ - 0x00, 0x00, 0x00, 0x00, /* 288, PAGE2-32 */ - 0x00, 0x00, 0x00, 0x00, /* 292, PAGE2-36 */ - 0x00, 0x00, 0x00, 0x00, /* 296, PAGE2-40 */ - 0x00, 0x00, 0x00, 0x00, /* 300, PAGE2-44 */ - 0x00, 0x00, 0x00, 0x00, /* 304, PAGE2-48 */ - 0x00, 0x00, 0x00, 0x00, /* 308, PAGE2-52 */ - 0x00, 0x00, 0x00, 0x00, /* 312, PAGE2-56 */ - 0x00, 0x00, 0x00, 0x00, /* 316, PAGE2-60 */ - 0x00, 0x00, 0x00, 0x00, /* 320, PAGE2-64 */ - 0x00, 0x00, 0x00, 0x00, /* 324, PAGE2-68 */ - 0x00, 0x00, 0x00, 0x00, /* 328, PAGE2-72 */ - 0x00, 0x00, 0x00, 0x00, /* 332, PAGE2-76 */ - 0x00, 0x00, 0x00, 0x00, /* 336, PAGE2-80 */ - 0x00, 0x00, 0x00, 0x00, /* 340, PAGE2-84 */ - 0x00, 0x00, 0x00, 0x00, /* 344, PAGE2-88 */ - 0x00, 0x00, 0x00, 0x00, /* 348, PAGE2-92 */ - 0x00, 0x00, 0x00, 0x00, /* 352, PAGE2-96 */ - 0x00, 0x00, 0x00, 0x00, /* 356, PAGE2-100 */ - 0x00, 0x00, 0x00, 0x00, /* 360, PAGE2-104 */ - 0x00, 0x00, 0x00, 0x00, /* 364, PAGE2-108 */ - 0x00, 0x00, 0x00, 0x00, /* 368, PAGE2-112*/ - 0x00, 0x00, 0x00, 0x00, /* 372, PAGE2-116*/ - 0x00, 0x00, 0x00, 0x00, /* 376, PAGE2-120*/ - 0x00, 0x00, 0x00, 0x00, /* 380, PAGE2-124 Page 2 Registers Ends Here */ - 0x00, 0x00, 0x00, 0x00, /* 384, PAGE3-0 */ - 0x00, 0x00, 0x00, 0x00, /* 388, PAGE3-4 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-8 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-12 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-16 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-20 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-24 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-28 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-32 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-36 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-40 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-44 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-48 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-52 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-56 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-60 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-64 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-68 */ - 0x00, 0x00, 0x00, 0x00, /* 328, PAGE3-72 */ - 0x00, 0x00, 0x00, 0x00, /* 332, PAGE3-76 */ - 0x00, 0x00, 0x00, 0x00, /* 336, PAGE3-80 */ - 0x00, 0x00, 0x00, 0x00, /* 340, PAGE3-84 */ - 0x00, 0x00, 0x00, 0x00, /* 344, PAGE3-88 */ - 0x00, 0x00, 0x00, 0x00, /* 348, PAGE3-92 */ - 0x00, 0x00, 0x00, 0x00, /* 352, PAGE3-96 */ - 0x00, 0x00, 0x00, 0x00, /* 356, PAGE3-100 */ - 0x00, 0x00, 0x00, 0x00, /* 360, PAGE3-104 */ - 0x00, 0x00, 0x00, 0x00, /* 364, PAGE3-108 */ - 0x00, 0x00, 0x00, 0x00, /* 368, PAGE3-112*/ - 0x00, 0x00, 0x00, 0x00, /* 372, PAGE3-116*/ - 0x00, 0x00, 0x00, 0x00, /* 376, PAGE3-120*/ - 0x00, 0x00, 0x00, 0x00, /* 380, PAGE3-124 Page 3 Registers Ends Here */ - 0x00, 0x00, 0x00, 0x00, /* 384, PAGE4-0 */ - 0x00, 0x00, 0x00, 0x00, /* 388, PAGE4-4 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-8 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-12 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-16 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-20 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-24 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-28 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-32 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-36 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-40 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-44 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-48 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-52 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-56 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-60 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-64 */ - 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-68 */ - 0x00, 0x00, 0x00, 0x00, /* 328, PAGE4-72 */ - 0x00, 0x00, 0x00, 0x00, /* 332, PAGE4-76 */ - 0x00, 0x00, 0x00, 0x00, /* 336, PAGE4-80 */ - 0x00, 0x00, 0x00, 0x00, /* 340, PAGE4-84 */ - 0x00, 0x00, 0x00, 0x00, /* 344, PAGE4-88 */ - 0x00, 0x00, 0x00, 0x00, /* 348, PAGE4-92 */ - 0x00, 0x00, 0x00, 0x00, /* 352, PAGE4-96 */ - 0x00, 0x00, 0x00, 0x00, /* 356, PAGE4-100 */ - 0x00, 0x00, 0x00, 0x00, /* 360, PAGE4-104 */ - 0x00, 0x00, 0x00, 0x00, /* 364, PAGE4-108 */ - 0x00, 0x00, 0x00, 0x00, /* 368, PAGE4-112*/ - 0x00, 0x00, 0x00, 0x00, /* 372, PAGE4-116*/ - 0x00, 0x00, 0x00, 0x00, /* 376, PAGE4-120*/ - 0x00, 0x00, 0x00, 0x00, /* 380, PAGE4-124 Page 2 Registers Ends Here */ - +struct snd_soc_dai_ops aic3262_asi3_dai_ops = { + .hw_params = aic3262_hw_params, + .digital_mute = aic3262_mute, + .set_sysclk = aic3262_set_dai_sysclk, + .set_fmt = aic3262_set_dai_fmt, + .set_pll = aic3262_dai_set_pll, }; -/* - *------------------------------------------------------------------------------ - * aic3262 initialization data - * This structure initialization contains the initialization required for - * AIC326x. - * These registers values (reg_val) are written into the respective AIC3262 - * register offset (reg_offset) to initialize AIC326x. - * These values are used in aic3262_init() function only. - *------------------------------------------------------------------------------ - */ -static const struct aic3262_configs aic3262_reg_init[] = { - /* CLOCKING */ - - {0, RESET_REG, 1}, - {0, RESET_REG, 0}, - - {0, PASI_DAC_DP_SETUP, 0xc0}, /*DAC */ - {0, DAC_MVOL_CONF, 0x00}, /*DAC un-muted*/ - /* set default volumes */ - {0, DAC_LVOL, 0x01}, - {0, DAC_RVOL, 0x01}, - {0, HPL_VOL, 0x80}, - {0, HPR_VOL, 0x80}, - {0, SPK_AMP_CNTL_R2, 0x14}, - {0, SPK_AMP_CNTL_R3, 0x14}, - {0, SPK_AMP_CNTL_R4, 0x33}, - {0, REC_AMP_CNTL_R5, 0x82}, - {0, RAMPR_VOL, 20}, - {0, RAMP_CNTL_R1, 70}, - {0, RAMP_CNTL_R2, 70}, - - /* DRC Defaults */ - {0, DRC_CNTL_R1, 0x6c}, - {0, DRC_CNTL_R2, 16}, - - /* DEPOP SETTINGS */ - {0, HP_DEPOP, 0x14}, - {0, RECV_DEPOP, 0x14}, - - {0, POWER_CONF, 0x00}, /* Disconnecting AVDD-DVD weak link*/ - {0, REF_PWR_DLY, 0x01}, - {0, CM_REG, 0x00}, /*CM - default*/ - {0, LDAC_PTM, 0}, /*LDAC_PTM - default*/ - {0, RDAC_PTM, 0}, /*RDAC_PTM - default*/ - {0, HP_CTL, 0x30}, /*HP output percentage - at 75%*/ - {0, LADC_VOL, 0x01}, /*LADC volume*/ - {0, RADC_VOL, 0x01}, /*RADC volume*/ - - {0, DAC_ADC_CLKIN_REG, 0x33}, /*DAC ADC CLKIN*/ - {0, PLL_CLKIN_REG, 0x00}, /*PLL CLKIN*/ - {0, PLL_PR_POW_REG, 0x11}, /*PLL Power=0-down, P=1, R=1 vals*/ - {0, 0x3d, 1}, - - {0, LMIC_PGA_PIN, 0x0}, /*IN1_L select - - 10k -LMICPGA_P*/ - {0, LMIC_PGA_MIN, 0x40}, /*CM to LMICPGA-M*/ - {0, RMIC_PGA_PIN, 0x0}, /*IN1_R select - - 10k -RMIC_PGA_P*/ - {0, RMIC_PGA_MIN, 0x0}, /*CM to RMICPGA_M*/ - {0, MIC_PWR_DLY , 33}, /*LMIC-PGA-POWERUP-DELAY - default*/ - {0, REF_PWR_DLY, 1}, /*FIXMELATER*/ - - - {0, ADC_CHANNEL_POW, 0x0}, /*ladc, radc ON , SOFT STEP disabled*/ - {0, ADC_FINE_GAIN, 0x00}, /*ladc - unmute, radc - unmute*/ - {0, MICL_PGA, 0x3f}, - {0, MICR_PGA, 0x3f}, - /*controls MicBias ext power based on B0_P1_R51_D6*/ - {0, MIC_BIAS_CNTL, 0x80}, - /* ASI1 Configuration */ - {0, ASI1_BUS_FMT, 0}, - {0, ASI1_BWCLK_CNTL_REG, 0x00}, /* originaly 0x24*/ - {0, ASI1_BCLK_N_CNTL, 1}, - {0, ASI1_BCLK_N, 0x04}, - - {0, MA_CNTL, 0}, /* Mixer Amp disabled */ - {0, LINE_AMP_CNTL_R2, 0x00}, /* Line Amp Cntl disabled */ - - /* ASI2 Configuration */ - {0, ASI2_BUS_FMT, 0}, - {0, ASI2_BCLK_N_CNTL, 0x01}, - {0, ASI2_BCLK_N, 0x04}, - {0, ASI2_BWCLK_OUT_CNTL, 0x20}, - - {0, BEEP_CNTL_R1, 0x05}, - {0, BEEP_CNTL_R2, 0x04}, - - /* Interrupt config for headset detection */ - {0,HEADSET_TUNING1_REG,0x7f}, - {0, INT1_CNTL, 0x40}, - /*{0, TIMER_REG, 0x8c},*/ - {0, INT_FMT, 0x40}, - {0, GPIO1_IO_CNTL, 0x14}, - {0, HP_DETECT, 0x96}, - -#if defined(CONFIG_MINI_DSP) - {0, 60, 0}, - {0, 61, 0}, - /* Added the below set of values after consulting the miniDSP - * Program Section Array - */ - {0, MINIDSP_ACCESS_CTRL, 0x00}, -#endif - +struct snd_soc_dai_driver aic326x_dai_driver[] = { + { + .name = "aic326x-asi1", + .playback = { + .stream_name = "ASI1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = AIC3262_RATES, + .formats = AIC3262_FORMATS, + }, + .capture = { + .stream_name = "ASI1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = AIC3262_RATES, + .formats = AIC3262_FORMATS, + }, + .ops = &aic3262_asi1_dai_ops, + }, + { + .name = "aic326x-asi2", + .playback = { + .stream_name = "ASI2 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = AIC3262_RATES, + .formats = AIC3262_FORMATS, + }, + .capture = { + .stream_name = "ASI2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = AIC3262_RATES, + .formats = AIC3262_FORMATS, + }, + .ops = &aic3262_asi2_dai_ops, + }, + { + .name = "aic326x-asi3", + .playback = { + .stream_name = "ASI3 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = AIC3262_RATES, + .formats = AIC3262_FORMATS, + }, + .capture = { + .stream_name = "ASI3 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = AIC3262_RATES, + .formats = AIC3262_FORMATS, + }, + .ops = &aic3262_asi3_dai_ops, + }, }; -static int reg_init_size = - sizeof(aic3262_reg_init) / sizeof(struct aic3262_configs); static const unsigned int adc_ma_tlv[] = { -TLV_DB_RANGE_HEAD(4), + TLV_DB_RANGE_HEAD(4), 0, 29, TLV_DB_SCALE_ITEM(-1450, 500, 0), 30, 35, TLV_DB_SCALE_ITEM(-2060, 1000, 0), 36, 38, TLV_DB_SCALE_ITEM(-2660, 2000, 0), 39, 40, TLV_DB_SCALE_ITEM(-3610, 5000, 0), }; -static const DECLARE_TLV_DB_SCALE(lo_hp_tlv, -7830, 50, 0); +static const DECLARE_TLV_DB_SCALE(lo_hp_tlv, -7830, 50, 0); static const struct snd_kcontrol_new mal_pga_mixer_controls[] = { - SOC_DAPM_SINGLE("IN1L Switch", MA_CNTL, 5, 1, 0), - SOC_DAPM_SINGLE_TLV("Left MicPGA Volume", LADC_PGA_MAL_VOL, 0, - 0x3f, 1, adc_ma_tlv), - + SOC_DAPM_SINGLE("IN1L Switch", AIC3262_MA_CNTL, 5, 1, 0), + SOC_DAPM_SINGLE_TLV("Left MicPGA Volume", AIC3262_LADC_PGA_MAL_VOL, + 0, 0x3f, 1, adc_ma_tlv), }; static const struct snd_kcontrol_new mar_pga_mixer_controls[] = { - SOC_DAPM_SINGLE("IN1R Switch", MA_CNTL, 4, 1, 0), - SOC_DAPM_SINGLE_TLV("Right MicPGA Volume", RADC_PGA_MAR_VOL, 0, - 0x3f, 1, adc_ma_tlv), + SOC_DAPM_SINGLE("IN1R Switch", AIC3262_MA_CNTL, 4, 1, 0), + SOC_DAPM_SINGLE_TLV("Right MicPGA Volume", AIC3262_RADC_PGA_MAR_VOL, + 0, 0x3f, 1, adc_ma_tlv), }; /* Left HPL Mixer */ static const struct snd_kcontrol_new hpl_output_mixer_controls[] = { - SOC_DAPM_SINGLE("MAL Switch", HP_AMP_CNTL_R1, 7, 1, 0), - SOC_DAPM_SINGLE("LDAC Switch", HP_AMP_CNTL_R1, 5, 1, 0), - SOC_DAPM_SINGLE_TLV("LOL-B1 Volume", HP_AMP_CNTL_R2, 0, - 0x7f, 0, lo_hp_tlv), + SOC_DAPM_SINGLE("MAL Switch", AIC3262_HP_AMP_CNTL_R1, 7, 1, + 0), + SOC_DAPM_SINGLE("LDAC Switch", AIC3262_HP_AMP_CNTL_R1, + 5, 1, 0), + SOC_DAPM_SINGLE_TLV("LOL-B1 Volume", + AIC3262_HP_AMP_CNTL_R2, 0, 0x7f, 1, lo_hp_tlv), }; /* Right HPR Mixer */ static const struct snd_kcontrol_new hpr_output_mixer_controls[] = { - SOC_DAPM_SINGLE_TLV("LOR-B1 Volume", HP_AMP_CNTL_R3, 0, - 0x7f, 0, lo_hp_tlv), - SOC_DAPM_SINGLE("LDAC Switch", HP_AMP_CNTL_R1, 2, 1, 0), - SOC_DAPM_SINGLE("RDAC Switch", HP_AMP_CNTL_R1, 4, 1, 0), - SOC_DAPM_SINGLE("MAR Switch", HP_AMP_CNTL_R1, 6, 1, 0), + SOC_DAPM_SINGLE_TLV("LOR-B1 Volume", + AIC3262_HP_AMP_CNTL_R3, 0, 0x7f, 1, lo_hp_tlv), + SOC_DAPM_SINGLE("LDAC Switch", AIC3262_HP_AMP_CNTL_R1, + 2, 1, 0), + SOC_DAPM_SINGLE("RDAC Switch", AIC3262_HP_AMP_CNTL_R1, + 4, 1, 0), + SOC_DAPM_SINGLE("MAR Switch", AIC3262_HP_AMP_CNTL_R1, + 6, 1, 0), }; /* Left LOL Mixer */ static const struct snd_kcontrol_new lol_output_mixer_controls[] = { - SOC_DAPM_SINGLE("MAL Switch", LINE_AMP_CNTL_R2, 7, 1, 0), - SOC_DAPM_SINGLE("IN1L-B Switch", LINE_AMP_CNTL_R2, 3, 1,0), - SOC_DAPM_SINGLE("LDAC Switch", LINE_AMP_CNTL_R1, 7, 1, 0), - SOC_DAPM_SINGLE("RDAC Switch", LINE_AMP_CNTL_R1, 5, 1, 0), + SOC_DAPM_SINGLE("MAL Switch", AIC3262_LINE_AMP_CNTL_R2, + 7, 1, 0), + SOC_DAPM_SINGLE("IN1L-B Switch", AIC3262_LINE_AMP_CNTL_R2, + 3, 1, 0), + SOC_DAPM_SINGLE("LDAC Switch", AIC3262_LINE_AMP_CNTL_R1, + 7, 1, 0), + SOC_DAPM_SINGLE("RDAC Switch", AIC3262_LINE_AMP_CNTL_R1, + 5, 1, 0), }; /* Right LOR Mixer */ static const struct snd_kcontrol_new lor_output_mixer_controls[] = { - SOC_DAPM_SINGLE("LOL Switch", LINE_AMP_CNTL_R1, 2, 1, 0), - SOC_DAPM_SINGLE("RDAC Switch", LINE_AMP_CNTL_R1, 6, 1, 0), - SOC_DAPM_SINGLE("MAR Switch", LINE_AMP_CNTL_R2, 6, 1, 0), - SOC_DAPM_SINGLE("IN1R-B Switch", LINE_AMP_CNTL_R2, 0, 1,0), + SOC_DAPM_SINGLE("LOL Switch", AIC3262_LINE_AMP_CNTL_R1, + 2, 1, 0), + SOC_DAPM_SINGLE("RDAC Switch", AIC3262_LINE_AMP_CNTL_R1, + 6, 1, 0), + SOC_DAPM_SINGLE("MAR Switch", AIC3262_LINE_AMP_CNTL_R2, + 6, 1, 0), + SOC_DAPM_SINGLE("IN1R-B Switch", AIC3262_LINE_AMP_CNTL_R2, + 0, 1, 0), }; /* Left SPKL Mixer */ static const struct snd_kcontrol_new spkl_output_mixer_controls[] = { - SOC_DAPM_SINGLE("MAL Switch", SPK_AMP_CNTL_R1, 7, 1, 0), - SOC_DAPM_SINGLE_TLV("LOL Volume", SPK_AMP_CNTL_R2, 0, 0x7f,0, - lo_hp_tlv), - SOC_DAPM_SINGLE("SPR_IN Switch", SPK_AMP_CNTL_R1, 2, 1, 0), + SOC_DAPM_SINGLE("MAL Switch", AIC3262_SPK_AMP_CNTL_R1, + 7, 1, 0), + SOC_DAPM_SINGLE_TLV("LOL Volume", + AIC3262_SPK_AMP_CNTL_R2, 0, 0x7f, 1, lo_hp_tlv), + SOC_DAPM_SINGLE("SPR_IN Switch", AIC3262_SPK_AMP_CNTL_R1, 2, 1, 0), }; /* Right SPKR Mixer */ static const struct snd_kcontrol_new spkr_output_mixer_controls[] = { - SOC_DAPM_SINGLE_TLV("LOR Volume", SPK_AMP_CNTL_R3, 0, 0x7f, 0, - lo_hp_tlv), - SOC_DAPM_SINGLE("MAR Switch", SPK_AMP_CNTL_R1, 6, 1, 0), + SOC_DAPM_SINGLE_TLV("LOR Volume", + AIC3262_SPK_AMP_CNTL_R3, 0, 0x7f, 1, lo_hp_tlv), + SOC_DAPM_SINGLE("MAR Switch", + AIC3262_SPK_AMP_CNTL_R1, 6, 1, 0), }; /* REC Mixer */ static const struct snd_kcontrol_new rec_output_mixer_controls[] = { - SOC_DAPM_SINGLE_TLV("LOL-B2 Volume", RAMP_CNTL_R1, 0, 0x7f,0, - lo_hp_tlv), - SOC_DAPM_SINGLE_TLV("IN1L Volume", IN1L_SEL_RM, 0, 0x7f, 1, lo_hp_tlv), - SOC_DAPM_SINGLE_TLV("IN1R Volume", IN1R_SEL_RM, 0, 0x7f, 1, lo_hp_tlv), - SOC_DAPM_SINGLE_TLV("LOR-B2 Volume", RAMP_CNTL_R2, 0,0x7f, 0,lo_hp_tlv), + SOC_DAPM_SINGLE_TLV("LOL-B2 Volume", + AIC3262_RAMP_CNTL_R1, 0, 0x7f, 1, lo_hp_tlv), + SOC_DAPM_SINGLE_TLV("IN1L Volume", + AIC3262_IN1L_SEL_RM, 0, 0x7f, 1, lo_hp_tlv), + SOC_DAPM_SINGLE_TLV("IN1R Volume", + AIC3262_IN1R_SEL_RM, 0, 0x7f, 1, lo_hp_tlv), + SOC_DAPM_SINGLE_TLV("LOR-B2 Volume", + AIC3262_RAMP_CNTL_R2, 0, 0x7f, 1, lo_hp_tlv), }; /* Left Input Mixer */ static const struct snd_kcontrol_new left_input_mixer_controls[] = { - SOC_DAPM_SINGLE("IN1L Switch", LMIC_PGA_PIN, 6, 1, 0), - SOC_DAPM_SINGLE("IN2L Switch", LMIC_PGA_PIN, 4, 1, 0), - SOC_DAPM_SINGLE("IN3L Switch", LMIC_PGA_PIN, 2, 1, 0), - SOC_DAPM_SINGLE("IN4L Switch", LMIC_PGA_PM_IN4, 5, 1, 0), - SOC_DAPM_SINGLE("IN1R Switch", LMIC_PGA_PIN, 0, 1, 0), - SOC_DAPM_SINGLE("IN2R Switch", LMIC_PGA_MIN, 4, 1, 0), - SOC_DAPM_SINGLE("IN3R Switch", LMIC_PGA_MIN, 2, 1, 0), - SOC_DAPM_SINGLE("IN4R Switch", LMIC_PGA_PM_IN4, 4, 1, 0), - SOC_DAPM_SINGLE("CM2L Switch", LMIC_PGA_MIN, 0, 1, 0), - SOC_DAPM_SINGLE("CM1L Switch", LMIC_PGA_MIN, 6, 1, 0), + SOC_DAPM_SINGLE("IN1L Switch", AIC3262_LMIC_PGA_PIN, + 6, 3, 0), + SOC_DAPM_SINGLE("IN2L Switch", AIC3262_LMIC_PGA_PIN, + 4, 3, 0), + SOC_DAPM_SINGLE("IN3L Switch", AIC3262_LMIC_PGA_PIN, + 2, 3, 0), + SOC_DAPM_SINGLE("IN4L Switch", AIC3262_LMIC_PGA_PM_IN4, + 5, 1, 0), + SOC_DAPM_SINGLE("IN1R Switch", AIC3262_LMIC_PGA_PIN, + 0, 3, 0), + SOC_DAPM_SINGLE("IN2R Switch", AIC3262_LMIC_PGA_MIN, + 4, 3, 0), + SOC_DAPM_SINGLE("IN3R Switch", AIC3262_LMIC_PGA_MIN, + 2, 3, 0), + SOC_DAPM_SINGLE("IN4R Switch", AIC3262_LMIC_PGA_PM_IN4, + 4, 1, 0), + SOC_DAPM_SINGLE("CM2L Switch", AIC3262_LMIC_PGA_MIN, + 0, 3, 0), + SOC_DAPM_SINGLE("CM1L Switch", AIC3262_LMIC_PGA_MIN, + 6, 3, 0), }; /* Right Input Mixer */ static const struct snd_kcontrol_new right_input_mixer_controls[] = { - SOC_DAPM_SINGLE("IN1R Switch", RMIC_PGA_PIN, 6, 1, 0), - SOC_DAPM_SINGLE("IN2R Switch", RMIC_PGA_PIN, 4, 1, 0), - SOC_DAPM_SINGLE("IN3R Switch", RMIC_PGA_PIN, 2, 1, 0), - SOC_DAPM_SINGLE("IN4R Switch", RMIC_PGA_PM_IN4, 5, 1, 0), - SOC_DAPM_SINGLE("IN2L Switch", RMIC_PGA_PIN, 0, 1, 0), - SOC_DAPM_SINGLE("IN1L Switch", RMIC_PGA_MIN, 4, 1, 0), - SOC_DAPM_SINGLE("IN3L Switch", RMIC_PGA_MIN, 2, 1, 0), - SOC_DAPM_SINGLE("IN4L Switch", RMIC_PGA_PM_IN4, 4, 1, 0), - SOC_DAPM_SINGLE("CM1R Switch", RMIC_PGA_MIN, 6, 1, 0), - SOC_DAPM_SINGLE("CM2R Switch", RMIC_PGA_MIN, 0, 1, 0), + SOC_DAPM_SINGLE("IN1R Switch", AIC3262_RMIC_PGA_PIN, + 6, 3, 0), + SOC_DAPM_SINGLE("IN2R Switch", AIC3262_RMIC_PGA_PIN, + 4, 3, 0), + SOC_DAPM_SINGLE("IN3R Switch", AIC3262_RMIC_PGA_PIN, + 2, 3, 0), + SOC_DAPM_SINGLE("IN4R Switch", AIC3262_RMIC_PGA_PM_IN4, + 5, 1, 0), + SOC_DAPM_SINGLE("IN2L Switch", AIC3262_RMIC_PGA_PIN, + 0, 3, 0), + SOC_DAPM_SINGLE("IN1L Switch", AIC3262_RMIC_PGA_MIN, + 4, 3, 0), + SOC_DAPM_SINGLE("IN3L Switch", AIC3262_RMIC_PGA_MIN, + 2, 3, 0), + SOC_DAPM_SINGLE("IN4L Switch", AIC3262_RMIC_PGA_PM_IN4, + 4, 1, 0), + SOC_DAPM_SINGLE("CM1R Switch", AIC3262_RMIC_PGA_MIN, + 6, 3, 0), + SOC_DAPM_SINGLE("CM2R Switch", AIC3262_RMIC_PGA_MIN, + 0, 3, 0), }; - -static const char *asi1lin_text[] = { - "Off", "ASI1 Left In","ASI1 Right In","ASI1 MonoMix In" +static const char * const asi1lin_text[] = { + "Off", "ASI1 Left In", "ASI1 Right In", "ASI1 MonoMix In" }; -SOC_ENUM_SINGLE_DECL(asi1lin_enum, ASI1_DAC_OUT_CNTL, 6, asi1lin_text); +SOC_ENUM_SINGLE_DECL(asi1lin_enum, AIC3262_ASI1_DAC_OUT_CNTL, 6, asi1lin_text); static const struct snd_kcontrol_new asi1lin_control = - SOC_DAPM_ENUM("ASI1LIN Route", asi1lin_enum); - +SOC_DAPM_ENUM("ASI1LIN Route", asi1lin_enum); -static const char *asi1rin_text[] = { - "Off", "ASI1 Right In","ASI1 Left In","ASI1 MonoMix In" +static const char * const asi1rin_text[] = { + "Off", "ASI1 Right In", "ASI1 Left In", "ASI1 MonoMix In" }; -SOC_ENUM_SINGLE_DECL(asi1rin_enum, ASI1_DAC_OUT_CNTL, 4, asi1rin_text); +SOC_ENUM_SINGLE_DECL(asi1rin_enum, AIC3262_ASI1_DAC_OUT_CNTL, 4, asi1rin_text); static const struct snd_kcontrol_new asi1rin_control = - SOC_DAPM_ENUM("ASI1RIN Route", asi1rin_enum); +SOC_DAPM_ENUM("ASI1RIN Route", asi1rin_enum); -static const char *asi2lin_text[] = { - "Off", "ASI2 Left In","ASI2 Right In","ASI2 MonoMix In" +static const char * const asi2lin_text[] = { + "Off", "ASI2 Left In", "ASI2 Right In", "ASI2 MonoMix In" }; -SOC_ENUM_SINGLE_DECL(asi2lin_enum, ASI2_DAC_OUT_CNTL, 6, asi2lin_text); +SOC_ENUM_SINGLE_DECL(asi2lin_enum, AIC3262_ASI2_DAC_OUT_CNTL, 6, asi2lin_text); + static const struct snd_kcontrol_new asi2lin_control = - SOC_DAPM_ENUM("ASI2LIN Route", asi2lin_enum); +SOC_DAPM_ENUM("ASI2LIN Route", asi2lin_enum); -static const char *asi2rin_text[] = { - "Off", "ASI2 Right In","ASI2 Left In","ASI2 MonoMix In" +static const char * const asi2rin_text[] = { + "Off", "ASI2 Right In", "ASI2 Left In", "ASI2 MonoMix In" }; - -SOC_ENUM_SINGLE_DECL(asi2rin_enum, ASI2_DAC_OUT_CNTL, 4, asi2rin_text); +SOC_ENUM_SINGLE_DECL(asi2rin_enum, AIC3262_ASI2_DAC_OUT_CNTL, 4, asi2rin_text); static const struct snd_kcontrol_new asi2rin_control = - SOC_DAPM_ENUM("ASI2RIN Route", asi2rin_enum); +SOC_DAPM_ENUM("ASI2RIN Route", asi2rin_enum); -static const char *asi3lin_text[] = { - "Off", "ASI3 Left In","ASI3 Right In","ASI3 MonoMix In" +static const char * const asi3lin_text[] = { + "Off", "ASI3 Left In", "ASI3 Right In", "ASI3 MonoMix In" }; +SOC_ENUM_SINGLE_DECL(asi3lin_enum, AIC3262_ASI3_DAC_OUT_CNTL, 6, asi3lin_text); -SOC_ENUM_SINGLE_DECL(asi3lin_enum, ASI3_DAC_OUT_CNTL, 6, asi3lin_text); static const struct snd_kcontrol_new asi3lin_control = - SOC_DAPM_ENUM("ASI3LIN Route", asi3lin_enum); - +SOC_DAPM_ENUM("ASI3LIN Route", asi3lin_enum); -static const char *asi3rin_text[] = { - "Off", "ASI3 Right In","ASI3 Left In","ASI3 MonoMix In" +static const char * const asi3rin_text[] = { + "Off", "ASI3 Right In", "ASI3 Left In", "ASI3 MonoMix In" }; +SOC_ENUM_SINGLE_DECL(asi3rin_enum, AIC3262_ASI3_DAC_OUT_CNTL, 4, asi3rin_text); -SOC_ENUM_SINGLE_DECL(asi3rin_enum, ASI3_DAC_OUT_CNTL, 4, asi3rin_text); static const struct snd_kcontrol_new asi3rin_control = - SOC_DAPM_ENUM("ASI3RIN Route", asi3rin_enum); +SOC_DAPM_ENUM("ASI3RIN Route", asi3rin_enum); - -static const char *dacminidspin1_text[] = { - "ASI1 In", "ASI2 In","ASI3 In","ADC MiniDSP Out" +static const char * const dacminidspin1_text[] = { + "ASI1 In", "ASI2 In", "ASI3 In", "ADC MiniDSP Out" }; -SOC_ENUM_SINGLE_DECL(dacminidspin1_enum, MINIDSP_PORT_CNTL_REG, 4, dacminidspin1_text); +SOC_ENUM_SINGLE_DECL(dacminidspin1_enum, AIC3262_MINIDSP_DATA_PORT_CNTL, 4, + dacminidspin1_text); + static const struct snd_kcontrol_new dacminidspin1_control = - SOC_DAPM_ENUM("DAC MiniDSP IN1 Route", dacminidspin1_enum); +SOC_DAPM_ENUM("DAC MiniDSP IN1 Route", dacminidspin1_enum); -static const char *dacminidspin2_text[] = { - "ASI1 In", "ASI2 In","ASI3 In" +static const char * const dacminidspin2_text[] = { + "ASI1 In", "ASI2 In", "ASI3 In" }; -//static const struct soc_enum dacminidspin1_enum = -// SOC_ENUM_SINGLE(MINIDSP_DATA_PORT_CNTL, 5, 2, dacminidspin1_text); -SOC_ENUM_SINGLE_DECL(dacminidspin2_enum, MINIDSP_PORT_CNTL_REG, 2, dacminidspin2_text); +SOC_ENUM_SINGLE_DECL(dacminidspin2_enum, AIC3262_MINIDSP_DATA_PORT_CNTL, 2, + dacminidspin2_text); static const struct snd_kcontrol_new dacminidspin2_control = - SOC_DAPM_ENUM("DAC MiniDSP IN2 Route", dacminidspin2_enum); +SOC_DAPM_ENUM("DAC MiniDSP IN2 Route", dacminidspin2_enum); -static const char *dacminidspin3_text[] = { - "ASI1 In", "ASI2 In","ASI3 In" +static const char * const dacminidspin3_text[] = { + "ASI1 In", "ASI2 In", "ASI3 In" }; -//static const struct soc_enum dacminidspin1_enum = -// SOC_ENUM_SINGLE(MINIDSP_DATA_PORT_CNTL, 5, 2, dacminidspin1_text); -SOC_ENUM_SINGLE_DECL(dacminidspin3_enum, MINIDSP_PORT_CNTL_REG, 0, dacminidspin3_text); +SOC_ENUM_SINGLE_DECL(dacminidspin3_enum, AIC3262_MINIDSP_DATA_PORT_CNTL, 0, + dacminidspin3_text); static const struct snd_kcontrol_new dacminidspin3_control = SOC_DAPM_ENUM("DAC MiniDSP IN3 Route", dacminidspin3_enum); -static const char *asi1out_text[] = { +static const char * const adcdac_route_text[] = { "Off", + "On", +}; + +SOC_ENUM_SINGLE_DECL(adcdac_enum, 0, 2, adcdac_route_text); + +static const struct snd_kcontrol_new adcdacroute_control = +SOC_DAPM_ENUM_VIRT("ADC DAC Route", adcdac_enum); + +static const char * const dout1_text[] = { "ASI1 Out", + "DIN1 Bypass", + "DIN2 Bypass", + "DIN3 Bypass", +}; + +SOC_ENUM_SINGLE_DECL(dout1_enum, AIC3262_ASI1_DOUT_CNTL, 0, dout1_text); +static const struct snd_kcontrol_new dout1_control = +SOC_DAPM_ENUM("DOUT1 Route", dout1_enum); + +static const char * const dout2_text[] = { + "ASI2 Out", + "DIN1 Bypass", + "DIN2 Bypass", + "DIN3 Bypass", +}; + +SOC_ENUM_SINGLE_DECL(dout2_enum, AIC3262_ASI2_DOUT_CNTL, 0, dout2_text); +static const struct snd_kcontrol_new dout2_control = +SOC_DAPM_ENUM("DOUT2 Route", dout2_enum); + +static const char * const dout3_text[] = { + "ASI3 Out", + "DIN1 Bypass", + "DIN2 Bypass", + "DIN3 Bypass", +}; + +SOC_ENUM_SINGLE_DECL(dout3_enum, AIC3262_ASI3_DOUT_CNTL, 0, dout3_text); +static const struct snd_kcontrol_new dout3_control = +SOC_DAPM_ENUM("DOUT3 Route", dout3_enum); + +static const char * const asi1out_text[] = { + "Off", + "ADC MiniDSP Out1", "ASI1In Bypass", "ASI2In Bypass", "ASI3In Bypass", }; -SOC_ENUM_SINGLE_DECL(asi1out_enum, ASI1_ADC_INPUT_CNTL, 0, asi1out_text); + +SOC_ENUM_SINGLE_DECL(asi1out_enum, AIC3262_ASI1_ADC_INPUT_CNTL, + 0, asi1out_text); static const struct snd_kcontrol_new asi1out_control = - SOC_DAPM_ENUM("ASI1OUT Route", asi1out_enum); +SOC_DAPM_ENUM("ASI1OUT Route", asi1out_enum); -static const char *asi2out_text[] = { +static const char * const asi2out_text[] = { "Off", - "ASI1 Out", + "ADC MiniDSP Out1", "ASI1In Bypass", "ASI2In Bypass", "ASI3In Bypass", - "ASI2 Out", + "ADC MiniDSP Out2", }; -SOC_ENUM_SINGLE_DECL(asi2out_enum, ASI2_ADC_INPUT_CNTL, 0, asi2out_text); + +SOC_ENUM_SINGLE_DECL(asi2out_enum, AIC3262_ASI2_ADC_INPUT_CNTL, + 0, asi2out_text); static const struct snd_kcontrol_new asi2out_control = - SOC_DAPM_ENUM("ASI2OUT Route", asi2out_enum); -static const char *asi3out_text[] = { +SOC_DAPM_ENUM("ASI2OUT Route", asi2out_enum); +static const char * const asi3out_text[] = { "Off", - "ASI1 Out", + "ADC MiniDSP Out1", "ASI1In Bypass", "ASI2In Bypass", "ASI3In Bypass", - "ASI3 Out", + "Reserved", + "ADC MiniDSP Out3", }; -SOC_ENUM_SINGLE_DECL(asi3out_enum, ASI3_ADC_INPUT_CNTL, 0, asi3out_text); -static const struct snd_kcontrol_new asi3out_control = - SOC_DAPM_ENUM("ASI3OUT Route", asi3out_enum); -static const char *asi1bclk_text[] = { +SOC_ENUM_SINGLE_DECL(asi3out_enum, AIC3262_ASI3_ADC_INPUT_CNTL, + 0, asi3out_text); +static const struct snd_kcontrol_new asi3out_control = +SOC_DAPM_ENUM("ASI3OUT Route", asi3out_enum); +static const char * const asibclk_text[] = { "DAC_CLK", "DAC_MOD_CLK", "ADC_CLK", "ADC_MOD_CLK", }; -SOC_ENUM_SINGLE_DECL(asi1bclk_enum, ASI1_BCLK_N_CNTL, 0, asi1bclk_text); +SOC_ENUM_SINGLE_DECL(asi1bclk_enum, AIC3262_ASI1_BCLK_N_CNTL, 0, asibclk_text); static const struct snd_kcontrol_new asi1bclk_control = - SOC_DAPM_ENUM("ASI1_BCLK Route", asi1bclk_enum); +SOC_DAPM_ENUM("ASI1_BCLK Route", asi1bclk_enum); -static const char *asi2bclk_text[] = { - "DAC_CLK", - "DAC_MOD_CLK", - "ADC_CLK", - "ADC_MOD_CLK", -}; -SOC_ENUM_SINGLE_DECL(asi2bclk_enum, ASI2_BCLK_N_CNTL, 0, asi2bclk_text); +SOC_ENUM_SINGLE_DECL(asi2bclk_enum, AIC3262_ASI2_BCLK_N_CNTL, 0, asibclk_text); static const struct snd_kcontrol_new asi2bclk_control = - SOC_DAPM_ENUM("ASI2_BCLK Route", asi2bclk_enum); -static const char *asi3bclk_text[] = { - "DAC_CLK", - "DAC_MOD_CLK", - "ADC_CLK", - "ADC_MOD_CLK", -}; -SOC_ENUM_SINGLE_DECL(asi3bclk_enum, ASI3_BCLK_N_CNTL, 0, asi3bclk_text); +SOC_DAPM_ENUM("ASI2_BCLK Route", asi2bclk_enum); +SOC_ENUM_SINGLE_DECL(asi3bclk_enum, AIC3262_ASI3_BCLK_N_CNTL, 0, asibclk_text); static const struct snd_kcontrol_new asi3bclk_control = - SOC_DAPM_ENUM("ASI3_BCLK Route", asi3bclk_enum); +SOC_DAPM_ENUM("ASI3_BCLK Route", asi3bclk_enum); -static int aic326x_hp_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - return 0; -} -static int pll_power_on_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - if (event == SND_SOC_DAPM_POST_PMU) - { - mdelay(10); - } - return 0; -} +static const char * const adc_mux_text[] = { + "Analog", + "Digital", +}; -static int polling_loop(struct snd_soc_codec *codec, unsigned int reg, - int mask, int on_off) -{ - unsigned int counter, status; - - counter = 0; - switch(on_off) { - case 0: /*off*/ - do { - status = snd_soc_read(codec, reg); - counter++; - } while ((counter < 500) && ((status & mask) == mask)); - break; - case 1: /*on*/ - do { - status = snd_soc_read(codec, reg); - counter++; - } while ((counter < 500) && ((status & mask) != mask)); - break; - default: - printk("%s: unknown arguement\n", __func__); - break; - } +SOC_ENUM_SINGLE_DECL(adcl_enum, AIC3262_ADC_CHANNEL_POW, 4, adc_mux_text); +SOC_ENUM_SINGLE_DECL(adcr_enum, AIC3262_ADC_CHANNEL_POW, 2, adc_mux_text); - printk("%s: exiting with count value %d \n", __func__, counter); - if(counter >= 500) - return -1; - return 0; -} +static const struct snd_kcontrol_new adcl_mux = +SOC_DAPM_ENUM("Left ADC Route", adcl_enum); -int poll_dac(struct snd_soc_codec *codec, int left_right, int on_off) -{ - int ret = 0; +static const struct snd_kcontrol_new adcr_mux = +SOC_DAPM_ENUM("Right ADC Route", adcr_enum); - aic3262_change_page(codec, 0); - aic3262_change_book(codec, 0); - - switch(on_off) { - - case 0:/*power off polling*/ - /*DAC power polling logic*/ - switch(left_right) { - case 0: /*left dac polling*/ - ret = polling_loop(codec, DAC_FLAG_R1, LDAC_POW_FLAG_MASK, 0); - break; - case 1:/*right dac polling*/ - ret = polling_loop(codec, DAC_FLAG_R1, RDAC_POW_FLAG_MASK, 0); - break; - } - break; - case 1:/*power on polling*/ - /*DAC power polling logic*/ - switch(left_right) { - case 0: /*left dac polling*/ - ret = polling_loop(codec, DAC_FLAG_R1, LDAC_POW_FLAG_MASK, 1); - break; - case 1:/*right dac polling*/ - ret = polling_loop(codec, DAC_FLAG_R1, RDAC_POW_FLAG_MASK, 1); - break; - } +/** + * aic326x_hp_event: - To handle headphone related task before and after + * headphone powrup and power down + * @w: pointer variable to dapm_widget + * @kcontrol: mixer control + * @event: event element information + * + * Returns 0 for success. + */ +static int aic326x_hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + int reg_mask = 0; + int ret_wbits = 0; + + if (w->shift == 1) + reg_mask = AIC3262_HPL_POWER_MASK; + if (w->shift == 0) + reg_mask = AIC3262_HPR_POWER_MASK; + switch (event) { + case SND_SOC_DAPM_POST_PMU: + ret_wbits = aic3262_wait_bits(w->codec->control_data, + AIC3262_HP_FLAG, reg_mask, + reg_mask, TIME_DELAY, + DELAY_COUNTER); + if (!ret_wbits) { + dev_err(w->codec->dev, "HP POST_PMU timedout\n"); + return -1; + } break; - default: - printk("%s:unknown arguement\n", __func__); - break; + case SND_SOC_DAPM_POST_PMD: + ret_wbits = aic3262_wait_bits(w->codec->control_data, + AIC3262_HP_FLAG, reg_mask, 0, + TIME_DELAY, DELAY_COUNTER); + if (!ret_wbits) { + dev_err(w->codec->dev, "HP POST_PMD timedout\n"); + return -1; } - if(ret) - printk("%s: power %s %s failure", __func__, left_right?"right":"left", on_off?"on":"off"); - return ret; + break; + default: + BUG(); + return -EINVAL; + } + return 0; } -int poll_adc(struct snd_soc_codec *codec, int left_right, int on_off) -{ - int ret = 0; +/** + *aic326x_dac_event: Headset popup reduction and powering up dsps together + * when they are in sync mode + * @w: pointer variable to dapm_widget + * @kcontrol: pointer to sound control + * @event: event element information + * + * Returns 0 for success. + */ +static int aic326x_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + int reg_mask = 0; + int ret_wbits = 0; + int run_state_mask; + struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(w->codec); + int sync_needed = 0, non_sync_state = 0; + int other_dsp = 0, run_state = 0; + + if (w->shift == 7) { + reg_mask = AIC3262_LDAC_POWER_MASK; + run_state_mask = AIC3262_COPS_MDSP_D_L; + } + if (w->shift == 6) { + reg_mask = AIC3262_RDAC_POWER_MASK; + run_state_mask = AIC3262_COPS_MDSP_D_R; + } + switch (event) { + case SND_SOC_DAPM_POST_PMU: + + ret_wbits = aic3262_wait_bits(w->codec->control_data, + AIC3262_DAC_FLAG, reg_mask, + reg_mask, TIME_DELAY, + DELAY_COUNTER); + + sync_needed = SYNC_STATE(aic3262); + non_sync_state = DSP_NON_SYNC_MODE(aic3262->dsp_runstate); + other_dsp = aic3262->dsp_runstate & AIC3262_COPS_MDSP_A; + + if (sync_needed && non_sync_state && other_dsp) { + run_state = get_runstate(aic3262->codec->control_data); + aic3262_dsp_pwrdwn_status(aic3262); + aic3262_dsp_pwrup(aic3262, run_state); + } + aic3262->dsp_runstate |= run_state_mask; - aic3262_change_page(codec, 0); - aic3262_change_book(codec, 0); + if (!ret_wbits) { + dev_err(w->codec->dev, "DAC POST_PMU timedout\n"); + return -1; + } + break; + case SND_SOC_DAPM_POST_PMD: - switch(on_off) { + ret_wbits = aic3262_wait_bits(w->codec->control_data, + AIC3262_DAC_FLAG, reg_mask, 0, + TIME_DELAY, DELAY_COUNTER); - case 0:/*power off polling*/ - /*DAC power polling logic*/ - switch(left_right) { - case 0: /*left dac polling*/ - ret = polling_loop(codec, ADC_FLAG_R1, LADC_POW_FLAG_MASK, 0); - break; - case 1:/*right dac polling*/ - ret = polling_loop(codec, ADC_FLAG_R1, RADC_POW_FLAG_MASK, 0); - break; - } - break; - case 1:/*power on polling*/ - /*DAC power polling logic*/ - switch(left_right) { - case 0: /*left dac polling*/ - ret = polling_loop(codec, ADC_FLAG_R1, LADC_POW_FLAG_MASK, 1); - break; - case 1:/*right dac polling*/ - ret = polling_loop(codec, ADC_FLAG_R1, RADC_POW_FLAG_MASK, 1); - break; + aic3262->dsp_runstate = (aic3262->dsp_runstate & + ~run_state_mask); + if (!ret_wbits) { + dev_err(w->codec->dev, "DAC POST_PMD timedout\n"); + return -1; } - break; - default: - printk("%s:unknown arguement\n", __func__); - break; + break; + default: + BUG(); + return -EINVAL; } + return 0; +} - if(ret) - printk("%s: power %s %s failure", __func__, left_right?"right":"left", on_off?"on":"off"); - return ret; +/** + * aic326x_spk_event: Speaker related task before and after + * headphone powrup and power down$ + * @w: pointer variable to dapm_widget, + * @kcontrolr: pointer variable to sound control, + * @event: integer to event, + * + * Return value: 0 for success + */ +static int aic326x_spk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + int reg_mask; + + if (w->shift == 1) + reg_mask = AIC3262_SPKL_POWER_MASK; + if (w->shift == 0) + reg_mask = AIC3262_SPKR_POWER_MASK; + switch (event) { + case SND_SOC_DAPM_POST_PMU: + mdelay(1); + break; + case SND_SOC_DAPM_POST_PMD: + mdelay(1); + break; + default: + BUG(); + return -EINVAL; + } + return 0; } -static int slave_dac_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) +/**$ + * pll_power_on_event: provide delay after widget power up + * @w: pointer variable to dapm_widget, + * @kcontrolr: pointer variable to sound control, + * @event: integer to event, + * + * Return value: 0 for success + */ +static int pll_power_on_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + if (event == SND_SOC_DAPM_POST_PMU) + mdelay(10); + return 0; +} +/** + * aic3262_set_mode_get: To get different mode of Firmware through tinymix + * @kcontrolr: pointer to sound control, + * ucontrol: pointer to control element value, + * + * Return value: 0 for success + */ +static int aic3262_set_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct aic3262_priv *priv_ds = snd_soc_codec_get_drvdata(codec); - if (event & SND_SOC_DAPM_POST_PMU) { - /* Poll for DAC Power-up first */ - poll_dac(codec, 0, 1); - poll_dac(codec, 1, 1); - } + ucontrol->value.integer.value[0] = ((priv_ds->cfw_p->cur_mode << 8) + | priv_ds->cfw_p->cur_cfg); - if (event & SND_SOC_DAPM_POST_PMD) { - poll_dac(codec, 0, 0); - poll_dac(codec, 1, 0); - } return 0; } - -static int slave_adc_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) - +/** + * aic3262_set_mode_put: To set different mode of Firmware through tinymix + * @kcontrolr: pointer to sound control, + * ucontrol: pointer to control element value, + * + * Return value: 0 for success + */ +static int aic3262_set_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct aic3262_priv *priv_ds = snd_soc_codec_get_drvdata(codec); - if (event & SND_SOC_DAPM_POST_PMU) { + int next_mode = 0, next_cfg = 0; + int ret = 0; - /* Poll for ADC Power-up first */ - poll_adc(codec, 0, 1); - poll_adc(codec, 1, 1); - } + next_mode = (ucontrol->value.integer.value[0] >> 8); + next_cfg = (ucontrol->value.integer.value[0]) & 0xFF; + if (priv_ds == NULL) + dev_err(codec->dev, "failed to load firmware\n"); + else + ret = aic3xxx_cfw_setmode_cfg(priv_ds->cfw_p, + next_mode, next_cfg); + return ret; +} - if (event & SND_SOC_DAPM_POST_PMD) { - poll_adc(codec, 0, 0); - poll_adc(codec, 1, 0); +/** + * aic326x_adc_dsp_event: To get DSP run state to perform synchronization + * @w: pointer variable to dapm_widget + * @kcontrol: pointer to sound control + * @event: event element information + * + * Returns 0 for success. + */ +static int aic326x_adc_dsp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + int run_state = 0; + int non_sync_state = 0, sync_needed = 0; + int other_dsp = 0; + int run_state_mask = 0; + struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(w->codec); + int reg_mask = 0; + int ret_wbits = 0; + + if (w->shift == 7) { + reg_mask = AIC3262_LADC_POWER_MASK; + run_state_mask = AIC3262_COPS_MDSP_A_L; + } + if (w->shift == 6) { + reg_mask = AIC3262_RADC_POWER_MASK; + run_state_mask = AIC3262_COPS_MDSP_A_R; + } + switch (event) { + case SND_SOC_DAPM_POST_PMU: + ret_wbits = aic3262_wait_bits(w->codec->control_data, + AIC3262_ADC_FLAG, reg_mask, + reg_mask, TIME_DELAY, + DELAY_COUNTER); + sync_needed = SYNC_STATE(aic3262); + non_sync_state = DSP_NON_SYNC_MODE(aic3262->dsp_runstate); + other_dsp = aic3262->dsp_runstate & AIC3262_COPS_MDSP_D; + if (sync_needed && non_sync_state && other_dsp) { + run_state = get_runstate(aic3262->codec->control_data); + aic3262_dsp_pwrdwn_status(aic3262); + aic3262_dsp_pwrup(aic3262, run_state); + } + aic3262->dsp_runstate |= run_state_mask; + if (!ret_wbits) { + dev_err(w->codec->dev, "ADC POST_PMU timedout\n"); + return -1; + } + break; + case SND_SOC_DAPM_POST_PMD: + ret_wbits = aic3262_wait_bits(w->codec->control_data, + AIC3262_ADC_FLAG, reg_mask, 0, + TIME_DELAY, DELAY_COUNTER); + aic3262->dsp_runstate = (aic3262->dsp_runstate & + ~run_state_mask); + if (!ret_wbits) { + dev_err(w->codec->dev, "ADC POST_PMD timedout\n"); + return -1; + } + break; + default: + BUG(); + return -EINVAL; } - return 0; } static const struct snd_soc_dapm_widget aic3262_dapm_widgets[] = { - /* TODO: Can we switch these off ? */ - SND_SOC_DAPM_AIF_IN("ASI1IN", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("ASI2IN", "ASI2 Playback", 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("ASI3IN", "ASI3 Playback", 0, SND_SOC_NOPM, 0, 0), - + SND_SOC_DAPM_AIF_IN("DIN1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DIN2", "ASI2 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DIN3", "ASI3 Playback", 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_DAC_E("Left DAC", NULL, PASI_DAC_DP_SETUP, 7, 0, - slave_dac_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD | - SND_SOC_DAPM_PRE_PMD), - SND_SOC_DAPM_DAC_E("Right DAC", NULL, PASI_DAC_DP_SETUP, 6, 0, - slave_dac_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD | - SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_DAC_E("Left DAC", NULL, AIC3262_PASI_DAC_DP_SETUP, 7, 0, + aic326x_dac_event, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("Right DAC", NULL, AIC3262_PASI_DAC_DP_SETUP, 6, 0, + aic326x_dac_event, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), /* dapm widget (path domain) for HPL Output Mixer */ SND_SOC_DAPM_MIXER("HPL Output Mixer", SND_SOC_NOPM, 0, 0, - &hpl_output_mixer_controls[0], - ARRAY_SIZE(hpl_output_mixer_controls)), + &hpl_output_mixer_controls[0], + ARRAY_SIZE(hpl_output_mixer_controls)), /* dapm widget (path domain) for HPR Output Mixer */ SND_SOC_DAPM_MIXER("HPR Output Mixer", SND_SOC_NOPM, 0, 0, - &hpr_output_mixer_controls[0], - ARRAY_SIZE(hpr_output_mixer_controls)), + &hpr_output_mixer_controls[0], + ARRAY_SIZE(hpr_output_mixer_controls)), - SND_SOC_DAPM_PGA_E("HPL Driver", HP_AMP_CNTL_R1, 1, 0, NULL, 0, - aic326x_hp_event, SND_SOC_DAPM_POST_PMU), - SND_SOC_DAPM_PGA_E("HPR Driver", HP_AMP_CNTL_R1, 0, 0, NULL, 0, - aic326x_hp_event, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_E("HPL Driver", AIC3262_HP_AMP_CNTL_R1, + 1, 0, NULL, 0, aic326x_hp_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPR Driver", AIC3262_HP_AMP_CNTL_R1, + 0, 0, NULL, 0, aic326x_hp_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), /* dapm widget (path domain) for LOL Output Mixer */ SND_SOC_DAPM_MIXER("LOL Output Mixer", SND_SOC_NOPM, 0, 0, - &lol_output_mixer_controls[0], - ARRAY_SIZE(lol_output_mixer_controls)), + &lol_output_mixer_controls[0], + ARRAY_SIZE(lol_output_mixer_controls)), /* dapm widget (path domain) for LOR Output Mixer mixer */ SND_SOC_DAPM_MIXER("LOR Output Mixer", SND_SOC_NOPM, 0, 0, - &lor_output_mixer_controls[0], - ARRAY_SIZE(lor_output_mixer_controls)), + &lor_output_mixer_controls[0], + ARRAY_SIZE(lor_output_mixer_controls)), - SND_SOC_DAPM_PGA("LOL Driver", LINE_AMP_CNTL_R1, 1, 0, NULL, 0), - SND_SOC_DAPM_PGA("LOR Driver", LINE_AMP_CNTL_R1, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("LOL Driver", AIC3262_LINE_AMP_CNTL_R1, + 1, 0, NULL, 0), + SND_SOC_DAPM_PGA("LOR Driver", AIC3262_LINE_AMP_CNTL_R1, + 0, 0, NULL, 0), /* dapm widget (path domain) for SPKL Output Mixer */ SND_SOC_DAPM_MIXER("SPKL Output Mixer", SND_SOC_NOPM, 0, 0, - &spkl_output_mixer_controls[0], - ARRAY_SIZE(spkl_output_mixer_controls)), + &spkl_output_mixer_controls[0], + ARRAY_SIZE(spkl_output_mixer_controls)), /* dapm widget (path domain) for SPKR Output Mixer */ SND_SOC_DAPM_MIXER("SPKR Output Mixer", SND_SOC_NOPM, 0, 0, - &spkr_output_mixer_controls[0], - ARRAY_SIZE(spkr_output_mixer_controls)), + &spkr_output_mixer_controls[0], + ARRAY_SIZE(spkr_output_mixer_controls)), - SND_SOC_DAPM_PGA("SPKL Driver", SPK_AMP_CNTL_R1, 1, 0, NULL, 0), - SND_SOC_DAPM_PGA("SPKR Driver", SPK_AMP_CNTL_R1, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA_E("SPKL Driver", AIC3262_SPK_AMP_CNTL_R1, + 1, 0, NULL, 0, aic326x_spk_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_E("SPKR Driver", AIC3262_SPK_AMP_CNTL_R1, + 0, 0, NULL, 0, aic326x_spk_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), /* dapm widget (path domain) for SPKR Output Mixer */ SND_SOC_DAPM_MIXER("REC Output Mixer", SND_SOC_NOPM, 0, 0, - &rec_output_mixer_controls[0], - ARRAY_SIZE(rec_output_mixer_controls)), + &rec_output_mixer_controls[0], + ARRAY_SIZE(rec_output_mixer_controls)), - SND_SOC_DAPM_PGA("RECP Driver", REC_AMP_CNTL_R5, 7, 0, NULL, 0), - SND_SOC_DAPM_PGA("RECM Driver", REC_AMP_CNTL_R5, 6, 0, NULL, 0), + SND_SOC_DAPM_PGA("RECP Driver", AIC3262_REC_AMP_CNTL_R5, + 7, 0, NULL, 0), + SND_SOC_DAPM_PGA("RECM Driver", AIC3262_REC_AMP_CNTL_R5, + 6, 0, NULL, 0), SND_SOC_DAPM_MUX("ASI1LIN Route", - SND_SOC_NOPM, 0, 0, &asi1lin_control), + SND_SOC_NOPM, 0, 0, &asi1lin_control), SND_SOC_DAPM_MUX("ASI1RIN Route", - SND_SOC_NOPM, 0, 0, &asi1rin_control), + SND_SOC_NOPM, 0, 0, &asi1rin_control), SND_SOC_DAPM_MUX("ASI2LIN Route", - SND_SOC_NOPM, 0, 0, &asi2lin_control), + SND_SOC_NOPM, 0, 0, &asi2lin_control), SND_SOC_DAPM_MUX("ASI2RIN Route", - SND_SOC_NOPM, 0, 0, &asi2rin_control), + SND_SOC_NOPM, 0, 0, &asi2rin_control), SND_SOC_DAPM_MUX("ASI3LIN Route", - SND_SOC_NOPM, 0, 0, &asi3lin_control), + SND_SOC_NOPM, 0, 0, &asi3lin_control), SND_SOC_DAPM_MUX("ASI3RIN Route", - SND_SOC_NOPM, 0, 0, &asi3rin_control), + SND_SOC_NOPM, 0, 0, &asi3rin_control), SND_SOC_DAPM_PGA("ASI1LIN", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("ASI1RIN", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -3030,14 +1078,6 @@ static const struct snd_soc_dapm_widget aic3262_dapm_widgets[] = { SND_SOC_DAPM_PGA("ASI2RIN", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("ASI3LIN", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("ASI3RIN", SND_SOC_NOPM, 0, 0, NULL, 0), - - SND_SOC_DAPM_PGA("ASI1LOUT", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("ASI1ROUT", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("ASI2LOUT", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("ASI2ROUT", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("ASI3LOUT", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("ASI3ROUT", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("ASI1MonoMixIN", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("ASI2MonoMixIN", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("ASI3MonoMixIN", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -3046,13 +1086,15 @@ static const struct snd_soc_dapm_widget aic3262_dapm_widgets[] = { SND_SOC_DAPM_PGA("ASI2IN Port", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("ASI3IN Port", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_MUX("DAC MiniDSP IN1 Route", - SND_SOC_NOPM, 0, 0, &dacminidspin1_control), -SND_SOC_DAPM_MUX("DAC MiniDSP IN2 Route", - SND_SOC_NOPM, 0, 0, &dacminidspin2_control), + SND_SOC_NOPM, 0, 0, &dacminidspin1_control), + SND_SOC_DAPM_MUX("DAC MiniDSP IN2 Route", + SND_SOC_NOPM, 0, 0, &dacminidspin2_control), SND_SOC_DAPM_MUX("DAC MiniDSP IN3 Route", - SND_SOC_NOPM, 0, 0, &dacminidspin3_control), + SND_SOC_NOPM, 0, 0, &dacminidspin3_control), + + SND_SOC_DAPM_VIRT_MUX("ADC DAC Route", + SND_SOC_NOPM, 0, 0, &adcdacroute_control), SND_SOC_DAPM_PGA("CM", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("CM1L", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -3061,59 +1103,74 @@ SND_SOC_DAPM_MUX("DAC MiniDSP IN2 Route", SND_SOC_DAPM_PGA("CM2R", SND_SOC_NOPM, 0, 0, NULL, 0), /* TODO: Can we switch these off ? */ - SND_SOC_DAPM_AIF_OUT("ASI1OUT","ASI1 Capture", 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_OUT("ASI2OUT", "ASI2 Capture",0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_OUT("ASI3OUT", "ASI3 Capture",0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DOUT1", "ASI1 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DOUT2", "ASI2 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DOUT3", "ASI3 Capture", 0, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_MUX("DOUT1 Route", + SND_SOC_NOPM, 0, 0, &dout1_control), + SND_SOC_DAPM_MUX("DOUT2 Route", + SND_SOC_NOPM, 0, 0, &dout2_control), + SND_SOC_DAPM_MUX("DOUT3 Route", + SND_SOC_NOPM, 0, 0, &dout3_control), + + SND_SOC_DAPM_PGA("ASI1OUT", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("ASI2OUT", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("ASI3OUT", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MUX("ASI1OUT Route", - SND_SOC_NOPM, 0, 0, &asi1out_control), + SND_SOC_NOPM, 0, 0, &asi1out_control), SND_SOC_DAPM_MUX("ASI2OUT Route", - SND_SOC_NOPM, 0, 0, &asi2out_control), + SND_SOC_NOPM, 0, 0, &asi2out_control), SND_SOC_DAPM_MUX("ASI3OUT Route", - SND_SOC_NOPM, 0, 0, &asi3out_control), + SND_SOC_NOPM, 0, 0, &asi3out_control), - /* TODO: Will be used during MINIDSP programming */ + /* TODO: Can we switch the ASI1 OUT1 off? */ /* TODO: Can we switch them off? */ SND_SOC_DAPM_PGA("ADC MiniDSP OUT1", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("ADC MiniDSP OUT2", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("ADC MiniDSP OUT3", SND_SOC_NOPM, 0, 0, NULL, 0), +/* SND_SOC_DAPM_MUX("DMICDAT Input Route", + SND_SOC_NOPM, 0, 0, &dmicinput_control),*/ + SND_SOC_DAPM_MUX("Left ADC Route", SND_SOC_NOPM, 0, 0, &adcl_mux), + SND_SOC_DAPM_MUX("Right ADC Route", SND_SOC_NOPM, 0, 0, &adcr_mux), - SND_SOC_DAPM_ADC_E("Left ADC", NULL, ADC_CHANNEL_POW, 7, 0, - slave_adc_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD | - SND_SOC_DAPM_PRE_PMD), - SND_SOC_DAPM_ADC_E("Right ADC", NULL, ADC_CHANNEL_POW, 6, 0, - slave_adc_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD | - SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("Left ADC", NULL, AIC3262_ADC_CHANNEL_POW, 7, 0, + aic326x_adc_dsp_event, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("Right ADC", NULL, AIC3262_ADC_CHANNEL_POW, 6, 0, + aic326x_adc_dsp_event, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_PGA("Left MicPGA",MICL_PGA, 7, 1, NULL, 0), - SND_SOC_DAPM_PGA("Right MicPGA",MICR_PGA, 7, 1, NULL, 0), + SND_SOC_DAPM_PGA("Left MicPGA", AIC3262_MICL_PGA, 7, 1, NULL, 0), + SND_SOC_DAPM_PGA("Right MicPGA", AIC3262_MICR_PGA, 7, 1, NULL, 0), - SND_SOC_DAPM_PGA("MAL PGA", MA_CNTL, 3, 0, NULL, 0), - SND_SOC_DAPM_PGA("MAR PGA", MA_CNTL, 2, 0, NULL, 0), + SND_SOC_DAPM_PGA("MAL PGA", AIC3262_MA_CNTL, + 3, 0, NULL, 0), + SND_SOC_DAPM_PGA("MAR PGA", AIC3262_MA_CNTL, + 2, 0, NULL, 0), - - /* dapm widget for MAL PGA Mixer*/ + /* dapm widget for MAL PGA Mixer */ SND_SOC_DAPM_MIXER("MAL PGA Mixer", SND_SOC_NOPM, 0, 0, - &mal_pga_mixer_controls[0], - ARRAY_SIZE(mal_pga_mixer_controls)), + &mal_pga_mixer_controls[0], + ARRAY_SIZE(mal_pga_mixer_controls)), - /* dapm widget for MAR PGA Mixer*/ + /* dapm widget for MAR PGA Mixer */ SND_SOC_DAPM_MIXER("MAR PGA Mixer", SND_SOC_NOPM, 0, 0, - &mar_pga_mixer_controls[0], - ARRAY_SIZE(mar_pga_mixer_controls)), + &mar_pga_mixer_controls[0], + ARRAY_SIZE(mar_pga_mixer_controls)), - /* dapm widget for Left Input Mixer*/ + /* dapm widget for Left Input Mixer */ SND_SOC_DAPM_MIXER("Left Input Mixer", SND_SOC_NOPM, 0, 0, - &left_input_mixer_controls[0], - ARRAY_SIZE(left_input_mixer_controls)), + &left_input_mixer_controls[0], + ARRAY_SIZE(left_input_mixer_controls)), - /* dapm widget for Right Input Mixer*/ + /* dapm widget for Right Input Mixer */ SND_SOC_DAPM_MIXER("Right Input Mixer", SND_SOC_NOPM, 0, 0, - &right_input_mixer_controls[0], - ARRAY_SIZE(right_input_mixer_controls)), - + &right_input_mixer_controls[0], + ARRAY_SIZE(right_input_mixer_controls)), SND_SOC_DAPM_OUTPUT("HPL"), SND_SOC_DAPM_OUTPUT("HPR"), @@ -3132,31 +1189,36 @@ SND_SOC_DAPM_MUX("DAC MiniDSP IN2 Route", SND_SOC_DAPM_INPUT("IN2R"), SND_SOC_DAPM_INPUT("IN3R"), SND_SOC_DAPM_INPUT("IN4R"), - - - SND_SOC_DAPM_MICBIAS("Mic Bias Ext", MIC_BIAS_CNTL, 6, 0), - SND_SOC_DAPM_MICBIAS("Mic Bias Int", MIC_BIAS_CNTL, 2, 0), - - SND_SOC_DAPM_SUPPLY("PLLCLK",PLL_PR_POW_REG,7,0,pll_power_on_event, - SND_SOC_DAPM_POST_PMU), - SND_SOC_DAPM_SUPPLY("DACCLK",NDAC_DIV_POW_REG,7,0, NULL, 0), - SND_SOC_DAPM_SUPPLY("CODEC_CLK_IN",SND_SOC_NOPM,0,0, NULL, 0), - SND_SOC_DAPM_SUPPLY("DAC_MOD_CLK",MDAC_DIV_POW_REG,7,0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADCCLK",NADC_DIV_POW_REG,7,0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC_MOD_CLK",MADC_DIV_POW_REG,7,0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ASI1_BCLK",ASI1_BCLK_N,7,0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ASI1_WCLK",ASI1_WCLK_N,7,0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ASI2_BCLK",ASI2_BCLK_N,7,0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ASI2_WCLK",ASI2_WCLK_N,7,0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ASI3_BCLK",ASI3_BCLK_N,7,0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ASI3_WCLK",ASI3_WCLK_N,7,0, NULL, 0), + SND_SOC_DAPM_INPUT("Left DMIC"), + SND_SOC_DAPM_INPUT("Right DMIC"), + + SND_SOC_DAPM_MICBIAS("Mic Bias Ext", AIC3262_MIC_BIAS_CNTL, 6, 0), + SND_SOC_DAPM_MICBIAS("Mic Bias Int", AIC3262_MIC_BIAS_CNTL, 2, 0), + + SND_SOC_DAPM_SUPPLY("PLLCLK", AIC3262_PLL_PR_POW_REG, 7, 0, + pll_power_on_event, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_SUPPLY("DACCLK", AIC3262_NDAC_DIV_POW_REG, 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("CODEC_CLK_IN", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC_MOD_CLK", AIC3262_MDAC_DIV_POW_REG, + 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADCCLK", AIC3262_NADC_DIV_POW_REG, 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC_MOD_CLK", AIC3262_MADC_DIV_POW_REG, + 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ASI1_BCLK", AIC3262_ASI1_BCLK_N, 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ASI1_WCLK", AIC3262_ASI1_WCLK_N, 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ASI2_BCLK", AIC3262_ASI2_BCLK_N, 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ASI2_WCLK", AIC3262_ASI2_WCLK_N, 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ASI3_BCLK", AIC3262_ASI3_BCLK_N, 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ASI3_WCLK", AIC3262_ASI3_WCLK_N, 7, 0, NULL, 0), SND_SOC_DAPM_MUX("ASI1_BCLK Route", - SND_SOC_NOPM, 0, 0, &asi1bclk_control), - SND_SOC_DAPM_MUX("ASI2_BCLK Route", SND_SOC_NOPM, 0, 0, &asi2bclk_control), - SND_SOC_DAPM_MUX("ASI3_BCLK Route", SND_SOC_NOPM, 0, 0, &asi3bclk_control), + SND_SOC_NOPM, 0, 0, &asi1bclk_control), + SND_SOC_DAPM_MUX("ASI2_BCLK Route", + SND_SOC_NOPM, 0, 0, &asi2bclk_control), + SND_SOC_DAPM_MUX("ASI3_BCLK Route", + SND_SOC_NOPM, 0, 0, &asi3bclk_control), }; -static const struct snd_soc_dapm_route aic3262_dapm_routes[] ={ +static const struct snd_soc_dapm_route aic3262_dapm_routes[] = { /* TODO: Do we need only DACCLK for ASIIN's and ADCCLK for ASIOUT??? */ /* Clock portion */ {"CODEC_CLK_IN", NULL, "PLLCLK"}, @@ -3164,185 +1226,179 @@ static const struct snd_soc_dapm_route aic3262_dapm_routes[] ={ {"ADCCLK", NULL, "CODEC_CLK_IN"}, {"DAC_MOD_CLK", NULL, "DACCLK"}, #ifdef AIC3262_SYNC_MODE - {"ADC_MOD_CLK", NULL,"DACCLK"}, + {"ADC_MOD_CLK", NULL, "DACCLK"}, #else {"ADC_MOD_CLK", NULL, "ADCCLK"}, #endif - {"ASI1_BCLK Route","DAC_CLK","DACCLK"}, - {"ASI1_BCLK Route","DAC_MOD_CLK","DAC_MOD_CLK"}, - {"ASI1_BCLK Route","ADC_CLK","ADCCLK"}, - {"ASI1_BCLK Route","ADC_MOD_CLK","ADC_MOD_CLK"}, + {"ASI1_BCLK Route", "DAC_CLK", "DACCLK"}, + {"ASI1_BCLK Route", "DAC_MOD_CLK", "DAC_MOD_CLK"}, + {"ASI1_BCLK Route", "ADC_CLK", "ADCCLK"}, + {"ASI1_BCLK Route", "ADC_MOD_CLK", "ADC_MOD_CLK"}, - {"ASI2_BCLK Route","DAC_CLK","DACCLK"}, - {"ASI2_BCLK Route","DAC_MOD_CLK","DAC_MOD_CLK"}, - {"ASI2_BCLK Route","ADC_CLK","ADCCLK"}, - {"ASI2_BCLK Route","ADC_MOD_CLK","ADC_MOD_CLK"}, + {"ASI2_BCLK Route", "DAC_CLK", "DACCLK"}, + {"ASI2_BCLK Route", "DAC_MOD_CLK", "DAC_MOD_CLK"}, + {"ASI2_BCLK Route", "ADC_CLK", "ADCCLK"}, + {"ASI2_BCLK Route", "ADC_MOD_CLK", "ADC_MOD_CLK"}, - {"ASI3_BCLK Route","DAC_CLK","DACCLK"}, - {"ASI3_BCLK Route","DAC_MOD_CLK","DAC_MOD_CLK"}, - {"ASI3_BCLK Route","ADC_CLK","ADCCLK"}, - {"ASI3_BCLK Route","ADC_MOD_CLK","ADC_MOD_CLK"}, + {"ASI3_BCLK Route", "DAC_CLK", "DACCLK"}, + {"ASI3_BCLK Route", "DAC_MOD_CLK", "DAC_MOD_CLK"}, + {"ASI3_BCLK Route", "ADC_CLK", "ADCCLK"}, + {"ASI3_BCLK Route", "ADC_MOD_CLK", "ADC_MOD_CLK"}, {"ASI1_BCLK", NULL, "ASI1_BCLK Route"}, {"ASI2_BCLK", NULL, "ASI2_BCLK Route"}, {"ASI3_BCLK", NULL, "ASI3_BCLK Route"}, - - {"ASI1IN", NULL , "PLLCLK"}, - {"ASI1IN", NULL , "DACCLK"}, - {"ASI1IN", NULL , "ADCCLK"}, - {"ASI1IN", NULL , "DAC_MOD_CLK"}, - {"ASI1IN", NULL , "ADC_MOD_CLK"}, - - {"ASI1OUT", NULL , "PLLCLK"}, - {"ASI1OUT", NULL , "DACCLK"}, - {"ASI1OUT", NULL , "ADCCLK"}, - {"ASI1OUT", NULL , "DAC_MOD_CLK"}, - {"ASI1OUT", NULL , "ADC_MOD_CLK"}, + {"DIN1", NULL, "PLLCLK"}, + {"DIN1", NULL, "DACCLK"}, + {"DIN1", NULL, "ADCCLK"}, + {"DIN1", NULL, "DAC_MOD_CLK"}, + {"DIN1", NULL, "ADC_MOD_CLK"}, + + {"DOUT1", NULL, "PLLCLK"}, + {"DOUT1", NULL, "DACCLK"}, + {"DOUT1", NULL, "ADCCLK"}, + {"DOUT1", NULL, "DAC_MOD_CLK"}, + {"DOUT1", NULL, "ADC_MOD_CLK"}, #ifdef AIC3262_ASI1_MASTER - {"ASI1IN", NULL , "ASI1_BCLK"}, - {"ASI1OUT", NULL , "ASI1_BCLK"}, - {"ASI1IN", NULL , "ASI1_WCLK"}, - {"ASI1OUT", NULL , "ASI1_WCLK"}, + {"DIN1", NULL, "ASI1_BCLK"}, + {"DOUT1", NULL, "ASI1_BCLK"}, + {"DIN1", NULL, "ASI1_WCLK"}, + {"DOUT1", NULL, "ASI1_WCLK"}, #else #endif - - {"ASI2IN", NULL , "PLLCLK"}, - {"ASI2IN", NULL , "DACCLK"}, - {"ASI2IN", NULL , "ADCCLK"}, - {"ASI2IN", NULL , "DAC_MOD_CLK"}, - {"ASI2IN", NULL , "ADC_MOD_CLK"}, - - {"ASI2OUT", NULL , "PLLCLK"}, - {"ASI2OUT", NULL , "DACCLK"}, - {"ASI2OUT", NULL , "ADCCLK"}, - {"ASI2OUT", NULL , "DAC_MOD_CLK"}, - {"ASI2OUT", NULL , "ADC_MOD_CLK"}, + {"DIN2", NULL, "PLLCLK"}, + {"DIN2", NULL, "DACCLK"}, + {"DIN2", NULL, "ADCCLK"}, + {"DIN2", NULL, "DAC_MOD_CLK"}, + {"DIN2", NULL, "ADC_MOD_CLK"}, + + {"DOUT2", NULL, "PLLCLK"}, + {"DOUT2", NULL, "DACCLK"}, + {"DOUT2", NULL, "ADCCLK"}, + {"DOUT2", NULL, "DAC_MOD_CLK"}, + {"DOUT2", NULL, "ADC_MOD_CLK"}, #ifdef AIC3262_ASI2_MASTER - {"ASI2IN", NULL , "ASI2_BCLK"}, - {"ASI2OUT", NULL , "ASI2_BCLK"}, - {"ASI2IN", NULL , "ASI2_WCLK"}, - {"ASI2OUT", NULL , "ASI2_WCLK"}, + {"DIN2", NULL, "ASI2_BCLK"}, + {"DOUT2", NULL, "ASI2_BCLK"}, + {"DIN2", NULL, "ASI2_WCLK"}, + {"DOUT2", NULL, "ASI2_WCLK"}, #else #endif - {"ASI3IN", NULL , "PLLCLK"}, - {"ASI3IN", NULL , "DACCLK"}, - {"ASI3IN", NULL , "ADCCLK"}, - {"ASI3IN", NULL , "DAC_MOD_CLK"}, - {"ASI3IN", NULL , "ADC_MOD_CLK"}, - - - {"ASI3OUT", NULL , "PLLCLK"}, - {"ASI3OUT", NULL , "DACCLK"}, - {"ASI3OUT", NULL , "ADCCLK"}, - {"ASI3OUT", NULL , "DAC_MOD_CLK"}, - {"ASI3OUT", NULL , "ADC_MOD_CLK"}, + {"DIN3", NULL, "PLLCLK"}, + {"DIN3", NULL, "DACCLK"}, + {"DIN3", NULL, "ADCCLK"}, + {"DIN3", NULL, "DAC_MOD_CLK"}, + {"DIN3", NULL, "ADC_MOD_CLK"}, + + {"DOUT3", NULL, "PLLCLK"}, + {"DOUT3", NULL, "DACCLK"}, + {"DOUT3", NULL, "ADCCLK"}, + {"DOUT3", NULL, "DAC_MOD_CLK"}, + {"DOUT3", NULL, "ADC_MOD_CLK"}, #ifdef AIC3262_ASI3_MASTER - {"ASI3IN", NULL , "ASI3_BCLK"}, - {"ASI3OUT", NULL , "ASI3_BCLK"}, - {"ASI3IN", NULL , "ASI3_WCLK"}, - {"ASI3OUT", NULL , "ASI3_WCLK"}, + {"DIN3", NULL, "ASI3_BCLK"}, + {"DOUT3", NULL, "ASI3_BCLK"}, + {"DIN3", NULL, "ASI3_WCLK"}, + {"DOUT3", NULL, "ASI3_WCLK"}, #else -#endif - -/* Playback (DAC) Portion */ - {"HPL Output Mixer","LDAC Switch","Left DAC"}, - {"HPL Output Mixer","MAL Switch","MAL PGA"}, - {"HPL Output Mixer","LOL-B1 Volume","LOL"}, - {"HPR Output Mixer","LOR-B1 Volume","LOR"}, - {"HPR Output Mixer","LDAC Switch","Left DAC"}, - {"HPR Output Mixer","RDAC Switch","Right DAC"}, - {"HPR Output Mixer","MAR Switch","MAR PGA"}, - - {"HPL Driver",NULL,"HPL Output Mixer"}, - {"HPR Driver",NULL,"HPR Output Mixer"}, - - {"HPL",NULL,"HPL Driver"}, - {"HPR",NULL,"HPR Driver"}, +#endif + /* Playback (DAC) Portion */ + {"HPL Output Mixer", "LDAC Switch", "Left DAC"}, + {"HPL Output Mixer", "MAL Switch", "MAL PGA"}, + {"HPL Output Mixer", "LOL-B1 Volume", "LOL"}, - {"LOL Output Mixer","MAL Switch","MAL PGA"}, - {"LOL Output Mixer","IN1L-B Switch","IN1L"}, - {"LOL Output Mixer","LDAC Switch","Left DAC"}, - {"LOL Output Mixer","RDAC Switch","Right DAC"}, + {"HPR Output Mixer", "LOR-B1 Volume", "LOR"}, + {"HPR Output Mixer", "LDAC Switch", "Left DAC"}, + {"HPR Output Mixer", "RDAC Switch", "Right DAC"}, + {"HPR Output Mixer", "MAR Switch", "MAR PGA"}, - {"LOR Output Mixer","LOL Switch","LOL"}, - {"LOR Output Mixer","RDAC Switch","Right DAC"}, - {"LOR Output Mixer","MAR Switch","MAR PGA"}, - {"LOR Output Mixer","IN1R-B Switch","IN1R"}, + {"HPL Driver", NULL, "HPL Output Mixer"}, + {"HPR Driver", NULL, "HPR Output Mixer"}, - {"LOL Driver",NULL,"LOL Output Mixer"}, - {"LOR Driver",NULL,"LOR Output Mixer"}, + {"HPL", NULL, "HPL Driver"}, + {"HPR", NULL, "HPR Driver"}, - {"LOL",NULL,"LOL Driver"}, - {"LOR",NULL,"LOR Driver"}, + {"LOL Output Mixer", "MAL Switch", "MAL PGA"}, + {"LOL Output Mixer", "IN1L-B Switch", "IN1L"}, + {"LOL Output Mixer", "LDAC Switch", "Left DAC"}, + {"LOL Output Mixer", "RDAC Switch", "Right DAC"}, - {"REC Output Mixer","LOL-B2 Volume","LOL"}, - {"REC Output Mixer","IN1L Volume","IN1L"}, - {"REC Output Mixer","IN1R Volume","IN1R"}, - {"REC Output Mixer","LOR-B2 Volume","LOR"}, + {"LOR Output Mixer", "LOL Switch", "LOL"}, + {"LOR Output Mixer", "RDAC Switch", "Right DAC"}, + {"LOR Output Mixer", "MAR Switch", "MAR PGA"}, + {"LOR Output Mixer", "IN1R-B Switch", "IN1R"}, - {"RECP Driver",NULL,"REC Output Mixer"}, - {"RECM Driver",NULL,"REC Output Mixer"}, + {"LOL Driver", NULL, "LOL Output Mixer"}, + {"LOR Driver", NULL, "LOR Output Mixer"}, - {"RECP",NULL,"RECP Driver"}, - {"RECM",NULL,"RECM Driver"}, + {"LOL", NULL, "LOL Driver"}, + {"LOR", NULL, "LOR Driver"}, - {"SPKL Output Mixer","MAL Switch","MAL PGA"}, - {"SPKL Output Mixer","LOL Volume","LOL"}, - {"SPKL Output Mixer","SPR_IN Switch","SPKR Output Mixer"}, + {"REC Output Mixer", "LOL-B2 Volume", "LOL"}, + {"REC Output Mixer", "IN1L Volume", "IN1L"}, + {"REC Output Mixer", "IN1R Volume", "IN1R"}, + {"REC Output Mixer", "LOR-B2 Volume", "LOR"}, - {"SPKR Output Mixer", "LOR Volume","LOR"}, - {"SPKR Output Mixer", "MAR Switch","MAR PGA"}, + {"RECP Driver", NULL, "REC Output Mixer"}, + {"RECM Driver", NULL, "REC Output Mixer"}, + {"RECP", NULL, "RECP Driver"}, + {"RECM", NULL, "RECM Driver"}, - {"SPKL Driver",NULL,"SPKL Output Mixer"}, - {"SPKR Driver",NULL,"SPKR Output Mixer"}, + {"SPKL Output Mixer", "MAL Switch", "MAL PGA"}, + {"SPKL Output Mixer", "LOL Volume", "LOL"}, + {"SPKL Output Mixer", "SPR_IN Switch", "SPKR Output Mixer"}, - {"SPKL",NULL,"SPKL Driver"}, - {"SPKR",NULL,"SPKR Driver"}, -/* ASI Input routing */ - {"ASI1LIN", NULL, "ASI1IN"}, - {"ASI1RIN", NULL, "ASI1IN"}, - {"ASI2LIN", NULL, "ASI2IN"}, - {"ASI2RIN", NULL, "ASI2IN"}, - {"ASI3LIN", NULL, "ASI3IN"}, - {"ASI3RIN", NULL, "ASI3IN"}, + {"SPKR Output Mixer", "LOR Volume", "LOR"}, + {"SPKR Output Mixer", "MAR Switch", "MAR PGA"}, - {"ASI1MonoMixIN", NULL, "ASI1IN"}, - {"ASI2MonoMixIN", NULL, "ASI2IN"}, - {"ASI3MonoMixIN", NULL, "ASI3IN"}, - {"ASI1LIN Route","ASI1 Left In","ASI1LIN"}, - {"ASI1LIN Route","ASI1 Right In","ASI1RIN"}, - {"ASI1LIN Route","ASI1 MonoMix In","ASI1MonoMixIN"}, + {"SPKL Driver", NULL, "SPKL Output Mixer"}, + {"SPKR Driver", NULL, "SPKR Output Mixer"}, - {"ASI1RIN Route", "ASI1 Right In","ASI1RIN"}, - {"ASI1RIN Route","ASI1 Left In","ASI1LIN"}, - {"ASI1RIN Route","ASI1 MonoMix In","ASI1MonoMixIN"}, + {"SPKL", NULL, "SPKL Driver"}, + {"SPKR", NULL, "SPKR Driver"}, + /* ASI Input routing */ + {"ASI1LIN", NULL, "DIN1"}, + {"ASI1RIN", NULL, "DIN1"}, + {"ASI1MonoMixIN", NULL, "DIN1"}, + {"ASI2LIN", NULL, "DIN2"}, + {"ASI2RIN", NULL, "DIN2"}, + {"ASI2MonoMixIN", NULL, "DIN2"}, + {"ASI3LIN", NULL, "DIN3"}, + {"ASI3RIN", NULL, "DIN3"}, + {"ASI3MonoMixIN", NULL, "DIN3"}, + {"ASI1LIN Route", "ASI1 Left In", "ASI1LIN"}, + {"ASI1LIN Route", "ASI1 Right In", "ASI1RIN"}, + {"ASI1LIN Route", "ASI1 MonoMix In", "ASI1MonoMixIN"}, - {"ASI2LIN Route","ASI2 Left In","ASI2LIN"}, - {"ASI2LIN Route","ASI2 Right In","ASI2RIN"}, - {"ASI2LIN Route","ASI2 MonoMix In","ASI2MonoMixIN"}, + {"ASI1RIN Route", "ASI1 Right In", "ASI1RIN"}, + {"ASI1RIN Route", "ASI1 Left In", "ASI1LIN"}, + {"ASI1RIN Route", "ASI1 MonoMix In", "ASI1MonoMixIN"}, - {"ASI2RIN Route","ASI2 Right In","ASI2RIN"}, - {"ASI2RIN Route","ASI2 Left In","ASI2LIN"}, - {"ASI2RIN Route","ASI2 MonoMix In","ASI2MonoMixIN"}, + {"ASI2LIN Route", "ASI2 Left In", "ASI2LIN"}, + {"ASI2LIN Route", "ASI2 Right In", "ASI2RIN"}, + {"ASI2LIN Route", "ASI2 MonoMix In", "ASI2MonoMixIN"}, + {"ASI2RIN Route", "ASI2 Right In", "ASI2RIN"}, + {"ASI2RIN Route", "ASI2 Left In", "ASI2LIN"}, + {"ASI2RIN Route", "ASI2 MonoMix In", "ASI2MonoMixIN"}, - {"ASI3LIN Route","ASI3 Left In","ASI3LIN"}, - {"ASI3LIN Route","ASI3 Right In","ASI3RIN"}, - {"ASI3LIN Route","ASI3 MonoMix In","ASI3MonoMixIN"}, + {"ASI3LIN Route", "ASI3 Left In", "ASI3LIN"}, + {"ASI3LIN Route", "ASI3 Right In", "ASI3RIN"}, + {"ASI3LIN Route", "ASI3 MonoMix In", "ASI3MonoMixIN"}, - {"ASI3RIN Route","ASI3 Right In","ASI3RIN"}, - {"ASI3RIN Route","ASI3 Left In","ASI3LIN"}, - {"ASI3RIN Route","ASI3 MonoMix In","ASI3MonoMixIN"}, + {"ASI3RIN Route", "ASI3 Right In", "ASI3RIN"}, + {"ASI3RIN Route", "ASI3 Left In", "ASI3LIN"}, + {"ASI3RIN Route", "ASI3 MonoMix In", "ASI3MonoMixIN"}, {"ASI1IN Port", NULL, "ASI1LIN Route"}, {"ASI1IN Port", NULL, "ASI1RIN Route"}, @@ -3351,83 +1407,94 @@ static const struct snd_soc_dapm_route aic3262_dapm_routes[] ={ {"ASI3IN Port", NULL, "ASI3LIN Route"}, {"ASI3IN Port", NULL, "ASI3RIN Route"}, - {"DAC MiniDSP IN1 Route", "ASI1 In","ASI1IN Port"}, - {"DAC MiniDSP IN1 Route","ASI2 In","ASI2IN Port"}, - {"DAC MiniDSP IN1 Route","ASI3 In","ASI3IN Port"}, - {"DAC MiniDSP IN1 Route","ADC MiniDSP Out","ADC MiniDSP OUT1"}, + {"DAC MiniDSP IN1 Route", "ASI1 In", "ASI1IN Port"}, + {"DAC MiniDSP IN1 Route", "ASI2 In", "ASI2IN Port"}, + {"DAC MiniDSP IN1 Route", "ASI3 In", "ASI3IN Port"}, + {"DAC MiniDSP IN1 Route", "ADC MiniDSP Out", "ADC MiniDSP OUT1"}, - {"DAC MiniDSP IN2 Route","ASI1 In","ASI1IN Port"}, - {"DAC MiniDSP IN2 Route","ASI2 In","ASI2IN Port"}, - {"DAC MiniDSP IN2 Route","ASI3 In","ASI3IN Port"}, + {"DAC MiniDSP IN2 Route", "ASI1 In", "ASI1IN Port"}, + {"DAC MiniDSP IN2 Route", "ASI2 In", "ASI2IN Port"}, + {"DAC MiniDSP IN2 Route", "ASI3 In", "ASI3IN Port"}, - {"DAC MiniDSP IN3 Route","ASI1 In","ASI1IN Port"}, - {"DAC MiniDSP IN3 Route","ASI2 In","ASI2IN Port"}, - {"DAC MiniDSP IN3 Route","ASI3 In","ASI3IN Port"}, + {"DAC MiniDSP IN3 Route", "ASI1 In", "ASI1IN Port"}, + {"DAC MiniDSP IN3 Route", "ASI2 In", "ASI2IN Port"}, + {"DAC MiniDSP IN3 Route", "ASI3 In", "ASI3IN Port"}, {"Left DAC", "NULL", "DAC MiniDSP IN1 Route"}, {"Right DAC", "NULL", "DAC MiniDSP IN1 Route"}, + {"Left DAC", "NULL", "DAC MiniDSP IN2 Route"}, + {"Right DAC", "NULL", "DAC MiniDSP IN2 Route"}, + {"Left DAC", "NULL", "DAC MiniDSP IN3 Route"}, + {"Right DAC", "NULL", "DAC MiniDSP IN3 Route"}, - {"Left DAC", "NULL","DAC MiniDSP IN2 Route"}, - {"Right DAC", "NULL","DAC MiniDSP IN2 Route"}, - - {"Left DAC", "NULL","DAC MiniDSP IN3 Route"}, - {"Right DAC", "NULL","DAC MiniDSP IN3 Route"}, - - -/* Mixer Amplifier */ + /* Mixer Amplifier */ - {"MAL PGA Mixer", "IN1L Switch","IN1L"}, - {"MAL PGA Mixer", "Left MicPGA Volume","Left MicPGA"}, + {"MAL PGA Mixer", "IN1L Switch", "IN1L"}, + {"MAL PGA Mixer", "Left MicPGA Volume", "Left MicPGA"}, {"MAL PGA", NULL, "MAL PGA Mixer"}, - {"MAR PGA Mixer", "IN1R Switch","IN1R"}, - {"MAR PGA Mixer", "Right MicPGA Volume","Right MicPGA"}, + {"MAR PGA Mixer", "IN1R Switch", "IN1R"}, + {"MAR PGA Mixer", "Right MicPGA Volume", "Right MicPGA"}, {"MAR PGA", NULL, "MAR PGA Mixer"}, -/* Capture (ADC) portions */ + /* Virtual connection between DAC and ADC for miniDSP IPC */ + {"ADC DAC Route", "On", "Left ADC"}, + {"ADC DAC Route", "On", "Right ADC"}, + + {"Left DAC", NULL, "ADC DAC Route"}, + {"Right DAC", NULL, "ADC DAC Route"}, + + /* Capture (ADC) portions */ /* Left Positive PGA input */ - {"Left Input Mixer","IN1L Switch","IN1L"}, - {"Left Input Mixer","IN2L Switch","IN2L"}, - {"Left Input Mixer","IN3L Switch","IN3L"}, - {"Left Input Mixer","IN4L Switch","IN4L"}, - {"Left Input Mixer","IN1R Switch","IN1R"}, + {"Left Input Mixer", "IN1L Switch", "IN1L"}, + {"Left Input Mixer", "IN2L Switch", "IN2L"}, + {"Left Input Mixer", "IN3L Switch", "IN3L"}, + {"Left Input Mixer", "IN4L Switch", "IN4L"}, + {"Left Input Mixer", "IN1R Switch", "IN1R"}, /* Left Negative PGA input */ - {"Left Input Mixer","IN2R Switch","IN2R"}, - {"Left Input Mixer","IN3R Switch","IN3R"}, - {"Left Input Mixer","IN4R Switch","IN4R"}, - {"Left Input Mixer","CM2L Switch","CM2L"}, - {"Left Input Mixer","CM1L Switch","CM1L"}, + {"Left Input Mixer", "IN2R Switch", "IN2R"}, + {"Left Input Mixer", "IN3R Switch", "IN3R"}, + {"Left Input Mixer", "IN4R Switch", "IN4R"}, + {"Left Input Mixer", "CM2L Switch", "CM2L"}, + {"Left Input Mixer", "CM1L Switch", "CM1L"}, - /* Right Positive PGA Input */ - {"Right Input Mixer","IN1R Switch","IN1R"}, - {"Right Input Mixer","IN2R Switch","IN2R"}, - {"Right Input Mixer","IN3R Switch","IN3R"}, - {"Right Input Mixer","IN4R Switch","IN4R"}, - {"Right Input Mixer","IN2L Switch","IN2L"}, + /* Right Positive PGA Input */ + {"Right Input Mixer", "IN1R Switch", "IN1R"}, + {"Right Input Mixer", "IN2R Switch", "IN2R"}, + {"Right Input Mixer", "IN3R Switch", "IN3R"}, + {"Right Input Mixer", "IN4R Switch", "IN4R"}, + {"Right Input Mixer", "IN2L Switch", "IN2L"}, /* Right Negative PGA Input */ - {"Right Input Mixer","IN1L Switch","IN1L"}, - {"Right Input Mixer","IN3L Switch","IN3L"}, - {"Right Input Mixer","IN4L Switch","IN4L"}, - {"Right Input Mixer","CM1R Switch","CM1R"}, - {"Right Input Mixer","CM2R Switch","CM2R"}, + {"Right Input Mixer", "IN1L Switch", "IN1L"}, + {"Right Input Mixer", "IN3L Switch", "IN3L"}, + {"Right Input Mixer", "IN4L Switch", "IN4L"}, + {"Right Input Mixer", "CM1R Switch", "CM1R"}, + {"Right Input Mixer", "CM2R Switch", "CM2R"}, + {"CM1L", NULL, "CM"}, {"CM2L", NULL, "CM"}, {"CM1R", NULL, "CM"}, {"CM2R", NULL, "CM"}, - {"Left MicPGA",NULL,"Left Input Mixer"}, - {"Right MicPGA",NULL,"Right Input Mixer"}, + {"Left MicPGA", NULL, "Left Input Mixer"}, + {"Right MicPGA", NULL, "Right Input Mixer"}, - {"Left ADC", NULL, "Left MicPGA"}, - {"Right ADC", NULL, "Right MicPGA"}, + {"Left ADC Route", "Analog", "Left MicPGA"}, + {"Left ADC Route", "Digital", "Left DMIC"}, -/* ASI Output Routing */ + {"Right ADC Route", "Analog", "Right MicPGA"}, + {"Right ADC Route", "Digital", "Right DMIC"}, + + {"Left ADC", NULL, "Left ADC Route"}, + {"Right ADC", NULL, "Right ADC Route"}, + + /* ASI Output Routing */ {"ADC MiniDSP OUT1", NULL, "Left ADC"}, {"ADC MiniDSP OUT1", NULL, "Right ADC"}, {"ADC MiniDSP OUT2", NULL, "Left ADC"}, @@ -3435,459 +1502,673 @@ static const struct snd_soc_dapm_route aic3262_dapm_routes[] ={ {"ADC MiniDSP OUT3", NULL, "Left ADC"}, {"ADC MiniDSP OUT3", NULL, "Right ADC"}, - {"ASI1OUT Route", "ASI1 Out","ADC MiniDSP OUT1"},// Port 1 - {"ASI1OUT Route", "ASI1In Bypass","ASI1IN Port"}, - {"ASI1OUT Route", "ASI2In Bypass","ASI2IN Port"}, - {"ASI1OUT Route", "ASI3In Bypass","ASI3IN Port"}, - - {"ASI2OUT Route", "ASI1 Out","ADC MiniDSP OUT1"},// Port 1 - {"ASI2OUT Route", "ASI1In Bypass","ASI1IN Port"}, - {"ASI2OUT Route", "ASI2In Bypass","ASI2IN Port"}, - {"ASI2OUT Route", "ASI3In Bypass","ASI3IN Port"}, - {"ASI2OUT Route", "ASI2 Out","ADC MiniDSP OUT2"},// Port 2 - - {"ASI3OUT Route", "ASI1 Out","ADC MiniDSP OUT1"},// Port 1 - {"ASI3OUT Route", "ASI1In Bypass","ASI1IN Port"}, - {"ASI3OUT Route", "ASI2In Bypass","ASI2IN Port"}, - {"ASI3OUT Route", "ASI3In Bypass","ASI3IN Port"}, - {"ASI3OUT Route", "ASI3 Out","ADC MiniDSP OUT3"},// Port 3 - - {"ASI1OUT",NULL,"ASI1OUT Route"}, - {"ASI2OUT",NULL,"ASI2OUT Route"}, - {"ASI3OUT",NULL,"ASI3OUT Route"}, - + {"ASI1OUT Route", "ADC MiniDSP Out1", "ADC MiniDSP OUT1"}, + {"ASI1OUT Route", "ASI1In Bypass", "ASI1IN Port"}, + {"ASI1OUT Route", "ASI2In Bypass", "ASI2IN Port"}, + {"ASI1OUT Route", "ASI3In Bypass", "ASI3IN Port"}, + + {"ASI2OUT Route", "ADC MiniDSP Out1", "ADC MiniDSP OUT1"}, + {"ASI2OUT Route", "ASI1In Bypass", "ASI1IN Port"}, + {"ASI2OUT Route", "ASI2In Bypass", "ASI2IN Port"}, + {"ASI2OUT Route", "ASI3In Bypass", "ASI3IN Port"}, + {"ASI2OUT Route", "ADC MiniDSP Out2", "ADC MiniDSP OUT2"}, + + {"ASI3OUT Route", "ADC MiniDSP Out1", "ADC MiniDSP OUT1"}, + {"ASI3OUT Route", "ASI1In Bypass", "ASI1IN Port"}, + {"ASI3OUT Route", "ASI2In Bypass", "ASI2IN Port"}, + {"ASI3OUT Route", "ASI3In Bypass", "ASI3IN Port"}, + {"ASI3OUT Route", "ADC MiniDSP Out3", "ADC MiniDSP OUT3"}, + + {"ASI1OUT", NULL, "ASI1OUT Route"}, + {"ASI2OUT", NULL, "ASI2OUT Route"}, + {"ASI3OUT", NULL, "ASI3OUT Route"}, + + {"DOUT1 Route", "ASI1 Out", "ASI1OUT"}, + {"DOUT1 Route", "DIN1 Bypass", "DIN1"}, + {"DOUT1 Route", "DIN2 Bypass", "DIN2"}, + {"DOUT1 Route", "DIN3 Bypass", "DIN3"}, + + {"DOUT2 Route", "ASI2 Out", "ASI2OUT"}, + {"DOUT2 Route", "DIN1 Bypass", "DIN1"}, + {"DOUT2 Route", "DIN2 Bypass", "DIN2"}, + {"DOUT2 Route", "DIN3 Bypass", "DIN3"}, + + {"DOUT3 Route", "ASI3 Out", "ASI3OUT"}, + {"DOUT3 Route", "DIN1 Bypass", "DIN1"}, + {"DOUT3 Route", "DIN2 Bypass", "DIN2"}, + {"DOUT3 Route", "DIN3 Bypass", "DIN3"}, + + {"DOUT1", NULL, "DOUT1 Route"}, + {"DOUT2", NULL, "DOUT2 Route"}, + {"DOUT3", NULL, "DOUT3 Route"}, }; +#define AIC3262_DAPM_ROUTE_NUM (ARRAY_SIZE(aic3262_dapm_routes)/ \ + sizeof(struct snd_soc_dapm_route)) +/* aic3262_firmware_load: This function is called by the + * request_firmware_nowait function as soon + * as the firmware has been loaded from the file. + * The firmware structure contains the data and$ + * the size of the firmware loaded. + * @fw: pointer to firmware file to be dowloaded + * @context: pointer variable to codec + * + * Returns 0 for success. + */ +void aic3262_firmware_load(const struct firmware *fw, void *context) +{ + struct snd_soc_codec *codec = context; + struct aic3262_priv *private_ds = snd_soc_codec_get_drvdata(codec); + int ret = 0; -#define AIC3262_DAPM_ROUTE_NUM (sizeof(aic3262_dapm_routes)/sizeof(struct snd_soc_dapm_route)) + aic3xxx_cfw_lock(private_ds->cfw_p, 1); + if (private_ds->cur_fw != NULL) + release_firmware(private_ds->cur_fw); + private_ds->cur_fw = NULL; + + if (fw != NULL) { + dev_dbg(codec->dev, "Firmware binary load\n"); + private_ds->cur_fw = (void *)fw; + ret = aic3xxx_cfw_reload(private_ds->cfw_p, + (void *)fw->data, fw->size); + if (ret < 0) { /* reload failed */ + dev_err(codec->dev, "Firmware binary load failed\n"); + release_firmware(private_ds->cur_fw); + private_ds->cur_fw = NULL; + fw = NULL; + } else + private_ds->isdefault_fw = 0; + } + + if (fw == NULL) { + /* either request_firmware or reload failed */ + dev_dbg(codec->dev, "Default firmware load\n"); + ret = aic3xxx_cfw_reload(private_ds->cfw_p, default_firmware, + sizeof(default_firmware)); + if (ret < 0) + dev_err(codec->dev, "Default firmware load failed\n"); + else + private_ds->isdefault_fw = 1; + } + aic3xxx_cfw_lock(private_ds->cfw_p, 0); + if (ret >= 0) { + /* init function for transition */ + aic3xxx_cfw_transition(private_ds->cfw_p, "INIT"); + if (!private_ds->isdefault_fw) { + aic3xxx_cfw_add_modes(codec, private_ds->cfw_p); + aic3xxx_cfw_add_controls(codec, private_ds->cfw_p); + } + aic3xxx_cfw_setmode_cfg(private_ds->cfw_p, 0, 0); + } +} -/* - ***************************************************************************** - * Function Definitions - ***************************************************************************** - */ +/*========================================================= + headset work and headphone/headset jack interrupt handlers -/* - *---------------------------------------------------------------------------- - * Function : aic3262_change_page - * Purpose : This function is to switch between page 0 and page 1. + ========================================================*/ + +/** + * aic3262_hs_jack_report: Report jack notication to upper layor + * @codec: pointer variable to codec having information related to codec + * @jack: Pointer variable to snd_soc_jack having information of codec + * and pin number$ + * @report: Provides informaton of whether it is headphone or microphone * - *---------------------------------------------------------------------------- - */ -int aic3262_change_page(struct snd_soc_codec *codec, u8 new_page) +*/ +static void aic3262_hs_jack_report(struct snd_soc_codec *codec, + struct snd_soc_jack *jack, int report) { struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - u8 data[2]; - int ret = 0; + int status, state = 0; - data[0] = 0; - data[1] = new_page; - aic3262->page_no = new_page; + mutex_lock(&aic3262->mutex); -#if defined(LOCAL_REG_ACCESS) - if (codec->hw_write(codec->control_data, data, 2) != 2) - ret = -EIO; -#else - ret = snd_soc_write(codec, data[0], data[1]); -#endif - if (ret) - printk(KERN_ERR "Error in changing page to %d\n", new_page); + /* Sync status */ + status = snd_soc_read(codec, AIC3262_DAC_FLAG); + /* We will check only stereo MIC and headphone */ + if (status & AIC3262_JACK_WITH_STEREO_HS) + state |= SND_JACK_HEADPHONE; + if (status & AIC3262_JACK_WITH_MIC) + state |= SND_JACK_MICROPHONE; - /*DBG("# Changing page to %d\r\n", new_page);*/ + mutex_unlock(&aic3262->mutex); + + snd_soc_jack_report(jack, state, report); - return ret; } -/* - *---------------------------------------------------------------------------- - * Function : aic3262_change_book - * Purpose : This function is to switch between books + +/** + * aic3262_hs_jack_detect: Detect headphone jack during boot time + * @codec: pointer variable to codec having information related to codec + * @jack: Pointer variable to snd_soc_jack having information of codec + * and pin number$ + * @report: Provides informaton of whether it is headphone or microphone * - *---------------------------------------------------------------------------- - */ -int aic3262_change_book(struct snd_soc_codec *codec, u8 new_book) +*/ +void aic3262_hs_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *jack, int report) { struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - u8 data[2]; - int ret = 0; + struct aic3262_jack_data *hs_jack = &aic3262->hs_jack; - data[0] = 0x7F; - data[1] = new_book; - aic3262->book_no = new_book; + hs_jack->jack = jack; + hs_jack->report = report; + aic3262_hs_jack_report(codec, hs_jack->jack, hs_jack->report); +} +EXPORT_SYMBOL_GPL(aic3262_hs_jack_detect); +/** + * aic3262_accessory_work: Finished bottom half work from headphone jack + * insertion interupt + * @work: pionter variable to work_struct which is maintaining work queqe + * +*/ +static void aic3262_accessory_work(struct work_struct *work) +{ + struct aic3262_priv *aic3262 = container_of(work, + struct aic3262_priv, + delayed_work.work); + struct snd_soc_codec *codec = aic3262->codec; + struct aic3262_jack_data *hs_jack = &aic3262->hs_jack; + aic3262_hs_jack_report(codec, hs_jack->jack, hs_jack->report); +} - ret = aic3262_change_page(codec, 0); - if (ret) - return ret; +/** + * aic3262_audio_handler: audio interrupt handler called + * when interupt is generated + * @irq: provides interupt number which is assigned by aic3262_request_irq, + * @data having information of data passed by aic3262_request_irq last arg, + * + * Return IRQ_HANDLED(means interupt handeled successfully) +*/ +static irqreturn_t aic3262_audio_handler(int irq, void *data) +{ + struct snd_soc_codec *codec = data; + struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); -#if defined(LOCAL_REG_ACCESS) - if (codec->hw_write(codec->control_data, data, 2) != 2) - ret = -EIO; -#else - ret = snd_soc_write(codec, data[0], data[1]); -#endif - if (ret) - printk(KERN_ERR "Error in changing Book\n"); + queue_delayed_work(aic3262->workqueue, &aic3262->delayed_work, + msecs_to_jiffies(200)); + return IRQ_HANDLED; +} - /*DBG("# Changing book to %d\r\n", new_book);*/ +static irqreturn_t aic3262_button_handler(int irq, void *data) +{ + struct snd_soc_codec *codec = data; + struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); + input_report_key(aic3262->idev, KEY_MEDIA, 1); + mdelay(50); + input_report_key(aic3262->idev, KEY_MEDIA, 0); + input_sync(aic3262->idev); - return ret; + return IRQ_HANDLED; } -/* - *---------------------------------------------------------------------------- - * Function : aic3262_write_reg_cache - * Purpose : This function is to write aic3262 register cache + +/** + * aic3262_codec_read: provide read api to read aic3262 registe space + * @codec: pointer variable to codec having codec information, + * @reg: register address, * - *---------------------------------------------------------------------------- + * Return: Return value will be value read. */ -void aic3262_write_reg_cache(struct snd_soc_codec *codec, - u16 reg, u8 value) +unsigned int aic3262_codec_read(struct snd_soc_codec *codec, unsigned int reg) { -#if defined(EN_REG_CACHE) - u8 *cache = codec->reg_cache; - if (reg >= AIC3262_CACHEREGNUM) - return; + u8 value; - if (cache) - cache[reg] = value; -#endif + union aic326x_reg_union *aic_reg = (union aic326x_reg_union *) ® + value = aic3262_reg_read(codec->control_data, reg); + dev_dbg(codec->dev, "p %d , r 30 %x %x\n", + aic_reg->aic326x_register.page, + aic_reg->aic326x_register.offset, value); + return value; } -/* - *---------------------------------------------------------------------------- - * Function : aic3262_read - * Purpose : This function is to read the aic3262 register space. +/** + * aic3262_codec_write: provide write api to write at aic3262 registe space + * @codec: Pointer variable to codec having codec information, + * @reg: Register address, + * @value: Value to be written to address space * - *---------------------------------------------------------------------------- + * Return: Total no of byte written to address space. */ +int aic3262_codec_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + union aic326x_reg_union *aic_reg = (union aic326x_reg_union *) ® + dev_dbg(codec->dev, "p %d, w 30 %x %x\n", + aic_reg->aic326x_register.page, + aic_reg->aic326x_register.offset, value); + return aic3262_reg_write(codec->control_data, reg, value); +} -unsigned int aic3262_read(struct snd_soc_codec *codec, unsigned int reg) +/** + * aic3262_add_widget: This function is to add the dapm widgets + * The following are the main widgets supported + * # Left DAC to Left Outputs + * # Right DAC to Right Outputs + * # Left Inputs to Left ADC + * # Right Inputs to Right ADC + * @codec: pointer variable to codec having informaton related to codec, + * + * Return: return 0 on success. + */ +static int aic3262_add_widgets(struct snd_soc_codec *codec) { - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - u8 value; - u8 page = reg / 128; - u16 *cache = codec->reg_cache; - u16 cmd; - u8 buffer[2]; - int rc = 0; - reg = reg % 128; - - if (reg >= AIC3262_CACHEREGNUM) { - return 0; - } - if (aic3262->control_type == SND_SOC_I2C) { - if (aic3262->page_no != page) { - aic3262_change_page(codec, page); - } - i2c_master_send(codec->control_data, (char *)®, 1); - i2c_master_recv(codec->control_data, &value, 1); - /*DBG("r %2x %02x\r\n", reg, value); */ - } else if (aic3262->control_type == SND_SOC_SPI) { - u16 value; - - /* Do SPI transfer; first 16bits are command; remaining is - * register contents */ - cmd = AIC3262_READ_COMMAND_WORD(reg); - buffer[0] = (cmd >> 8) & 0xff; - buffer[1] = cmd & 0xff; - //rc = spi_write_then_read(aic3262->spi, buffer, 2, buffer, 2); - - if (rc) { - dev_err(&aic3262->spi->dev, "AIC26 reg read error\n"); - return -EIO; - } - value = (buffer[0] << 8) | buffer[1]; - } else { - printk(KERN_ERR "Unknown Interface Type in aic3262_read\n"); - } + snd_soc_dapm_new_controls(&codec->dapm, aic3262_dapm_widgets, + ARRAY_SIZE(aic3262_dapm_widgets)); + /* set up audio path interconnects */ + dev_dbg(codec->dev, "#Completed adding new dapm widget" + " controls size=%d\n", ARRAY_SIZE(aic3262_dapm_widgets)); - /* Update the cache before returning with the value */ - cache[reg] = value; - return value; + snd_soc_dapm_add_routes(&codec->dapm, aic3262_dapm_routes, + ARRAY_SIZE(aic3262_dapm_routes)); + dev_dbg(codec->dev, "#Completed adding DAPM routes\n"); + snd_soc_dapm_new_widgets(&codec->dapm); + dev_dbg(codec->dev, "#Completed updating dapm\n"); + return 0; } -/* - *---------------------------------------------------------------------------- - * Function : aic3262_write - * Purpose : This function is to write to the aic3262 register space. +/** + * aic3262_set_interface_fmt: Setting interface ASI1/2/3 data format + * @dai: ponter to dai Holds runtime data for a DAI, + * @fmt: asi format info, + * @channel: number of channel, * - *---------------------------------------------------------------------------- - */ -int aic3262_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) + * Return: On success return 0. +*/ +static int aic3262_set_interface_fmt(struct snd_soc_dai *dai, unsigned int fmt, + unsigned int channel) { - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - u8 data[2]; - u8 page; - int ret = 0; - - page = reg / 128; - data[AIC3262_REG_OFFSET_INDEX] = reg % 128; - if (aic3262->page_no != page) - aic3262_change_page(codec, page); + int aif_interface_reg; + int aif_bclk_offset_reg; + struct snd_soc_codec *codec = dai->codec; + u8 iface_val = 0; + u8 dsp_a_val = 0; - /* data is - * D15..D8 aic3262 register offset - * D7...D0 register data - */ - data[AIC3262_REG_DATA_INDEX] = value & AIC3262_8BITS_MASK; -#if defined(EN_REG_CACHE) - if ((page >= 0) & (page <= 4)) - aic3262_write_reg_cache(codec, reg, value); + switch (dai->id) { + case 0: + aif_interface_reg = AIC3262_ASI1_BUS_FMT; + aif_bclk_offset_reg = AIC3262_ASI1_LCH_OFFSET; + break; + case 1: + aif_interface_reg = AIC3262_ASI2_BUS_FMT; + aif_bclk_offset_reg = AIC3262_ASI2_LCH_OFFSET; + break; + case 2: + aif_interface_reg = AIC3262_ASI3_BUS_FMT; + aif_bclk_offset_reg = AIC3262_ASI3_LCH_OFFSET; + break; + default: + return -EINVAL; -#endif - if (!data[AIC3262_REG_OFFSET_INDEX]) { - /* if the write is to reg0 update aic3262->page_no */ - aic3262->page_no = value; } + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + iface_val = 0; + break; + case SND_SOC_DAIFMT_DSP_A: + dsp_a_val = 0x1; /* Intentionally falling back + to following case */ + case SND_SOC_DAIFMT_DSP_B: + switch (channel) { + case 1: + iface_val = 0x80; /* Choose mono PCM */ + break; + case 2: + iface_val = 0x20; + break; + default: + return -EINVAL; + } + break; + case SND_SOC_DAIFMT_RIGHT_J: + iface_val = 0x40; + break; + case SND_SOC_DAIFMT_LEFT_J: + iface_val = 0x60; + break; + default: + dev_err(codec->dev, "Invalid DAI interface format\n"); + return -EINVAL; + } + snd_soc_update_bits(codec, aif_interface_reg, + AIC3262_ASI_INTERFACE_MASK, iface_val); + snd_soc_update_bits(codec, aif_bclk_offset_reg, + AIC3262_BCLK_OFFSET_MASK, dsp_a_val); + return 0; - /*DBG("w %2x %02x\r\n", - data[AIC3262_REG_OFFSET_INDEX], data[AIC3262_REG_DATA_INDEX]);*/ - -#if defined(LOCAL_REG_ACCESS) - if (codec->hw_write(codec->control_data, data, 2) != 2) - ret = -EIO; -#else - ret = snd_soc_write(codec, data[AIC3262_REG_OFFSET_INDEX], - data[AIC3262_REG_DATA_INDEX]); -#endif - if (ret) - printk(KERN_ERR "Error in i2c write\n"); - - return ret; } -/* - *------------------------------------------------------------------------------ - * Function : aic3262_write__ - * Purpose : This function is to write to the aic3262 register space. - * (low level). - *------------------------------------------------------------------------------ +/** + * aic3262_hw_params: This function is to set the hardware parameters + * for AIC3262. + * The functions set the sample rate and audio serial data word + * length. + * @substream: pointer variable to sn_pcm_substream, + * @params: pointer to snd_pcm_hw_params structure, + * @dai: ponter to dai Holds runtime data for a DAI, + * + * Return: Return 0 on success. */ - -int aic3262_write__(struct i2c_client *client, const char *buf, int count) +int aic3262_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - u8 data[3]; - int ret; - data[0] = *buf; - data[1] = *(buf+1); - data[2] = *(buf+2); - /*DBG("w %2x %02x\r\n", - data[AIC3262_REG_OFFSET_INDEX], data[AIC3262_REG_DATA_INDEX]);*/ - ret = i2c_master_send(client, data, 2); - if (ret < 2) { - printk( - KERN_ERR "I2C write Error : bytes written = %d\n\n", ret); - return -EIO; - } + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); + int asi_reg; + u8 data = 0; - return ret; -} -/* - *---------------------------------------------------------------------------- - * Function : aic3262_reset_cache - * Purpose : This function is to reset the cache. - *---------------------------------------------------------------------------- - */ -int aic3262_reset_cache(struct snd_soc_codec *codec) -{ -#if defined(EN_REG_CACHE) - if (codec->reg_cache) { - memcpy(codec->reg_cache, aic3262_reg, sizeof(aic3262_reg)); - return 0; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + aic3262->stream_status = 1; + else + aic3262->stream_status = 0; + + switch (dai->id) { + case 0: + asi_reg = AIC3262_ASI1_BUS_FMT; + break; + case 1: + asi_reg = AIC3262_ASI2_BUS_FMT; + break; + case 2: + asi_reg = AIC3262_ASI3_BUS_FMT; + break; + default: + return -EINVAL; } - codec->reg_cache = kmemdup(aic3262_reg, - sizeof(aic3262_reg), GFP_KERNEL); - if (!codec->reg_cache) { - printk(KERN_ERR "aic32x4: kmemdup failed\n"); - return -ENOMEM; + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + data = data | 0x00; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + data |= (0x08); + break; + case SNDRV_PCM_FORMAT_S24_LE: + data |= (0x10); + break; + case SNDRV_PCM_FORMAT_S32_LE: + data |= (0x18); + break; } -#endif - return 0; + + /* configure the respective Registers for the above configuration */ + snd_soc_update_bits(codec, asi_reg, + AIC3262_ASI_DATA_WORD_LENGTH_MASK, data); + return aic3262_set_interface_fmt(dai, aic3262->asi_fmt[dai->id], + params_channels(params)); } -/* - *---------------------------------------------------------------------------- - * Function : aic3262_get_divs - * Purpose : This function is to get required divisor from the "aic3262_divs" - * table. +/** + * aic3262_mute: This function is to mute or unmute the left and right DAC + * @dai: ponter to dai Holds runtime data for a DAI, + * @mute: integer value one if we using mute else unmute, * - *---------------------------------------------------------------------------- + * Return: return 0 on success. */ -static inline int aic3262_get_divs(int mclk, int rate) +static int aic3262_mute(struct snd_soc_dai *dai, int mute) { - int i; - - for (i = 0; i < ARRAY_SIZE(aic3262_divs); i++) { - if ((aic3262_divs[i].rate == rate) - && (aic3262_divs[i].mclk == mclk)) { - DBG(KERN_INFO "#%s: Found Entry %d in Clock_Array\n", - __func__, i); - return i; - } - } - printk(KERN_ERR "Master clock and sample rate is not supported\n"); - return -EINVAL; + struct snd_soc_codec *codec = dai->codec; + struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "codec : %s : started\n", __func__); + if (dai->id > 2) + return -EINVAL; + if (mute) { + aic3262->mute_asi &= ~((0x1) << dai->id); + if (aic3262->mute_asi == 0) + /* Mute only when all asi's are muted */ + snd_soc_update_bits_locked(codec, + AIC3262_DAC_MVOL_CONF, + AIC3262_DAC_LR_MUTE_MASK, + AIC3262_DAC_LR_MUTE); + + } else { /* Unmute */ + if (aic3262->mute_asi == 0) + /* Unmute for the first asi that need to unmute. + rest unmute will pass */ + snd_soc_update_bits_locked(codec, + AIC3262_DAC_MVOL_CONF, + AIC3262_DAC_LR_MUTE_MASK, + 0x0); + aic3262->mute_asi |= ((0x1) << dai->id); + } + dev_dbg(codec->dev, "codec : %s : ended\n", __func__); + return 0; } -/* - *---------------------------------------------------------------------------- - * Function : aic3262_add_widgets - * Purpose : This function is to add the dapm widgets - * The following are the main widgets supported - * # Left DAC to Left Outputs - * # Right DAC to Right Outputs - * # Left Inputs to Left ADC - * # Right Inputs to Right ADC +/** + * aic3262_set_dai_sysclk: This function is to set the DAI system clock + * @codec_dai: ponter to dai Holds runtime data for a DAI, + * @freq: system clock to be set, + * @dir: integer dir, * - *---------------------------------------------------------------------------- + * Return: return 0 on success. */ -static int aic3262_add_widgets(struct snd_soc_codec *codec) +static int aic3262_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) { - int ret; - struct snd_soc_dapm_context *dapm = &codec->dapm; -#ifndef AIC3262_MULTI_I2S - int i; - for (i = 0; i < ARRAY_SIZE(aic3262_dapm_widgets); i++) - ret = snd_soc_dapm_new_control(dapm, &aic3262_dapm_widgets[i]); -#else - ret = snd_soc_dapm_new_controls(dapm, aic3262_dapm_widgets, - ARRAY_SIZE(aic3262_dapm_widgets)); - if (ret != 0) { - printk(KERN_ERR "#%s: Unable to add DAPM Controls. Err %d\n", - __func__, ret); + struct aic3262_priv *aic3262; + struct snd_soc_codec *codec; + + codec = codec_dai->codec; + aic3262 = snd_soc_codec_get_drvdata(codec); + switch (freq) { + case AIC3262_FREQ_12000000: + aic3262->sysclk = freq; + return 0; + case AIC3262_FREQ_24000000: + aic3262->sysclk = freq; + return 0; + break; + case AIC3262_FREQ_19200000: + aic3262->sysclk = freq; + return 0; + break; + case AIC3262_FREQ_38400000: + aic3262->sysclk = freq; + dev_dbg(codec->dev, "codec: sysclk = %d\n", aic3262->sysclk); + return 0; + break; + case AIC3262_FREQ_12288000: + aic3262->sysclk = freq; + dev_dbg(codec->dev, "codec: sysclk = %d\n", aic3262->sysclk); + return 0; + break; + } -#endif - /* set up audio path interconnects */ - DBG("#Completed adding new dapm widget controls size=%d\n", - ARRAY_SIZE(aic3262_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, aic3262_dapm_routes, - ARRAY_SIZE(aic3262_dapm_routes)); - DBG("#Completed adding DAPM routes\n"); - snd_soc_dapm_new_widgets(dapm); - DBG("#Completed updating dapm\n"); - return 0; + dev_err(codec->dev, "Invalid frequency to set DAI system clock\n"); + + return -EINVAL; } -/* - *---------------------------------------------------------------------------- - * Function : reg_def_conf - * Purpose : This function is to reset the codec book 0 registers + +/** + * aic3262_set_dai_fmt: This function is to set the DAI format + * @codec_dai: ponter to dai Holds runtime data for a DAI, + * @fmt: asi format info, * - *---------------------------------------------------------------------------- + * return: return 0 on success. */ -int reg_def_conf(struct snd_soc_codec *codec) +static int aic3262_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { - int i = 0, ret; - DBG(KERN_INFO "#%s: Invoked..\n", __func__); + struct aic3262_priv *aic3262; + struct snd_soc_codec *codec; + u8 iface_val, master; + int aif_bclk_wclk_reg; - ret = aic3262_change_page(codec, 0); - if (ret != 0) - return ret; + codec = codec_dai->codec; + aic3262 = snd_soc_codec_get_drvdata(codec); + iface_val = 0x00; + master = 0x0; - ret = aic3262_change_book(codec, 0); - if (ret != 0) - return ret; + switch (codec_dai->id) { + case 0: + aif_bclk_wclk_reg = AIC3262_ASI1_BWCLK_CNTL_REG; + break; + case 1: + aif_bclk_wclk_reg = AIC3262_ASI2_BWCLK_CNTL_REG; + break; + case 2: + aif_bclk_wclk_reg = AIC3262_ASI3_BWCLK_CNTL_REG; + break; + default: + return -EINVAL; + + } + aic3262->asi_fmt[codec_dai->id] = fmt; + /* set master/slave audio interface */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + aic3262->master = 1; + master |= (AIC3262_WCLK_OUT_MASK | AIC3262_BCLK_OUT_MASK); + break; + case SND_SOC_DAIFMT_CBS_CFS: + aic3262->master = 0; + break; + case SND_SOC_DAIFMT_CBS_CFM: /* new case..just for debugging */ + master |= (AIC3262_WCLK_OUT_MASK); + aic3262->master = 0; + break; + case SND_SOC_DAIFMT_CBM_CFS: + master |= (AIC3262_BCLK_OUT_MASK); + aic3262->master = 0; + break; - /* Configure the Codec with the default Initialization Values */ - for (i = 0; i < reg_init_size; i++) { - ret = snd_soc_write(codec, aic3262_reg_init[i].reg_offset, - aic3262_reg_init[i].reg_val); - if (ret) + default: + dev_err(codec->dev, "Invalid DAI master/slave" " interface\n"); + + return -EINVAL; + } + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + master |= AIC3262_BCLK_INV_MASK; break; + default: + return -EINVAL; + } + break; + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_LEFT_J: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + master |= AIC3262_BCLK_INV_MASK; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; } - DBG(KERN_INFO "#%s: Done..\n", __func__); - return ret; + snd_soc_update_bits(codec, aif_bclk_wclk_reg, + AIC3262_WCLK_BCLK_MASTER_MASK, master); + return 0; } -/* - * i2c_verify_book0 +/** + * aic3262_dai_set_pll: This function is to Set pll for aic3262 codec dai + * @dai: ponter to dai Holds runtime data for a DAI,$ + * @pll_id: integer pll_id + * @fin: frequency in, + * @fout: Frequency out, * - * This function is used to dump the values of the Book 0 Pages. - */ -int i2c_verify_book0(struct snd_soc_codec *codec) + * Return: return 0 on success +*/ +static int aic3262_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int Fin, unsigned int Fout) { - int i, j, k = 0; - u8 val1; - - DBG("starting i2c_verify\n"); - DBG("Resetting page to 0\n"); - aic3262_change_book(codec, 0); - for (j = 0; j < 3; j++) { - if (j == 0) { - aic3262_change_page(codec, 0); - k = 0; - } - if (j == 1) { - aic3262_change_page(codec, 1); - k = 1; - } - /* - if (j == 2) { - aic3262_change_page(codec, 4); - k = 4; - }*/ - for (i = 0; i <= 127; i++) { -#if defined(LOCAL_REG_ACCESS) - val1 = i2c_smbus_read_byte_data(codec->control_data, i); -#else - val1 = snd_soc_read(codec, i); -#endif - /* printk("[%d][%d]=[0x%2x]\n",k,i,val1); */ - } - } + struct snd_soc_codec *codec = dai->codec; + struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "In aic3262: dai_set_pll\n"); + dev_dbg(codec->dev, "%d, %s, dai->id = %d\n", __LINE__, + __func__, dai->id); + /* select the PLL_CLKIN */ + snd_soc_update_bits(codec, AIC3262_PLL_CLKIN_REG, + AIC3262_PLL_CLKIN_MASK, source << + AIC3262_PLL_CLKIN_SHIFT); + /* TODO: How to select low/high clock range? */ + + aic3xxx_cfw_set_pll(aic3262->cfw_p, dai->id); return 0; } -/* - *---------------------------------------------------------------------------- - * Function : aic3262_set_bias_level - * Purpose : This function is to get triggered when dapm events occurs. +/** * - *---------------------------------------------------------------------------- + * aic3262_set_bias_level: This function is to get triggered + * when dapm events occurs. + * @codec: pointer variable to codec having informaton related to codec, + * @level: Bias level-> ON, PREPARE, STANDBY, OFF. + * + * Return: Return 0 on success. */ - static int aic3262_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) + enum snd_soc_bias_level level) { + switch (level) { /* full On */ case SND_SOC_BIAS_ON: - /* all power is driven by DAPM system */ dev_dbg(codec->dev, "set_bias_on\n"); break; /* partial On */ case SND_SOC_BIAS_PREPARE: - dev_dbg(codec->dev, "set_bias_prepare\n"); - break; - /* Off, with power */ + /* Off, with power */ case SND_SOC_BIAS_STANDBY: /* * all power is driven by DAPM system, * so output power is safe if bypass was set */ - dev_dbg(codec->dev, "set_bias_stby\n"); + dev_dbg(codec->dev, "set_bias_stby\n"); + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + snd_soc_update_bits(codec, AIC3262_POWER_CONF, + (AIC3262_AVDD_TO_DVDD_MASK | + AIC3262_EXT_ANALOG_SUPPLY_MASK), + 0x0); + snd_soc_update_bits(codec, AIC3262_REF_PWR_DLY, + AIC3262_CHIP_REF_PWR_ON_MASK, + AIC3262_CHIP_REF_PWR_ON); + mdelay(40); + } break; - /* Off, without power */ - case SND_SOC_BIAS_OFF: - dev_dbg(codec->dev, "set_bias_off\n"); + /* Off, without power */ + case SND_SOC_BIAS_OFF: + dev_dbg(codec->dev, "set_bias_off\n"); + if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) { + snd_soc_update_bits(codec, AIC3262_REF_PWR_DLY, + AIC3262_CHIP_REF_PWR_ON_MASK, 0x0); + snd_soc_update_bits(codec, AIC3262_POWER_CONF, + (AIC3262_AVDD_TO_DVDD_MASK | + AIC3262_EXT_ANALOG_SUPPLY_MASK), + (AIC3262_AVDD_TO_DVDD | + AIC3262_EXT_ANALOG_SUPPLY_OFF)); + } break; } - codec->dapm.bias_level=level; + codec->dapm.bias_level = level; return 0; } - /* *---------------------------------------------------------------------------- * Function : aic3262_suspend @@ -3897,13 +2178,7 @@ static int aic3262_set_bias_level(struct snd_soc_codec *codec, */ static int aic3262_suspend(struct snd_soc_codec *codec, pm_message_t state) { - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - DBG(KERN_INFO "#%s: Invoked..\n", __func__); - if (aic3262) - disable_irq(aic3262->irq); - - aic3262_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - + aic3262_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } @@ -3916,207 +2191,10 @@ static int aic3262_suspend(struct snd_soc_codec *codec, pm_message_t state) */ static int aic3262_resume(struct snd_soc_codec *codec) { - int i; - u8 data[2]; - int ret = 0; - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - u8 *cache = codec->reg_cache; - DBG(KERN_INFO "#%s: Invoked..\n", __func__); - - ret = aic3262_change_page(codec, 0); - if (ret) - return ret; -#if defined(EN_REG_CACHE) - /* Sync reg_cache with the hardware */ - for (i = 0; i < ARRAY_SIZE(aic3262_reg); i++) { - data[0] = i % 128; - data[1] = cache[i]; -#if defined(LOCAL_REG_ACCESS) - codec->hw_write(codec->control_data, data, 2); -#else - ret = snd_soc_write(codec, data[0], data[1]); - if (ret) - break; -#endif - } -#endif - if (!ret) { - aic3262_change_page(codec, 0); - aic3262_set_bias_level(codec, SND_SOC_BIAS_ON); - - if (aic3262) - enable_irq(aic3262->irq); - } - return ret; -} -/* - *---------------------------------------------------------------------------- - * Function : aic3262_hw_read - * Purpose : This is a low level harware read function. - * - *---------------------------------------------------------------------------- - */ -unsigned int aic3262_hw_read(struct snd_soc_codec *codec, unsigned int count) -{ - struct i2c_client *client = codec->control_data; - unsigned int buf; - - if (count > (sizeof(unsigned int))) - return 0; - - i2c_master_recv(client, (char *)&buf, count); - return buf; -} - -/* -* aic3262_jack_handler -* -* This function is called from the Interrupt Handler -* to check the status of the AIC3262 Registers related to Headset Detection -*/ -static irqreturn_t aic3262_jack_handler(int irq, void *data) -{ - struct snd_soc_codec *codec = data; - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - unsigned int value; - unsigned int micbits, hsbits = 0; - DBG(KERN_INFO "%s++\n", __func__); - - aic3262_change_page(codec, 0); - - /* Read the Jack Status Register*/ - value = snd_soc_read(codec, STICKY_FLAG2); - DBG(KERN_INFO "reg44 0x%x\n", value); - - - value = snd_soc_read(codec, INT_FLAG2); - DBG(KERN_INFO "reg46 0x%x\n", value); - - value = snd_soc_read(codec, DAC_FLAG_R1); - DBG(KERN_INFO "reg37 0x%x\n", value); - - micbits = value & DAC_FLAG_MIC_MASKBITS; - DBG(KERN_INFO "micbits 0x%x\n", micbits); - - hsbits = value & DAC_FLAG_HS_MASKBITS; - DBG(KERN_INFO "hsbits 0x%x\n", hsbits); - - - /* No Headphone or Headset*/ - if (!micbits && !hsbits) { - DBG(KERN_INFO "no headset/headphone\n"); - snd_soc_jack_report(aic3262->headset_jack, - 0, SND_JACK_HEADSET); - } - - /* Headphone Detected */ - if ((micbits == DAC_FLAG_R1_NOMIC) || (hsbits)) { - DBG(KERN_INFO "headphone\n"); - snd_soc_jack_report(aic3262->headset_jack, - SND_JACK_HEADPHONE, SND_JACK_HEADSET); - } - - /* Headset Detected - only with capless */ - if (micbits == DAC_FLAG_R1_MIC) { - DBG(KERN_INFO "headset\n"); - snd_soc_jack_report(aic3262->headset_jack, - SND_JACK_HEADSET, SND_JACK_HEADSET); - } - DBG(KERN_INFO "%s--\n", __func__); - return IRQ_HANDLED; -} - -/* -* aic326x_headset_detect -* -* Call-back function called to check the status of Headset Pin. -*/ -int aic326x_headset_detect(struct snd_soc_codec *codec, - struct snd_soc_jack *jack, int jack_type) -{ - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - - aic3262->headset_jack = jack; - /*Enable the Headset Interrupts*/ - snd_soc_write(codec, INT1_CNTL, 0x80); - - return 0; -} -EXPORT_SYMBOL_GPL(aic326x_headset_detect); - -int aic326x_headset_button_init(struct snd_soc_codec *codec, - struct snd_soc_jack *jack, int jack_type) -{ - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - - aic3262->button_dev = input_allocate_device(); - aic3262->button_dev->name = "aic326x_headset_button"; - aic3262->button_dev->phys = "codec/input0"; - aic3262->button_dev->dev.parent = snd_card_get_device_link(codec->card->snd_card); - input_set_capability(aic3262->button_dev, EV_KEY, KEY_MEDIA); - - if (input_register_device(aic3262->button_dev)) - { - printk( "Unable to register input device headset button"); - } + aic3262_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - aic3262_jack_handler(aic3262->irq, codec); return 0; } -#ifdef AIC3262_MULTI_I2S -/* -* aic3262_asi_default_config -* -* This function is used to perform the default pin configurations for -* the functionalities which are specific to each ASI Port of the AIC3262 -* Audio Codec Chipset. The user is encouraged to change these values -* if required on their platforms. -*/ -static void aic3262_asi_default_config(struct snd_soc_codec *codec) -{ - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - u16 counter; - - DBG(KERN_INFO - "#%s: Invoked. Will Config ASI Registers to Defaults..\n", - __func__); - for (counter = 0; counter < MAX_ASI_COUNT; counter++) { - aic3262->asiCtxt[counter].asi_active = 0; - aic3262->asiCtxt[counter].bclk_div = 1; - aic3262->asiCtxt[counter].wclk_div = 1; - aic3262->asiCtxt[counter].port_muted = 1; - aic3262->asiCtxt[counter].bclk_div_option = - BDIV_CLKIN_DAC_MOD_CLK; - aic3262->asiCtxt[counter].offset1 = 0; - aic3262->asiCtxt[counter].offset2 = 0; - } - /* ASI1 Defaults */ - aic3262->asiCtxt[0].bclk_output = ASI1_BCLK_DIVIDER_OUTPUT; - aic3262->asiCtxt[0].wclk_output = GENERATED_DAC_FS; - aic3262->asiCtxt[0].left_dac_output = DAC_PATH_LEFT; - aic3262->asiCtxt[0].right_dac_output = DAC_PATH_LEFT; - aic3262->asiCtxt[0].adc_input = ADC_PATH_MINIDSP_1; - aic3262->asiCtxt[0].dout_option = ASI_OUTPUT; - - /* ASI2 Defaults */ - aic3262->asiCtxt[1].bclk_output = ASI2_BCLK_DIVIDER_OUTPUT; - aic3262->asiCtxt[1].wclk_output = GENERATED_DAC_FS; - aic3262->asiCtxt[1].left_dac_output = DAC_PATH_LEFT; - aic3262->asiCtxt[1].right_dac_output = DAC_PATH_LEFT; - aic3262->asiCtxt[1].adc_input = ADC_PATH_MINIDSP_2; - aic3262->asiCtxt[1].dout_option = ASI_OUTPUT; - - /* ASI3 Defaults */ - aic3262->asiCtxt[2].bclk_output = ASI3_BCLK_DIVIDER_OUTPUT; - aic3262->asiCtxt[2].wclk_output = GENERATED_DAC_FS; - aic3262->asiCtxt[2].left_dac_output = DAC_PATH_LEFT; - aic3262->asiCtxt[2].right_dac_output = DAC_PATH_LEFT; - aic3262->asiCtxt[2].adc_input = ADC_PATH_MINIDSP_3; - aic3262->asiCtxt[2].dout_option = ASI2_INPUT; - return; -} - -#endif /* #ifdef AIC3262_MULTI_I2S */ /* *---------------------------------------------------------------------------- @@ -4125,402 +2203,223 @@ static void aic3262_asi_default_config(struct snd_soc_codec *codec) * *---------------------------------------------------------------------------- */ - -static int aic3262_probe(struct snd_soc_codec *codec) +static int aic3262_codec_probe(struct snd_soc_codec *codec) { - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); int ret = 0; + int ret_btn = 0; + struct aic3262 *control; + struct aic3262_priv *aic3262; + struct aic3262_jack_data *jack; - DBG(KERN_INFO "#%s: Invoked..\n", __func__); - -#if defined(EN_REG_CACHE) - codec->reg_cache = - kmemdup(aic3262_reg, sizeof(aic3262_reg), GFP_KERNEL); + if (codec == NULL) + dev_err(codec->dev, "codec pointer is NULL.\n"); - if (!codec->reg_cache) { - printk(KERN_ERR "aic3262: kmemdup failed\n"); + codec->control_data = dev_get_drvdata(codec->dev->parent); + control = codec->control_data; + aic3262 = kzalloc(sizeof(struct aic3262_priv), GFP_KERNEL); + if (aic3262 == NULL) return -ENOMEM; - } -#else - /* Setting cache bypass - not to overwrite the cache registers, - Codec registers have 4 pages which is not handled in the common - cache code properly - bypass it in write value and save it - using separate call*/ - codec->cache_bypass = 1; -#endif -#if defined(LOCAL_REG_ACCESS) - codec->control_data = aic3262->control_data; - codec->hw_write = (hw_write_t) aic3262_write__; - codec->hw_read = aic3262_hw_read; -#else - ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); - if (ret != 0) { - dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); - return ret; - } -#endif - ret = reg_def_conf(codec); - if (ret != 0) { - printk(KERN_ERR "Failed to init TI codec: %d\n", ret); - return ret; + snd_soc_codec_set_drvdata(codec, aic3262); + aic3262->pdata = dev_get_platdata(codec->dev->parent); + aic3262->codec = codec; + aic3262->cur_fw = NULL; + aic3262->isdefault_fw = 0; + aic3262->cfw_p = &(aic3262->cfw_ps); + aic3xxx_cfw_init(aic3262->cfw_p, &aic3262_cfw_codec_ops, aic3262); + aic3262->workqueue = create_singlethread_workqueue("aic3262-codec"); + if (!aic3262->workqueue) { + ret = -ENOMEM; + goto work_err; + } + ret = device_create_file(codec->dev, &dev_attr_debug_level); + if (ret) + dev_info(codec->dev, "Failed to add debug_level sysfs\n"); + INIT_DELAYED_WORK(&aic3262->delayed_work, aic3262_accessory_work); + mutex_init(&aic3262->mutex); + mutex_init(&codec->mutex); + mutex_init(&aic3262->cfw_mutex); + aic3262->dsp_runstate = 0; + /* use switch-class based headset reporting if platform requires it */ + jack = &aic3262->hs_jack; + aic3262->idev = input_allocate_device(); + if (aic3262->idev <= 0) + printk(KERN_ERR, "Allocate failed\n"); + + input_set_capability(aic3262->idev, EV_KEY, KEY_MEDIA); + ret = input_register_device(aic3262->idev); + if (ret < 0) { + dev_err(codec->dev, "register input dev fail\n"); + goto input_dev_err; } - if (aic3262->irq) { - /* audio interrupt */ - ret = request_threaded_irq(aic3262->irq, NULL, - aic3262_jack_handler, - IRQF_TRIGGER_FALLING, - "tlv320aic3262", codec); + if (control->irq) { + ret = aic3262_request_irq(codec->control_data, + AIC3262_IRQ_HEADSET_DETECT, + aic3262_audio_handler, 0, + "aic3262_irq_headset", codec); + if (ret) { - printk(KERN_INFO "#%s: IRQ Registration failed..[%d]", - __func__, ret); - dev_err(codec->dev, "Failed to request IRQ: %d\n", ret); - return ret; - } else - DBG(KERN_INFO - "#%s: irq Registration for IRQ %d done..\n", - __func__, aic3262->irq); - } else { - DBG(KERN_INFO "#%s: I2C IRQ Configuration is Wrong. \ - Please check it..\n", __func__); - } + dev_err(codec->dev, "HEADSET detect irq request" + "failed: %d\n", ret); + goto irq_err; + } + + ret = aic3262_request_irq(codec->control_data, + AIC3262_IRQ_BUTTON_PRESS, + aic3262_button_handler, 0, "aic3262_irq_button", + codec); - aic3262_asi_default_config(codec); + if (ret) { + dev_err(codec->dev, "button press irq request" + "failed: %d\n", ret); + goto irq_err; + } + } + /* Keep the reference voltage ON while in$ + STANDBY mode for fast power up */ - /* off, with power on */ + snd_soc_update_bits(codec, AIC3262_REF_PWR_DLY, + AIC3262_CHIP_REF_PWR_ON_MASK, + AIC3262_CHIP_REF_PWR_ON); + mdelay(40); aic3262_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - ret = snd_soc_add_controls(codec, aic3262_snd_controls, - ARRAY_SIZE(aic3262_snd_controls)); - if(ret) - { - printk(KERN_INFO "%s failed\n", __func__); - } + aic3262->mute_asi = 0; + + snd_soc_add_controls(codec, aic3262_snd_controls, + ARRAY_SIZE(aic3262_snd_controls)); aic3262_add_widgets(codec); - /*TODO*/ - snd_soc_write(codec, MIC_BIAS_CNTL, 0x66); #ifdef AIC3262_TiLoad ret = aic3262_driver_init(codec); if (ret < 0) - printk(KERN_ERR - "\nAIC3262 CODEC: aic3262_probe :TiLoad Initialization failed\n"); -#endif - - -#ifdef CONFIG_MINI_DSP - /* Program MINI DSP for ADC and DAC */ - aic3262_minidsp_program(codec); - aic3262_add_minidsp_controls(codec); - aic3262_change_book(codec, 0x0); -#endif - -#ifdef MULTIBYTE_CONFIG_SUPPORT - aic3262_add_multiconfig_controls(codec); + dev_err(codec->dev, "\nTiLoad Initialization failed\n"); #endif + /* force loading the default firmware */ + aic3262_firmware_load(NULL, codec); + request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + "tlv320aic3262_fw_v1.bin", codec->dev, + GFP_KERNEL, codec, aic3262_firmware_load); - DBG(KERN_INFO "#%s: done..\n", __func__); - return ret; + return 0; +irq_err: + input_unregister_device(aic3262->idev); + input_free_device(aic3262->idev); +input_dev_err: +reg_err: +work_err: + kfree(aic3262); + return 0; } - - /* - *---------------------------------------------------------------------------- - * Function : aic3262_remove - * Purpose : to remove aic3262 soc device - * - *---------------------------------------------------------------------------- - */ -static int aic3262_remove(struct snd_soc_codec *codec) +* aic3262_remove: Cleans up and Remove aic3262 soc device +* @codec: pointer variable to codec having informaton related to codec, +* +* Return: Return 0 on success. +*/ +static int aic3262_codec_remove(struct snd_soc_codec *codec) { - /* power down chip */ + struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); + struct aic3262 *control = codec->control_data; + struct aic3262_jack_data *jack = &aic3262->hs_jack; + aic3262_set_bias_level(codec, SND_SOC_BIAS_OFF); + /* free_irq if any */ + switch (control->type) { + case TLV320AIC3262: + if (control->irq) { + aic3262_free_irq(control, AIC3262_IRQ_HEADSET_DETECT, + codec); + aic3262_free_irq(control, AIC3262_IRQ_BUTTON_PRESS, + codec); + } + break; + } + /* release firmware if any */ + if (aic3262->cur_fw != NULL) + release_firmware(aic3262->cur_fw); + /* destroy workqueue for jac dev */ + destroy_workqueue(aic3262->workqueue); + input_unregister_device(aic3262->idev); + input_free_device(aic3262->idev); + + kfree(aic3262); + return 0; } - -/* - *---------------------------------------------------------------------------- - * @struct snd_soc_codec_device | - * This structure is soc audio codec device sturecute which pointer - * to basic functions aic3262_probe(), aic3262_remove(), - * aic3262_suspend() and aic3262_resume() - *---------------------------------------------------------------------------- - */ -static struct snd_soc_codec_driver soc_codec_dev_aic3262 = { - .probe = aic3262_probe, - .remove = aic3262_remove, +static struct snd_soc_codec_driver soc_codec_driver_aic326x = { + .probe = aic3262_codec_probe, + .remove = aic3262_codec_remove, .suspend = aic3262_suspend, .resume = aic3262_resume, + .read = aic3262_codec_read, + .write = aic3262_codec_write, .set_bias_level = aic3262_set_bias_level, -#if defined(LOCAL_REG_ACCESS) - .read = aic3262_read, - .write = aic3262_write, -#endif -#if !defined(EN_REG_CACHE) - .reg_cache_size = ARRAY_SIZE(aic3262_reg), + .reg_cache_size = 0, .reg_word_size = sizeof(u8), - .reg_cache_default = aic3262_reg, -#endif + .reg_cache_default = NULL, }; - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -/* - *---------------------------------------------------------------------------- - * Function : aic3262_codec_probe - * Purpose : This function attaches the i2c client and initializes - * AIC3262 CODEC. - * NOTE: - * This function is called from i2c core when the I2C address is - * valid. - * If the i2c layer weren't so broken, we could pass this kind of - * data around - * - *---------------------------------------------------------------------------- - */ -static __devinit int aic3262_codec_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int aic326x_probe(struct platform_device *pdev) { - int ret; - - struct aic3262_priv *aic3262; - - DBG(KERN_INFO "#%s: Entered\n", __func__); - - aic3262 = kzalloc(sizeof(struct aic3262_priv), GFP_KERNEL); - - if (!aic3262) { - printk(KERN_ERR "#%s: Unable to Allocate Priv struct..\n", - __func__); - return -ENOMEM; - } - - i2c_set_clientdata(i2c, aic3262); -#if defined(LOCAL_REG_ACCESS) - aic3262->control_data = i2c; -#endif - aic3262->control_type = SND_SOC_I2C; - aic3262->irq = i2c->irq; - aic3262->pdata = i2c->dev.platform_data; - - /* The Configuration Support will be by default to 3 which - * holds the MAIN Patch Configuration. - */ - aic3262->current_dac_config[0] = -1; - aic3262->current_dac_config[1] = -1; - aic3262->current_adc_config[0] = -1; - aic3262->current_adc_config[1] = -1; - - aic3262->mute_codec = 1; - - aic3262->page_no = 0; - aic3262->book_no = 0; - aic3262->active_count = 0; - aic3262->dac_clkin_option = 3; - aic3262->adc_clkin_option = 3; - - ret = snd_soc_register_codec(&i2c->dev, - &soc_codec_dev_aic3262, - tlv320aic3262_dai, ARRAY_SIZE(tlv320aic3262_dai)); + return snd_soc_register_codec(&pdev->dev, &soc_codec_driver_aic326x, + aic326x_dai_driver, + ARRAY_SIZE(aic326x_dai_driver)); - if (ret < 0) - kfree(aic3262); - DBG(KERN_INFO "#%s: Done ret %d\n", __func__, ret); - return ret; } -/* - *---------------------------------------------------------------------------- - * Function : aic3262_i2c_remove - * Purpose : This function removes the i2c client and uninitializes - * AIC3262 CODEC. - * NOTE: - * This function is called from i2c core - * If the i2c layer weren't so broken, we could pass this kind of - * data around - * - *---------------------------------------------------------------------------- - */ -static __devexit int aic3262_i2c_remove(struct i2c_client *i2c) +static int aic326x_remove(struct platform_device *pdev) { - snd_soc_unregister_codec(&i2c->dev); - kfree(i2c_get_clientdata(i2c)); + snd_soc_unregister_codec(&pdev->dev); return 0; } -static const struct i2c_device_id tlv320aic3262_id[] = { - {"aic3262-codec", 0}, - {} -}; -MODULE_DEVICE_TABLE(i2c, tlv320aic3262_id); - -static struct i2c_driver tlv320aic3262_i2c_driver = { +static struct platform_driver aic326x_codec_driver = { .driver = { - .name = "aic3262-codec", - .owner = THIS_MODULE, - }, - .probe = aic3262_codec_probe, - .remove = __devexit_p(aic3262_i2c_remove), - .id_table = tlv320aic3262_id, + .name = "tlv320aic3262-codec", + .owner = THIS_MODULE, + }, + .probe = aic326x_probe, + .remove = __devexit_p(aic326x_remove), }; -#endif /*#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)*/ - -#if defined(CONFIG_SPI_MASTER) -static int aic3262_spi_write(struct spi_device *spi, const char *data, int len) -{ - struct spi_transfer t; - struct spi_message m; - u8 msg[2]; - - if (len <= 0) - return 0; - - msg[0] = data[0]; - msg[1] = data[1]; - - spi_message_init(&m); - memset(&t, 0, (sizeof t)); - t.tx_buf = &msg[0]; - t.len = len; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; -} - -#ifdef RUN_DELAYED_WORK /* - * This function forces any delayed work to be queued and run. - */ -static int run_delayed_work(struct delayed_work *dwork) -{ - int ret; - - /* cancel any work waiting to be queued. */ - ret = cancel_delayed_work(dwork); - - /* if there was any work waiting then we run it now and - * wait for it's completion */ - if (ret) { - schedule_delayed_work(dwork, 0); - flush_scheduled_work(); - } - return ret; -} -#endif - -static int __devinit aic3262_spi_probe(struct spi_device *spi) -{ - int ret; - struct snd_soc_codec *codec; - struct aic3262_priv *aic3262; - printk(KERN_INFO "%s entering\n",__func__); - aic3262 = kzalloc(sizeof(struct aic3262_priv), GFP_KERNEL); - - if (!aic3262) { - printk(KERN_ERR "#%s: Unable to Allocate Priv struct..\n", - __func__); - return -ENOMEM; - } - codec = &aic3262->codec; - codec->control_data = spi; - aic3262->control_type = SND_SOC_SPI; - codec->hw_write = (hw_write_t)aic3262_spi_write; - codec->dev = &spi->dev; - - aic3262->pdata = spi->dev.platform_data; - - /* The Configuration Support will be by default to 3 which - * holds the MAIN Patch Configuration. - */ - aic3262->current_dac_config[0] = -1; - aic3262->current_dac_config[1] = -1; - aic3262->current_adc_config[0] = -1; - aic3262->current_adc_config[1] = -1; - - aic3262->mute_codec = 1; - - aic3262->page_no = 0; - aic3262->book_no = 0; - aic3262->active_count = 0; - aic3262->dac_clkin_option = 3; - aic3262->adc_clkin_option = 3; - dev_set_drvdata(&spi->dev, aic3262); - spi_set_drvdata(spi, aic3262); - ret = snd_soc_register_codec(&spi->dev, - &soc_codec_dev_aic3262, - tlv320aic3262_dai, ARRAY_SIZE(tlv320aic3262_dai)); - - if (ret < 0) { - printk(KERN_INFO "%s codec registeration failed\n",__func__); - kfree(aic3262); - } - else { - printk(KERN_INFO "%s registered\n",__func__); - } - printk(KERN_INFO "#%s: Done ret %d\n", __func__, ret); - return ret; -} - -static int __devexit aic3262_spi_remove(struct spi_device *spi) -{ - struct aic3262_priv *aic3262 = dev_get_drvdata(&spi->dev); - aic3262_set_bias_level(&aic3262->codec, SND_SOC_BIAS_OFF); - snd_soc_unregister_codec(&spi->dev); - kfree(aic3262); - aic3262_codec = NULL; - return 0; - -} - -static struct spi_driver aic3262_spi_driver = { - .driver = { - .name = "aic3262-codec", - .bus = &spi_bus_type, - .owner = THIS_MODULE, - }, - .probe = aic3262_spi_probe, - .remove = __devexit_p(aic3262_spi_remove), -}; -#endif +*---------------------------------------------------------------------------- +* Function : tlv320aic3262_modinit +* Purpose : module init function. First function to run. +* +*---------------------------------------------------------------------------- +*/ static int __init tlv320aic3262_modinit(void) { - int ret = 0; - printk(KERN_INFO "In %s\n",__func__); -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - ret = i2c_add_driver(&tlv320aic3262_i2c_driver); - if (ret != 0) - printk(KERN_ERR "Failed to register aic326x i2c driver %d\n", - ret); -#endif -#if defined(CONFIG_SPI_MASTER) - printk(KERN_INFO "Inside config_spi_master\n"); - ret = spi_register_driver(&aic3262_spi_driver); - if (ret != 0) - printk(KERN_ERR "Failed to register aic3262 SPI driver: %d\n", ret); -#endif - return ret; - + return platform_driver_register(&aic326x_codec_driver); } module_init(tlv320aic3262_modinit); +/* +*---------------------------------------------------------------------------- +* Function : tlv320aic3262_exit +* Purpose : module init function. First function to run. +* +*---------------------------------------------------------------------------- +*/ static void __exit tlv320aic3262_exit(void) { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_del_driver(&tlv320aic3262_i2c_driver); -#endif + platform_driver_unregister(&aic326x_codec_driver); + } -module_exit(tlv320aic3262_exit); +module_exit(tlv320aic3262_exit); +MODULE_ALIAS("platform:tlv320aic3262-codec"); MODULE_DESCRIPTION("ASoC TLV320AIC3262 codec driver"); -MODULE_AUTHOR("Barani Prashanth<gvbarani@mistralsolutions.com>"); -MODULE_AUTHOR("Ravindra<ravindra@mistralsolutions.com>"); +MODULE_AUTHOR("Y Preetam Sashank Reddy "); +MODULE_AUTHOR("Barani Prashanth "); +MODULE_AUTHOR("Mukund Navada K <navada@ti.com>"); +MODULE_AUTHOR("Naren Vasanad <naren.vasanad@ti.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic326x.h b/sound/soc/codecs/tlv320aic326x.h index bfcbefc5c079..4a7d909cea74 100644 --- a/sound/soc/codecs/tlv320aic326x.h +++ b/sound/soc/codecs/tlv320aic326x.h @@ -1,8 +1,9 @@ /* - * linux/sound/soc/codecs/tlv320aic3262.h + * linux/sound/soc/codecs/tlv320aic326x.h * + * Copyright (C) 2011 TI Solutions Pvt Ltd. * - * Copyright (C) 2012 Texas Instruments, Inc. + * Based on sound/soc/codecs/tlv320aic3262.c * * This package is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -12,49 +13,44 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * History: - * Rev 0.1 ASoC driver support 20-01-2011 + * The TLV320AIC3262 is a flexible, low-power, low-voltage stereo audio + * codec with digital microphone inputs and programmable outputs. * - * The AIC3262 ASoC driver is ported for the codec AIC3262. + * History: * + * Rev 0.1 ASoC driver support TI 20-01-2011 + * The AIC325x ASoC driver is ported for the codec AIC3262. + * Rev 0.2 ASoC driver support TI 21-03-2011 + * The AIC326x ASoC driver is updated for linux 2.6.32 Kernel. + * Rev 0.3 ASoC driver support TI 20-04-2011 + * The AIC326x ASoC driver is ported to 2.6.35 omap4 kernel */ #ifndef _TLV320AIC3262_H #define _TLV320AIC3262_H -#include <linux/input.h> +#include "aic3xxx_cfw.h" +#include "aic3xxx_cfw_ops.h" +#include <linux/switch.h> + #define AUDIO_NAME "aic3262" #define AIC3262_VERSION "1.1" - -//#define AIC3262_ASI2_MASTER 1 +/* Macro to enable the inclusion of tiload kernel driver */ +#define AIC3262_TiLoad +#undef AIC3262_SYNC_MODE + +/* #define AIC3262_ASI1_MASTER */ +#undef AIC3262_ASI1_MASTER +/* #define AIC3262_ASI2_MASTER */ +#undef AIC3262_ASI2_MASTER +/* #define AIC3262_ASI3_MASTER */ +#undef AIC3262_ASI3_MASTER +/* Macro for McBsp master / slave configuration */ +#define AIC3262_MCBSP_SLAVE /*3262 master */ /* Enable this macro allow for different ASI formats */ -/*#define ASI_MULTI_FMT*/ #undef ASI_MULTI_FMT -#define INT_FLAG2_BUTTN_PRESSBIT 0x20 - -/* Enable register caching on write */ -#define EN_REG_CACHE 1 - -//#define MULTIBYTE_CONFIG_SUPPORT - -/*Setting all codec reg/write locally*/ -/* This definition is added as the snd_ direct call are -result some issue with cache. Common code doesnot support -page, so fix that before commenting this line*/ -#define LOCAL_REG_ACCESS 1 - -/* Macro to enable the inclusion of tiload kernel driver */ -//#define AIC3262_TiLoad - - -/* Macro enables or disables support for miniDSP in the driver */ -/* Enable the AIC3262_TiLoad macro first before enabling these macros */ -//#define CONFIG_MINI_DSP -/*#undef CONFIG_MINI_DSP*/ - /* Enable or disable controls to have Input routing*/ -/*#define FULL_IN_CNTL */ #undef FULL_IN_CNTL /* AIC3262 supported sample rate are 8k to 192k */ #define AIC3262_RATES SNDRV_PCM_RATE_8000_192000 @@ -64,27 +60,10 @@ page, so fix that before commenting this line*/ | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) #define AIC3262_FREQ_12000000 12000000 -#define AIC3262_FREQ_12288000 12288000 +#define AIC3262_FREQ_19200000 19200000 #define AIC3262_FREQ_24000000 24000000 - -/* Macro for enabling the Multi_I2S Support in Driver */ -#define AIC3262_MULTI_I2S 1 - -/* Driver Debug Messages Enabled */ -//#define DEBUG - -#ifdef DEBUG - #define DBG(x...) printk(x) -#else - #define DBG(x...) -#endif - -/*Select the below macro to decide on the DAC master volume controls. - *2 independent or one combined - */ -/*#define DAC_INDEPENDENT_VOL*/ -#undef DAC_INDEPENDENT_VOL - +#define AIC3262_FREQ_38400000 38400000 +#define AIC3262_FREQ_12288000 12288000 /* Audio data word length = 16-bits (default setting) */ #define AIC3262_WORD_LEN_16BITS 0x00 #define AIC3262_WORD_LEN_20BITS 0x01 @@ -92,510 +71,79 @@ page, so fix that before commenting this line*/ #define AIC3262_WORD_LEN_32BITS 0x03 /* sink: name of target widget */ -#define AIC3262_WIDGET_NAME 0 +#define AIC3262_WIDGET_NAME 0 /* control: mixer control name */ -#define AIC3262_CONTROL_NAME +#define AIC3262_CONTROL_NAME 1 /* source: name of source name */ -#define AIC3262_SOURCE_NAME 2 +#define AIC3262_SOURCE_NAME 2 /* D15..D8 aic3262 register offset */ -#define AIC3262_REG_OFFSET_INDEX 0 +#define AIC3262_REG_OFFSET_INDEX 0 /* D7...D0 register data */ -#define AIC3262_REG_DATA_INDEX 1 +#define AIC3262_REG_DATA_INDEX 1 /* Serial data bus uses I2S mode (Default mode) */ -#define AIC3262_I2S_MODE 0x00 -#define AIC3262_DSP_MODE 0x01 -#define AIC3262_RIGHT_JUSTIFIED_MODE 0x02 -#define AIC3262_LEFT_JUSTIFIED_MODE 0x03 +#define AIC3262_I2S_MODE 0x00 +#define AIC3262_DSP_MODE 0x01 +#define AIC3262_RIGHT_JUSTIFIED_MODE 0x02 +#define AIC3262_LEFT_JUSTIFIED_MODE 0x03 /* 8 bit mask value */ -#define AIC3262_8BITS_MASK 0xFF +#define AIC3262_8BITS_MASK 0xFF /* shift value for CLK_REG_3 register */ -#define CLK_REG_3_SHIFT 6 +#define CLK_REG_3_SHIFT 6 /* shift value for DAC_OSR_MSB register */ -#define DAC_OSR_MSB_SHIFT 4 +#define DAC_OSR_MSB_SHIFT 4 /* number of codec specific register for configuration */ -#define NO_FEATURE_REGS 2 - -/* Total number of ASI Ports */ -#define MAX_ASI_COUNT 3 - +#define NO_FEATURE_REGS 2 /* AIC3262 register space */ /* Updated from 256 to support Page 3 registers */ -#define AIC3262_CACHEREGNUM 1024 -#define BIT7 (0x01 << 7) -#define BIT6 (0x01 << 6) -#define BIT5 (0x01 << 5) -#define BIT4 (0x01 << 4) -#define BIT3 (0x01 << 3) -#define BIT2 (0x01 << 2) -#define BIT1 (0x01 << 1) -#define BIT0 (0x01 << 0) - -#define DAC_FLAG_MIC_MASKBITS 0x30 -#define DAC_FLAG_HS_MASKBITS 0x03 -#define DAC_FLAG_R1_NOJACK 0 -#define DAC_FLAG_R1_NOMIC (0x1 << 4) -#define DAC_FLAG_R1_MIC (0x3 << 4) -#define DAC_FLAG_R1_NOHS 0 -#define DAC_FLAG_R1_MONOHS 1 -#define DAC_FLAG_R1_STEREOHS 2 - -/*mask patterns for DAC and ADC polling logic*/ -#define LDAC_POW_FLAG_MASK 0x80 -#define RDAC_POW_FLAG_MASK 0x08 -#define LADC_POW_FLAG_MASK 0x40 -#define RADC_POW_FLAG_MASK 0x04 - -/* ****************** Book 0 Registers **************************************/ - -/* ****************** Page 0 Registers **************************************/ - -#define PAGE_SEL_REG 0 -#define RESET_REG 1 -#define DAC_ADC_CLKIN_REG 4 -#define PLL_CLKIN_REG 5 -#define PLL_CLK_RANGE_REG 5 -#define PLL_PR_POW_REG 6 -#define PLL_J_REG 7 -#define PLL_D_MSB 8 -#define PLL_D_LSB 9 -#define PLL_CKIN_DIV 10 - -#define NDAC_DIV_POW_REG 11 -#define MDAC_DIV_POW_REG 12 -#define DOSR_MSB_REG 13 -#define DOSR_LSB_REG 14 - -#define NADC_DIV_POW_REG 18 -#define MADC_DIV_POW_REG 19 -#define AOSR_REG 20 -#define CLKOUT_MUX 21 -#define CLKOUT_MDIV_VAL 22 -#define TIMER_REG 23 - -#define LF_CLK_CNTL 24 -#define HF_CLK_CNTL_R1 25 -#define HF_CLK_CNTL_R2 26 -#define HF_CLK_CNTL_R3 27 -#define HF_CLK_CNTL_R4 28 -#define HF_CLK_TRIM_R1 29 -#define HF_CLK_TRIM_R2 30 -#define HF_CLK_TRIM_R3 31 -#define HF_CLK_TRIM_R4 32 -#define ADC_FLAG_R1 36 -#define DAC_FLAG_R1 37 -#define DAC_FLAG_R2 38 - -#define STICKY_FLAG1 42 -#define INT_FLAG1 43 -#define STICKY_FLAG2 44 -#define STICKY_FLAG3 45 -#define INT_FLAG2 46 -#define INT1_CNTL 48 -#define INT2_CNTL 49 -#define INT_FMT 51 - -#define DAC_PRB 60 -#define ADC_PRB 61 -#define PASI_DAC_DP_SETUP 63 -#define DAC_MVOL_CONF 64 -#define DAC_LVOL 65 -#define DAC_RVOL 66 -#define HP_DETECT 67 -#define DRC_CNTL_R1 68 -#define DRC_CNTL_R2 69 -#define DRC_CNTL_R3 70 -#define BEEP_CNTL_R1 71 -#define BEEP_CNTL_R2 72 - -#define ADC_CHANNEL_POW 81 -#define ADC_FINE_GAIN 82 -#define LADC_VOL 83 -#define RADC_VOL 84 -#define ADC_PHASE 85 +#define AIC3262_CACHEREGNUM 1024 -#define LAGC_CNTL 86 -#define LAGC_CNTL_R2 87 -#define LAGC_CNTL_R3 88 -#define LAGC_CNTL_R4 89 -#define LAGC_CNTL_R5 90 -#define LAGC_CNTL_R6 91 -#define LAGC_CNTL_R7 92 -#define LAGC_CNTL_R8 93 +#define DSP_NON_SYNC_MODE(state) (!((state & 0x03) && (state & 0x30))) -#define RAGC_CNTL 94 -#define RAGC_CNTL_R2 95 -#define RAGC_CNTL_R3 96 -#define RAGC_CNTL_R4 97 -#define RAGC_CNTL_R5 98 -#define RAGC_CNTL_R6 99 -#define RAGC_CNTL_R7 100 -#define RAGC_CNTL_R8 101 -#define MINIDSP_ACCESS_CTRL 121 -/* ****************** Page 1 Registers **************************************/ -#define PAGE_1 128 - -#define POWER_CONF (PAGE_1 + 1) -#define LDAC_PTM (PAGE_1 + 3) -#define RDAC_PTM (PAGE_1 + 4) -#define CM_REG (PAGE_1 + 8) -#define HP_CTL (PAGE_1 + 9) -#define HP_DEPOP (PAGE_1 + 11) -#define RECV_DEPOP (PAGE_1 + 12) -#define MA_CNTL (PAGE_1 + 17) -#define LADC_PGA_MAL_VOL (PAGE_1 + 18) -#define RADC_PGA_MAR_VOL (PAGE_1 + 19) - - -#define LINE_AMP_CNTL_R1 (PAGE_1 + 22) -#define LINE_AMP_CNTL_R2 (PAGE_1 + 23) - -#define HP_AMP_CNTL_R1 (PAGE_1 + 27) -#define HP_AMP_CNTL_R2 (PAGE_1 + 28) -#define HP_AMP_CNTL_R3 (PAGE_1 + 29) - -#define HPL_VOL (PAGE_1 + 31) -#define HPR_VOL (PAGE_1 + 32) -#define INT1_SEL_L (PAGE_1 + 34) -#define RAMP_CNTL_R1 (PAGE_1 + 36) -#define RAMP_CNTL_R2 (PAGE_1 + 37) -//#define INT1_SEL_RM (PAGE_1 + 39) -#define IN1L_SEL_RM (PAGE_1 + 39) -#define IN1R_SEL_RM (PAGE_1 + 39) - -#define REC_AMP_CNTL_R5 (PAGE_1 + 40) -#define RAMPR_VOL (PAGE_1 + 41) -#define RAMP_TIME_CNTL (PAGE_1 + 42) -#define SPK_AMP_CNTL_R1 (PAGE_1 + 45) -#define SPK_AMP_CNTL_R2 (PAGE_1 + 46) -#define SPK_AMP_CNTL_R3 (PAGE_1 + 47) -#define SPK_AMP_CNTL_R4 (PAGE_1 + 48) -#define MIC_BIAS_CNTL (PAGE_1 + 51) - -#define LMIC_PGA_PIN (PAGE_1 + 52) -#define LMIC_PGA_PM_IN4 (PAGE_1 + 53) -#define LMIC_PGA_MIN (PAGE_1 + 54) -#define RMIC_PGA_PIN (PAGE_1 + 55) -#define RMIC_PGA_PM_IN4 (PAGE_1 + 56) -#define RMIC_PGA_MIN (PAGE_1 + 57) -/* MIC PGA Gain Registers */ -#define MICL_PGA (PAGE_1 + 59) -#define MICR_PGA (PAGE_1 + 60) -#define HEADSET_TUNING1_REG (PAGE_1 + 119) -#define HEADSET_TUNING2_REG (PAGE_1 + 120) -#define MIC_PWR_DLY (PAGE_1 + 121) -#define REF_PWR_DLY (PAGE_1 + 122) - -/* ****************** Page 4 Registers **************************************/ -#define PAGE_4 512 -#define ASI1_BUS_FMT (PAGE_4 + 1) -#define ASI1_LCH_OFFSET (PAGE_4 + 2) -#define ASI1_RCH_OFFSET (PAGE_4 + 3) -#define ASI1_CHNL_SETUP (PAGE_4 + 4) -#define ASI1_MULTI_CH_SETUP_R1 (PAGE_4 + 5) -#define ASI1_MULTI_CH_SETUP_R2 (PAGE_4 + 6) -#define ASI1_ADC_INPUT_CNTL (PAGE_4 + 7) -#define ASI1_DAC_OUT_CNTL (PAGE_4 + 8) -#define ASI1_ADC_OUT_TRISTATE (PAGE_4 + 9) -#define ASI1_BWCLK_CNTL_REG (PAGE_4 + 10) -#define ASI1_BCLK_N_CNTL (PAGE_4 + 11) -#define ASI1_BCLK_N (PAGE_4 + 12) -#define ASI1_WCLK_N (PAGE_4 + 13) -#define ASI1_BWCLK_OUT_CNTL (PAGE_4 + 14) -#define ASI1_DATA_OUT (PAGE_4 + 15) -#define ASI2_BUS_FMT (PAGE_4 + 17) -#define ASI2_LCH_OFFSET (PAGE_4 + 18) -#define ASI2_RCH_OFFSET (PAGE_4 + 19) -#define ASI2_ADC_INPUT_CNTL (PAGE_4 + 23) -#define ASI2_DAC_OUT_CNTL (PAGE_4 + 24) -#define ASI2_BWCLK_CNTL_REG (PAGE_4 + 26) -#define ASI2_BCLK_N_CNTL (PAGE_4 + 27) -#define ASI2_BCLK_N (PAGE_4 + 28) -#define ASI2_WCLK_N (PAGE_4 + 29) -#define ASI2_BWCLK_OUT_CNTL (PAGE_4 + 30) -#define ASI2_DATA_OUT (PAGE_4 + 31) -#define ASI3_BUS_FMT (PAGE_4 + 33) -#define ASI3_LCH_OFFSET (PAGE_4 + 34) -#define ASI3_RCH_OFFSET (PAGE_4 + 35) -#define ASI3_ADC_INPUT_CNTL (PAGE_4 + 39) -#define ASI3_DAC_OUT_CNTL (PAGE_4 + 40) -#define ASI3_BWCLK_CNTL_REG (PAGE_4 + 42) -#define ASI3_BCLK_N_CNTL (PAGE_4 + 43) -#define ASI3_BCLK_N (PAGE_4 + 44) -#define ASI3_WCLK_N (PAGE_4 + 45) -#define ASI3_BWCLK_OUT_CNTL (PAGE_4 + 46) -#define ASI3_DATA_OUT (PAGE_4 + 47) -#define WCLK1_PIN_CNTL_REG (PAGE_4 + 65) -#define DOUT1_PIN_CNTL_REG (PAGE_4 + 67) -#define DIN1_PIN_CNTL_REG (PAGE_4 + 68) -#define WCLK2_PIN_CNTL_REG (PAGE_4 + 69) -#define BCLK2_PIN_CNTL_REG (PAGE_4 + 70) -#define DOUT2_PIN_CNTL_REG (PAGE_4 + 71) -#define DIN2_PIN_CNTL_REG (PAGE_4 + 72) -#define WCLK3_PIN_CNTL_REG (PAGE_4 + 73) -#define BCLK3_PIN_CNTL_REG (PAGE_4 + 74) -#define DOUT3_PIN_CNTL_REG (PAGE_4 + 75) -#define DIN3_PIN_CNTL_REG (PAGE_4 + 76) -#define MCLK2_PIN_CNTL_REG (PAGE_4 + 82) -#define GPIO1_IO_CNTL (PAGE_4 + 86) -#define GPIO2_IO_CNTL (PAGE_4 + 87) -#define GPI1_EN (PAGE_4 + 91) -#define GPO2_EN (PAGE_4 + 92) -#define GPO1_PIN_CNTL (PAGE_4 + 96) -#define MINIDSP_PORT_CNTL_REG (PAGE_4 + 118) - -/**************************************************************************** -* Mixer control related #defines -*************************************************************************** -*/ -#define WCLK1_ENUM 0 -#define DOUT1_ENUM 1 -#define DIN1_ENUM 2 -#define WCLK2_ENUM 3 -#define BCLK2_ENUM 4 -#define DOUT2_ENUM 5 -#define DIN2_ENUM 6 -#define WCLK3_ENUM 7 -#define BCLK3_ENUM 8 -#define DOUT3_ENUM 9 -#define DIN3_ENUM 10 -#define CLKIN_ENUM 11 -/* -***************************************************************************** -* Enumeration Definitions -***************************************************************************** -*/ -/* The below enumeration lists down all the possible inputs to the -* the PLL of the AIC3262. The Private structure will hold a member -* of this Enumeration Type. -*/ -enum AIC3262_PLL_OPTION { - PLL_CLKIN_MCLK1 = 0, /* 0000: (Device Pin) */ - PLL_CLKIN_BLKC1, /* 0001: (Device Pin) */ - PLL_CLKIN_GPIO1, /* 0010: (Device Pin)*/ - PLL_CLKIN_DIN1, /* 0011: (Device Pin)*/ - PLL_CLKIN_BCLK2, /* 0100: (Device Pin)*/ - PLL_CLKIN_GPI1, /* 0101: (Device Pin)*/ - PLL_CLKIN_HF_REF_CLK, /* 0110: (Device Pin)*/ - PLL_CLKIN_GPIO2, /* 0111: (Device Pin)*/ - PLL_CLKIN_GPI2, /* 1000: (Device Pin)*/ - PLL_CLKIN_MCLK2 /* 1001: (Device Pin)*/ -}; +#define TIME_DELAY 5 +#define DELAY_COUNTER 100 -/* ASI Specific Bit Clock Divider Input Options. -* Please refer to Page 4 Reg 11, Reg 27 and Reg 43 -*/ -enum ASI_BDIV_CLKIN_OPTION { - BDIV_CLKIN_DAC_CLK = 0, /* 00 DAC_CLK */ - BDIV_CLKIN_DAC_MOD_CLK, /* 01 DAC_MOD_CLK */ - BDIV_CLKIN_ADC_CLK, /* 02 ADC_CLK */ - BDIV_CLKIN_ADC_MOD_CLK /* 03 ADC_MOD_CLK */ -}; - -/* ASI Specific Bit Clock Output Mux Options. -* Please refer to Page 4 Reg 14, Reg 30 and Reg 46 -* Please note that we are not handling the Reserved -* cases here. -*/ -enum ASI_BCLK_OPTION { - ASI1_BCLK_DIVIDER_OUTPUT = 0, /* 00 ASI1 Bit Clock Divider Output */ - ASI1_BCLK_INPUT, /* 01 ASI1 Bit Clock Input */ - ASI2_BCLK_DIVIDER_OUTPUT, /* 02 ASI2 Bit Clock Divider Output */ - ASI2_BCLK_INPUT, /* 03 ASI2 Bit Clock Input */ - ASI3_BCLK_DIVIDER_OUTPUT, /* 04 ASI3 Bit Clock Divider Output */ - ASI3_BBCLK_INPUT /* 05 ASi3 Bit Clock Input */ -}; - -/* Above bits are to be configured after Shifting 4 bits */ -#define AIC3262_ASI_BCLK_MUX_SHIFT 4 -#define AIC3262_ASI_BCLK_MUX_MASK (BIT6 | BIT5 | BIT4) -#define AIC3262_ASI_WCLK_MUX_MASK (BIT2 | BIT1 | BIT0) - -/* ASI Specific Word Clock Output Mux Options */ -enum ASI_WCLK_OPTION { - GENERATED_DAC_FS = 0, /* 00 WCLK = DAC_FS */ - GENERATED_ADC_FS = 1, /* 01 WCLK = ADC_FS */ - ASI1_WCLK_DIV_OUTPUT = 2, /* 02 WCLK = ASI1 WCLK_DIV_OUT */ - ASI1_WCLK_INPUT = 3, /* 03 WCLK = ASI1 WCLK Input */ - ASI2_WCLK_DIV_OUTPUT = 4, /* 04 WCLK = ASI2 WCLK_DIV_OUT */ - ASI2_WCLK_INPUT = 5, /* 05 WCLK = ASI2 WCLK Input */ - ASI3_WCLK_DIV_OUTPUT = 6, /* 06 WCLK = ASI3 WCLK_DIV_OUT */ - ASI3_WCLK_INPUT = 7 /* 07 WCLK = ASI3 WCLK Input */ -}; - -/* ASI DAC Output Control Options */ -enum ASI_DAC_OUTPUT_OPTION { - DAC_PATH_OFF = 0, /* 00 DAC Datapath Off */ - DAC_PATH_LEFT, /* 01 DAC Datapath left Data */ - DAC_PATH_RIGHT, /* 02 DAC Datapath Right Data */ -}; - -#define AIC3262_READ_COMMAND_WORD(addr) ((1 << 15) | (addr << 5)) -#define AIC3262_WRITE_COMMAND_WORD(addr) ((0 << 15) | (addr << 5)) - -/* Shift the above options by so many bits */ -#define AIC3262_ASI_LDAC_PATH_SHIFT 6 -#define AIC3262_ASI_LDAC_PATH_MASK (BIT5 | BIT4) -#define AIC3262_ASI_RDAC_PATH_SHIFT 4 -#define AIC3262_ASI_RDAC_PATH_MASK (BIT7 | BIT6) - - -#define DAC_LR_MUTE_MASK 0xc -#define DAC_LR_MUTE 0xc -#define ENABLE_CLK_MASK 0x80 -#define ENABLE_CLK 0x80 - -/* ASI specific ADC Input Control Options */ -enum ASI_ADC_INPUT_OPTION { - ADC_PATH_OFF = 0, /* 00 ASI Digital Output Disabled */ - ADC_PATH_MINIDSP_1, /* 01 ASI Digital O/P from miniDSP_A(L1,R1) */ - ADC_PATH_ASI1, /* 02 ASI Digital Output from ASI1 */ - ADC_PATH_ASI2, /* 03 ASI Digital Output from ASI2 */ - ADC_PATH_ASI3, /* 04 ASI Digital Output from ASI3 */ - ADC_PATH_MINIDSP_2, /* 05 ASI Digital O/P from miniDSP_A(L2,R2) */ - ADC_PATH_MINIDSP_3 /* 05 ASI Digital O/P from miniDSP_A(L3,R3) */ -}; - -/* ASI Specific DOUT Pin Options */ -enum ASI_DOUT_OPTION { - ASI_OUTPUT = 0, /* 00 Default ASI Output */ - ASI1_INPUT, /* 01 ASI1 Data Input */ - ASI2_INPUT, /* 02 ASI2 Data Input */ - ASI3_INPUT /* 03 ASI3 Data Input */ -}; - -#define AIC3262_ASI_DOUT_MASK (BIT1 | BIT0) - -/* - ***************************************************************************** - * Structures Definitions - ***************************************************************************** - */ -#define AIC3262_MULTI_ASI_ACTIVE(x) (((x)->asiCtxt[0].asi_active) || \ - ((x)->asiCtxt[1].asi_active) || \ - ((x)->asiCtxt[2].asi_active)) - -/* -*---------------------------------------------------------------------------- -* @struct aic3262_setup_data | -* i2c specific data setup for AIC3262. -* @field unsigned short |i2c_address | -* Unsigned short for i2c address. -*---------------------------------------------------------------------------- -*/ - struct aic3262_setup_data { - unsigned short i2c_address; -}; +#ifdef AIC3262_TiLoad +int aic3262_driver_init(struct snd_soc_codec *codec); +#endif -/* -*---------------------------------------------------------------------------- -* @struct aic3262_asi_data -* ASI specific data stored for each ASI Interface -* -* -*--------------------------------------------------------------------------- -*/ -struct aic3262_asi_data { - u8 asi_active; /* ASI Active Flag */ - u8 master; /* Frame Master */ - u32 sampling_rate; /* Sampling Rate */ - enum ASI_BDIV_CLKIN_OPTION bclk_div_option; /* BCLK DIV Mux Option*/ - enum ASI_BCLK_OPTION bclk_output; /* BCLK Output Option*/ - enum ASI_WCLK_OPTION wclk_output; /* WCLK Output Option*/ - u8 bclk_div; /* BCLK Divider */ - u8 wclk_div; /* WCLK Divider */ - enum ASI_DAC_OUTPUT_OPTION left_dac_output; /* LDAC Path */ - enum ASI_DAC_OUTPUT_OPTION right_dac_output; /* RDAC Path */ - enum ASI_ADC_INPUT_OPTION adc_input; /* ADC Input Control */ - enum ASI_DOUT_OPTION dout_option; /* DOUT Option */ - u8 playback_mode; /* Playback Selected */ - u8 capture_mode; /* Record Selected */ - u8 port_muted; /* ASI Muted */ - u8 pcm_format; /* PCM Format */ - u8 word_len; /* Word Length */ - u8 offset1; /* Left Ch offset */ - u8 offset2; /* Right Ch Offset */ +struct aic3262_jack_data { + struct snd_soc_jack *jack; + int report; + struct switch_dev sdev; }; -/* -*---------------------------------------------------------------------------- -* @struct aic3262_priv | -* AIC3262 priviate data structure to set the system clock, mode and -* page number. -* @field u32 | sysclk | -* system clock -* @field s32 | master | -* master/slave mode setting for AIC3262 -* @field u8 | book_no | -* book number. -* @field u8 | page_no | -* page number. Here, page 0 and page 1 are used. -*---------------------------------------------------------------------------- -*/ struct aic3262_priv { - enum snd_soc_control_type control_type; - struct aic326x_pdata *pdata; - struct snd_soc_codec codec; u32 sysclk; s32 master; - u8 book_no; - u8 page_no; - u8 process_flow; - u8 mute_codec; u8 stream_status; - u32 active_count; - int current_dac_config[MAX_ASI_COUNT]; - int current_adc_config[MAX_ASI_COUNT]; - int current_config; - struct aic3262_asi_data asiCtxt[MAX_ASI_COUNT]; - enum AIC3262_PLL_OPTION aic3262_pllclkin_option; - u8 dac_clkin_option; - u8 adc_clkin_option; - int irq; - u8 dac_reg; - u8 adc_gain; - u8 hpl; - u8 hpr; - u8 rec_amp; - u8 rampr; - u8 spk_amp; - struct spi_device *spi; - struct snd_soc_jack *headset_jack; - struct input_dev *button_dev; - int codec_audio_mode; -#if defined(LOCAL_REG_ACCESS) - void *control_data; -#endif -}; - -/* - *---------------------------------------------------------------------------- - * @struct aic3262_configs | - * AIC3262 initialization data which has register offset and register - * value. - * @field u8 | book_no | - * AIC3262 Book Number Offsets required for initialization.. - * @field u16 | reg_offset | - * AIC3262 Register offsets required for initialization.. - * @field u8 | reg_val | - * value to set the AIC3262 register to initialize the AIC3262. - *---------------------------------------------------------------------------- - */ -struct aic3262_configs { - u8 book_no; - u16 reg_offset; - u8 reg_val; + struct aic3262_jack_data hs_jack; + struct workqueue_struct *workqueue; + struct delayed_work delayed_work; + struct input_dev *idev; + struct snd_soc_codec *codec; + struct mutex mutex; + struct mutex cfw_mutex; + struct cfw_state cfw_ps; + struct cfw_state *cfw_p; + struct aic3262_pdata *pdata; + int mute_asi; /* Bit 0 -> ASI1, Bit 1-> ASI2, Bit 2 -> ASI3 */ + int asi_fmt[2]; + int dsp_runstate; + struct firmware *cur_fw; + int isdefault_fw; }; /* *---------------------------------------------------------------------------- * @struct aic3262_rate_divs | * Setting up the values to get different freqencies + * * @field u32 | mclk | * Master clock * @field u32 | rate | @@ -620,8 +168,6 @@ struct aic3262_configs { * value for madc * @field u32 | blck_N | * value for block N - * @field u32 | aic3262_configs | - * configurations for aic3262 register value *---------------------------------------------------------------------------- */ struct aic3262_rate_divs { @@ -637,49 +183,16 @@ struct aic3262_rate_divs { u8 nadc; u8 madc; u8 blck_N; - struct aic3262_configs codec_specific_regs[NO_FEATURE_REGS]; }; -/* -***************************************************************************** -* EXTERN DECLARATIONS -***************************************************************************** -*/ -/* - *---------------------------------------------------------------------------- - * @func aic326x_headset_detect - * This function help to setup the needed registers to - * enable the headset detection - * - */ -extern int aic326x_headset_detect(struct snd_soc_codec *codec, - struct snd_soc_jack *jack, int jack_type); -extern int aic326x_headset_button_init(struct snd_soc_codec *codec, - struct snd_soc_jack *jack, int jack_type); - -extern unsigned int aic3262_read(struct snd_soc_codec *codec, unsigned int reg); -extern u16 aic3262_read_2byte(struct snd_soc_codec *codec, u16 reg); -extern int aic3262_reset_cache(struct snd_soc_codec *codec); -extern int aic3262_change_page(struct snd_soc_codec *codec, u8 new_page); -extern int aic3262_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value); -extern void aic3262_write_reg_cache(struct snd_soc_codec *codec, - u16 reg, u8 value); -extern int aic3262_change_book(struct snd_soc_codec *codec, u8 new_book); -extern int reg_def_conf(struct snd_soc_codec *codec); -extern int i2c_verify_book0(struct snd_soc_codec *codec); -extern int poll_dac(struct snd_soc_codec *codec, int left_right, int on_off); -extern int poll_adc(struct snd_soc_codec *codec, int left_right, int on_off); - -#ifdef CONFIG_MINI_DSP -extern int aic3262_minidsp_program(struct snd_soc_codec *codec); -extern int aic3262_add_minidsp_controls(struct snd_soc_codec *codec); -#endif - - -#ifdef MULTIBYTE_CONFIG_SUPPORT -extern int aic3262_add_multiconfig_controls(struct snd_soc_codec *codec); -#endif +extern struct snd_soc_dai tlv320aic3262_dai; +extern struct snd_soc_codec_device soc_codec_dev_aic3262; +extern const struct aic3xxx_codec_ops aic3262_cfw_codec_ops; +void aic3262_hs_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *jack, int report); +unsigned int aic3262_read(struct snd_soc_codec *codec, unsigned int reg); +int aic3262_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value); #endif /* _TLV320AIC3262_H */ |