ASoC: codecs: add aw883xx smart PA

Signed-off-by: XiaoTan Luo <lxt@rock-chips.com>
Change-Id: Iad30b10913ff922e71ec21cdb59ddd829ca69164
This commit is contained in:
XiaoTan Luo
2022-04-22 18:13:12 +08:00
committed by Tao Huang
parent 43c50a5fca
commit 7e755ee50b
20 changed files with 14638 additions and 0 deletions

View File

@@ -1874,4 +1874,5 @@ config SND_SOC_TPA6130A2
depends on I2C
source "sound/soc/codecs/aw87xxx/Kconfig"
source "sound/soc/codecs/aw883xx/Kconfig"
endmenu

View File

@@ -640,6 +640,7 @@ obj-$(CONFIG_SND_SOC_ZX_AUD96P22) += snd-soc-zx-aud96p22.o
# Amp
obj-$(CONFIG_SND_SOC_AW87XXX) += aw87xxx/
obj-$(CONFIG_SND_SOC_AW883XX) += aw883xx/
obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o
obj-$(CONFIG_SND_SOC_MAX98504) += snd-soc-max98504.o
obj-$(CONFIG_SND_SOC_SIMPLE_AMPLIFIER) += snd-soc-simple-amplifier.o

View File

@@ -0,0 +1,5 @@
config SND_SOC_AW883XX
tristate "SoC Audio for awinic AW883XX series Smart PA"
depends on I2C
help
This option enables support for AW883XX series Smart PA.

View File

@@ -0,0 +1,3 @@
#for AWINIC AW883XX Smart PA
snd-soc-aw883xx-objs := aw883xx.o aw_device.o aw_monitor.o aw_bin_parse.o aw_init.o aw_calib.o aw_spin.o
obj-$(CONFIG_SND_SOC_AW883XX) += snd-soc-aw883xx.o

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,201 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __AW883XX_H__
#define __AW883XX_H__
#include <linux/version.h>
#include <sound/control.h>
#include <sound/soc.h>
#include "aw_device.h"
/*#define AW_QCOM_PLATFORM*/
#define AW_MTK_PLATFORM
/*#define AW_SPRD_PLATFORM*/
#define AW883XX_CHIP_ID_REG (0x00)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 1)
#define AW_KERNEL_VER_OVER_4_19_1
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
#define AW_KERNEL_VER_OVER_5_4_0
MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);
#endif
/* i2c transaction on Linux limited to 64k
* (See Linux kernel documentation: Documentation/i2c/writing-clients)
*/
#define MAX_I2C_BUFFER_SIZE (65536)
#define AW883XX_READ_MSG_NUM (2)
#define AW_I2C_RETRIES (5)
#define AW_I2C_RETRY_DELAY (5)/* 5ms */
#define AW_READ_CHIPID_RETRY_DELAY (5)/* 5ms */
#define AW_START_RETRIES (5)
#define AW883XX_FLAG_START_ON_MUTE (1 << 0)
#define AW883XX_FLAG_SKIP_INTERRUPTS (1 << 1)
#define AW883XX_I2S_CHECK_MAX (5)
#define AW883XX_SYSST_CHECK_MAX (10)
#define AW883XX_BIN_TYPE_NUM (3)
#define AW883XX_LOAD_FW_DELAY_TIME (3000)
#define AW883XX_START_WORK_DELAY_MS (0)
#define AW883XX_DSP_16_DATA_MASK (0x0000ffff)
#define AW_GET_IV_CNT_MAX (6)
#define AW_KCONTROL_NUM (3)
#define AW_HW_MONITOR_DELAY (1000)
enum {
AWRW_I2C_ST_NONE = 0,
AWRW_I2C_ST_READ,
AWRW_I2C_ST_WRITE,
};
enum {
AWRW_DSP_ST_NONE = 0,
AWRW_DSP_READY,
};
enum {
AW_SYNC_START = 0,
AW_ASYNC_START,
};
#define AWRW_ADDR_BYTES (1)
#define AWRW_DATA_BYTES (2)
#define AWRW_HDR_LEN (24)
enum {
AWRW_FLAG_WRITE = 0,
AWRW_FLAG_READ,
};
enum {
AWRW_HDR_WR_FLAG = 0,
AWRW_HDR_ADDR_BYTES,
AWRW_HDR_DATA_BYTES,
AWRW_HDR_REG_NUM,
AWRW_HDR_REG_ADDR,
AWRW_HDR_MAX,
};
struct aw883xx_i2c_packet{
unsigned char i2c_status;
unsigned char dsp_status;
unsigned int reg_num;
unsigned int reg_addr;
unsigned int dsp_addr;
char *reg_data;
};
enum {
AW883XX_STREAM_CLOSE = 0,
AW883XX_STREAM_OPEN,
};
enum aw883xx_init {
AW883XX_INIT_ST = 0,
AW883XX_INIT_OK = 1,
AW883XX_INIT_NG = 2,
};
enum aw_re_range {
AW_RE_MIN = 1000,
AW_RE_MAX = 40000,
};
/********************************************
*
* Compatible with codec and component
*
*******************************************/
#ifdef AW_KERNEL_VER_OVER_4_19_1
typedef struct snd_soc_component aw_snd_soc_codec_t;
typedef struct snd_soc_component_driver aw_snd_soc_codec_driver_t;
#else
typedef struct snd_soc_codec aw_snd_soc_codec_t;
typedef struct snd_soc_codec_driver aw_snd_soc_codec_driver_t;
#endif
struct aw_componet_codec_ops {
aw_snd_soc_codec_t *(*kcontrol_codec)(struct snd_kcontrol *kcontrol);
void *(*codec_get_drvdata)(aw_snd_soc_codec_t *codec);
int (*add_codec_controls)(aw_snd_soc_codec_t *codec,
const struct snd_kcontrol_new *controls, unsigned int num_controls);
void (*unregister_codec)(struct device *dev);
int (*register_codec)(struct device *dev,
const aw_snd_soc_codec_driver_t *codec_drv,
struct snd_soc_dai_driver *dai_drv,
int num_dai);
};
struct aw883xx {
struct i2c_client *i2c;
struct device *dev;
struct clk *mclk;
struct mutex lock;
struct mutex i2c_lock;
aw_snd_soc_codec_t *codec;
struct aw_componet_codec_ops *codec_ops;
struct aw_device *aw_pa;
int sysclk;
int reset_gpio;
int irq_gpio;
unsigned char phase_sync; /*phase sync*/
uint32_t allow_pw;
uint8_t pstream;
unsigned char fw_retry_cnt;
uint8_t dbg_en_prof;
uint8_t i2c_log_en;
uint8_t spin_flag;
struct list_head list;
struct workqueue_struct *work_queue;
struct delayed_work start_work;
struct delayed_work monitor_work;
struct delayed_work interrupt_work;
struct delayed_work acf_work;
uint8_t reg_addr;
uint16_t dsp_addr;
uint16_t chip_id;
struct aw883xx_i2c_packet i2c_packet;
};
int aw883xx_init(struct aw883xx *aw883xx);
int aw883xx_i2c_writes(struct aw883xx *aw883xx,
uint8_t reg_addr, uint8_t *buf, uint16_t len);
int aw883xx_i2c_write(struct aw883xx *aw883xx,
uint8_t reg_addr, uint16_t reg_data);
int aw883xx_reg_write(struct aw883xx *aw883xx,
uint8_t reg_addr, uint16_t reg_data);
int aw883xx_i2c_read(struct aw883xx *aw883xx,
uint8_t reg_addr, uint16_t *reg_data);
int aw883xx_reg_read(struct aw883xx *aw883xx,
uint8_t reg_addr, uint16_t *reg_data);
int aw883xx_reg_write_bits(struct aw883xx *aw883xx,
uint8_t reg_addr, uint16_t mask, uint16_t reg_data);
int aw883xx_dsp_write(struct aw883xx *aw883xx,
uint16_t dsp_addr, uint32_t dsp_data, uint8_t data_type);
int aw883xx_dsp_read(struct aw883xx *aw883xx,
uint16_t dsp_addr, uint32_t *dsp_data, uint8_t data_type);
int aw883xx_get_dev_num(void);
int aw883xx_get_version(char *buf, int size);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,141 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __AW_BIN_PARSE_H__
#define __AW_BIN_PARSE_H__
#include "aw_device.h"
#define NULL ((void *)0)
#define GET_32_DATA(w, x, y, z) ((unsigned int)((((uint8_t)w) << 24) | (((uint8_t)x) << 16) | (((uint8_t)y) << 8) | ((uint8_t)z)))
#define BIN_NUM_MAX 100
#define HEADER_LEN 60
/*********************************************************
*
* header information
*
********************************************************/
enum return_enum {
BIN_HEADER_VER_ERR = 1,
BIN_DATA_TYPE_ERR = 2,
BIN_DATA_LEN_ERR = 3,
DATA_VER_ERR = 4,
REG_NUM_ERR = 5,
DSP_REG_NUM_ERR = 6,
SOC_APP_NUM_ERR = 7,
BIN_IS_NULL = 8,
};
enum bin_header_version_enum {
HEADER_VERSION_1_0_0 = 0x01000000,
};
enum data_type_enum {
DATA_TYPE_REGISTER = 0x00000000,
DATA_TYPE_DSP_REG = 0x00000010,
DATA_TYPE_DSP_CFG = 0x00000011,
DATA_TYPE_SOC_REG = 0x00000020,
DATA_TYPE_SOC_APP = 0x00000021,
DATA_TYPE_DSP_FW = DATA_TYPE_SOC_APP,
DATA_TYPE_MULTI_BINS = 0x00002000,
};
/**
* @DATA_VERSION_V1default little edian
*/
enum data_version_enum {
DATA_VERSION_V1 = 0X00000001,
DATA_VERSION_MAX,
};
/**
* @header_len: Frame header length
* @check_sum: Frame header information-Checksum
* @header_ver: Frame header information-Frame header version
* @bin_data_type: Frame header information-Data type
* @bin_data_ver: Frame header information-Data version
* @bin_data_len: Frame header information-Data length
* @ui_ver: Frame header information-ui version
* @chip_type[8]: Frame header information-chip type
* @reg_byte_len: Frame header information-reg byte len
* @data_byte_len: Frame header information-data byte len
* @device_addr: Frame header information-device addr
* @valid_data_len: Length of valid data obtained after parsing
* @valid_data_addr: The offset address of the valid data obtained
* after parsing relative to info
* @reg_num: The number of registers obtained after parsing
* @reg_data_byte_len: The byte length of the register obtained after parsing
* @download_addr: The starting address or download address obtained
* after parsing
* @app_version: The software version number obtained after parsing
*/
struct bin_header_info {
unsigned int header_len;
unsigned int check_sum;
unsigned int header_ver;
unsigned int bin_data_type;
unsigned int bin_data_ver;
unsigned int bin_data_len;
unsigned int ui_ver;
unsigned char chip_type[8];
unsigned int reg_byte_len;
unsigned int data_byte_len;
unsigned int device_addr;
unsigned int valid_data_len;
unsigned int valid_data_addr;
unsigned int reg_num;
unsigned int reg_data_byte_len;
unsigned int download_addr;
unsigned int app_version;
};
/************************************************************
*
* function define
*
************************************************************/
/**
* @len: The size of the bin file obtained from the firmware
* @data[]: Store the bin file obtained from the firmware
*/
struct bin_container {
unsigned int len;
unsigned char data[];
};
/**
* @p_addr: Offset pointer (backward offset pointer to obtain frame header
* information and important information)
* @all_bin_parse_num: The number of all bin files
* @multi_bin_parse_num: The number of single bin files
* @single_bin_parse_num: The number of multiple bin files
* @header_info[BIN_NUM_MAX]: Frame header information and other important data
* obtained after parsing
* @info: Obtained bin file data that needs to be parsed
*/
struct aw_bin {
unsigned char *p_addr;
unsigned int all_bin_parse_num;
unsigned int multi_bin_parse_num;
unsigned int single_bin_parse_num;
struct bin_header_info header_info[BIN_NUM_MAX];
struct bin_container info;
};
int aw_parsing_bin_file(struct aw_bin *bin);
int aw_parse_bin_header_1_0_0(struct aw_bin *bin);
/*******************awinic audio parse acf***********************/
int aw_dev_dsp_data_order(struct aw_device *aw_dev,
uint8_t *data, uint32_t data_len);
int aw_dev_get_prof_data(struct aw_device *aw_dev, int index,
struct aw_prof_desc **prof_desc);
char *aw_dev_get_prof_name(struct aw_device *aw_dev, int index);
int aw_dev_set_profile_index(struct aw_device *aw_dev, int index);
int aw_dev_get_profile_index(struct aw_device *aw_dev);
int aw_dev_check_profile_index(struct aw_device *aw_dev, int index);
int aw_dev_get_profile_count(struct aw_device *aw_dev);
int aw_dev_cfg_load(struct aw_device *aw_dev, struct aw_container *aw_cfg);
int aw_dev_load_acf_check(struct aw_container *aw_cfg);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,147 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __AWINIC_CALIBRATION_H__
#define __AWINIC_CALIBRATION_H__
/*#define AW_CALI_STORE_EXAMPLE*/
#define AW_CALI_STORE_EXAMPLE
#define AW_ERRO_CALI_RE_VALUE (0)
#define AW_ERRO_CALI_F0_VALUE (2600)
#define AW_CALI_RE_DEFAULT_TIMER (3000)
#define MSGS_SIZE (512)
#define RESERVED_SIZE (252)
#define AW_CALI_ALL_DEV (0xFFFFFFFF)
#define AW_CALI_RE_MAX (15000)
#define AW_CALI_RE_MIN (4000)
#define AW_CALI_CFG_NUM (4)
#define AW_CALI_F0_DATA_NUM (4)
#define AW_CALI_READ_CNT_MAX (8)
#define AW_CALI_DATA_SUM_RM (2)
#define AW_DSP_RE_TO_SHOW_RE(re, shift) (((re) * (1000)) >> (shift))
#define AW_SHOW_RE_TO_DSP_RE(re, shift) (((re) << shift) / (1000))
#define AW_CALI_F0_TIME (5 * 1000)
#define F0_READ_CNT_MAX (5)
#define AW_FS_CFG_MAX (11)
#define AW_DEV_CH_MAX (16)
#define AW_DEV_RE_RANGE (RE_RANGE_NUM * AW_DEV_CH_MAX)
#define AW_TE_CACL_VALUE(te, coil_alpha) ((int32_t)(((int32_t)te << 18) / (coil_alpha)))
#define AW_RE_REALTIME_VALUE(re_cacl, te_cacl) ((re_cacl) + (int32_t)((int64_t)((te_cacl) * (re_cacl)) >> 14))
enum {
CALI_CHECK_DISABLE = 0,
CALI_CHECK_ENABLE = 1,
};
enum {
CALI_RESULT_NONE = 0,
CALI_RESULT_NORMAL = 1,
CALI_RESULT_ERROR = -1,
};
enum {
CALI_OPS_HMUTE = 0X0001,
CALI_OPS_NOISE = 0X0002,
};
enum {
CALI_TYPE_RE = 0,
CALI_TYPE_F0,
};
enum{
AW_CALI_MODE_NONE = 0,
AW_CALI_MODE_ATTR,
AW_CALI_MODE_CLASS,
AW_CALI_MODE_MISC,
AW_CALI_MODE_MAX
};
enum {
GET_RE_TYPE = 0,
GET_F0_TYPE,
GET_Q_TYPE,
};
enum {
AW_CALI_CMD_RE = 0,
AW_CALI_CMD_F0,
AW_CALI_CMD_RE_F0,
AW_CALI_CMD_F0_Q,
AW_CALI_CMD_RE_F0_Q,
};
enum {
CALI_STR_NONE = 0,
CALI_STR_CALI_RE_F0,
CALI_STR_CALI_RE,
CALI_STR_CALI_F0,
CALI_STR_SET_RE,
CALI_STR_SHOW_RE, /*show cali_re*/
CALI_STR_SHOW_R0, /*show real r0*/
CALI_STR_SHOW_CALI_F0, /*GET DEV CALI_F0*/
CALI_STR_SHOW_F0, /*SHOW REAL F0*/
CALI_STR_SHOW_TE,
CALI_STR_DEV_SEL, /*switch device*/
CALI_STR_VER,
CALI_STR_SHOW_RE_RANGE,
CALI_STR_MAX,
};
enum {
RE_MIN_FLAG = 0,
RE_MAX_FLAG = 1,
RE_RANGE_NUM = 2,
};
struct re_data {
uint32_t re_range[2];
};
#define AW_IOCTL_MAGIC 'a'
#define AW_IOCTL_GET_F0 _IOWR(AW_IOCTL_MAGIC, 5, int32_t)
#define AW_IOCTL_SET_CALI_RE _IOWR(AW_IOCTL_MAGIC, 6, int32_t)
#define AW_IOCTL_GET_RE _IOWR(AW_IOCTL_MAGIC, 17, int32_t)
#define AW_IOCTL_GET_CALI_F0 _IOWR(AW_IOCTL_MAGIC, 18, int32_t)
#define AW_IOCTL_GET_REAL_R0 _IOWR(AW_IOCTL_MAGIC, 19, int32_t)
#define AW_IOCTL_GET_TE _IOWR(AW_IOCTL_MAGIC, 20, int32_t)
#define AW_IOCTL_GET_RE_RANGE _IOWR(AW_IOCTL_MAGIC, 21, struct re_data)
struct cali_cfg {
uint32_t data[AW_CALI_CFG_NUM];
};
struct aw_cali_desc {
bool status;
struct cali_cfg cali_cfg;
uint16_t store_vol;
uint32_t cali_re; /*cali value*/
uint32_t f0;
uint32_t q;
uint32_t ra;
int8_t cali_result;
uint8_t cali_check_st;
};
void aw_cali_init(struct aw_cali_desc *cali_desc);
void aw_cali_deinit(struct aw_cali_desc *cali_desc);
bool aw_cali_svc_get_cali_status(struct aw_cali_desc *cali_desc);
int aw_cali_svc_set_cali_re_to_dsp(struct aw_cali_desc *cali_desc);
int aw_cali_svc_get_ra(struct aw_cali_desc *cali_desc);
int aw_cali_svc_get_dev_te(struct aw_cali_desc *cali_desc, int32_t *te);
int aw_cali_get_cali_re(struct aw_cali_desc *cali_desc);
int aw_cali_read_cali_re_from_dsp(struct aw_cali_desc *cali_desc, uint32_t *re);
#endif

View File

@@ -0,0 +1,150 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __AWINIC_DATA_TYPE_H__
#define __AWINIC_DATA_TYPE_H__
#define AW_NAME_BUF_MAX (50)
/******************************************************************
* aw profile
*******************************************************************/
#define PROJECT_NAME_MAX (24)
#define CUSTOMER_NAME_MAX (16)
#define CFG_VERSION_MAX (4)
#define DEV_NAME_MAX (16)
#define PROFILE_STR_MAX (32)
#define ACF_FILE_ID (0xa15f908)
struct aw_msg_hdr {
int32_t type;
int32_t opcode_id;
int32_t version;
int32_t reseriver[3];
};
enum aw_cfg_hdr_version {
AW_CFG_HDR_VER_0_0_0_1 = 0x00000001,
AW_CFG_HDR_VER_1_0_0_0 = 0x01000000,
};
enum aw_cfg_dde_type {
AW_DEV_NONE_TYPE_ID = 0xFFFFFFFF,
AW_DEV_TYPE_ID = 0x00000000,
AW_SKT_TYPE_ID = 0x00000001,
AW_DEV_DEFAULT_TYPE_ID = 0x00000002,
};
enum aw_sec_type {
ACF_SEC_TYPE_REG = 0,
ACF_SEC_TYPE_DSP,
ACF_SEC_TYPE_DSP_CFG,
ACF_SEC_TYPE_DSP_FW,
ACF_SEC_TYPE_HDR_REG,
ACF_SEC_TYPE_HDR_DSP_CFG,
ACF_SEC_TYPE_HDR_DSP_FW,
ACF_SEC_TYPE_MUTLBIN,
ACF_SEC_TYPE_SKT_PROJECT,
ACF_SEC_TYPE_DSP_PROJECT,
ACF_SEC_TYPE_MONITOR,
ACF_SEC_TYPE_MAX,
};
enum profile_data_type {
AW_DATA_TYPE_REG = 0,
AW_DATA_TYPE_DSP_CFG,
AW_DATA_TYPE_DSP_FW,
AW_DATA_TYPE_MAX,
};
enum aw_prof_type {
AW_PROFILE_MUSIC = 0,
AW_PROFILE_VOICE,
AW_PROFILE_VOIP,
AW_PROFILE_RINGTONE,
AW_PROFILE_RINGTONE_HS,
AW_PROFILE_LOWPOWER,
AW_PROFILE_BYPASS,
AW_PROFILE_MMI,
AW_PROFILE_FM,
AW_PROFILE_NOTIFICATION,
AW_PROFILE_RECEIVER,
AW_PROFILE_MAX,
};
enum aw_profile_status {
AW_PROFILE_WAIT = 0,
AW_PROFILE_OK,
};
struct aw_cfg_hdr {
uint32_t a_id; /*acf file ID 0xa15f908*/
char a_project[PROJECT_NAME_MAX]; /*project name*/
char a_custom[CUSTOMER_NAME_MAX]; /*custom name :huawei xiaomi vivo oppo*/
char a_version[CFG_VERSION_MAX]; /*author update version*/
uint32_t a_author_id; /*author id*/
uint32_t a_ddt_size; /*sub section table entry size*/
uint32_t a_ddt_num; /*sub section table entry num*/
uint32_t a_hdr_offset; /*sub section table offset in file*/
uint32_t a_hdr_version; /*sub section table version*/
uint32_t reserve[3];
};
struct aw_cfg_dde {
uint32_t type; /*DDE type id*/
char dev_name[DEV_NAME_MAX];
uint16_t dev_index; /*dev id*/
uint16_t dev_bus; /*dev bus id*/
uint16_t dev_addr; /*dev addr id*/
uint16_t dev_profile; /*dev profile id*/
uint32_t data_type; /*data type id*/
uint32_t data_size;
uint32_t data_offset;
uint32_t data_crc;
uint32_t reserve[5];
};
struct aw_cfg_dde_v_1_0_0_0 {
uint32_t type; /*DDE type id*/
char dev_name[DEV_NAME_MAX];
uint16_t dev_index; /*dev id*/
uint16_t dev_bus; /*dev bus id*/
uint16_t dev_addr; /*dev addr id*/
uint16_t dev_profile; /*dev profile id*/
uint32_t data_type; /*data type id*/
uint32_t data_size;
uint32_t data_offset;
uint32_t data_crc;
char dev_profile_str[PROFILE_STR_MAX];
uint32_t chip_id;
uint32_t reserve[4];
};
struct aw_sec_data_desc {
uint32_t len;
unsigned char *data;
};
struct aw_prof_desc {
uint32_t id;
uint32_t prof_st;
char *prf_str;
uint32_t fw_ver;
struct aw_sec_data_desc sec_desc[AW_DATA_TYPE_MAX];
};
struct aw_all_prof_info {
struct aw_prof_desc prof_desc[AW_PROFILE_MAX];
};
struct aw_prof_info {
int count;
int prof_type;
char **prof_name_list;
struct aw_prof_desc *prof_desc;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,533 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __AWINIC_DEVICE_FILE_H__
#define __AWINIC_DEVICE_FILE_H__
#include "aw_spin.h"
#include "aw_monitor.h"
#include "aw_data_type.h"
#include "aw_calib.h"
#define AW_DEV_DEFAULT_CH (0)
#define AW_DEV_I2S_CHECK_MAX (5)
#define AW_DEV_DSP_CHECK_MAX (5)
/********************************************
*
* DSP I2C WRITES
*
*******************************************/
#define AW_DSP_I2C_WRITES
#define AW_MAX_RAM_WRITE_BYTE_SIZE (128)
#define AW_DSP_ODD_NUM_BIT_TEST (0x5555)
#define AW_DSP_EVEN_NUM_BIT_TEST (0xAAAA)
#define AW_DSP_ST_CHECK_MAX (2)
#define AW_FADE_IN_OUT_DEFAULT (0)
#define AW_CALI_DELAY_CACL(value) ((value * 32) / 48)
struct aw_device;
enum {
AW_DEV_VDSEL_DAC = 0,
AW_DEV_VDSEL_VSENSE = 1,
};
enum {
AW_DSP_CRC_NA = 0,
AW_DSP_CRC_OK = 1,
};
enum {
AW_DSP_CRC_DISABLE = 0,
AW_DSP_CRC_ENABLE = 1,
};
enum {
AW_DSP_FW_UPDATE_OFF = 0,
AW_DSP_FW_UPDATE_ON = 1,
};
enum {
AW_FORCE_UPDATE_OFF = 0,
AW_FORCE_UPDATE_ON = 1,
};
enum {
AW_1000_US = 1000,
AW_2000_US = 2000,
AW_3000_US = 3000,
AW_4000_US = 4000,
AW_5000_US = 5000,
AW_10000_US = 10000,
AW_100000_US = 100000,
};
enum {
AW_DEV_TYPE_OK = 0,
AW_DEV_TYPE_NONE = 1,
};
enum AW_DEV_STATUS {
AW_DEV_PW_OFF = 0,
AW_DEV_PW_ON,
};
enum AW_DEV_FW_STATUS {
AW_DEV_FW_FAILED = 0,
AW_DEV_FW_OK,
};
enum AW_DEV_MEMCLK {
AW_DEV_MEMCLK_OSC = 0,
AW_DEV_MEMCLK_PLL = 1,
};
enum AW_DEV_DSP_CFG {
AW_DEV_DSP_WORK = 0,
AW_DEV_DSP_BYPASS = 1,
};
enum {
AW_DSP_16_DATA = 0,
AW_DSP_32_DATA = 1,
};
enum aw_platform {
AW_QCOM = 0,
AW_MTK = 1,
AW_SPRD = 2,
};
enum {
AW_NOT_RCV_MODE = 0,
AW_RCV_MODE = 1,
};
struct aw_device_ops {
int (*aw_i2c_writes)(struct aw_device *aw_dev, uint8_t reg_addr, uint8_t *buf, uint16_t len);
int (*aw_i2c_write)(struct aw_device *aw_dev, uint8_t reg_addr, uint16_t reg_data);
int (*aw_i2c_read)(struct aw_device *aw_dev, uint8_t reg_addr, uint16_t *reg_data);
int (*aw_reg_write)(struct aw_device *aw_dev, uint8_t reg_addr, uint16_t reg_data);
int (*aw_reg_read)(struct aw_device *aw_dev, uint8_t reg_addr, uint16_t *reg_data);
int (*aw_reg_write_bits)(struct aw_device *aw_dev, uint8_t reg_addr, uint16_t mask, uint16_t reg_data);
int (*aw_dsp_write)(struct aw_device *aw_dev, uint16_t dsp_addr, uint32_t reg_data, uint8_t data_type);
int (*aw_dsp_read)(struct aw_device *aw_dev, uint16_t dsp_addr, uint32_t *dsp_data, uint8_t data_type);
int (*aw_dsp_write_bits)(struct aw_device *aw_dev, uint16_t dsp_addr, uint16_t mask, uint16_t dsp_data);
int (*aw_set_volume)(struct aw_device *aw_dev, uint16_t value);
int (*aw_get_volume)(struct aw_device *aw_dev, uint16_t *value);
unsigned int (*aw_reg_val_to_db)(unsigned int value);
void (*aw_i2s_tx_enable)(struct aw_device *aw_dev, bool flag);
int (*aw_get_dev_num)(void);
bool (*aw_check_wr_access)(int reg);
bool (*aw_check_rd_access)(int reg);
int (*aw_get_reg_num)(void);
int (*aw_get_version)(char *buf, int size);
int (*aw_read_dsp_pid)(struct aw_device *aw_dev);
int (*aw_get_hw_mon_st)(struct aw_device *aw_dev, bool *is_enable, uint8_t *temp_flag);
int (*aw_cali_svc_get_iv_st)(struct aw_device *aw_dev);
void (*aw_set_cfg_f0_fs)(struct aw_device *aw_dev, uint32_t *f0_fs);
int (*aw_dsp_fw_check)(struct aw_device *aw_dev);
};
struct aw_int_desc {
unsigned int mask_reg; /*interrupt mask reg*/
unsigned int st_reg; /*interrupt status reg*/
unsigned int mask_default; /*default mask close all*/
unsigned int int_mask; /*set mask*/
unsigned int intst_mask; /*interrupt check mask*/
uint16_t sysint_st; /*interrupt reg status*/
};
struct aw_pwd_desc {
unsigned int reg;
unsigned int mask;
unsigned int enable;
unsigned int disable;
};
struct aw_vcalb_desc {
unsigned int icalk_reg;
unsigned int icalk_reg_mask;
unsigned int icalk_sign_mask;
unsigned int icalk_neg_mask;
int icalk_value_factor;
unsigned int vcalk_reg;
unsigned int vcalk_reg_mask;
unsigned int vcalk_sign_mask;
unsigned int vcalk_neg_mask;
unsigned int vcalk_shift;
int vcalk_value_factor;
unsigned int vcalb_dsp_reg;
unsigned char data_type;
int cabl_base_value;
int vcal_factor;
int vscal_factor;
int iscal_factor;
unsigned int vcalb_adj_shift;
unsigned int vcalb_vsense_reg;
int vscal_factor_vsense_in;
int vcalk_value_factor_vsense_in;
unsigned int vcalk_dac_shift;
unsigned int vcalk_dac_mask;
unsigned int vcalk_dac_neg_mask;
unsigned int vcalk_vdsel_mask;
};
struct aw_mute_desc {
unsigned int reg;
unsigned int mask;
unsigned int enable;
unsigned int disable;
};
struct aw_sysst_desc {
unsigned int reg;
unsigned int st_check;
unsigned int st_mask;
unsigned int pll_check;
unsigned int dsp_check;
unsigned int dsp_mask;
};
struct aw_profctrl_desc {
unsigned int reg;
unsigned int mask;
unsigned int rcv_mode_val;
unsigned int cur_mode;
};
struct aw_volume_desc {
unsigned int reg;
unsigned int mask;
unsigned int shift;
int init_volume;
int mute_volume;
};
struct aw_dsp_en_desc {
unsigned int reg;
unsigned int mask;
unsigned int enable;
unsigned int disable;
};
struct aw_memclk_desc {
unsigned int reg;
unsigned int mask;
unsigned int mcu_hclk;
unsigned int osc_clk;
};
struct aw_watch_dog_desc {
unsigned int reg;
unsigned int mask;
};
struct aw_dsp_mem_desc {
unsigned int dsp_madd_reg;
unsigned int dsp_mdat_reg;
unsigned int dsp_fw_base_addr;
unsigned int dsp_cfg_base_addr;
};
struct aw_voltage_desc {
unsigned int reg;
unsigned int vbat_range;
unsigned int int_bit;
};
struct aw_temperature_desc {
unsigned int reg;
unsigned int sign_mask;
unsigned int neg_mask;
};
struct aw_ipeak_desc {
unsigned int reg;
unsigned int mask;
};
struct aw_vmax_desc {
unsigned int dsp_reg;
unsigned char data_type;
unsigned int init_vmax;
};
struct aw_soft_rst {
uint8_t reg;
uint16_t reg_value;
};
struct aw_cali_cfg_desc {
unsigned int actampth_reg;
unsigned char actampth_data_type;
unsigned int noiseampth_reg;
unsigned char noiseampth_data_type;
unsigned int ustepn_reg;
unsigned char ustepn_data_type;
unsigned int alphan_reg;
unsigned int alphan_data_type;
};
struct aw_dsp_vol_desc {
unsigned int reg;
unsigned int mute_st;
unsigned int noise_st;
unsigned int mask;
};
struct aw_amppd_desc {
unsigned int reg;
unsigned int mask;
unsigned int enable;
unsigned int disable;
};
struct aw_f0_desc {
unsigned int dsp_reg;
unsigned char data_type;
unsigned int shift;
};
struct aw_cfgf0_fs_desc {
unsigned int dsp_reg;
unsigned char data_type;
};
struct aw_q_desc {
unsigned int dsp_reg;
unsigned char data_type;
unsigned int shift;
};
struct aw_ra_desc {
unsigned int dsp_reg;
unsigned char data_type;
};
struct aw_noise_desc {
unsigned int dsp_reg;
unsigned char data_type;
unsigned int mask;
};
struct aw_hw_mon_desc {
unsigned int dsp_reg;
unsigned char data_type;
unsigned int mask;
unsigned int enable;
unsigned int disable;
};
struct aw_ste_re_desc {
unsigned int dsp_reg;
unsigned char data_type;
unsigned int shift;
};
struct aw_adpz_re_desc {
unsigned int dsp_reg;
unsigned char data_type;
unsigned int shift;
};
struct aw_adpz_t0_desc {
unsigned int dsp_reg;
unsigned char data_type;
uint16_t coilalpha_reg;
unsigned char coil_type;
};
struct aw_spkr_temp_desc {
unsigned int reg;
};
struct aw_dsp_crc_desc {
unsigned int ctl_reg;
unsigned int ctl_mask;
unsigned int ctl_enable;
unsigned int ctl_disable;
unsigned int dsp_reg;
unsigned char data_type;
};
struct aw_cco_mux_desc {
unsigned int reg;
unsigned int mask;
unsigned int divider;
unsigned int bypass;
};
struct aw_hw_temp_desc {
unsigned int dsp_reg;
unsigned char data_type;
};
struct aw_re_range_desc {
uint32_t re_min;
uint32_t re_max;
uint32_t re_min_default;
uint32_t re_max_default;
};
struct aw_cali_delay_desc {
unsigned int dsp_reg;
unsigned char data_type;
unsigned int delay;
};
struct aw_chansel_desc {
unsigned int rxchan_reg;
unsigned int rxchan_mask;
unsigned int txchan_reg;
unsigned int txchan_mask;
unsigned int rx_left;
unsigned int rx_right;
unsigned int tx_left;
unsigned int tx_right;
};
struct aw_tx_en_desc {
unsigned int tx_en_mask;
unsigned int tx_disable;
};
struct aw_dsp_st {
unsigned int dsp_reg_s1;
unsigned int dsp_reg_e1;
unsigned int dsp_reg_s2;
unsigned int dsp_reg_e2;
};
struct aw_container {
int len;
uint8_t data[];
};
struct aw_device {
int status;
struct mutex *i2c_lock;
unsigned char cur_prof; /*current profile index*/
unsigned char set_prof; /*set profile index*/
unsigned char dsp_crc_st;
uint16_t chip_id;
unsigned int channel; /*pa channel select*/
unsigned int fade_step;
struct i2c_client *i2c;
struct device *dev;
char *acf;
void *private_data;
uint32_t fade_en;
unsigned char dsp_cfg;
uint32_t dsp_fw_len;
uint32_t dsp_cfg_len;
uint8_t platform;
uint8_t fw_status; /*load cfg status*/
struct aw_prof_info prof_info;
struct aw_sec_data_desc crc_dsp_cfg;
struct aw_int_desc int_desc;
struct aw_pwd_desc pwd_desc;
struct aw_mute_desc mute_desc;
struct aw_vcalb_desc vcalb_desc;
struct aw_sysst_desc sysst_desc;
struct aw_profctrl_desc profctrl_desc;
struct aw_volume_desc volume_desc;
struct aw_dsp_en_desc dsp_en_desc;
struct aw_memclk_desc memclk_desc;
struct aw_watch_dog_desc watch_dog_desc;
struct aw_dsp_mem_desc dsp_mem_desc;
struct aw_voltage_desc voltage_desc;
struct aw_temperature_desc temp_desc;
struct aw_vmax_desc vmax_desc;
struct aw_ipeak_desc ipeak_desc;
struct aw_soft_rst soft_rst;
struct aw_cali_cfg_desc cali_cfg_desc;
struct aw_ra_desc ra_desc;
struct aw_dsp_vol_desc dsp_vol_desc;
struct aw_noise_desc noise_desc;
struct aw_f0_desc f0_desc;
struct aw_cfgf0_fs_desc cfgf0_fs_desc;
struct aw_q_desc q_desc;
struct aw_hw_mon_desc hw_mon_desc;
struct aw_ste_re_desc ste_re_desc;
struct aw_adpz_re_desc adpz_re_desc;
struct aw_adpz_t0_desc t0_desc;
struct aw_amppd_desc amppd_desc;
struct aw_spkr_temp_desc spkr_temp_desc;
struct aw_dsp_crc_desc dsp_crc_desc;
struct aw_cco_mux_desc cco_mux_desc;
struct aw_hw_temp_desc hw_temp_desc;
struct aw_cali_desc cali_desc;
struct aw_monitor_desc monitor_desc;
struct aw_re_range_desc re_range;
struct aw_spin_desc spin_desc;
struct aw_chansel_desc chansel_desc;
struct aw_tx_en_desc tx_en_desc;
struct aw_cali_delay_desc cali_delay_desc;
struct aw_dsp_st dsp_st_desc;
struct aw_device_ops ops;
struct list_head list_node;
};
void aw_dev_deinit(struct aw_device *aw_dev);
int aw_device_init(struct aw_device *aw_dev, struct aw_container *aw_prof);
int aw_device_start(struct aw_device *aw_dev);
int aw_device_stop(struct aw_device *aw_dev);
int aw_dev_fw_update(struct aw_device *aw_dev, bool up_dsp_fw_en, bool force_up_en);
int aw_dev_get_int_status(struct aw_device *aw_dev, uint16_t *int_status);
void aw_dev_set_volume_step(struct aw_device *aw_dev, unsigned int step);
int aw_dev_set_intmask(struct aw_device *aw_dev, bool flag);
void aw_dev_clear_int_status(struct aw_device *aw_dev);
int aw_dev_get_volume_step(struct aw_device *aw_dev);
int aw_device_probe(struct aw_device *aw_dev);
int aw_device_remove(struct aw_device *aw_dev);
int aw_dev_syspll_check(struct aw_device *aw_dev);
int aw_dev_get_dsp_status(struct aw_device *aw_dev);
void aw_dev_set_fade_vol_step(struct aw_device *aw_dev, unsigned int step);
int aw_dev_get_fade_vol_step(struct aw_device *aw_dev);
void aw_dev_get_fade_time(unsigned int *time, bool fade_in);
void aw_dev_set_fade_time(unsigned int time, bool fade_in);
int aw_dev_get_hmute(struct aw_device *aw_dev);
int aw_dev_sysst_check(struct aw_device *aw_dev);
int aw_dev_get_list_head(struct list_head **head);
int aw_dev_dsp_check(struct aw_device *aw_dev);
void aw_dev_memclk_select(struct aw_device *aw_dev, unsigned char flag);
void aw_dev_dsp_enable(struct aw_device *aw_dev, bool dsp);
void aw_dev_mute(struct aw_device *aw_dev, bool mute);
int aw_dev_dsp_fw_update(struct aw_device *aw_dev,
uint8_t *data, uint32_t len);
int aw_dev_dsp_cfg_update(struct aw_device *aw_dev,
uint8_t *data, uint32_t len);
int aw_dev_modify_dsp_cfg(struct aw_device *aw_dev,
unsigned int addr, uint32_t dsp_data, unsigned char data_type);
int aw_dev_get_iis_status(struct aw_device *aw_dev);
#endif

View File

@@ -0,0 +1,630 @@
// SPDX-License-Identifier: GPL-2.0+
#include <linux/module.h>
#include <linux/i2c.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/version.h>
#include <linux/workqueue.h>
#include <linux/syscalls.h>
#include <sound/control.h>
#include <linux/uaccess.h>
#include <linux/syscalls.h>
#include "aw883xx.h"
#include "aw_bin_parse.h"
#include "aw_pid_2049_reg.h"
#include "aw_log.h"
#define AW_FW_CHECK_PART (10)
static int aw883xx_dev_i2c_writes(struct aw_device *aw_dev,
uint8_t reg_addr, uint8_t *buf, uint16_t len)
{
struct aw883xx *aw883xx = (struct aw883xx *)aw_dev->private_data;
return aw883xx_i2c_writes(aw883xx, reg_addr, buf, len);
}
static int aw883xx_dev_i2c_write(struct aw_device *aw_dev,
uint8_t reg_addr, uint16_t reg_data)
{
struct aw883xx *aw883xx = (struct aw883xx *)aw_dev->private_data;
return aw883xx_i2c_write(aw883xx, reg_addr, reg_data);
}
static int aw883xx_dev_i2c_read(struct aw_device *aw_dev,
uint8_t reg_addr, uint16_t *reg_data)
{
struct aw883xx *aw883xx = (struct aw883xx *)aw_dev->private_data;
return aw883xx_i2c_read(aw883xx, reg_addr, reg_data);
}
static int aw883xx_dev_reg_read(struct aw_device *aw_dev,
uint8_t reg_addr, uint16_t *reg_data)
{
struct aw883xx *aw883xx = (struct aw883xx *)aw_dev->private_data;
return aw883xx_reg_read(aw883xx, reg_addr, reg_data);
}
static int aw883xx_dev_reg_write(struct aw_device *aw_dev,
uint8_t reg_addr, uint16_t reg_data)
{
struct aw883xx *aw883xx = (struct aw883xx *)aw_dev->private_data;
return aw883xx_reg_write(aw883xx, reg_addr, reg_data);
}
static int aw883xx_dev_reg_write_bits(struct aw_device *aw_dev,
uint8_t reg_addr, uint16_t mask, uint16_t reg_data)
{
struct aw883xx *aw883xx = (struct aw883xx *)aw_dev->private_data;
return aw883xx_reg_write_bits(aw883xx, reg_addr, mask, reg_data);
}
static int aw883xx_dev_dsp_write(struct aw_device *aw_dev,
uint16_t dsp_addr, uint32_t dsp_data, uint8_t data_type)
{
struct aw883xx *aw883xx = (struct aw883xx *)aw_dev->private_data;
return aw883xx_dsp_write(aw883xx, dsp_addr, dsp_data, data_type);
}
static int aw883xx_dev_dsp_read(struct aw_device *aw_dev,
uint16_t dsp_addr, uint32_t *dsp_data, uint8_t data_type)
{
struct aw883xx *aw883xx = (struct aw883xx *)aw_dev->private_data;
return aw883xx_dsp_read(aw883xx, dsp_addr, dsp_data, data_type);
}
/******************************************************
*
* aw883xx i2c write/read
*
******************************************************/
/*[9 : 6]: -6DB ; [5 : 0]: -0.125DB real_value = value * 8 : 0.125db --> 1*/
static unsigned int aw_pid_2049_reg_val_to_db(unsigned int value)
{
return (((value >> AW_PID_2049_VOL_6DB_START) * AW_PID_2049_VOLUME_STEP_DB) +
((value & 0x3f) % AW_PID_2049_VOLUME_STEP_DB));
}
/*[9 : 6]: -6DB ; [5 : 0]: -0.125DB reg_value = value / step << 6 + value % step ; step = 6 * 8*/
static uint16_t aw883xx_db_val_to_reg(uint16_t value)
{
return (((value / AW_PID_2049_VOLUME_STEP_DB) << AW_PID_2049_VOL_6DB_START) +
(value % AW_PID_2049_VOLUME_STEP_DB));
}
static int aw883xx_set_volume(struct aw883xx *aw883xx, uint16_t value)
{
uint16_t reg_value = 0;
uint16_t real_value = aw883xx_db_val_to_reg(value);
/* cal real value */
aw883xx_reg_read(aw883xx, AW_PID_2049_SYSCTRL2_REG, &reg_value);
aw_dev_dbg(aw883xx->dev, "value 0x%x , reg:0x%x", value, real_value);
/*[15 : 6] volume*/
real_value = (real_value << AW_PID_2049_VOL_START_BIT) | (reg_value & AW_PID_2049_VOL_MASK);
/* write value */
aw883xx_reg_write(aw883xx, AW_PID_2049_SYSCTRL2_REG, real_value);
return 0;
}
static int aw883xx_get_volume(struct aw883xx *aw883xx, uint16_t *value)
{
uint16_t reg_value = 0;
uint16_t real_value = 0;
/* read value */
aw883xx_reg_read(aw883xx, AW_PID_2049_SYSCTRL2_REG, &reg_value);
/*[15 : 6] volume*/
real_value = reg_value >> AW_PID_2049_VOL_START_BIT;
real_value = aw_pid_2049_reg_val_to_db(real_value);
*value = real_value;
return 0;
}
static int aw_pid_2049_set_volume(struct aw_device *aw_dev, uint16_t value)
{
struct aw883xx *aw883xx = (struct aw883xx *)aw_dev->private_data;
return aw883xx_set_volume(aw883xx, value);
}
static int aw_pid_2049_get_volume(struct aw_device *aw_dev, uint16_t *value)
{
struct aw883xx *aw883xx = (struct aw883xx *)aw_dev->private_data;
return aw883xx_get_volume(aw883xx, value);
}
static void aw_pid_2049_i2s_tx_enable(struct aw_device *aw_dev, bool flag)
{
struct aw883xx *aw883xx = (struct aw883xx *)aw_dev->private_data;
aw_dev_dbg(aw883xx->dev, "enter");
if (flag) {
aw883xx_reg_write_bits(aw883xx, AW_PID_2049_I2SCFG1_REG,
AW_PID_2049_I2STXEN_MASK,
AW_PID_2049_I2STXEN_ENABLE_VALUE);
} else {
aw883xx_reg_write_bits(aw883xx, AW_PID_2049_I2SCFG1_REG,
AW_PID_2049_I2STXEN_MASK,
AW_PID_2049_I2STXEN_DISABLE_VALUE);
}
}
static void aw_pid_2049_set_cfg_f0_fs(struct aw_device *aw_dev, uint32_t *f0_fs)
{
uint16_t rate_data = 0;
uint32_t fs = 0;
struct aw883xx *aw883xx = (struct aw883xx *)aw_dev->private_data;
aw_dev_dbg(aw883xx->dev, "enter");
aw883xx_reg_read(aw883xx, AW_PID_2049_I2SCTRL_REG, &rate_data);
switch (rate_data & (~AW_PID_2049_I2SSR_MASK)) {
case AW_PID_2049_I2SSR_8_KHZ_VALUE:
fs = 8000;
break;
case AW_PID_2049_I2SSR_16_KHZ_VALUE:
fs = 16000;
break;
case AW_PID_2049_I2SSR_32_KHZ_VALUE:
fs = 32000;
break;
case AW_PID_2049_I2SSR_44_KHZ_VALUE:
fs = 44000;
break;
case AW_PID_2049_I2SSR_48_KHZ_VALUE:
fs = 48000;
break;
case AW_PID_2049_I2SSR_96_KHZ_VALUE:
fs = 96000;
break;
case AW_PID_2049_I2SSR_192KHZ_VALUE:
fs = 192000;
break;
default:
fs = 48000;
aw_dev_err(aw883xx->dev,
"rate can not support, use default 48k");
break;
}
aw_dev_dbg(aw883xx->dev, "get i2s fs:%d", fs);
*f0_fs = fs / 8;
aw883xx_dsp_write(aw883xx,
AW_PID_2049_DSP_REG_CFGF0_FS, *f0_fs, AW_DSP_32_DATA);
}
static bool aw_pid_2049_check_rd_access(int reg)
{
if (reg >= AW_PID_2049_REG_MAX)
return false;
if (aw_pid_2049_reg_access[reg] & REG_RD_ACCESS)
return true;
else
return false;
}
static bool aw_pid_2049_check_wr_access(int reg)
{
if (reg >= AW_PID_2049_REG_MAX)
return false;
if (aw_pid_2049_reg_access[reg] & REG_WR_ACCESS)
return true;
else
return false;
}
static int aw_pid_2049_get_reg_num(void)
{
return AW_PID_2049_REG_MAX;
}
static int aw_pid_2049_get_hw_mon_st(struct aw_device *aw_dev,
bool *is_enable, uint8_t *temp_flag)
{
int ret = 0;
uint32_t vbat_en = 0;
uint32_t temp_en = 0;
uint32_t temp_switch = 0;
struct aw883xx *aw883xx = (struct aw883xx *)aw_dev->private_data;
ret = aw883xx_dsp_read(aw883xx,
AW_PID_2049_DSP_REG_CFG_MBMEC_GLBCFG, &vbat_en, AW_DSP_16_DATA);
if (ret < 0) {
aw_dev_err(aw883xx->dev, "read hardware monitor status failed");
return ret;
}
ret = aw883xx_dsp_read(aw883xx,
AW_PID_2049_DSP_REG_TEMP_SWITCH, &temp_en, AW_DSP_16_DATA);
if (ret < 0) {
aw_dev_err(aw883xx->dev, "read hardware temp switch failed");
return ret;
}
temp_switch = temp_en;
vbat_en &= (~AW_PID_2049_DSP_MONITOR_MASK);
temp_en &= (~AW_PID_2049_DSP_TEMP_PEAK_MASK);
temp_switch &= (~AW_PID_2049_DSP_TEMP_SEL_FLAG);
if (vbat_en || temp_en)
*is_enable = true;
else
*is_enable = false;
if (temp_switch)
*temp_flag = AW_EXTERNAL_TEMP;
else
*temp_flag = AW_INTERNAL_TEMP;
return 0;
}
static int aw_pid_2049_cali_get_iv_st(struct aw_device *aw_dev)
{
struct aw883xx *aw883xx = (struct aw883xx *)aw_dev->private_data;
int ret;
uint16_t reg_data = 0;
int i;
aw_dev_info(aw_dev->dev, "enter");
for (i = 0; i < AW_GET_IV_CNT_MAX; i++) {
ret = aw883xx_reg_read(aw883xx, AW_PID_2049_ASR1_REG, &reg_data);
if (ret < 0) {
aw_dev_err(aw883xx->dev,
"read 0x%x failed", AW_PID_2049_ASR1_REG);
return ret;
}
reg_data &= (~AW_PID_2049_ReAbs_MASK);
if (!reg_data)
return 0;
msleep(30);
}
aw_dev_err(aw883xx->dev, "IV data abnormal, please check");
return -EINVAL;
}
static int aw_pid_2049_dsp_fw_check(struct aw_device *aw_dev)
{
struct aw_prof_desc *set_prof_desc = NULL;
struct aw_sec_data_desc *dsp_fw_desc = NULL;
uint16_t base_addr = AW_PID_2049_DSP_FW_ADDR;
uint16_t addr = base_addr;
int ret, i;
uint32_t dsp_val;
uint16_t bin_val;
aw_dev_info(aw_dev->dev, "enter");
ret = aw_dev_get_prof_data(aw_dev, aw_dev->cur_prof, &set_prof_desc);
if (ret < 0)
return ret;
/*update reg*/
dsp_fw_desc = &set_prof_desc->sec_desc[AW_DATA_TYPE_DSP_FW];
for (i = 0; i < AW_FW_CHECK_PART; i++) {
ret = aw883xx_dev_dsp_read(aw_dev, addr, &dsp_val, AW_DSP_16_DATA);
if (ret < 0) {
aw_dev_err(aw_dev->dev, "dsp read failed");
return ret;
}
bin_val = AW_GET_16_DATA(dsp_fw_desc->data[2 * (addr - base_addr)],
dsp_fw_desc->data[2 * (addr - base_addr) + 1]);
if (dsp_val != bin_val) {
aw_dev_err(aw_dev->dev, "check failed, addr[0x%x], read[0x%x] != bindata[0x%x]",
addr, dsp_val, bin_val);
return -EINVAL;
}
addr += (dsp_fw_desc->len / 2) / AW_FW_CHECK_PART;
if ((addr - base_addr) > dsp_fw_desc->len) {
aw_dev_err(aw_dev->dev, "check failed, addr[0x%x] too large", addr);
return -EINVAL;
}
}
aw_dev_info(aw_dev->dev, "dsp fw check success");
return 0;
}
static int aw883xx_dev_init(struct aw883xx *aw883xx)
{
struct aw_device *aw_pa = NULL;
aw_pa = devm_kzalloc(aw883xx->dev, sizeof(struct aw_device), GFP_KERNEL);
if (aw_pa == NULL) {
aw_dev_err(aw883xx->dev, "dev kalloc failed");
return -ENOMEM;
}
/*call aw device init func*/
aw_pa->acf = NULL;
aw_pa->prof_info.prof_desc = NULL;
aw_pa->prof_info.count = 0;
aw_pa->prof_info.prof_type = AW_DEV_NONE_TYPE_ID;
aw_pa->channel = 0;
aw_pa->i2c_lock = &aw883xx->i2c_lock;
aw_pa->i2c = aw883xx->i2c;
aw_pa->fw_status = AW_DEV_FW_FAILED;
aw_pa->fade_step = AW_PID_2049_VOLUME_STEP_DB;
aw_pa->re_range.re_min_default = AW_RE_MIN;
aw_pa->re_range.re_max_default = AW_RE_MAX;
aw_pa->monitor_desc.hw_monitor_delay = AW_HW_MONITOR_DELAY;
aw_pa->chip_id = aw883xx->chip_id;
aw_pa->private_data = (void *)aw883xx;
aw_pa->dev = aw883xx->dev;
aw_pa->ops.aw_get_version = aw883xx_get_version;
aw_pa->ops.aw_i2c_writes = aw883xx_dev_i2c_writes;
aw_pa->ops.aw_i2c_write = aw883xx_dev_i2c_write;
aw_pa->ops.aw_reg_write = aw883xx_dev_reg_write;
aw_pa->ops.aw_reg_write_bits = aw883xx_dev_reg_write_bits;
aw_pa->ops.aw_i2c_read = aw883xx_dev_i2c_read;
aw_pa->ops.aw_reg_read = aw883xx_dev_reg_read;
aw_pa->ops.aw_dsp_read = aw883xx_dev_dsp_read;
aw_pa->ops.aw_dsp_write = aw883xx_dev_dsp_write;
aw_pa->ops.aw_get_dev_num = aw883xx_get_dev_num;
aw_pa->ops.aw_get_volume = aw_pid_2049_get_volume;
aw_pa->ops.aw_set_volume = aw_pid_2049_set_volume;
aw_pa->ops.aw_reg_val_to_db = aw_pid_2049_reg_val_to_db;
aw_pa->ops.aw_check_rd_access = aw_pid_2049_check_rd_access;
aw_pa->ops.aw_check_wr_access = aw_pid_2049_check_wr_access;
aw_pa->ops.aw_get_reg_num = aw_pid_2049_get_reg_num;
aw_pa->ops.aw_i2s_tx_enable = aw_pid_2049_i2s_tx_enable;
aw_pa->ops.aw_get_hw_mon_st = aw_pid_2049_get_hw_mon_st;
aw_pa->ops.aw_cali_svc_get_iv_st = aw_pid_2049_cali_get_iv_st;
aw_pa->ops.aw_set_cfg_f0_fs = aw_pid_2049_set_cfg_f0_fs;
aw_pa->ops.aw_dsp_fw_check = aw_pid_2049_dsp_fw_check;
aw_pa->int_desc.mask_reg = AW_PID_2049_SYSINTM_REG;
aw_pa->int_desc.mask_default = AW_PID_2049_SYSINTM_DEFAULT;
aw_pa->int_desc.int_mask = AW_PID_2049_SYSINTM_DEFAULT;
aw_pa->int_desc.st_reg = AW_PID_2049_SYSINT_REG;
aw_pa->int_desc.intst_mask = AW_PID_2049_BIT_SYSINT_CHECK;
aw_pa->pwd_desc.reg = AW_PID_2049_SYSCTRL_REG;
aw_pa->pwd_desc.mask = AW_PID_2049_PWDN_MASK;
aw_pa->pwd_desc.enable = AW_PID_2049_PWDN_POWER_DOWN_VALUE;
aw_pa->pwd_desc.disable = AW_PID_2049_PWDN_WORKING_VALUE;
aw_pa->mute_desc.reg = AW_PID_2049_SYSCTRL_REG;
aw_pa->mute_desc.mask = AW_PID_2049_HMUTE_MASK;
aw_pa->mute_desc.enable = AW_PID_2049_HMUTE_ENABLE_VALUE;
aw_pa->mute_desc.disable = AW_PID_2049_HMUTE_DISABLE_VALUE;
aw_pa->vcalb_desc.vcalb_dsp_reg = AW_PID_2049_DSP_REG_VCALB;
aw_pa->vcalb_desc.data_type = AW_DSP_16_DATA;
aw_pa->vcalb_desc.vcal_factor = AW_PID_2049_VCAL_FACTOR;
aw_pa->vcalb_desc.cabl_base_value = AW_PID_2049_CABL_BASE_VALUE;
aw_pa->vcalb_desc.vscal_factor = AW_PID_2049_VSCAL_FACTOR;
aw_pa->vcalb_desc.iscal_factor = AW_PID_2049_ISCAL_FACTOR;
aw_pa->vcalb_desc.vcalb_adj_shift = AW_PID_2049_VCALB_ADJ_FACTOR;
aw_pa->vcalb_desc.icalk_value_factor = AW_PID_2049_ICABLK_FACTOR;
aw_pa->vcalb_desc.icalk_reg = AW_PID_2049_EFRM2_REG;
aw_pa->vcalb_desc.icalk_reg_mask = AW_PID_2049_EF_ISN_GESLP_MASK;
aw_pa->vcalb_desc.icalk_sign_mask = AW_PID_2049_EF_ISN_GESLP_SIGN_MASK;
aw_pa->vcalb_desc.icalk_neg_mask = AW_PID_2049_EF_ISN_GESLP_SIGN_NEG;
aw_pa->vcalb_desc.vcalk_reg = AW_PID_2049_EFRH_REG;
aw_pa->vcalb_desc.vcalk_reg_mask = AW_PID_2049_EF_VSN_GESLP_MASK;
aw_pa->vcalb_desc.vcalk_sign_mask = AW_PID_2049_EF_VSN_GESLP_SIGN_MASK;
aw_pa->vcalb_desc.vcalk_neg_mask = AW_PID_2049_EF_VSN_GESLP_SIGN_NEG;
aw_pa->vcalb_desc.vcalk_value_factor = AW_PID_2049_VCABLK_FACTOR;
aw_pa->vcalb_desc.vcalk_shift = AW_PID_2049_EF_VSENSE_GAIN_SHIFT;
aw_pa->vcalb_desc.vcalb_vsense_reg = AW_PID_2049_I2SCFG3_REG;
aw_pa->vcalb_desc.vcalk_vdsel_mask = AW_PID_2049_VDSEL_MASK;
aw_pa->vcalb_desc.vcalk_value_factor_vsense_in = AW_PID_2049_VCABLK_FACTOR_DAC;
aw_pa->vcalb_desc.vscal_factor_vsense_in = AW_PID_2049_VSCAL_FACTOR_DAC;
aw_pa->vcalb_desc.vcalk_dac_shift = AW_PID_2049_EF_DAC_GESLP_SHIFT;
aw_pa->vcalb_desc.vcalk_dac_mask = AW_PID_2049_EF_DAC_GESLP_SIGN_MASK;
aw_pa->vcalb_desc.vcalk_dac_neg_mask = AW_PID_2049_EF_DAC_GESLP_SIGN_NEG;
aw_pa->sysst_desc.reg = AW_PID_2049_SYSST_REG;
aw_pa->sysst_desc.st_check = AW_PID_2049_BIT_SYSST_CHECK;
aw_pa->sysst_desc.st_mask = AW_PID_2049_BIT_SYSST_CHECK_MASK;
aw_pa->sysst_desc.pll_check = AW_PID_2049_BIT_PLL_CHECK;
aw_pa->sysst_desc.dsp_check = AW_PID_2049_DSPS_NORMAL_VALUE;
aw_pa->sysst_desc.dsp_mask = AW_PID_2049_DSPS_MASK;
aw_pa->profctrl_desc.reg = AW_PID_2049_SYSCTRL_REG;
aw_pa->profctrl_desc.mask = AW_PID_2049_RCV_MODE_MASK;
aw_pa->profctrl_desc.rcv_mode_val = AW_PID_2049_RCV_MODE_RECEIVER_VALUE;
aw_pa->volume_desc.reg = AW_PID_2049_SYSCTRL2_REG;
aw_pa->volume_desc.mask = AW_PID_2049_VOL_MASK;
aw_pa->volume_desc.shift = AW_PID_2049_VOL_START_BIT;
aw_pa->volume_desc.mute_volume = AW_PID_2049_MUTE_VOL;
aw_pa->dsp_en_desc.reg = AW_PID_2049_SYSCTRL_REG;
aw_pa->dsp_en_desc.mask = AW_PID_2049_DSPBY_MASK;
aw_pa->dsp_en_desc.enable = AW_PID_2049_DSPBY_WORKING_VALUE;
aw_pa->dsp_en_desc.disable = AW_PID_2049_DSPBY_BYPASS_VALUE;
aw_pa->memclk_desc.reg = AW_PID_2049_DBGCTRL_REG;
aw_pa->memclk_desc.mask = AW_PID_2049_MEM_CLKSEL_MASK;
aw_pa->memclk_desc.mcu_hclk = AW_PID_2049_MEM_CLKSEL_DAP_HCLK_VALUE;
aw_pa->memclk_desc.osc_clk = AW_PID_2049_MEM_CLKSEL_OSC_CLK_VALUE;
aw_pa->watch_dog_desc.reg = AW_PID_2049_WDT_REG;
aw_pa->watch_dog_desc.mask = AW_PID_2049_WDT_CNT_MASK;
aw_pa->dsp_mem_desc.dsp_madd_reg = AW_PID_2049_DSPMADD_REG;
aw_pa->dsp_mem_desc.dsp_mdat_reg = AW_PID_2049_DSPMDAT_REG;
aw_pa->dsp_mem_desc.dsp_cfg_base_addr = AW_PID_2049_DSP_CFG_ADDR;
aw_pa->dsp_mem_desc.dsp_fw_base_addr = AW_PID_2049_DSP_FW_ADDR;
aw_pa->voltage_desc.reg = AW_PID_2049_VBAT_REG;
aw_pa->voltage_desc.vbat_range = AW_PID_2049_VBAT_RANGE;
aw_pa->voltage_desc.int_bit = AW_PID_2049_INT_10BIT;
aw_pa->temp_desc.reg = AW_PID_2049_TEMP_REG;
aw_pa->temp_desc.sign_mask = AW_PID_2049_TEMP_SIGN_MASK;
aw_pa->temp_desc.neg_mask = AW_PID_2049_TEMP_NEG_MASK;
aw_pa->vmax_desc.dsp_reg = AW_PID_2049_DSP_REG_VMAX;
aw_pa->vmax_desc.data_type = AW_DSP_16_DATA;
aw_pa->ipeak_desc.reg = AW_PID_2049_SYSCTRL2_REG;
aw_pa->ipeak_desc.mask = AW_PID_2049_BST_IPEAK_MASK;
aw_pa->soft_rst.reg = AW_PID_2049_ID_REG;
aw_pa->soft_rst.reg_value = AW_PID_2049_SOFT_RESET_VALUE;
aw_pa->dsp_vol_desc.reg = AW_PID_2049_DSPCFG_REG;
aw_pa->dsp_vol_desc.mask = AW_PID_2049_DSP_VOL_MASK;
aw_pa->dsp_vol_desc.mute_st = AW_PID_2049_DSP_VOL_MUTE;
aw_pa->dsp_vol_desc.noise_st = AW_PID_2049_DSP_VOL_NOISE_ST;
aw_pa->amppd_desc.reg = AW_PID_2049_SYSCTRL_REG;
aw_pa->amppd_desc.mask = AW_PID_2049_AMPPD_MASK;
aw_pa->amppd_desc.enable = AW_PID_2049_AMPPD_POWER_DOWN_VALUE;
aw_pa->amppd_desc.disable = AW_PID_2049_AMPPD_WORKING_VALUE;
aw_pa->spkr_temp_desc.reg = AW_PID_2049_ASR2_REG;
/*32-bit data types need bypass dsp*/
aw_pa->ra_desc.dsp_reg = AW_PID_2049_DSP_REG_CFG_ADPZ_RA;
aw_pa->ra_desc.data_type = AW_DSP_32_DATA;
/*32-bit data types need bypass dsp*/
aw_pa->cali_cfg_desc.actampth_reg = AW_PID_2049_DSP_REG_CFG_MBMEC_ACTAMPTH;
aw_pa->cali_cfg_desc.actampth_data_type = AW_DSP_32_DATA;
/*32-bit data types need bypass dsp*/
aw_pa->cali_cfg_desc.noiseampth_reg = AW_PID_2049_DSP_REG_CFG_MBMEC_NOISEAMPTH;
aw_pa->cali_cfg_desc.noiseampth_data_type = AW_DSP_32_DATA;
aw_pa->cali_cfg_desc.ustepn_reg = AW_PID_2049_DSP_REG_CFG_ADPZ_USTEPN;
aw_pa->cali_cfg_desc.ustepn_data_type = AW_DSP_16_DATA;
aw_pa->cali_cfg_desc.alphan_reg = AW_PID_2049_DSP_REG_CFG_RE_ALPHA;
aw_pa->cali_cfg_desc.alphan_data_type = AW_DSP_16_DATA;
/*32-bit data types need bypass dsp*/
aw_pa->adpz_re_desc.dsp_reg = AW_PID_2049_DSP_REG_CFG_ADPZ_RE;
aw_pa->adpz_re_desc.data_type = AW_DSP_32_DATA;
aw_pa->adpz_re_desc.shift = AW_PID_2049_DSP_RE_SHIFT;
aw_pa->t0_desc.dsp_reg = AW_PID_2049_DSP_CFG_ADPZ_T0;
aw_pa->t0_desc.data_type = AW_DSP_16_DATA;
aw_pa->t0_desc.coilalpha_reg = AW_PID_2049_DSP_CFG_ADPZ_COILALPHA;
aw_pa->t0_desc.coil_type = AW_DSP_16_DATA;
aw_pa->ste_re_desc.shift = AW_PID_2049_DSP_REG_CALRE_SHIFT;
aw_pa->ste_re_desc.dsp_reg = AW_PID_2049_DSP_REG_CALRE;
aw_pa->ste_re_desc.data_type = AW_DSP_16_DATA;
aw_pa->noise_desc.dsp_reg = AW_PID_2049_DSP_REG_CFG_MBMEC_GLBCFG;
aw_pa->noise_desc.data_type = AW_DSP_16_DATA;
aw_pa->noise_desc.mask = AW_PID_2049_DSP_REG_NOISE_MASK;
aw_pa->f0_desc.dsp_reg = AW_PID_2049_DSP_REG_RESULT_F0;
aw_pa->f0_desc.shift = AW_PID_2049_DSP_F0_SHIFT;
aw_pa->f0_desc.data_type = AW_DSP_16_DATA;
/*32-bit data types need bypass dsp*/
aw_pa->cfgf0_fs_desc.dsp_reg = AW_PID_2049_DSP_REG_CFGF0_FS;
aw_pa->cfgf0_fs_desc.data_type = AW_DSP_32_DATA;
aw_pa->q_desc.dsp_reg = AW_PID_2049_DSP_REG_RESULT_Q;
aw_pa->q_desc.shift = AW_PID_2049_DSP_Q_SHIFT;
aw_pa->q_desc.data_type = AW_DSP_16_DATA;
/*32-bit data types need bypass dsp*/
aw_pa->dsp_crc_desc.dsp_reg = AW_PID_2049_DSP_REG_CRC_ADDR;
aw_pa->dsp_crc_desc.data_type = AW_DSP_32_DATA;
aw_pa->dsp_crc_desc.ctl_reg = AW_PID_2049_HAGCCFG7_REG;
aw_pa->dsp_crc_desc.ctl_mask = AW_PID_2049_AGC_DSP_CTL_MASK;
aw_pa->dsp_crc_desc.ctl_enable = AW_PID_2049_AGC_DSP_CTL_ENABLE_VALUE;
aw_pa->dsp_crc_desc.ctl_disable = AW_PID_2049_AGC_DSP_CTL_DISABLE_VALUE;
aw_pa->cco_mux_desc.reg = AW_PID_2049_PLLCTRL1_REG;
aw_pa->cco_mux_desc.mask = AW_PID_2049_CCO_MUX_MASK;
aw_pa->cco_mux_desc.divider = AW_PID_2049_CCO_MUX_DIVIDED_VALUE;
aw_pa->cco_mux_desc.bypass = AW_PID_2049_CCO_MUX_BYPASS_VALUE;
/*hw monitor temp reg*/
aw_pa->hw_temp_desc.dsp_reg = AW_PID_2049_DSP_REG_TEMP_ADDR;
aw_pa->hw_temp_desc.data_type = AW_DSP_16_DATA;
aw_pa->chansel_desc.rxchan_reg = AW_PID_2049_I2SCTRL_REG;
aw_pa->chansel_desc.rxchan_mask = AW_PID_2049_CHSEL_MASK;
aw_pa->chansel_desc.txchan_reg = AW_PID_2049_I2SCFG1_REG;
aw_pa->chansel_desc.txchan_mask = AW_PID_2049_I2SCHS_MASK;
aw_pa->chansel_desc.rx_left = AW_PID_2049_CHSEL_LEFT_VALUE;
aw_pa->chansel_desc.rx_right = AW_PID_2049_CHSEL_RIGHT_VALUE;
aw_pa->chansel_desc.tx_left = AW_PID_2049_I2SCHS_LEFT_VALUE;
aw_pa->chansel_desc.tx_right = AW_PID_2049_I2SCHS_RIGHT_VALUE;
aw_pa->tx_en_desc.tx_en_mask = AW_PID_2049_I2STXEN_MASK;
aw_pa->tx_en_desc.tx_disable = AW_PID_2049_I2STXEN_DISABLE_VALUE;
aw_pa->cali_delay_desc.dsp_reg = AW_PID_2049_DSP_CALI_F0_DELAY;
aw_pa->cali_delay_desc.data_type = AW_DSP_16_DATA;
aw_pa->dsp_st_desc.dsp_reg_s1 = AW_PID_2049_DSP_ST_S1;
aw_pa->dsp_st_desc.dsp_reg_e1 = AW_PID_2049_DSP_ST_E1;
aw_pa->dsp_st_desc.dsp_reg_s2 = AW_PID_2049_DSP_ST_S2;
aw_pa->dsp_st_desc.dsp_reg_e2 = AW_PID_2049_DSP_ST_E2;
aw_device_probe(aw_pa);
aw883xx->aw_pa = aw_pa;
return 0;
}
int aw883xx_init(struct aw883xx *aw883xx)
{
if (aw883xx->chip_id == AW883XX_PID_2049) {
return aw883xx_dev_init(aw883xx);
} else {
aw_dev_err(aw883xx->dev, "unsupported device");
return -EINVAL;
}
}

View File

@@ -0,0 +1,54 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __AWINIC_LOG_H__
#define __AWINIC_LOG_H__
/********************************************
* print information control
*******************************************/
#define aw_dev_err(dev, format, ...) \
do { \
pr_err("[Awinic][%s]%s: " format "\n", dev_name(dev), __func__, ##__VA_ARGS__); \
} while (0)
#ifdef AW_INFO_LOG_ENABLE
#define aw_dev_info(dev, format, ...) \
do { \
pr_info("[Awinic][%s]%s: " format "\n", dev_name(dev), __func__, ##__VA_ARGS__); \
} while (0)
#else
#define aw_dev_info(dev, format, ...) \
do { \
pr_debug("[Awinic][%s]%s: " format "\n", dev_name(dev), __func__, ##__VA_ARGS__); \
} while (0)
#endif
#define aw_dev_dbg(dev, format, ...) \
do { \
pr_debug("[Awinic][%s]%s: " format "\n", dev_name(dev), __func__, ##__VA_ARGS__); \
} while (0)
#define aw_pr_err(format, ...) \
do { \
pr_err("[Awinic]%s: " format "\n", __func__, ##__VA_ARGS__); \
} while (0)
#ifdef AW_INFO_LOG_ENABLE
#define aw_pr_info(format, ...) \
do { \
pr_info("[Awinic]%s: " format "\n", __func__, ##__VA_ARGS__); \
} while (0)
#else
#define aw_pr_info(format, ...) \
do { \
pr_debug("[Awinic]%s: " format "\n", __func__, ##__VA_ARGS__); \
} while (0)
#endif
#define aw_pr_dbg(format, ...) \
do { \
pr_debug("[Awinic]%s: " format "\n", __func__, ##__VA_ARGS__); \
} while (0)
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,159 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __AW_MONITOR_H__
#define __AW_MONITOR_H__
/*#define AW_DEBUG*/
/*#define AW_SYS_BATTERY_ST*/
struct aw_table;
#define AW_TABLE_SIZE sizeof(struct aw_table)
#define AW_MONITOR_DEFAULT_FLAG (0)
#define IPEAK_NONE (0xFF)
#define GAIN_NONE (0xFF)
#define VMAX_NONE (0xFFFFFFFF)
#define AW_GET_32_DATA(w, x, y, z) \
((uint32_t)((((uint8_t)w) << 24) | (((uint8_t)x) << 16) | (((uint8_t)y) << 8) | ((uint8_t)z)))
#define AW_GET_16_DATA(x, y) \
((uint16_t)((((uint8_t)x) << 8) | (uint8_t)y))
enum {
AW_MON_LOGIC_OR = 0,
AW_MON_LOGIC_AND = 1,
};
enum {
AW_FIRST_ENTRY = 0,
AW_NOT_FIRST_ENTRY = 1,
};
enum aw_monitor_hdr_ver {
AW_MONITOR_HDR_VER_0_1_1 = 0x00010100,
};
enum aw_monitor_init {
AW_MON_CFG_ST = 0,
AW_MON_CFG_OK = 1,
};
#define MONITOR_EN_MASK 0x01
enum {
MONITOR_EN_BIT = 0,
MONITOR_LOGIC_BIT = 1,
MONITOR_IPEAK_EN_BIT = 2,
MONITOR_GAIN_EN_BIT = 3,
MONITOR_VMAX_EN_BIT = 4,
MONITOR_TEMP_EN_BIT = 5,
MONITOR_VOL_EN_BIT = 6,
};
enum {
AW_INTERNAL_TEMP = 0,
AW_EXTERNAL_TEMP = 1,
};
struct aw_monitor_hdr_v_0_1_1 {
uint32_t check_sum;
uint32_t monitor_ver;
char chip_type[16];
uint32_t ui_ver;
uint32_t monitor_time;
uint32_t monitor_count;
uint32_t enable_flag;
/* [bit 31:7]*/
/* [bit 6: vol en]*/
/* [bit 5: temp en]*/
/* [bit 4: vmax en]*/
/* [bit 3: gain en]*/
/* [bit 2: ipeak en]*/
/* [bit 1: & or | flag]*/
/* [bit 0: monitor en]*/
uint32_t temp_aplha;
uint32_t temp_num;
uint32_t single_temp_size;
uint32_t temp_offset;
uint32_t vol_aplha;
uint32_t vol_num;
uint32_t single_vol_size;
uint32_t vol_offset;
uint32_t reserver[3];
};
struct aw_table {
int16_t min_val;
int16_t max_val;
uint16_t ipeak;
uint16_t gain;
uint32_t vmax;
};
struct aw_table_info {
uint8_t table_num;
struct aw_table *aw_table;
};
struct aw_monitor_cfg {
uint8_t monitor_status;
uint32_t monitor_switch;
uint32_t monitor_time;
uint32_t monitor_count;
uint32_t logic_switch;
uint32_t temp_switch;
uint32_t temp_aplha;
uint32_t vol_switch;
uint32_t vol_aplha;
uint32_t ipeak_switch;
uint32_t gain_switch;
uint32_t vmax_switch;
struct aw_table_info temp_info;
struct aw_table_info vol_info;
};
struct aw_monitor_trace {
int32_t pre_val;
int32_t sum_val;
struct aw_table aw_table;
};
/******************************************************************
* struct aw882xx monitor
*******************************************************************/
struct aw_monitor_desc {
struct delayed_work delay_work;
struct delayed_work hw_monitor_work;
struct aw_monitor_cfg monitor_cfg;
bool hw_mon_en;
uint8_t hw_temp_flag;
uint8_t first_entry;
uint8_t samp_count;
uint32_t pre_vmax;
uint32_t hw_monitor_delay;
struct aw_monitor_trace temp_trace;
struct aw_monitor_trace vol_trace;
#ifdef AW_DEBUG
uint16_t test_vol;
int16_t test_temp;
#endif
};
/******************************************************************
* aw882xx monitor functions
*******************************************************************/
void aw_monitor_start(struct aw_monitor_desc *monitor_desc);
int aw_monitor_stop(struct aw_monitor_desc *monitor_desc);
void aw_monitor_init(struct aw_monitor_desc *monitor_desc);
void aw_monitor_deinit(struct aw_monitor_desc *monitor_desc);
int aw_monitor_parse_fw(struct aw_monitor_desc *monitor_desc,
uint8_t *data, uint32_t data_len);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,778 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* aw_spin.c aw883xx spin module
*
* Copyright (c) 2020 AWINIC Technology CO., LTD
*
* Author: Bruce zhao <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 <linux/module.h>
#include <linux/i2c.h>
#include <sound/soc.h>
#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/version.h>
#include <linux/syscalls.h>
#include <sound/control.h>
#include <linux/uaccess.h>
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include "aw_spin.h"
#include "aw_device.h"
#include "aw883xx.h"
#include "aw_log.h"
static DEFINE_MUTEX(g_aw_spin_lock);
static unsigned int g_spin_angle = AW_SPIN_0;
static unsigned int g_spin_mode = AW_SPIN_OFF_MODE;
static const char *const aw_spin[] = {"spin_0", "spin_90",
"spin_180", "spin_270"};
#ifdef AW_MTK_PLATFORM_SPIN
extern int mtk_spk_send_ipi_buf_to_dsp(void *data_buffer, uint32_t data_size);
extern int mtk_spk_recv_ipi_buf_from_dsp(int8_t *buffer, int16_t size, uint32_t *buf_len);
#elif defined AW_QCOM_PLATFORM_SPIN
extern int afe_get_topology(int port_id);
extern int aw_send_afe_cal_apr(uint32_t param_id,
void *buf, int cmd_size, bool write);
#else
static int aw_send_afe_cal_apr(uint32_t param_id,
void *buf, int cmd_size, bool write)
{
return 0;
}
static int afe_get_topology(int port_id)
{
return 0;
}
#endif
static int aw_get_msg_id(int dev_ch, uint32_t *msg_id)
{
switch (dev_ch) {
case AW_DEV_CH_PRI_L:
*msg_id = AFE_MSG_ID_MSG_0;
break;
case AW_DEV_CH_PRI_R:
*msg_id = AFE_MSG_ID_MSG_0;
break;
case AW_DEV_CH_SEC_L:
*msg_id = AFE_MSG_ID_MSG_1;
break;
case AW_DEV_CH_SEC_R:
*msg_id = AFE_MSG_ID_MSG_1;
break;
default:
pr_err("%s: can not find msg num, channel %d ", __func__, dev_ch);
return -EINVAL;
}
pr_debug("%s: msg id[%d] ", __func__, *msg_id);
return 0;
}
#ifdef AW_MTK_PLATFORM_SPIN
static int aw_mtk_write_data_to_dsp(int msg_id, void *data, int size)
{
int32_t *dsp_data = NULL;
struct aw_msg_hdr *hdr = NULL;
int ret;
dsp_data = kzalloc(sizeof(struct aw_msg_hdr) + size, GFP_KERNEL);
if (!dsp_data) {
pr_err("%s: kzalloc dsp_msg error\n", __func__);
return -ENOMEM;
}
hdr = (struct aw_msg_hdr *)dsp_data;
hdr->type = AW_DSP_MSG_TYPE_DATA;
hdr->opcode_id = msg_id;
hdr->version = AW_DSP_MSG_HDR_VER;
memcpy(((char *)dsp_data) + sizeof(struct aw_msg_hdr), data, size);
ret = mtk_spk_send_ipi_buf_to_dsp(dsp_data,
sizeof(struct aw_msg_hdr) + size);
if (ret < 0) {
pr_err("%s: write data failed\n", __func__);
kfree(dsp_data);
dsp_data = NULL;
return ret;
}
kfree(dsp_data);
dsp_data = NULL;
return 0;
}
static int aw_mtk_set_spin_angle(struct aw_device *aw_dev, uint32_t spin_angle)
{
int ret;
ret = aw_mtk_write_data_to_dsp(AW_MSG_ID_SPIN, &spin_angle, sizeof(uint32_t));
if (ret)
aw_dev_err(aw_dev->dev, "write data to dsp failed");
return ret;
}
static int aw_mtk_get_spin_angle(void *spin_angle, int size)
{
int ret;
struct aw_msg_hdr hdr;
hdr.type = AW_DSP_MSG_TYPE_CMD;
hdr.opcode_id = AW_MSG_ID_SPIN;
hdr.version = AW_DSP_MSG_HDR_VER;
ret = mtk_spk_send_ipi_buf_to_dsp(&hdr, sizeof(struct aw_msg_hdr));
if (ret < 0) {
pr_err("%s:send cmd failed\n", __func__);
return ret;
}
ret = mtk_spk_recv_ipi_buf_from_dsp(spin_angle, size, &size);
if (ret < 0) {
pr_err("%s:get data failed\n", __func__);
return ret;
}
return 0;
}
static int aw_mtk_set_mixer_en(struct aw_device *aw_dev, uint32_t msg_id, int32_t is_enable)
{
int32_t *dsp_msg = NULL;
struct aw_msg_hdr *hdr = NULL;
int ret;
dsp_msg = kzalloc(sizeof(struct aw_msg_hdr) + sizeof(int32_t), GFP_KERNEL);
if (!dsp_msg) {
aw_dev_err(aw_dev->dev, "kzalloc dsp_msg error");
return -ENOMEM;
}
hdr = (struct aw_msg_hdr *)dsp_msg;
hdr->type = AW_DSP_MSG_TYPE_DATA;
hdr->opcode_id = AW_INLINE_ID_AUDIO_MIX;
hdr->version = AW_DSP_MSG_HDR_VER;
memcpy(((char *)dsp_msg) + sizeof(struct aw_msg_hdr),
(char *)&is_enable, sizeof(int32_t));
ret = aw_mtk_write_data_to_dsp(msg_id, (void *)dsp_msg,
sizeof(struct aw_msg_hdr) + sizeof(int32_t));
if (ret < 0) {
aw_dev_err(aw_dev->dev, " write data failed");
kfree(dsp_msg);
dsp_msg = NULL;
return ret;
}
kfree(dsp_msg);
dsp_msg = NULL;
return 0;
}
#else
static int aw_check_dsp_ready(void)
{
int ret;
ret = afe_get_topology(AW_RX_PORT_ID);
pr_debug("topo_id 0x%x ", ret);
if (ret != AW_RX_TOPO_ID)
return false;
else
return true;
}
static int aw_qcom_write_data_to_dsp(uint32_t msg_id, void *data, int size)
{
int ret;
int try = 0;
while (try < AW_DSP_TRY_TIME) {
if (aw_check_dsp_ready()) {
ret = aw_send_afe_cal_apr(msg_id, data, size, true);
return ret;
} else {
try++;
usleep_range(AW_10000_US, AW_10000_US + 10);
pr_info("%s: afe topo not ready try again\n", __func__);
}
}
return -EINVAL;
}
static int aw_qcom_read_data_from_dsp(uint32_t msg_id, void *data, int size)
{
int ret;
int try = 0;
while (try < AW_DSP_TRY_TIME) {
if (aw_check_dsp_ready()) {
ret = aw_send_afe_cal_apr(msg_id, data, size, false);
return ret;
} else {
try++;
usleep_range(AW_10000_US, AW_10000_US + 10);
pr_info("%s: afe topo not ready try again\n", __func__);
}
}
return -EINVAL;
}
static int aw_qcom_set_spin_angle(struct aw_device *aw_dev,
uint32_t spin_angle)
{
int ret;
ret = aw_qcom_write_data_to_dsp(AW_MSG_ID_SPIN, &spin_angle, sizeof(uint32_t));
if (ret)
aw_dev_err(aw_dev->dev, "write spin angle to dsp failed");
else
aw_dev_info(aw_dev->dev, "write spin angle to dsp successful");
return ret;
}
static int aw_qcom_get_spin_angle(uint32_t *spin_angle, int size)
{
int ret;
ret = aw_qcom_read_data_from_dsp(AW_MSG_ID_SPIN, spin_angle, size);
if (ret)
pr_err("%s: get spin angle failed\n", __func__);
else
pr_info("%s: get spin angle successful\n", __func__);
return ret;
}
static int aw_qcom_set_mixer_en(struct aw_device *aw_dev,
uint32_t msg_id, int32_t is_enable)
{
int32_t *dsp_msg;
int ret = 0;
int msg_len = (int)(sizeof(struct aw_msg_hdr) + sizeof(int32_t));
dsp_msg = kzalloc(msg_len, GFP_KERNEL);
if (!dsp_msg) {
aw_dev_err(aw_dev->dev, "kzalloc dsp_msg error");
return -ENOMEM;
}
dsp_msg[0] = AW_DSP_MSG_TYPE_DATA;
dsp_msg[1] = AW_INLINE_ID_AUDIO_MIX;
dsp_msg[2] = AW_DSP_MSG_HDR_VER;
memcpy(dsp_msg + (sizeof(struct aw_msg_hdr) / sizeof(int32_t)),
(char *)&is_enable, sizeof(int32_t));
ret = aw_qcom_write_data_to_dsp(msg_id, (void *)dsp_msg, msg_len);
if (ret < 0) {
aw_dev_err(aw_dev->dev, "write data to dsp failed");
kfree(dsp_msg);
return ret;
}
aw_dev_dbg(aw_dev->dev, "write data[%d] to dsp success", msg_len);
kfree(dsp_msg);
return 0;
}
#endif
/***********************************spin_angle**********************************/
static int aw_set_adsp_spin_angle(struct aw_device *aw_dev, uint32_t spin_angle)
{
if (spin_angle >= AW_SPIN_MAX) {
aw_dev_err(aw_dev->dev, "spin_angle:%d not support",
spin_angle);
return -EINVAL;
}
#ifdef AW_MTK_PLATFORM_SPIN
return aw_mtk_set_spin_angle(aw_dev, spin_angle);
#else
return aw_qcom_set_spin_angle(aw_dev, spin_angle);
#endif
}
static void aw_get_adsp_spin_angle(uint32_t *spin_angle)
{
#ifdef AW_MTK_PLATFORM_SPIN
aw_mtk_get_spin_angle(spin_angle, sizeof(uint32_t));
#else
aw_qcom_get_spin_angle(spin_angle, sizeof(uint32_t));
#endif
}
/*******************************************************************************/
/**********************************mixer_status*********************************/
static int aw_set_mixer_en(struct aw_device *aw_dev, int32_t is_enable)
{
int ret;
uint32_t msg_id;
ret = aw_get_msg_id(aw_dev->channel, &msg_id);
if (ret < 0) {
aw_dev_err(aw_dev->dev, "get msg_num failed");
return ret;
}
#ifdef AW_MTK_PLATFORM_SPIN
ret = aw_mtk_set_mixer_en(aw_dev, msg_id, is_enable);
#else
ret = aw_qcom_set_mixer_en(aw_dev, msg_id, is_enable);
#endif
if (ret)
aw_dev_err(aw_dev->dev, "set mixer status failed");
return ret;
}
int aw_hold_reg_spin_st(struct aw_spin_desc *spin_desc)
{
struct aw_device *aw_dev = container_of(spin_desc,
struct aw_device, spin_desc);
uint16_t reg_val;
if (aw_dev == NULL) {
aw_pr_err("aw_dev is NULL");
return -EINVAL;
}
mutex_lock(&g_aw_spin_lock);
if ((g_spin_mode == AW_REG_SPIN_MODE) ||
(g_spin_mode == AW_REG_MIXER_SPIN_MODE)) {
/*set rx*/
aw_dev->ops.aw_reg_read(aw_dev,
aw_dev->chansel_desc.rxchan_reg, &reg_val);
reg_val &= aw_dev->chansel_desc.rxchan_mask;
reg_val |= spin_desc->spin_table[g_spin_angle].rx_val;
aw_dev->ops.aw_reg_write(aw_dev,
aw_dev->chansel_desc.rxchan_reg, reg_val);
/*set tx*/
aw_dev->ops.aw_reg_read(aw_dev,
aw_dev->chansel_desc.txchan_reg, &reg_val);
reg_val &= aw_dev->chansel_desc.txchan_mask;
reg_val |= spin_desc->spin_table[g_spin_angle].tx_val;
aw_dev->ops.aw_reg_write(aw_dev,
aw_dev->chansel_desc.txchan_reg, reg_val);
}
mutex_unlock(&g_aw_spin_lock);
return 0;
}
int aw_check_spin_mode(struct aw_spin_desc *spin_desc)
{
struct list_head *pos = NULL;
struct list_head *dev_list = NULL;
struct aw_device *local_pa = NULL;
int ret = -1;
int spin_mode = AW_SPIN_OFF_MODE;
struct aw_device *aw_dev = container_of(spin_desc,
struct aw_device, spin_desc);
struct aw883xx *aw883xx = (struct aw883xx *)aw_dev->private_data;
if (g_spin_mode == AW_SPIN_OFF_MODE) {
aw883xx->spin_flag = AW_SPIN_OFF;
return 0;
}
ret = aw_dev_get_list_head(&dev_list);
if (ret) {
aw_pr_err("get dev list failed");
return ret;
}
list_for_each(pos, dev_list) {
local_pa = container_of(pos, struct aw_device, list_node);
spin_mode = local_pa->spin_desc.spin_mode;
if (g_spin_mode != spin_mode) {
aw_pr_err("dev[%d] spin mode:%d not equal g_spin_mode:%d, check failed",
local_pa->channel, spin_mode, g_spin_mode);
aw883xx->spin_flag = AW_SPIN_OFF;
return -EINVAL;
}
}
aw883xx->spin_flag = AW_SPIN_ON;
return 0;
}
int aw_hold_dsp_spin_st(struct aw_spin_desc *spin_desc)
{
struct aw_device *aw_dev = container_of(spin_desc,
struct aw_device, spin_desc);
int ret = -1;
if (aw_dev == NULL) {
aw_pr_err("aw_dev is NULL");
return -EINVAL;
}
if (aw_dev->channel == 0) {
if (g_spin_mode == AW_ADSP_SPIN_MODE) {
ret = aw_set_adsp_spin_angle(aw_dev,
g_spin_angle);
if (ret < 0)
return ret;
}
}
return ret;
}
static int aw_set_channal_mode(struct aw_device *aw_pa,
uint32_t spin_angle)
{
int ret;
struct aw_chansel_desc *chansel_desc = &aw_pa->chansel_desc;
struct aw_spin_ch *spin_ch = &aw_pa->spin_desc.spin_table[spin_angle];
ret = aw_pa->ops.aw_reg_write_bits(aw_pa, chansel_desc->rxchan_reg,
chansel_desc->rxchan_mask, spin_ch->rx_val);
if (ret < 0) {
aw_dev_err(aw_pa->dev, "set rx failed");
return ret;
}
ret = aw_pa->ops.aw_reg_write_bits(aw_pa, chansel_desc->txchan_reg,
chansel_desc->txchan_mask, spin_ch->tx_val);
if (ret < 0) {
aw_dev_err(aw_pa->dev, "set tx failed");
return ret;
}
aw_dev_dbg(aw_pa->dev, "set channel mode done!");
return 0;
}
static int aw_set_reg_spin_angle(struct aw883xx *aw883xx, uint32_t spin_angle)
{
struct list_head *pos = NULL;
struct list_head *dev_list = NULL;
struct aw_device *local_pa = NULL;
int ret;
if (spin_angle >= ARRAY_SIZE(aw_spin)) {
aw_dev_err(aw883xx->dev, "spin_angle:%d not support",
spin_angle);
return -EINVAL;
}
ret = aw_dev_get_list_head(&dev_list);
if (ret) {
aw_dev_err(aw883xx->dev, "get dev list failed");
return ret;
}
list_for_each(pos, dev_list) {
local_pa = container_of(pos, struct aw_device, list_node);
ret = aw_set_channal_mode(local_pa, spin_angle);
if (ret < 0) {
aw_dev_err(aw883xx->dev, "set channal mode failed");
return ret;
}
}
return 0;
}
static int aw_set_reg_mixer_spin_angle(struct aw883xx *aw883xx, uint32_t spin_angle)
{
int ret;
if (spin_angle >= ARRAY_SIZE(aw_spin)) {
aw_dev_err(aw883xx->dev, "spin_angle:%d not support",
spin_angle);
return -EINVAL;
}
ret = aw_set_mixer_en(aw883xx->aw_pa, AW_AUDIO_MIX_ENABLE);
if (ret)
return ret;
usleep_range(AW_100000_US, AW_100000_US + 10);
aw_set_reg_spin_angle(aw883xx, spin_angle);
ret = aw_set_mixer_en(aw883xx->aw_pa, AW_AUDIO_MIX_DISABLE);
if (ret)
return ret;
return ret;
}
static void aw_get_reg_spin_angle(uint32_t *spin_angle)
{
*spin_angle = g_spin_angle;
pr_debug("%s: get spin:%s\n", __func__, aw_spin[g_spin_angle]);
}
static int aw_set_spin_angle(struct aw883xx *aw883xx, uint32_t spin_angle)
{
switch (g_spin_mode) {
case AW_REG_SPIN_MODE:
return aw_set_reg_spin_angle(aw883xx, spin_angle);
case AW_ADSP_SPIN_MODE:
return aw_set_adsp_spin_angle(aw883xx->aw_pa, spin_angle);
case AW_REG_MIXER_SPIN_MODE:
return aw_set_reg_mixer_spin_angle(aw883xx, spin_angle);
default:
aw_pr_err("unsupported spin mode:%d", g_spin_mode);
return -EINVAL;
}
}
static void aw_set_spin_mode(int mode)
{
g_spin_mode = mode;
}
static int aw_set_spin(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aw883xx *aw883xx = (struct aw883xx *)kcontrol->private_value;
uint32_t ctrl_value;
int ret;
aw_dev_dbg(aw883xx->dev, "ucontrol->value.integer.value[0]=%ld",
ucontrol->value.integer.value[0]);
if (aw883xx->spin_flag == AW_SPIN_OFF) {
aw_dev_dbg(aw883xx->dev, "spin func not enable");
return 0;
}
ctrl_value = ucontrol->value.integer.value[0];
mutex_lock(&g_aw_spin_lock);
if (aw883xx->pstream == AW883XX_STREAM_OPEN) {
ret = aw_set_spin_angle(aw883xx, ctrl_value);
if (ret < 0)
aw_dev_err(aw883xx->dev, "set spin error, ret=%d\n",
ret);
} else {
if ((g_spin_mode == AW_REG_SPIN_MODE) || (g_spin_mode == AW_REG_MIXER_SPIN_MODE))
aw_set_reg_spin_angle(aw883xx, ctrl_value);
else
aw_dev_info(aw883xx->dev, "stream no start only record spin angle");
}
g_spin_angle = ctrl_value;
mutex_unlock(&g_aw_spin_lock);
return 0;
}
static void aw_get_spin_angle(uint32_t *spin_angle)
{
if ((g_spin_mode == AW_REG_SPIN_MODE) || (g_spin_mode == AW_REG_MIXER_SPIN_MODE))
aw_get_reg_spin_angle(spin_angle);
else if (g_spin_mode == AW_ADSP_SPIN_MODE)
aw_get_adsp_spin_angle(spin_angle);
}
static int aw_get_spin(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aw883xx *aw883xx = (struct aw883xx *)kcontrol->private_value;
uint32_t ctrl_value = 0;
mutex_lock(&g_aw_spin_lock);
if (aw883xx->pstream == AW883XX_STREAM_OPEN) {
aw_get_spin_angle(&ctrl_value);
ucontrol->value.integer.value[0] = ctrl_value;
} else {
ucontrol->value.integer.value[0] = g_spin_angle;
aw_dev_dbg(aw883xx->dev, "no stream, use record value");
}
mutex_unlock(&g_aw_spin_lock);
return 0;
}
static int aw_spin_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct aw883xx *aw883xx = (struct aw883xx *)kcontrol->private_value;
int count = 0;
if (aw883xx == NULL) {
aw_pr_err("get struct aw883xx failed");
return -EINVAL;
}
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
count = ARRAY_SIZE(aw_spin);
uinfo->value.enumerated.items = count;
if (uinfo->value.enumerated.item >= count)
uinfo->value.enumerated.item = count - 1;
strlcpy(uinfo->value.enumerated.name,
aw_spin[uinfo->value.enumerated.item],
strlen(aw_spin[uinfo->value.enumerated.item]) + 1);
return 0;
}
static int aw_spin_control_create(struct aw883xx *aw883xx)
{
int kcontrol_num = 1;
struct snd_kcontrol_new *aw_spin_control = NULL;
char *kctl_name = NULL;
aw_spin_control = devm_kzalloc(aw883xx->codec->dev,
sizeof(struct snd_kcontrol_new) * 1, GFP_KERNEL);
if (aw_spin_control == NULL) {
aw_dev_err(aw883xx->codec->dev, "kcontrol malloc failed!");
return -ENOMEM;
}
kctl_name = devm_kzalloc(aw883xx->codec->dev, AW_NAME_BUF_MAX, GFP_KERNEL);
if (kctl_name == NULL)
return -ENOMEM;
snprintf(kctl_name, AW_NAME_BUF_MAX, "aw_spin_switch");
aw_spin_control[0].name = kctl_name;
aw_spin_control[0].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
aw_spin_control[0].info = aw_spin_info;
aw_spin_control[0].get = aw_get_spin;
aw_spin_control[0].put = aw_set_spin;
aw_spin_control[0].private_value = (unsigned long)aw883xx;
kctl_name = devm_kzalloc(aw883xx->codec->dev, AW_NAME_BUF_MAX, GFP_KERNEL);
if (!kctl_name)
return -ENOMEM;
aw883xx->codec_ops->add_codec_controls(aw883xx->codec,
aw_spin_control, kcontrol_num);
return 0;
}
void aw_add_spin_controls(void *aw_dev)
{
struct aw883xx *aw883xx = (struct aw883xx *)aw_dev;
if (aw883xx->aw_pa->spin_desc.spin_mode != AW_SPIN_OFF_MODE)
aw_spin_control_create(aw883xx);
}
static int aw_parse_spin_table_dt(struct aw_device *aw_dev,
struct device_node *np)
{
int ret = -1;
const char *str_data = NULL;
char spin_table_str[AW_SPIN_MAX] = { 0 };
int i, spin_count = 0;
ret = of_property_read_string(np, "spin-data", &str_data);
if (ret < 0) {
aw_dev_err(aw_dev->dev, "get spin_data failed, close spin function");
return ret;
}
ret = sscanf(str_data, "%c %c %c %c",
&spin_table_str[AW_SPIN_0], &spin_table_str[AW_SPIN_90],
&spin_table_str[AW_SPIN_180], &spin_table_str[AW_SPIN_270]);
if (ret != AW_SPIN_MAX) {
aw_dev_err(aw_dev->dev, "unsupported str:%s, close spin function",
str_data);
return -EINVAL;
}
for (i = 0; i < AW_SPIN_MAX; i++) {
if (spin_table_str[i] == 'l' || spin_table_str[i] == 'L') {
aw_dev->spin_desc.spin_table[i].rx_val = aw_dev->chansel_desc.rx_left;
aw_dev->spin_desc.spin_table[i].tx_val = aw_dev->chansel_desc.tx_left;
spin_count++;
} else if (spin_table_str[i] == 'r' || spin_table_str[i] == 'R') {
aw_dev->spin_desc.spin_table[i].rx_val = aw_dev->chansel_desc.rx_right;
aw_dev->spin_desc.spin_table[i].tx_val = aw_dev->chansel_desc.tx_right;
spin_count++;
} else {
aw_dev_err(aw_dev->dev, "unsupported str:%s, close spin function",
str_data);
return -EINVAL;
}
}
if (spin_count != ARRAY_SIZE(aw_spin)) {
aw_dev_err(aw_dev->dev, "get spin_data failed, spin_count:%d", spin_count);
return -EINVAL;
}
return 0;
}
static int aw_parse_spin_mode_dt(struct aw_device *aw_dev)
{
int ret = -1;
const char *spin_mode = NULL;
int mode;
struct device_node *np = aw_dev->dev->of_node;
ret = of_property_read_string(np, "spin-mode", &spin_mode);
if (ret < 0) {
aw_dev_info(aw_dev->dev,
"spin-mode get failed, spin switch off");
aw_dev->spin_desc.spin_mode = AW_SPIN_OFF_MODE;
return 0;
}
if (!strcmp(spin_mode, "dsp_spin"))
mode = AW_ADSP_SPIN_MODE;
else if (!strcmp(spin_mode, "reg_spin"))
mode = AW_REG_SPIN_MODE;
else if (!strcmp(spin_mode, "reg_mixer_spin"))
mode = AW_REG_MIXER_SPIN_MODE;
else
mode = AW_SPIN_OFF_MODE;
aw_dev->spin_desc.spin_mode = mode;
aw_set_spin_mode(mode);
if ((mode == AW_REG_SPIN_MODE) || (mode == AW_REG_MIXER_SPIN_MODE)) {
ret = aw_parse_spin_table_dt(aw_dev, np);
if (ret < 0) {
aw_dev->spin_desc.spin_mode = AW_SPIN_OFF_MODE;
aw_dev_err(aw_dev->dev,
"spin-table get failed, ret = %d", ret);
return ret;
}
}
aw_dev_info(aw_dev->dev, "spin mode is %d", mode);
return 0;
}
void aw_spin_init(struct aw_spin_desc *spin_desc)
{
struct aw_device *aw_dev = container_of(spin_desc,
struct aw_device, spin_desc);
aw_parse_spin_mode_dt(aw_dev);
}

View File

@@ -0,0 +1,73 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __AW_SPIN_H__
#define __AW_SPIN_H__
/*#define AW_MTK_PLATFORM_SPIN*/
/*#define AW_QCOM_PLATFORM_SPIN*/
#define AW_DSP_TRY_TIME (3)
#define AW_DSP_MSG_HDR_VER (1)
#define AFE_MSG_ID_MSG_0 (0X10013D2A)
#define AFE_MSG_ID_MSG_1 (0X10013D2B)
#define AW_RX_PORT_ID (0x1006)
#define AW_RX_TOPO_ID (0x1000FF01)
#define AW_MSG_ID_SPIN (0x10013D2E)
#define AW_INLINE_ID_AUDIO_MIX (0x0000000B)
enum {
AW_DEV_CH_PRI_L = 0,
AW_DEV_CH_PRI_R = 1,
AW_DEV_CH_SEC_L = 2,
AW_DEV_CH_SEC_R = 3,
AW_DEV_CHAN_MAX,
};
enum aw_dsp_msg_type {
AW_DSP_MSG_TYPE_DATA = 0,
AW_DSP_MSG_TYPE_CMD = 1,
};
enum {
AW_SPIN_OFF = 0,
AW_SPIN_ON = 1,
};
enum {
AW_SPIN_0 = 0,
AW_SPIN_90,
AW_SPIN_180,
AW_SPIN_270,
AW_SPIN_MAX,
};
enum {
AW_SPIN_OFF_MODE = 0,
AW_ADSP_SPIN_MODE,
AW_REG_SPIN_MODE,
AW_REG_MIXER_SPIN_MODE,
AW_SPIN_MODE_MAX,
};
enum {
AW_AUDIO_MIX_DISABLE = 0,
AW_AUDIO_MIX_ENABLE,
};
struct aw_spin_ch {
uint16_t rx_val;
uint16_t tx_val;
};
struct aw_spin_desc {
struct aw_spin_ch spin_table[AW_SPIN_MAX];
uint32_t spin_mode;
};
int aw_check_spin_mode(struct aw_spin_desc *spin_desc);
int aw_hold_dsp_spin_st(struct aw_spin_desc *spin_desc);
int aw_hold_reg_spin_st(struct aw_spin_desc *spin_desc);
void aw_add_spin_controls(void *aw_dev);
void aw_spin_init(struct aw_spin_desc *spin_desc);
#endif