mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
ASoC: codecs: add aw883xx smart PA
Signed-off-by: XiaoTan Luo <lxt@rock-chips.com> Change-Id: Iad30b10913ff922e71ec21cdb59ddd829ca69164
This commit is contained in:
@@ -1874,4 +1874,5 @@ config SND_SOC_TPA6130A2
|
||||
depends on I2C
|
||||
|
||||
source "sound/soc/codecs/aw87xxx/Kconfig"
|
||||
source "sound/soc/codecs/aw883xx/Kconfig"
|
||||
endmenu
|
||||
|
||||
@@ -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
|
||||
|
||||
5
sound/soc/codecs/aw883xx/Kconfig
Normal file
5
sound/soc/codecs/aw883xx/Kconfig
Normal 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.
|
||||
3
sound/soc/codecs/aw883xx/Makefile
Normal file
3
sound/soc/codecs/aw883xx/Makefile
Normal 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
|
||||
2574
sound/soc/codecs/aw883xx/aw883xx.c
Normal file
2574
sound/soc/codecs/aw883xx/aw883xx.c
Normal file
File diff suppressed because it is too large
Load Diff
201
sound/soc/codecs/aw883xx/aw883xx.h
Normal file
201
sound/soc/codecs/aw883xx/aw883xx.h
Normal 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
|
||||
1404
sound/soc/codecs/aw883xx/aw_bin_parse.c
Normal file
1404
sound/soc/codecs/aw883xx/aw_bin_parse.c
Normal file
File diff suppressed because it is too large
Load Diff
141
sound/soc/codecs/aw883xx/aw_bin_parse.h
Normal file
141
sound/soc/codecs/aw883xx/aw_bin_parse.h
Normal 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_V1:default 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
|
||||
2509
sound/soc/codecs/aw883xx/aw_calib.c
Normal file
2509
sound/soc/codecs/aw883xx/aw_calib.c
Normal file
File diff suppressed because it is too large
Load Diff
147
sound/soc/codecs/aw883xx/aw_calib.h
Normal file
147
sound/soc/codecs/aw883xx/aw_calib.h
Normal 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
|
||||
|
||||
|
||||
150
sound/soc/codecs/aw883xx/aw_data_type.h
Normal file
150
sound/soc/codecs/aw883xx/aw_data_type.h
Normal 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
|
||||
|
||||
1677
sound/soc/codecs/aw883xx/aw_device.c
Normal file
1677
sound/soc/codecs/aw883xx/aw_device.c
Normal file
File diff suppressed because it is too large
Load Diff
533
sound/soc/codecs/aw883xx/aw_device.h
Normal file
533
sound/soc/codecs/aw883xx/aw_device.h
Normal 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
|
||||
|
||||
630
sound/soc/codecs/aw883xx/aw_init.c
Normal file
630
sound/soc/codecs/aw883xx/aw_init.c
Normal 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, ®_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, ®_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, ®_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;
|
||||
}
|
||||
}
|
||||
|
||||
54
sound/soc/codecs/aw883xx/aw_log.h
Normal file
54
sound/soc/codecs/aw883xx/aw_log.h
Normal 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
|
||||
|
||||
1217
sound/soc/codecs/aw883xx/aw_monitor.c
Normal file
1217
sound/soc/codecs/aw883xx/aw_monitor.c
Normal file
File diff suppressed because it is too large
Load Diff
159
sound/soc/codecs/aw883xx/aw_monitor.h
Normal file
159
sound/soc/codecs/aw883xx/aw_monitor.h
Normal 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
|
||||
|
||||
2381
sound/soc/codecs/aw883xx/aw_pid_2049_reg.h
Normal file
2381
sound/soc/codecs/aw883xx/aw_pid_2049_reg.h
Normal file
File diff suppressed because it is too large
Load Diff
778
sound/soc/codecs/aw883xx/aw_spin.c
Normal file
778
sound/soc/codecs/aw883xx/aw_spin.c
Normal 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, ®_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, ®_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);
|
||||
}
|
||||
|
||||
73
sound/soc/codecs/aw883xx/aw_spin.h
Normal file
73
sound/soc/codecs/aw883xx/aw_spin.h
Normal 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
|
||||
Reference in New Issue
Block a user