285 lines
7.5 KiB
C
285 lines
7.5 KiB
C
/*
|
|
* Copyright (c) CompanyNameMagicTag 2023-2023. All rights reserved.
|
|
* Description: source file for aw88166 driver
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include "soc_osal.h"
|
|
#include "audio_debug.h"
|
|
#include "gpio.h"
|
|
#include "hal_gpio.h"
|
|
#include "i2c.h"
|
|
#include "pinctrl.h"
|
|
#include "vendor_common.h"
|
|
#include "soc_uapi_vendor.h"
|
|
|
|
#include "aw883xx_init.h"
|
|
#include "aw883xx.h"
|
|
#include "aw_params.h"
|
|
|
|
static td_bool g_aw88166_i2c_inited = TD_FALSE;
|
|
|
|
#if defined(TJD_BOARD_ENABLE)
|
|
#define AW88166_PWR_ON_PIN S_AGPIO_L25
|
|
#define AW88166_I2C_BUS_ID I2C_BUS_3
|
|
#define AW88166_I2C_DEV_ADDR 0x34
|
|
#else
|
|
#define AW88166_PWR_ON_PIN S_MGPIO4
|
|
#define AW88166_I2C_BUS_ID I2C_BUS_0
|
|
#define AW88166_I2C_DEV_ADDR 0x34
|
|
#endif
|
|
|
|
static td_s32 aw_dev0_i2c_write_func(td_u16 dev_addr, td_u8 reg_addr, td_u8 *pdata, td_u16 len)
|
|
{
|
|
td_s32 ret;
|
|
i2c_data_t data;
|
|
const td_u8 reg_addr_len = sizeof(reg_addr); /* data len of reg_addr */
|
|
const td_u8 send_len = len + reg_addr_len; /* pdata bytes && reg_addr len */
|
|
td_u8 *send_data = osal_kmalloc_align(send_len, 0, 8); /* 8 : Align up to 8 bytes */
|
|
|
|
if (send_data == TD_NULL) {
|
|
ret = -1; /* -1:FAILED ERR CODE */
|
|
vendor_log_fun_err(malloc, ret);
|
|
return ret;
|
|
}
|
|
|
|
/* pack reg addr & reg data */
|
|
*send_data = reg_addr; /* reg_addr */
|
|
ret = memcpy_s(send_data + reg_addr_len, (send_len - reg_addr_len), pdata, len); /* pdata */
|
|
if (ret != EOK) {
|
|
vendor_log_fun_err(memcpy_s, ret);
|
|
goto out;
|
|
}
|
|
|
|
data.send_buf = send_data;
|
|
data.send_len = send_len;
|
|
data.receive_buf = NULL;
|
|
data.receive_len = 0;
|
|
ret = (td_s32)uapi_i2c_master_write(AW88166_I2C_BUS_ID, dev_addr, &data);
|
|
if (ret != ERRCODE_SUCC) {
|
|
vendor_log_fun_err(uapi_i2c_master_write, ret);
|
|
goto out;
|
|
}
|
|
|
|
out:
|
|
if (send_data != TD_NULL) {
|
|
osal_kfree(send_data);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static td_s32 aw_dev0_i2c_read_func(td_u16 dev_addr, td_u8 reg_addr, td_u8 *pdata, td_u16 len)
|
|
{
|
|
td_s32 ret;
|
|
|
|
i2c_data_t data;
|
|
|
|
data.send_buf = ®_addr;
|
|
data.send_len = sizeof(reg_addr);
|
|
data.receive_buf = pdata;
|
|
data.receive_len = len;
|
|
ret = (td_s32)uapi_i2c_master_writeread(AW88166_I2C_BUS_ID, dev_addr, &data);
|
|
if (ret != ERRCODE_SUCC) {
|
|
vendor_log_fun_err(uapi_i2c_master_writeread, ret);
|
|
return ret;
|
|
}
|
|
|
|
return AUDIO_SUCCESS;
|
|
}
|
|
|
|
static td_void aw_dev0_reset_gpio_ctl(bool state)
|
|
{
|
|
uapi_gpio_set_val(AW88166_PWR_ON_PIN, state);
|
|
}
|
|
|
|
static td_void aw88166_pwr_on_pin_init(td_void)
|
|
{
|
|
uapi_gpio_set_dir(AW88166_PWR_ON_PIN, GPIO_DIRECTION_OUTPUT);
|
|
}
|
|
|
|
static td_s32 aw88166_i2c_init(td_void)
|
|
{
|
|
td_s32 ret;
|
|
audio_func_enter();
|
|
|
|
/* init i2c */
|
|
vendor_trace_log_u32(AW88166_I2C_BUS_ID);
|
|
ret = (td_s32)uapi_i2c_master_init(AW88166_I2C_BUS_ID, I2C_BAUDRATE, I2C_HIGH_SPEED_CODE);
|
|
if (ret != AUDIO_SUCCESS) {
|
|
vendor_log_fun_err(uapi_i2c_master_init, ret);
|
|
return ret;
|
|
}
|
|
|
|
vendor_printf("aw88166 i2c init success\n");
|
|
audio_func_exit();
|
|
return AUDIO_SUCCESS;
|
|
}
|
|
|
|
static td_s32 aw88166_i2c_deinit(td_void)
|
|
{
|
|
td_s32 ret;
|
|
audio_func_enter();
|
|
|
|
/* deinit i2c */
|
|
vendor_trace_log_u32(AW88166_I2C_BUS_ID);
|
|
ret = (td_s32)uapi_i2c_deinit(AW88166_I2C_BUS_ID);
|
|
if (ret != AUDIO_SUCCESS) {
|
|
vendor_log_fun_err(uapi_i2c_deinit, ret);
|
|
return ret;
|
|
}
|
|
|
|
vendor_printf("aw88166 i2c deinit success\n");
|
|
audio_func_exit();
|
|
return AUDIO_SUCCESS;
|
|
}
|
|
|
|
td_s32 aw883xx_pid_2066_dev_init(td_void *aw883xx);
|
|
|
|
struct aw_init_info init_info[] = {
|
|
{
|
|
.dev = AW_DEV_0,
|
|
.i2c_addr = AW88166_I2C_DEV_ADDR,
|
|
.re_min = 2000, /* awinic:If the re_min(ohms) and re_max(ohms) are not set, the default value is used */
|
|
.re_max = 39000,
|
|
.mix_chip_count = AW_DEV0_MIX_CHIP_NUM,
|
|
.prof_info = g_dev0_prof_info,
|
|
.i2c_read_func = aw_dev0_i2c_read_func,
|
|
.i2c_write_func = aw_dev0_i2c_write_func,
|
|
.reset_gpio_ctl = aw_dev0_reset_gpio_ctl,
|
|
.dev_init_ops = {aw883xx_pid_2066_dev_init},
|
|
}
|
|
};
|
|
|
|
static td_s32 audio_aw88166_configuration(const uapi_vendor_codec_attr *attr)
|
|
{
|
|
td_s32 ret;
|
|
|
|
/* awinic:Control interface of dev0 */
|
|
/* awinic:initialization */
|
|
ret = aw883xx_smartpa_init((td_void *)&init_info[AW_DEV_0]);
|
|
if (ret != AUDIO_SUCCESS) {
|
|
vendor_printf("aw883xx_smartpa_init already init\n");
|
|
}
|
|
/* awinic:set mode "Music", "aw_params.h" contains id information */
|
|
ret = aw883xx_set_profile_byname(AW_DEV_0, "Music");
|
|
if (ret != AUDIO_SUCCESS) {
|
|
vendor_log_fun_err(aw883xx_set_profile_byname, ret);
|
|
}
|
|
|
|
vendor_unused(attr);
|
|
return ret;
|
|
}
|
|
|
|
static td_s32 audio_aw88166_deconfiguration(td_void)
|
|
{
|
|
/* awinic:Free the requested memory when PA is not used */
|
|
aw883xx_smartpa_deinit(AW_DEV_0);
|
|
|
|
return AUDIO_SUCCESS;
|
|
}
|
|
|
|
td_s32 audio_aw88166_init(const uapi_vendor_codec_attr *attr)
|
|
{
|
|
td_s32 ret;
|
|
|
|
audio_func_enter();
|
|
|
|
aw88166_pwr_on_pin_init();
|
|
|
|
if (g_aw88166_i2c_inited != TD_TRUE) {
|
|
ret = aw88166_i2c_init();
|
|
if (ret != AUDIO_SUCCESS) {
|
|
vendor_log_fun_err(aw88166_i2c_init, ret);
|
|
return ret;
|
|
}
|
|
g_aw88166_i2c_inited = TD_TRUE;
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
|
|
ret = audio_aw88166_configuration(attr);
|
|
if (ret != AUDIO_SUCCESS) {
|
|
vendor_log_fun_err(audio_aw88166_configuration, ret);
|
|
}
|
|
|
|
return AUDIO_SUCCESS;
|
|
}
|
|
|
|
td_s32 audio_aw88166_deinit(td_void)
|
|
{
|
|
td_s32 ret;
|
|
audio_func_enter();
|
|
|
|
ret = audio_aw88166_deconfiguration();
|
|
if (ret != AUDIO_SUCCESS) {
|
|
vendor_log_fun_err(audio_aw88166_deconfiguration, ret);
|
|
}
|
|
|
|
if (g_aw88166_i2c_inited != TD_FALSE) {
|
|
ret = aw88166_i2c_deinit();
|
|
if (ret != AUDIO_SUCCESS) {
|
|
vendor_log_fun_err(aw88166_i2c_deinit, ret);
|
|
return ret;
|
|
}
|
|
g_aw88166_i2c_inited = TD_FALSE;
|
|
} else {
|
|
ret = AUDIO_SUCCESS;
|
|
}
|
|
|
|
audio_func_exit();
|
|
return ret;
|
|
}
|
|
|
|
td_s32 audio_aw88166_start(const uapi_vendor_codec_attr *attr)
|
|
{
|
|
td_s32 ret;
|
|
|
|
audio_func_enter();
|
|
|
|
/* awinic:The platform needs to output I2s first, and then ctl start */
|
|
ret = aw883xx_ctrl_state(AW_DEV_0, AW_START);
|
|
if (ret != AUDIO_SUCCESS) {
|
|
vendor_log_fun_err(aw883xx_ctrl_state, ret);
|
|
}
|
|
|
|
vendor_unused(attr);
|
|
return ret;
|
|
}
|
|
|
|
td_s32 audio_aw88166_stop(td_void)
|
|
{
|
|
td_s32 ret;
|
|
audio_func_enter();
|
|
|
|
/* awinic:The platform needs to control the stop first and then stop I2S */
|
|
ret = aw883xx_ctrl_state(AW_DEV_0, AW_STOP);
|
|
if (ret != AUDIO_SUCCESS) {
|
|
vendor_log_fun_err(aw883xx_ctrl_state, ret);
|
|
}
|
|
audio_func_exit();
|
|
return ret;
|
|
}
|
|
|
|
td_s32 audio_aw88166_set_aef_profile(uapi_snd_aef_profile aef_profile)
|
|
{
|
|
td_s32 ret;
|
|
|
|
audio_func_enter();
|
|
|
|
/* awinic:set mode "Receiver"/"Music", "aw_params.h" contains id information */
|
|
if (aef_profile == UAPI_SND_AEF_PROFILE_VOIP) {
|
|
/* awinic:set mode "Receiver" */
|
|
ret = aw883xx_set_profile_byname(AW_DEV_0, "Receiver");
|
|
} else {
|
|
/* awinic:set mode "Music" */
|
|
ret = aw883xx_set_profile_byname(AW_DEV_0, "Music");
|
|
}
|
|
|
|
if (ret != AUDIO_SUCCESS) {
|
|
vendor_log_fun_err(aw883xx_set_profile_byname, ret);
|
|
}
|
|
|
|
audio_func_exit();
|
|
return ret;
|
|
}
|