You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

396 lines
16 KiB

/*
* 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 */