diff options
Diffstat (limited to 'asoc/codecs/tas256x/logical_layer/src/tas256x-logic.c')
-rw-r--r-- | asoc/codecs/tas256x/logical_layer/src/tas256x-logic.c | 1428 |
1 files changed, 1428 insertions, 0 deletions
diff --git a/asoc/codecs/tas256x/logical_layer/src/tas256x-logic.c b/asoc/codecs/tas256x/logical_layer/src/tas256x-logic.c new file mode 100644 index 00000000..125d0a45 --- /dev/null +++ b/asoc/codecs/tas256x/logical_layer/src/tas256x-logic.c @@ -0,0 +1,1428 @@ +#include "logical_layer/inc/tas256x-logic.h" +#include "physical_layer/inc/tas256x-device.h" +#if IS_ENABLED(CONFIG_TAS25XX_ALGO) +#include "algo/inc/tas_smart_amp_v2.h" +#include "algo/inc/tas25xx-calib.h" +#include "os_layer/inc/tas256x-regmap.h" +#endif /*CONFIG_TAS25XX_ALGO*/ + +static int tas256x_change_book_page(struct tas256x_priv *p_tas256x, + enum channel chn, + int book, int page) +{ + int n_result = 0, rc = 0; + int i = 0; + + for (i = 0; i < p_tas256x->mn_channels; i++) { + if (((chn&channel_left) && (i == 0)) + || ((chn&channel_right) && (i == 1))) { + if (p_tas256x->devs[i]->mn_current_book != book) { + n_result = p_tas256x->plat_write(p_tas256x->platform_data, + p_tas256x->devs[i]->mn_addr, + TAS256X_BOOKCTL_PAGE, 0); + if (n_result < 0) { + pr_err( + "%s, ERROR, L=%d, E=%d\n", + __func__, __LINE__, n_result); + rc |= n_result; + continue; + } + p_tas256x->devs[i]->mn_current_page = 0; + n_result = p_tas256x->plat_write(p_tas256x->platform_data, + p_tas256x->devs[i]->mn_addr, + TAS256X_BOOKCTL_REG, book); + if (n_result < 0) { + pr_err( + "%s, ERROR, L=%d, E=%d\n", + __func__, __LINE__, n_result); + rc |= n_result; + continue; + } + p_tas256x->devs[i]->mn_current_book = book; + } + + if (p_tas256x->devs[i]->mn_current_page != page) { + n_result = p_tas256x->plat_write(p_tas256x->platform_data, + p_tas256x->devs[i]->mn_addr, + TAS256X_BOOKCTL_PAGE, page); + if (n_result < 0) { + pr_err( + "%s, ERROR, L=%d, E=%d\n", + __func__, __LINE__, n_result); + rc |= n_result; + continue; + } + p_tas256x->devs[i]->mn_current_page = page; + } + } + } + + if (rc < 0) { + if (chn&channel_left) + p_tas256x->mn_err_code |= ERROR_DEVA_I2C_COMM; + if (chn&channel_right) + p_tas256x->mn_err_code |= ERROR_DEVB_I2C_COMM; + } else { + if (chn&channel_left) + p_tas256x->mn_err_code &= ~ERROR_DEVA_I2C_COMM; + if (chn&channel_right) + p_tas256x->mn_err_code &= ~ERROR_DEVB_I2C_COMM; + } + return rc; +} + +static int tas256x_dev_read(struct tas256x_priv *p_tas256x, + enum channel chn, + unsigned int reg, unsigned int *pValue) +{ + int n_result = 0; + int i = 0, chnTemp = 0; + + mutex_lock(&p_tas256x->dev_lock); + + if (chn == channel_both) { + for (i = 0; i < p_tas256x->mn_channels; i++) { + if (p_tas256x->devs[i]->spk_control == 1) + chnTemp |= 1 << i; + } + chn = (chnTemp == 0) ? chn : (enum channel)chnTemp; + } + + n_result = tas256x_change_book_page(p_tas256x, chn, + TAS256X_BOOK_ID(reg), TAS256X_PAGE_ID(reg)); + if (n_result < 0) + goto end; + + /*Force left incase of mono*/ + if ((chn == channel_right) && (p_tas256x->mn_channels == 1)) + chn = channel_left; + + n_result = p_tas256x->plat_read(p_tas256x->platform_data, + p_tas256x->devs[chn >> 1]->mn_addr, + TAS256X_PAGE_REG(reg), pValue); + if (n_result < 0) { + pr_err("%s, ERROR, L=%d, E=%d\n", + __func__, __LINE__, n_result); + if (chn&channel_left) + p_tas256x->mn_err_code |= ERROR_DEVA_I2C_COMM; + if (chn&channel_right) + p_tas256x->mn_err_code |= ERROR_DEVB_I2C_COMM; + } else { + pr_debug( + "%s: chn:%x:BOOK:PAGE:REG 0x%02x:0x%02x:0x%02x,0x%02x\n", + __func__, + p_tas256x->devs[chn >> 1]->mn_addr, TAS256X_BOOK_ID(reg), + TAS256X_PAGE_ID(reg), + TAS256X_PAGE_REG(reg), *pValue); + if (chn&channel_left) + p_tas256x->mn_err_code &= ~ERROR_DEVA_I2C_COMM; + if (chn&channel_right) + p_tas256x->mn_err_code &= ~ERROR_DEVB_I2C_COMM; + } +end: + mutex_unlock(&p_tas256x->dev_lock); + return n_result; +} + +static int tas256x_dev_write(struct tas256x_priv *p_tas256x, enum channel chn, + unsigned int reg, unsigned int value) +{ + int n_result = 0, rc = 0; + int i = 0, chnTemp = 0; + + mutex_lock(&p_tas256x->dev_lock); + + if (chn == channel_both) { + for (i = 0; i < p_tas256x->mn_channels; i++) { + if (p_tas256x->devs[i]->spk_control == 1) + chnTemp |= 1 << i; + } + chn = (chnTemp == 0) ? chn : (enum channel)chnTemp; + } + + n_result = tas256x_change_book_page(p_tas256x, chn, + TAS256X_BOOK_ID(reg), TAS256X_PAGE_ID(reg)); + if (n_result < 0) + goto end; + + for (i = 0; i < p_tas256x->mn_channels; i++) { + if (((chn&channel_left) && (i == 0)) + || ((chn&channel_right) && (i == 1))) { + n_result = p_tas256x->plat_write(p_tas256x->platform_data, + p_tas256x->devs[i]->mn_addr, + TAS256X_PAGE_REG(reg), value); + if (n_result < 0) { + pr_err( + "%s, ERROR, L=%u, chn=0x%02x, E=%d\n", + __func__, __LINE__, + p_tas256x->devs[i]->mn_addr, n_result); + rc |= n_result; + if (chn&channel_left) + p_tas256x->mn_err_code |= ERROR_DEVA_I2C_COMM; + if (chn&channel_right) + p_tas256x->mn_err_code |= ERROR_DEVB_I2C_COMM; + } else { + pr_debug( + "%s: %u: chn:0x%02x:BOOK:PAGE:REG 0x%02x:0x%02x:0x%02x, VAL: 0x%02x\n", + __func__, __LINE__, + p_tas256x->devs[i]->mn_addr, + TAS256X_BOOK_ID(reg), + TAS256X_PAGE_ID(reg), + TAS256X_PAGE_REG(reg), value); + if (chn&channel_left) + p_tas256x->mn_err_code &= ~ERROR_DEVA_I2C_COMM; + if (chn&channel_right) + p_tas256x->mn_err_code &= ~ERROR_DEVB_I2C_COMM; + } + } + } +end: + mutex_unlock(&p_tas256x->dev_lock); + return rc; +} + +static int tas256x_dev_bulk_write(struct tas256x_priv *p_tas256x, + enum channel chn, + unsigned int reg, unsigned char *p_data, unsigned int n_length) +{ + int n_result = 0, rc = 0; + int i = 0, chnTemp = 0; + + mutex_lock(&p_tas256x->dev_lock); + + if (chn == channel_both) { + for (i = 0; i < p_tas256x->mn_channels; i++) { + if (p_tas256x->devs[i]->spk_control == 1) + chnTemp |= 1 << i; + } + chn = (chnTemp == 0) ? chn : (enum channel)chnTemp; + } + + n_result = tas256x_change_book_page(p_tas256x, chn, + TAS256X_BOOK_ID(reg), TAS256X_PAGE_ID(reg)); + if (n_result < 0) + goto end; + + for (i = 0; i < p_tas256x->mn_channels; i++) { + if (((chn&channel_left) && (i == 0)) + || ((chn&channel_right) && (i == 1))) { + n_result = p_tas256x->plat_bulk_write(p_tas256x->platform_data, + p_tas256x->devs[i]->mn_addr, + TAS256X_PAGE_REG(reg), + p_data, n_length); + if (n_result < 0) { + pr_err( + "%s, ERROR, L=%u, chn=0x%02x: E=%d\n", + __func__, __LINE__, + p_tas256x->devs[i]->mn_addr, n_result); + rc |= n_result; + if (chn&channel_left) + p_tas256x->mn_err_code |= ERROR_DEVA_I2C_COMM; + if (chn&channel_right) + p_tas256x->mn_err_code |= ERROR_DEVB_I2C_COMM; + } else { + pr_debug( + "%s: chn%x:BOOK:PAGE:REG 0x%02x:0x%02x:0x%02x, len: %u\n", + __func__, p_tas256x->devs[i]->mn_addr, + TAS256X_BOOK_ID(reg), TAS256X_PAGE_ID(reg), + TAS256X_PAGE_REG(reg), n_length); + if (chn&channel_left) + p_tas256x->mn_err_code &= ~ERROR_DEVA_I2C_COMM; + if (chn&channel_right) + p_tas256x->mn_err_code &= ~ERROR_DEVB_I2C_COMM; + } + } + } + +end: + mutex_unlock(&p_tas256x->dev_lock); + return rc; +} + +static int tas256x_dev_bulk_read(struct tas256x_priv *p_tas256x, + enum channel chn, + unsigned int reg, unsigned char *p_data, unsigned int n_length) +{ + int n_result = 0; + int i = 0, chnTemp = 0; + + mutex_lock(&p_tas256x->dev_lock); + + if (chn == channel_both) { + for (i = 0; i < p_tas256x->mn_channels; i++) { + if (p_tas256x->devs[i]->spk_control == 1) + chnTemp |= 1 << i; + } + chn = (chnTemp == 0) ? chn : (enum channel)chnTemp; + } + + n_result = tas256x_change_book_page(p_tas256x, chn, + TAS256X_BOOK_ID(reg), TAS256X_PAGE_ID(reg)); + if (n_result < 0) + goto end; + + n_result = p_tas256x->plat_bulk_read(p_tas256x->platform_data, + p_tas256x->devs[chn >> 1]->mn_addr, TAS256X_PAGE_REG(reg), + p_data, n_length); + if (n_result < 0) { + pr_err("%s, ERROR, L=%d, E=%d\n", + __func__, __LINE__, n_result); + if (chn&channel_left) + p_tas256x->mn_err_code |= ERROR_DEVA_I2C_COMM; + if (chn&channel_right) + p_tas256x->mn_err_code |= ERROR_DEVB_I2C_COMM; + } else { + pr_debug( + "%s: chn%x:BOOK:PAGE:REG %u:%u:%u, len: 0x%02x\n", + __func__, p_tas256x->devs[chn >> 1]->mn_addr, + TAS256X_BOOK_ID(reg), TAS256X_PAGE_ID(reg), + TAS256X_PAGE_REG(reg), n_length); + if (chn&channel_left) + p_tas256x->mn_err_code &= ~ERROR_DEVA_I2C_COMM; + if (chn&channel_right) + p_tas256x->mn_err_code &= ~ERROR_DEVB_I2C_COMM; + } +end: + mutex_unlock(&p_tas256x->dev_lock); + return n_result; +} + +static int tas256x_dev_update_bits(struct tas256x_priv *p_tas256x, + enum channel chn, + unsigned int reg, unsigned int mask, unsigned int value) +{ + int n_result = 0, rc = 0; + int i = 0, chnTemp = 0; + + mutex_lock(&p_tas256x->dev_lock); + + if (chn == channel_both) { + for (i = 0; i < p_tas256x->mn_channels; i++) { + if (p_tas256x->devs[i]->spk_control == 1) + chnTemp |= 1 << i; + } + chn = (chnTemp == 0) ? chn : (enum channel)chnTemp; + } + + n_result = tas256x_change_book_page(p_tas256x, chn, + TAS256X_BOOK_ID(reg), TAS256X_PAGE_ID(reg)); + if (n_result < 0) { + rc = n_result; + goto end; + } + + for (i = 0; i < p_tas256x->mn_channels; i++) { + if (((chn&channel_left) && (i == 0)) + || ((chn&channel_right) && (i == 1))) { + n_result = p_tas256x->plat_update_bits(p_tas256x->platform_data, + p_tas256x->devs[i]->mn_addr, + TAS256X_PAGE_REG(reg), + mask, value); + if (n_result < 0) { + pr_err( + "%s, ERROR, L=%u, chn=0x%02x: E=%d\n", + __func__, __LINE__, + p_tas256x->devs[i]->mn_addr, n_result); + rc |= n_result; + p_tas256x->mn_err_code |= + (chn == channel_left) ? ERROR_DEVA_I2C_COMM : ERROR_DEVB_I2C_COMM; + } else { + pr_debug( + "%s: chn%x:BOOK:PAGE:REG 0x%02x:0x%02x:0x%02x, mask: 0x%02x, val: 0x%02x\n", + __func__, p_tas256x->devs[i]->mn_addr, + TAS256X_BOOK_ID(reg), + TAS256X_PAGE_ID(reg), + TAS256X_PAGE_REG(reg), mask, value); + p_tas256x->mn_err_code &= + (chn == channel_left) ? ~ERROR_DEVA_I2C_COMM : ~ERROR_DEVB_I2C_COMM; + } + } + } + +end: + mutex_unlock(&p_tas256x->dev_lock); + return rc; +} + +static void tas256x_hard_reset(struct tas256x_priv *p_tas256x) +{ + int i = 0; + + p_tas256x->hw_reset(p_tas256x); + + for (i = 0; i < p_tas256x->mn_channels; i++) { + p_tas256x->devs[i]->mn_current_book = -1; + p_tas256x->devs[i]->mn_current_page = -1; + } + + if (p_tas256x->mn_err_code) + pr_err("%s: before reset, ErrCode=0x%x\n", __func__, + p_tas256x->mn_err_code); + p_tas256x->mn_err_code = 0; +} + +void tas256x_failsafe(struct tas256x_priv *p_tas256x) +{ + int n_result; + + pr_err("%s\n", __func__); + p_tas256x->mn_err_code |= ERROR_FAILSAFE; + + if (p_tas256x->mn_restart < RESTART_MAX) { + p_tas256x->mn_restart++; + msleep(100); + pr_err("I2C COMM error, restart SmartAmp.\n"); + tas256x_set_power_state(p_tas256x, p_tas256x->mn_power_state); + return; + } + + n_result = tas256x_set_power_shutdown(p_tas256x, channel_both); + p_tas256x->mb_power_up = false; + p_tas256x->mn_power_state = TAS256X_POWER_SHUTDOWN; + msleep(20); + /*Mask interrupt for TDM*/ + n_result = tas256x_interrupt_enable(p_tas256x, 0/*Disable*/, + channel_both); + p_tas256x->enable_irq(p_tas256x, false); + tas256x_hard_reset(p_tas256x); + p_tas256x->write(p_tas256x, channel_both, TAS256X_SOFTWARERESET, + TAS256X_SOFTWARERESET_SOFTWARERESET_RESET); + udelay(1000); + /*pTAS256x->write(pTAS256x, channel_both, TAS256X_SPK_CTRL_REG, 0x04);*/ +} + +int tas256x_load_i2s_tdm_interface_settings(struct tas256x_priv *p_tas256x, int ch) +{ + int n_result = 0; + + /*Frame_Start Settings*/ + n_result |= tas256x_rx_set_frame_start(p_tas256x, + p_tas256x->mn_frame_start, ch); + /*RX Edge Settings*/ + n_result |= tas256x_rx_set_edge(p_tas256x, + p_tas256x->mn_rx_edge, ch); + /*RX Offset Settings*/ + n_result |= tas256x_rx_set_start_slot(p_tas256x, + p_tas256x->mn_rx_offset, ch); + /*TX Edge Settings*/ + n_result |= tas256x_tx_set_edge(p_tas256x, + p_tas256x->mn_tx_edge, ch); + /*TX Offset Settings*/ + n_result |= tas256x_tx_set_start_slot(p_tas256x, + p_tas256x->mn_tx_offset, ch); + + return n_result; +} + +int tas256x_load_init(struct tas256x_priv *p_tas256x) +{ + int ret = 0, i; + + pr_info("%s:\n", __func__); + + for (i = 0; i < p_tas256x->mn_channels; i++) { + if (p_tas256x->devs[i]->dev_ops.tas_init) + ret |= (p_tas256x->devs[i]->dev_ops.tas_init)(p_tas256x, i+1); + } + + ret |= tas256x_set_misc_config(p_tas256x, 0/*Ignored*/, channel_both); + if (ret < 0) + goto end; + ret |= tas256x_set_tx_config(p_tas256x, 0/*Ignored*/, channel_both); + if (ret < 0) + goto end; + ret |= tas256x_load_i2s_tdm_interface_settings(p_tas256x, channel_both); + if (ret < 0) + goto end; + ret |= tas256x_set_clock_config(p_tas256x, 0/*Ignored*/, channel_both); + if (ret < 0) + goto end; + + /*ICN Improve Performance*/ + ret |= tas256x_icn_config(p_tas256x, 0/*Ignored*/, channel_both); + if (ret < 0) + goto end; +#if IS_ENABLED(HPF_BYPASS) + /*Disable the HPF in Forward Path*/ + ret |= tas256x_HPF_FF_Bypass(p_tas256x, 0/*Ignored*/, channel_both); + if (ret < 0) + goto end; + /*Disable the HPF in Reverse Path*/ + ret |= tas256x_HPF_FB_Bypass(p_tas256x, 0/*Ignored*/, channel_both); + if (ret < 0) + goto end; +#endif + ret |= tas256x_set_classH_config(p_tas256x, 0/*Ignored*/, channel_both); + +end: + if (ret < 0) { + if (p_tas256x->mn_err_code & + (ERROR_DEVA_I2C_COMM | ERROR_DEVB_I2C_COMM)) + tas256x_failsafe(p_tas256x); + } + return ret; +} + +int tas256x_load_ctrl_values(struct tas256x_priv *p_tas256x, int ch) +{ + int n_result = 0; + + n_result |= tas256x_update_playback_volume(p_tas256x, + p_tas256x->devs[ch-1]->dvc_pcm, ch); + + n_result |= tas256x_update_lim_max_attenuation(p_tas256x, + p_tas256x->devs[ch-1]->lim_max_attn, ch); + + n_result |= tas256x_update_lim_max_thr(p_tas256x, + p_tas256x->devs[ch-1]->lim_thr_max, ch); + + n_result |= tas256x_update_lim_min_thr(p_tas256x, + p_tas256x->devs[ch-1]->lim_thr_min, ch); + + n_result |= tas256x_update_lim_inflection_point(p_tas256x, + p_tas256x->devs[ch-1]->lim_infl_pt, ch); + + n_result |= tas256x_update_lim_slope(p_tas256x, + p_tas256x->devs[ch-1]->lim_trk_slp, ch); + + n_result |= tas256x_update_bop_thr(p_tas256x, + p_tas256x->devs[ch-1]->bop_thd, ch); + + n_result |= tas256x_update_bosd_thr(p_tas256x, + p_tas256x->devs[ch-1]->bosd_thd, ch); + + n_result |= tas256x_update_boost_voltage(p_tas256x, + p_tas256x->devs[ch-1]->bst_vltg, ch); + + n_result |= tas256x_update_current_limit(p_tas256x, + p_tas256x->devs[ch-1]->bst_ilm, ch); + + n_result |= tas256x_update_ampoutput_level(p_tas256x, + p_tas256x->devs[ch-1]->ampoutput_lvl, ch); + + n_result |= tas256x_update_limiter_enable(p_tas256x, + p_tas256x->devs[ch-1]->lim_switch, ch); + + n_result |= tas256x_update_limiter_attack_rate(p_tas256x, + p_tas256x->devs[ch-1]->lim_att_rate, ch); + + n_result |= tas256x_update_limiter_attack_step_size(p_tas256x, + p_tas256x->devs[ch-1]->lim_att_stp_size, ch); + + n_result |= tas256x_update_limiter_release_rate(p_tas256x, + p_tas256x->devs[ch-1]->lim_rel_rate, ch); + + n_result |= tas256x_update_limiter_release_step_size(p_tas256x, + p_tas256x->devs[ch-1]->lim_rel_stp_size, ch); + + n_result |= tas256x_update_bop_enable(p_tas256x, + p_tas256x->devs[ch-1]->bop_enable, ch); + + n_result |= tas256x_update_bop_mute(p_tas256x, + p_tas256x->devs[ch-1]->bop_mute, ch); + + n_result |= tas256x_update_bop_shutdown_enable(p_tas256x, + p_tas256x->devs[ch-1]->bosd_enable, ch); + + n_result |= tas256x_update_bop_attack_rate(p_tas256x, + p_tas256x->devs[ch-1]->bop_att_rate, ch); + + n_result |= tas256x_update_bop_attack_step_size(p_tas256x, + p_tas256x->devs[ch-1]->bop_att_stp_size, ch); + + n_result |= tas256x_update_bop_hold_time(p_tas256x, + p_tas256x->devs[ch-1]->bop_hld_time, ch); + + n_result |= tas256x_update_vbat_lpf(p_tas256x, + p_tas256x->devs[ch-1]->vbat_lpf, ch); + + n_result |= tas256x_update_rx_cfg(p_tas256x, + p_tas256x->devs[ch-1]->rx_cfg, ch); + + n_result |= tas256x_update_classh_timer(p_tas256x, + p_tas256x->devs[ch-1]->classh_timer, ch); + + n_result |= tas256x_enable_reciever_mode(p_tas256x, + p_tas256x->devs[ch-1]->reciever_enable, ch); + + n_result |= tas256x_icn_disable(p_tas256x, + p_tas256x->icn_sw, ch); + + n_result |= tas256x_rx_set_slot(p_tas256x, + p_tas256x->mn_rx_slot_map[ch-1], ch); + + return n_result; +} + +void tas256x_irq_reload(struct tas256x_priv *p_tas256x) +{ + int ret = 0; + + pr_info("%s:\n", __func__); + ret |= tas256x_set_power_state(p_tas256x, p_tas256x->mn_power_state); + /* power up failed, restart later */ + if (ret < 0) { + if (p_tas256x->mn_err_code & + (ERROR_DEVA_I2C_COMM | ERROR_DEVB_I2C_COMM)) + tas256x_failsafe(p_tas256x); + } + +} + +void tas256x_load_config(struct tas256x_priv *p_tas256x) +{ + int ret = 0; + + pr_info("%s:\n", __func__); + tas256x_hard_reset(p_tas256x); + msleep(20); + + ret |= tas56x_software_reset(p_tas256x, channel_both); + if (ret < 0) + goto end; + ret |= tas256x_load_ctrl_values(p_tas256x, channel_left); + if (ret < 0) + goto end; + if (p_tas256x->mn_channels == 2) { + ret |= tas256x_load_ctrl_values(p_tas256x, channel_right); + if (ret < 0) + goto end; + } + ret |= tas256x_load_init(p_tas256x); + if (ret < 0) + goto end; + ret |= tas256x_update_rx_cfg(p_tas256x, p_tas256x->devs[0]->rx_cfg, + channel_left); + if (ret < 0) + goto end; + if (p_tas256x->mn_channels == 2) { + ret |= tas256x_update_rx_cfg(p_tas256x, p_tas256x->devs[1]->rx_cfg, + channel_right); + if (ret < 0) + goto end; + } + ret |= tas256x_iv_sense_enable_set(p_tas256x, 1, + channel_both); + if (ret < 0) + goto end; + if (p_tas256x->mn_fmt_mode == 2) { + ret |= tas256x_set_tdm_rx_slot(p_tas256x, p_tas256x->mn_slots, + p_tas256x->mn_rx_slot_width); + if (ret < 0) + goto end; + ret |= tas256x_set_tdm_tx_slot(p_tas256x, p_tas256x->mn_slots, + p_tas256x->mn_tx_slot_width); + if (ret < 0) + goto end; + } else { /*I2S Mode*/ + ret |= tas256x_set_bitwidth(p_tas256x, + p_tas256x->mn_rx_width, TAS256X_STREAM_PLAYBACK); + if (ret < 0) + goto end; + ret |= tas256x_set_bitwidth(p_tas256x, + p_tas256x->mn_rx_width, TAS256X_STREAM_CAPTURE); + if (ret < 0) + goto end; + } + + ret |= tas256x_set_samplerate(p_tas256x, p_tas256x->mn_sampling_rate, + channel_both); + if (ret < 0) + goto end; + ret |= tas256x_set_power_state(p_tas256x, p_tas256x->mn_power_state); + if (ret < 0) + goto end; +end: +/* power up failed, restart later */ + if (ret < 0) { + if (p_tas256x->mn_err_code & + (ERROR_DEVA_I2C_COMM | ERROR_DEVB_I2C_COMM)) + tas256x_failsafe(p_tas256x); + } +} + +void tas256x_reload(struct tas256x_priv *p_tas256x, int chn) +{ + int ret = 0; + /*To be used later*/ + (void)chn; + + pr_info("%s: chn %d\n", __func__, chn); + p_tas256x->enable_irq(p_tas256x, false); + + ret |= tas56x_software_reset(p_tas256x, channel_both); + if (ret < 0) + goto end; + ret |= tas256x_load_init(p_tas256x); + if (ret < 0) + goto end; + ret |= tas256x_load_ctrl_values(p_tas256x, channel_left); + if (ret < 0) + goto end; + if (p_tas256x->mn_channels == 2) { + ret |= tas256x_load_ctrl_values(p_tas256x, channel_right); + if (ret < 0) + goto end; + } + ret |= tas256x_iv_sense_enable_set(p_tas256x, 1, + channel_both); + if (ret < 0) + goto end; + ret |= tas256x_set_bitwidth(p_tas256x, + p_tas256x->mn_rx_width, TAS256X_STREAM_PLAYBACK); + if (ret < 0) + goto end; + ret |= tas256x_set_bitwidth(p_tas256x, + p_tas256x->mn_rx_width, TAS256X_STREAM_CAPTURE); + if (ret < 0) + goto end; + ret |= tas256x_set_samplerate(p_tas256x, p_tas256x->mn_sampling_rate, + channel_both); + if (ret < 0) + goto end; + ret |= tas256x_set_power_state(p_tas256x, p_tas256x->mn_power_state); + if (ret < 0) + goto end; +end: + p_tas256x->enable_irq(p_tas256x, true); +/* power up failed, restart later */ + if (ret < 0) { + if (p_tas256x->mn_err_code & + (ERROR_DEVA_I2C_COMM | ERROR_DEVB_I2C_COMM)) + tas256x_failsafe(p_tas256x); + } +} + +static int tas2558_specific(struct tas256x_priv *p_tas256x, int chn) +{ + int ret = 0; + + pr_info("%s: chn %d\n", __func__, chn); + ret = tas256x_boost_volt_update(p_tas256x, DEVICE_TAS2558, chn); + + return ret; +} + +static int tas2564_specific(struct tas256x_priv *p_tas256x, int chn) +{ + int ret = 0; + + pr_info("%s: chn %d\n", __func__, chn); + ret = tas256x_boost_volt_update(p_tas256x, DEVICE_TAS2564, chn); + + return ret; +} + +int tas256x_irq_work_func(struct tas256x_priv *p_tas256x) +{ + unsigned int nDevInt1Status = 0, nDevInt2Status = 0, + nDevInt3Status = 0, nDevInt4Status = 0; + int n_counter = 2; + int n_result = 0; + int irqreg, irqreg2, i, chnTemp = 0; + enum channel chn = channel_left; + + pr_info("%s:\n", __func__); + + p_tas256x->enable_irq(p_tas256x, false); + + if (p_tas256x->mn_err_code & ERROR_FAILSAFE) + goto reload; + + if (p_tas256x->mn_power_state == TAS256X_POWER_SHUTDOWN) { + pr_err("%s: device not powered\n", __func__); + goto end; + } + + n_result = tas256x_interrupt_enable(p_tas256x, 0/*Disable*/, + channel_both); + if (n_result < 0) + goto reload; + + /*Reset error codes*/ + p_tas256x->mn_err_code = 0; + + for (i = 0; i < p_tas256x->mn_channels; i++) { + if (p_tas256x->devs[i]->spk_control == 1) + chnTemp |= 1 << i; + } + chn = (chnTemp == 0) ? chn : (enum channel)chnTemp; + + if (chn & channel_left) { + n_result = tas256x_interrupt_read(p_tas256x, + &nDevInt1Status, &nDevInt2Status, channel_left); + if (n_result < 0) + goto reload; + p_tas256x->mn_err_code = + tas256x_interrupt_determine(p_tas256x, channel_left, + nDevInt1Status, nDevInt2Status); + } + + if (chn & channel_right) { + n_result = tas256x_interrupt_read(p_tas256x, + &nDevInt3Status, &nDevInt4Status, channel_right); + if (n_result < 0) + goto reload; + p_tas256x->mn_err_code |= + tas256x_interrupt_determine(p_tas256x, channel_right, + nDevInt3Status, nDevInt4Status); + } + + pr_err("%s: IRQ status : 0x%x, 0x%x, 0x%x, 0x%x mn_err_code %d\n", + __func__, + nDevInt1Status, nDevInt2Status, + nDevInt3Status, nDevInt4Status, + p_tas256x->mn_err_code); + + if (p_tas256x->mn_err_code) { + tas256x_irq_reload(p_tas256x); + goto end; + } else { + pr_err("%s: Power Up\n", __func__); + n_counter = 2; + while (n_counter > 0) { + if (chn & channel_left) + n_result = tas256x_power_check(p_tas256x, + &nDevInt1Status, + channel_left); + if (n_result < 0) + goto reload; + if (chn & channel_right) + n_result = tas256x_power_check(p_tas256x, + &nDevInt3Status, + channel_right); + if (n_result < 0) + goto reload; + + if (nDevInt1Status) { + /* If only left should be power on */ + if (chn == channel_left) + break; + /* If both should be power on */ + if (nDevInt3Status) + break; + } else if (chn == channel_right) { + /*If only right should be power on */ + if (nDevInt3Status) + break; + } + + tas256x_interrupt_read(p_tas256x, + &irqreg, &irqreg2, channel_both); + n_counter--; + if (n_counter > 0) { + /* in case check pow status + *just after power on TAS256x + */ + if (chn & channel_left) + pr_err("%s: PowSts A: 0x%x, check again after 10ms\n", + __func__, + nDevInt1Status); + + if (chn & channel_right) + pr_err("%s: PowSts B: 0x%x, check again after 10ms\n", + __func__, + nDevInt3Status); + + msleep(20); + } + } + + if (((!nDevInt1Status) && (chn & channel_left)) + || ((!nDevInt3Status) && (chn & channel_right))) { + if (chn & channel_left) + pr_err("%s, Critical ERROR A REG[POWERCONTROL] = 0x%x\n", + __func__, + nDevInt1Status); + + if (chn & channel_right) + pr_err("%s, Critical ERROR B REG[POWERCONTROL] = 0x%x\n", + __func__, + nDevInt3Status); + goto reload; + } + } + + n_result = tas256x_interrupt_enable(p_tas256x, 1/*Enable*/, + channel_both); + if (n_result < 0) + goto reload; + + goto end; + +reload: + /* hardware reset and reload */ + tas256x_load_config(p_tas256x); + +end: + p_tas256x->enable_irq(p_tas256x, true); + + return n_result; +} + +int tas256x_init_work_func(struct tas256x_priv *p_tas256x) +{ + int n_result = 0; + + pr_info("%s:\n", __func__); + + /* Clear latched IRQ before power on */ + n_result = tas256x_interrupt_clear(p_tas256x, channel_both); + + /*Un-Mask interrupt for TDM*/ + n_result = tas256x_interrupt_enable(p_tas256x, 1/*Enable*/, + channel_both); + + p_tas256x->enable_irq(p_tas256x, true); + + return n_result; +} + +int tas256x_dc_work_func(struct tas256x_priv *p_tas256x, int ch) +{ + int n_result = 0; + + pr_info("%s: ch %d\n", __func__, ch); + tas256x_reload(p_tas256x, ch); + + return n_result; +} + +int tas256x_register_device(struct tas256x_priv *p_tas256x) +{ + int n_result; + int i; + + pr_info("%s:\n", __func__); + p_tas256x->read = tas256x_dev_read; + p_tas256x->write = tas256x_dev_write; + p_tas256x->bulk_read = tas256x_dev_bulk_read; + p_tas256x->bulk_write = tas256x_dev_bulk_write; + p_tas256x->update_bits = tas256x_dev_update_bits; + + tas256x_hard_reset(p_tas256x); + + pr_info("Before SW reset\n"); + /* Reset the chip */ + n_result = tas56x_software_reset(p_tas256x, channel_both); + if (n_result < 0) { + pr_err("I2c fail, %d\n", n_result); + goto err; + } + + pr_info("After SW reset\n"); + + for (i = 0; i < p_tas256x->mn_channels; i++) { + n_result = tas56x_get_chipid(p_tas256x, + &(p_tas256x->devs[i]->mn_chip_id), + (i == 0) ? channel_left : channel_right); + if (n_result < 0) + goto err; + switch (p_tas256x->devs[i]->mn_chip_id) { + case 0x10: + case 0x20: + p_tas256x->devs[i]->device_id = DEVICE_TAS2562; + p_tas256x->devs[i]->dev_ops.tas_init = NULL; + break; + case 0x00: + p_tas256x->devs[i]->device_id = DEVICE_TAS2564; + p_tas256x->devs[i]->dev_ops.tas_init = + tas2564_specific; + break; + default: + p_tas256x->devs[i]->device_id = DEVICE_TAS2558; + p_tas256x->devs[i]->dev_ops.tas_init = + tas2558_specific; + break; + } + pr_info("TAS%x chip, chip_id = 0x%x", + p_tas256x->devs[i]->device_id, + p_tas256x->devs[i]->mn_chip_id); + n_result |= tas256x_set_misc_config(p_tas256x, 0, + (i == 0) ? channel_left : channel_right); + } +err: + return n_result; +} + +int tas256x_probe(struct tas256x_priv *p_tas256x) +{ + int ret = 0; +#if IS_ENABLED(CONFIG_TAS25XX_ALGO) + struct linux_platform *plat_data = + (struct linux_platform *) p_tas256x->platform_data; +#endif + + pr_info("%s:\n", __func__); + ret = tas256x_load_init(p_tas256x); + if (ret < 0) + goto end; + ret = tas256x_iv_sense_enable_set(p_tas256x, 1, channel_both); +#if IS_ENABLED(CONFIG_TAS25XX_ALGO) + if (plat_data) { + tas_smartamp_add_algo_controls(plat_data->codec, plat_data->dev, + p_tas256x->mn_channels); + /*Send IV Vbat format but don't update to algo yet*/ + tas25xx_set_iv_bit_fomat(p_tas256x->mn_iv_width, + p_tas256x->mn_vbat, 0); + } +#endif +#if IS_ENABLED(CONFIG_TAS256X_REGBIN_PARSER) + ret = tas256x_load_container(p_tas256x); + pr_info("%s Bin file loading requested: %d\n", __func__, ret); +#endif +end: + return ret; +} + +void tas256x_remove(struct tas256x_priv *p_tas256x) +{ +#if IS_ENABLED(CONFIG_TAS25XX_ALGO) + struct linux_platform *plat_data = + (struct linux_platform *) p_tas256x->platform_data; + if (plat_data) { + tas_smartamp_remove_algo_controls(plat_data->codec); + } +#else + /*Ignore argument*/ + (void)p_tas256x; +#endif +#if IS_ENABLED(CONFIG_TAS256X_REGBIN_PARSER) + tas256x_config_info_remove(p_tas256x); +#endif +} + +int tas256x_set_power_state(struct tas256x_priv *p_tas256x, + int state) +{ + int n_result = 0, i = 0, chnTemp = 0; + enum channel chn = channel_left; + + pr_info("%s: state %d\n", __func__, state); + + if ((p_tas256x->mb_mute) && (state == TAS256X_POWER_ACTIVE)) + state = TAS256X_POWER_MUTE; + + for (i = 0; i < p_tas256x->mn_channels; i++) { + if (p_tas256x->devs[i]->spk_control == 1) + chnTemp |= 1 << i; + } + chn = (chnTemp == 0) ? chn : (enum channel)chnTemp; + + switch (state) { + case TAS256X_POWER_ACTIVE: + n_result = tas256x_iv_sense_enable_set(p_tas256x, 1, chn); +#if IS_ENABLED(CONFIG_TAS25XX_CALIB_VAL_BIG) + tas25xx_send_channel_mapping(); + tas25xx_send_algo_calibration(); + tas25xx_set_iv_bit_fomat(p_tas256x->mn_iv_width, + p_tas256x->mn_vbat, 1); +#endif + /* Clear latched IRQ before power on */ + tas256x_interrupt_clear(p_tas256x, chn); + + /*Mask interrupt for TDM*/ + n_result = tas256x_interrupt_enable(p_tas256x, 0/*Disable*/, + channel_both); + +#if IS_ENABLED(CONFIG_TAS256X_REGBIN_PARSER) + /*set p_tas256x->profile_cfg_id by tinymix*/ + tas256x_select_cfg_blk(p_tas256x, + p_tas256x->profile_cfg_id, + TAS256X_BIN_BLK_PRE_POWER_UP); +#endif + n_result = tas256x_set_power_up(p_tas256x, chn); + + pr_info("%s: set ICN to -80dB\n", __func__); + n_result = tas256x_icn_data(p_tas256x, chn); +#if IS_ENABLED(CONFIG_TAS256X_REGBIN_PARSER) + /*set p_tas256x->profile_cfg_id by tinymix*/ + tas256x_select_cfg_blk(p_tas256x, + p_tas256x->profile_cfg_id, + TAS256X_BIN_BLK_POST_POWER_UP); +#endif + p_tas256x->mb_power_up = true; + p_tas256x->mn_power_state = TAS256X_POWER_ACTIVE; + p_tas256x->schedule_init_work(p_tas256x); + break; + + case TAS256X_POWER_MUTE: + n_result = tas256x_set_power_mute(p_tas256x, chn); + p_tas256x->mb_power_up = true; + p_tas256x->mn_power_state = TAS256X_POWER_MUTE; + + /*Mask interrupt for TDM*/ + n_result = tas256x_interrupt_enable(p_tas256x, 0/*Disable*/, + chn); + break; + + case TAS256X_POWER_SHUTDOWN: +#if IS_ENABLED(CONFIG_TAS256X_REGBIN_PARSER) + /*set p_tas256x->profile_cfg_id by tinymix*/ + tas256x_select_cfg_blk(p_tas256x, p_tas256x->profile_cfg_id, + TAS256X_BIN_BLK_PRE_SHUTDOWN); +#endif + for (i = 0; i < p_tas256x->mn_channels; i++) { + if (p_tas256x->devs[i]->device_id == DEVICE_TAS2564) { + if (chn & (i+1)) { + /*Mask interrupt for TDM*/ + n_result = + tas256x_interrupt_enable(p_tas256x, + 0/*Disable*/, i+1); + n_result = + tas256x_set_power_mute(p_tas256x, + i+1); + n_result = + tas256x_iv_sense_enable_set(p_tas256x, + 0, i+1); + p_tas256x->mb_power_up = false; + p_tas256x->mn_power_state = + TAS256X_POWER_SHUTDOWN; + } + } else { + if (chn & (i+1)) { + n_result = + tas256x_set_power_shutdown(p_tas256x, i+1); + n_result = + tas256x_iv_sense_enable_set(p_tas256x, 0, + i+1); + p_tas256x->mb_power_up = false; + p_tas256x->mn_power_state = + TAS256X_POWER_SHUTDOWN; + /*Mask interrupt for TDM*/ + n_result = tas256x_interrupt_enable(p_tas256x, + 0/*Disable*/, + i+1); + } + } + } + p_tas256x->enable_irq(p_tas256x, false); + /*Device Shutdown need 16ms after shutdown writes are made*/ + usleep_range(16000, 16100); + +#if IS_ENABLED(CONFIG_TAS256X_REGBIN_PARSER) + /*set p_tas256x->profile_cfg_id by tinymix*/ + tas256x_select_cfg_blk(p_tas256x, p_tas256x->profile_cfg_id, + TAS256X_BIN_BLK_POST_SHUTDOWN); +#endif +#if IS_ENABLED(CONFIG_TAS25XX_CALIB_VAL_BIG) + tas25xx_update_big_data(); +#endif +#if IS_ENABLED(CONFIG_TISA_KBIN_INTF) + tas25xx_algo_set_inactive(); +#endif + break; + default: + pr_err("wrong power state setting %d\n", + state); + } + + return n_result; +} + +int tas256x_iv_vbat_slot_config(struct tas256x_priv *p_tas256x, + int mn_slot_width) +{ + int n_result = 0; + + pr_debug("%s: mn_slot_width %d\n", __func__, mn_slot_width); + + if (p_tas256x->mn_fmt_mode == 2) { /*TDM Mode*/ + if (p_tas256x->mn_channels == 2) { + if (mn_slot_width == 16) { + if (p_tas256x->mn_vbat == 1) { + n_result |= + tas256x_set_iv_slot(p_tas256x, + channel_left, TX_SLOT1, + TX_SLOT0); + n_result |= + tas256x_set_iv_slot(p_tas256x, + channel_right, TX_SLOT5, + TX_SLOT4); + n_result |= + tas256x_set_vbat_slot(p_tas256x, + channel_left, TX_SLOT3); + n_result |= + tas256x_set_vbat_slot(p_tas256x, + channel_right, + TX_SLOT7); + } else { + n_result |= + tas256x_set_iv_slot(p_tas256x, + channel_left, TX_SLOT2, + TX_SLOT0); + n_result |= + tas256x_set_iv_slot(p_tas256x, + channel_right, TX_SLOT6, + TX_SLOT4); + } + + } else if (mn_slot_width == 24) { + n_result |= + tas256x_set_iv_slot(p_tas256x, + channel_left, TX_SLOT3, + TX_SLOT0); + n_result |= + tas256x_set_iv_slot(p_tas256x, + channel_right, TX_SLOT9, + TX_SLOT6); + if (p_tas256x->mn_vbat == 1) { + n_result |= + tas256x_set_vbat_slot(p_tas256x, + channel_left, TX_SLOT5); + n_result |= + tas256x_set_vbat_slot(p_tas256x, + channel_right, + TX_SLOTa); + } + } else { /*Assumed 32bit*/ + n_result |= + tas256x_set_iv_slot(p_tas256x, + channel_left, TX_SLOT4, + TX_SLOT0); + n_result |= tas256x_set_iv_slot(p_tas256x, + channel_right, TX_SLOTc, + TX_SLOT8); + + if (p_tas256x->mn_vbat == 1) { + n_result |= + tas256x_set_vbat_slot(p_tas256x, + channel_left, TX_SLOT6); + n_result |= + tas256x_set_vbat_slot(p_tas256x, + channel_right, + TX_SLOTe); + } + } + } else { /*Assumed Mono Channels*/ + if (mn_slot_width == 16) { + if (p_tas256x->mn_vbat == 1) { + n_result |= + tas256x_set_iv_slot(p_tas256x, + channel_left, TX_SLOT1, + TX_SLOT0); + n_result |= + tas256x_set_vbat_slot(p_tas256x, + channel_left, TX_SLOT3); + } else { + n_result |= + tas256x_set_iv_slot(p_tas256x, + channel_left, TX_SLOT2, + TX_SLOT0); + } + } else if (mn_slot_width == 24) { + n_result |= + tas256x_set_iv_slot(p_tas256x, + channel_left, TX_SLOT3, + TX_SLOT0); + if (p_tas256x->mn_vbat == 1) { + n_result |= + tas256x_set_vbat_slot(p_tas256x, + channel_left, TX_SLOT5); + } + } else { /*Assumed 32bit*/ + n_result |= + tas256x_set_iv_slot(p_tas256x, + channel_left, TX_SLOT4, + TX_SLOT0); + if (p_tas256x->mn_vbat == 1) { + n_result |= + tas256x_set_vbat_slot(p_tas256x, + channel_left, TX_SLOT6); + } + } + } + } else { /*I2S Mode*/ + if (p_tas256x->mn_channels == 2) { + if (mn_slot_width == 16) { + n_result |= tas256x_set_iv_slot(p_tas256x, + channel_left, TX_SLOT1, TX_SLOT0); + n_result |= tas256x_set_iv_slot(p_tas256x, + channel_right, TX_SLOT3, TX_SLOT2); + } else { /*16 or 32 bit*/ + if (p_tas256x->mn_iv_width == 8) { + n_result |= + tas256x_set_iv_slot(p_tas256x, + channel_left, TX_SLOT1, + TX_SLOT0); + n_result |= + tas256x_set_iv_slot(p_tas256x, + channel_right, TX_SLOT5, + TX_SLOT4); + if (p_tas256x->mn_vbat == 1) { + n_result |= + tas256x_set_vbat_slot(p_tas256x, + channel_left, TX_SLOT2); + n_result |= + tas256x_set_vbat_slot(p_tas256x, + channel_right, TX_SLOT6); + } + } else { /*p_tas256x->mn_iv_width == 16 & VBat + *cannot exist in this combination + */ + n_result |= + tas256x_set_iv_slot(p_tas256x, + channel_left, TX_SLOT2, + TX_SLOT0); + n_result |= + tas256x_set_iv_slot(p_tas256x, + channel_right, TX_SLOT6, + TX_SLOT4); + } + } + } else if ((p_tas256x->mn_channels == 1) + && (mn_slot_width == 32)) { + if (p_tas256x->mn_iv_width == 16) { + n_result |= tas256x_set_iv_slot(p_tas256x, + channel_left, TX_SLOT4, TX_SLOT0); + } else if (p_tas256x->mn_iv_width == 12) { + n_result |= tas256x_set_iv_slot(p_tas256x, + channel_left, TX_SLOT1, TX_SLOT0); + if (p_tas256x->mn_vbat == 1) + n_result |= + tas256x_set_vbat_slot(p_tas256x, + channel_left, TX_SLOT4); + } + } else if ((p_tas256x->mn_channels == 1) + && (mn_slot_width == 16)) { + if (p_tas256x->mn_iv_width == 16) { + n_result |= tas256x_set_iv_slot(p_tas256x, + channel_left, TX_SLOT2, TX_SLOT0); + } else if (p_tas256x->mn_iv_width == 12) { + n_result |= tas256x_set_iv_slot(p_tas256x, + channel_left, TX_SLOT1, TX_SLOT0); + if (p_tas256x->mn_vbat == 1) + n_result |= + tas256x_set_vbat_slot(p_tas256x, + channel_left, TX_SLOT3); + } + } else { + n_result = -1; + } + } + + if (n_result == 0) + p_tas256x->mn_tx_slot_width = mn_slot_width; + + return n_result; +} + +int tas256x_set_bitwidth(struct tas256x_priv *p_tas256x, + int bitwidth, int stream) +{ + int n_result = 0; + int slot_width_tmp = 16; + + if (bitwidth == 24) + slot_width_tmp = 32; + + pr_info("%s: bitwidth %d stream %d\n", __func__, bitwidth, stream); + + if (stream == TAS256X_STREAM_PLAYBACK) { + n_result |= tas256x_rx_set_bitwidth(p_tas256x, bitwidth, + channel_both); + n_result |= tas256x_rx_set_slot_len(p_tas256x, slot_width_tmp, + channel_both); + } else { /*stream == TAS256X_STREAM_CAPTURE*/ + n_result |= tas256x_iv_bitwidth_config(p_tas256x, + p_tas256x->mn_iv_width, channel_both); + n_result |= tas256x_iv_vbat_slot_config(p_tas256x, + slot_width_tmp); + } + + if (n_result < 0) { + if (p_tas256x->mn_err_code & + (ERROR_DEVA_I2C_COMM | ERROR_DEVB_I2C_COMM)) + tas256x_failsafe(p_tas256x); + } + + return n_result; +} + +int tas256x_set_tdm_rx_slot(struct tas256x_priv *p_tas256x, + int slots, int slot_width) +{ + int ret = -1; + int bitwidth = slot_width; + + if (((p_tas256x->mn_channels == 1) && (slots < 1)) || + ((p_tas256x->mn_channels == 2) && (slots < 2))) { + pr_err("Invalid Slots %d\n", slots); + return ret; + } + p_tas256x->mn_slots = slots; + + if ((slot_width != 16) && + (slot_width != 24) && + (slot_width != 32)) { + pr_err("Unsupported slot width %d\n", slot_width); + return ret; + } + + ret = tas256x_rx_set_slot_len(p_tas256x, slot_width, channel_both); + + switch (bitwidth) { + case 16: + ret = tas256x_rx_set_bitwidth(p_tas256x, + 16, channel_both); + break; + case 24: + case 32: + ret = tas256x_rx_set_bitwidth(p_tas256x, + 24, channel_both); + break; + default: + pr_err("Not supported params format\n"); + } + + /*Enable Auto Detect of Sample Rate */ + ret = tas256x_set_auto_detect_clock(p_tas256x, + 1, channel_both); + + /*Enable Clock Config*/ + ret = tas256x_set_clock_config(p_tas256x, 0/*Ignored*/, + channel_both); + + return ret; +} + +int tas256x_set_tdm_tx_slot(struct tas256x_priv *p_tas256x, + int slots, int slot_width) +{ + int ret = -1; + + if ((slot_width != 16) && + (slot_width != 24) && + (slot_width != 32)) { + pr_err("Unsupported slot width %d\n", slot_width); + return ret; + } + + if (((p_tas256x->mn_channels == 1) && (slots < 2)) || + ((p_tas256x->mn_channels == 2) && (slots < 4))) { + pr_err("Invalid Slots %d\n", slots); + return ret; + } + p_tas256x->mn_slots = slots; + + if (slot_width == 24) + slot_width = 32; + + ret = tas256x_iv_vbat_slot_config(p_tas256x, slot_width); + + if ((p_tas256x->mn_channels == 2) && + (p_tas256x->mn_tx_slot_width == 16)) { + if (p_tas256x->mn_vbat == 1) { + ret |= tas256x_iv_bitwidth_config(p_tas256x, 12, + channel_both); + } else { + ret |= tas256x_iv_bitwidth_config(p_tas256x, 16, + channel_both); + } + } else { + ret |= tas256x_iv_bitwidth_config(p_tas256x, 16, + channel_both); + } + + return ret; +} |