/* * Copyright (c) Hisilicon Technologies Co., Ltd.. 2019-2020. All rights reserved. * Description: amp device and driver PA RT9119 * Author: audio * Create: 2019-10-14 */ #include "osal_ext.h" #include "soc_errno.h" #include "drv_amp_debug.h" #include "drv_amp_osal.h" #include "drv_amp_common.h" #ifdef __cplusplus extern "C" { #endif #define RT9119_DEV_ID 0x20 /* Device ID for RT9119 is 0x20 */ #define RT9119_DEV_ID_REG_ADDR 0x01 /* Register address for Device ID */ #define RT9119_DEV_ID_REG_SIZE 1 /* Register size for Device ID is 1 Byte */ #define RT9119_VOL_REG_ADDR 0x07 /* Register address for Mute */ #define RT9119_VOL_REG_SIZE 2 /* Register size for Mute is 2 Bytes */ #define RT9119_TURN_OFF_VOL_H 0x07 /* Mute value set to 0x07ff */ #define RT9119_TURN_OFF_VOL_L 0xFF /* Mute value set to 0x07ff */ #define RT9119_VOL_H_BYTE 0 /* Register value for Mute contain 2 Bytes indicate High Byte */ #define RT9119_VOL_L_BYTE 1 /* Register value for Mute contain 2 Bytes indicate Low Byte */ #define RT9119_RESET_REG_ADDR 0x80 /* Register address for Soft Reset */ #define RT9119_RESET_REG_SIZE 1 /* Register size for Mute is 1 Byte */ #define RT9119_RESET_REG_VALUE 0x80 /* Reset value set to 0x80 */ #define RT9119_MAX_REG_SIZE 20 /* MAX register bytes is 20 */ #define RT9119_MAX_INIT_REG_NUM 15 /* Max registers need to configue for init */ #define RT9119_REG_SIZE_ONE_BYTE 1 #define RT9119_I2S_FMT_REG_ADDR 0x02 /* I2S Bit Resolution setting */ #define RT9119_I2S_FMT_REG_VALUE 0x06 /* I2S Bit Resolution setting 0110 : 24bits */ #define RT9119_SYS_CTL_REG_ADDR 0x05 /* Configue the system, such as CLK frequence, BTL PTL mode */ #define RT9119_SYS_CTL_REG_VALUE_BTL 0x01 /* Amp turn on (For PWM 400kHz) For BTL */ #define RT9119_SYS_CTL_REG_VALUE_PBTL 0x21 /* Amp turn on (For PWM 400kHz) For PBTL */ #define RT9119_SYS_CTL_REG_VALUE_800_KHZ 0x11 /* Amp turn on (For PWM 800kHz) */ #define RT9119_ERR_TYPE_REG_ADDR 0x06 /* Fault behavior type select */ #define RT9119_ERR_TYPE_REG_VALUE 0x08 /* Set OCP to latch mode */ #define RT9119_DC_PROT_REG_ADDR 0x10 /* DC protection function */ #define RT9119_DC_PROT_REG_VALUE 0x21 /* threshold for DC detection 18.75%, detection time 342ms, default mode */ #define RT9119_SPK_GAIN_REG_ADDR 0x0E /* Class D gain setting */ #define RT9119_INTER_PWR_CTRL_REG_ADDR 0x0F /* Mono configuration */ #define RT9119_USE_LEFT_CH 0x55 /* Mono configuration use Left channel */ #define RT9119_USE_RIGHT_CH 0xAA /* Mono configuration use Right channel */ #define RT9119_USE_LEFT_AND_RIGHT_CH 0xFF /* Mono configuration use Left and Right channel */ #define RT9119_DEPOP_DEGLITCH_REG_ADDR 0xD8 /* DE POP noise */ #define RT9119_DEPOP_DEGLITCH_VALUE 0x01 /* Disable DEPOP Function */ #define RT9119_MIX_CH1_IN_REG_ADDR 0x12 /* Input mixer gain setting Left output channel control */ #define RT9119_MIX_CH2_IN_REG_ADDR 0x13 /* Input mixer gain setting Right output channel control */ #define RT9119_MIX_CH_IN_REG_SIZE 8 /* Input Mixer Gain Setting register bytes */ #define RT9119_I2C_RETRY_TIMES 3 #define RT9119_I2C_RETRY_PRINT ((RT9119_I2C_RETRY_TIMES) + 1) #define RT9119_SHORT_WAIT_INTERVAL 1 /* 1ms waiting time */ #define RT9119_MEDIUM_WAIT_INTERVAL 10 /* Sleep 10ms */ #define RT9119_SOFT_RESET_WAIT_INTERVAL 10 /* Soft reset waiting time is 10ms */ typedef enum { INVALID_COUNT_RT9119 = 0, OSCA_COUNT_RT9119 = 1, /* OSCA only has 1 PA */ HEGEL_COUNT_RT9119 = 4, /* PA Numbers for HEGEL and PLATO are 4 */ PLAT_COUNT_RT9119 = 4, FREG_COUNT_RT9119 = 6, MAX_COUNT_RT9119 } rt9119_pa_num; /* Index for RT9119, max number now is HEGEL_COUNT_RT9119 */ typedef enum { RT9119_DEF_PA0 = 0, RT9119_EXT_PA1 = 1, RT9119_EXT_PA2 = 2, RT9119_EXT_PA3 = 3, RT9119_EXT_PA4 = 4, RT9119_EXT_PA5 = 5, RT9119_PA_MAX } rt9119_num_index; /* Turn On value set */ typedef enum { RT9119_PA1_TURN_ON_VOL_H = 0x00, /* 24dB - (Dec * 0.0625), default: 12dB = 0xC0 = 192 */ RT9119_PA2_TURN_ON_VOL_H = 0x00, RT9119_PA3_TURN_ON_VOL_H = 0x00, RT9119_PA4_TURN_ON_VOL_H = 0x00, RT9119_PA1_TURN_ON_VOL_L = 0xC0, RT9119_PA2_TURN_ON_VOL_L = 0xC0, RT9119_PA3_TURN_ON_VOL_L = 0xC0, RT9119_PA4_TURN_ON_VOL_L = 0xC0, } rt9119_vol_gain; /* Class D output gain */ typedef enum { RT9119_PA1_SPK_GAIN_VALUE = 0x01, RT9119_PA2_SPK_GAIN_VALUE = 0x01, RT9119_PA3_SPK_GAIN_VALUE = 0x01, RT9119_PA4_SPK_GAIN_VALUE = 0x01, RT9119_PA5_SPK_GAIN_VALUE = 0x01, RT9119_PA6_SPK_GAIN_VALUE = 0x01, } rt9119_spk_gain; /* !!! NOTES: if you want add Register table must change RT9119_MAX_INIT_REG_NUM !!! */ static drv_amp_reg_map g_rt9119_init_reg[RT9119_PA_MAX][RT9119_MAX_INIT_REG_NUM] = { /* ---Addr--- ---length--- ---Value--- PA1 default Register table */ { { RT9119_I2S_FMT_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_I2S_FMT_REG_VALUE } }, { RT9119_SPK_GAIN_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_PA1_SPK_GAIN_VALUE } }, { RT9119_DEPOP_DEGLITCH_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_DEPOP_DEGLITCH_VALUE } }, { RT9119_DC_PROT_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_DC_PROT_REG_VALUE } }, { RT9119_ERR_TYPE_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_ERR_TYPE_REG_VALUE } }, { RT9119_VOL_REG_ADDR, RT9119_VOL_REG_SIZE, { RT9119_PA1_TURN_ON_VOL_H, RT9119_PA1_TURN_ON_VOL_L } }, { RT9119_SYS_CTL_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_SYS_CTL_REG_VALUE_BTL } }, { ENDTBL_FLAG, RT9119_REG_SIZE_ONE_BYTE, { 0x00 } } }, /* End of PA1 */ /* ---Addr--- ---length--- ---Value--- PA2 default Register table */ { { RT9119_I2S_FMT_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_I2S_FMT_REG_VALUE } }, { RT9119_SPK_GAIN_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_PA2_SPK_GAIN_VALUE } }, { RT9119_DEPOP_DEGLITCH_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_DEPOP_DEGLITCH_VALUE } }, { RT9119_DC_PROT_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_DC_PROT_REG_VALUE } }, { RT9119_ERR_TYPE_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_ERR_TYPE_REG_VALUE } }, { RT9119_VOL_REG_ADDR, RT9119_VOL_REG_SIZE, { RT9119_PA2_TURN_ON_VOL_H, RT9119_PA2_TURN_ON_VOL_L } }, { RT9119_SYS_CTL_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_SYS_CTL_REG_VALUE_BTL } }, { ENDTBL_FLAG, RT9119_REG_SIZE_ONE_BYTE, { 0x00 } } }, /* End of PA2 */ /* ---Addr--- ---length--- ---Value--- PA3 default Register table */ { { RT9119_I2S_FMT_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_I2S_FMT_REG_VALUE } }, { RT9119_SPK_GAIN_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_PA3_SPK_GAIN_VALUE } }, { RT9119_DEPOP_DEGLITCH_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_DEPOP_DEGLITCH_VALUE } }, { RT9119_DC_PROT_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_DC_PROT_REG_VALUE } }, { RT9119_ERR_TYPE_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_ERR_TYPE_REG_VALUE } }, { RT9119_VOL_REG_ADDR, RT9119_VOL_REG_SIZE, { RT9119_PA3_TURN_ON_VOL_H, RT9119_PA3_TURN_ON_VOL_L } }, { RT9119_SYS_CTL_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_SYS_CTL_REG_VALUE_BTL } }, { ENDTBL_FLAG, RT9119_REG_SIZE_ONE_BYTE, { 0x00 } } }, /* End of PA3 */ /* ---Addr--- ---length--- ---Value--- PA4 default Register table */ { { RT9119_I2S_FMT_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_I2S_FMT_REG_VALUE } }, { RT9119_SPK_GAIN_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_PA4_SPK_GAIN_VALUE } }, { RT9119_DEPOP_DEGLITCH_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_DEPOP_DEGLITCH_VALUE } }, { RT9119_DC_PROT_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_DC_PROT_REG_VALUE } }, { RT9119_ERR_TYPE_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_ERR_TYPE_REG_VALUE } }, { RT9119_VOL_REG_ADDR, RT9119_VOL_REG_SIZE, { RT9119_PA4_TURN_ON_VOL_H, RT9119_PA4_TURN_ON_VOL_L } }, { RT9119_SYS_CTL_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_SYS_CTL_REG_VALUE_BTL } }, { ENDTBL_FLAG, RT9119_REG_SIZE_ONE_BYTE, { 0x00 } } }, /* End of PA4 */ /* ---Addr--- ---length--- ---Value--- PA5 default Register table */ { { RT9119_I2S_FMT_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_I2S_FMT_REG_VALUE } }, { RT9119_SPK_GAIN_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_PA3_SPK_GAIN_VALUE } }, { RT9119_DEPOP_DEGLITCH_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_DEPOP_DEGLITCH_VALUE } }, { RT9119_DC_PROT_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_DC_PROT_REG_VALUE } }, { RT9119_ERR_TYPE_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_ERR_TYPE_REG_VALUE } }, { RT9119_VOL_REG_ADDR, RT9119_VOL_REG_SIZE, { RT9119_PA3_TURN_ON_VOL_H, RT9119_PA3_TURN_ON_VOL_L } }, { RT9119_SYS_CTL_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_SYS_CTL_REG_VALUE_BTL } }, { ENDTBL_FLAG, RT9119_REG_SIZE_ONE_BYTE, { 0x00 } } }, /* End of PA5 */ /* ---Addr--- ---length--- ---Value--- PA6 default Register table */ { { RT9119_I2S_FMT_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_I2S_FMT_REG_VALUE } }, { RT9119_SPK_GAIN_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_PA4_SPK_GAIN_VALUE } }, { RT9119_DEPOP_DEGLITCH_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_DEPOP_DEGLITCH_VALUE } }, { RT9119_DC_PROT_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_DC_PROT_REG_VALUE } }, { RT9119_ERR_TYPE_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_ERR_TYPE_REG_VALUE } }, { RT9119_VOL_REG_ADDR, RT9119_VOL_REG_SIZE, { RT9119_PA4_TURN_ON_VOL_H, RT9119_PA4_TURN_ON_VOL_L } }, { RT9119_SYS_CTL_REG_ADDR, RT9119_REG_SIZE_ONE_BYTE, { RT9119_SYS_CTL_REG_VALUE_BTL } }, { ENDTBL_FLAG, RT9119_REG_SIZE_ONE_BYTE, { 0x00 } } } /* End of PA6 */ }; static td_s32 rt9119_get_mute(const amp_platform_device *dev, amp_channel_type channel_type, td_bool *mute) { td_s32 ret; td_u8 vol[RT9119_VOL_REG_SIZE] = {0}; if (mute == TD_NULL) { return SOC_ERR_AMP_NULL_PTR; } ret = amp_osal_i2c_read(&dev->i2c, RT9119_VOL_REG_ADDR, vol, RT9119_VOL_REG_SIZE); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(amp_osal_i2c_read, ret); return ret; } if (channel_type == AMP_CHANNEL_TYPE_ALL) { if ((vol[RT9119_VOL_H_BYTE] == RT9119_TURN_OFF_VOL_H) && (vol[RT9119_VOL_L_BYTE] == RT9119_TURN_OFF_VOL_L)) { *mute = TD_TRUE; } else { *mute = TD_FALSE; } } else { /* need add by custom */ } return TD_SUCCESS; } static td_s32 rt9119_set_mute(const amp_platform_device *dev, amp_channel_type channel_type, td_bool mute) { td_s32 ret; const td_u8 vol_mute[RT9119_VOL_REG_SIZE] = { RT9119_TURN_OFF_VOL_H, RT9119_TURN_OFF_VOL_L, }; const td_u8 vol_unmute_pa_123[RT9119_VOL_REG_SIZE] = { RT9119_PA1_TURN_ON_VOL_H, RT9119_PA1_TURN_ON_VOL_L, }; const td_u8 vol_unmute_pa_4[RT9119_VOL_REG_SIZE] = { RT9119_PA4_TURN_ON_VOL_H, RT9119_PA4_TURN_ON_VOL_L, }; const td_u8 *vol_unmute = (dev->dev_id == RT9119_EXT_PA3) ? vol_unmute_pa_4 : vol_unmute_pa_123; const td_u8 *vol = (mute == TD_TRUE) ? vol_mute : vol_unmute; if (channel_type != AMP_CHANNEL_TYPE_ALL) { /* need custom add */ } ret = amp_osal_i2c_write(&dev->i2c, RT9119_VOL_REG_ADDR, vol, RT9119_VOL_REG_SIZE); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(amp_osal_i2c_write, ret); return ret; } return TD_SUCCESS; } static td_s32 rt9119_check_status(const amp_platform_device *dev) { td_s32 ret; td_u8 dev_id = 0; ret = amp_osal_i2c_read(&dev->i2c, RT9119_DEV_ID_REG_ADDR, &dev_id, RT9119_DEV_ID_REG_SIZE); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(amp_osal_i2c_read, ret); return ret; } if (dev_id != RT9119_DEV_ID) { soc_warn_print_h32(dev_id); return TD_FAILURE; } return TD_SUCCESS; } static td_void rt9119_write_reg_map(const amp_platform_device *dev, const drv_amp_reg_map *reg_map) { td_s32 ret; td_u32 addr; td_u32 size; const td_u8 *reg = TD_NULL; while (1) { if ((reg_map == TD_NULL) || (reg_map->addr == ENDTBL_FLAG)) { return; } addr = reg_map->addr; reg = reg_map->reg; size = reg_map->size; ret = amp_osal_i2c_write(&dev->i2c, addr, reg, size); if (ret != TD_SUCCESS) { soc_log_err("addr(%x), reg(%p), size(%d)\n", addr, reg, size); soc_err_print_call_fun_err(amp_osal_i2c_write, ret); return; } if (addr == RT9119_I2S_FMT_REG_ADDR) { osal_msleep(RT9119_MEDIUM_WAIT_INTERVAL); } reg_map++; } } static td_s32 rt9119_reg_init(const amp_platform_device *dev) { td_s32 ret; drv_amp_reg_map *reg_map = TD_NULL; if (dev->dev_id >= MAX_COUNT_RT9119) { soc_log_err("dev_id:%d max:%d \n", dev->dev_id, MAX_COUNT_RT9119); return SOC_ERR_AMP_INVALID_PARA; } ret = rt9119_check_status(dev); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(rt9119_check_status, ret); return ret; } reg_map = &(g_rt9119_init_reg[dev->dev_id][0]); rt9119_write_reg_map(dev, reg_map); return TD_SUCCESS; } static td_s32 rt9119_init(const amp_platform_device *dev) { td_s32 ret; if ((dev->mute_gpio_config == TD_FALSE) || (dev->reset_gpio_config == TD_FALSE)) { drv_amp_dev_hw_mute(dev, TD_TRUE); osal_msleep(RT9119_MEDIUM_WAIT_INTERVAL); drv_amp_dev_hw_reset(dev, TD_TRUE); osal_msleep(RT9119_MEDIUM_WAIT_INTERVAL); drv_amp_dev_hw_reset(dev, TD_FALSE); osal_msleep(RT9119_MEDIUM_WAIT_INTERVAL); drv_amp_dev_hw_mute(dev, TD_FALSE); } ret = rt9119_reg_init(dev); if (ret != TD_SUCCESS) { soc_log_err("dev_id: %d\n", dev->dev_id); soc_err_print_call_fun_err(rt9119_reg_init, ret); return ret; } return TD_SUCCESS; } static td_void rt9119_deinit(const amp_platform_device *dev) { drv_amp_dev_hw_mute(dev, TD_TRUE); drv_amp_dev_hw_reset(dev, TD_TRUE); } static td_void rt9119_soft_reset(const amp_platform_device *dev, td_bool reset) { td_s32 ret; td_u8 reset_value = RT9119_RESET_REG_VALUE; if (reset == TD_FALSE) { return; } ret = amp_osal_i2c_write(&dev->i2c, RT9119_RESET_REG_ADDR, &reset_value, RT9119_RESET_REG_SIZE); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(amp_osal_i2c_write, ret); return; } osal_msleep(RT9119_SOFT_RESET_WAIT_INTERVAL); } static td_void rt9119_dump_reg(const amp_platform_device *dev, td_void *file) { if (dev->dev_id >= RT9119_PA_MAX) { soc_err_print_u32(dev->dev_id); return; } drv_amp_dev_dump_reg_map(dev, file, &(g_rt9119_init_reg[dev->dev_id][0])); } static td_s32 rt9119_get_active(const amp_platform_device *dev, td_bool *active) { if (active == TD_NULL) { return SOC_ERR_AMP_NULL_PTR; } if (dev->dev_id >= RT9119_PA_MAX) { soc_err_print_u32(dev->dev_id); return SOC_ERR_AMP_NULL_PTR; } *active = TD_TRUE; return TD_SUCCESS; } static amp_platform_driver g_rt9119_driver = { .name = "RT9119", .dev_type = AMP_DEV_RT9119, .deinit = rt9119_deinit, .init = rt9119_init, .get_mute = rt9119_get_mute, .set_mute = rt9119_set_mute, .hw_mute = drv_amp_dev_hw_mute, .reset = rt9119_soft_reset, .get_active = rt9119_get_active, .dump_reg = rt9119_dump_reg, }; td_s32 rt9119_register_driver(td_void) { return amp_platform_driver_register(&g_rt9119_driver); } #ifdef __cplusplus } #endif /* __cplusplus */