diff options
Diffstat (limited to 'sound/soc/codecs/aic3262_codec_ops.c')
-rw-r--r-- | sound/soc/codecs/aic3262_codec_ops.c | 424 |
1 files changed, 424 insertions, 0 deletions
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, +}; + |