2342 lines
62 KiB
C
2342 lines
62 KiB
C
/*
|
|
* aw883xx_device.c aw883xx codec driver
|
|
*
|
|
* Copyright (c) 2021 AWINIC Technology CO., LTD
|
|
*
|
|
* Author: <zhaolei@awinic.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
* option) any later version.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
|
|
#include "aw883xx_base.h"
|
|
#include "aw883xx_device.h"
|
|
#include "aw_profile_process.h"
|
|
|
|
#define AW_DEV_SYSST_CHECK_MAX (10)
|
|
|
|
static unsigned int g_fade_in_time = AW_1_MS;
|
|
static unsigned int g_fade_out_time = AW_1_MS;
|
|
|
|
|
|
#ifdef AW_MONITOR
|
|
extern int aw883xx_monitor_init(void *dev);
|
|
extern void aw883xx_monitor_start(void *dev);
|
|
extern void aw883xx_monitor_stop(void *dev);
|
|
extern void aw883xx_monitor_deinit(void *dev);
|
|
extern int aw883xx_monitor_work_func(void *dev);
|
|
extern void aw883xx_monitor_set_handle(void *dev);
|
|
extern void aw883xx_monitor_update_st(void *dev, monitor_update_t type);
|
|
|
|
void aw883xx_dev_get_monitor_func(struct aw_device *aw_dev)
|
|
{
|
|
aw_dev->ops.aw_monitor_init = aw883xx_monitor_init;
|
|
aw_dev->ops.aw_monitor_start = aw883xx_monitor_start;
|
|
aw_dev->ops.aw_monitor_stop = aw883xx_monitor_stop;
|
|
aw_dev->ops.aw_monitor_deinit = aw883xx_monitor_deinit;
|
|
aw_dev->ops.aw_monitor_work_func = aw883xx_monitor_work_func;
|
|
aw_dev->ops.aw_monitor_set_handle = aw883xx_monitor_set_handle;
|
|
}
|
|
|
|
#else
|
|
void aw883xx_dev_get_monitor_func(struct aw_device *aw_dev)
|
|
{
|
|
aw_dev->ops.aw_monitor_init = NULL;
|
|
aw_dev->ops.aw_monitor_start = NULL;
|
|
aw_dev->ops.aw_monitor_stop = NULL;
|
|
aw_dev->ops.aw_monitor_deinit = NULL;
|
|
aw_dev->ops.aw_monitor_work_func = NULL;
|
|
aw_dev->ops.aw_monitor_work_func = NULL;
|
|
aw_dev->ops.aw_monitor_set_handle = NULL;
|
|
}
|
|
#endif
|
|
|
|
|
|
int aw883xx_dev_check_prof(uint32_t dev, struct aw_prof_info *prof_info)
|
|
{
|
|
struct aw_prof_desc *prof_desc = NULL;
|
|
int i = 0;
|
|
int j = 0;
|
|
|
|
if (prof_info == NULL) {
|
|
aw_dev_err(dev, "prof_info is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (prof_info->count <= 0) {
|
|
aw_dev_err(dev, "prof count :%d unsupported", prof_info->count);
|
|
return -EINVAL;
|
|
}
|
|
|
|
prof_desc = prof_info->prof_desc;
|
|
for (i = 0; i < prof_info->count; i++) {
|
|
if (prof_desc == NULL) {
|
|
aw_dev_err(dev, "invalid prof_desc");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (prof_desc->sec_desc->len <= 0) {
|
|
aw_dev_err(dev, "prof len:%d unsupported", prof_desc->sec_desc->len);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (prof_desc->sec_desc->data == NULL) {
|
|
aw_dev_err(dev, "prof data is NULL");
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
|
|
for (i = 0; i < prof_info->count; i++) {
|
|
for (j = i + 1; j < prof_info->count; j++) {
|
|
if (strncmp(prof_info->prof_desc[i].name, prof_info->prof_desc[j].name, AW_PROF_NAME_MAX) == 0) {
|
|
aw_dev_err(dev, "prof_desc pos[%d] and prof_desc pos[%d] conflict with prof_name[%s]",
|
|
i, j, prof_info->prof_desc[j].name);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
aw_dev_info(dev, "aw_dev_check_prof success");
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct aw_sec_data_desc *aw883xx_dev_get_prof_data_byname(struct aw_device *aw_dev, char *prof_name, int data_type)
|
|
{
|
|
struct aw_sec_data_desc *sec_data = NULL;
|
|
struct aw_prof_desc *prof_desc = NULL;
|
|
struct aw_prof_info *prof_info = aw_dev->prof_info;
|
|
int i = 0;
|
|
|
|
if (data_type >= AW_DATA_TYPE_MAX) {
|
|
aw_dev_err(aw_dev->dev, "unsupport data type id [%d]", data_type);
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < prof_info->count; i++) {
|
|
if (strncmp(prof_name, prof_info->prof_desc[i].name, AW_PROF_NAME_MAX) == 0) {
|
|
prof_desc = &aw_dev->prof_info->prof_desc[i];
|
|
sec_data = &prof_desc->sec_desc[data_type];
|
|
aw_dev_dbg(aw_dev->dev, "get prof[%s] data len[%d]",
|
|
prof_desc->name, sec_data->len);
|
|
return sec_data;
|
|
}
|
|
}
|
|
|
|
aw_dev_err(aw_dev->dev, "not found prof_name[%s]", prof_name);
|
|
return NULL;
|
|
}
|
|
|
|
static int aw_dev_check_profile_name(struct aw_device *aw_dev, const char *prof_name)
|
|
{
|
|
int i =0;
|
|
struct aw_prof_info *prof_info = aw_dev->prof_info;
|
|
|
|
for (i = 0; i < prof_info->count; i++) {
|
|
if (strncmp(prof_name, prof_info->prof_desc[i].name, AW_PROF_NAME_MAX) == 0){
|
|
return 0;
|
|
}
|
|
}
|
|
aw_dev_err(aw_dev->dev, "not found prof_name[%s]", prof_name);
|
|
return -EINVAL;
|
|
}
|
|
|
|
int aw883xx_dev_set_profile_name(struct aw_device *aw_dev, const char *prof_name)
|
|
{
|
|
if (aw_dev_check_profile_name(aw_dev, prof_name)) {
|
|
return -EINVAL;
|
|
} else {
|
|
strncpy(aw_dev->set_prof_name, prof_name, AW_PROF_NAME_MAX - 1);
|
|
aw_dev_info(aw_dev->dev, "set prof_name[%s]", aw_dev->set_prof_name);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
char *aw883xx_dev_get_profile_name(struct aw_device *aw_dev)
|
|
{
|
|
return aw_dev->set_prof_name;
|
|
}
|
|
|
|
static int aw_dev_prof_init(struct aw_device *aw_dev, struct aw_init_info *init_info)
|
|
{
|
|
int i =0;
|
|
const char *first_prof_name = NULL;
|
|
/*find profile*/
|
|
for (i = 0; i < init_info->mix_chip_count; i++) {
|
|
if (init_info->prof_info[i].chip_id == aw_dev->chip_id) {
|
|
aw_dev->prof_info = &init_info->prof_info[i];
|
|
first_prof_name = init_info->prof_info[i].prof_desc[0].name;
|
|
strncpy(aw_dev->first_prof_name, first_prof_name, AW_PROF_NAME_MAX);
|
|
aw_dev_info(aw_dev->dev, "first prof_name[%s]", aw_dev->first_prof_name);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
aw_dev_err(aw_dev->dev, "no supported profile");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/*****************************awinic device*************************************/
|
|
int aw883xx_dev_reg_dump(struct aw_device *aw_dev)
|
|
{
|
|
int reg_num = aw_dev->ops.aw_get_reg_num();
|
|
uint8_t i = 0;
|
|
uint16_t reg_val = 0;
|
|
|
|
for (i = 0; i < reg_num; i++) {
|
|
if (aw_dev->ops.aw_check_rd_access(i)) {
|
|
aw_dev->ops.aw_reg_read(aw_dev, i, ®_val);
|
|
aw_dev_info(aw_dev->dev, "read: reg = 0x%02x, val = 0x%04x",
|
|
i, reg_val);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_set_volume(struct aw_device *aw_dev, uint32_t set_vol)
|
|
{
|
|
uint16_t hw_vol = 0;
|
|
int ret = -1;
|
|
struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
|
|
|
|
hw_vol = set_vol + vol_desc->init_volume;
|
|
|
|
ret = aw_dev->ops.aw_set_hw_volume(aw_dev, hw_vol);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "set volume failed");
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_get_volume(struct aw_device *aw_dev, uint32_t *get_vol)
|
|
{
|
|
int ret = -1;
|
|
uint16_t hw_vol = 0;
|
|
struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
|
|
|
|
ret = aw_dev->ops.aw_get_hw_volume(aw_dev, &hw_vol);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "read volume failed");
|
|
return ret;
|
|
}
|
|
|
|
*get_vol = hw_vol - vol_desc->init_volume;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void aw_dev_fade_in(struct aw_device *aw_dev)
|
|
{
|
|
int i = 0;
|
|
struct aw_volume_desc *desc = &aw_dev->volume_desc;
|
|
int fade_step = aw_dev->fade_step;
|
|
int fade_in_vol = desc->ctl_volume;
|
|
if (!aw_dev->fade_en) {
|
|
return;
|
|
}
|
|
|
|
if (fade_step == 0 || g_fade_in_time == 0) {
|
|
aw_dev_set_volume(aw_dev, fade_in_vol);
|
|
return;
|
|
}
|
|
/*volume up*/
|
|
for (i = desc->mute_volume; i >= fade_in_vol; i -= fade_step) {
|
|
aw_dev_set_volume(aw_dev, i);
|
|
AW_MS_DELAY(g_fade_in_time);
|
|
}
|
|
if (i != fade_in_vol) {
|
|
aw_dev_set_volume(aw_dev, fade_in_vol);
|
|
}
|
|
}
|
|
|
|
static void aw_dev_fade_out(struct aw_device *aw_dev)
|
|
{
|
|
int i = 0;
|
|
struct aw_volume_desc *desc = &aw_dev->volume_desc;
|
|
int fade_step = aw_dev->fade_step;
|
|
|
|
if (!aw_dev->fade_en)
|
|
return;
|
|
|
|
if (fade_step == 0 || g_fade_out_time == 0) {
|
|
aw_dev_set_volume(aw_dev, desc->mute_volume);
|
|
return;
|
|
}
|
|
|
|
for (i = desc->ctl_volume; i <= desc->mute_volume; i += fade_step) {
|
|
aw_dev_set_volume(aw_dev, i);
|
|
AW_MS_DELAY(g_fade_out_time);
|
|
}
|
|
if (i != desc->mute_volume) {
|
|
aw_dev_set_volume(aw_dev, desc->mute_volume);
|
|
AW_MS_DELAY(g_fade_out_time);
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef AW_FADE
|
|
static int aw_dev_get_fade_vol_step(struct aw_device *aw_dev, uint32_t *fade_step)
|
|
{
|
|
*fade_step = aw_dev->fade_step;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_set_fade_vol_step(struct aw_device *aw_dev, unsigned int step)
|
|
{
|
|
aw_dev->fade_step = step;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_get_fade_time(unsigned int *time, fade_time_t fade_type)
|
|
{
|
|
if (fade_type == AW_FADE_IN_TIME) {
|
|
*time = g_fade_in_time;
|
|
} else if (fade_type == AW_FADE_OUT_TIME) {
|
|
*time = g_fade_out_time;
|
|
} else {
|
|
aw_pr_err("unsupported fade type:%d", fade_type);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_set_fade_time(unsigned int time, fade_time_t fade_type)
|
|
{
|
|
if (fade_type == AW_FADE_IN_TIME) {
|
|
g_fade_in_time = time;
|
|
} else if (fade_type == AW_FADE_OUT_TIME) {
|
|
g_fade_out_time = time;
|
|
} else {
|
|
aw_pr_err("unsupported fade type:%d", fade_type);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#ifdef AW_IRQ
|
|
static void aw_dev_interrupt_clear(struct aw_device *aw_dev)
|
|
{
|
|
uint16_t reg_val;
|
|
|
|
aw_dev->ops.aw_i2c_read(aw_dev, aw_dev->sysst_desc.reg, ®_val);
|
|
aw_dev_info(aw_dev->dev,"reg SYSST=0x%x", reg_val);
|
|
aw_dev->ops.aw_i2c_read(aw_dev, aw_dev->int_desc.st_reg, ®_val);
|
|
aw_dev_info(aw_dev->dev,"reg SYSINT=0x%x", reg_val);
|
|
aw_dev->ops.aw_i2c_read(aw_dev, aw_dev->int_desc.mask_reg, ®_val);
|
|
aw_dev_info(aw_dev->dev,"reg SYSINTM=0x%x", reg_val);
|
|
}
|
|
#endif
|
|
|
|
static void aw_dev_soft_reset(struct aw_device *aw_dev)
|
|
{
|
|
struct aw_soft_rst *reset = &aw_dev->soft_rst;
|
|
|
|
aw_dev->ops.aw_i2c_write(aw_dev, reset->reg, reset->reg_value);
|
|
aw_dev_info(aw_dev->dev, "soft reset done");
|
|
}
|
|
|
|
static void aw_dev_pwd(struct aw_device *aw_dev, bool pwd)
|
|
{
|
|
struct aw_pwd_desc *pwd_desc = &aw_dev->pwd_desc;
|
|
|
|
aw_dev_dbg(aw_dev->dev, "enter");
|
|
|
|
if (pwd) {
|
|
aw_dev->ops.aw_reg_write_bits(aw_dev, pwd_desc->reg,
|
|
pwd_desc->mask,
|
|
pwd_desc->enable);
|
|
} else {
|
|
aw_dev->ops.aw_reg_write_bits(aw_dev, pwd_desc->reg,
|
|
pwd_desc->mask,
|
|
pwd_desc->disable);
|
|
}
|
|
aw_dev_info(aw_dev->dev, "done");
|
|
}
|
|
|
|
static void aw_dev_amppd(struct aw_device *aw_dev, bool amppd)
|
|
{
|
|
struct aw_amppd_desc *amppd_desc = &aw_dev->amppd_desc;
|
|
|
|
aw_dev_dbg(aw_dev->dev, "enter");
|
|
if (amppd) {
|
|
aw_dev->ops.aw_reg_write_bits(aw_dev, amppd_desc->reg,
|
|
amppd_desc->mask,
|
|
amppd_desc->enable);
|
|
} else {
|
|
aw_dev->ops.aw_reg_write_bits(aw_dev, amppd_desc->reg,
|
|
amppd_desc->mask,
|
|
amppd_desc->disable);
|
|
}
|
|
aw_dev_info(aw_dev->dev, "done");
|
|
}
|
|
|
|
static int aw_dev_set_hmute(struct aw_device *aw_dev, uint32_t mute)
|
|
{
|
|
int ret = -1;
|
|
struct aw_mute_desc *mute_desc = &aw_dev->mute_desc;
|
|
|
|
aw_dev_dbg(aw_dev->dev, "enter");
|
|
|
|
if (mute == AW_DEV_HMUTE_ENABLE) {
|
|
aw_dev_fade_out(aw_dev);
|
|
ret = aw_dev->ops.aw_reg_write_bits(aw_dev, mute_desc->reg,
|
|
mute_desc->mask, mute_desc->enable);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "write mute enable failed");
|
|
return ret;
|
|
}
|
|
} else if (mute == AW_DEV_HMUTE_DISABLE) {
|
|
ret = aw_dev->ops.aw_reg_write_bits(aw_dev, mute_desc->reg,
|
|
mute_desc->mask, mute_desc->disable);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "write mute disable failed");
|
|
return ret;
|
|
}
|
|
aw_dev_fade_in(aw_dev);
|
|
} else {
|
|
aw_dev_err(aw_dev->dev, "unsupported mute state: %d", mute);
|
|
return -EINVAL;
|
|
}
|
|
|
|
aw_dev_info(aw_dev->dev, "done");
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_get_hmute(struct aw_device *aw_dev, uint32_t *status)
|
|
{
|
|
uint16_t reg_val = 0;
|
|
int ret = -1;
|
|
struct aw_mute_desc *desc = &aw_dev->mute_desc;
|
|
|
|
aw_dev_dbg(aw_dev->dev, "enter");
|
|
|
|
ret = aw_dev->ops.aw_reg_read(aw_dev, desc->reg, ®_val);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
if (reg_val & (~desc->mask)) {
|
|
*status = AW_DEV_HMUTE_ENABLE;
|
|
} else {
|
|
*status = AW_DEV_HMUTE_DISABLE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_get_icalk(struct aw_device * aw_dev, int16_t *icalk)
|
|
{
|
|
int ret = -1;
|
|
uint16_t reg_val = 0;
|
|
uint16_t icalkh_val = 0;
|
|
uint16_t icalkl_val = 0;
|
|
uint16_t icalk_val = 0;
|
|
struct aw_efuse_check_desc *efuse_check_desc = &aw_dev->efuse_check_desc;
|
|
struct aw_vcalb_desc *vcalb_desc = &aw_dev->vcalb_desc;
|
|
|
|
ret = aw_dev->ops.aw_reg_read(aw_dev, vcalb_desc->icalkh_reg, ®_val);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "read icalkh_reg failed");
|
|
return ret;
|
|
}
|
|
icalkh_val = reg_val & (~vcalb_desc->icalkh_reg_mask);
|
|
|
|
ret = aw_dev->ops.aw_reg_read(aw_dev, vcalb_desc->icalkl_reg, ®_val);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "read icalkl_reg failed");
|
|
return ret;
|
|
}
|
|
icalkl_val = reg_val & (~vcalb_desc->icalkl_reg_mask);
|
|
|
|
if (efuse_check_desc->check_val == AW_EF_AND_CHECK) {
|
|
icalk_val = (icalkh_val >> vcalb_desc->icalkh_shift) & (icalkl_val >> vcalb_desc->icalkl_shift);
|
|
} else if (efuse_check_desc->check_val == AW_EF_OR_CHECK) {
|
|
icalk_val = (icalkh_val >> vcalb_desc->icalkh_shift) | (icalkl_val >> vcalb_desc->icalkl_shift);
|
|
} else {
|
|
aw_dev_err(aw_dev->dev, "unsupported check type:%d", efuse_check_desc->check_val);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (icalk_val & (~vcalb_desc->icalk_sign_mask)) {
|
|
icalk_val = icalk_val | vcalb_desc->icalk_neg_mask;
|
|
}
|
|
*icalk = (int16_t)icalk_val;
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_get_vcalk(struct aw_device * aw_dev, int16_t *vcalk)
|
|
{
|
|
int ret = -1;
|
|
uint16_t reg_val = 0;
|
|
uint16_t vcalkh_val = 0;
|
|
uint16_t vcalkl_val = 0;
|
|
uint16_t vcalk_val = 0;
|
|
struct aw_efuse_check_desc *efuse_check_desc = &aw_dev->efuse_check_desc;
|
|
struct aw_vcalb_desc *vcalb_desc = &aw_dev->vcalb_desc;
|
|
|
|
ret = aw_dev->ops.aw_reg_read(aw_dev, vcalb_desc->vcalkh_reg, ®_val);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "read vcalkh_reg failed");
|
|
return ret;
|
|
}
|
|
vcalkh_val = reg_val & (~vcalb_desc->vcalkh_reg_mask);
|
|
|
|
ret = aw_dev->ops.aw_reg_read(aw_dev, vcalb_desc->vcalkl_reg, ®_val);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "read vcalkl_reg failed");
|
|
return ret;
|
|
}
|
|
vcalkl_val = reg_val & (~vcalb_desc->vcalkl_reg_mask);
|
|
|
|
if (efuse_check_desc->check_val == AW_EF_AND_CHECK) {
|
|
vcalk_val = (vcalkh_val >> vcalb_desc->vcalkh_shift) & (vcalkl_val >> vcalb_desc->vcalkl_shift);
|
|
} else if (efuse_check_desc->check_val == AW_EF_OR_CHECK) {
|
|
vcalk_val = (vcalkh_val >> vcalb_desc->vcalkh_shift) | (vcalkl_val >> vcalb_desc->vcalkl_shift);
|
|
} else {
|
|
aw_dev_err(aw_dev->dev, "unsupported check type:%d", efuse_check_desc->check_val);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (vcalk_val & (~vcalb_desc->vcalk_sign_mask)) {
|
|
vcalk_val = vcalk_val | vcalb_desc->vcalk_neg_mask;
|
|
}
|
|
*vcalk = (int16_t)vcalk_val;
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_get_internal_vcalk(struct aw_device *aw_dev, int16_t *vcalk)
|
|
{
|
|
int ret = -1;
|
|
uint16_t reg_val = 0;
|
|
uint16_t vcalkh_val = 0;
|
|
uint16_t vcalkl_val = 0;
|
|
uint16_t vcalk_val = 0;
|
|
struct aw_efuse_check_desc *efuse_check_desc = &aw_dev->efuse_check_desc;
|
|
struct aw_vcalb_desc *vcalb_desc = &aw_dev->vcalb_desc;
|
|
|
|
ret = aw_dev->ops.aw_reg_read(aw_dev, vcalb_desc->vcalkh_dac_reg, ®_val);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "read vcalkh_dac_reg failed");
|
|
return ret;
|
|
}
|
|
vcalkh_val = reg_val & (~vcalb_desc->vcalkh_dac_reg_mask);
|
|
|
|
ret = aw_dev->ops.aw_reg_read(aw_dev, vcalb_desc->vcalkl_dac_reg, ®_val);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "read vcalkl_dac_reg failed");
|
|
return ret;
|
|
}
|
|
vcalkl_val = reg_val & (~vcalb_desc->vcalkl_dac_reg_mask);
|
|
|
|
if (efuse_check_desc->check_val == AW_EF_AND_CHECK) {
|
|
vcalk_val = (vcalkh_val >> vcalb_desc->vcalkh_dac_shift) & (vcalkl_val >> vcalb_desc->vcalkl_dac_shift);
|
|
} else if (efuse_check_desc->check_val == AW_EF_OR_CHECK) {
|
|
vcalk_val = (vcalkh_val >> vcalb_desc->vcalkh_dac_shift) | (vcalkl_val >> vcalb_desc->vcalkl_dac_shift);
|
|
} else {
|
|
aw_dev_err(aw_dev->dev, "unsupported check type:%d", efuse_check_desc->check_val);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (vcalk_val & (~vcalb_desc->vcalk_dac_sign_mask)) {
|
|
vcalk_val = vcalk_val | vcalb_desc->vcalk_dac_neg_mask;
|
|
}
|
|
*vcalk = (int16_t)vcalk_val;
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_vsense_select(struct aw_device *aw_dev, int *vsense_select)
|
|
{
|
|
int ret = -1;
|
|
struct aw_vsense_desc *desc = &aw_dev->vsense_desc;
|
|
uint16_t vsense_reg_val;
|
|
|
|
ret = aw_dev->ops.aw_reg_read(aw_dev, desc->vcalb_vsense_reg, &vsense_reg_val);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "read vsense_reg_val failed");
|
|
return ret;
|
|
}
|
|
aw_dev_dbg(aw_dev->dev, "vsense_reg = 0x%x", vsense_reg_val);
|
|
|
|
if (vsense_reg_val & (~desc->vcalk_vdsel_mask)) {
|
|
*vsense_select = AW_DEV_VDSEL_VSENSE;
|
|
aw_dev_info(aw_dev->dev, "vsense external");
|
|
return 0;
|
|
}
|
|
|
|
*vsense_select = AW_DEV_VDSEL_DAC;
|
|
aw_dev_info(aw_dev->dev, "vsense internal");
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_set_vcalb_to_hw(struct aw_device *aw_dev)
|
|
{
|
|
int ret = -1;
|
|
uint16_t reg_val = 0;
|
|
int16_t icalk = 0;
|
|
int16_t vcalk = 0;
|
|
int32_t ical_k = 0;
|
|
int32_t vcal_k = 0;
|
|
int32_t vcalb = 0;
|
|
int vsense_select = -1;
|
|
struct aw_vcalb_desc *vcalb_desc = &aw_dev->vcalb_desc;
|
|
|
|
if (aw_dev->vsense_desc.vcalb_vsense_reg) {
|
|
ret = aw_dev_vsense_select(aw_dev, &vsense_select);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
aw_dev_dbg(aw_dev->dev, "vsense_select = %d", vsense_select);
|
|
} else {
|
|
vsense_select = aw_dev->vsense_desc.vcalb_vsense_default;
|
|
}
|
|
|
|
ret = aw_dev_get_icalk(aw_dev, &icalk);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "get icalk failed");
|
|
return ret;
|
|
}
|
|
aw_dev_info(aw_dev->dev, "icalk = %d", icalk);
|
|
|
|
ical_k = icalk * vcalb_desc->icalk_value_factor + vcalb_desc->cabl_base_value;
|
|
|
|
if (vsense_select == AW_DEV_VDSEL_VSENSE) {
|
|
ret = aw_dev_get_vcalk(aw_dev, &vcalk);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
vcal_k = vcalk * vcalb_desc->vcalk_value_factor + vcalb_desc->cabl_base_value;
|
|
vcalb = vcalb_desc->vcalb_accuracy *
|
|
vcalb_desc->vscal_factor / vcalb_desc->iscal_factor * ical_k / vcal_k * vcalb_desc->init_value;
|
|
|
|
aw_dev_info(aw_dev->dev, "icalk=%d, vcalk=%d", icalk, vcalk);
|
|
} else if (vsense_select == AW_DEV_VDSEL_DAC) {
|
|
ret = aw_dev_get_internal_vcalk(aw_dev, &vcalk);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
vcal_k = vcalk * vcalb_desc->vcalk_dac_value_factor + vcalb_desc->cabl_base_value;
|
|
vcalb = vcalb_desc->vcalb_accuracy *
|
|
vcalb_desc->vscal_dac_factor / vcalb_desc->iscal_dac_factor * ical_k / vcal_k * vcalb_desc->init_value;
|
|
|
|
aw_dev_info(aw_dev->dev, "icalk=%d, vcalk=%d", icalk, vcalk);
|
|
} else {
|
|
aw_dev_err(aw_dev->dev, "unsupport vsense status");
|
|
return -EINVAL;
|
|
}
|
|
|
|
vcalb = vcalb >> vcalb_desc->vcalb_adj_shift;
|
|
reg_val = (uint32_t)vcalb;
|
|
|
|
aw_dev_info(aw_dev->dev, "vcalb = %d, vcalb_adj = %d",
|
|
reg_val, vcalb_desc->init_value >> vcalb_desc->vcalb_adj_shift);
|
|
|
|
ret = aw_dev->ops.aw_reg_write(aw_dev, vcalb_desc->vcalb_reg, reg_val);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "write vcalb_reg failed");
|
|
return ret;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_set_vcalb(struct aw_device *aw_dev)
|
|
{
|
|
int ret = -1;
|
|
|
|
if (aw_dev->ops.aw_set_vcalb) {
|
|
ret = aw_dev->ops.aw_set_vcalb(aw_dev);
|
|
} else {
|
|
ret = aw_dev_set_vcalb_to_hw(aw_dev);
|
|
}
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "set_vcalb failed");
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_get_int_status(struct aw_device *aw_dev, uint32_t *int_val)
|
|
{
|
|
int ret = -1;
|
|
uint16_t reg_val = 0;
|
|
|
|
ret = aw_dev->ops.aw_reg_read(aw_dev, aw_dev->int_desc.st_reg, ®_val);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "read interrupt reg fail, ret=%d", ret);
|
|
return ret;
|
|
}
|
|
|
|
*int_val = reg_val;
|
|
aw_dev_dbg(aw_dev->dev, "read interrupt reg = 0x%04x", reg_val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_clear_int_status(struct aw_device *aw_dev)
|
|
{
|
|
uint32_t reg_val = 0;
|
|
|
|
/*read int status and clear*/
|
|
aw_dev_get_int_status(aw_dev, ®_val);
|
|
/*make sure int status is clear*/
|
|
aw_dev_get_int_status(aw_dev, ®_val);
|
|
aw_dev_info(aw_dev->dev, "done");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_get_sysst_value(struct aw_device *aw_dev, uint32_t *value)
|
|
{
|
|
int ret = -1;
|
|
uint16_t reg_val = 0;
|
|
struct aw_sysst_desc *desc = &aw_dev->sysst_desc;
|
|
|
|
ret = aw_dev->ops.aw_reg_read(aw_dev, desc->reg, ®_val);
|
|
if(ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "read sysst failed");
|
|
return ret;
|
|
}
|
|
|
|
*value = reg_val;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static bool aw_dev_get_iis_status(struct aw_device *aw_dev)
|
|
{
|
|
int ret = -1;
|
|
bool status = false;
|
|
uint16_t reg_val = 0;
|
|
struct aw_sysst_desc *desc = &aw_dev->sysst_desc;
|
|
|
|
aw_dev_dbg(aw_dev->dev, "enter");
|
|
|
|
ret = aw_dev->ops.aw_reg_read(aw_dev, desc->reg, ®_val);
|
|
if(ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "read pll failed");
|
|
return false;
|
|
}
|
|
|
|
if ((reg_val & desc->pll_check) == desc->pll_check) {
|
|
status = true;
|
|
} else {
|
|
status = false;
|
|
aw_dev_err(aw_dev->dev, "check pll lock fail,reg_val:0x%04x", reg_val);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
static int aw_dev_mode1_pll_check(struct aw_device *aw_dev)
|
|
{
|
|
int ret = -1;
|
|
uint16_t i = 0;
|
|
|
|
for (i = 0; i < AW_DEV_SYSST_CHECK_MAX; i++) {
|
|
if (!(aw_dev_get_iis_status(aw_dev))) {
|
|
aw_dev_err(aw_dev->dev, "mode1 iis signal check error");
|
|
AW_MS_DELAY(AW_2_MS);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int aw_dev_mode2_pll_check(struct aw_device *aw_dev)
|
|
{
|
|
int ret = -1;
|
|
uint16_t i = 0;
|
|
uint16_t reg_val = 0;
|
|
struct aw_cco_mux_desc *cco_mux_desc = &aw_dev->cco_mux_desc;
|
|
|
|
aw_dev->ops.aw_reg_read(aw_dev, cco_mux_desc->reg, ®_val);
|
|
reg_val &= (~cco_mux_desc->mask);
|
|
if (reg_val == cco_mux_desc->divider) {
|
|
aw_dev_dbg(aw_dev->dev, "CCO_MUX is already divider");
|
|
return ret;
|
|
}
|
|
|
|
/* change mode2 */
|
|
aw_dev->ops.aw_reg_write_bits(aw_dev, cco_mux_desc->reg,
|
|
cco_mux_desc->mask, cco_mux_desc->divider);
|
|
|
|
for (i = 0; i < AW_DEV_SYSST_CHECK_MAX; i++) {
|
|
if (!(aw_dev_get_iis_status(aw_dev))) {
|
|
aw_dev_err(aw_dev->dev, "mode2 iis signal check error");
|
|
AW_MS_DELAY(AW_2_MS);
|
|
ret = -EINVAL;
|
|
} else {
|
|
ret = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* change mode1*/
|
|
aw_dev->ops.aw_reg_write_bits(aw_dev, cco_mux_desc->reg,
|
|
cco_mux_desc->mask, cco_mux_desc->bypass);
|
|
|
|
if (ret == 0) {
|
|
AW_MS_DELAY(AW_2_MS);
|
|
for (i = 0; i < AW_DEV_SYSST_CHECK_MAX; i++) {
|
|
ret = aw_dev_mode1_pll_check(aw_dev);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error");
|
|
AW_MS_DELAY(AW_2_MS);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int aw_dev_syspll_check(struct aw_device *aw_dev)
|
|
{
|
|
int ret = -1;
|
|
|
|
ret = aw_dev_mode1_pll_check(aw_dev);
|
|
if (ret < 0) {
|
|
aw_dev_info(aw_dev->dev, "mode1 check iis failed try switch to mode2 check");
|
|
ret = aw_dev_mode2_pll_check(aw_dev);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "mode2 check iis failed");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int aw883xx_dev_sysst_check(struct aw_device *aw_dev)
|
|
{
|
|
int ret = -1;
|
|
unsigned char i = 0;
|
|
uint16_t reg_val = 0;
|
|
unsigned int check_value = 0;
|
|
struct aw_sysst_desc *desc = &aw_dev->sysst_desc;
|
|
struct aw_noise_gate_en *noise_gate_desc = &aw_dev->noise_gate_en;
|
|
|
|
check_value = desc->st_check;
|
|
|
|
if (noise_gate_desc->reg != AW_REG_NONE) {
|
|
aw_dev->ops.aw_reg_read(aw_dev, noise_gate_desc->reg, ®_val);
|
|
if (reg_val & (~noise_gate_desc->noise_gate_mask)) {
|
|
check_value = desc->st_check;
|
|
} else {
|
|
check_value = desc->st_sws_check;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < AW_DEV_SYSST_CHECK_MAX; i++) {
|
|
aw_dev->ops.aw_reg_read(aw_dev, desc->reg, ®_val);
|
|
if (((reg_val & (~desc->st_mask)) & check_value) == check_value) {
|
|
ret = 0;
|
|
break;
|
|
} else {
|
|
aw_dev_dbg(aw_dev->dev, "check fail, cnt=%d, reg_val=0x%04x",
|
|
i, reg_val);
|
|
AW_MS_DELAY(AW_2_MS);
|
|
}
|
|
}
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "check fail");
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int aw_dev_get_monitor_sysint_st(struct aw_device *aw_dev)
|
|
{
|
|
int ret = 0;
|
|
struct aw_int_desc *desc = &aw_dev->int_desc;
|
|
|
|
if ((desc->intst_mask) & (desc->sysint_st)) {
|
|
aw_dev_err(aw_dev->dev,
|
|
"monitor check fail:0x%04x", desc->sysint_st);
|
|
ret = -EINVAL;
|
|
}
|
|
desc->sysint_st = 0;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int aw_dev_sysint_check(struct aw_device *aw_dev)
|
|
{
|
|
int ret = 0;
|
|
uint32_t reg_val = 0;
|
|
struct aw_int_desc *desc = &aw_dev->int_desc;
|
|
|
|
ret = aw_dev_get_int_status(aw_dev, ®_val);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "get int status fail ret:%d", ret);
|
|
return ret;
|
|
}
|
|
|
|
if (reg_val & (desc->intst_mask)) {
|
|
aw_dev_err(aw_dev->dev, "int check fail:0x%04x", reg_val);
|
|
ret = -EINVAL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void aw_dev_get_cur_mode_st(struct aw_device *aw_dev)
|
|
{
|
|
uint16_t reg_val;
|
|
struct aw_profctrl_desc *profctrl_desc = &aw_dev->profctrl_desc;
|
|
|
|
aw_dev->ops.aw_reg_read(aw_dev, aw_dev->pwd_desc.reg, ®_val);
|
|
|
|
if ((reg_val & (~profctrl_desc->mask)) == profctrl_desc->rcv_mode_val) {
|
|
profctrl_desc->cur_mode = AW_RCV_MODE;
|
|
} else {
|
|
profctrl_desc->cur_mode = AW_NOT_RCV_MODE;
|
|
}
|
|
}
|
|
|
|
static int aw_dev_set_intmask(struct aw_device *aw_dev, uint32_t flag)
|
|
{
|
|
int ret = -1;
|
|
struct aw_int_desc *desc = &aw_dev->int_desc;
|
|
|
|
if (flag == AW_DEV_UNMASK_INT_VAL) {
|
|
ret = aw_dev->ops.aw_reg_write(aw_dev, desc->mask_reg,
|
|
desc->int_mask);
|
|
} else if (flag == AW_DEV_MASK_INT_VAL) {
|
|
ret = aw_dev->ops.aw_reg_write(aw_dev, desc->mask_reg,
|
|
desc->mask_default);
|
|
} else {
|
|
aw_dev_err(aw_dev->dev, "unsupported flag : %d", flag);
|
|
return -EINVAL;
|
|
}
|
|
|
|
aw_dev_info(aw_dev->dev, "done");
|
|
return ret;
|
|
}
|
|
|
|
static int aw_dev_dsp_enable(struct aw_device *aw_dev, uint32_t dsp)
|
|
{
|
|
int ret = -1;
|
|
struct aw_dsp_en_desc *desc = &aw_dev->dsp_en_desc;
|
|
|
|
if (dsp == AW_DEV_DSP_WORK) {
|
|
ret = aw_dev->ops.aw_reg_write_bits(aw_dev, desc->reg,
|
|
desc->mask, desc->enable);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "enable dsp failed");
|
|
return ret;
|
|
}
|
|
} else if (dsp == AW_DEV_DSP_BYPASS) {
|
|
ret = aw_dev->ops.aw_reg_write_bits(aw_dev, desc->reg,
|
|
desc->mask, desc->disable);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "disable dsp failed");
|
|
return ret;
|
|
}
|
|
} else {
|
|
aw_dev_err(aw_dev->dev, "unsupported flag : %d", dsp);
|
|
return -EINVAL;
|
|
}
|
|
|
|
aw_dev_info(aw_dev->dev, "done");
|
|
return 0;
|
|
}
|
|
|
|
static void aw_dev_memclk_select(struct aw_device *aw_dev, unsigned char flag)
|
|
{
|
|
struct aw_memclk_desc *desc = &aw_dev->memclk_desc;
|
|
int ret = -1;
|
|
|
|
if (flag == AW_DEV_MEMCLK_PLL) {
|
|
ret = aw_dev->ops.aw_reg_write_bits(aw_dev, desc->reg,
|
|
desc->mask, desc->mcu_hclk);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "memclk select pll failed");
|
|
}
|
|
} else if (flag == AW_DEV_MEMCLK_OSC) {
|
|
ret = aw_dev->ops.aw_reg_write_bits(aw_dev, desc->reg,
|
|
desc->mask, desc->osc_clk);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "memclk select OSC failed");
|
|
}
|
|
} else {
|
|
aw_dev_err(aw_dev->dev, "unknown memclk config, flag=0x%x", flag);
|
|
}
|
|
|
|
aw_dev_info(aw_dev->dev, "done");
|
|
}
|
|
|
|
static int aw_dev_get_dsp_status(struct aw_device *aw_dev)
|
|
{
|
|
int i = -1;
|
|
int ret = -1;
|
|
uint16_t reg_val = 0;
|
|
struct aw_watch_dog_desc *desc = &aw_dev->watch_dog_desc;
|
|
|
|
aw_dev_info(aw_dev->dev, "enter");
|
|
|
|
for (i = 0; i < AW_DEV_DSP_CHECK_MAX; i++) {
|
|
aw_dev->ops.aw_reg_read(aw_dev, desc->reg, ®_val);
|
|
if (reg_val & (~desc->mask)) {
|
|
return 0;
|
|
}
|
|
AW_MS_DELAY(AW_1_MS);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static bool aw_dev_get_pll_wdt_status(struct aw_device *aw_dev)
|
|
{
|
|
int ret = -1;
|
|
|
|
ret = aw_dev_syspll_check(aw_dev);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "pll abnormal");
|
|
return false;
|
|
}
|
|
|
|
ret = aw_dev_get_dsp_status(aw_dev);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "dsp not work");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static int aw_dev_get_cali_f0_delay(struct aw_device *aw_dev)
|
|
{
|
|
struct aw_cali_delay_desc *desc = &aw_dev->cali_desc.cali_delay_desc;
|
|
uint32_t cali_delay = 0;
|
|
int ret = -1;
|
|
|
|
ret = aw_dev->ops.aw_dsp_read(aw_dev,
|
|
desc->dsp_reg, &cali_delay, desc->data_type);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "read cali delay failed, ret=%d", ret);
|
|
return ret;
|
|
}
|
|
|
|
desc->delay = AW_CALI_DELAY_CACL(cali_delay);
|
|
aw_dev_info(aw_dev->dev, "read cali delay: %d ms", desc->delay);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/******************************************************
|
|
*
|
|
* aw_dev update cfg
|
|
*
|
|
******************************************************/
|
|
|
|
static int aw_dev_get_crc_flag(struct aw_device *aw_dev)
|
|
{
|
|
return aw_dev->dsp_crc_st;
|
|
|
|
}
|
|
|
|
static int aw_dev_set_crc_flag(struct aw_device *aw_dev, uint32_t status)
|
|
{
|
|
aw_dev->dsp_crc_st = status;
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_cfg_crc_check(struct aw_device *aw_dev)
|
|
{
|
|
int ret = -1;
|
|
uint16_t reg_val;
|
|
uint16_t check_val;
|
|
uint16_t cfg_len_val;
|
|
struct aw_crc_check_desc *crc_check_desc = &aw_dev->crc_check_desc;
|
|
|
|
/*calculate cfg_end_addr*/
|
|
cfg_len_val = ((aw_dev->dsp_cfg_len / AW_FW_ADDR_LEN) - 1) +
|
|
crc_check_desc->crc_cfg_base_addr;
|
|
aw_dev_info(aw_dev->dev, "cfg_end_addr 0x%x", cfg_len_val);
|
|
|
|
/*write cfg_end_addr to crc_end_addr*/
|
|
ret = aw_dev->ops.aw_reg_write_bits(aw_dev, crc_check_desc->crc_ctrl_reg,
|
|
crc_check_desc->crc_end_addr_mask, cfg_len_val);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "write cfg_len_val failed");
|
|
return ret;
|
|
}
|
|
|
|
/*enable cfg crc check*/
|
|
ret = aw_dev->ops.aw_reg_write_bits(aw_dev, crc_check_desc->crc_ctrl_reg,
|
|
crc_check_desc->crc_cfg_check_en_mask, crc_check_desc->crc_cfgcheck_enable);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "write crc_check_enable failed");
|
|
return ret;
|
|
}
|
|
|
|
AW_MS_DELAY(AW_1_MS);
|
|
/*read crc check result*/
|
|
ret = aw_dev->ops.aw_reg_read(aw_dev, crc_check_desc->crc_check_reg, ®_val);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "read crc_check_reg failed");
|
|
return ret;
|
|
}
|
|
|
|
check_val = (reg_val & (~crc_check_desc->crc_check_mask)) >> crc_check_desc->crc_check_bits_shift;
|
|
|
|
/*disable cfg crc check*/
|
|
ret = aw_dev->ops.aw_reg_write_bits(aw_dev, crc_check_desc->crc_ctrl_reg,
|
|
crc_check_desc->crc_cfg_check_en_mask, crc_check_desc->crc_cfgcheck_disable);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "write crc_check_disable failed");
|
|
return ret;
|
|
}
|
|
|
|
/*compare crc check result and pass value*/
|
|
if (check_val != crc_check_desc->crc_check_pass) {
|
|
aw_dev_err(aw_dev->dev, "crc_check failed,check val %x != %x", check_val,
|
|
crc_check_desc->crc_check_pass);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_fw_crc_check(struct aw_device *aw_dev)
|
|
{
|
|
int ret = -1;
|
|
uint16_t reg_val;
|
|
uint16_t check_val;
|
|
uint16_t fw_len_val;
|
|
struct aw_crc_check_desc *crc_check_desc = &aw_dev->crc_check_desc;
|
|
|
|
/*calculate fw_end_addr*/
|
|
fw_len_val = ((aw_dev->dsp_fw_len / AW_FW_ADDR_LEN) - 1) +
|
|
crc_check_desc->crc_fw_base_addr;
|
|
|
|
aw_dev_info(aw_dev->dev, "fw_end_addr 0x%x", fw_len_val);
|
|
|
|
/*write fw_end_addr to crc_end_addr*/
|
|
ret = aw_dev->ops.aw_reg_write_bits(aw_dev, crc_check_desc->crc_ctrl_reg,
|
|
crc_check_desc->crc_end_addr_mask, fw_len_val);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "write fw_len_val failed");
|
|
return ret;
|
|
}
|
|
/*enable fw crc check*/
|
|
ret = aw_dev->ops.aw_reg_write_bits(aw_dev, crc_check_desc->crc_ctrl_reg,
|
|
crc_check_desc->crc_fw_check_en_mask, crc_check_desc->crc_fwcheck_enable);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "write crc_check_enable failed");
|
|
return ret;
|
|
}
|
|
|
|
AW_MS_DELAY(AW_2_MS);
|
|
/*read crc check result*/
|
|
ret = aw_dev->ops.aw_reg_read(aw_dev, crc_check_desc->crc_check_reg, ®_val);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "read crc_check_reg failed");
|
|
return ret;
|
|
}
|
|
|
|
check_val = (reg_val & (~crc_check_desc->crc_check_mask)) >> crc_check_desc->crc_check_bits_shift;
|
|
|
|
/*disable fw crc check*/
|
|
ret = aw_dev->ops.aw_reg_write_bits(aw_dev, crc_check_desc->crc_ctrl_reg,
|
|
crc_check_desc->crc_fw_check_en_mask, crc_check_desc->crc_fwcheck_disable);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "write crc_check_disable failed");
|
|
return ret;
|
|
}
|
|
|
|
/*compare crc check result and pass value*/
|
|
if (check_val != crc_check_desc->crc_check_pass) {
|
|
aw_dev_err(aw_dev->dev, "crc_check failed,check val %x != %x", check_val,
|
|
crc_check_desc->crc_check_pass);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_hw_crc_check(struct aw_device *aw_dev)
|
|
{
|
|
int ret = -1;
|
|
struct aw_crc_check_desc *crc_check_desc = &aw_dev->crc_check_desc;
|
|
|
|
/*force RAM clock on*/
|
|
ret = aw_dev->ops.aw_reg_write_bits(aw_dev, crc_check_desc->ram_clk_reg,
|
|
crc_check_desc->ram_clk_mask, crc_check_desc->ram_clk_on);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "write ram_clk_on failed");
|
|
return ret;
|
|
}
|
|
|
|
ret = aw_dev_fw_crc_check(aw_dev);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, " fw_crc_check failed");
|
|
goto ram_clk_off;
|
|
}
|
|
|
|
ret = aw_dev_cfg_crc_check(aw_dev);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, " cfg_crc_check failed");
|
|
goto ram_clk_off;
|
|
}
|
|
|
|
/*write bin value to crc reg when fw & cfg crc check pass*/
|
|
ret = aw_dev->ops.aw_reg_write(aw_dev, crc_check_desc->crc_ctrl_reg, crc_check_desc->crc_init_val);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "write crc_init_val failed");
|
|
goto ram_clk_off;
|
|
}
|
|
|
|
/*disable force RAM clock*/
|
|
aw_dev->ops.aw_reg_write_bits(aw_dev, crc_check_desc->ram_clk_reg,
|
|
crc_check_desc->ram_clk_mask, crc_check_desc->ram_clk_off);
|
|
|
|
return 0;
|
|
ram_clk_off:
|
|
aw_dev->ops.aw_reg_write_bits(aw_dev, crc_check_desc->ram_clk_reg,
|
|
crc_check_desc->ram_clk_mask, crc_check_desc->ram_clk_off);
|
|
return ret;
|
|
}
|
|
|
|
static int aw_dev_crc_check(struct aw_device *aw_dev)
|
|
{
|
|
int ret = -1;
|
|
|
|
if (aw_dev_get_crc_flag(aw_dev) == AW_DSP_CRC_BYPASS) {
|
|
aw_dev_info(aw_dev->dev, "CRC Bypass in driver debug process");
|
|
return 0;
|
|
}
|
|
if (aw_dev->crc_type == AW_SW_CRC_CHECK) {
|
|
if (aw_dev->ops.aw_sw_crc_check) {
|
|
ret = aw_dev->ops.aw_sw_crc_check(aw_dev);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "dsp crc check failed");
|
|
return ret;
|
|
}
|
|
} else {
|
|
aw_dev_err(aw_dev->dev, "sw_crc_check ops is NULL");
|
|
return ret;
|
|
}
|
|
} else if (aw_dev->crc_type == AW_HW_CRC_CHECK) {
|
|
ret = aw_dev_hw_crc_check(aw_dev);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "hw_crc_check failed");
|
|
return ret;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#ifdef AW_MONITOR
|
|
static void aw_dev_init_vmax_update(struct aw_device *aw_dev, backup_sec_t flag)
|
|
{
|
|
if (flag == AW_RECOVERY_SEC_DATA) {
|
|
aw883xx_monitor_update_st(aw_dev, AW_SET_INIT_VMAX);
|
|
} else if (flag == AW_RECORD_SEC_DATA) {
|
|
aw883xx_monitor_update_st(aw_dev, AW_GET_INIT_VMAX);
|
|
} else {
|
|
aw_dev_err(aw_dev->dev, "unsupported type:%d", flag);
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static int aw_dev_init_vcalb_update(struct aw_device *aw_dev, backup_sec_t flag)
|
|
{
|
|
int ret = -1;
|
|
struct aw_vcalb_desc *vcalb_desc = &aw_dev->vcalb_desc;
|
|
|
|
if (aw_dev->ops.aw_init_vcalb_update) {
|
|
ret = aw_dev->ops.aw_init_vcalb_update(aw_dev, flag);
|
|
if (ret < 0)
|
|
aw_dev_err(aw_dev->dev, "write vcalb_reg failed");
|
|
return ret;
|
|
}
|
|
|
|
if (flag == AW_RECOVERY_SEC_DATA) {
|
|
ret = aw_dev->ops.aw_reg_write(aw_dev, vcalb_desc->vcalb_reg, vcalb_desc->init_value);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "write vcalb_reg failed");
|
|
return ret;
|
|
}
|
|
} else if (flag == AW_RECORD_SEC_DATA) {
|
|
ret = aw_dev->ops.aw_reg_read(aw_dev, vcalb_desc->vcalb_reg, &vcalb_desc->init_value);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "write vcalb_reg failed");
|
|
return ret;
|
|
}
|
|
} else {
|
|
aw_dev_err(aw_dev->dev, "unsupported type:%d", flag);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_get_firmware_ver(struct aw_device *aw_dev)
|
|
{
|
|
int ret = -1;
|
|
struct aw_fw_ver_desc *fw_ver_desc = &aw_dev->fw_ver_desc;
|
|
|
|
ret = aw_dev->ops.aw_dsp_read(aw_dev,
|
|
fw_ver_desc->version_reg, &aw_dev->fw_ver, fw_ver_desc->data_type);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "read firmware version failed, ret=%d", ret);
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*pwd enable update reg*/
|
|
|
|
static int aw_dev_reg_container_update(struct aw_device *aw_dev,
|
|
const uint8_t *data, uint32_t len)
|
|
{
|
|
int i = 0;
|
|
int ret = -1;
|
|
uint8_t reg_addr = 0;
|
|
uint16_t reg_val = 0;
|
|
uint16_t read_vol = 0;
|
|
struct aw_int_desc *int_desc = &aw_dev->int_desc;
|
|
struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
|
|
uint16_t *reg_data = NULL;
|
|
int data_len;
|
|
|
|
aw_dev_dbg(aw_dev->dev, "enter");
|
|
reg_data = (uint16_t *)data;
|
|
data_len = len >> 1;
|
|
|
|
if (data_len % 2 != 0) {
|
|
aw_dev_err(aw_dev->dev, "data len:%d unsupported",
|
|
data_len);
|
|
return -EINVAL;
|
|
}
|
|
|
|
for (i = 0; i < data_len; i += 2) {
|
|
reg_addr = reg_data[i];
|
|
reg_val = reg_data[i + 1];
|
|
aw_dev_dbg(aw_dev->dev, "reg = 0x%02x, val = 0x%04x",
|
|
reg_addr, reg_val);
|
|
if (reg_addr == int_desc->mask_reg) {
|
|
int_desc->int_mask = reg_val;
|
|
reg_val = int_desc->mask_default;
|
|
}
|
|
if (reg_addr == aw_dev->mute_desc.reg) {
|
|
reg_val &= aw_dev->mute_desc.mask;
|
|
reg_val |= aw_dev->mute_desc.enable;
|
|
}
|
|
|
|
if (reg_addr == aw_dev->pwd_desc.reg) {
|
|
reg_val &= aw_dev->pwd_desc.mask;
|
|
reg_val |= aw_dev->pwd_desc.enable;
|
|
}
|
|
|
|
if (reg_addr == aw_dev->txen_desc.reg) {
|
|
/*get bin value*/
|
|
aw_dev->txen_st = reg_val & (~aw_dev->txen_desc.mask);
|
|
aw_dev_dbg(aw_dev->dev, "txen_st=0x%04x", aw_dev->txen_st);
|
|
|
|
reg_val &= aw_dev->txen_desc.mask;
|
|
reg_val |= aw_dev->txen_desc.disable;
|
|
}
|
|
|
|
if (reg_addr == aw_dev->dsp_crc_desc.ctl_reg) {
|
|
reg_val &= aw_dev->dsp_crc_desc.ctl_mask;
|
|
}
|
|
|
|
if (reg_addr == aw_dev->volume_desc.reg) {
|
|
read_vol = (reg_val & (~aw_dev->volume_desc.mask)) >>
|
|
aw_dev->volume_desc.shift;
|
|
aw_dev->volume_desc.init_volume =
|
|
aw_dev->ops.aw_reg_val_to_db(read_vol);
|
|
}
|
|
|
|
if (reg_addr == aw_dev->efuse_check_desc.reg) {
|
|
if ((reg_val & (~aw_dev->efuse_check_desc.mask)) ==
|
|
aw_dev->efuse_check_desc.or_val)
|
|
aw_dev->efuse_check_desc.check_val = AW_EF_OR_CHECK;
|
|
else
|
|
aw_dev->efuse_check_desc.check_val = AW_EF_AND_CHECK;
|
|
}
|
|
|
|
if (reg_addr == aw_dev->crc_check_desc.crc_ctrl_reg)
|
|
aw_dev->crc_check_desc.crc_init_val = reg_val;
|
|
|
|
if (reg_addr == aw_dev->vcalb_desc.vcalb_reg) {
|
|
aw_dev->vcalb_desc.init_value = reg_val;
|
|
continue;
|
|
}
|
|
|
|
if (reg_addr == aw_dev->cali_desc.hw_cali_re_desc.hbits_reg) {
|
|
aw_dev->cali_desc.hw_cali_re_desc.re_hbits = reg_val;
|
|
continue;
|
|
}
|
|
|
|
if (reg_addr == aw_dev->cali_desc.hw_cali_re_desc.lbits_reg) {
|
|
aw_dev->cali_desc.hw_cali_re_desc.re_lbits = reg_val;
|
|
continue;
|
|
}
|
|
|
|
if (reg_addr == aw_dev->dsp_en_desc.reg) {
|
|
if (reg_val & (~aw_dev->dsp_en_desc.mask))
|
|
aw_dev->dsp_cfg = AW_DEV_DSP_BYPASS;
|
|
else
|
|
aw_dev->dsp_cfg = AW_DEV_DSP_WORK;
|
|
reg_val &= aw_dev->dsp_en_desc.mask;
|
|
reg_val |= aw_dev->dsp_en_desc.disable;
|
|
}
|
|
|
|
if(reg_addr == aw_dev->dither_desc.reg) {
|
|
aw_dev->dither_st = reg_val & (~aw_dev->dither_desc.mask);
|
|
aw_dev_info(aw_dev->dev, "dither_st=0x%04x", aw_dev->dither_st);
|
|
}
|
|
|
|
ret = aw_dev->ops.aw_reg_write(aw_dev, reg_addr, reg_val);
|
|
if (ret < 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
aw_dev_pwd(aw_dev, false);
|
|
AW_MS_DELAY(AW_1_MS);;
|
|
|
|
aw_dev_get_cur_mode_st(aw_dev);
|
|
|
|
if ((strncmp(aw_dev->cur_prof_name, aw_dev->set_prof_name, AW_PROF_NAME_MAX) != 0)) {
|
|
/*clear control volume when PA change profile*/
|
|
vol_desc->ctl_volume = 0;
|
|
} else {
|
|
/*keep control volume when PA start with sync mode*/
|
|
aw_dev_set_volume(aw_dev, vol_desc->ctl_volume);
|
|
}
|
|
|
|
/*keep min volume*/
|
|
if (aw_dev->fade_en) {
|
|
aw_dev_set_volume(aw_dev, vol_desc->mute_volume);
|
|
}
|
|
|
|
#ifdef AW_MONITOR
|
|
aw883xx_monitor_update_st(aw_dev, AW_HW_MONITOR_ST);
|
|
#endif
|
|
|
|
aw_dev_dbg(aw_dev->dev, "exit");
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int aw_dev_reg_update(struct aw_device *aw_dev)
|
|
{
|
|
struct aw_sec_data_desc *reg_data = NULL;
|
|
reg_data = aw883xx_dev_get_prof_data_byname(aw_dev, aw_dev->set_prof_name, AW_DATA_TYPE_REG);
|
|
|
|
if (reg_data == NULL){
|
|
aw_dev_err(aw_dev->dev, "reg data is null");
|
|
return -EINVAL;
|
|
}
|
|
|
|
aw_dev_reg_container_update(aw_dev, reg_data->data, reg_data->len);
|
|
|
|
aw_dev_dbg(aw_dev->dev, "reg len:%d", reg_data->len);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_dsp_container_update(struct aw_device *aw_dev,
|
|
const uint8_t *dsp_data, uint32_t len, uint16_t base)
|
|
{
|
|
uint32_t i;
|
|
struct aw_dsp_mem_desc *dsp_mem_desc = &aw_dev->dsp_mem_desc;
|
|
uint8_t *data = NULL;
|
|
data = (uint8_t *)dsp_data;
|
|
|
|
#ifdef AW_DSP_I2C_WRITES
|
|
uint32_t tmp_len = 0;
|
|
#else
|
|
uint16_t reg_val = 0;
|
|
#endif
|
|
|
|
aw_dev_dbg(aw_dev->dev, "enter");
|
|
aw_mutex_lock();
|
|
#ifdef AW_DSP_I2C_WRITES
|
|
/* i2c writes */
|
|
aw_dev->ops.aw_i2c_write(aw_dev, dsp_mem_desc->dsp_madd_reg, base);
|
|
|
|
for (i = 0; i < len; i += AW_MAX_RAM_WRITE_BYTE_SIZE) {
|
|
if ((len - i) < AW_MAX_RAM_WRITE_BYTE_SIZE) {
|
|
tmp_len = len - i;
|
|
} else {
|
|
tmp_len = AW_MAX_RAM_WRITE_BYTE_SIZE;
|
|
}
|
|
aw_dev->ops.aw_i2c_writes(aw_dev, dsp_mem_desc->dsp_mdat_reg,
|
|
&data[i], tmp_len);
|
|
}
|
|
|
|
#else
|
|
/* i2c write */
|
|
aw_dev->ops.aw_i2c_write(aw_dev, dsp_mem_desc->dsp_madd_reg, base);
|
|
|
|
for (i = 0; i < len; i += 2) {
|
|
reg_val = (data[i] << 8) + data[i + 1];
|
|
aw_dev->ops.aw_i2c_write(aw_dev, dsp_mem_desc->dsp_mdat_reg,
|
|
reg_val);
|
|
}
|
|
#endif
|
|
|
|
aw_mutex_unlock();
|
|
aw_dev_dbg(aw_dev->dev, "exit");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_dsp_fw_update(struct aw_device *aw_dev)
|
|
{
|
|
struct aw_dsp_mem_desc *dsp_mem_desc = &aw_dev->dsp_mem_desc;
|
|
struct aw_sec_data_desc *dsp_fw_data = NULL;
|
|
|
|
dsp_fw_data = aw883xx_dev_get_prof_data_byname(aw_dev, aw_dev->set_prof_name, AW_DATA_TYPE_DSP_FW);
|
|
|
|
if (dsp_fw_data == NULL) {
|
|
aw_dev_err(aw_dev->dev, "dsp firmware data is null");
|
|
return -EINVAL;
|
|
}
|
|
|
|
aw_dev_dsp_container_update(aw_dev, dsp_fw_data->data,
|
|
dsp_fw_data->len, dsp_mem_desc->dsp_fw_base_addr);
|
|
aw_dev->dsp_fw_len = dsp_fw_data->len;
|
|
aw_dev_dbg(aw_dev->dev, "dsp firmware len:%d", dsp_fw_data->len);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_crc_realtime_get(struct aw_device *aw_dev, uint32_t *status)
|
|
{
|
|
int ret = -1;
|
|
struct aw_crc_check_realtime_desc *desc =&aw_dev->crc_check_realtime_desc;
|
|
unsigned int crc_realtime_val = 0;
|
|
|
|
ret = aw_dev->ops.aw_dsp_read(aw_dev, desc->addr,
|
|
&crc_realtime_val, desc->data_type);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "get crc_realtime failed");
|
|
return ret;
|
|
}
|
|
|
|
if (crc_realtime_val & (~desc->mask))
|
|
*status = aw_dev->crc_check_realtime_desc.enable;
|
|
else
|
|
*status = aw_dev->crc_check_realtime_desc.disable;
|
|
|
|
aw_dev_dbg(aw_dev->dev, "get %d", *status);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_crc_realtime_set(struct aw_device *aw_dev, uint32_t enable)
|
|
{
|
|
int ret = -1;
|
|
struct aw_crc_check_realtime_desc *crc_desc =&aw_dev->crc_check_realtime_desc;
|
|
|
|
aw_dev_dbg(aw_dev->dev, "set %d", enable);
|
|
|
|
if (enable) {
|
|
ret = aw_dev->ops.aw_dsp_write_bits(aw_dev, crc_desc->addr,
|
|
crc_desc->mask, crc_desc->enable, crc_desc->data_type);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "set enable failed");
|
|
return ret;
|
|
}
|
|
} else {
|
|
ret = aw_dev->ops.aw_dsp_write_bits(aw_dev, crc_desc->addr,
|
|
crc_desc->mask, crc_desc->disable, crc_desc->data_type);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "set disable failed");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int aw883xx_crc_realtime_check(struct aw_device *aw_dev, uint32_t *status)
|
|
{
|
|
int ret = -1;
|
|
uint16_t sysst_val;
|
|
uint32_t crc_check_val;
|
|
struct aw_sysst_desc *desc = &aw_dev->sysst_desc;
|
|
struct aw_int_desc *int_desc = &aw_dev->int_desc;
|
|
struct aw_crc_check_realtime_desc *crc_desc =&aw_dev->crc_check_realtime_desc;
|
|
|
|
if (aw_dev_get_crc_flag(aw_dev) == AW_DSP_CRC_BYPASS) {
|
|
int_desc->int_mask = int_desc->mask_default;
|
|
aw_dev_info(aw_dev->dev, "CRC Bypass in driver debug process");
|
|
return 0;
|
|
}
|
|
|
|
ret = aw_dev->ops.aw_reg_read(aw_dev, desc->reg, &sysst_val);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "read reg0x%x failed", desc->reg);
|
|
return ret;
|
|
}
|
|
|
|
ret = aw_dev->ops.aw_dsp_read(aw_dev, crc_desc->check_addr,
|
|
&crc_check_val, crc_desc->check_data_type);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "get crc_check_val failed");
|
|
return ret;
|
|
}
|
|
|
|
if (((sysst_val & desc->dsp_mask) != desc->dsp_check) &&
|
|
(crc_check_val & (~crc_desc->check_mask)) ==
|
|
aw_dev->crc_check_realtime_desc.check_abnormal) {
|
|
*status = AW_REALTIME_CRC_CHECK_ABNORMAL;
|
|
} else {
|
|
*status = AW_REALTIME_CRC_CHECK_NORMAL;
|
|
}
|
|
|
|
aw_dev_dbg(aw_dev->dev, "check status %d", *status);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void aw_dev_backup_sec_record(struct aw_device *aw_dev)
|
|
{
|
|
aw_dev_init_vcalb_update(aw_dev, AW_RECORD_SEC_DATA);
|
|
aw_dev_crc_realtime_get(aw_dev, &aw_dev->crc_check_realtime_desc.init_switch);
|
|
#ifdef AW_CALIB
|
|
aw883xx_cali_init_re_update(aw_dev, AW_RECORD_SEC_DATA);
|
|
#endif
|
|
#ifdef AW_MONITOR
|
|
aw_dev_init_vmax_update(aw_dev, AW_RECORD_SEC_DATA);
|
|
#endif
|
|
}
|
|
|
|
static void aw_dev_backup_sec_recovery(struct aw_device *aw_dev)
|
|
{
|
|
aw_dev_init_vcalb_update(aw_dev, AW_RECOVERY_SEC_DATA);
|
|
#ifdef AW_CALIB
|
|
aw883xx_cali_init_re_update(aw_dev, AW_RECOVERY_SEC_DATA);
|
|
#endif
|
|
#ifdef AW_MONITOR
|
|
aw_dev_init_vmax_update(aw_dev, AW_RECOVERY_SEC_DATA);
|
|
#endif
|
|
|
|
}
|
|
|
|
static int aw_dev_dsp_cfg_update(struct aw_device *aw_dev)
|
|
{
|
|
struct aw_dsp_mem_desc *dsp_mem_desc = &aw_dev->dsp_mem_desc;
|
|
struct aw_sec_data_desc *dsp_cfg_data = NULL;
|
|
|
|
dsp_cfg_data = aw883xx_dev_get_prof_data_byname(aw_dev, aw_dev->set_prof_name, AW_DATA_TYPE_DSP_CFG);
|
|
|
|
if (dsp_cfg_data == NULL) {
|
|
aw_dev_err(aw_dev->dev, "dsp config data is null");
|
|
return -EINVAL;
|
|
}
|
|
|
|
aw_dev_dsp_container_update(aw_dev,
|
|
dsp_cfg_data->data, dsp_cfg_data->len, dsp_mem_desc->dsp_cfg_base_addr);
|
|
aw_dev->dsp_cfg_len = dsp_cfg_data->len;
|
|
aw_dev_dbg(aw_dev->dev, "dsp config len:%d", dsp_cfg_data->len);
|
|
|
|
aw_dev_backup_sec_record(aw_dev);
|
|
|
|
#ifdef AW_CALIB
|
|
aw883xx_cali_get_ra((void *)aw_dev);
|
|
aw_dev_get_cali_f0_delay(aw_dev);
|
|
#endif
|
|
|
|
#ifdef AW_MONITOR
|
|
aw883xx_monitor_update_st(aw_dev, AW_DSP_MONITOR_ST);
|
|
#endif
|
|
|
|
aw_dev_get_firmware_ver(aw_dev);
|
|
aw_dev_info(aw_dev->dev, "fw_ver: [%04x]", aw_dev->fw_ver);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_sram_check(struct aw_device *aw_dev)
|
|
{
|
|
int ret = -1;
|
|
uint16_t reg_val = 0;
|
|
struct aw_dsp_mem_desc *dsp_mem_desc = &aw_dev->dsp_mem_desc;
|
|
|
|
aw_mutex_lock();
|
|
|
|
/*read dsp_rom_check_reg*/
|
|
aw_dev->ops.aw_i2c_write(aw_dev, dsp_mem_desc->dsp_madd_reg,
|
|
dsp_mem_desc->dsp_rom_check_reg);
|
|
aw_dev->ops.aw_i2c_read(aw_dev, dsp_mem_desc->dsp_mdat_reg, ®_val);
|
|
if (dsp_mem_desc->dsp_rom_check_data != reg_val) {
|
|
aw_dev_err(aw_dev->dev, "check reg 0x40 failed, read[0x%x] does not match write[0x%x]",
|
|
reg_val, dsp_mem_desc->dsp_rom_check_data);
|
|
goto error;
|
|
}
|
|
|
|
/*write dsp_cfg_base_addr*/
|
|
aw_dev->ops.aw_i2c_write(aw_dev, dsp_mem_desc->dsp_madd_reg,
|
|
dsp_mem_desc->dsp_cfg_base_addr);
|
|
aw_dev->ops.aw_i2c_write(aw_dev, dsp_mem_desc->dsp_mdat_reg,
|
|
AW_DSP_ODD_NUM_BIT_TEST);
|
|
|
|
/*read dsp_cfg_base_addr*/
|
|
aw_dev->ops.aw_i2c_write(aw_dev, dsp_mem_desc->dsp_madd_reg,
|
|
dsp_mem_desc->dsp_cfg_base_addr);
|
|
aw_dev->ops.aw_i2c_read(aw_dev, dsp_mem_desc->dsp_mdat_reg, ®_val);
|
|
if (AW_DSP_ODD_NUM_BIT_TEST != reg_val) {
|
|
aw_dev_err(aw_dev->dev, "check dsp cfg failed, read[0x%x] does not match write[0x%x]",
|
|
reg_val, AW_DSP_ODD_NUM_BIT_TEST);
|
|
goto error;
|
|
}
|
|
aw_mutex_unlock();
|
|
return 0;
|
|
|
|
error:
|
|
aw_mutex_unlock();
|
|
return ret;
|
|
}
|
|
|
|
int aw883xx_device_fw_update(struct aw_device *aw_dev, bool up_dsp_fw_en, bool force_up_en)
|
|
{
|
|
int ret = -1;
|
|
|
|
aw_dev_info(aw_dev->dev, "enter ");
|
|
|
|
if ((strncmp(aw_dev->cur_prof_name, aw_dev->set_prof_name, AW_PROF_NAME_MAX) == 0) &&
|
|
(force_up_en == AW_FORCE_UPDATE_OFF)) {
|
|
aw_dev_info(aw_dev->dev, "scene no change, not update");
|
|
return 0;
|
|
}
|
|
|
|
/*update reg*/
|
|
ret = aw_dev_reg_update(aw_dev);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "update reg failed");
|
|
return ret;
|
|
}
|
|
|
|
aw_dev_set_hmute(aw_dev, AW_DEV_HMUTE_ENABLE);
|
|
|
|
if (aw_dev->dsp_cfg == AW_DEV_DSP_WORK) {
|
|
aw_dev_dsp_enable(aw_dev, AW_DEV_DSP_BYPASS);
|
|
}
|
|
|
|
aw_dev_memclk_select(aw_dev, AW_DEV_MEMCLK_OSC);
|
|
|
|
ret = aw_dev_sram_check(aw_dev);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "check sram failed");
|
|
goto error;
|
|
}
|
|
|
|
aw_dev_backup_sec_recovery(aw_dev);
|
|
|
|
if (up_dsp_fw_en) {
|
|
/*update dsp firmware*/
|
|
ret = aw_dev_dsp_fw_update(aw_dev);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "update dsp fw failed");
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
/*update dsp config*/
|
|
ret = aw_dev_dsp_cfg_update(aw_dev);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "update dsp cfg failed");
|
|
goto error;
|
|
}
|
|
|
|
aw_dev_memclk_select(aw_dev, AW_DEV_MEMCLK_PLL);
|
|
|
|
strncpy(aw_dev->cur_prof_name, aw_dev->set_prof_name, AW_PROF_NAME_MAX);
|
|
|
|
aw_dev_info(aw_dev->dev, "load [%s] done", aw_dev->cur_prof_name);
|
|
return 0;
|
|
|
|
error:
|
|
aw_dev_memclk_select(aw_dev, AW_DEV_MEMCLK_PLL);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int aw883xx_dev_dsp_check(struct aw_device *aw_dev)
|
|
{
|
|
int ret = -1;
|
|
uint16_t i = 0;
|
|
|
|
aw_dev_dbg(aw_dev->dev, "enter");
|
|
|
|
if (aw_dev->dsp_cfg == AW_DEV_DSP_BYPASS) {
|
|
aw_dev_dbg(aw_dev->dev, "dsp bypass");
|
|
return 0;
|
|
} else if (aw_dev->dsp_cfg == AW_DEV_DSP_WORK) {
|
|
aw_dev_dsp_enable(aw_dev, AW_DEV_DSP_BYPASS);
|
|
aw_dev_dsp_enable(aw_dev, AW_DEV_DSP_WORK);
|
|
AW_MS_DELAY(AW_1_MS);
|
|
for (i = 0; i < AW_DEV_DSP_CHECK_MAX; i++) {
|
|
ret = aw_dev_get_dsp_status(aw_dev);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "dsp wdt status error=%d", ret);
|
|
AW_MS_DELAY(AW_2_MS);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
} else {
|
|
aw_dev_err(aw_dev->dev, "unknown dsp cfg=%d", aw_dev->dsp_cfg);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
static void aw_dev_set_dither(struct aw_device *aw_dev, bool dither)
|
|
{
|
|
struct aw_dither_desc *dither_desc = &aw_dev->dither_desc;
|
|
|
|
aw_dev_dbg(aw_dev->dev, "enter, dither: %d", dither);
|
|
|
|
if (dither_desc->reg == AW_REG_NONE)
|
|
return;
|
|
|
|
if (dither) {
|
|
aw_dev->ops.aw_reg_write_bits(aw_dev, dither_desc->reg,
|
|
dither_desc->mask,
|
|
dither_desc->enable);
|
|
} else {
|
|
aw_dev->ops.aw_reg_write_bits(aw_dev, dither_desc->reg,
|
|
dither_desc->mask,
|
|
dither_desc->disable);
|
|
}
|
|
|
|
aw_dev_info(aw_dev->dev, "done");
|
|
}
|
|
|
|
#ifdef AW_CALIB
|
|
static void aw_dev_cali_re_update(struct aw_device *aw_dev)
|
|
{
|
|
if (aw_dev->cali_desc.cali_re < aw_dev->re_range.re_max &&
|
|
aw_dev->cali_desc.cali_re > aw_dev->re_range.re_min) {
|
|
aw883xx_set_cali_re((void *)aw_dev);
|
|
} else {
|
|
aw_dev_err(aw_dev->dev, "cali_re:%d is error, no set",
|
|
aw_dev->cali_desc.cali_re);
|
|
}
|
|
}
|
|
|
|
static int aw_dev_get_cali_msg(struct aw_device *aw_dev, void *cali_data, dev_params_t type)
|
|
{
|
|
int ret = -1;
|
|
struct cali_msg_hdr *msg_hdr = NULL;
|
|
uint32_t cali_params[AW_DEV_MAX] = { 0 };
|
|
aw_single_t is_single = IS_SINGLE;
|
|
|
|
if (cali_data == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
msg_hdr = (struct cali_msg_hdr *)cali_data;
|
|
is_single = (aw_single_t)msg_hdr->opcode_id;
|
|
|
|
switch (type) {
|
|
case AW_DEV_TE_PARAMS:
|
|
ret = aw883xx_cali_get_te(aw_dev, is_single, (int32_t *)cali_params);
|
|
break;
|
|
case AW_DEV_F0_PARAMS:
|
|
ret = aw883xx_cali_get_f0(aw_dev, is_single, cali_params);
|
|
break;
|
|
case AW_DEV_R0_PARAMS:
|
|
ret = aw883xx_cali_get_r0(aw_dev, is_single, cali_params);
|
|
break;
|
|
case AW_DEV_RE_RANGE_PARAMS:
|
|
ret = aw883xx_cali_get_re_range(aw_dev, is_single, cali_params);
|
|
break;
|
|
case AW_DEV_CALI_RE_PARAMS:
|
|
ret = aw883xx_cali_re_show(aw_dev, is_single, cali_params);
|
|
break;
|
|
case AW_DEV_CALI_F0_PARAMS:
|
|
ret = aw883xx_cali_f0_show(aw_dev, is_single, cali_params);
|
|
break;
|
|
case AW_DEV_CALI_Q_PARAMS:
|
|
ret = aw883xx_cali_q_show(aw_dev, is_single, cali_params);
|
|
break;
|
|
case AW_DEV_CALI_TIME_PARAMS:
|
|
return aw883xx_cali_show_cali_time((uint32_t *)cali_data);
|
|
case AW_DEV_DSP_RE_PARAMS:
|
|
return aw883xx_cali_read_re_from_dsp(aw_dev, (uint32_t *)cali_data);
|
|
default:
|
|
aw_dev_err(aw_dev->dev, "unsupported type:%d", type);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
memcpy(msg_hdr->msg, cali_params, sizeof(cali_params));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aw_dev_set_cali_msg(struct aw_device *aw_dev, void *cali_data, dev_params_t type)
|
|
{
|
|
struct cali_msg_hdr *msg_hdr = NULL;
|
|
uint32_t *set_params = NULL;
|
|
int ret = -1;
|
|
|
|
if (cali_data == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
set_params = (uint32_t *)cali_data;
|
|
|
|
switch (type) {
|
|
case AW_DEV_CALI_RE_PARAMS:
|
|
ret = aw883xx_cail_re_cali(aw_dev, (aw_single_t)set_params[0]);
|
|
break;
|
|
case AW_DEV_CALI_RE_F0_PARAMS:
|
|
ret = aw883xx_cali_re_f0_cali(aw_dev, (aw_single_t)set_params[0]);
|
|
break;
|
|
case AW_DEV_CALI_F0_Q_PARAMS:
|
|
ret = aw883xx_cali_f0_q_cali(aw_dev, (aw_single_t)set_params[0]);
|
|
break;
|
|
case AW_DEV_CALI_TIME_PARAMS:
|
|
ret = aw883xx_cali_store_cali_time(set_params[0]);
|
|
break;
|
|
case AW_DEV_STORE_CALI_RE_PARAMS:
|
|
msg_hdr = (struct cali_msg_hdr *)cali_data;
|
|
ret = aw883xx_cali_store_cali_re(aw_dev, (aw_single_t)msg_hdr->opcode_id, &msg_hdr->msg[0]);
|
|
break;
|
|
default:
|
|
aw_dev_err(aw_dev->dev, "unsupported type:%d", type);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
static int aw_dev_set_params(struct aw_device *aw_dev, dev_params_t type, void *params, uint8_t len)
|
|
{
|
|
uint32_t *set_params = NULL;
|
|
if ((params == NULL) || (len == 0)) {
|
|
aw_dev_err(aw_dev->dev, "input params error");
|
|
return -EINVAL;
|
|
}
|
|
|
|
set_params = (uint32_t *)params;
|
|
|
|
switch (type) {
|
|
case AW_DEV_VOLUME_PARAMS:
|
|
return aw_dev_set_volume(aw_dev, set_params[0]);
|
|
#ifdef AW_FADE
|
|
case AW_DEV_FADE_STEP_PARAMS:
|
|
return aw_dev_set_fade_vol_step(aw_dev, set_params[0]);
|
|
case AW_DEV_FADE_IN_TIME_PARAMS:
|
|
return aw_dev_set_fade_time(set_params[0], AW_FADE_IN_TIME);
|
|
case AW_DEV_FADE_OUT_TIME_PARAMS:
|
|
return aw_dev_set_fade_time(set_params[0], AW_FADE_OUT_TIME);
|
|
#endif
|
|
case AW_DEV_DSP_PARAMS:
|
|
return aw_dev_dsp_enable(aw_dev, set_params[0]);
|
|
case AW_DEV_HMUTE_PARAMS:
|
|
return aw_dev_set_hmute(aw_dev, set_params[0]);
|
|
case AW_DEV_INT_PARAMS:
|
|
return aw_dev_set_intmask(aw_dev, set_params[0]);
|
|
case AW_DEV_CRC_FLAG_PARAMS:
|
|
return aw_dev_set_crc_flag(aw_dev, set_params[0]);
|
|
case AW_DEV_REALTIME_CRC_SET_PARAMS:
|
|
return aw_dev_crc_realtime_set(aw_dev, set_params[0]);
|
|
#ifdef AW_CALIB
|
|
case AW_DEV_CALI_RE_PARAMS:
|
|
case AW_DEV_CALI_RE_F0_PARAMS:
|
|
case AW_DEV_CALI_F0_Q_PARAMS:
|
|
case AW_DEV_CALI_TIME_PARAMS:
|
|
case AW_DEV_STORE_CALI_RE_PARAMS:
|
|
return aw_dev_set_cali_msg(aw_dev, params, type);
|
|
#endif
|
|
default:
|
|
aw_dev_err(aw_dev->dev, "unsupported type:%d", type);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
static int aw_dev_get_params(struct aw_device *aw_dev, dev_params_t type, void *params, uint8_t len)
|
|
{
|
|
int ret = -1;
|
|
if ((params == NULL) || (len == 0)) {
|
|
aw_dev_err(aw_dev->dev, "input params error");
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (type) {
|
|
case AW_DEV_VOLUME_PARAMS:
|
|
ret = aw_dev_get_volume(aw_dev, params);
|
|
break;
|
|
#ifdef AW_FADE
|
|
case AW_DEV_FADE_STEP_PARAMS:
|
|
ret = aw_dev_get_fade_vol_step(aw_dev, params);
|
|
break;
|
|
case AW_DEV_FADE_IN_TIME_PARAMS:
|
|
ret = aw_dev_get_fade_time(params, AW_FADE_IN_TIME);
|
|
break;
|
|
case AW_DEV_FADE_OUT_TIME_PARAMS:
|
|
ret = aw_dev_get_fade_time(params, AW_FADE_OUT_TIME);
|
|
break;
|
|
#endif
|
|
case AW_DEV_INT_PARAMS:
|
|
ret = aw_dev_get_int_status(aw_dev, params);
|
|
break;
|
|
case AW_DEV_HMUTE_PARAMS:
|
|
ret = aw_dev_get_hmute(aw_dev, params);
|
|
break;
|
|
case AW_DEV_SYSST_PARAMS:
|
|
ret = aw_dev_get_sysst_value(aw_dev, params);
|
|
break;
|
|
case AW_DEV_REALTIME_CRC_GET_PARAMS:
|
|
ret = aw_dev_crc_realtime_get(aw_dev, params);
|
|
break;
|
|
#ifdef AW_CALIB
|
|
case AW_DEV_TE_PARAMS:
|
|
case AW_DEV_F0_PARAMS:
|
|
case AW_DEV_R0_PARAMS:
|
|
case AW_DEV_RE_RANGE_PARAMS:
|
|
case AW_DEV_CALI_RE_PARAMS:
|
|
case AW_DEV_CALI_F0_PARAMS:
|
|
case AW_DEV_CALI_Q_PARAMS:
|
|
case AW_DEV_CALI_TIME_PARAMS:
|
|
case AW_DEV_DSP_RE_PARAMS:
|
|
ret = aw_dev_get_cali_msg(aw_dev, params, type);
|
|
break;
|
|
#endif
|
|
default:
|
|
aw_dev_err(aw_dev->dev, "unsupported type:%d", type);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int aw883xx_device_params(struct aw_device *aw_dev, dev_params_t params_type,
|
|
void *data, uint8_t size, params_option_t params_ops)
|
|
{
|
|
if (params_ops == AW_SET_DEV_PARAMS) {
|
|
return aw_dev_set_params(aw_dev, params_type, data, size);
|
|
} else if (params_ops == AW_GET_DEV_PARAMS) {
|
|
return aw_dev_get_params(aw_dev, params_type, data, size);
|
|
} else {
|
|
aw_dev_err(aw_dev->dev, "unsupported params_ops:%d", params_ops);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
static bool aw_dev_get_status(struct aw_device *aw_dev, dev_status_t type)
|
|
{
|
|
switch (type) {
|
|
case AW_DEV_PLL_WDT_STATUS:
|
|
return aw_dev_get_pll_wdt_status(aw_dev);
|
|
default:
|
|
aw_dev_err(aw_dev->dev, "unsupported type:%d", type);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static void aw_dev_set_status(struct aw_device *aw_dev, dev_status_t type)
|
|
{
|
|
switch (type) {
|
|
#ifdef AW_IRQ
|
|
case AW_DEV_INTERRUPT_CLEAR_STATUS:
|
|
aw_dev_interrupt_clear(aw_dev);
|
|
break;
|
|
#endif
|
|
case AW_DEV_CLEAR_INT_STATUS:
|
|
aw_dev_clear_int_status(aw_dev);
|
|
break;
|
|
case AW_DEV_SOFT_RESET_STATUS:
|
|
aw_dev_soft_reset(aw_dev);
|
|
break;
|
|
case AW_DEV_REG_DUMP_STATUS:
|
|
aw883xx_dev_reg_dump(aw_dev);
|
|
break;
|
|
default:
|
|
aw_dev_err(aw_dev->dev, "unsupported type:%d", type);
|
|
return;
|
|
}
|
|
}
|
|
|
|
bool aw883xx_device_status(struct aw_device *aw_dev, dev_status_t type, status_option_t status_ops)
|
|
{
|
|
if (status_ops == AW_SET_DEV_STATUS) {
|
|
aw_dev_set_status(aw_dev, type);
|
|
return true;
|
|
} else if (status_ops == AW_GET_DEV_STATUS) {
|
|
return aw_dev_get_status(aw_dev, type);
|
|
} else {
|
|
aw_dev_err(aw_dev->dev, "unsupported status_ops:%d", status_ops);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
int aw883xx_device_start(struct aw_device *aw_dev)
|
|
{
|
|
int ret = -1;
|
|
struct aw_dither_desc *dither_desc = &aw_dev->dither_desc;
|
|
|
|
aw_dev_info(aw_dev->dev, "enter");
|
|
|
|
if (aw_dev->status == AW_DEV_PW_ON) {
|
|
aw_dev_info(aw_dev->dev, "already power on");
|
|
return 0;
|
|
}
|
|
|
|
aw_dev_set_dither(aw_dev, false);
|
|
|
|
/*power on*/
|
|
aw_dev_pwd(aw_dev, false);
|
|
AW_MS_DELAY(AW_2_MS);
|
|
|
|
ret = aw_dev_syspll_check(aw_dev);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "pll check failed cannot start");
|
|
aw883xx_dev_reg_dump(aw_dev);
|
|
goto pll_check_fail;
|
|
}
|
|
|
|
/*amppd on*/
|
|
aw_dev_amppd(aw_dev, false);
|
|
AW_MS_DELAY(AW_1_MS);
|
|
|
|
/*check i2s status*/
|
|
ret = aw883xx_dev_sysst_check(aw_dev);
|
|
if (ret < 0) {
|
|
/*check failed*/
|
|
aw883xx_dev_reg_dump(aw_dev);
|
|
goto sysst_check_fail;
|
|
}
|
|
|
|
if (aw_dev->dsp_cfg == AW_DEV_DSP_WORK) {
|
|
aw_dev_backup_sec_recovery(aw_dev);
|
|
ret = aw_dev_crc_check(aw_dev);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "crc check failed");
|
|
aw883xx_dev_reg_dump(aw_dev);
|
|
goto crc_check_fail;
|
|
}
|
|
|
|
/*dsp bypass*/
|
|
aw_dev_dsp_enable(aw_dev, AW_DEV_DSP_BYPASS);
|
|
|
|
aw_dev_set_vcalb(aw_dev);
|
|
#ifdef AW_CALIB
|
|
aw_dev_cali_re_update(aw_dev);
|
|
#endif
|
|
|
|
ret = aw883xx_dev_dsp_check(aw_dev);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "check dsp status failed");
|
|
aw883xx_dev_reg_dump(aw_dev);
|
|
goto dsp_check_fail;
|
|
}
|
|
} else {
|
|
aw_dev_dbg(aw_dev->dev, "start pa with dsp bypass");
|
|
}
|
|
|
|
/*enable tx feedback*/
|
|
if (aw_dev->ops.aw_i2s_tx_enable) {
|
|
if (aw_dev->txen_st) {
|
|
aw_dev->ops.aw_i2s_tx_enable(aw_dev, true);
|
|
}
|
|
}
|
|
|
|
if(aw_dev->dither_st == dither_desc->enable) {
|
|
aw_dev_set_dither(aw_dev, true);
|
|
}
|
|
|
|
/*close mute*/
|
|
if (aw883xx_cali_check_result(&aw_dev->cali_desc)) {
|
|
aw_dev_set_hmute(aw_dev, AW_DEV_HMUTE_DISABLE);
|
|
} else {
|
|
aw_dev_set_hmute(aw_dev, AW_DEV_HMUTE_ENABLE);
|
|
}
|
|
/*clear inturrupt*/
|
|
aw_dev_clear_int_status(aw_dev);
|
|
/*set inturrupt mask*/
|
|
aw_dev_set_intmask(aw_dev, AW_DEV_UNMASK_INT_VAL);
|
|
|
|
if (aw_dev->ops.aw_monitor_start) {
|
|
aw_dev->ops.aw_monitor_start((void *)aw_dev);
|
|
}
|
|
|
|
aw_dev->status = AW_DEV_PW_ON;
|
|
|
|
aw_dev_info(aw_dev->dev, "done");
|
|
|
|
return 0;
|
|
|
|
dsp_check_fail:
|
|
crc_check_fail:
|
|
aw_dev_dsp_enable(aw_dev, AW_DEV_DSP_BYPASS);
|
|
sysst_check_fail:
|
|
/*clear interrupt*/
|
|
aw_dev_clear_int_status(aw_dev);
|
|
aw_dev_amppd(aw_dev, true);
|
|
pll_check_fail:
|
|
aw_dev_pwd(aw_dev, true);
|
|
aw_dev->status = AW_DEV_PW_OFF;
|
|
return ret;
|
|
}
|
|
|
|
int aw883xx_device_stop(struct aw_device *aw_dev)
|
|
{
|
|
int int_st = 0;
|
|
int monitor_int_st = 0;
|
|
uint16_t reg_data = 0;
|
|
|
|
aw_dev_info(aw_dev->dev, "enter");
|
|
|
|
aw_dev->ops.aw_reg_read(aw_dev, aw_dev->pwd_desc.reg, ®_data);
|
|
|
|
if ((aw_dev->status == AW_DEV_PW_OFF) &&
|
|
(reg_data & aw_dev->pwd_desc.enable)) {
|
|
aw_dev_info(aw_dev->dev, "already power off");
|
|
return 0;
|
|
}
|
|
|
|
aw_dev->status = AW_DEV_PW_OFF;
|
|
|
|
if (aw_dev->ops.aw_monitor_stop) {
|
|
aw_dev->ops.aw_monitor_stop((void *)aw_dev);
|
|
}
|
|
|
|
/*set mute*/
|
|
aw_dev_set_hmute(aw_dev, AW_DEV_HMUTE_ENABLE);
|
|
AW_MS_DELAY(AW_4_MS);
|
|
|
|
/*close tx feedback*/
|
|
if (aw_dev->ops.aw_i2s_tx_enable) {
|
|
aw_dev->ops.aw_i2s_tx_enable(aw_dev, false);
|
|
}
|
|
AW_MS_DELAY(AW_1_MS);
|
|
|
|
/*set defaut int mask*/
|
|
aw_dev_set_intmask(aw_dev, AW_DEV_MASK_INT_VAL);
|
|
|
|
/*check sysint state*/
|
|
int_st = aw_dev_sysint_check(aw_dev);
|
|
|
|
/*close dsp*/
|
|
aw_dev_dsp_enable(aw_dev, AW_DEV_DSP_BYPASS);
|
|
|
|
/*enable amppd*/
|
|
aw_dev_amppd(aw_dev, true);
|
|
|
|
/*check monitor process sysint state*/
|
|
monitor_int_st = aw_dev_get_monitor_sysint_st(aw_dev);
|
|
|
|
if (int_st < 0 || monitor_int_st < 0) {
|
|
/*system status anomaly*/
|
|
aw_dev_memclk_select(aw_dev, AW_DEV_MEMCLK_OSC);
|
|
aw_dev_sram_check(aw_dev);
|
|
aw_dev_dsp_fw_update(aw_dev);
|
|
aw_dev_dsp_cfg_update(aw_dev);
|
|
aw_dev_memclk_select(aw_dev, AW_DEV_MEMCLK_PLL);
|
|
}
|
|
|
|
/*set power down*/
|
|
aw_dev_pwd(aw_dev, true);
|
|
|
|
aw_dev_info(aw_dev->dev, "done");
|
|
return 0;
|
|
}
|
|
|
|
static int aw_device_init(struct aw_device *aw_dev)
|
|
{
|
|
int ret = -1;
|
|
|
|
if (aw_dev == NULL) {
|
|
aw_pr_err("aw_dev is NULL");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
strncpy(aw_dev->cur_prof_name, aw_dev->first_prof_name, AW_PROF_NAME_MAX);
|
|
strncpy(aw_dev->set_prof_name, aw_dev->first_prof_name, AW_PROF_NAME_MAX);
|
|
|
|
ret = aw883xx_device_fw_update(aw_dev, AW_FORCE_UPDATE_ON,
|
|
AW_DSP_FW_UPDATE_ON);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "fw update failed");
|
|
return ret;
|
|
}
|
|
|
|
aw_dev_set_intmask(aw_dev, AW_DEV_MASK_INT_VAL);
|
|
|
|
/*set mute*/
|
|
aw_dev_set_hmute(aw_dev, AW_DEV_HMUTE_ENABLE);
|
|
|
|
/*close tx feedback*/
|
|
if (aw_dev->ops.aw_i2s_tx_enable) {
|
|
aw_dev->ops.aw_i2s_tx_enable(aw_dev, false);
|
|
}
|
|
AW_MS_DELAY(AW_1_MS);
|
|
|
|
/*enable amppd*/
|
|
aw_dev_amppd(aw_dev, true);
|
|
/*close dsp*/
|
|
aw_dev_dsp_enable(aw_dev, AW_DEV_DSP_BYPASS);
|
|
/*set power down*/
|
|
aw_dev_pwd(aw_dev, true);
|
|
|
|
aw_dev_info(aw_dev->dev, "init done");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int aw883xx_device_probe(struct aw_device *aw_dev, struct aw_init_info *init_info)
|
|
{
|
|
int ret = -1;
|
|
|
|
ret = aw_dev_prof_init(aw_dev, init_info);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "prof init failed");
|
|
return ret;
|
|
}
|
|
|
|
aw883xx_dev_get_monitor_func(aw_dev);
|
|
|
|
if(aw_dev->ops.aw_monitor_init) {
|
|
ret = aw_dev->ops.aw_monitor_init((void *)aw_dev);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "monitor init failed");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
ret = aw_device_init(aw_dev);
|
|
if (ret < 0) {
|
|
aw_dev_err(aw_dev->dev, "dev init failed");
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|