Merge tag 'MMI-U1UGS34.23-110-23-2' of https://github.com/MotorolaMobilityLLC/kernel-msm-5.4-techpack-audio into lineage-22.2

Fogos push for Android 14

* tag 'MMI-U1UGS34.23-110-23-2' of https://github.com/MotorolaMobilityLLC/kernel-msm-5.4-techpack-audio: (79 commits)
  Revert "asoc: msm-compress : Fix for CTS-on-gsi with gki"
  soc: swr-mstr-ctrl: allow runtime suspend first before system suspend
  audio:add lock for aw dynamics set dailink
  Revert "(CR):audio:add lock for aw dynamics set dailink"
  dsp: q6lsm: Address use after free for mmap handle
  dsp: q6lsm: Add check for payload buffer
  ASoC: msm-pcm-host-voice: Check validity of session idx
  audio:add lock for aw dynamics set dailink
  q6fsm:add protect for fs1815 algo
  fs1815:correct rotation code
  aw882xxacf: add hac scene algo ctrl
  audio-kernel: fix build fail caused by aw8838
  techpack:add aw8838 driver
  fsm:correct fsm vbat monitor logic
  audio/dsp:reduce fsm vbat monitor retry times
  audio/asoc:add PRI_MI2S_TX_HOSTLESS
  machie_driver:add aw pri I2S dailink
  audio:add fs1815 bypass algo code and logic.
  Awinic: update communicate with adsp logic
  codecs:add fs1815 PA driver
  ...

 Conflicts:
	techpack/audio/dsp/q6lsm.c

Change-Id: I6ec23f0d578fd2494e5e29577ce470dc2cb90f5c
This commit is contained in:
Michael Bestas 2025-03-21 18:35:48 +02:00
commit 0cd369436c
No known key found for this signature in database
83 changed files with 61723 additions and 18 deletions

View file

@ -261,6 +261,18 @@ INCS += $(COMMON_INC) \
EXTRA_CFLAGS += $(INCS)
ifeq ($(CONFIG_AW882XX_STEREO_SMARTPA), y)
EXTRA_CFLAGS += -DCONFIG_AW882XX_STEREO_SMARTPA
endif
ifeq ($(CONFIG_AW882XX_STEREO_SMARTPA_PRI), y)
EXTRA_CFLAGS += -DCONFIG_AW882XX_STEREO_SMARTPA_PRI
endif
ifeq ($(CONFIG_SND_SOC_AW8838), y)
EXTRA_CFLAGS += -DCONFIG_SND_SOC_AW8838
endif
CDEFINES += -DANI_LITTLE_BYTE_ENDIAN \
-DANI_LITTLE_BIT_ENDIAN \
-DDOT11F_LITTLE_ENDIAN_HOST \
@ -271,6 +283,14 @@ CDEFINES += -DANI_LITTLE_BYTE_ENDIAN \
-Werror\
-D__linux__
ifdef CONFIG_SND_SOC_AW87XXX
CDEFINES += -DCONFIG_SND_SOC_AW87XXX
endif
ifdef CONFIG_SND_SOC_FS1815
CDEFINES += -DCONFIG_SND_SOC_FS1815
endif
KBUILD_CPPFLAGS += $(CDEFINES)
# Currently, for versions of gcc which support it, the kernel Makefile
@ -291,6 +311,7 @@ KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/dsp/Module
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/Module.symvers
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/Module.symvers
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/Module.symvers
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/aw8838/Module.symvers
endif
ifeq ($(KERNEL_BUILD), 1)
obj-y += codecs/

View file

@ -274,6 +274,13 @@ ifeq ($(KERNEL_BUILD), 1)
obj-y += bolero/
obj-y += wsa883x/
obj-y += rouleur/
obj-y += aw882xx/
obj-y += aw882xxacf/
obj-y += aw87xxx/
obj-y += fs1815/
ifeq ($(CONFIG_SND_SOC_AW8838), y)
obj-y += aw8838/
endif
endif
# Module information used by KBuild framework
obj-$(CONFIG_WCD9XXX_CODEC_CORE) += wcd_core_dlkm.o

View file

@ -0,0 +1,16 @@
# add -Wall to try to catch everything we can.
EXTRA_CFLAGS += -Wall
EXTRA_CFLAGS += -I$(TOP)/kernel/msm-5.4/techpack/audio/include
EXTRA_CFLAGS += -I$(TOP)/kernel/msm-5.4/techpack/audio/include/uapi/
ifdef CONFIG_SND_SOC_AW87XXX
AW87XXX_OBJS += aw87xxx.o
AW87XXX_OBJS += aw87xxx_device.o
AW87XXX_OBJS += aw87xxx_monitor.o
AW87XXX_OBJS += aw87xxx_bin_parse.o
AW87XXX_OBJS += aw87xxx_dsp.o
AW87XXX_OBJS += aw87xxx_acf_bin.o
endif
obj-$(CONFIG_SND_SOC_AW87XXX) += aw87xxx_dlkm.o
aw87xxx_dlkm-y := $(AW87XXX_OBJS)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,127 @@
#ifndef __AW87XXX_H__
#define __AW87XXX_H__
#include <linux/version.h>
#include <linux/kernel.h>
#include <sound/control.h>
#include <sound/soc.h>
#include "aw87xxx_device.h"
#include "aw87xxx_monitor.h"
#include "aw87xxx_acf_bin.h"
#define AW_CFG_UPDATE_DELAY
#define AW_CFG_UPDATE_DELAY_TIMER (3000)
#define AW87XXX_NO_OFF_BIN (0)
#define AW87XXX_OFF_BIN_OK (1)
#define AW87XXX_PRIVATE_KCONTROL_NUM (3)
#define AW87XXX_PUBLIC_KCONTROL_NUM (4)
#define AW_I2C_RETRIES (5)
#define AW_I2C_RETRY_DELAY (2)
#define AW_I2C_READ_MSG_NUM (2)
#define AW87XXX_FW_NAME_MAX (64)
#define AW_NAME_BUF_MAX (64)
#define AW_LOAD_FW_RETRIES (3)
#define AW_DEV_REG_RD_ACCESS (1 << 0)
#define AW_DEV_REG_WR_ACCESS (1 << 1)
#define AWRW_ADDR_BYTES (1)
#define AWRW_DATA_BYTES (1)
#define AWRW_HDR_LEN (24)
#define AW87XXX_RUNIN_TEST 1
/***********************************************************
*
* aw87xxx codec control compatible with kernel 4.19
*
***********************************************************/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 1)
#define AW_KERNEL_VER_OVER_4_19_1
#endif
#ifdef AW_KERNEL_VER_OVER_4_19_1
typedef struct snd_soc_component aw_snd_soc_codec_t;
#else
typedef struct snd_soc_codec aw_snd_soc_codec_t;
#endif
struct aw_componet_codec_ops {
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);
};
/********************************************
*
* aw87xxx devices attributes
*
*******************************************/
enum {
AWRW_FLAG_WRITE = 0,
AWRW_FLAG_READ,
};
enum {
AWRW_I2C_ST_NONE = 0,
AWRW_I2C_ST_READ,
AWRW_I2C_ST_WRITE,
};
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 aw_i2c_packet {
char status;
unsigned int reg_num;
unsigned int reg_addr;
char *reg_data;
};
/********************************************
*
* aw87xxx device struct
*
*******************************************/
struct aw87xxx {
char fw_name[AW87XXX_FW_NAME_MAX];
int32_t dev_index;
char *current_profile;
char prof_off_name[AW_PROFILE_STR_MAX];
uint32_t off_bin_status;
struct device *dev;
struct mutex reg_lock;
struct aw_device aw_dev;
struct aw_i2c_packet i2c_packet;
struct delayed_work fw_load_work;
struct acf_bin_info acf_info;
aw_snd_soc_codec_t *codec;
struct list_head list;
struct aw_monitor monitor;
#ifdef AW87XXX_RUNIN_TEST
struct delayed_work adsp_status;
#endif
struct delayed_work spin_status;
};
int aw87xxx_update_profile(struct aw87xxx *aw87xxx, char *profile);
int aw87xxx_update_profile_esd(struct aw87xxx *aw87xxx, char *profile);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,191 @@
#ifndef __AW87XXX_ACF_BIN_H__
#define __AW87XXX_ACF_BIN_H__
#include "aw87xxx_device.h"
#define AW_PROJECT_NAME_MAX (24)
#define AW_CUSTOMER_NAME_MAX (16)
#define AW_CFG_VERSION_MAX (4)
#define AW_TBL_VERSION_MAX (4)
#define AW_DDE_DEVICE_TYPE (0)
#define AW_DDE_SKT_TYPE (1)
#define AW_DDE_DEFAULT_TYPE (2)
#define AW_REG_ADDR_BYTE (1)
#define AW_REG_DATA_BYTE (1)
#define AW_ACF_FILE_ID (0xa15f908)
#define AW_PROFILE_STR_MAX (32)
#define AW_POWER_OFF_NAME_SUPPORT_COUNT (5)
enum aw_cfg_hdr_version {
AW_ACF_HDR_VER_0_0_0_1 = 0x00000001,
AW_ACF_HDR_VER_1_0_0_0 = 0x01000000,
};
enum aw_acf_dde_type_id {
AW_DEV_NONE_TYPE_ID = 0xFFFFFFFF,
AW_DDE_DEV_TYPE_ID = 0x00000000,
AW_DDE_SKT_TYPE_ID = 0x00000001,
AW_DDE_DEV_DEFAULT_TYPE_ID = 0x00000002,
AW_DDE_TYPE_MAX,
};
enum aw_raw_data_type_id {
AW_BIN_TYPE_REG = 0x00000000,
AW_BIN_TYPE_DSP,
AW_BIN_TYPE_DSP_CFG,
AW_BIN_TYPE_DSP_FW,
AW_BIN_TYPE_HDR_REG,
AW_BIN_TYPE_HDR_DSP_CFG,
AW_BIN_TYPE_HDR_DSP_FW,
AW_BIN_TYPE_MUTLBIN,
AW_SKT_UI_PROJECT,
AW_DSP_CFG,
AW_MONITOR,
AW_BIN_TYPE_MAX,
};
enum {
AW_DEV_TYPE_OK = 0,
AW_DEV_TYPE_NONE = 1,
};
enum aw_profile_status {
AW_PROFILE_WAIT = 0,
AW_PROFILE_OK,
};
enum aw_acf_load_status {
AW_ACF_WAIT = 0,
AW_ACF_UPDATE,
};
enum aw_bin_dev_profile_id {
AW_PROFILE_MUSIC = 0x0000,
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_OFF,
AW_PROFILE_MAX,
};
struct aw_acf_hdr {
int32_t a_id; /* acf file ID 0xa15f908 */
char project[AW_PROJECT_NAME_MAX]; /* project name */
char custom[AW_CUSTOMER_NAME_MAX]; /* custom name :huawei xiaomi vivo oppo */
uint8_t version[AW_CFG_VERSION_MAX]; /* author update version */
int32_t author_id; /* author id */
int32_t ddt_size; /* sub section table entry size */
int32_t dde_num; /* sub section table entry num */
int32_t ddt_offset; /* sub section table offset in file */
int32_t hdr_version; /* sub section table version */
int32_t reserve[3]; /* Reserved Bits */
};
struct aw_acf_dde {
int32_t type; /* dde type id */
char dev_name[AW_CUSTOMER_NAME_MAX]; /* customer dev name */
int16_t dev_index; /* dev id */
int16_t dev_bus; /* dev bus id */
int16_t dev_addr; /* dev addr id */
int16_t dev_profile; /* dev profile id */
int32_t data_type; /* data type id */
int32_t data_size; /* dde data size in block */
int32_t data_offset; /* dde data offset in block */
int32_t data_crc; /* dde data crc checkout */
int32_t reserve[5]; /* Reserved Bits */
};
struct aw_acf_dde_v_1_0_0_0 {
uint32_t type; /* DDE type id */
char dev_name[AW_CUSTOMER_NAME_MAX]; /* customer dev name */
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; /* dde data size in block */
uint32_t data_offset; /* dde data offset in block */
uint32_t data_crc; /* dde data crc checkout */
char dev_profile_str[AW_PROFILE_STR_MAX]; /* dde custom profile name */
uint32_t chip_id; /* dde custom product chip id */
uint32_t reserve[4];
};
struct aw_data_with_header {
uint32_t check_sum;
uint32_t header_ver;
uint32_t bin_data_type;
uint32_t bin_data_ver;
uint32_t bin_data_size;
uint32_t ui_ver;
char product[8];
uint32_t addr_byte_len;
uint32_t data_byte_len;
uint32_t device_addr;
uint32_t reserve[4];
};
struct aw_data_container {
uint32_t len;
uint8_t *data;
};
struct aw_prof_desc {
uint32_t prof_st;
char *prof_name;
char dev_name[AW_CUSTOMER_NAME_MAX];
struct aw_data_container data_container;
};
struct aw_all_prof_info {
struct aw_prof_desc prof_desc[AW_PROFILE_MAX];
};
struct aw_prof_info {
int count;
int status;
int prof_type;
char (*prof_name_list)[AW_PROFILE_STR_MAX];
struct aw_prof_desc *prof_desc;
};
struct acf_bin_info {
int load_count;
int fw_size;
int16_t dev_index;
char *fw_data;
int product_cnt;
const char **product_tab;
struct aw_device *aw_dev;
struct aw_acf_hdr acf_hdr;
struct aw_prof_info prof_info;
};
char *aw87xxx_ctos_get_prof_name(int profile_id);
void aw87xxx_acf_profile_free(struct device *dev,
struct acf_bin_info *acf_info);
int aw87xxx_acf_parse(struct device *dev, struct acf_bin_info *acf_info);
struct aw_prof_desc *aw87xxx_acf_get_prof_desc_form_name(struct device *dev,
struct acf_bin_info *acf_info, char *profile_name);
int aw87xxx_acf_get_prof_index_form_name(struct device *dev,
struct acf_bin_info *acf_info, char *profile_name);
char *aw87xxx_acf_get_prof_name_form_index(struct device *dev,
struct acf_bin_info *acf_info, int index);
int aw87xxx_acf_get_profile_count(struct device *dev,
struct acf_bin_info *acf_info);
char *aw87xxx_acf_get_prof_off_name(struct device *dev,
struct acf_bin_info *acf_info);
void aw87xxx_acf_init(struct aw_device *aw_dev, struct acf_bin_info *acf_info, int index);
#endif

View file

@ -0,0 +1,515 @@
/*
* aw87xxx_bin_parse.c
*
* Copyright (c) 2020 AWINIC Technology CO., LTD
*
* 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/kernel.h>
#include <linux/i2c.h>
#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/debugfs.h>
#include <linux/miscdevice.h>
#include <asm/uaccess.h>
#include <linux/regmap.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/hrtimer.h>
#include <linux/mutex.h>
#include <linux/cdev.h>
#include <linux/list.h>
#include <linux/string.h>
#include "aw87xxx_bin_parse.h"
#define AWINIC_CODE_VERSION "V0.0.7-V1.0.4" /* "code version"-"excel version" */
#define DEBUG_LOG_LEVEL
#ifdef DEBUG_LOG_LEVEL
#define DBG(fmt, arg...) do {\
printk("AWINIC_BIN %s,line= %d,"fmt, __func__, __LINE__, ##arg);\
} while (0)
#define DBG_ERR(fmt, arg...) do {\
printk("AWINIC_BIN_ERR %s,line= %d,"fmt, __func__, __LINE__, ##arg);\
} while (0)
#else
#define DBG(fmt, arg...) do {} while (0)
#define DBG_ERR(fmt, arg...) do {} while (0)
#endif
#define printing_data_code
typedef unsigned short int aw_uint16;
typedef unsigned long int aw_uint32;
#define BigLittleSwap16(A) ((((aw_uint16)(A) & 0xff00) >> 8) | \
(((aw_uint16)(A) & 0x00ff) << 8))
#define BigLittleSwap32(A) ((((aw_uint32)(A) & 0xff000000) >> 24) | \
(((aw_uint32)(A) & 0x00ff0000) >> 8) | \
(((aw_uint32)(A) & 0x0000ff00) << 8) | \
(((aw_uint32)(A) & 0x000000ff) << 24))
static int aw_parse_bin_header_1_0_0(struct aw_bin *bin);
/**
*
* Interface function
*
* return value:
* value = 0 :success;
* value = -1 :check bin header version
* value = -2 :check bin data type
* value = -3 :check sum or check bin data len error
* value = -4 :check data version
* value = -5 :check register num
* value = -6 :check dsp reg num
* value = -7 :check soc app num
* value = -8 :bin is NULL point
*
**/
/********************************************************
*
* check sum data
*
********************************************************/
static int aw_check_sum(struct aw_bin *bin, int bin_num)
{
unsigned int i = 0;
unsigned int sum_data = 0;
unsigned int check_sum = 0;
unsigned char *p_check_sum = NULL;
DBG("enter\n");
p_check_sum =
&(bin->info.data[(bin->header_info[bin_num].valid_data_addr -
bin->header_info[bin_num].header_len)]);
DBG("aw_bin_parse p_check_sum = %p\n", p_check_sum);
check_sum = GET_32_DATA(*(p_check_sum + 3),
*(p_check_sum + 2),
*(p_check_sum + 1), *(p_check_sum));
for (i = 4;
i <
bin->header_info[bin_num].bin_data_len +
bin->header_info[bin_num].header_len; i++) {
sum_data += *(p_check_sum + i);
}
DBG("aw_bin_parse bin_num=%d, check_sum = 0x%x, sum_data = 0x%x\n",
bin_num, check_sum, sum_data);
if (sum_data != check_sum) {
p_check_sum = NULL;
DBG_ERR("aw_bin_parse check sum or check bin data len error\n");
DBG_ERR("aw_bin_parse bin_num=%d, check_sum = 0x%x, sum_data = 0x%x\n", bin_num, check_sum, sum_data);
return -3;
}
p_check_sum = NULL;
return 0;
}
static int aw_check_data_version(struct aw_bin *bin, int bin_num)
{
int i = 0;
DBG("enter\n");
for (i = DATA_VERSION_V1; i < DATA_VERSION_MAX; i++) {
if (bin->header_info[bin_num].bin_data_ver == i) {
return 0;
}
}
DBG_ERR("aw_bin_parse Unrecognized this bin data version\n");
return -4;
}
static int aw_check_register_num_v1(struct aw_bin *bin, int bin_num)
{
unsigned int check_register_num = 0;
unsigned int parse_register_num = 0;
unsigned char *p_check_sum = NULL;
DBG("enter\n");
p_check_sum =
&(bin->info.data[(bin->header_info[bin_num].valid_data_addr)]);
DBG("aw_bin_parse p_check_sum = %p\n", p_check_sum);
parse_register_num = GET_32_DATA(*(p_check_sum + 3),
*(p_check_sum + 2),
*(p_check_sum + 1), *(p_check_sum));
check_register_num = (bin->header_info[bin_num].bin_data_len - 4) /
(bin->header_info[bin_num].reg_byte_len +
bin->header_info[bin_num].data_byte_len);
DBG
("aw_bin_parse bin_num=%d, parse_register_num = 0x%x, check_register_num = 0x%x\n",
bin_num, parse_register_num, check_register_num);
if (parse_register_num != check_register_num) {
p_check_sum = NULL;
DBG_ERR("aw_bin_parse register num is error\n");
DBG_ERR("aw_bin_parse bin_num=%d, parse_register_num = 0x%x, check_register_num = 0x%x\n", bin_num, parse_register_num, check_register_num);
return -5;
}
bin->header_info[bin_num].reg_num = parse_register_num;
bin->header_info[bin_num].valid_data_len =
bin->header_info[bin_num].bin_data_len - 4;
p_check_sum = NULL;
bin->header_info[bin_num].valid_data_addr =
bin->header_info[bin_num].valid_data_addr + 4;
return 0;
}
static int aw_check_dsp_reg_num_v1(struct aw_bin *bin, int bin_num)
{
unsigned int check_dsp_reg_num = 0;
unsigned int parse_dsp_reg_num = 0;
unsigned char *p_check_sum = NULL;
DBG("enter\n");
p_check_sum =
&(bin->info.data[(bin->header_info[bin_num].valid_data_addr)]);
DBG("aw_bin_parse p_check_sum = %p\n", p_check_sum);
parse_dsp_reg_num = GET_32_DATA(*(p_check_sum + 7),
*(p_check_sum + 6),
*(p_check_sum + 5), *(p_check_sum + 4));
bin->header_info[bin_num].reg_data_byte_len =
GET_32_DATA(*(p_check_sum + 11), *(p_check_sum + 10),
*(p_check_sum + 9), *(p_check_sum + 8));
check_dsp_reg_num =
(bin->header_info[bin_num].bin_data_len -
12) / bin->header_info[bin_num].reg_data_byte_len;
DBG
("aw_bin_parse bin_num=%d, parse_dsp_reg_num = 0x%x, check_dsp_reg_num = 0x%x\n",
bin_num, parse_dsp_reg_num, check_dsp_reg_num);
if (parse_dsp_reg_num != check_dsp_reg_num) {
p_check_sum = NULL;
DBG_ERR("aw_bin_parse dsp reg num is error\n");
DBG_ERR("aw_bin_parse bin_num=%d, parse_dsp_reg_num = 0x%x, check_dsp_reg_num = 0x%x\n", bin_num, parse_dsp_reg_num, check_dsp_reg_num);
return -6;
}
bin->header_info[bin_num].download_addr =
GET_32_DATA(*(p_check_sum + 3), *(p_check_sum + 2),
*(p_check_sum + 1), *(p_check_sum));
bin->header_info[bin_num].reg_num = parse_dsp_reg_num;
bin->header_info[bin_num].valid_data_len =
bin->header_info[bin_num].bin_data_len - 12;
p_check_sum = NULL;
bin->header_info[bin_num].valid_data_addr =
bin->header_info[bin_num].valid_data_addr + 12;
return 0;
}
static int aw_check_soc_app_num_v1(struct aw_bin *bin, int bin_num)
{
unsigned int check_soc_app_num = 0;
unsigned int parse_soc_app_num = 0;
unsigned char *p_check_sum = NULL;
DBG("enter\n");
p_check_sum =
&(bin->info.data[(bin->header_info[bin_num].valid_data_addr)]);
DBG("aw_bin_parse p_check_sum = %p\n", p_check_sum);
bin->header_info[bin_num].app_version = GET_32_DATA(*(p_check_sum + 3),
*(p_check_sum + 2),
*(p_check_sum + 1),
*(p_check_sum));
parse_soc_app_num = GET_32_DATA(*(p_check_sum + 11),
*(p_check_sum + 10),
*(p_check_sum + 9), *(p_check_sum + 8));
check_soc_app_num = bin->header_info[bin_num].bin_data_len - 12;
DBG
("aw_bin_parse bin_num=%d, parse_soc_app_num = 0x%x, check_soc_app_num = 0x%x\n",
bin_num, parse_soc_app_num, check_soc_app_num);
if (parse_soc_app_num != check_soc_app_num) {
p_check_sum = NULL;
DBG_ERR("aw_bin_parse soc app num is error\n");
DBG_ERR("aw_bin_parse bin_num=%d, parse_soc_app_num = 0x%x, check_soc_app_num = 0x%x\n", bin_num, parse_soc_app_num, check_soc_app_num);
return -7;
}
bin->header_info[bin_num].reg_num = parse_soc_app_num;
bin->header_info[bin_num].download_addr =
GET_32_DATA(*(p_check_sum + 7), *(p_check_sum + 6),
*(p_check_sum + 5), *(p_check_sum + 4));
bin->header_info[bin_num].valid_data_len =
bin->header_info[bin_num].bin_data_len - 12;
p_check_sum = NULL;
bin->header_info[bin_num].valid_data_addr =
bin->header_info[bin_num].valid_data_addr + 12;
return 0;
}
/************************
***
***bin header 1_0_0
***
************************/
static void aw_get_single_bin_header_1_0_0(struct aw_bin *bin)
{
int i;
DBG("enter %s\n", __func__);
bin->header_info[bin->all_bin_parse_num].header_len = 60;
bin->header_info[bin->all_bin_parse_num].check_sum =
GET_32_DATA(*(bin->p_addr + 3), *(bin->p_addr + 2),
*(bin->p_addr + 1), *(bin->p_addr));
bin->header_info[bin->all_bin_parse_num].header_ver =
GET_32_DATA(*(bin->p_addr + 7), *(bin->p_addr + 6),
*(bin->p_addr + 5), *(bin->p_addr + 4));
bin->header_info[bin->all_bin_parse_num].bin_data_type =
GET_32_DATA(*(bin->p_addr + 11), *(bin->p_addr + 10),
*(bin->p_addr + 9), *(bin->p_addr + 8));
bin->header_info[bin->all_bin_parse_num].bin_data_ver =
GET_32_DATA(*(bin->p_addr + 15), *(bin->p_addr + 14),
*(bin->p_addr + 13), *(bin->p_addr + 12));
bin->header_info[bin->all_bin_parse_num].bin_data_len =
GET_32_DATA(*(bin->p_addr + 19), *(bin->p_addr + 18),
*(bin->p_addr + 17), *(bin->p_addr + 16));
bin->header_info[bin->all_bin_parse_num].ui_ver =
GET_32_DATA(*(bin->p_addr + 23), *(bin->p_addr + 22),
*(bin->p_addr + 21), *(bin->p_addr + 20));
bin->header_info[bin->all_bin_parse_num].reg_byte_len =
GET_32_DATA(*(bin->p_addr + 35), *(bin->p_addr + 34),
*(bin->p_addr + 33), *(bin->p_addr + 32));
bin->header_info[bin->all_bin_parse_num].data_byte_len =
GET_32_DATA(*(bin->p_addr + 39), *(bin->p_addr + 38),
*(bin->p_addr + 37), *(bin->p_addr + 36));
bin->header_info[bin->all_bin_parse_num].device_addr =
GET_32_DATA(*(bin->p_addr + 43), *(bin->p_addr + 42),
*(bin->p_addr + 41), *(bin->p_addr + 40));
for (i = 0; i < 8; i++) {
bin->header_info[bin->all_bin_parse_num].chip_type[i] =
*(bin->p_addr + 24 + i);
}
bin->header_info[bin->all_bin_parse_num].reg_num = 0x00000000;
bin->header_info[bin->all_bin_parse_num].reg_data_byte_len = 0x00000000;
bin->header_info[bin->all_bin_parse_num].download_addr = 0x00000000;
bin->header_info[bin->all_bin_parse_num].app_version = 0x00000000;
bin->header_info[bin->all_bin_parse_num].valid_data_len = 0x00000000;
bin->all_bin_parse_num += 1;
}
static int aw_parse_each_of_multi_bins_1_0_0(unsigned int bin_num, int bin_serial_num,
struct aw_bin *bin)
{
int ret = 0;
unsigned int bin_start_addr = 0;
unsigned int valid_data_len = 0;
DBG("aw_bin_parse enter multi bin branch -- %s\n", __func__);
if (!bin_serial_num) {
bin_start_addr = GET_32_DATA(*(bin->p_addr + 67),
*(bin->p_addr + 66),
*(bin->p_addr + 65),
*(bin->p_addr + 64));
bin->p_addr += (60 + bin_start_addr);
bin->header_info[bin->all_bin_parse_num].valid_data_addr =
bin->header_info[bin->all_bin_parse_num -
1].valid_data_addr + 4 + 8 * bin_num + 60;
} else {
valid_data_len =
bin->header_info[bin->all_bin_parse_num - 1].bin_data_len;
bin->p_addr += (60 + valid_data_len);
bin->header_info[bin->all_bin_parse_num].valid_data_addr =
bin->header_info[bin->all_bin_parse_num -
1].valid_data_addr +
bin->header_info[bin->all_bin_parse_num - 1].bin_data_len +
60;
}
ret = aw_parse_bin_header_1_0_0(bin);
return ret;
}
/* Get the number of bins in multi bins, and set a for loop, loop processing each bin data */
static int aw_get_multi_bin_header_1_0_0(struct aw_bin *bin)
{
int i = 0;
int ret = 0;
unsigned int bin_num = 0;
DBG("aw_bin_parse enter multi bin branch -- %s\n", __func__);
bin_num = GET_32_DATA(*(bin->p_addr + 63),
*(bin->p_addr + 62),
*(bin->p_addr + 61), *(bin->p_addr + 60));
if (bin->multi_bin_parse_num == 1) {
bin->header_info[bin->all_bin_parse_num].valid_data_addr = 60;
}
aw_get_single_bin_header_1_0_0(bin);
for (i = 0; i < bin_num; i++) {
DBG("aw_bin_parse enter multi bin for is %d\n", i);
ret = aw_parse_each_of_multi_bins_1_0_0(bin_num, i, bin);
if (ret < 0) {
return ret;
}
}
return 0;
}
/********************************************************
*
* If the bin framework header version is 1.0.0,
determine the data type of bin, and then perform different processing
according to the data type
If it is a single bin data type, write the data directly into the structure array
If it is a multi-bin data type, first obtain the number of bins,
and then recursively call the bin frame header processing function
according to the bin number to process the frame header information of each bin separately
*
********************************************************/
static int aw_parse_bin_header_1_0_0(struct aw_bin *bin)
{
int ret = 0;
unsigned int bin_data_type;
DBG("enter %s\n", __func__);
bin_data_type = GET_32_DATA(*(bin->p_addr + 11),
*(bin->p_addr + 10),
*(bin->p_addr + 9), *(bin->p_addr + 8));
DBG("aw_bin_parse bin_data_type 0x%x\n", bin_data_type);
switch (bin_data_type) {
case DATA_TYPE_REGISTER:
case DATA_TYPE_DSP_REG:
case DATA_TYPE_SOC_APP:
/* Divided into two processing methods,
one is single bin processing,
and the other is single bin processing in multi bin */
DBG("aw_bin_parse enter single bin branch\n");
bin->single_bin_parse_num += 1;
DBG("%s bin->single_bin_parse_num is %d\n", __func__,
bin->single_bin_parse_num);
if (!bin->multi_bin_parse_num) {
bin->header_info[bin->
all_bin_parse_num].valid_data_addr =
60;
}
aw_get_single_bin_header_1_0_0(bin);
break;
case DATA_TYPE_MULTI_BINS:
/* Get the number of times to enter multi bins */
DBG("aw_bin_parse enter multi bin branch\n");
bin->multi_bin_parse_num += 1;
DBG("%s bin->multi_bin_parse_num is %d\n", __func__,
bin->multi_bin_parse_num);
ret = aw_get_multi_bin_header_1_0_0(bin);
if (ret < 0) {
return ret;
}
break;
default:
DBG_ERR("aw_bin_parse Unrecognized this bin data type\n");
return -2;
}
return 0;
}
/* get the bin's header version */
static int aw_check_bin_header_version(struct aw_bin *bin)
{
int ret = 0;
unsigned int header_version = 0;
header_version = GET_32_DATA(*(bin->p_addr + 7),
*(bin->p_addr + 6),
*(bin->p_addr + 5), *(bin->p_addr + 4));
DBG("aw_bin_parse header_version 0x%x\n", header_version);
/* Write data to the corresponding structure array
according to different formats of the bin frame header version */
switch (header_version) {
case HEADER_VERSION_1_0_0:
ret = aw_parse_bin_header_1_0_0(bin);
return ret;
default:
DBG_ERR("aw_bin_parse Unrecognized this bin header version \n");
return -1;
}
}
int aw87xxx_parsing_bin_file(struct aw_bin *bin)
{
int i = 0;
int ret = 0;
DBG("aw_bin_parse code version:%s\n", AWINIC_CODE_VERSION);
if (!bin) {
DBG_ERR("aw_bin_parse bin is NULL\n");
return -8;
}
bin->p_addr = bin->info.data;
bin->all_bin_parse_num = 0;
bin->multi_bin_parse_num = 0;
bin->single_bin_parse_num = 0;
/* filling bins header info */
ret = aw_check_bin_header_version(bin);
if (ret < 0) {
DBG_ERR("aw_bin_parse check bin header version error\n");
return ret;
}
bin->p_addr = NULL;
/* check bin header info */
for (i = 0; i < bin->all_bin_parse_num; i++) {
/* check sum */
ret = aw_check_sum(bin, i);
if (ret < 0) {
DBG_ERR("aw_bin_parse check sum data error\n");
return ret;
}
/* check bin data version */
ret = aw_check_data_version(bin, i);
if (ret < 0) {
DBG_ERR("aw_bin_parse check data version error\n");
return ret;
}
/* check valid data */
if (bin->header_info[i].bin_data_ver == DATA_VERSION_V1) {
/* check register num */
if (bin->header_info[i].bin_data_type ==
DATA_TYPE_REGISTER) {
ret = aw_check_register_num_v1(bin, i);
if (ret < 0) {
DBG_ERR
("aw_bin_parse check register num error\n");
return ret;
}
/* check dsp reg num */
} else if (bin->header_info[i].bin_data_type ==
DATA_TYPE_DSP_REG) {
ret = aw_check_dsp_reg_num_v1(bin, i);
if (ret < 0) {
DBG_ERR
("aw_bin_parse check dsp reg num error\n");
return ret;
}
/* check soc app num */
} else if (bin->header_info[i].bin_data_type ==
DATA_TYPE_SOC_APP) {
ret = aw_check_soc_app_num_v1(bin, i);
if (ret < 0) {
DBG_ERR
("aw_bin_parse check soc app num error\n");
return ret;
}
} else {
bin->header_info[i].valid_data_len =
bin->header_info[i].bin_data_len;
}
}
}
DBG("aw_bin_parse parsing success\n");
return 0;
}

View file

@ -0,0 +1,73 @@
#ifndef __AW87XXX_BIN_PARSE_H__
#define __AW87XXX_BIN_PARSE_H__
#define NULL ((void *)0)
#define GET_32_DATA(w, x, y, z) ((unsigned int)(((w) << 24) | ((x) << 16) | ((y) << 8) | (z)))
#define BIN_NUM_MAX 100
#define HEADER_LEN 60
/*********************************************************
*
* header information
*
********************************************************/
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_MULTI_BINS = 0x00002000,
DATA_TYPE_MONITOR_ANALOG = 0x00020000,
};
enum data_version_enum {
DATA_VERSION_V1 = 0X00000001, /*default little edian */
DATA_VERSION_MAX,
};
struct bin_header_info {
unsigned int header_len; /* Frame header length */
unsigned int check_sum; /* Frame header information-Checksum */
unsigned int header_ver; /* Frame header information-Frame header version */
unsigned int bin_data_type; /* Frame header information-Data type */
unsigned int bin_data_ver; /* Frame header information-Data version */
unsigned int bin_data_len; /* Frame header information-Data length */
unsigned int ui_ver; /* Frame header information-ui version */
unsigned char chip_type[8]; /* Frame header information-chip type */
unsigned int reg_byte_len; /* Frame header information-reg byte len */
unsigned int data_byte_len; /* Frame header information-data byte len */
unsigned int device_addr; /* Frame header information-device addr */
unsigned int valid_data_len; /* Length of valid data obtained after parsing */
unsigned int valid_data_addr; /* The offset address of the valid data obtained after parsing relative to info */
unsigned int reg_num; /* The number of registers obtained after parsing */
unsigned int reg_data_byte_len; /* The byte length of the register obtained after parsing */
unsigned int download_addr; /* The starting address or download address obtained after parsing */
unsigned int app_version; /* The software version number obtained after parsing */
};
/************************************************************
*
* function define
*
************************************************************/
struct bin_container {
unsigned int len; /* The size of the bin file obtained from the firmware */
unsigned char data[]; /* Store the bin file obtained from the firmware */
};
struct aw_bin {
unsigned char *p_addr; /* Offset pointer (backward offset pointer to obtain frame header information and important information) */
unsigned int all_bin_parse_num; /* The number of all bin files */
unsigned int multi_bin_parse_num; /* The number of single bin files */
unsigned int single_bin_parse_num; /* The number of multiple bin files */
struct bin_header_info header_info[BIN_NUM_MAX]; /* Frame header information and other important data obtained after parsing */
struct bin_container info; /* Obtained bin file data that needs to be parsed */
};
extern int aw87xxx_parsing_bin_file(struct aw_bin *bin);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,167 @@
#ifndef __AW87XXX_DEVICE_H__
#define __AW87XXX_DEVICE_H__
#include <linux/version.h>
#include <linux/kernel.h>
#include <sound/control.h>
#include <sound/soc.h>
#include "aw87xxx_acf_bin.h"
#define AW87XXX_PID_9B_PRODUCT_MAX (1)
#define AW87XXX_PID_18_PRODUCT_MAX (1)
#define AW87XXX_PID_39_PRODUCT_MAX (3)
#define AW87XXX_PID_59_3X9_PRODUCT_MAX (2)
#define AW87XXX_PID_59_5X9_PRODUCT_MAX (4)
#define AW87XXX_PID_5A_PRODUCT_MAX (6)
#define AW87XXX_PID_76_PROFUCT_MAX (5)
#define AW87XXX_PID_60_PROFUCT_MAX (5)
#define AW_PRODUCT_NAME_LEN (8)
#define AW_GPIO_HIGHT_LEVEL (1)
#define AW_GPIO_LOW_LEVEL (0)
#define AW_I2C_RETRIES (5)
#define AW_I2C_RETRY_DELAY (2)
#define AW_I2C_READ_MSG_NUM (2)
#define AW_READ_CHIPID_RETRIES (5)
#define AW_READ_CHIPID_RETRY_DELAY (2)
#define AW_DEV_REG_CHIPID (0x00)
#define AW_DEV_REG_INVALID_MASK (0xff)
#define AW_NO_RESET_GPIO (-1)
#define AW_PID_9B_BIN_REG_CFG_COUNT (10)
#define AW87XXX_DELAY_REG_ADDR (0xFE)
#define AW87XXX_REG_DELAY_TIME (1000)
#define AW_BOOST_VOLTAGE_MIN (0x00)
#define AW_REG_NONE (0xFF)
/********************************************
*
* aw87xxx devices attributes
*
*******************************************/
struct aw_device;
struct aw_device_ops {
int (*pwr_on_func)(struct aw_device *aw_dev, struct aw_data_container *data);
int (*pwr_off_func)(struct aw_device *aw_dev, struct aw_data_container *data);
};
enum aw_dev_chipid {
AW_DEV_CHIPID_18 = 0x18,
AW_DEV_CHIPID_39 = 0x39,
AW_DEV_CHIPID_59 = 0x59,
AW_DEV_CHIPID_69 = 0x69,
AW_DEV_CHIPID_5A = 0x5A,
AW_DEV_CHIPID_9A = 0x9A,
AW_DEV_CHIPID_9B = 0x9B,
AW_DEV_CHIPID_76 = 0x76,
AW_DEV_CHIPID_60 = 0x60,
};
enum aw_dev_hw_status {
AW_DEV_HWEN_OFF = 0,
AW_DEV_HWEN_ON,
AW_DEV_HWEN_INVALID,
AW_DEV_HWEN_STATUS_MAX,
};
enum aw_dev_soft_off_enable {
AW_DEV_SOFT_OFF_DISENABLE = 0,
AW_DEV_SOFT_OFF_ENABLE = 1,
};
enum aw_dev_soft_rst_enable {
AW_DEV_SOFT_RST_DISENABLE = 0,
AW_DEV_SOFT_RST_ENABLE = 1,
};
enum aw_reg_receiver_mode {
AW_NOT_REC_MODE = 0,
AW_IS_REC_MODE = 1,
};
enum aw_reg_voltage_status {
AW_VOLTAGE_LOW = 0,
AW_VOLTAGE_HIGH,
};
struct aw_mute_desc {
uint8_t addr;
uint8_t enable;
uint8_t disable;
uint16_t mask;
};
struct aw_soft_rst_desc {
int len;
unsigned char *access;
};
struct aw_esd_check_desc {
uint8_t first_update_reg_addr;
uint8_t first_update_reg_val;
};
struct aw_rec_mode_desc {
uint8_t addr;
uint8_t enable;
uint8_t disable;
uint8_t mask;
};
struct aw_voltage_desc {
uint8_t addr;
uint8_t vol_max;
uint8_t vol_min;
};
struct aw_device {
uint8_t i2c_addr;
uint8_t chipid;
uint8_t soft_rst_enable;
uint8_t soft_off_enable;
uint8_t is_rec_mode;
int hwen_status;
int i2c_bus;
int rst_gpio;
int reg_max_addr;
int product_cnt;
const char **product_tab;
const unsigned char *reg_access;
struct device *dev;
struct i2c_client *i2c;
struct aw_mute_desc mute_desc;
struct aw_soft_rst_desc soft_rst_desc;
struct aw_esd_check_desc esd_desc;
struct aw_rec_mode_desc rec_desc;
struct aw_voltage_desc vol_desc;
struct aw_device_ops ops;
};
int aw87xxx_dev_i2c_write_byte(struct aw_device *aw_dev,
uint8_t reg_addr, uint8_t reg_data);
int aw87xxx_dev_i2c_read_byte(struct aw_device *aw_dev,
uint8_t reg_addr, uint8_t *reg_data);
int aw87xxx_dev_i2c_read_msg(struct aw_device *aw_dev,
uint8_t reg_addr, uint8_t *data_buf, uint32_t data_len);
int aw87xxx_dev_i2c_write_bits(struct aw_device *aw_dev,
uint8_t reg_addr, uint8_t mask, uint8_t reg_data);
void aw87xxx_dev_soft_reset(struct aw_device *aw_dev);
void aw87xxx_dev_hw_pwr_ctrl(struct aw_device *aw_dev, bool enable);
int aw87xxx_dev_default_pwr_on(struct aw_device *aw_dev,
struct aw_data_container *profile_data);
int aw87xxx_dev_default_pwr_off(struct aw_device *aw_dev,
struct aw_data_container *profile_data);
int aw87xxx_dev_esd_reg_status_check(struct aw_device *aw_dev);
int aw87xxx_dev_check_reg_is_rec_mode(struct aw_device *aw_dev);
int aw87xxx_dev_init(struct aw_device *aw_dev);
#endif

View file

@ -0,0 +1,433 @@
/*
* aw87xxx_dsp.c
*
* Copyright (c) 2021 AWINIC Technology CO., LTD
*
* Author: Barry <zhaozhongbo@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/uaccess.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/hrtimer.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/version.h>
#include "aw87xxx_log.h"
#include "aw87xxx_dsp.h"
/***************dsp communicate**************/
#ifdef AW_QCOM_OPEN_DSP_PLATFORM
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 1))
#include <dsp/msm_audio_ion.h>
#include <dsp/q6afe-v2.h>
#include <dsp/q6audio-v2.h>
#include <dsp/q6adm-v2.h>
#else
#include <linux/msm_audio_ion.h>
#include <sound/q6afe-v2.h>
#include <sound/q6audio-v2.h>
#include <sound/q6adm-v2.h>
#include <sound/adsp_err.h>
#endif
#endif
static DEFINE_MUTEX(g_dsp_lock);
static unsigned int g_spin_value;
static int g_rx_topo_id = AW_RX_DEFAULT_TOPO_ID;
static int g_rx_port_id = AW_RX_DEFAULT_PORT_ID;
#define AW_COPP_MODULE_ID (0X10013D02) /*SKT module id*/
#define AW_COPP_PARAMS_ID_AWDSP_ENABLE (0X10013D14) /*SKT enable param id*/
#ifdef AW_MTK_OPEN_DSP_PLATFORM
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);
/*
static int mtk_spk_send_ipi_buf_to_dsp(void *data_buffer,
uint32_t data_size)
{
AW_LOGI("enter");
return 0;
}
static int mtk_spk_recv_ipi_buf_from_dsp(int8_t *buffer,
int16_t size, uint32_t *buf_len)
{
AW_LOGI("enter");
return 0;
}
*/
#elif defined AW_QCOM_OPEN_DSP_PLATFORM
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);
/*
static int afe_get_topology(int port_id)
{
return -EPERM;
}
static int aw_send_afe_cal_apr(uint32_t param_id,
void *buf, int cmd_size, bool write)
{
AW_LOGI("enter, no define AWINIC_ADSP_ENABLE", __func__);
return 0;
}
*/
#endif
#ifdef AW_QCOM_OPEN_DSP_PLATFORM
extern void aw_set_port_id(int rx_port_id);
#else
static void aw_set_port_id(int rx_port_id)
{
return;
}
#endif
static int aw_adm_param_enable(int port_id, int module_id, int param_id, int enable)
{
/*for v3*/
int copp_idx = 0;
uint32_t enable_param;
struct param_hdr_v3 param_hdr;
int rc = 0;
pr_info("%s Awinic port_id 0x%x, module_id 0x%x, enable %d\n",
__func__, port_id, module_id, enable);
copp_idx = adm_get_default_copp_idx(port_id);
if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
return -EINVAL;
}
if (enable < 0 || enable > 1) {
pr_err("%s: Invalid value for enable %d\n", __func__, enable);
return -EINVAL;
}
pr_info("%s Awinic port_id 0x%x, module_id 0x%x, copp_idx 0x%x, enable %d\n",
__func__, port_id, module_id, copp_idx, enable);
memset(&param_hdr, 0, sizeof(param_hdr));
param_hdr.module_id = module_id;
param_hdr.instance_id = INSTANCE_ID_0;
param_hdr.param_id = param_id;
param_hdr.param_size = sizeof(enable_param);
enable_param = enable;
rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
(uint8_t *) &enable_param);
if (rc)
pr_err("%s: Awinic Failed to set enable of module(%d) instance(%d) to %d, err %d\n",
__func__, module_id, INSTANCE_ID_0, enable, rc);
return rc;
}
uint8_t aw87xxx_dsp_isEnable(void)
{
#if (defined AW_QCOM_OPEN_DSP_PLATFORM) || (defined AW_MTK_OPEN_DSP_PLATFORM)
return true;
#else
return false;
#endif
}
/*****************mtk dsp communication function start**********************/
#ifdef AW_MTK_OPEN_DSP_PLATFORM
static int aw_mtk_write_data_to_dsp(int32_t param_id,
void *data, int size)
{
int32_t *dsp_data = NULL;
mtk_dsp_hdr_t *hdr = NULL;
int ret;
dsp_data = kzalloc(sizeof(mtk_dsp_hdr_t) + size, GFP_KERNEL);
if (!dsp_data) {
AW_LOGE("kzalloc dsp_msg error");
return -ENOMEM;
}
hdr = (mtk_dsp_hdr_t *)dsp_data;
hdr->type = DSP_MSG_TYPE_DATA;
hdr->opcode_id = param_id;
hdr->version = AW_DSP_MSG_HDR_VER;
memcpy(((char *)dsp_data) + sizeof(mtk_dsp_hdr_t),
data, size);
ret = mtk_spk_send_ipi_buf_to_dsp(dsp_data,
sizeof(mtk_dsp_hdr_t) + size);
if (ret < 0) {
AW_LOGE("write data failed");
kfree(dsp_data);
dsp_data = NULL;
return ret;
}
kfree(dsp_data);
dsp_data = NULL;
return 0;
}
static int aw_mtk_read_data_from_dsp(int32_t param_id, void *data,
int data_size)
{
int ret;
mtk_dsp_hdr_t hdr;
mutex_lock(&g_dsp_lock);
hdr.type = DSP_MSG_TYPE_CMD;
hdr.opcode_id = param_id;
hdr.version = AW_DSP_MSG_HDR_VER;
ret = mtk_spk_send_ipi_buf_to_dsp(&hdr, sizeof(mtk_dsp_hdr_t));
if (ret < 0)
goto failed;
ret = mtk_spk_recv_ipi_buf_from_dsp(data, data_size, &data_size);
if (ret < 0)
goto failed;
mutex_unlock(&g_dsp_lock);
return 0;
failed:
mutex_unlock(&g_dsp_lock);
return ret;
}
#endif
/********************mtk dsp communication function end***********************/
/******************qcom dsp communication function start**********************/
#ifdef AW_QCOM_OPEN_DSP_PLATFORM
static int aw_check_dsp_ready(void)
{
int ret;
ret = afe_get_topology(g_rx_port_id);
AW_LOGD("topo_id 0x%x", ret);
if (ret != g_rx_topo_id)
AW_LOGE("topo id 0x%x", ret);
return ret;
}
static int aw_qcom_write_data_to_dsp(int32_t param_id,
void *data, int data_size)
{
int ret = -1;
int topo = -1;
AW_LOGI("enter");
mutex_lock(&g_dsp_lock);
topo = aw_check_dsp_ready();
if (topo != 0)
ret = aw_send_afe_cal_apr(param_id, data,
data_size, true);
mutex_unlock(&g_dsp_lock);
return ret;
}
static int aw_qcom_read_data_from_dsp(int32_t param_id,
void *data, int data_size)
{
int ret = -1;
int topo = -1;
AW_LOGI("enter");
mutex_lock(&g_dsp_lock);
topo = aw_check_dsp_ready();
if (topo != 0)
ret = aw_send_afe_cal_apr(param_id, data,
data_size, false);
mutex_unlock(&g_dsp_lock);
return ret;
}
#endif
/*****************qcom dsp communication function end*********************/
/*****************read/write msg communication function*********************/
static int aw_write_data_to_dsp(int32_t param_id, void *data, int data_size)
{
#if defined AW_QCOM_OPEN_DSP_PLATFORM
return aw_qcom_write_data_to_dsp(param_id, data, data_size);
#elif defined AW_MTK_OPEN_DSP_PLATFORM
return aw_mtk_write_data_to_dsp(param_id, data, data_size);
#else
return -EINVAL;
#endif
}
static int aw_read_data_from_dsp(int32_t param_id, void *data, int data_size)
{
#if defined AW_QCOM_OPEN_DSP_PLATFORM
return aw_qcom_read_data_from_dsp(param_id, data, data_size);
#elif defined AW_MTK_OPEN_DSP_PLATFORM
return aw_mtk_read_data_from_dsp(param_id, data, data_size);
#else
return -EINVAL;
#endif
}
/***************read/write msg communication function end*******************/
int aw87xxx_dsp_get_rx_module_enable(int *enable)
{
if (!enable) {
AW_LOGE("enable is NULL");
return -EINVAL;
}
return aw_read_data_from_dsp(AWDSP_RX_SET_ENABLE,
(void *)enable, sizeof(uint32_t));
}
int aw87xxx_dsp_set_rx_module_enable(int enable)
{
switch (enable) {
case AW_RX_MODULE_DISENABLE:
AW_LOGD("set enable=%d", enable);
break;
case AW_RX_MODULE_ENABLE:
AW_LOGD("set enable=%d", enable);
break;
default:
AW_LOGE("unsupport enable=%d", enable);
return -EINVAL;
}
return aw_write_data_to_dsp(AWDSP_RX_SET_ENABLE,
&enable, sizeof(uint32_t));
}
int aw87xxx_dsp_set_copp_module_enable(bool enable)
{
int ret;
ret = aw_adm_param_enable(g_rx_port_id, AW_COPP_MODULE_ID,
AW_COPP_PARAMS_ID_AWDSP_ENABLE, enable);
if (ret)
return -EINVAL;
AW_LOGI("set skt %s", enable == 1 ? "enable" : "disable");
return 0;
}
int aw87xxx_dsp_get_vmax(uint32_t *vmax, int dev_index)
{
int32_t param_id = 0;
switch (dev_index % AW_DSP_CHANNEL_MAX) {
case AW_DSP_CHANNEL_0:
param_id = AWDSP_RX_VMAX_0;
break;
case AW_DSP_CHANNEL_1:
param_id = AWDSP_RX_VMAX_1;
break;
default:
AW_LOGE("algo only support double PA channel:%d unsupport",
dev_index);
return -EINVAL;
}
return aw_read_data_from_dsp(param_id,
(void *)vmax, sizeof(uint32_t));
}
int aw87xxx_dsp_set_vmax(uint32_t vmax, int dev_index)
{
int32_t param_id = 0;
switch (dev_index % AW_DSP_CHANNEL_MAX) {
case AW_DSP_CHANNEL_0:
param_id = AWDSP_RX_VMAX_0;
break;
case AW_DSP_CHANNEL_1:
param_id = AWDSP_RX_VMAX_1;
break;
default:
AW_LOGE("algo only support double PA channel:%d unsupport",
dev_index);
return -EINVAL;
}
return aw_write_data_to_dsp(param_id, &vmax, sizeof(uint32_t));
}
int aw87xxx_dsp_set_spin(uint32_t ctrl_value)
{
int ret = 0;
if (ctrl_value >= AW_SPIN_MAX) {
AW_LOGE("spin [%d] unsupported ", ctrl_value);
return -EINVAL;
}
ret = aw_write_data_to_dsp(AW_MSG_ID_SPIN, &ctrl_value,
sizeof(uint32_t));
if (ret) {
AW_LOGE("spin [%d] set failed ", ctrl_value);
return ret;
}
g_spin_value = ctrl_value;
return 0;
}
int aw87xxx_dsp_get_spin(void)
{
return g_spin_value;
}
int aw87xxx_spin_set_record_val(void)
{
AW_LOGD("record write spin enter");
return aw87xxx_dsp_set_spin(g_spin_value);
}
EXPORT_SYMBOL(aw87xxx_spin_set_record_val);
void aw87xxx_device_parse_topo_id_dt(struct aw_device *aw_dev)
{
int ret;
ret = of_property_read_u32(aw_dev->dev->of_node, "aw-rx-topo-id", &g_rx_topo_id);
if (ret < 0) {
g_rx_topo_id = AW_RX_DEFAULT_TOPO_ID;
AW_DEV_LOGI(aw_dev->dev, "read aw-rx-topo-id failed,use default");
}
AW_DEV_LOGI(aw_dev->dev, "rx-topo-id: 0x%x", g_rx_topo_id);
}
void aw87xxx_device_parse_port_id_dt(struct aw_device *aw_dev)
{
int ret;
ret = of_property_read_u32(aw_dev->dev->of_node, "aw-rx-port-id", &g_rx_port_id);
if (ret < 0) {
g_rx_port_id = AW_RX_DEFAULT_PORT_ID;
AW_DEV_LOGI(aw_dev->dev, "read aw-rx-port-id failed,use default");
}
aw_set_port_id(g_rx_port_id);
AW_DEV_LOGI(aw_dev->dev, "rx-port-id: 0x%x", g_rx_port_id);
}

View file

@ -0,0 +1,66 @@
#ifndef __AW87XXX_DSP_H__
#define __AW87XXX_DSP_H__
#include "aw87xxx_device.h"
/*#define AW_MTK_OPEN_DSP_PLATFORM*/
#define AW_QCOM_OPEN_DSP_PLATFORM
/*Note: The pord_ID is configured according to different platforms*/
#define AW_DSP_SLEEP_TIME (10)
#define AW_DSP_MSG_HDR_VER (1)
#define AW_RX_DEFAULT_TOPO_ID (0x1000FF01)
#define AW_RX_DEFAULT_PORT_ID (0x4000)
#define AWDSP_RX_SET_ENABLE (0x10013D11)
#define AWDSP_RX_PARAMS (0x10013D12)
#define AWDSP_RX_VMAX_0 (0X10013D17)
#define AWDSP_RX_VMAX_1 (0X10013D18)
#define AW_MSG_ID_SPIN (0x10013D2E)
enum {
AW_SPIN_0 = 0,
AW_SPIN_90,
AW_SPIN_180,
AW_SPIN_270,
AW_SPIN_MAX,
};
typedef struct mtk_dsp_msg_header {
int32_t type;
int32_t opcode_id;
int32_t version;
int32_t reserver[3];
} mtk_dsp_hdr_t;
enum aw_rx_module_enable {
AW_RX_MODULE_DISENABLE = 0,
AW_RX_MODULE_ENABLE,
};
enum aw_dsp_msg_type {
DSP_MSG_TYPE_DATA = 0,
DSP_MSG_TYPE_CMD = 1,
};
enum aw_dsp_channel {
AW_DSP_CHANNEL_0 = 0,
AW_DSP_CHANNEL_1,
AW_DSP_CHANNEL_MAX,
};
uint8_t aw87xxx_dsp_isEnable(void);
int aw87xxx_dsp_get_rx_module_enable(int *enable);
int aw87xxx_dsp_set_rx_module_enable(int enable);
int aw87xxx_dsp_set_copp_module_enable(bool enable);
int aw87xxx_dsp_get_vmax(uint32_t *vmax, int channel);
int aw87xxx_dsp_set_vmax(uint32_t vmax, int channel);
int aw87xxx_dsp_set_spin(uint32_t ctrl_value);
int aw87xxx_dsp_get_spin(void);
int aw87xxx_spin_set_record_val(void);
void aw87xxx_device_parse_port_id_dt(struct aw_device *aw_dev);
void aw87xxx_device_parse_topo_id_dt(struct aw_device *aw_dev);
#endif

View file

@ -0,0 +1,33 @@
#ifndef __AW87XXX_LOG_H__
#define __AW87XXX_LOG_H__
#include <linux/kernel.h>
/********************************************
*
* print information control
*
*******************************************/
#define AW_LOGI(fmt, ...)\
pr_info("[Awinic] %s:" fmt "\n", __func__, ##__VA_ARGS__)
#define AW_LOGD(fmt, ...)\
pr_debug("[Awinic] %s:" fmt "\n", __func__, ##__VA_ARGS__)
#define AW_LOGE(fmt, ...)\
pr_err("[Awinic] %s:" fmt "\n", __func__, ##__VA_ARGS__)
#define AW_DEV_LOGI(dev, fmt, ...)\
pr_info("[Awinic] [%s]%s: " fmt "\n", dev_name(dev), __func__, ##__VA_ARGS__)
#define AW_DEV_LOGD(dev, fmt, ...)\
pr_debug("[Awinic] [%s]%s: " fmt "\n", dev_name(dev), __func__, ##__VA_ARGS__)
#define AW_DEV_LOGE(dev, fmt, ...)\
pr_err("[Awinic] [%s]%s: " fmt "\n", dev_name(dev), __func__, ##__VA_ARGS__)
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,101 @@
#ifndef __AW87XXX_MONITOR_H__
#define __AW87XXX_MONITOR_H__
#define AW_WAIT_DSP_OPEN_TIME (3000)
#define AW_VBAT_CAPACITY_MIN (0)
#define AW_VBAT_CAPACITY_MAX (100)
#define AW_VMAX_INIT_VAL (0xFFFFFFFF)
#define AW_VBAT_MAX (100)
#define AW_VMAX_MAX (0)
#define AW_DEFAULT_MONITOR_TIME (3000)
#define AW_WAIT_TIME (3000)
#define REG_STATUS_CHECK_MAX (10)
#define AW_ESD_CHECK_DELAY (1)
#define AW_MONITOR_TIME_MIN (0)
#define AW_MONITOR_TIME_MAX (50000)
#define AW_ESD_ENABLE (true)
#define AW_ESD_DISABLE (false)
#define AW_ESD_ENABLE_STRLEN (16)
enum aw_monitor_init {
AW_MONITOR_CFG_WAIT = 0,
AW_MONITOR_CFG_OK = 1,
};
enum aw_monitor_hdr_info {
AW_MONITOR_HDR_DATA_SIZE = 0x00000004,
AW_MONITOR_HDR_DATA_BYTE_LEN = 0x00000004,
};
enum aw_monitor_data_ver {
AW_MONITOR_DATA_VER = 0x00000001,
AW_MONITOR_DATA_VER_MAX,
};
enum aw_monitor_first_enter {
AW_FIRST_ENTRY = 0,
AW_NOT_FIRST_ENTRY = 1,
};
struct aw_bin_header {
uint32_t check_sum;
uint32_t header_ver;
uint32_t bin_data_type;
uint32_t bin_data_ver;
uint32_t bin_data_size;
uint32_t ui_ver;
char product[8];
uint32_t addr_byte_len;
uint32_t data_byte_len;
uint32_t device_addr;
uint32_t reserve[4];
};
struct aw_monitor_header {
uint32_t monitor_switch;
uint32_t monitor_time;
uint32_t monitor_count;
uint32_t step_count;
uint32_t reserve[4];
};
struct vmax_step_config {
uint32_t vbat_min;
uint32_t vbat_max;
int vmax_vol;
};
struct aw_monitor {
bool open_dsp_en;
bool esd_enable;
int32_t dev_index;
uint8_t first_entry;
uint8_t timer_cnt;
uint32_t vbat_sum;
int32_t custom_capacity;
uint32_t pre_vmax;
int bin_status;
struct aw_monitor_header monitor_hdr;
struct vmax_step_config *vmax_cfg;
struct delayed_work with_dsp_work;
};
void aw87xxx_monitor_cfg_free(struct aw_monitor *monitor);
int aw87xxx_monitor_bin_parse(struct device *dev,
char *monitor_data, uint32_t data_len);
void aw87xxx_monitor_stop(struct aw_monitor *monitor);
void aw87xxx_monitor_start(struct aw_monitor *monitor);
int aw87xxx_monitor_no_dsp_get_vmax(struct aw_monitor *monitor,
int32_t *vmax);
void aw87xxx_monitor_init(struct device *dev, struct aw_monitor *monitor,
struct device_node *dev_node);
void aw87xxx_monitor_exit(struct aw_monitor *monitor);
int aw87xxx_dev_monitor_switch_set(struct aw_monitor *monitor, uint32_t enable);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,67 @@
#ifndef __AW87XXX_PID_39_REG_H__
#define __AW87XXX_PID_39_REG_H__
#define AW87XXX_PID_39_REG_CHIPID (0x00)
#define AW87XXX_PID_39_REG_SYSCTRL (0x01)
#define AW87XXX_PID_39_REG_MODECTRL (0x02)
#define AW87XXX_PID_39_REG_CPOVP (0x03)
#define AW87XXX_PID_39_REG_CPP (0x04)
#define AW87XXX_PID_39_REG_GAIN (0x05)
#define AW87XXX_PID_39_REG_AGC3_PO (0x06)
#define AW87XXX_PID_39_REG_AGC3 (0x07)
#define AW87XXX_PID_39_REG_AGC2_PO (0x08)
#define AW87XXX_PID_39_REG_AGC2 (0x09)
#define AW87XXX_PID_39_REG_AGC1 (0x0A)
#define AW87XXX_PID_39_REG_DFT1 (0x62)
#define AW87XXX_PID_39_REG_DFT2 (0x63)
#define AW87XXX_PID_39_REG_ENCRY (0x64)
#define AW87XXX_PID_39_MODECTRL_DEFAULT (0xa0)
/********************************************
* soft control info
* If you need to update this file, add this information manually
*******************************************/
unsigned char aw87xxx_pid_39_softrst_access[2] = {0x00, 0xaa};
/********************************************
* Register Access
*******************************************/
#define AW87XXX_PID_39_REG_MAX (0x65)
#define REG_NONE_ACCESS (0)
#define REG_RD_ACCESS (1 << 0)
#define REG_WR_ACCESS (1 << 1)
const unsigned char aw87xxx_pid_39_reg_access[AW87XXX_PID_39_REG_MAX] = {
[AW87XXX_PID_39_REG_CHIPID] = (REG_RD_ACCESS),
[AW87XXX_PID_39_REG_SYSCTRL] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_39_REG_MODECTRL] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_39_REG_CPOVP] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_39_REG_CPP] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_39_REG_GAIN] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_39_REG_AGC3_PO] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_39_REG_AGC3] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_39_REG_AGC2_PO] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_39_REG_AGC2] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_39_REG_AGC1] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_39_REG_DFT1] = (REG_RD_ACCESS),
[AW87XXX_PID_39_REG_DFT2] = (REG_RD_ACCESS),
[AW87XXX_PID_39_REG_ENCRY] = (REG_RD_ACCESS),
};
/* RCV_MODE bit 3 (MODECTRL 0x02) */
#define AW87XXX_PID_39_REC_MODE_START_BIT (3)
#define AW87XXX_PID_39_REC_MODE_BITS_LEN (1)
#define AW87XXX_PID_39_REC_MODE_MASK \
(~(((1<<AW87XXX_PID_39_REC_MODE_BITS_LEN)-1) << AW87XXX_PID_39_REC_MODE_START_BIT))
#define AW87XXX_PID_39_REC_MODE_DISABLE (0)
#define AW87XXX_PID_39_REC_MODE_DISABLE_VALUE \
(AW87XXX_PID_39_REC_MODE_DISABLE << AW87XXX_PID_39_REC_MODE_START_BIT)
#define AW87XXX_PID_39_REC_MODE_ENABLE (1)
#define AW87XXX_PID_39_REC_MODE_ENABLE_VALUE \
(AW87XXX_PID_39_REC_MODE_ENABLE << AW87XXX_PID_39_REC_MODE_START_BIT)
#endif

View file

@ -0,0 +1,93 @@
/*
* @Descripttion: Header file of AW87XXX_PID_59_3X9_REG
* @version: V1.33
* @Author: zhaozhongbo
* @Date: 2021-03-10
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-03-10
*/
#ifndef __AW87XXX_PID_59_3X9_REG_H__
#define __AW87XXX_PID_59_3X9_REG_H__
#define AW87XXX_PID_59_3X9_REG_CHIPID (0x00)
#define AW87XXX_PID_59_3X9_REG_SYSCTRL (0x01)
#define AW87XXX_PID_59_3X9_REG_MDCRTL (0x02)
#define AW87XXX_PID_59_3X9_REG_CPOVP (0x03)
#define AW87XXX_PID_59_3X9_REG_CPP (0x04)
#define AW87XXX_PID_59_3X9_REG_PAG (0x05)
#define AW87XXX_PID_59_3X9_REG_AGC3PO (0x06)
#define AW87XXX_PID_59_3X9_REG_AGC3PA (0x07)
#define AW87XXX_PID_59_3X9_REG_AGC2PO (0x08)
#define AW87XXX_PID_59_3X9_REG_AGC2PA (0x09)
#define AW87XXX_PID_59_3X9_REG_AGC1PA (0x0A)
#define AW87XXX_PID_59_3X9_REG_SYSST (0x59)
#define AW87XXX_PID_59_3X9_REG_SYSINT (0x60)
#define AW87XXX_PID_59_3X9_REG_DFT_SYSCTRL (0x61)
#define AW87XXX_PID_59_3X9_REG_DFT_MDCTRL (0x62)
#define AW87XXX_PID_59_3X9_REG_DFT_CPOVP2 (0x63)
#define AW87XXX_PID_59_3X9_REG_DFT_AGCPA (0x64)
#define AW87XXX_PID_59_3X9_REG_DFT_POFR (0x65)
#define AW87XXX_PID_59_3X9_REG_DFT_OC (0x66)
#define AW87XXX_PID_59_3X9_REG_DFT_OTA (0x67)
#define AW87XXX_PID_59_3X9_REG_DFT_REF (0x68)
#define AW87XXX_PID_59_3X9_REG_DFT_LDO (0x69)
#define AW87XXX_PID_59_3X9_REG_ENCR (0x70)
#define AW87XXX_PID_59_3X9_ENCR_DEFAULT (0x00)
/********************************************
* soft control info
* If you need to update this file, add this information manually
*******************************************/
unsigned char aw87xxx_pid_59_3x9_softrst_access[2] = {0x00, 0xaa};
/********************************************
* Register Access
*******************************************/
#define AW87XXX_PID_59_3X9_REG_MAX (0x71)
#define REG_NONE_ACCESS (0)
#define REG_RD_ACCESS (1 << 0)
#define REG_WR_ACCESS (1 << 1)
const unsigned char aw87xxx_pid_59_3x9_reg_access[AW87XXX_PID_59_3X9_REG_MAX] = {
[AW87XXX_PID_59_3X9_REG_CHIPID] = (REG_RD_ACCESS),
[AW87XXX_PID_59_3X9_REG_SYSCTRL] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_3X9_REG_MDCRTL] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_3X9_REG_CPOVP] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_3X9_REG_CPP] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_3X9_REG_PAG] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_3X9_REG_AGC3PO] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_3X9_REG_AGC3PA] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_3X9_REG_AGC2PO] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_3X9_REG_AGC2PA] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_3X9_REG_AGC1PA] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_3X9_REG_SYSST] = (REG_RD_ACCESS),
[AW87XXX_PID_59_3X9_REG_SYSINT] = (REG_RD_ACCESS),
[AW87XXX_PID_59_3X9_REG_DFT_SYSCTRL] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_3X9_REG_DFT_MDCTRL] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_3X9_REG_DFT_CPOVP2] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_3X9_REG_DFT_AGCPA] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_3X9_REG_DFT_POFR] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_3X9_REG_DFT_OC] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_3X9_REG_DFT_OTA] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_3X9_REG_DFT_REF] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_3X9_REG_DFT_LDO] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_3X9_REG_ENCR] = (REG_RD_ACCESS | REG_WR_ACCESS),
};
/* SPK_MODE bit 2 (MDCRTL 0x02) */
#define AW87XXX_PID_59_3X9_SPK_MODE_START_BIT (2)
#define AW87XXX_PID_59_3X9_SPK_MODE_BITS_LEN (1)
#define AW87XXX_PID_59_3X9_SPK_MODE_MASK \
(~(((1<<AW87XXX_PID_59_3X9_SPK_MODE_BITS_LEN)-1) << AW87XXX_PID_59_3X9_SPK_MODE_START_BIT))
#define AW87XXX_PID_59_3X9_SPK_MODE_DISABLE (0)
#define AW87XXX_PID_59_3X9_SPK_MODE_DISABLE_VALUE \
(AW87XXX_PID_59_3X9_SPK_MODE_DISABLE << AW87XXX_PID_59_3X9_SPK_MODE_START_BIT)
#define AW87XXX_PID_59_3X9_SPK_MODE_ENABLE (1)
#define AW87XXX_PID_59_3X9_SPK_MODE_ENABLE_VALUE \
(AW87XXX_PID_59_3X9_SPK_MODE_ENABLE << AW87XXX_PID_59_3X9_SPK_MODE_START_BIT)
#endif

View file

@ -0,0 +1,94 @@
/*
* @Descripttion: Header file of AW87XXX_PID_59_5X9_REG
* @version: V1.33
* @Author: zhaozhongbo
* @Date: 2021-03-10
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-03-10
*/
#ifndef __AW87XXX_PID_59_5X9_REG_H__
#define __AW87XXX_PID_59_5X9_REG_H__
#define AW87XXX_PID_59_5X9_REG_CHIPID (0x00)
#define AW87XXX_PID_59_5X9_REG_SYSCTRL (0x01)
#define AW87XXX_PID_59_5X9_REG_BATSAFE (0x02)
#define AW87XXX_PID_59_5X9_REG_BSTOVR (0x03)
#define AW87XXX_PID_59_5X9_REG_BSTVPR (0x04)
#define AW87XXX_PID_59_5X9_REG_PAGR (0x05)
#define AW87XXX_PID_59_5X9_REG_PAGC3OPR (0x06)
#define AW87XXX_PID_59_5X9_REG_PAGC3PR (0x07)
#define AW87XXX_PID_59_5X9_REG_PAGC2OPR (0x08)
#define AW87XXX_PID_59_5X9_REG_PAGC2PR (0x09)
#define AW87XXX_PID_59_5X9_REG_PAGC1PR (0x0A)
#define AW87XXX_PID_59_5X9_REG_SYSST (0x58)
#define AW87XXX_PID_59_5X9_REG_SYSINT (0x59)
#define AW87XXX_PID_59_5X9_REG_CPCR (0x60)
#define AW87XXX_PID_59_5X9_REG_DFT1R (0x61)
#define AW87XXX_PID_59_5X9_REG_DFT2R (0x62)
#define AW87XXX_PID_59_5X9_REG_DFT3R (0x63)
#define AW87XXX_PID_59_5X9_REG_DFT4R (0x64)
#define AW87XXX_PID_59_5X9_REG_DFT5R (0x65)
#define AW87XXX_PID_59_5X9_REG_DFT6R (0x66)
#define AW87XXX_PID_59_5X9_REG_DFT7R (0x67)
#define AW87XXX_PID_59_5X9_REG_DFT8R (0x68)
#define AW87XXX_PID_59_5X9_REG_ENCR (0x69)
#define AW87XXX_PID_59_5X9_ENCRY_DEFAULT (0x00)
/********************************************
* soft control info
* If you need to update this file, add this information manually
*******************************************/
unsigned char aw87xxx_pid_59_5x9_softrst_access[2] = {0x00, 0xaa};
/********************************************
* Register Access
*******************************************/
#define AW87XXX_PID_59_5X9_REG_MAX (0x70)
#define REG_NONE_ACCESS (0)
#define REG_RD_ACCESS (1 << 0)
#define REG_WR_ACCESS (1 << 1)
const unsigned char aw87xxx_pid_59_5x9_reg_access[AW87XXX_PID_59_5X9_REG_MAX] = {
[AW87XXX_PID_59_5X9_REG_CHIPID] = (REG_RD_ACCESS),
[AW87XXX_PID_59_5X9_REG_SYSCTRL] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_5X9_REG_BATSAFE] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_5X9_REG_BSTOVR] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_5X9_REG_BSTVPR] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_5X9_REG_PAGR] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_5X9_REG_PAGC3OPR] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_5X9_REG_PAGC3PR] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_5X9_REG_PAGC2OPR] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_5X9_REG_PAGC2PR] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_5X9_REG_PAGC1PR] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_5X9_REG_SYSST] = (REG_RD_ACCESS),
[AW87XXX_PID_59_5X9_REG_SYSINT] = (REG_RD_ACCESS),
[AW87XXX_PID_59_5X9_REG_CPCR] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_5X9_REG_DFT1R] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_5X9_REG_DFT2R] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_5X9_REG_DFT3R] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_5X9_REG_DFT4R] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_5X9_REG_DFT5R] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_5X9_REG_DFT6R] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_5X9_REG_DFT7R] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_5X9_REG_DFT8R] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_59_5X9_REG_ENCR] = (REG_RD_ACCESS | REG_WR_ACCESS),
};
/* RCV_MODE bit 3 (SYSCTRL 0x01) */
#define AW87XXX_PID_59_5X9_REC_MODE_START_BIT (3)
#define AW87XXX_PID_59_5X9_REC_MODE_BITS_LEN (1)
#define AW87XXX_PID_59_5X9_REC_MODE_MASK \
(~(((1<<AW87XXX_PID_59_5X9_REC_MODE_BITS_LEN)-1) << AW87XXX_PID_59_5X9_REC_MODE_START_BIT))
#define AW87XXX_PID_59_5X9_REC_MODE_DISABLE (0)
#define AW87XXX_PID_59_5X9_REC_MODE_DISABLE_VALUE \
(AW87XXX_PID_59_5X9_REC_MODE_DISABLE << AW87XXX_PID_59_5X9_REC_MODE_START_BIT)
#define AW87XXX_PID_59_5X9_REC_MODE_ENABLE (1)
#define AW87XXX_PID_59_5X9_REC_MODE_ENABLE_VALUE \
(AW87XXX_PID_59_5X9_REC_MODE_ENABLE << AW87XXX_PID_59_5X9_REC_MODE_START_BIT)
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,81 @@
#ifndef __AW87XXX_PID_9B_REG_H__
#define __AW87XXX_PID_9B_REG_H__
#define AW87XXX_PID_9B_CHIPID_REG (0x00)
#define AW87XXX_PID_9B_SYSCTRL_REG (0x01)
#define AW87XXX_PID_9B_BATSAFE_REG (0x02)
#define AW87XXX_PID_9B_BOV_REG (0x03)
#define AW87XXX_PID_9B_BP_REG (0x04)
#define AW87XXX_PID_9B_GAIN_REG (0x05)
#define AW87XXX_PID_9B_AGC3_PO_REG (0x06)
#define AW87XXX_PID_9B_AGC3_REG (0x07)
#define AW87XXX_PID_9B_AGC2_REG (0x08)
#define AW87XXX_PID_9B_AGC1_REG (0x09)
#define AW87XXX_PID_9B_SYSCTRL_DEFAULT (0x03)
/********************************************
* soft control info
* If you need to update this file, add this information manually
*******************************************/
unsigned char aw87xxx_pid_9b_softrst_access[2] = {0x00, 0xaa};
/********************************************
* Register Access
*******************************************/
#define AW87XXX_PID_9B_REG_MAX (0x64)
#define REG_NONE_ACCESS (0)
#define REG_RD_ACCESS (1 << 0)
#define REG_WR_ACCESS (1 << 1)
const unsigned char aw87xxx_pid_9b_reg_access[AW87XXX_PID_9B_REG_MAX] = {
[AW87XXX_PID_9B_CHIPID_REG] = (REG_RD_ACCESS),
[AW87XXX_PID_9B_SYSCTRL_REG] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_9B_BATSAFE_REG] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_9B_BOV_REG] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_9B_BP_REG] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_9B_GAIN_REG] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_9B_AGC3_PO_REG] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_9B_AGC3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_9B_AGC2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS),
[AW87XXX_PID_9B_AGC1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS),
};
#define AW87XXX_PID_9B_ENCRYPTION_REG (0x64)
#define AW87XXX_PID_9B_ENCRYPTION_BOOST_OUTPUT_SET (0x2C)
/* REG_EN_SW bit 2 (SYSCTRL 0x01) */
#define AW87XXX_PID_9B_REG_EN_SW_START_BIT (2)
#define AW87XXX_PID_9B_REG_EN_SW_BITS_LEN (1)
#define AW87XXX_PID_9B_REG_EN_SW_MASK \
(~(((1<<AW87XXX_PID_9B_REG_EN_SW_BITS_LEN)-1) << AW87XXX_PID_9B_REG_EN_SW_START_BIT))
#define AW87XXX_PID_9B_REG_EN_SW_DISABLE (0)
#define AW87XXX_PID_9B_REG_EN_SW_DISABLE_VALUE \
(AW87XXX_PID_9B_REG_EN_SW_DISABLE << AW87XXX_PID_9B_REG_EN_SW_START_BIT)
#define AW87XXX_PID_9B_REG_EN_SW_ENABLE (1)
#define AW87XXX_PID_9B_REG_EN_SW_ENABLE_VALUE \
(AW87XXX_PID_9B_REG_EN_SW_ENABLE << AW87XXX_PID_9B_REG_EN_SW_START_BIT)
#define AW87XXX_PID_9B_REG_EN_SW_DEFAULT_VALUE (1)
#define AW87XXX_PID_9B_REG_EN_SW_DEFAULT \
(AW87XXX_PID_9B_REG_EN_SW_DEFAULT_VALUE << AW87XXX_PID_9B_REG_EN_SW_START_BIT)
/* SPK_MODE bit 0 (SYSCTRL 0x01) */
#define AW87XXX_PID_9B_SPK_MODE_START_BIT (0)
#define AW87XXX_PID_9B_SPK_MODE_BITS_LEN (1)
#define AW87XXX_PID_9B_SPK_MODE_MASK \
(~(((1<<AW87XXX_PID_9B_SPK_MODE_BITS_LEN)-1) << AW87XXX_PID_9B_SPK_MODE_START_BIT))
#define AW87XXX_PID_9B_SPK_MODE_DISABLE (0)
#define AW87XXX_PID_9B_SPK_MODE_DISABLE_VALUE \
(AW87XXX_PID_9B_SPK_MODE_DISABLE << AW87XXX_PID_9B_SPK_MODE_START_BIT)
#define AW87XXX_PID_9B_SPK_MODE_ENABLE (1)
#define AW87XXX_PID_9B_SPK_MODE_ENABLE_VALUE \
(AW87XXX_PID_9B_SPK_MODE_ENABLE << AW87XXX_PID_9B_SPK_MODE_START_BIT)
#endif

View file

@ -0,0 +1,8 @@
DLKM_DIR := $(TOP)/device/qcom/common/dlkm
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := aw882xx_k419.ko
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
include $(DLKM_DIR)/AndroidKernelModule.mk

View file

@ -0,0 +1,9 @@
# add -Wall to try to catch everything we can.
EXTRA_CFLAGS += -Wall
EXTRA_CFLAGS += -I$(TOP)/kernel/msm-5.4/techpack/audio/include
EXTRA_CFLAGS += -I$(TOP)/kernel/msm-5.4/techpack/audio/include/uapi/
EXTRA_CFLAGS += -DCONFIG_AW882XX_CODEC -DCONFIG_AW882XX_DSP
aw882xx_k419-objs = aw882xx.o
obj-m += aw882xx_k419.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,317 @@
#ifndef _AW882XX_H_
#define _AW882XX_H_
//#define AW_DEBUG
/*
* i2c transaction on Linux limited to 64k
* (See Linux kernel documentation: Documentation/i2c/writing-clients)
*/
#define MAX_I2C_BUFFER_SIZE 65536
#define AW882XX_I2C_READ_MSG_NUM 2
#define AW_VOL_COUNT (3)
#define AW882XX_FLAG_START_ON_MUTE (1 << 0)
#define AW882XX_FLAG_SKIP_INTERRUPTS (1 << 1)
#define AW882XX_FLAG_SAAM_AVAILABLE (1 << 2)
#define AW882XX_FLAG_STEREO_DEVICE (1 << 3)
#define AW882XX_FLAG_MULTI_MIC_INPUTS (1 << 4)
#define AW882XX_NUM_RATES 9
#define AW882XX_SYSST_CHECK_MAX 10
#define AW882XX_MODE_SHIFT_MAX 2
#define AW882XX_DEFAULT_AFE_RX_PROT_ID 0x1000 /*AFE_PORT_ID_PRIMARY_MI2S_RX*/
#define AW882XX_DEFAULT_AFE_TX_PROT_ID 0x1001 /*AFE_PORT_ID_PRIMARY_MI2S_TX*/
#define AW_MODULE_ID_COPP (0X10013D02) /*SKT module id*/
#define AW_MODULE_PARAMS_ID_COPP_ENABLE (0X10013D14) /*SKT enable param id*/
#define AW_IOCTL_MSG_VERSION (0)
#define DEFAULT_CALI_VALUE (7)
#define ERRO_CALI_VALUE (0)
#define AFE_PARAM_ID_AWDSP_RX_SET_ENABLE (0x10013D11)
#define AFE_PARAM_ID_AWDSP_RX_PARAMS (0x10013D12)
#define AFE_PARAM_ID_AWDSP_TX_SET_ENABLE (0x10013D13)
#define AFE_PARAM_ID_AWDSP_RX_VMAX_L (0X10013D17)
#define AFE_PARAM_ID_AWDSP_RX_VMAX_R (0X10013D18)
#define AFE_PARAM_ID_AWDSP_RX_CALI_CFG_L (0X10013D19)
#define AFE_PARAM_ID_AWDSP_RX_CALI_CFG_R (0x10013d1A)
#define AFE_PARAM_ID_AWDSP_RX_RE_L (0x10013d1B)
#define AFE_PARAM_ID_AWDSP_RX_RE_R (0X10013D1C)
#define AFE_PARAM_ID_AWDSP_RX_NOISE_L (0X10013D1D)
#define AFE_PARAM_ID_AWDSP_RX_NOISE_R (0X10013D1E)
#define AFE_PARAM_ID_AWDSP_RX_F0_L (0X10013D1F)
#define AFE_PARAM_ID_AWDSP_RX_F0_R (0X10013D20)
#define AFE_PARAM_ID_AWDSP_RX_REAL_DATA_L (0X10013D21)
#define AFE_PARAM_ID_AWDSP_RX_REAL_DATA_R (0X10013D22)
#define AFE_PARAM_ID_AWDSP_RX_MSG (0X10013D2A)
enum {
AW_FIRST_ENTRY = 0,
AW_NOT_FIRST_ENTRY = 1,
};
enum {
AW_IOCTL_MSG_IOCTL = 0,
AW_IOCTL_MSG_RD_DSP,
AW_IOCTL_MSG_WR_DSP
};
enum AWINIC_CALI_CMD{
AW_CALI_CMD_NONE = 0,
AW_CALI_CMD_START,
AW_CALI_CMD_END,
AW_CALI_CMD_SET_CALI_CFG,
AW_CALI_CMD_GET_CALI_CFG,
AW_CALI_CMD_GET_CALI_DATA,
AW_CALI_CMD_SET_NOISE,
AW_CALI_CMD_GET_F0,
AW_CALI_CMD_SET_CALI_RE,
AW_CALI_CMD_GET_CALI_RE,
AW_CALI_CMD_SET_VMAX,
AW_CALI_CMD_GET_VMAX,
AW_CALI_CMD_MAX,
};
enum aw882xx_dsp_msg_type {
DSP_MSG_TYPE_DATA = 0,
DSP_MSG_TYPE_CMD = 1,
};
#define AW882XX_CALI_CFG_NUM 3
#define AW882XX_CALI_DATA_NUM 6
#define AW882XX_PARAMS_NUM 400
#define AWINIC_DSP_MSG_HDR_VER (1)
struct cali_cfg{
int32_t data[AW882XX_CALI_CFG_NUM];
};
struct cali_data{
int32_t data[AW882XX_CALI_DATA_NUM];
};
struct params_data{
int32_t data[AW882XX_PARAMS_NUM];
};
struct ptr_params_data {
int len;
int32_t *data;
};
typedef struct {
int32_t type;
int32_t opcode_id;
int32_t version;
int32_t data_len;
char *data_buf;
int32_t reseriver[2];
}aw_ioctl_msg_t;
struct aw_dsp_msg_hdr {
int32_t type;
int32_t opcode_id;
int32_t version;
int32_t reserver[3];
};
#define AW882XX_IOCTL_MAGIC 'a'
#define AW882XX_IOCTL_SET_CALI_CFG _IOWR(AW882XX_IOCTL_MAGIC, 1, struct cali_cfg)
#define AW882XX_IOCTL_GET_CALI_CFG _IOWR(AW882XX_IOCTL_MAGIC, 2, struct cali_cfg)
#define AW882XX_IOCTL_GET_CALI_DATA _IOWR(AW882XX_IOCTL_MAGIC, 3, struct cali_data)
#define AW882XX_IOCTL_SET_NOISE _IOWR(AW882XX_IOCTL_MAGIC, 4, int32_t)
#define AW882XX_IOCTL_GET_F0 _IOWR(AW882XX_IOCTL_MAGIC, 5, int32_t)
#define AW882XX_IOCTL_SET_CALI_RE _IOWR(AW882XX_IOCTL_MAGIC, 6, int32_t)
#define AW882XX_IOCTL_GET_CALI_RE _IOWR(AW882XX_IOCTL_MAGIC, 7, int32_t)
#define AW882XX_IOCTL_SET_VMAX _IOWR(AW882XX_IOCTL_MAGIC, 8, int32_t)
#define AW882XX_IOCTL_GET_VMAX _IOWR(AW882XX_IOCTL_MAGIC, 9, int32_t)
#define AW882XX_IOCTL_SET_PARAM _IOWR(AW882XX_IOCTL_MAGIC, 10,struct params_data)
#define AW882XX_IOCTL_ENABLE_CALI _IOWR(AW882XX_IOCTL_MAGIC, 11,int8_t)
#define AW882XX_IOCTL_SET_PTR_PARAM_NUM _IOWR(AW882XX_IOCTL_MAGIC, 12, struct ptr_params_data)
#define AW882XX_IOCTL_MSG _IOWR(AW882XX_IOCTL_MAGIC, 16, aw_ioctl_msg_t)
enum aw882xx_init {
AW882XX_INIT_ST = 0,
AW882XX_INIT_OK = 1,
AW882XX_INIT_NG = 2,
};
enum aw882xx_power_status {
AW882XX_POWER_DOWN = 0,
AW882XX_POWER_ING = 1,
AW882XX_POWER_UP = 2,
};
enum aw882xx_chipid {
AW882XX_ID = 0x1852,
};
enum aw882xx_modeshift {
AW882XX_MODE_SPK_SHIFT = 0,
AW882XX_MODE_RCV_SHIFT = 1,
};
enum aw882xx_mode_spk_rcv {
AW882XX_SPEAKER_MODE = 0,
AW882XX_RECEIVER_MODE = 1,
};
//smartpa monitor
enum aw882xx_ipeak {
IPEAK_3P50_A = 0x08,
IPEAK_3P00_A = 0x06,
IPEAK_2P75_A = 0x05,
IPEAK_2P50_A = 0x04,
IPEAK_NONE = 0xFF,
};
enum aw882xx_gain {
GAIN_NEG_0P0_DB = 0x00,
GAIN_NEG_0P5_DB = 0x01,
GAIN_NEG_1P0_DB = 0x02,
GAIN_NEG_1P5_DB = 0x03,
GAIN_NEG_3P0_DB = 0x06,
GAIN_NEG_4P5_DB = 0x09,
GAIN_NEG_6P0_DB = 0x10,
GAIN_NONE = 0xFF,
};
enum aw882xx_vmax_percentage {
VMAX_100_PERCENTAGE = 0x00000000,
VMAX_086_PERCENTAGE = 0xFFED714D,
VMAX_075_PERCENTAGE = 0xFFD80505,
VMAX_063_PERCENTAGE = 0xFFBEAE7E,
VMAX_NONE = 0xFFFFFFFF,
};
#define AW882XX_MONITOR_DEFAULT_FLAG 0
#define AW882XX_MONITOR_DEFAULT_TIMER_VAL 30000
#define AW882XX_MONITOR_VBAT_RANGE 6025
#define AW882XX_MONITOR_INT_10BIT 1023
#define AW882XX_MONITOR_TEMP_SIGN_MASK (1<<9)
#define AW882XX_MONITOR_TEMP_NEG_MASK (0XFC00)
#define AW882XX_BIT_SYSCTRL2_BST_IPEAK_MASK ( 15<< 0)
#define AW882XX_BIT_HAGCCFG4_GAIN_SHIFT (8)
#define AW882XX_BIT_HAGCCFG4_GAIN_MASK (0x00ff)
struct aw882xx_low_vol {
uint32_t vol;
uint8_t ipeak;
uint8_t gain;
};
struct aw882xx_low_temp {
int16_t temp;
uint8_t ipeak;
uint8_t gain;
uint32_t vmax;
};
struct aw882xx_monitor{
struct hrtimer timer;
uint32_t timer_val;
struct work_struct work;
uint32_t is_enable;
uint16_t pre_vol;
uint16_t vol_count;
uint8_t first_entry;
struct aw882xx_low_vol vol_cfg;
struct aw882xx_low_temp temp_cfg;
int vol_up_num;
int vol_down_num;
int temp_up_num;
int temp_down_num;
struct aw882xx_low_vol *vol_up_table;
struct aw882xx_low_vol *vol_down_table;
struct aw882xx_low_temp *temp_up_table;
struct aw882xx_low_temp *temp_down_table;
#ifdef AW_DEBUG
uint16_t test_vol;
int16_t test_temp;
#endif
};
/*control runin test function*/
#define AW882XX_RUNIN_TEST
enum AWINIC_PROFILE{
AW_PROFILE_MUSIC = 0,
AW_PROFILE_RINGTONE,
AW_PROFILE_NOTIFICATION,
AW_PROFILE_VOICE,
AW_PROFILE_MAX,
};
#define VERSION_MAX 4
#define PROJECT_NAME_MAX 24
#define VOLUME_STEP_DB (6)
#define VOLUME_MIN_NEG_90_DB (90)
#define FADE_STEP_DB (6)
typedef struct awinic_afe_param_header{
uint8_t fw[VERSION_MAX];
uint8_t cfg[VERSION_MAX];
uint8_t project[PROJECT_NAME_MAX];
uint32_t start;
uint32_t params_len;
uint8_t check_sum;
uint8_t profile_num;
uint8_t reserve[2];
}aw_afe_params_hdr_t;
struct profile_info {
struct mutex lock;
int cur_profile;
int status;
int len;
char* data[AW_PROFILE_MAX];
};
struct aw882xx {
struct regmap *regmap;
struct i2c_client *i2c;
struct snd_soc_component *component;
struct device *dev;
struct mutex lock;
struct aw882xx_monitor monitor;
#ifdef AW882XX_RUNIN_TEST
struct delayed_work adsp_status;
#endif
struct delayed_work fade_work;
int delayed_time;
int fade_work_start;
int is_fade_in;
int sysclk;
int rate;
int pstream;
int cstream;
int reset_gpio;
int irq_gpio;
int power_flag;
unsigned char reg_addr;
unsigned int flags;
unsigned int chipid;
unsigned int init;
unsigned int spk_rcv_mode;
uint32_t cali_re;
uint32_t default_re;
uint8_t cur_gain;
uint8_t need_fade;
unsigned int cfg_num;
unsigned int afe_rx_portid;
unsigned int afe_tx_portid;
unsigned int afe_profile;
unsigned int fade_flag;
struct profile_info profile;
};
struct aw882xx_container {
int len;
unsigned char data[];
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,11 @@
DLKM_DIR := $(TOP)/device/qcom/common/dlkm
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_ADDITIONAL_DEPENDENCIES += $(KERNEL_MODULES_OUT)/machine_dlkm.ko
LOCAL_MODULE := aw882xx_acf.ko
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
include $(DLKM_DIR)/AndroidKernelModule.mk

View file

@ -0,0 +1,25 @@
# add -Wall to try to catch everything we can.
EXTRA_CFLAGS += -Wall
EXTRA_CFLAGS += -I$(TOP)/kernel/msm-5.4/techpack/audio/include
EXTRA_CFLAGS += -I$(TOP)/kernel/msm-5.4/techpack/audio/include/uapi/
EXTRA_CFLAGS += -DCONFIG_AW882XX_CODEC -DCONFIG_AW882XX_DSP
ifeq ($(CONFIG_AW882XX_STEREO_SMARTPA), y)
EXTRA_CFLAGS += -DCONFIG_AW882XX_STEREO_SMARTPA
EXTRA_CFLAGS += -DAW_SPIN_ENABLE
endif
ifeq ($(CONFIG_AW882XX_PARAMS_FROM_BIN), y)
EXTRA_CFLAGS += -DCONFIG_AW882XX_ALGO_BIN_PARAMS
endif
aw882xx_acf-objs += aw882xx.o
aw882xx_acf-objs += aw_bin_parse.o
aw882xx_acf-objs += aw_calib.o
aw882xx_acf-objs += aw_device.o
aw882xx_acf-objs += aw_dsp.o
aw882xx_acf-objs += aw_init.o
aw882xx_acf-objs += aw_monitor.o
obj-m += aw882xx_acf.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,274 @@
#ifndef _AW882XX_H_
#define _AW882XX_H_
#include <linux/version.h>
#include <linux/kernel.h>
#include "aw_device.h"
/*
* i2c transaction on Linux limited to 64k
* (See Linux kernel documentation: Documentation/i2c/writing-clients)
*/
#define AW882XX_CHIP_ID_REG (0x00)
#define MAX_I2C_BUFFER_SIZE 65536
#define AW882XX_I2C_READ_MSG_NUM 2
#define AW882XX_DC_DELAY_TIME (1000)
#define AW882XX_LOAD_FW_DELAY_TIME (0)
#define AW_START_RETRIES (5)
#define AW882XX_RUNIN_TEST
#define AW_ALGO_SKT_BIN "aw_skt.bin"
#define AW_DEFAULT_PRO_ID (0xFFFFFFFF)
#define AW_I2C_RETRIES 5 /* 5 times */
#define AW_I2C_RETRY_DELAY 5 /* 5 ms */
#define AW882XX_RATES SNDRV_PCM_RATE_8000_48000
#define AW882XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
enum {
AW882XX_STREAM_CLOSE = 0,
AW882XX_STREAM_OPEN,
};
enum aw882xx_chipid {
PID_1852_ID = 0x1852,
PID_2013_ID = 0x2013,
PID_2032_ID = 0x2032,
PID_2055_ID = 0x2055,
PID_2071_ID = 0x2071,
PID_2113_ID = 0x2113,
};
#define AW882XX_SOFT_RESET_VALUE (0x55aa)
enum aw882xx_int_type {
INT_TYPE_NONE = 0,
INT_TYPE_UVLO = 0x1,
INT_TYPE_BSTOC = 0x2,
INT_TYPE_OCDI = 0x4,
INT_TYPE_OTHI = 0x8,
};
#ifdef CONFIG_AW882XX_ALGO_BIN_PARAMS
enum {
AW_ALGO_PROFILE_ID_0 = 0,
AW_ALGO_PROFILE_ID_1,
AW_ALGO_PROFILE_ID_2,
AW_ALGO_PROFILE_ID_3,
AW_ALGO_PROFILE_ID_4,
AW_ALGO_PROFILE_ID_5,
AW_ALGO_PROFILE_ID_6,
AW_ALGO_PROFILE_ID_7,
AW_ALGO_PROFILE_ID_MAX,
};
struct aw882xx_scene_info {
int id;
char name[20];
int priority;
int skt_profile_id;
int is_active;
int active_cnt;
};
enum {
AW_PARAMS_PATH_MODE = 0,
AW_PARAMS_DATA_MODE,
};
#endif
#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
#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);
};
enum {
AWRW_I2C_ST_NONE = 0,
AWRW_I2C_ST_READ,
AWRW_I2C_ST_WRITE,
};
#define AWRW_ADDR_BYTES (1)
#define AWRW_DATA_BYTES (2)
#define AWRW_HDR_LEN (24)
enum {
AWRW_FLAG_WRITE = 0,
AWRW_FLAG_READ,
};
enum {
AW_BSTCFG_DISABLE = 0,
AW_BSTCFG_ENABLE,
};
enum {
AW_FRCSET_DISABLE = 0,
AW_FRCSET_ENABLE,
};
enum {
AW_BOP_DISABLE = 0,
AW_BOP_ENABLE,
};
enum {
AW882XX_RAMP_OFF = 0,
AW882XX_RAMP_ON,
};
#ifdef CONFIG_AW882XX_ALGO_BIN_PARAMS
enum {
AW_ALGO_CALI_OFF = 0,
AW_ALGO_CALI_ON,
};
enum {
AW_ALGO_BYPASS_OFF = 0,
AW_ALGO_BYPASS_ON,
};
enum {
AW_ALGO_HANDSET_OFF = 0,
AW_ALGO_HANDSET_ON,
};
enum {
AW_ALGO_VOICE_OFF = 0,
AW_ALGO_VOICE_ON,
};
enum {
AW_ALGO_VOIP_OFF = 0,
AW_ALGO_VOIP_ON,
};
enum {
AW_ALGO_MUSIC_DEEPBUFFER_OFF = 0,
AW_ALGO_MUSIC_DEEPBUFFER_ON,
};
enum {
AW_ALGO_MUSIC_FASTTRACK_OFF = 0,
AW_ALGO_MUSIC_FASTTRACK_ON,
};
#endif
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 aw882xx_i2c_packet{
char status;
unsigned int reg_num;
unsigned int reg_addr;
char *reg_data;
};
/********************************************
* struct aw882xx
*******************************************/
struct aw882xx {
int sysclk;
int rate;
int pstream;
int cstream;
int aw882xx_ramp_status; /* ramp status */
#ifdef CONFIG_AW882XX_ALGO_BIN_PARAMS
int aw882xx_algo_cali;
int aw882xx_algo_bypass;
int aw882xx_algo_handset;
int aw882xx_algo_voice;
int aw882xx_algo_voip;
int aw882xx_algo_music_deepbuffer;
int aw882xx_algo_music_fasttrack;
int aw882xx_algo_prof_id;
int cur_algo_prof_id;
#endif
unsigned int skt_prof_mode;
unsigned int fade_flag;
unsigned char index;
unsigned char phase_sync; /* phase sync */
unsigned char dc_flag;
unsigned char dbg_en_prof; /* debug enable/disable profile function */
unsigned char allow_pw; /* allow power */
int reset_gpio;
int irq_gpio;
unsigned int chip_id;
unsigned char fw_status;
unsigned char fw_retry_cnt;
unsigned char rw_reg_addr; /* rw attr node store read addr */
aw_snd_soc_codec_t *codec;
struct aw_componet_codec_ops *codec_ops;
struct i2c_client *i2c;
struct device *dev;
struct aw882xx_i2c_packet i2c_packet;
struct aw_device *aw_pa;
struct workqueue_struct *work_queue;
struct delayed_work start_work;
struct delayed_work interrupt_work;
struct delayed_work dc_work;
struct delayed_work fw_work;
#ifdef AW882XX_RUNIN_TEST
struct delayed_work adsp_status;
#endif
struct mutex lock;
};
void aw882xx_kcontorl_set(struct aw882xx *aw882xx);
int aw882xx_get_version(char *buf, int size);
int aw882xx_get_dev_num(void);
int aw882xx_i2c_write(struct aw882xx *aw882xx,
unsigned char reg_addr, unsigned int reg_data);
int aw882xx_i2c_read(struct aw882xx *aw882xx,
unsigned char reg_addr, unsigned int *reg_data);
int aw882xx_i2c_write_bits(struct aw882xx *aw882xx,
unsigned char reg_addr, unsigned int mask, unsigned int reg_data);
int aw882xx_init(struct aw882xx *aw882xx, int index);
int aw882xx_hw_reset(struct aw882xx *aw882xx);
#endif

View file

@ -0,0 +1,512 @@
/*
* aw_bin_parse.c
*
* Copyright (c) 2020 AWINIC Technology CO., LTD
*
* 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/kernel.h>
#include <linux/i2c.h>
#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/debugfs.h>
#include <linux/miscdevice.h>
#include <asm/uaccess.h>
#include <linux/regmap.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/hrtimer.h>
#include <linux/mutex.h>
#include <linux/cdev.h>
#include <linux/list.h>
#include <linux/string.h>
#include "aw_bin_parse.h"
#define AWINIC_CODE_VERSION "V0.0.7-V1.0.4" /* "code version"-"excel version" */
#define DEBUG_LOG_LEVEL
#ifdef DEBUG_LOG_LEVEL
#define DBG(fmt, arg...) do {\
printk("AWINIC_BIN %s,line= %d,"fmt, __func__, __LINE__, ##arg);\
} while (0)
#define DBG_ERR(fmt, arg...) do {\
printk("AWINIC_BIN_ERR %s,line= %d,"fmt, __func__, __LINE__, ##arg);\
} while (0)
#else
#define DBG(fmt, arg...) do {} while (0)
#define DBG_ERR(fmt, arg...) do {} while (0)
#endif
#define printing_data_code
typedef unsigned short int aw_uint16;
typedef unsigned long int aw_uint32;
#define BigLittleSwap16(A) ((((aw_uint16)(A) & 0xff00) >> 8) | \
(((aw_uint16)(A) & 0x00ff) << 8))
#define BigLittleSwap32(A) ((((aw_uint32)(A) & 0xff000000) >> 24) | \
(((aw_uint32)(A) & 0x00ff0000) >> 8) | \
(((aw_uint32)(A) & 0x0000ff00) << 8) | \
(((aw_uint32)(A) & 0x000000ff) << 24))
/**
*
* Interface function
*
* return value:
* value = 0 :success;
* value = -1 :check bin header version
* value = -2 :check bin data type
* value = -3 :check sum or check bin data len error
* value = -4 :check data version
* value = -5 :check register num
* value = -6 :check dsp reg num
* value = -7 :check soc app num
* value = -8 :bin is NULL point
*
**/
/********************************************************
*
* check sum data
*
********************************************************/
int aw_check_sum(struct aw_bin *bin, int bin_num)
{
unsigned int i = 0;
unsigned int sum_data = 0;
unsigned int check_sum = 0;
unsigned char *p_check_sum = NULL;
DBG("enter\n");
p_check_sum =
&(bin->info.data[(bin->header_info[bin_num].valid_data_addr -
bin->header_info[bin_num].header_len)]);
DBG("aw_bin_parse p_check_sum = %p\n", p_check_sum);
check_sum = GET_32_DATA(*(p_check_sum + 3),
*(p_check_sum + 2),
*(p_check_sum + 1), *(p_check_sum));
for (i = 4;
i <
bin->header_info[bin_num].bin_data_len +
bin->header_info[bin_num].header_len; i++) {
sum_data += *(p_check_sum + i);
}
DBG("aw_bin_parse bin_num=%d, check_sum = 0x%x, sum_data = 0x%x\n",
bin_num, check_sum, sum_data);
if (sum_data != check_sum) {
p_check_sum = NULL;
DBG_ERR("aw_bin_parse check sum or check bin data len error\n");
DBG_ERR("aw_bin_parse bin_num=%d, check_sum = 0x%x, sum_data = 0x%x\n", bin_num, check_sum, sum_data);
return -3;
}
p_check_sum = NULL;
return 0;
}
int aw_check_data_version(struct aw_bin *bin, int bin_num)
{
int i = 0;
DBG("enter\n");
for (i = DATA_VERSION_V1; i < DATA_VERSION_MAX; i++) {
if (bin->header_info[bin_num].bin_data_ver == i) {
return 0;
}
}
DBG_ERR("aw_bin_parse Unrecognized this bin data version\n");
return -4;
}
int aw_check_register_num_v1(struct aw_bin *bin, int bin_num)
{
unsigned int check_register_num = 0;
unsigned int parse_register_num = 0;
char *p_check_sum = NULL;
DBG("enter\n");
p_check_sum =
&(bin->info.data[(bin->header_info[bin_num].valid_data_addr)]);
DBG("aw_bin_parse p_check_sum = %p\n", p_check_sum);
parse_register_num = GET_32_DATA(*(p_check_sum + 3),
*(p_check_sum + 2),
*(p_check_sum + 1), *(p_check_sum));
check_register_num = (bin->header_info[bin_num].bin_data_len - 4) /
(bin->header_info[bin_num].reg_byte_len +
bin->header_info[bin_num].data_byte_len);
DBG
("aw_bin_parse bin_num=%d, parse_register_num = 0x%x, check_register_num = 0x%x\n",
bin_num, parse_register_num, check_register_num);
if (parse_register_num != check_register_num) {
p_check_sum = NULL;
DBG_ERR("aw_bin_parse register num is error\n");
DBG_ERR("aw_bin_parse bin_num=%d, parse_register_num = 0x%x, check_register_num = 0x%x\n", bin_num, parse_register_num, check_register_num);
return -5;
}
bin->header_info[bin_num].reg_num = parse_register_num;
bin->header_info[bin_num].valid_data_len =
bin->header_info[bin_num].bin_data_len - 4;
p_check_sum = NULL;
bin->header_info[bin_num].valid_data_addr =
bin->header_info[bin_num].valid_data_addr + 4;
return 0;
}
int aw_check_dsp_reg_num_v1(struct aw_bin *bin, int bin_num)
{
unsigned int check_dsp_reg_num = 0;
unsigned int parse_dsp_reg_num = 0;
char *p_check_sum = NULL;
DBG("enter\n");
p_check_sum =
&(bin->info.data[(bin->header_info[bin_num].valid_data_addr)]);
DBG("aw_bin_parse p_check_sum = %p\n", p_check_sum);
parse_dsp_reg_num = GET_32_DATA(*(p_check_sum + 7),
*(p_check_sum + 6),
*(p_check_sum + 5), *(p_check_sum + 4));
bin->header_info[bin_num].reg_data_byte_len =
GET_32_DATA(*(p_check_sum + 11), *(p_check_sum + 10),
*(p_check_sum + 9), *(p_check_sum + 8));
check_dsp_reg_num =
(bin->header_info[bin_num].bin_data_len -
12) / bin->header_info[bin_num].reg_data_byte_len;
DBG
("aw_bin_parse bin_num=%d, parse_dsp_reg_num = 0x%x, check_dsp_reg_num = 0x%x\n",
bin_num, parse_dsp_reg_num, check_dsp_reg_num);
if (parse_dsp_reg_num != check_dsp_reg_num) {
p_check_sum = NULL;
DBG_ERR("aw_bin_parse dsp reg num is error\n");
DBG_ERR("aw_bin_parse bin_num=%d, parse_dsp_reg_num = 0x%x, check_dsp_reg_num = 0x%x\n", bin_num, parse_dsp_reg_num, check_dsp_reg_num);
return -6;
}
bin->header_info[bin_num].download_addr =
GET_32_DATA(*(p_check_sum + 3), *(p_check_sum + 2),
*(p_check_sum + 1), *(p_check_sum));
bin->header_info[bin_num].reg_num = parse_dsp_reg_num;
bin->header_info[bin_num].valid_data_len =
bin->header_info[bin_num].bin_data_len - 12;
p_check_sum = NULL;
bin->header_info[bin_num].valid_data_addr =
bin->header_info[bin_num].valid_data_addr + 12;
return 0;
}
int aw_check_soc_app_num_v1(struct aw_bin *bin, int bin_num)
{
unsigned int check_soc_app_num = 0;
unsigned int parse_soc_app_num = 0;
char *p_check_sum = NULL;
DBG("enter\n");
p_check_sum =
&(bin->info.data[(bin->header_info[bin_num].valid_data_addr)]);
DBG("aw_bin_parse p_check_sum = %p\n", p_check_sum);
bin->header_info[bin_num].app_version = GET_32_DATA(*(p_check_sum + 3),
*(p_check_sum + 2),
*(p_check_sum + 1),
*(p_check_sum));
parse_soc_app_num = GET_32_DATA(*(p_check_sum + 11),
*(p_check_sum + 10),
*(p_check_sum + 9), *(p_check_sum + 8));
check_soc_app_num = bin->header_info[bin_num].bin_data_len - 12;
DBG
("aw_bin_parse bin_num=%d, parse_soc_app_num = 0x%x, check_soc_app_num = 0x%x\n",
bin_num, parse_soc_app_num, check_soc_app_num);
if (parse_soc_app_num != check_soc_app_num) {
p_check_sum = NULL;
DBG_ERR("aw_bin_parse soc app num is error\n");
DBG_ERR("aw_bin_parse bin_num=%d, parse_soc_app_num = 0x%x, check_soc_app_num = 0x%x\n", bin_num, parse_soc_app_num, check_soc_app_num);
return -7;
}
bin->header_info[bin_num].reg_num = parse_soc_app_num;
bin->header_info[bin_num].download_addr =
GET_32_DATA(*(p_check_sum + 7), *(p_check_sum + 6),
*(p_check_sum + 5), *(p_check_sum + 4));
bin->header_info[bin_num].valid_data_len =
bin->header_info[bin_num].bin_data_len - 12;
p_check_sum = NULL;
bin->header_info[bin_num].valid_data_addr =
bin->header_info[bin_num].valid_data_addr + 12;
return 0;
}
/************************
***
***bin header 1_0_0
***
************************/
void aw_get_single_bin_header_1_0_0(struct aw_bin *bin)
{
int i;
DBG("enter %s\n", __func__);
bin->header_info[bin->all_bin_parse_num].header_len = 60;
bin->header_info[bin->all_bin_parse_num].check_sum =
GET_32_DATA(*(bin->p_addr + 3), *(bin->p_addr + 2),
*(bin->p_addr + 1), *(bin->p_addr));
bin->header_info[bin->all_bin_parse_num].header_ver =
GET_32_DATA(*(bin->p_addr + 7), *(bin->p_addr + 6),
*(bin->p_addr + 5), *(bin->p_addr + 4));
bin->header_info[bin->all_bin_parse_num].bin_data_type =
GET_32_DATA(*(bin->p_addr + 11), *(bin->p_addr + 10),
*(bin->p_addr + 9), *(bin->p_addr + 8));
bin->header_info[bin->all_bin_parse_num].bin_data_ver =
GET_32_DATA(*(bin->p_addr + 15), *(bin->p_addr + 14),
*(bin->p_addr + 13), *(bin->p_addr + 12));
bin->header_info[bin->all_bin_parse_num].bin_data_len =
GET_32_DATA(*(bin->p_addr + 19), *(bin->p_addr + 18),
*(bin->p_addr + 17), *(bin->p_addr + 16));
bin->header_info[bin->all_bin_parse_num].ui_ver =
GET_32_DATA(*(bin->p_addr + 23), *(bin->p_addr + 22),
*(bin->p_addr + 21), *(bin->p_addr + 20));
bin->header_info[bin->all_bin_parse_num].reg_byte_len =
GET_32_DATA(*(bin->p_addr + 35), *(bin->p_addr + 34),
*(bin->p_addr + 33), *(bin->p_addr + 32));
bin->header_info[bin->all_bin_parse_num].data_byte_len =
GET_32_DATA(*(bin->p_addr + 39), *(bin->p_addr + 38),
*(bin->p_addr + 37), *(bin->p_addr + 36));
bin->header_info[bin->all_bin_parse_num].device_addr =
GET_32_DATA(*(bin->p_addr + 43), *(bin->p_addr + 42),
*(bin->p_addr + 41), *(bin->p_addr + 40));
for (i = 0; i < 8; i++) {
bin->header_info[bin->all_bin_parse_num].chip_type[i] =
*(bin->p_addr + 24 + i);
}
bin->header_info[bin->all_bin_parse_num].reg_num = 0x00000000;
bin->header_info[bin->all_bin_parse_num].reg_data_byte_len = 0x00000000;
bin->header_info[bin->all_bin_parse_num].download_addr = 0x00000000;
bin->header_info[bin->all_bin_parse_num].app_version = 0x00000000;
bin->header_info[bin->all_bin_parse_num].valid_data_len = 0x00000000;
bin->all_bin_parse_num += 1;
}
int aw_parse_each_of_multi_bins_1_0_0(unsigned int bin_num, int bin_serial_num,
struct aw_bin *bin)
{
int ret = 0;
unsigned int bin_start_addr = 0;
unsigned int valid_data_len = 0;
DBG("aw_bin_parse enter multi bin branch -- %s\n", __func__);
if (!bin_serial_num) {
bin_start_addr = GET_32_DATA(*(bin->p_addr + 67),
*(bin->p_addr + 66),
*(bin->p_addr + 65),
*(bin->p_addr + 64));
bin->p_addr += (60 + bin_start_addr);
bin->header_info[bin->all_bin_parse_num].valid_data_addr =
bin->header_info[bin->all_bin_parse_num -
1].valid_data_addr + 4 + 8 * bin_num + 60;
} else {
valid_data_len =
bin->header_info[bin->all_bin_parse_num - 1].bin_data_len;
bin->p_addr += (60 + valid_data_len);
bin->header_info[bin->all_bin_parse_num].valid_data_addr =
bin->header_info[bin->all_bin_parse_num -
1].valid_data_addr +
bin->header_info[bin->all_bin_parse_num - 1].bin_data_len +
60;
}
ret = aw_parse_bin_header_1_0_0(bin);
return ret;
}
/* Get the number of bins in multi bins, and set a for loop, loop processing each bin data */
int aw_get_multi_bin_header_1_0_0(struct aw_bin *bin)
{
int i = 0;
int ret = 0;
unsigned int bin_num = 0;
DBG("aw_bin_parse enter multi bin branch -- %s\n", __func__);
bin_num = GET_32_DATA(*(bin->p_addr + 63),
*(bin->p_addr + 62),
*(bin->p_addr + 61), *(bin->p_addr + 60));
if (bin->multi_bin_parse_num == 1) {
bin->header_info[bin->all_bin_parse_num].valid_data_addr = 60;
}
aw_get_single_bin_header_1_0_0(bin);
for (i = 0; i < bin_num; i++) {
DBG("aw_bin_parse enter multi bin for is %d\n", i);
ret = aw_parse_each_of_multi_bins_1_0_0(bin_num, i, bin);
if (ret < 0) {
return ret;
}
}
return 0;
}
/********************************************************
*
* If the bin framework header version is 1.0.0,
determine the data type of bin, and then perform different processing
according to the data type
If it is a single bin data type, write the data directly into the structure array
If it is a multi-bin data type, first obtain the number of bins,
and then recursively call the bin frame header processing function
according to the bin number to process the frame header information of each bin separately
*
********************************************************/
int aw_parse_bin_header_1_0_0(struct aw_bin *bin)
{
int ret = 0;
unsigned int bin_data_type;
DBG("enter %s\n", __func__);
bin_data_type = GET_32_DATA(*(bin->p_addr + 11),
*(bin->p_addr + 10),
*(bin->p_addr + 9), *(bin->p_addr + 8));
DBG("aw_bin_parse bin_data_type 0x%x\n", bin_data_type);
switch (bin_data_type) {
case DATA_TYPE_REGISTER:
case DATA_TYPE_DSP_REG:
case DATA_TYPE_SOC_APP:
/* Divided into two processing methods,
one is single bin processing,
and the other is single bin processing in multi bin */
DBG("aw_bin_parse enter single bin branch\n");
bin->single_bin_parse_num += 1;
DBG("%s bin->single_bin_parse_num is %d\n", __func__,
bin->single_bin_parse_num);
if (!bin->multi_bin_parse_num) {
bin->header_info[bin->
all_bin_parse_num].valid_data_addr =
60;
}
aw_get_single_bin_header_1_0_0(bin);
break;
case DATA_TYPE_MULTI_BINS:
/* Get the number of times to enter multi bins */
DBG("aw_bin_parse enter multi bin branch\n");
bin->multi_bin_parse_num += 1;
DBG("%s bin->multi_bin_parse_num is %d\n", __func__,
bin->multi_bin_parse_num);
ret = aw_get_multi_bin_header_1_0_0(bin);
if (ret < 0) {
return ret;
}
break;
default:
DBG_ERR("aw_bin_parse Unrecognized this bin data type\n");
return -2;
}
return 0;
}
/* get the bin's header version */
static int aw_check_bin_header_version(struct aw_bin *bin)
{
int ret = 0;
unsigned int header_version = 0;
header_version = GET_32_DATA(*(bin->p_addr + 7),
*(bin->p_addr + 6),
*(bin->p_addr + 5), *(bin->p_addr + 4));
DBG("aw_bin_parse header_version 0x%x\n", header_version);
/* Write data to the corresponding structure array
according to different formats of the bin frame header version */
switch (header_version) {
case HEADER_VERSION_1_0_0:
ret = aw_parse_bin_header_1_0_0(bin);
return ret;
default:
DBG_ERR("aw_bin_parse Unrecognized this bin header version \n");
return -1;
}
}
int aw_parsing_bin_file(struct aw_bin *bin)
{
int i = 0;
int ret = 0;
DBG("aw_bin_parse code version:%s\n", AWINIC_CODE_VERSION);
if (!bin) {
DBG_ERR("aw_bin_parse bin is NULL\n");
return -8;
}
bin->p_addr = bin->info.data;
bin->all_bin_parse_num = 0;
bin->multi_bin_parse_num = 0;
bin->single_bin_parse_num = 0;
/* filling bins header info */
ret = aw_check_bin_header_version(bin);
if (ret < 0) {
DBG_ERR("aw_bin_parse check bin header version error\n");
return ret;
}
bin->p_addr = NULL;
/* check bin header info */
for (i = 0; i < bin->all_bin_parse_num; i++) {
/* check sum */
ret = aw_check_sum(bin, i);
if (ret < 0) {
DBG_ERR("aw_bin_parse check sum data error\n");
return ret;
}
/* check bin data version */
ret = aw_check_data_version(bin, i);
if (ret < 0) {
DBG_ERR("aw_bin_parse check data version error\n");
return ret;
}
/* check valid data */
if (bin->header_info[i].bin_data_ver == DATA_VERSION_V1) {
/* check register num */
if (bin->header_info[i].bin_data_type ==
DATA_TYPE_REGISTER) {
ret = aw_check_register_num_v1(bin, i);
if (ret < 0) {
DBG_ERR
("aw_bin_parse check register num error\n");
return ret;
}
/* check dsp reg num */
} else if (bin->header_info[i].bin_data_type ==
DATA_TYPE_DSP_REG) {
ret = aw_check_dsp_reg_num_v1(bin, i);
if (ret < 0) {
DBG_ERR
("aw_bin_parse check dsp reg num error\n");
return ret;
}
/* check soc app num */
} else if (bin->header_info[i].bin_data_type ==
DATA_TYPE_SOC_APP) {
ret = aw_check_soc_app_num_v1(bin, i);
if (ret < 0) {
DBG_ERR
("aw_bin_parse check soc app num error\n");
return ret;
}
} else {
bin->header_info[i].valid_data_len =
bin->header_info[i].bin_data_len;
}
}
}
DBG("aw_bin_parse parsing success\n");
return 0;
}

View file

@ -0,0 +1,73 @@
#ifndef __AW_BIN_PARSE_H__
#define __AW_BIN_PARSE_H__
#define NULL ((void *)0)
#define GET_32_DATA(w, x, y, z) ((unsigned int)((((uint32_t)w) << 24) | (((uint32_t)x) << 16) | (((uint32_t)y) << 8) | ((uint32_t)z)))
#define BIN_NUM_MAX 100
#define HEADER_LEN 60
/*********************************************************
*
* header information
*
********************************************************/
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_MULTI_BINS = 0x00002000,
};
enum data_version_enum {
DATA_VERSION_V1 = 0X00000001, /*default little edian */
DATA_VERSION_MAX,
};
struct bin_header_info {
unsigned int header_len; /* Frame header length */
unsigned int check_sum; /* Frame header information-Checksum */
unsigned int header_ver; /* Frame header information-Frame header version */
unsigned int bin_data_type; /* Frame header information-Data type */
unsigned int bin_data_ver; /* Frame header information-Data version */
unsigned int bin_data_len; /* Frame header information-Data length */
unsigned int ui_ver; /* Frame header information-ui version */
unsigned char chip_type[8]; /* Frame header information-chip type */
unsigned int reg_byte_len; /* Frame header information-reg byte len */
unsigned int data_byte_len; /* Frame header information-data byte len */
unsigned int device_addr; /* Frame header information-device addr */
unsigned int valid_data_len; /* Length of valid data obtained after parsing */
unsigned int valid_data_addr; /* The offset address of the valid data obtained after parsing relative to info */
unsigned int reg_num; /* The number of registers obtained after parsing */
unsigned int reg_data_byte_len; /* The byte length of the register obtained after parsing */
unsigned int download_addr; /* The starting address or download address obtained after parsing */
unsigned int app_version; /* The software version number obtained after parsing */
};
/************************************************************
*
* function define
*
************************************************************/
struct bin_container {
unsigned int len; /* The size of the bin file obtained from the firmware */
unsigned char data[]; /* Store the bin file obtained from the firmware */
};
struct aw_bin {
unsigned char *p_addr; /* Offset pointer (backward offset pointer to obtain frame header information and important information) */
unsigned int all_bin_parse_num; /* The number of all bin files */
unsigned int multi_bin_parse_num; /* The number of single bin files */
unsigned int single_bin_parse_num; /* The number of multiple bin files */
struct bin_header_info header_info[BIN_NUM_MAX]; /* Frame header information and other important data obtained after parsing */
struct bin_container info; /* Obtained bin file data that needs to be parsed */
};
int aw_parsing_bin_file(struct aw_bin *bin);
int aw_parse_bin_header_1_0_0(struct aw_bin *bin);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,142 @@
#ifndef __AWINIC_CALIBRATION_H__
#define __AWINIC_CALIBRATION_H__
#define AW_CALI_STORE_EXAMPLE
#define AW_CALI_READ_TIMES (3)
#define AW_ERRO_CALI_VALUE (0)
#define AW_CALI_RE_DEFAULT_TIMER (3000)
#define AW_CALI_RE_MAX (15000)
#define AW_CALI_RE_MIN (4000)
#define AW_CALI_CFG_NUM (3)
#define AW_CALI_DATA_NUM (6)
#define AW_PARAMS_NUM (600)
#define AW_KILO_PARAMS_NUM (1000)
#define AW_CALI_RE_DEFAULT_MAX (50000)
#define AW_CALI_RE_DEFAULT_MIN (1000)
struct aw_device;
enum afe_module_type {
AW_RX_MODULE = 0,
AW_TX_MODULE = 1,
};
struct cali_cfg {
int32_t data[AW_CALI_CFG_NUM];
};
struct cali_data {
int32_t data[AW_CALI_DATA_NUM];
};
struct params_data {
int32_t data[AW_PARAMS_NUM];
};
struct ptr_params_data {
int len;
int32_t *data;
};
struct f0_q_data {
int32_t data[4];
};
enum {
AW_IOCTL_MSG_IOCTL = 0,
AW_IOCTL_MSG_RD_DSP,
AW_IOCTL_MSG_WR_DSP
};
#define AW_IOCTL_MSG_VERSION (0)
typedef struct {
int32_t type;
int32_t opcode_id;
int32_t version;
int32_t data_len;
char *data_buf;
int32_t reseriver[2];
} aw_ioctl_msg_t;
#define AW_IOCTL_MAGIC 'a'
#define AW_IOCTL_SET_CALI_CFG _IOWR(AW_IOCTL_MAGIC, 1, struct cali_cfg)
#define AW_IOCTL_GET_CALI_CFG _IOWR(AW_IOCTL_MAGIC, 2, struct cali_cfg)
#define AW_IOCTL_GET_CALI_DATA _IOWR(AW_IOCTL_MAGIC, 3, struct cali_data)
#define AW_IOCTL_SET_NOISE _IOWR(AW_IOCTL_MAGIC, 4, int32_t)
#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_CALI_RE _IOWR(AW_IOCTL_MAGIC, 7, int32_t)
#define AW_IOCTL_SET_VMAX _IOWR(AW_IOCTL_MAGIC, 8, int32_t)
#define AW_IOCTL_GET_VMAX _IOWR(AW_IOCTL_MAGIC, 9, int32_t)
#define AW_IOCTL_SET_PARAM _IOWR(AW_IOCTL_MAGIC, 10, struct params_data)
#define AW_IOCTL_ENABLE_CALI _IOWR(AW_IOCTL_MAGIC, 11, int8_t)
#define AW_IOCTL_SET_PTR_PARAM_NUM _IOWR(AW_IOCTL_MAGIC, 12, struct ptr_params_data)
#define AW_IOCTL_GET_F0_Q _IOWR(AW_IOCTL_MAGIC, 13, struct f0_q_data)
#define AW_IOCTL_SET_DSP_HMUTE _IOWR(AW_IOCTL_MAGIC, 14, int32_t)
#define AW_IOCTL_SET_CALI_CFG_FLAG _IOWR(AW_IOCTL_MAGIC, 15, int32_t)
#define AW_IOCTL_MSG _IOWR(AW_IOCTL_MAGIC, 16, aw_ioctl_msg_t)
enum{
AW_CALI_MODE_NONE = 0,
AW_CALI_MODE_ATTR,
AW_CALI_MODE_CLASS,
AW_CALI_MODE_MISC,
AW_CALI_MODE_ALL,
AW_CALI_MODE_MAX,
};
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_OPS_HMUTE = 0X0001,
CALI_OPS_NOISE = 0X0002,
};
enum {
CALI_TYPE_RE = 0,
CALI_TYPE_F0,
};
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_SHOW_ST,
CALI_STR_DEV_SEL, /*switch device*/
CALI_STR_VER,
CALI_STR_DEV_NUM,
CALI_STR_MAX,
};
struct aw_cali_desc {
unsigned char status;
unsigned char mode; /*0:NONE 1:ATTR 2:CLASS 3:MISC */
int32_t cali_re; /*set cali_re*/
int32_t cali_f0; /*store cali_f0*/
int32_t cali_q; /*store cali q*/
};
int aw_cali_init(struct aw_cali_desc *cali_desc);
void aw_cali_deinit(struct aw_cali_desc *cali_desc);
int aw_cali_svc_get_cali_status(void);
int aw_cali_read_re_from_nvram(int32_t *cali_re, int32_t ch_index);
#endif

View file

@ -0,0 +1,151 @@
#ifndef __AWINIC_DATA_TYPE_H__
#define __AWINIC_DATA_TYPE_H__
#define AW_NAME_BUF_MAX (50)
struct aw_msg_hdr {
int32_t type;
int32_t opcode_id;
int32_t version;
int32_t reseriver[3];
};
/******************************************************************
* 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)
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_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_PROFILE_DATA_TYPE_REG = 0,
AW_PROFILE_DATA_TYPE_DSP,
AW_PROFILE_DATA_TYPE_MAX,
};
enum algo_profile_data_type {
AW_PROFILE_DATA_TYPE_ALGO_DSP,
AW_PROFILE_DATA_TYPE_ALGO_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;
struct aw_sec_data_desc sec_desc[AW_PROFILE_DATA_TYPE_MAX];
};
struct aw_all_prof_info {
struct aw_prof_desc prof_desc[AW_PROFILE_MAX];
};
struct aw_prof_info {
int count;
char **prof_name_list;
struct aw_prof_desc *prof_desc;
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,328 @@
#ifndef __AWINIC_DEVICE_FILE_H__
#define __AWINIC_DEVICE_FILE_H__
#include "aw_data_type.h"
#include "aw_calib.h"
#include "aw_monitor.h"
#define AW_VOLUME_STEP_DB (6 * 2)
#define AW_REG_NONE (0xFF)
#define AW_NAME_MAX (50)
#define ALGO_VERSION_MAX (80)
#define AW_ALGO_PATH_MAX (256)
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,
};
struct aw_device;
enum {
AW_DEV_TYPE_OK = 0,
AW_DEV_TYPE_NONE = 1,
};
enum {
AW_EF_AND_CHECK = 0,
AW_EF_OR_CHECK,
};
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_CH_MAX,
};
enum AW_DEV_INIT {
AW_DEV_INIT_ST = 0,
AW_DEV_INIT_OK = 1,
AW_DEV_INIT_NG = 2,
};
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_CH_GROUP_PRI = 0,
AW_DEV_CH_GROUP_SEC = 1,
AW_DEV_CH_GROUP_MAX,
};
struct aw_device_ops {
int (*aw_i2c_write)(struct aw_device *aw_dev, unsigned char reg_addr, unsigned int reg_data);
int (*aw_i2c_read)(struct aw_device *aw_dev, unsigned char reg_addr, unsigned int *reg_data);
int (*aw_i2c_write_bits)(struct aw_device *aw_dev, unsigned char reg_addr, unsigned int mask, unsigned int reg_data);
int (*aw_set_volume)(struct aw_device *aw_dev, unsigned int value);
int (*aw_get_volume)(struct aw_device *aw_dev, unsigned int *value);
unsigned int (*aw_reg_val_to_db)(unsigned int value);
void (*aw_i2s_enable)(struct aw_device *aw_dev, bool flag);
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_get_dev_num)(void);
void (*aw_set_algo)(struct aw_device *aw_dev);
unsigned int (*aw_get_irq_type)(struct aw_device *aw_dev, unsigned int value);
void (*aw_reg_force_set)(struct aw_device *aw_dev);
int (*aw_frcset_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*/
};
struct aw_soft_rst {
int reg;
int reg_value;
};
struct aw_pwd_desc {
unsigned int reg;
unsigned int mask;
unsigned int enable;
unsigned int disable;
};
struct aw_amppd_desc {
unsigned int reg;
unsigned int mask;
unsigned int enable;
unsigned int disable;
};
struct aw_bop_desc {
unsigned int reg;
unsigned int mask;
unsigned int enable;
unsigned int disbale;
};
struct aw_vcalb_desc {
unsigned int icalk_reg;
unsigned int icalk_reg_mask;
unsigned int icalk_shift;
unsigned int icalkl_reg;
unsigned int icalkl_reg_mask;
unsigned int icalkl_shift;
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_shift;
unsigned int vcalkl_reg;
unsigned int vcalkl_reg_mask;
unsigned int vcalkl_shift;
unsigned int vcalk_sign_mask;
unsigned int vcalk_neg_mask;
int vcalk_value_factor;
unsigned int vcalb_reg;
int cabl_base_value;
int vcal_factor;
};
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 mask;
unsigned int st_check;
unsigned int pll_check;
};
struct aw_profctrl_desc {
unsigned int reg;
unsigned int mask;
unsigned int spk_mode;
unsigned int cfg_prof_mode;
};
struct aw_bstctrl_desc {
unsigned int reg;
unsigned int mask;
unsigned int frc_bst;
unsigned int tsp_type;
unsigned int cfg_bst_type;
};
struct aw_cco_mux_desc {
unsigned int reg;
unsigned int mask;
unsigned int divided_val;
unsigned int bypass_val;
};
struct aw_volume_desc {
unsigned int reg;
unsigned int mask;
unsigned int shift;
int init_volume;
int mute_volume;
};
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_container {
int len;
uint8_t data[];
};
struct aw_efcheck_desc {
unsigned int reg;
unsigned int mask;
unsigned int and_val;
unsigned int or_val;
};
struct aw_device {
int index;
int status;
int bstcfg_enable;
int frcset_en;
int bop_en;
int efuse_check;
unsigned int mute_st;
unsigned int amppd_st;
unsigned char cur_prof; /*current profile index*/
unsigned char set_prof; /*set profile index*/
unsigned int channel; /*pa channel select*/
unsigned int vol_step;
unsigned int re_max;
unsigned int re_min;
int cur_gain;
struct device *dev;
struct i2c_client *i2c;
char acf_name[AW_NAME_MAX];
char monitor_name[AW_NAME_MAX];
void *private_data;
char algo_path[AW_ALGO_PATH_MAX];
int pre_prof_id;
struct aw_int_desc int_desc;
struct aw_pwd_desc pwd_desc;
struct aw_amppd_desc amppd_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_bstctrl_desc bstctrl_desc;
struct aw_cco_mux_desc cco_mux_desc;
struct aw_voltage_desc voltage_desc;
struct aw_temperature_desc temp_desc;
struct aw_ipeak_desc ipeak_desc;
struct aw_volume_desc volume_desc;
struct aw_prof_info prof_info;
struct aw_prof_info skt_prof_info;
struct aw_cali_desc cali_desc;
struct aw_monitor_desc monitor_desc;
struct aw_soft_rst soft_rst;
struct aw_bop_desc bop_desc;
struct aw_efcheck_desc efcheck_desc;
struct aw_device_ops ops;
struct list_head list_node;
};
struct aw_sec_data_desc *aw_dev_get_algo_prof_data(struct aw_device *aw_dev, int prof_id);
int aw_dev_load_acf_check(struct aw_container *aw_cfg);
void aw_dev_deinit(struct aw_device *aw_dev);
int aw_device_init(struct aw_device *aw_dev, struct aw_container *aw_cfg);
int aw_dev_parse_skt_bin(struct aw_device *aw_dev, struct aw_container *aw_cfg);
int aw_device_start(struct aw_device *aw_dev);
int aw_device_stop(struct aw_device *aw_dev);
int aw_dev_reg_update(struct aw_device *aw_dev, bool force);
int aw_device_irq_reinit(struct aw_device *aw_dev);
/*profile*/
int aw_dev_prof_update(struct aw_device *aw_dev, bool force);
int aw_dev_get_profile_count(struct aw_device *aw_dev);
int aw_dev_get_profile_name(struct aw_device *aw_dev, char *name, int index);
int aw_dev_check_profile_index(struct aw_device *aw_dev, int index);
int aw_dev_get_profile_index(struct aw_device *aw_dev);
int aw_dev_set_profile_index(struct aw_device *aw_dev, int index);
/*re*/
int aw_dev_get_cali_re(struct aw_device *aw_dev, int32_t *cali_re);
int aw_dev_init_cali_re(struct aw_device *aw_dev);
int aw_dev_dc_status(struct aw_device *aw_dev);
/*interrupt*/
int aw_dev_status(struct aw_device *aw_dev);
int aw_dev_get_int_status(struct aw_device *aw_dev, uint16_t *int_status);
void aw_dev_clear_int_status(struct aw_device *aw_dev);
int aw_dev_set_intmask(struct aw_device *aw_dev, bool flag);
/*fade int / out*/
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);
/*dsp kcontrol*/
int aw_dev_set_afe_module_en(int type, int enable);
int aw_dev_get_afe_module_en(int type, int *status);
int aw_dev_set_copp_module_en(bool enable);
int aw_dev_set_spin(int spin_mode);
int aw_dev_get_spin(int *spin_mode);
int aw_dev_skt_prof_mode(struct aw_device *aw_dev, int prof_id);
int aw_dev_set_algo_prof_data(struct aw_device *aw_dev, void *prof_data, unsigned int prof_len);
int aw_dev_set_algo_prof(struct aw_device *aw_dev, int prof_id);
int aw_dev_get_algo_prof(struct aw_device *aw_dev, int *prof_id);
#ifdef CONFIG_AW882XX_ALGO_BIN_PARAMS
int aw_dev_set_algo_params_path(struct aw_device *aw_dev);
#endif
int aw_device_probe(struct aw_device *aw_dev);
int aw_device_remove(struct aw_device *aw_dev);
int aw_dev_get_list_head(struct list_head **head);
#ifdef AW_SPIN_ENABLE
int aw_dev_set_spin_param(struct aw_device *aw_dev, uint32_t enable, uint32_t relase_time);
int aw_dev_get_spin_param(struct aw_device *aw_dev, uint32_t* enable, uint32_t* relase_time);
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,79 @@
#ifndef __AWINIC_DSP_H__
#define __AWINIC_DSP_H__
#define AW_QCOM_PLATFORM
/*factor form 12bit(4096) to 1000*/
#define AW_DSP_RE_TO_SHOW_RE(re) (((re) * (1000)) >> (12))
#define AW_SHOW_RE_TO_DSP_RE(re) (((re) << 12) / (1000))
#define AW_DSP_TRY_TIME (3)
#define AW_DSP_SLEEP_TIME (10)
#define AW_TX_DEFAULT_TOPO_ID (0x1000FF00)
#define AW_RX_DEFAULT_TOPO_ID (0x1000FF01)
#define AW_TX_DEFAULT_PORT_ID (0x1007)
#define AW_RX_DEFAULT_PORT_ID (0x1006)
enum aw_dsp_msg_type {
AW_DSP_MSG_TYPE_DATA = 0,
AW_DSP_MSG_TYPE_CMD = 1,
};
enum {
AW_SPIN_0 = 0,
AW_SPIN_90,
AW_SPIN_180,
AW_SPIN_270,
AW_SPIN_MAX,
};
#define AW_DSP_MSG_HDR_VER (1)
typedef struct aw_msg_hdr aw_dsp_msg_t;
#ifdef AW_SPIN_ENABLE
struct aw_spin_param {
uint32_t enable;
uint32_t relase_time;
};
#endif
int aw_dsp_write_msg(struct aw_device *aw_dev, uint32_t msg_id, char *data_ptr, unsigned int data_size);
int aw_dsp_read_msg(struct aw_device *aw_dev, uint32_t msg_id, char *data_ptr, unsigned int data_size);
int aw_dsp_write_cali_cfg(struct aw_device *aw_dev, char *data, unsigned int data_len);
int aw_dsp_read_cali_cfg(struct aw_device *aw_dev, char *data, unsigned int data_len);
int aw_dsp_noise_en(struct aw_device *aw_dev, bool is_noise);
int aw_dsp_write_vmax(struct aw_device *aw_dev, char *data, unsigned int data_len);
int aw_dsp_read_vmax(struct aw_device *aw_dev, char *data, unsigned int data_len);
int aw_dsp_write_params(struct aw_device *aw_dev, char *data, unsigned int data_len);
int aw_dsp_write_cali_re(struct aw_device *aw_dev, int32_t cali_re);
int aw_dsp_read_cali_re(struct aw_device *aw_dev, int32_t *cali_re);
int aw_dsp_read_r0(struct aw_device *aw_dev, int32_t *r0);
int aw_dsp_read_st(struct aw_device *aw_dev, int32_t *r0, int32_t *te);
int aw_dsp_read_te(struct aw_device *aw_dev, int32_t *te);
int aw_dsp_get_dc_status(struct aw_device *aw_dev);
int aw_dsp_hmute_en(struct aw_device *aw_dev, bool is_hmute);
int aw_dsp_cali_en(struct aw_device *aw_dev, bool is_enable);
int aw_dsp_read_f0(struct aw_device *aw_dev, int32_t *f0);
int aw_dsp_read_f0_q(struct aw_device *aw_dev, int32_t *f0, int32_t *q);
int aw_dsp_read_cali_data(struct aw_device *aw_dev, char *data, unsigned int data_len);
int aw_dsp_set_afe_module_en(int type, int enable);
int aw_dsp_get_afe_module_en(int type, int *status);
int aw_dsp_set_copp_module_en(bool enable);
int aw_dsp_write_spin(int spin_mode);
int aw_dsp_read_spin(int *spin_mode);
int aw_get_algo_version(struct aw_device *aw_dev, char *algo_ver_buf);
int aw_dsp_set_algo_prof_data(struct aw_device *aw_dev, void *data, unsigned int size);
int aw_dsp_set_algo_prof(struct aw_device *aw_dev, int prof_id);
int aw_dsp_get_algo_prof(struct aw_device *aw_dev, int *prof_id);
int aw_dsp_set_algo_params_path(struct aw_device *aw_dev);
void aw_device_parse_topo_id_dt(struct aw_device *aw_dev);
void aw_device_parse_port_id_dt(struct aw_device *aw_dev);
#ifdef AW_SPIN_ENABLE
int aw_dsp_set_spin_param(struct aw_device *aw_dev,
uint32_t enable, uint32_t relase_time);
int aw_dsp_get_spin_param(struct aw_device *aw_dev,
uint32_t *enable, uint32_t *relase_time);
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,34 @@
#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)
#define aw_dev_info(dev, format, ...) \
do { \
pr_info("[Awinic][%s]%s: " format "\n", dev_name(dev), __func__, ##__VA_ARGS__); \
} while (0)
#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)
#define aw_pr_info(format, ...) \
do { \
pr_info("[Awinic]%s: " format "\n", __func__, ##__VA_ARGS__); \
} while (0)
#define aw_pr_dbg(format, ...) \
do { \
pr_debug("[Awinic]%s: " format "\n", __func__, ##__VA_ARGS__); \
} while (0)
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,173 @@
#ifndef __AW_MONITOR_H__
#define __AW_MONITOR_H__
/*#define AW_DEBUG*/
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_0 = 0x00010000,
AW_MONITOR_HDR_VER_0_1_1 = 0x00010100,
};
enum aw_monitor_init {
AW_MON_CFG_ST = 0,
AW_MON_CFG_OK = 1,
};
struct aw_monitor_hdr {
uint32_t check_sum;
uint32_t monitor_ver;
char chip_type[8];
uint32_t ui_ver;
uint32_t monitor_switch;
uint32_t monitor_time;
uint32_t monitor_count;
uint32_t ipeak_switch;
uint32_t gain_switch;
uint32_t vmax_switch;
uint32_t temp_switch;
uint32_t temp_aplha;
uint32_t temp_num;
uint32_t single_temp_size;
uint32_t temp_offset;
uint32_t vol_switch;
uint32_t vol_aplha;
uint32_t vol_num;
uint32_t single_vol_size;
uint32_t vol_offset;
};
#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,
};
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 aw_monitor_cfg monitor_cfg;
uint8_t first_entry;
uint8_t samp_count;
uint8_t db_offset;
uint32_t pre_vmax;
struct aw_monitor_trace temp_trace;
struct aw_monitor_trace vol_trace;
#ifdef AW_DEBUG
uint16_t test_vol;
int16_t test_temp;
#endif
};
/******************************************************************
* aw882xx monitor functions
*******************************************************************/
void aw_monitor_start(struct aw_monitor_desc *monitor_desc);
int aw_monitor_stop(struct aw_monitor_desc *monitor_desc);
void aw_monitor_init(struct aw_monitor_desc *monitor_desc);
void aw_monitor_deinit(struct aw_monitor_desc *monitor_desc);
int aw_monitor_parse_fw(struct aw_monitor_desc *monitor_desc,
uint8_t *data, uint32_t data_len);
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,42 @@
# Android makefile for audio kernel modules
# Assume no targets will be supported
AUDIO_CHIPSET := audio
# Build/Package only in case of supported target
ifeq ($(call is-board-platform-in-list,msm8953 msm8937 sdm710 qcs605),true)
LOCAL_PATH := $(call my-dir)
# This makefile is only for DLKM
ifneq ($(findstring vendor,$(LOCAL_PATH)),)
ifneq ($(findstring opensource,$(LOCAL_PATH)),)
AUDIO_BLD_DIR := $(ANDROID_BUILD_TOP)/vendor/qcom/opensource/audio-kernel
endif # opensource
DLKM_DIR := $(TOP)/device/qcom/common/dlkm
# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko
###########################################################
# This is set once per LOCAL_PATH, not per (kernel) module
KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR)
# We are actually building audio.ko here, as per the
# requirement we are specifying <chipset>_audio.ko as LOCAL_MODULE.
# This means we need to rename the module to <chipset>_audio.ko
# after audio.ko is built.
KBUILD_OPTIONS += MODNAME=audio_aw8838
KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM)
KBUILD_OPTIONS += $(AUDIO_SELECT)
###########################################################
include $(CLEAR_VARS)
LOCAL_MODULE := $(AUDIO_SELECT)aw8838.ko
LOCAL_MODULE_KBUILD_NAME := audio_aw8838.ko
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_DEBUG_ENABLE := true
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
include $(DLKM_DIR)/AndroidKernelModule.mk
###########################################################
endif # DLKM check
endif # supported target check

View file

@ -0,0 +1,125 @@
#ld either as part of a standalone Kernel build or as
# an external module. Determine which mechanism is being used
# add -Wall to try to catch everything we can.
EXTRA_CFLAGS += -Wall
EXTRA_CFLAGS += -I$(TOP)/vendor/qcom/opensource/audio-kernel/include
EXTRA_CFLAGS += -I$(TOP)/vendor/qcom/opensource/audio-kernel/include/uapi/
ifeq ($(MODNAME),)
KERNEL_BUILD := 1
else
KERNEL_BUILD := 0
endif
ifeq ($(KERNEL_BUILD), 1)
# These are configurable via Kconfig for kernel-based builds
# Need to explicitly configure for Android-based builds
AUDIO_BLD_DIR := $(ANDROID_BUILD_TOP)/kernel/msm-5.4
AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio
endif
ifeq ($(KERNEL_BUILD), 0)
ifeq ($(CONFIG_ARCH_SM6150), y)
include $(AUDIO_ROOT)/config/sm6150auto.conf
export
INCS += -include $(AUDIO_ROOT)/config/sm6150autoconf.h
endif
ifeq ($(CONFIG_ARCH_TRINKET), y)
include $(AUDIO_ROOT)/config/sm6150auto.conf
export
INCS += -include $(AUDIO_ROOT)/config/sm6150autoconf.h
endif
ifeq ($(CONFIG_ARCH_BENGAL), y)
include $(AUDIO_ROOT)/config/bengalauto.conf
export
INCS += -include $(AUDIO_ROOT)/config/bengalautoconf.h
endif
ifeq ($(CONFIG_ARCH_LITO), y)
include $(AUDIO_ROOT)/config/litoauto.conf
export
INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h
endif
endif
# As per target team, build is done as follows:
# Defconfig : build with default flags
# Slub : defconfig + CONFIG_SLUB_DEBUG := y +
# CONFIG_SLUB_DEBUG_ON := y + CONFIG_PAGE_POISONING := y
# Perf : Using appropriate msmXXXX-perf_defconfig
#
# Shipment builds (user variants) should not have any debug feature
# enabled. This is identified using 'TARGET_BUILD_VARIANT'. Slub builds
# are identified using the CONFIG_SLUB_DEBUG_ON configuration. Since
# there is no other way to identify defconfig builds, QTI internal
# representation of perf builds (identified using the string 'perf'),
# is used to identify if the build is a slub or defconfig one. This
# way no critical debug feature will be enabled for perf and shipment
# builds. Other OEMs are also protected using the TARGET_BUILD_VARIANT
# config.
############ UAPI ############
UAPI_DIR := uapi
UAPI_INC := -I$(AUDIO_ROOT)/include/$(UAPI_DIR)
############ COMMON ############
COMMON_DIR := include
COMMON_INC := -I$(AUDIO_ROOT)/$(COMMON_DIR)
############ AW882XX ############
# for AW8838 Codec
# 添加 aw8838 相关驱动的所有.c 文件
ifdef CONFIG_SND_SOC_AW8838
AW8838_OBJS += aw8838.o
AW8838_OBJS += aw8838_monitor.o
endif
LINUX_INC += -Iinclude/linux
INCS += $(COMMON_INC) \
$(UAPI_INC)
EXTRA_CFLAGS += $(INCS)
CDEFINES += -DANI_LITTLE_BYTE_ENDIAN \
-DANI_LITTLE_BIT_ENDIAN \
-DDOT11F_LITTLE_ENDIAN_HOST \
-DANI_COMPILER_TYPE_GCC \
-DANI_OS_TYPE_ANDROID=6 \
-DPTT_SOCK_SVC_ENABLE \
-Wall\
-Werror\
-D__linux__
KBUILD_CPPFLAGS += $(CDEFINES)
# Currently, for versions of gcc which support it, the kernel Makefile
# is disabling the maybe-uninitialized warning. Re-enable it for the
# AUDIO driver. Note that we must use EXTRA_CFLAGS here so that it
# will override the kernel settings.
ifeq ($(call cc-option-yn, -Wmaybe-uninitialized),y)
EXTRA_CFLAGS += -Wmaybe-uninitialized
endif
#EXTRA_CFLAGS += -Wmissing-prototypes
ifeq ($(call cc-option-yn, -Wheader-guard),y)
EXTRA_CFLAGS += -Wheader-guard
endif
ifeq ($(KERNEL_BUILD), 0)
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/ipc/Module.symvers
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/dsp/Module.symvers
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/Module.symvers
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/Module.symvers
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/soc/Module.symvers
endif
# Module information used by KBuild framework
obj-m += audio_aw8838.o
audio_aw8838-y := $(AW8838_OBJS)
# inject some build related information
DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\"

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,107 @@
#ifndef _AW8838_H_
#define _AW8838_H_
#include "aw8838_monitor.h"
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 1)
#define AW_KERNEL_VER_OVER_4_19_1
#endif
/*
* i2c transaction on Linux limited to 64k
* (See Linux kernel documentation: Documentation/i2c/writing-clients)
*/
#define MAX_I2C_BUFFER_SIZE 65536
#define AW8838_FLAG_START_ON_MUTE (1 << 0)
#define AW8838_FLAG_SKIP_INTERRUPTS (1 << 1)
#define AW8838_FLAG_SAAM_AVAILABLE (1 << 2)
#define AW8838_FLAG_STEREO_DEVICE (1 << 3)
#define AW8838_FLAG_MULTI_MIC_INPUTS (1 << 4)
#define AW8838_NUM_RATES 9
#define AW8838_MAX_REGISTER 0xff
enum aw8838_chipid{
AW8838_ID,
};
enum aw8838_mode_spk_rcv{
AW8838_SPEAKER_MODE = 0,
AW8838_RECEIVER_MODE = 1,
};
/********************************************
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 *(*aw_snd_soc_kcontrol_codec)(struct snd_kcontrol *kcontrol);
void *(*aw_snd_soc_codec_get_drvdata)(aw_snd_soc_codec_t *codec);
int (*aw_snd_soc_add_codec_controls)(aw_snd_soc_codec_t *codec,
const struct snd_kcontrol_new *controls, unsigned int num_controls);
void (*aw_snd_soc_unregister_codec)(struct device *dev);
int (*aw_snd_soc_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 aw8838 {
struct regmap *regmap;
struct i2c_client *i2c;
aw_snd_soc_codec_t *codec;
struct device *dev;
struct mutex cfg_lock;
#ifdef AW8838_VBAT_MONITOR
struct hrtimer vbat_monitor_timer;
struct work_struct vbat_monitor_work;
#endif
int sysclk;
int rate;
int pstream;
int cstream;
int reset_gpio;
int irq_gpio;
#ifdef CONFIG_DEBUG_FS
struct dentry *dbg_dir;
#endif
u8 reg;
unsigned int flags;
unsigned int chipid;
unsigned int init;
unsigned int spk_rcv_mode;
struct aw8838_monitor monitor;
uint32_t db_offset;
unsigned int cpmd_default;
};
struct aw8838_container{
int len;
unsigned char data[];
};
int aw8838_i2c_read(struct aw8838 *aw8838,
unsigned char reg_addr, unsigned int *reg_data);
int aw8838_i2c_write(struct aw8838 *aw8838,
unsigned char reg_addr, unsigned int reg_data);
int aw8838_get_volume(struct aw8838 *aw8838, uint32_t *value);
int aw8838_set_volume(struct aw8838 *aw8838, uint32_t value);
uint32_t aw8838_reg_val_to_db(uint32_t value);
int aw8838_get_hmute(struct aw8838 *aw8838);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,201 @@
#ifndef __AWINIC_MONITOR_H__
#define __AWINIC_MONITOR_H__
/*#define AW_DEBUG*/
/*#define AW_TEMP_EN*/
/*#define AW_QCOM_PLATFORM*/
#define AFE_PORT_ID_AWDSP_RX (0x1006) /*AFE_PORT_ID_QUATERNARY_MI2S_RX*/
#define AW_RX_TOPO_ID (0x1000FF01) /*RX topology id*/
#define AW_DSP_SLEEP_TIME (10)
#define AW_DSP_TRY_TIME (3)
struct aw_table;
#define AW_TABLE_SIZE sizeof(struct aw_table)
#define AFE_PARAM_ID_AWDSP_RX_VMAX_L (0X10013D17)
#define AFE_PARAM_ID_AWDSP_RX_VMAX_R (0X10013D18)
#define IPEAK_NONE (0xFF)
#define GAIN_NONE (0xFF)
#define VMAX_NONE (0xFFFFFFFF)
#define GET_DB_INT(x) (x / 2)
#define GET_DB_DECIMAL(x) ((x % 2) * 5)
#define AW_LOAD_MON_FW_DELAY_TIME (3000)
#define AW8838_MONITOR_DEFAULT_FLAG (0)
#define 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 GET_16_DATA(x, y) \
((uint16_t)((((uint8_t)x) << 8) | (uint8_t)y))
#define MONITOR_EN_MASK 0x01
enum {
AW_CHAN_LEFT = 0,
AW_CHAN_RIGHT = 1,
};
enum {
AW_MON_LOGIC_OR = 0,
AW_MON_LOGIC_AND = 1,
};
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_monitor_hdr_ver {
AW_MONITOR_HDR_VER_0_1_0 = 0x00010000,
AW_MONITOR_HDR_VER_0_1_1 = 0x00010100,
};
enum {
AW_FIRST_ENTRY = 0,
AW_NOT_FIRST_ENTRY = 1,
};
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;
};
enum aw_monitor_init {
AW_MON_CFG_ST = 0,
AW_MON_CFG_OK = 1,
};
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_hdr {
uint32_t check_sum;
uint32_t monitor_ver;
char chip_type[8];
uint32_t ui_ver;
uint32_t monitor_switch;
uint32_t monitor_time;
uint32_t monitor_count;
uint32_t ipeak_switch;
uint32_t gain_switch;
uint32_t vmax_switch;
uint32_t temp_switch;
uint32_t temp_aplha;
uint32_t temp_num;
uint32_t single_temp_size;
uint32_t temp_offset;
uint32_t vol_switch;
uint32_t vol_aplha;
uint32_t vol_num;
uint32_t single_vol_size;
uint32_t vol_offset;
};
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_monitor_trace {
int32_t pre_val;
int32_t sum_val;
struct aw_table aw_table;
};
/******************************************************************
* struct aw882xx monitor
*******************************************************************/
struct aw8838_monitor {
struct delayed_work delay_work;
struct delayed_work load_fw_work;
struct aw_monitor_cfg monitor_cfg;
uint32_t is_enable;
uint8_t first_entry;
uint8_t samp_count;
uint32_t pre_vmax;
struct aw_monitor_trace temp_trace;
struct aw_monitor_trace vol_trace;
#ifdef AW_DEBUG
uint16_t test_vol;
int16_t test_temp;
#endif
};
/******************************************************************
* aw8838 monitor functions
*******************************************************************/
void aw8838_monitor_start(struct aw8838_monitor *monitor);
void aw8838_monitor_stop(struct aw8838_monitor *monitor);
void aw8838_parse_monitor_dt(struct aw8838_monitor *monitor);
void aw8838_monitor_init(struct aw8838_monitor *monitor);
void aw8838_monitor_deinit(struct aw8838_monitor *monitor);
/********************************************
* print information control
*******************************************/
#define aw_dev_err(dev, format, ...) \
pr_err("[%s]" format, dev_name(dev), ##__VA_ARGS__)
#define aw_dev_info(dev, format, ...) \
pr_info("[%s]" format, dev_name(dev), ##__VA_ARGS__)
#define aw_dev_dbg(dev, format, ...) \
pr_debug("[%s]" format, dev_name(dev), ##__VA_ARGS__)
#endif

View file

@ -0,0 +1,258 @@
#ifndef _AW8838_REG_H_
#define _AW8838_REG_H_
/********************************************
* Register List
*******************************************/
#define AW8838_REG_ID 0x00
#define AW8838_REG_SYSST 0x01
#define AW8838_REG_SYSINT 0x02
#define AW8838_REG_SYSINTM 0x03
#define AW8838_REG_SYSCTRL 0x04
#define AW8838_REG_I2SCTRL 0x05
#define AW8838_REG_I2STXCFG 0x06
#define AW8838_REG_PWMCTRL 0x08
#define AW8838_REG_HAGCCFG0 0x10
#define AW8838_REG_HAGCCFG1 0x11
#define AW8838_REG_HAGCCFG2 0x12
#define AW8838_REG_HAGCCFG3 0x13
#define AW8838_REG_HAGCCFG4 0x14
#define AW8838_REG_HAGCCFG5 0x15
#define AW8838_REG_HAGCCFG6 0x16
#define AW8838_REG_HAGCCFG7 0x17
#define AW8838_REG_HAGCCFG8 0x18
#define AW8838_REG_DBGCTRL 0x20
#define AW8838_REG_I2SCFG 0x21
#define AW8838_REG_I2SSTAT 0x22
#define AW8838_REG_I2SCAPCNT 0x23
#define AW8838_REG_HPFCCFG1 0x50
#define AW8838_REG_HPFCCFG2 0x51
#define AW8838_REG_HPFCCFG3 0x52
#define AW8838_REG_HPFCCFG4 0x53
#define AW8838_REG_HPFCCFG5 0x54
#define AW8838_REG_CPCTRL 0x60
#define AW8838_REG_PLLCTRL1 0x61
#define AW8838_REG_PLLCTRL2 0x62
#define AW8838_REG_AMPDBG1 0x63
#define AW8838_REG_AMPDBG2 0x64
#define AW8838_REG_TESTCTRL 0x65
#define AW8838_REG_MAX 0x6F
/********************************************
* Register Access
*******************************************/
#define REG_NONE_ACCESS 0
#define REG_RD_ACCESS 1 << 0
#define REG_WR_ACCESS 1 << 1
static const unsigned char aw8838_reg_access[AW8838_REG_MAX]={
[AW8838_REG_ID ] = REG_RD_ACCESS,
[AW8838_REG_SYSST ] = REG_RD_ACCESS,
[AW8838_REG_SYSINT ] = REG_RD_ACCESS,
[AW8838_REG_SYSINTM ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_SYSCTRL ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_I2SCTRL ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_I2STXCFG ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_PWMCTRL ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_HAGCCFG0 ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_HAGCCFG1 ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_HAGCCFG2 ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_HAGCCFG3 ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_HAGCCFG4 ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_HAGCCFG5 ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_HAGCCFG6 ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_HAGCCFG7 ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_HAGCCFG8 ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_DBGCTRL ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_I2SCFG ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_I2SSTAT ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_I2SCAPCNT] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_HPFCCFG1 ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_HPFCCFG2 ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_HPFCCFG3 ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_HPFCCFG4 ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_HPFCCFG5 ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_CPCTRL ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_PLLCTRL1 ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_PLLCTRL2 ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_AMPDBG1 ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_AMPDBG2 ] = REG_RD_ACCESS|REG_WR_ACCESS,
[AW8838_REG_TESTCTRL ] = REG_RD_ACCESS|REG_WR_ACCESS,
};
/******************************************************
* Register Detail
*****************************************************/
// SYSST
#define AW8838_BIT_SYSST_UVLOS ( 1<<14)
#define AW8838_BIT_SYSST_ADPS ( 1<<13)
#define AW8838_BIT_SYSST_OVPS ( 1<<11)
#define AW8838_BIT_SYSST_HVS ( 1<<10)
#define AW8838_BIT_SYSST_VOS ( 1<< 9)
#define AW8838_BIT_SYSST_SWS ( 1<< 8)
#define AW8838_BIT_SYSST_NOCLKS ( 1<< 5)
#define AW8838_BIT_SYSST_CLKS ( 1<< 4)
#define AW8838_BIT_SYSST_OCDS ( 1<< 3)
#define AW8838_BIT_SYSST_OTLS ( 1<< 2)
#define AW8838_BIT_SYSST_OTHS ( 1<< 1)
#define AW8838_BIT_SYSST_PLLS ( 1<< 0)
// SYSINT
#define AW8838_BIT_SYSINT_UVLOI ( 1<<14)
#define AW8838_BIT_SYSINT_ADPI ( 1<<13)
#define AW8838_BIT_SYSINT_OVPI ( 1<<11)
#define AW8838_BIT_SYSINT_HVI ( 1<<10)
#define AW8838_BIT_SYSINT_VOI ( 1<< 9)
#define AW8838_BIT_SYSINT_SWI ( 1<< 8)
#define AW8838_BIT_SYSINT_NOCLKI ( 1<< 5)
#define AW8838_BIT_SYSINT_CLKI ( 1<< 4)
#define AW8838_BIT_SYSINT_OCDI ( 1<< 3)
#define AW8838_BIT_SYSINT_OTLI ( 1<< 2)
#define AW8838_BIT_SYSINT_OTHI ( 1<< 1)
#define AW8838_BIT_SYSINT_PLLI ( 1<< 0)
// SYSINTM
#define AW8838_BIT_SYSINTM_UVLOM ( 1<<14)
#define AW8838_BIT_SYSINTM_ADPM ( 1<<13)
#define AW8838_BIT_SYSINTM_OVPM ( 1<<11)
#define AW8838_BIT_SYSINTM_HVM ( 1<<10)
#define AW8838_BIT_SYSINTM_VOM ( 1<< 9)
#define AW8838_BIT_SYSINTM_SWM ( 1<< 8)
#define AW8838_BIT_SYSINTM_NOCLKM ( 1<< 5)
#define AW8838_BIT_SYSINTM_CLKM ( 1<< 4)
#define AW8838_BIT_SYSINTM_OCDM ( 1<< 3)
#define AW8838_BIT_SYSINTM_OTLM ( 1<< 2)
#define AW8838_BIT_SYSINTM_OTHM ( 1<< 1)
#define AW8838_BIT_SYSINTM_PLLM ( 1<< 0)
// SYSCTRL
#define AW8838_BIT_SYSCTRL_INTMODE_MASK (~( 3<< 8))
#define AW8838_BIT_SYSCTRL_INT_HIGH_PP ( 3<< 8)
#define AW8838_BIT_SYSCTRL_INT_LOW_PP ( 2<< 8)
#define AW8838_BIT_SYSCTRL_INT_HIGH_OD ( 1<< 8)
#define AW8838_BIT_SYSCTRL_INT_LOW_OD ( 0<< 8)
#define AW8838_BIT_SYSCTRL_MODE_MASK (~( 1<< 7))
#define AW8838_BIT_SYSCTRL_RCV_MODE ( 1<< 7)
#define AW8838_BIT_SYSCTRL_SPK_MODE ( 0<< 7)
#define AW8838_BIT_SYSCTRL_I2SEN_MASK (~( 1<< 6))
#define AW8838_BIT_SYSCTRL_I2S_ENABLE ( 1<< 6)
#define AW8838_BIT_SYSCTRL_I2S_DISABLE ( 0<< 6)
#define AW8838_BIT_SYSCTRL_WSINV_MASK (~( 1<< 5))
#define AW8838_BIT_SYSCTRL_WS_INVERT ( 1<< 5)
#define AW8838_BIT_SYSCTRL_WS_NO_INVERT ( 0<< 5)
#define AW8838_BIT_SYSCTRL_BCKINV_MASK (~( 1<< 4))
#define AW8838_BIT_SYSCTRL_BCK_INVERT ( 1<< 4)
#define AW8838_BIT_SYSCTRL_BCK_NO_INVERT ( 0<< 4)
#define AW8838_BIT_SYSCTRL_IPLL_MASK (~( 1<< 3))
#define AW8838_BIT_SYSCTRL_PLL_WORD ( 1<< 3)
#define AW8838_BIT_SYSCTRL_PLL_BIT ( 0<< 3)
#define AW8838_BIT_SYSCTRL_DSPBY_MASK (~( 1<< 2))
#define AW8838_BIT_SYSCTRL_DSP_BYPASS ( 1<< 2)
#define AW8838_BIT_SYSCTRL_DSP_WORK ( 0<< 2)
#define AW8838_BIT_SYSCTRL_CP_MASK (~( 1<< 1))
#define AW8838_BIT_SYSCTRL_CP_PDN ( 1<< 1)
#define AW8838_BIT_SYSCTRL_CP_ACTIVE ( 0<< 1)
#define AW8838_BIT_SYSCTRL_PW_MASK (~( 1<< 0))
#define AW8838_BIT_SYSCTRL_PW_PDN ( 1<< 0)
#define AW8838_BIT_SYSCTRL_PW_ACTIVE ( 0<< 0)
#define AW8838_BIT_SYSCTRL_CPPD_MASK (~( 1<< 1))
#define AW8838_BIT_SYSCTRL_CPPD_PDN ( 1<< 1)
#define AW8838_BIT_SYSCTRL_CPPD_ACTIVE ( 0<< 1)
// I2SCTRL
#define AW8838_BIT_I2SCTRL_INPLEV_MASK (~( 1<<13))
#define AW8838_BIT_I2SCTRL_INPLEV_0DB ( 1<<13)
#define AW8838_BIT_I2SCTRL_INPLEV_NEG_6DB ( 0<<13)
#define AW8838_BIT_I2SCTRL_STEREO_MASK (~( 1<<12))
#define AW8838_BIT_I2SCTRL_STEREO_ENABLE ( 1<<12)
#define AW8838_BIT_I2SCTRL_STEREO_DISABLE ( 0<<12)
#define AW8838_BIT_I2SCTRL_CHS_MASK (~( 3<<10))
#define AW8838_BIT_I2SCTRL_CHS_MONO ( 3<<10)
#define AW8838_BIT_I2SCTRL_CHS_RIGHT ( 2<<10)
#define AW8838_BIT_I2SCTRL_CHS_LEFT ( 1<<10)
#define AW8838_BIT_I2SCTRL_MD_MASK (~( 3<< 8))
#define AW8838_BIT_I2SCTRL_MD_LSB ( 2<< 8)
#define AW8838_BIT_I2SCTRL_MD_MSB ( 1<< 8)
#define AW8838_BIT_I2SCTRL_MD_STD ( 0<< 8)
#define AW8838_BIT_I2SCTRL_FMS_MASK (~( 3<< 6))
#define AW8838_BIT_I2SCTRL_FMS_32BIT ( 3<< 6)
#define AW8838_BIT_I2SCTRL_FMS_24BIT ( 2<< 6)
#define AW8838_BIT_I2SCTRL_FMS_20BIT ( 1<< 6)
#define AW8838_BIT_I2SCTRL_FMS_16BIT ( 0<< 6)
#define AW8838_BIT_I2SCTRL_BCK_MASK (~( 3<< 4))
#define AW8838_BIT_I2SCTRL_BCK_64FS ( 2<< 4)
#define AW8838_BIT_I2SCTRL_BCK_48FS ( 1<< 4)
#define AW8838_BIT_I2SCTRL_BCK_32FS ( 0<< 4)
#define AW8838_BIT_I2SCTRL_SR_MASK (~(15<< 0))
#define AW8838_BIT_I2SCTRL_SR_192K (10<< 0)
#define AW8838_BIT_I2SCTRL_SR_96K ( 9<< 0)
#define AW8838_BIT_I2SCTRL_SR_48K ( 8<< 0)
#define AW8838_BIT_I2SCTRL_SR_44P1K ( 7<< 0)
#define AW8838_BIT_I2SCTRL_SR_32K ( 6<< 0)
#define AW8838_BIT_I2SCTRL_SR_24K ( 5<< 0)
#define AW8838_BIT_I2SCTRL_SR_22K ( 4<< 0)
#define AW8838_BIT_I2SCTRL_SR_16K ( 3<< 0)
#define AW8838_BIT_I2SCTRL_SR_12K ( 2<< 0)
#define AW8838_BIT_I2SCTRL_SR_11K ( 1<< 0)
#define AW8838_BIT_I2SCTRL_SR_8K ( 0<< 0)
// I2STXCFG
#define AW8838_BIT_I2STXCFG_FSYNC_MASK (~( 1<<15))
#define AW8838_BIT_I2STXCFG_FSYNC_BCK_CYCLE ( 1<<15)
#define AW8838_BIT_I2STXCFG_FSYNC_ONE_SLOT ( 0<<15)
#define AW8838_BIT_I2STXCFG_SLOT_NUM_MASK (~( 1<<14))
#define AW8838_BIT_I2STXCFG_SLOT_NUM_4_TIMES ( 1<<14)
#define AW8838_BIT_I2STXCFG_SLOT_NUM_2_TIMES ( 0<<14)
#define AW8838_BIT_I2STXCFG_TX_SLOT_VLD_MASK (~(15<<12))
#define AW8838_BIT_I2STXCFG_TX_SLOT_VLD_3 ( 3<<12)
#define AW8838_BIT_I2STXCFG_TX_SLOT_VLD_2 ( 2<<12)
#define AW8838_BIT_I2STXCFG_TX_SLOT_VLD_1 ( 1<<12)
#define AW8838_BIT_I2STXCFG_TX_SLOT_VLD_0 ( 0<<12)
#define AW8838_BIT_I2STXCFG_RX_SLOT_VLD_MASK (~(15<< 8))
#define AW8838_BIT_I2STXCFG_RX_SLOT_VLD_3_2 (12<< 8)
#define AW8838_BIT_I2STXCFG_RX_SLOT_VLD_3_1 (10<< 8)
#define AW8838_BIT_I2STXCFG_RX_SLOT_VLD_3_0 ( 9<< 8)
#define AW8838_BIT_I2STXCFG_RX_SLOT_VLD_2_1 ( 6<< 8)
#define AW8838_BIT_I2STXCFG_RX_SLOT_VLD_2_0 ( 5<< 8)
#define AW8838_BIT_I2STXCFG_RX_SLOT_VLD_1_0 ( 3<< 8)
#define AW8838_BIT_I2STXCFG_RX_SLOT_VLD_3 ( 8<< 8)
#define AW8838_BIT_I2STXCFG_RX_SLOT_VLD_2 ( 4<< 8)
#define AW8838_BIT_I2STXCFG_RX_SLOT_VLD_1 ( 2<< 8)
#define AW8838_BIT_I2STXCFG_RX_SLOT_VLD_0 ( 1<< 8)
#define AW8838_BIT_I2STXCFG_DRVSTREN_MASK (~( 1<< 5))
#define AW8838_BIT_I2STXCFG_DRVSTREN_8MA ( 1<< 5)
#define AW8838_BIT_I2STXCFG_DRVSTREN_2MA ( 0<< 5)
#define AW8838_BIT_I2STXCFG_DOHZ_MASK (~( 1<< 4))
#define AW8838_BIT_I2STXCFG_DOHZ_HIZ ( 1<< 4)
#define AW8838_BIT_I2STXCFG_DOHZ_GND ( 0<< 4)
#define AW8838_BIT_I2STXCFG_DSEL_MASK (~( 3<< 2))
#define AW8838_BIT_I2STXCFG_DSEL_DSP ( 2<< 2)
#define AW8838_BIT_I2STXCFG_DSEL_GAIN ( 1<< 2)
#define AW8838_BIT_I2STXCFG_DSEL_ZERO ( 0<< 2)
#define AW8838_BIT_I2STXCFG_CHS_MASK (~( 1<< 1))
#define AW8838_BIT_I2STXCFG_CHS_RIGHT ( 1<< 1)
#define AW8838_BIT_I2STXCFG_CHS_LEFT ( 0<< 1)
#define AW8838_BIT_I2STXCFG_TX_MASK (~( 1<< 0))
#define AW8838_BIT_I2STXCFG_TX_ENABLE ( 1<< 0)
#define AW8838_BIT_I2STXCFG_TX_DISABLE ( 0<< 0)
// PWMCTRL
#define AW8838_BIT_PWMCTRL_HMUTE_MASK (~( 1<< 0))
#define AW8838_BIT_PWMCTRL_HMUTE_ENABLE ( 1<< 0)
#define AW8838_BIT_PWMCTRL_HMUTE_DISABLE ( 0<< 0)
// HAGCCFG8
#define AW8838_BIT_HAGCCFG8_VOL_MASK (~(255<< 8))
#define AW8838_VOLUME_MAX (0)
#define AW8838_VOLUME_MIN (-255)
#define AW8838_VOL_REG_SHIFT (8)
#define AW8838_VOL_6DB_STEP (6 * 2)
//CPCTRL
#define AW8838_BIT_CPCTRL_CP_IPEAK_MASK (~( 1<< 15))
#define AW8838_BIT_CPCTRL_CP_MD_MASK (~( 3<< 8))
#define AW8838_BIT_CPCTRL_CP_MD_TRANS ( 0<<8)
#endif

View file

@ -0,0 +1,15 @@
# add -Wall to try to catch everything we can.
EXTRA_CFLAGS += -Wall
EXTRA_CFLAGS += -I$(TOP)/kernel/msm-5.4/techpack/audio/include
EXTRA_CFLAGS += -I$(TOP)/kernel/msm-5.4/techpack/audio/include/uapi/
ifdef CONFIG_SND_SOC_FS1815
FS1815_OBJS += fs1815.o
FS1815_OBJS += fsm_core.o
FS1815_OBJS += fsm_firmware.o
FS1815_OBJS += fsm_i2c.o
FS1815_OBJS += fsm_misc.o
endif
obj-$(CONFIG_SND_SOC_FS1815) += fs1815_dlkm.o
fs1815_dlkm-y := $(FS1815_OBJS)

View file

@ -0,0 +1,12 @@
v4.0.8
2022-12-08 c7d54d6 FSDRV(fs1815): 4*fs1815 with i2c*2 application
2022-12-08 93ab5cc FSDRV(fs1815): SDZ pin 与友商兼容逻辑更新
2022-11-18 c27e168 Merge "FSDRV(fs181599): Update i2c shutdown same as FS1815&FS1599" into spc-driver-v1
2022-11-15 33ab193 FSDRV(fs181599): Update i2c shutdown same as FS1815&FS1599
2022-11-15 7822aa7 FSDRV(fs1815): Update i2c shutdown to make sure device power down
2022-07-12 2aa9943 Merge "fix(fs1815): Add soft reset and shutdown function" into spc-driver-v1
2022-06-09 5006522 feat(fs181599): Add fs1815&fs1599 compat driver
2022-06-16 4d6b5c2 fix(fs1815): Add soft reset and shutdown function
2022-05-26 eb95fce fix(fs1815): fix typo error of function symbol
2022-06-06 8fd4ca1 Merge "feat(fs1815): Add fs1815 i2c driver" into spc-driver-v1
2022-04-07 f06858f feat(fs1815): Add fs1815 i2c driver

View file

@ -0,0 +1,171 @@
/**
* Copyright (C) Fourier Semiconductor Inc. 2016-2020. All rights reserved.
* 2019-01-29 File created.
*/
#include "fsm_public.h"
#if defined(CONFIG_FSM_FS1815)
#define FS1815_STATUS 0xF000
#define FS1815_BOVDS 0x0000
#define FS1815_OTPDS 0x0200
#define FS1815_OVDS 0x0300
#define FS1815_UVDS 0x0400
#define FS1815_OCDS 0x0500
#define FS1815_OTWDS 0x0800
#define FS1815_BOPS 0x0900
#define FS1815_SPKS 0x0A00
#define FS1815_SPKT 0x0B00
#define FS1815_DEVID 0xF001
#define FS1815_REVID 0xF002
#define FS1815_ANASTAT 0xF003
#define FS1815_DIGSTAT 0xF004
#define FS1815_CHIPINI 0xF00E
#define FS1815_PWRCTRL 0xF010
#define FS1815_PWDN 0x0010
#define FS1815_I2CR 0x0110
#define FS1815_SYSCTRL 0xF011
#define FS1815_OSCEN 0x0011
#define FS1815_VBGEN 0x0111
#define FS1815_ZMEN 0x0211
#define FS1815_ADCEN 0x0311
#define FS1815_BSTPD 0x0611
#define FS1815_AMPEN 0x0711
#define FS1815_SPKCOEF 0xF014
#define FS1815_GAINCTRL 0xF018
#define FS1815_ACCKEY 0xF01F
#define FS1815_BSTCTRL 0xF020
#define FS1815_SSEND 0x0F20
#define FS1815_VOUTSEL 0x4820
#define FS1815_ILIMSEL 0x2420
#define FS1815_BSTMODE 0x1020
#define FS1815_DACCTRL 0xF030
#define FS1815_LNMCTRL 0xF03F
#define FS1815_TSCTRL 0xF04C
#define FS1815_OFFSTA 0x0E4C
#define FS1815_OFF_AUTOEN 0x0D4C
#define FS1815_TSEN 0x034C
#define FS1815_AGC1 0x3059
#define FS1815_AGC1RT 0x3059
#define FS1815_AGC2 0x305A
#define FS1815_AGC3 0x305B
#define FS1815_AGC4 0x305C
#define FS1815_BSGCTRL 0xF0BC
#define FS1815_FW_NAME "fs1815.fsm"
static int fs1815_i2c_reset(fsm_dev_t *fsm_dev)
{
uint16_t val;
int ret;
int i;
if (!fsm_dev) {
return -EINVAL;
}
for (i = 0; i < FSM_I2C_RETRY; i++) {
fsm_reg_write(fsm_dev, REG(FS1815_PWRCTRL), 0x0002); // reset nack
fsm_reg_read(fsm_dev, REG(FS1815_PWRCTRL), NULL); // dummy read
fsm_delay_ms(15); // 15ms
ret = fsm_reg_write(fsm_dev, REG(FS1815_PWRCTRL), 0x0001);
ret |= fsm_reg_read(fsm_dev, REG(FS1815_CHIPINI), &val);
if ((val == 0x0003) || (val == 0x0300)) { // init finished
break;
}
}
if (i == FSM_I2C_RETRY) {
pr_addr(err, "retry timeout");
ret = -ETIMEDOUT;
}
return ret;
}
int fs1815_reg_init(fsm_dev_t *fsm_dev)
{
fsm_config_t *cfg = fsm_get_config();
int ret;
if (fsm_dev == NULL || cfg == NULL) {
return -EINVAL;
}
ret = fs1815_i2c_reset(fsm_dev);
ret |= fsm_reg_write(fsm_dev, REG(FS1815_SPKCOEF), (fsm_dev->tcoef << 1));
ret |= fsm_write_reg_tbl(fsm_dev, FSM_SCENE_COMMON);
ret |= fsm_write_reg_tbl(fsm_dev, cfg->next_scene);
if (ret) {
pr_addr(err, "init failed:%d", ret);
fsm_dev->state.dev_inited = false;
}
return ret;
}
int fs1815_start_up(fsm_dev_t *fsm_dev)
{
int ret;
if (!fsm_dev) {
return -EINVAL;
}
if (fsm_dev->revid == 0x0011) {
ret = fsm_reg_write(fsm_dev, REG(FS1815_BSGCTRL), 0x9433);
}
// 0x1100EF; all enable
ret = fsm_reg_write(fsm_dev, REG(FS1815_SYSCTRL), 0x008F);
// 0x100000; power up
ret |= fsm_reg_write(fsm_dev, REG(FS1815_PWRCTRL), 0x0000);
ret |= fsm_config_vol(fsm_dev);
fsm_delay_ms(10);
fsm_dev->errcode = ret;
return ret;
}
int fs1815_shut_down(fsm_dev_t *fsm_dev)
{
int ret;
if (fsm_dev == NULL) {
return -EINVAL;
}
ret = fsm_reg_write(fsm_dev, REG(FS1815_PWRCTRL), 0x0001);
ret |= fsm_reg_write(fsm_dev, REG(FS1815_SYSCTRL), 0x0000);
fsm_delay_ms(10);
return ret;
}
void fs1815_ops(fsm_dev_t *fsm_dev)
{
fsm_config_t *cfg = fsm_get_config();
if (!fsm_dev || !cfg) {
return;
}
fsm_set_fw_name(FS1815_FW_NAME);
fsm_dev->dev_ops.reg_init = fs1815_reg_init;
fsm_dev->dev_ops.start_up = fs1815_start_up;
fsm_dev->dev_ops.shut_down = fs1815_shut_down;
cfg->nondsp_mode = true;
cfg->store_otp = false;
}
#endif

View file

@ -0,0 +1,831 @@
/**
* Copyright (C) Fourier Semiconductor Inc. 2016-2020. All rights reserved.
* 2018-10-16 File created.
*/
#ifndef __FSM_DEV_H__
#define __FSM_DEV_H__
/* ------- MACRO FEATURE ------- */
/* debug print macro, default closed */
//#define DEBUG
//#define FSM_DEBUG
//#define FSM_DEBUG_I2C
#if defined(__KERNEL__)
/* kernel module: */
#define CONFIG_FSM_MISC
//#define CONFIG_FSM_CODEC
#define CONFIG_FSM_FIRMWARE
#define CONFIG_FSM_I2C
//#define CONFIG_FSM_Q6AFE
#endif
/* device chip select: */
//#define CONFIG_FSM_NONDSP
//#define CONFIG_FSM_FS1958
#define CONFIG_FSM_FS1815
/* VERSION INFORMATION */
#define FSM_CODE_VERSION "v4.0.8"
#define FSM_CODE_DATE "20230612"
#define FSM_GIT_BRANCH "spc-driver-v1"
#define FSM_GIT_COMMIT "23749327"
#define FSM_DRV_NAME "fs16xx"
#define FSM_FW_NAME "fs16xx_dft.fsm"
// #define FSM_CALIB_SAVE_PATH "/data"
// TODO
#define FSM_CALIB_SAVE_PATH "/mnt/vendor/persist/audio"
//#ifndef BIT
//#define BIT(nr) (1UL << (nr))
//#endif
/* scenes defination */
#define FSM_SCENE_UNKNOW (0)
#define FSM_SCENE_MUSIC BIT(0)
#define FSM_SCENE_VOICE BIT(1)
#define FSM_SCENE_VOIP BIT(2)
#define FSM_SCENE_RING BIT(3)
#define FSM_SCENE_LOW_PWR BIT(4)
#define FSM_SCENE_MMI_ALL BIT(5)
#define FSM_SCENE_MMI_ALL_BYPASS BIT(6)
#define FSM_SCENE_TOP_LEFT BIT(7)
#define FSM_SCENE_TOP_LEFT_BYPASS BIT(8)
#define FSM_SCENE_TOP_RIGHT BIT(9)
#define FSM_SCENE_TOP_RIGHT_BYPASS BIT(10)
#define FSM_SCENE_BOT_LEFT BIT(11)
#define FSM_SCENE_BOT_LEFT_BYPASS BIT(12)
#define FSM_SCENE_BOT_RIGHT BIT(13)
#define FSM_SCENE_BOT_RIGHT_BYPASS BIT(14)
#define FSM_SCENE_RCV BIT(15)
#define FSM_SCENE_MAX (16) // TODO
#define FSM_SCENE_COMMON (0xFFFF)
#define FSM_VOLUME_MAX (0xFF)
/* ------- MACRO FEATURE ------- */
#ifndef pr_fmt
#define pr_fmt(fmt) "%s: " fmt "\n", __func__
#endif
#if defined(__KERNEL__)
#include <linux/module.h>
#include <linux/regmap.h>
//#include <linux/miscdevice.h>
#include <linux/ioctl.h>
#include <linux/workqueue.h>
#include <linux/list.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/delay.h>
#if defined(CONFIG_REGULATOR)
#include <linux/regulator/consumer.h>
#include <sound/soc.h>
#include <sound/control.h>
#endif
#define logprint(fmt, args...) printk(KERN_CONT fmt, ##args)
#elif defined(FSM_HAL_SUPPORT)
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <stdlib.h>
#include <stdbool.h>
#include <fcntl.h>
#include <unistd.h>
#include "fsm_list.h"
/* debug info */
#ifdef FSM_DEBUG
#undef NDEBUG
#define LOG_NDEBUG 0 // open LOGV
#endif
#if defined(LOG_TAG)
#undef LOG_TAG
#endif
#define LOG_TAG "fsm_hal"
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#endif
#if defined(FSM_APP)
#if defined(FSM_DEBUG)
#define pr_debug(fmt, args...) printf("%s: " fmt "\n", __func__, ##args)
#else
#define pr_debug(fmt, args...)
#endif
#define pr_info(fmt, args...) printf("%s: " fmt "\n", __func__, ##args)
#define pr_err(fmt, args...) printf("%s: " fmt "\n", __func__, ##args)
#define pr_warning(fmt, args...) printf("%s: " fmt "\n", __func__, ##args)
#define logprint(fmt, args...) printf(fmt, ##args)
#elif defined(BUILD_FSTOOL)
#ifdef DEBUG
#undef DEBUG
#endif
#ifdef FSM_DEBUG
#undef FSM_DEBUG
#endif
#ifndef FSM_DEBUG_I2C
#define FSM_DEBUG_I2C
#endif
#define pr_debug(fmt, args...) printf(fmt "\n", ##args)
#define pr_info(fmt, args...) printf(fmt "\n", ##args)
#define pr_err(fmt, args...) printf(fmt "\n", ##args)
#define pr_warning(fmt, args...) printf(fmt "\n", ##args)
#define logprint(fmt, args...) printf(fmt, ##args)
#elif defined(__NDK_BUILD__)
#include<android/log.h>
#define pr_debug(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG,\
LOG_TAG, "%s: " fmt, __func__, ##args)
#define pr_info(fmt, args...) __android_log_print(ANDROID_LOG_INFO,\
LOG_TAG, "%s: " fmt, __func__, ##args)
#define pr_err(fmt, args...) __android_log_print(ANDROID_LOG_ERROR,\
LOG_TAG, "%s: " fmt, __func__, ##args)
#define pr_warning(fmt, args...) __android_log_print(ANDROID_LOG_ERROR,\
LOG_TAG, "%s: " fmt, __func__, ##args)
#define logprint(fmt, args...) __android_log_print(ANDROID_LOG_INFO,\
LOG_TAG, fmt, ##args)
#elif defined(__ANDROID__)
#include <utils/Log.h>
#define pr_debug(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG,\
LOG_TAG, "%s: " fmt, __func__, ##args)
#define pr_info(fmt, args...) __android_log_print(ANDROID_LOG_INFO,\
LOG_TAG, "%s: " fmt, __func__, ##args)
#define pr_err(fmt, args...) __android_log_print(ANDROID_LOG_ERROR,\
LOG_TAG, "%s: " fmt, __func__, ##args)
#define pr_warning(fmt, args...) __android_log_print(ANDROID_LOG_ERROR,\
LOG_TAG, "%s: " fmt, __func__, ##args)
#define logprint(fmt, args...) __android_log_print(ANDROID_LOG_INFO,\
LOG_TAG, fmt, ##args)
#else
#define pr_debug(fmt, args...)
#define pr_info(fmt, args...)
#define pr_err(fmt, args...)
#define pr_warning(fmt, args...)
#define logprint(fmt, args...)
#endif // FSM_APP
#endif // FSM_HAL_SUPPORT
#define pr_addr(type, fmt, args...) \
pr_##type("%02X: " fmt, fsm_dev->addr, ##args)
#define FSM_FUNC_EXIT(ret) \
do { \
if (ret) \
pr_err("err: %d", ret); \
} while(0)
#define FSM_ADDR_EXIT(ret) \
do { \
if (ret) \
pr_addr(err, "err: %d", ret); \
} while(0)
#define UNUSED(expr) do { (void)(expr); } while(0)
enum dev_id_index {
FS1601S_DEV_ID = 0x3,
FS1603_DEV_ID = 0x5,
FS1818_DEV_ID = 0x6,
FS1860_DEV_ID = 0x7,
FS1896_DEV_ID = 0xB,
FS1815_DEV_ID = 0x12,
FS1820_DEV_ID = FS1815_DEV_ID,
FS1958_DEV_ID = 0x17,
FSM_DEV_ID_MAX,
};
#define FS1603S_V1 0X05B1
#define FS1603S_SERIES 0X05B0
#define IS_FS1603S(id) (((id) & 0xFFF0) == FS1603S_SERIES)
#define CUST_NAME_SIZE (32)
#define STRING_LEN_MAX (255)
#define LOG_BUF_SIZE (8 * 8 + 1)
#define FSM_AFE_HEADER_LEN (5)
#define FSM_DFT_AMB_TEMPR (25)
#define FSM_DFT_AMB_VBAT (3678)
#define STEREO_COEF_LEN (10)
#define FSM_MAGNIF_FACTOR (10) // magnification factor: 2^(x)
#define FSM_PAYLOAD_SIZE (64)
#define FSM_WAIT_STABLE_RETRY (30)
#define FSM_CALIB_RE25_RETRY (50)
#define FSM_I2C_RETRY (5)
#define FSM_ZMDELTA_MAX 0x150
#define FSM_RS_TRIM_DEFAULT 0x8F
#define FSM_MAGNIF_TEMPR_COEF 0xFFFF
#define FSM_OTP_ACC_KEY2 0xCA91
#define FSM_DATA_TYPE_RE25 0
#define FSM_DATA_TYPE_ZMDATA 1
#define MODULE_INITED (13579)
#define FSM_VBATH_COUNT (10)
#define FSM_VBAT_HIGH (4000) // mV
#define FSM_VBAT_LOW (3600) // mV
#define FSM_VBAT_STEP ((FSM_VBAT_HIGH - FSM_VBAT_LOW) / 8) // mV
#define FSM_DEV_MAX (4)
#define FSM_ADDR_BASE (0x34)
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define HIGH8(val) ((val >> 8) & 0xFF)
#define LOW8(val) (val & 0xFF)
#define WORD(addr) ((*(addr) << 8) & *((addr) + 1))
#define REG(bf) (bf & 0xFF)
#define FSM_REG_SIZE sizeof(uint16_t)
#define FSM_ADDR_SIZE sizeof(uint8_t)
/* f0 test */
#define COUNT(start, end, step) (((end) - (start)) / (step) + 1)
#define ACS_COEF_COUNT 12
#define COEF_LEN 5
#define FREQ_START 200 // 100*N
#define FREQ_END 1500 // bigger than FREQ_START && 100*N
#define F0_FREQ_STEP 100 // 50*N, N =1,2,3...
#define FREQ_COUNT COUNT(FREQ_START, FREQ_END, F0_FREQ_STEP)
#define FREQ_EXT_COUNT 300
#define RE25_TEST_COUNT 10
#define RE25_1ST_WAIT_MS 2500
#define RE25_DELAY_MS 100
#define F0_1ST_DELAY_MS 800
#define F0_TEST_DELAY_MS 500
#define FSM_POS_MONO (0)
#define FSM_POS_LTOP BIT(3)
#define FSM_POS_LBTM BIT(2)
#define FSM_POS_RTOP BIT(1)
#define FSM_POS_RBTM BIT(0)
//#undef NULL
//#define NULL ((void *)0)
//
//enum {
// false = 0,
// true = 1
//};
enum fsm_error {
FSM_ERROR_OK = 0,
FSM_ERROR_BAD_PARMS,
FSM_ERROR_I2C_FATAL,
FSM_ERROR_NO_SCENE_MATCH,
FSM_ERROR_RE25_INVAILD,
FSM_ERROR_MAX,
};
enum fsm_channel {
FSM_CHN_UNKNOW = 0,
FSM_CHN_LEFT = 1,
FSM_CHN_RIGHT = 2,
FSM_CHN_MONO = 3,
};
enum fsm_format {
FSM_FMT_DSP = 1,
FSM_FMT_MSB = 2,
FSM_FMT_I2S = 3,
FSM_FMT_LSB_16 = 4,
FSM_FMT_LSB_20 = 6,
FSM_FMT_LSB_24 = 7,
};
enum fsadsp_tx_fmt {
FSADSP_TX_FMT_NONE = 0,
FSADSP_TX_FMT_I2S_S16,
FSADSP_TX_FMT_I2S_S32,
FSADSP_TX_FMT_TDM_MONO_VBAT, // SLOT:2 LEN: 16BIT IV + 16BIT VBAT
FSADSP_TX_FMT_TDM_STEREO, // SLOT:4 LEN: 16BIT IV on LEFT / RIGHT
};
enum fsm_bstmode {
FSM_BSTMODE_FLW = 0,
FSM_BSTMODE_BST = 1,
FSM_BSTMODE_ADP = 2,
};
enum fsm_dsp_state {
FSM_DSP_OFF = 0,
FSM_DSP_ON = 1,
};
enum fsm_wait_type {
FSM_WAIT_AMP_ON = 1,
FSM_WAIT_AMP_ADC_ON,
FSM_WAIT_AMP_OFF,
FSM_WAIT_AMP_ADC_OFF,
FSM_WAIT_AMP_ADC_PLL_OFF,
FSM_WAIT_TSIGNAL_ON,
FSM_WAIT_TSIGNAL_OFF,
FSM_WAIT_OTP_READY,
FSM_WAIT_BOOST_SSEND,
FSM_WAIT_STATUS_ON,
};
enum fsm_eq_ram_type {
FSM_EQ_RAM0 = 0,
FSM_EQ_RAM1,
FSM_EQ_RAM_MAX,
};
struct fsm_version {
char git_branch[50];
char git_commit[41];
char code_date[18];
char code_version[10];
};
typedef struct fsm_version fsm_version_t;
struct fsm_pll_config {
uint32_t bclk;
uint16_t c1;
uint16_t c2;
uint16_t c3;
};
typedef struct fsm_pll_config fsm_pll_config_t;
#define PRESET_VER_FS1601S 0x8301 // FS1601S
#define PRESET_VER_FS1603 0x8501 // FS1603 series
#define PRESET_VER_FS1801 0x8A01 // FS1801 series
#define PRESET_VER_FS1860 0x8701 // FS1860
#define PRESET_VER3 (0x93)
#define IS_PRESET_V3(ver) (HIGH8(ver) >= PRESET_VER3)
enum fsm_dsc_type {
FSM_DSC_DEV_INFO = 0,
FSM_DSC_SPK_INFO,
FSM_DSC_REG_COMMON,
FSM_DSC_REG_SCENES,
FSM_DSC_PRESET_EQ,
FSM_DSC_STEREO_COEF,
FSM_DSC_EXCER_RAM,
FSM_DSC_MAX,
};
enum fsm_info_type {
FSM_INFO_SPK_TMAX = 0,
FSM_INFO_SPK_TEMPR_COEF,
FSM_INFO_SPK_TEMPR_SEL,
FSM_INFO_SPK_RES,
FSM_INFO_SPK_RAPP,
FSM_INFO_SPK_TRE,
FSM_INFO_SPK_TM6,
FSM_INFO_SPK_TM24,
FSM_INFO_SPK_TERR,
FSM_INFO_SPK_TM01,
FSM_INFO_SPK_TM02,
FSM_INFO_SPK_TM03,
FSM_INFO_SPK_TM04,
FSM_INFO_SPK_TM05,
FSM_INFO_SPK_TM06,
FSM_INFO_RSRL_RATIO,
FSM_INFO_SPK_POSITION,
FSM_INFO_SPK_MAX,
};
enum fsm_test_type {
TEST_NONE = 0,
TEST_RE25,
TEST_F0,
};
#pragma pack(push, 1)
struct fsm_date {
uint32_t min : 6;
uint32_t hour : 5;
uint32_t day : 5;
uint32_t month : 4;
uint32_t year : 12;
};
typedef struct fsm_date fsm_date_t;
struct data32_list {
uint16_t len;
uint32_t data[];
};
typedef struct data32_list preset_data_t;
typedef struct data32_list ram_data_t;
struct uint24 {
uint8_t DL;
uint8_t DM;
uint8_t DH;
};
typedef struct uint24 uint24_t;
struct data24_list {
uint16_t len;
uint24_t data[];
};
struct data16_list {
uint16_t len;
uint16_t data[];
};
typedef struct data16_list info_list_t;
typedef struct data16_list stereo_coef_t;
struct fsm_index {
uint16_t offset;
uint16_t type;
};
typedef struct fsm_index fsm_index_t;
struct dev_list {
uint16_t preset_ver;
char project[8];
char customer[8];
fsm_date_t date;
uint16_t data_len;
uint16_t crc16;
uint16_t len;
uint16_t bus;
uint16_t addr;
uint16_t dev_type;
uint16_t npreset;
uint16_t reg_scenes;
uint16_t eq_scenes;
fsm_index_t index[];
};
typedef struct dev_list dev_list_t;
struct preset_list {
uint16_t len;
uint16_t scene;
uint32_t data[];
};
typedef struct preset_list preset_list_t;
struct reg_unit {
uint16_t addr : 8;
uint16_t pos : 4;
uint16_t len : 4;
uint16_t value;
};
typedef struct reg_unit reg_unit_t;
struct reg_wait {
uint16_t val : 8;
uint16_t pos : 4;
uint16_t len : 4;
};
typedef struct reg_wait reg_wait_t;
struct reg_comm {
uint16_t len;
reg_unit_t reg[];
};
typedef struct reg_comm reg_comm_t;
struct regs_unit {
uint16_t scene;
reg_unit_t reg;
};
typedef struct regs_unit regs_unit_t;
struct reg_scene {
uint16_t len;
regs_unit_t regs[];
};
typedef struct reg_scene reg_scene_t;
struct reg_temp {
uint16_t new_val;
uint16_t old_val;
};
typedef struct reg_temp reg_temp_t;
struct preset_header {
uint16_t version;
char customer[8];
char project[8];
fsm_date_t date;
uint16_t size;
uint16_t crc16;
uint16_t ndev;
};
struct preset_file {
struct preset_header hdr;
fsm_index_t index[];
};
struct calib_index {
uint8_t chn;
int re25;
};
struct fsm_calib_bin {
int size;
uint8_t ndev;
struct calib_index index[];
};
#pragma pack(pop)
struct fsm_srate {
uint32_t srate : 28;
uint32_t bf_val : 4;
};
struct fsm_dev;
struct fsm_ops {
int (*reg_init)(struct fsm_dev *);
int (*dev_init)(struct fsm_dev *);
int (*pll_config)(struct fsm_dev *, bool on);
int (*i2s_config)(struct fsm_dev *);
int (*switch_preset)(struct fsm_dev *);
int (*check_stable)(struct fsm_dev *, int type);
int (*start_up)(struct fsm_dev *);
int (*set_unmute)(struct fsm_dev *);
int (*set_tsignal)(struct fsm_dev *, bool enable);
int (*set_mute)(struct fsm_dev *, bool mute);
int (*shut_down)(struct fsm_dev *);
int (*deinit)(struct fsm_dev *);
int (*dev_recover)(struct fsm_dev *);
int (*cal_zmdata)(struct fsm_dev *);
int (*pre_calib)(struct fsm_dev *);
int (*store_otp)(struct fsm_dev *, uint8_t valOTP);
int (*post_calib)(struct fsm_dev *);
int (*pre_f0_test)(struct fsm_dev *);
int (*f0_test)(struct fsm_dev *);
int (*post_f0_test)(struct fsm_dev *);
};
typedef struct fsm_ops fsm_ops_t;
struct fsm_config {
uint8_t dev_count;
uint16_t cur_angle;
uint16_t next_angle;
uint16_t next_scene;
uint16_t test_type;
uint16_t test_freq;
uint16_t freq_start;
uint16_t freq_end;
uint16_t freq_step;
uint16_t freq_count;
uint16_t volume;
uint16_t amb_tempr;
uint16_t state : 8;
uint16_t wait_type : 8;
uint16_t tx_fmt : 8;
uint16_t rsvd : 8;
unsigned int i2s_bclk;
unsigned int i2s_srate;
// flags
uint32_t codec_inited : 3;
uint32_t force_fw : 1;
uint32_t force_init : 1;
uint32_t force_scene : 1;
uint32_t force_calib : 1;
uint32_t store_otp : 1;
uint32_t force_mute : 1;
uint32_t vddd_on : 1;
uint32_t reset_chip : 1;
uint32_t stop_test : 1;
uint32_t use_monitor : 1;
uint32_t skip_monitor : 1;
uint32_t stream_muted : 1;
uint32_t i2c_debug : 1;
uint32_t nondsp_mode : 1;
uint32_t speaker_on : 1;
//uint32_t bypass_dsp : 1;
char *codec_name[FSM_DEV_MAX];
char *codec_dai_name[FSM_DEV_MAX];
char *fw_name;
void *preset;
};
typedef struct fsm_config fsm_config_t;
struct fsm_vbat_state {
uint16_t last_batv;
uint16_t cur_batv;
uint16_t batvh_count;
};
struct fsm_calib {
uint16_t pos : 8;
uint16_t addr : 8;
uint16_t cal_zm;
uint8_t count;
int errcode;
int re25;
int f0;
};
struct fsm_f0_data {
uint16_t freq;
uint16_t zmdata;
uint16_t min_zm;
};
struct fsm_cal_result {
uint16_t ndev;
uint16_t freq_start;
uint16_t freq_end;
uint16_t freq_step;
uint16_t freq_count;
struct fsm_calib info[FSM_DEV_MAX];
uint16_t f0_zmdata[];
};
struct re25_data {
uint16_t count;
uint16_t pre_val;
uint16_t min_val;
uint16_t zmdata;
};
struct f0_data {
uint16_t count : 8;
uint16_t min_idx : 8;
uint16_t min_zm;
uint16_t zmdata[];
};
struct fsm_test_data {
int test_re25;
int test_f0;
int sum_re25;
int count_re25;
int sum_f0;
int count_f0;
struct re25_data re25;
struct f0_data f0;
};
struct fsm_livedata {
int Re25;
int R0;
int F0;
int Q;
int T;
int Vbat;
int Excer;
};
struct fsm_cal_data {
uint32_t channel;
uint32_t cal_re;
uint32_t cal_tempr;
uint32_t re_min : 16;
uint32_t re_max : 16;
bool calib_pass; // true: pass, false: fail
};
struct fsm_calib_v2 {
uint32_t dev_count;
struct fsm_cal_data cal_data[FSM_DEV_MAX];
};
#if !defined(CONFIG_I2C)
struct i2c_client {
int addr;
};
#endif
struct fsm_msg {
uint32_t size; // size of *buf
void *buf;
};
typedef struct fsm_msg fsm_msg_t;
struct fsm_bpcoef {
int freq;
uint32_t coef[COEF_LEN];
};
struct fsm_state {
uint16_t dev_inited : 1;
uint16_t amp_mute : 1;
uint16_t bypass_dsp : 1;
uint16_t calibrated : 1;
uint16_t otp_stored : 1;
uint16_t re25_runin : 1;
uint16_t f0_runing : 1;
};
struct fsm_compat {
uint16_t preset_unit_len;
uint16_t excer_ram_len;
uint16_t addr_excer_ram;
uint16_t otp_max_count;
uint16_t ACSEQA : 8;
uint16_t ACSEQWL : 8;
uint16_t DACEQA : 8;
uint16_t DACEQWL : 8;
int RS2RL_RATIO;
};
struct fsm_monitor_data {
uint16_t status;
uint16_t anastat;
uint16_t digstat;
uint16_t tsctrl;
uint16_t zmdata;
uint16_t batv; // mV
int ic_tempr;
int spk_tempr;
int spk_imp;
};
#if defined(CONFIG_FSM_MISC) || defined(FSM_HAL_SUPPORT)
#include <linux/ioctl.h>
/* ioctl magic number and cmd. */
#define FSM_IOC_MAGIC (0x7C)
#define FSM_IOC_GET_DEVICE _IOR(FSM_IOC_MAGIC, 1, int)
#define FSM_IOC_SET_SRATE _IOW(FSM_IOC_MAGIC, 2, int)
#define FSM_IOC_SET_SCENE _IOW(FSM_IOC_MAGIC, 3, int)
#define FSM_IOC_INIT _IOW(FSM_IOC_MAGIC, 4, int)
#define FSM_IOC_SPEAKER_ON _IOW(FSM_IOC_MAGIC, 5, int)
#define FSM_IOC_SPEAKER_OFF _IOW(FSM_IOC_MAGIC, 6, int)
#define FSM_IOC_CALIBRATE _IOW(FSM_IOC_MAGIC, 7, int)
#define FSM_IOC_F0_TEST _IOW(FSM_IOC_MAGIC, 8, int)
#define FSM_IOC_GET_RESULT _IOR(FSM_IOC_MAGIC, 9, void *)
#define FSM_IOC_SET_ADDR _IOW(FSM_IOC_MAGIC, 10, int)
#define FSM_IOC_SEND_APR _IOWR(FSM_IOC_MAGIC, 11, void *)
#define FSM_IOC_SET_SLAVE (0x0706)
#define FSM_IOC_MAXNR (12)
#ifdef CONFIG_COMPAT
#define FSM_IOC_GET_RESULT32 _IOR(FSM_IOC_MAGIC, 9, compat_uptr_t)
#define FSM_IOC_SEND_APR32 _IOWR(FSM_IOC_MAGIC, 11, compat_uptr_t)
#endif
struct fsm_misc_args {
uint16_t scene;
int srate;
int bclk;
// init
bool force_init;
// re25
bool force_calib;
bool store_otp;
// f0
uint16_t freq_start;
uint16_t freq_end;
uint16_t freq_step;
uint16_t freq_count;
};
#endif
struct fsm_dev {
struct i2c_client *i2c;
#if defined(CONFIG_FSM_REGMAP)
struct regmap *regmap;
#endif
struct list_head list;
#if defined(__KERNEL__)
struct workqueue_struct *fsm_wq;
struct delayed_work init_work;
struct delayed_work monitor_work;
struct delayed_work interrupt_work;
struct mutex i2c_lock;
int irq_id;
#endif
struct fsm_ops dev_ops;
struct preset_file *preset;
struct dev_list *dev_list;
struct fsm_state state;
struct fsm_compat compat;
struct fsm_test_data *tdata;
uint16_t bus : 8;
uint16_t addr : 8;
uint16_t version;
uint16_t revid;
uint16_t ram_scene[FSM_EQ_RAM_MAX];
uint16_t own_scene;
uint16_t cur_scene;
uint16_t cal_count;
uint16_t tmax;
uint16_t tcoef;
uint16_t tsel;
uint16_t rapp;
uint16_t rstrim;
uint16_t pos_mask : 8; // position
uint16_t acc_count : 8; // acc-key count
uint16_t rec_count;
uint16_t load_fw : 1;
uint16_t use_irq : 1;
uint16_t is1603s : 1;
uint16_t is1801 : 1;
uint16_t is1820 : 1;
uint16_t is1958 : 1;
int rst_gpio;
int irq_gpio;
int id;
int spkr;
int re25;
int re25_dft;
int f0;
int errcode;
char const *dev_name;
};
typedef struct fsm_dev fsm_dev_t;
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,136 @@
/**
* Copyright (C) Fourier Semiconductor Inc. 2016-2020. All rights reserved.
* 2019-02-22 File created.
*/
#if defined(CONFIG_FSM_FIRMWARE)
#include "fsm_public.h"
#include <linux/firmware.h>
#include <linux/slab.h>
static int g_fsm_fw_init = 0;
#ifdef FSM_UNUSED_CODE
static void *fsm_devm_kzalloc(struct device *dev, void *buf, size_t size)
{
char *devm_buf = devm_kzalloc(dev, size, GFP_KERNEL);
if (!devm_buf) {
return devm_buf;
} else {
memcpy(devm_buf, buf, size);
}
return devm_buf;
}
static void fsm_devm_kfree(struct device *dev, void **buf)
{
if (*buf) {
devm_kfree(dev, *buf);
*buf = NULL;
}
}
#endif
static void fsm_firmware_inited(const struct firmware *cont, void *context)
{
struct device *dev = (struct device *)context;
int ret;
if (dev == NULL || cont == NULL) {
pr_err("bad parameter");
return;
}
pr_info("size: %zu", cont->size);
fsm_mutex_lock();
ret = fsm_parse_preset(cont->data, (uint32_t)cont->size);
fsm_mutex_unlock();
release_firmware(cont);
if (ret) {
pr_err("parse firmware fail: %d", ret);
g_fsm_fw_init = 0;
}
}
int fsm_firmware_init(char *fw_name)
{
struct device *dev;
int ret;
if (fw_name == NULL) {
pr_err("invalid firmware name");
return -EINVAL;
}
if (fsm_get_presets() || g_fsm_fw_init) {
return MODULE_INITED;
}
dev = fsm_get_pdev();
if (dev == NULL) {
pr_err("invalid device");
return -EINVAL;
}
pr_info("loading %s in nowait mode", fw_name);
ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
fw_name, dev, GFP_KERNEL,
dev, fsm_firmware_inited);
if (ret) {
pr_err("request %s failed: %d\n", fw_name, ret);
return ret;
}
g_fsm_fw_init = 1;
return ret;
}
int fsm_firmware_init_sync(char *fw_name)
{
fsm_config_t *cfg = fsm_get_config();
const struct firmware *fw_cont;
struct device *dev;
int ret;
if (fw_name == NULL) {
pr_err("invalid firmware name");
return -EINVAL;
}
if (cfg->force_fw) {
pr_info("force loading");
cfg->force_fw = false;
fsm_set_presets(NULL);
}
if (fsm_get_presets()) {
return MODULE_INITED;
}
dev = fsm_get_pdev();
if (dev == NULL) {
pr_err("invalid device");
return -EINVAL;
}
g_fsm_fw_init = 0;
pr_info("loading %s in sync mode", fw_name);
ret = request_firmware(&fw_cont, fw_name, dev);
if (ret) {
pr_err("request %s failed: %d\n", fw_name, ret);
return ret;
}
ret = fsm_parse_preset(fw_cont->data, (uint32_t)fw_cont->size);
release_firmware(fw_cont);
if (ret) {
pr_err("parse firmware fail: %d", ret);
return ret;
}
g_fsm_fw_init = 1;
return ret;
}
void fsm_firmware_deinit(void)
{
fsm_set_presets(NULL);
g_fsm_fw_init = 0;
}
#endif

View file

@ -0,0 +1,673 @@
/*
* Copyright (C) Fourier Semiconductor Inc. 2016-2020. All rights reserved.
*/
#include "fsm_public.h"
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/version.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#ifdef CONFIG_OF
#include <linux/of.h>
#include <linux/of_gpio.h>
#endif
#if defined(CONFIG_REGULATOR)
#include <linux/regulator/consumer.h>
static struct regulator *g_fsm_vdd = NULL;
#endif
static DEFINE_MUTEX(g_fsm_mutex);
static struct device *g_fsm_pdev = NULL;
/* customize configrature */
#include "fsm_firmware.c"
#include "fsm_misc.c"
//#include "fsm_codec.c"
void fsm_mutex_lock()
{
mutex_lock(&g_fsm_mutex);
}
void fsm_mutex_unlock()
{
mutex_unlock(&g_fsm_mutex);
}
int fsm_i2c_reg_read(fsm_dev_t *fsm_dev, uint8_t reg, uint16_t *pVal)
{
struct i2c_msg msgs[2];
uint8_t retries = 0;
uint8_t buffer[2];
int ret;
if (!fsm_dev || !fsm_dev->i2c || !pVal) {
return -EINVAL;
}
// write register address.
msgs[0].addr = fsm_dev->i2c->addr;
msgs[0].flags = 0;
msgs[0].len = 1;
msgs[0].buf = &reg;
// read register buffer.
msgs[1].addr = fsm_dev->i2c->addr;
msgs[1].flags = I2C_M_RD;
msgs[1].len = 2;
msgs[1].buf = &buffer[0];
do {
mutex_lock(&fsm_dev->i2c_lock);
ret = i2c_transfer(fsm_dev->i2c->adapter, &msgs[0], ARRAY_SIZE(msgs));
mutex_unlock(&fsm_dev->i2c_lock);
if (ret != ARRAY_SIZE(msgs)) {
fsm_delay_ms(5);
retries++;
}
} while (ret != ARRAY_SIZE(msgs) && retries < FSM_I2C_RETRY);
if (ret != ARRAY_SIZE(msgs)) {
pr_err("read %02x transfer error: %d", reg, ret);
return -EIO;
}
*pVal = ((buffer[0] << 8) | buffer[1]);
return 0;
}
int fsm_i2c_reg_write(fsm_dev_t *fsm_dev, uint8_t reg, uint16_t val)
{
struct i2c_msg msgs[1];
uint8_t retries = 0;
uint8_t buffer[3];
int ret;
if (!fsm_dev || !fsm_dev->i2c) {
return -EINVAL;
}
buffer[0] = reg;
buffer[1] = (val >> 8) & 0x00ff;
buffer[2] = val & 0x00ff;
msgs[0].addr = fsm_dev->i2c->addr;
msgs[0].flags = 0;
msgs[0].len = sizeof(buffer);
msgs[0].buf = &buffer[0];
do {
mutex_lock(&fsm_dev->i2c_lock);
ret = i2c_transfer(fsm_dev->i2c->adapter, &msgs[0], ARRAY_SIZE(msgs));
mutex_unlock(&fsm_dev->i2c_lock);
if (ret != ARRAY_SIZE(msgs)) {
fsm_delay_ms(5);
retries++;
}
} while (ret != ARRAY_SIZE(msgs) && retries < FSM_I2C_RETRY);
if (ret != ARRAY_SIZE(msgs)) {
pr_err("write %02x transfer error: %d", reg, ret);
return -EIO;
}
return 0;
}
int fsm_i2c_bulkwrite(fsm_dev_t *fsm_dev, uint8_t reg,
uint8_t *data, int len)
{
uint8_t retries = 0;
uint8_t *buf;
int size;
int ret;
if (!fsm_dev || !fsm_dev->i2c || !data) {
return -EINVAL;
}
size = sizeof(uint8_t) + len;
buf = (uint8_t *)fsm_alloc_mem(size);
if (!buf) {
pr_err("alloc memery failed");
return -ENOMEM;
}
buf[0] = reg;
memcpy(&buf[1], data, len);
do {
mutex_lock(&fsm_dev->i2c_lock);
ret = i2c_master_send(fsm_dev->i2c, buf, size);
mutex_unlock(&fsm_dev->i2c_lock);
if (ret < 0) {
fsm_delay_ms(5);
retries++;
} else if (ret == size) {
break;
}
} while (ret != size && retries < FSM_I2C_RETRY);
fsm_free_mem((void **)&buf);
if (ret != size) {
pr_err("write %02x transfer error: %d", reg, ret);
return -EIO;
}
return 0;
}
bool fsm_set_pdev(struct device *dev)
{
if (g_fsm_pdev == NULL || dev == NULL) {
g_fsm_pdev = dev;
// pr_debug("dev_name: %s", dev_name(dev));
return true;
}
return false; // already got device
}
struct device *fsm_get_pdev(void)
{
return g_fsm_pdev;
}
int fsm_vddd_on(struct device *dev)
{
fsm_config_t *cfg = fsm_get_config();
int ret = 0;
if (!cfg || cfg->vddd_on) {
return 0;
}
#if defined(CONFIG_REGULATOR)
g_fsm_vdd = regulator_get(dev, "fsm_vddd");
if (IS_ERR(g_fsm_vdd) != 0) {
pr_err("error getting fsm_vddd regulator");
ret = PTR_ERR(g_fsm_vdd);
g_fsm_vdd = NULL;
return ret;
}
pr_info("enable regulator");
regulator_set_voltage(g_fsm_vdd, 1800000, 1800000);
ret = regulator_enable(g_fsm_vdd);
if (ret < 0) {
pr_err("enabling fsm_vddd failed: %d", ret);
}
#endif
cfg->vddd_on = 1;
fsm_delay_ms(10);
return ret;
}
void fsm_vddd_off(void)
{
fsm_config_t *cfg = fsm_get_config();
if (!cfg || !cfg->vddd_on || cfg->dev_count > 0) {
return;
}
#if defined(CONFIG_REGULATOR)
if (g_fsm_vdd) {
pr_info("disable regulator");
regulator_disable(g_fsm_vdd);
regulator_put(g_fsm_vdd);
g_fsm_vdd = NULL;
}
#endif
cfg->vddd_on = 0;
}
int fsm_get_amb_tempr(void)
{
union power_supply_propval psp = { 0 };
struct power_supply *psy;
int tempr = FSM_DFT_AMB_TEMPR;
int vbat = FSM_DFT_AMB_VBAT;
psy = power_supply_get_by_name("battery");
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0))
if (psy && psy->get_property) {
// battery temperatrue
psy->get_property(psy, POWER_SUPPLY_PROP_TEMP, &psp);
tempr = DIV_ROUND_CLOSEST(psp.intval, 10);
psy->get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &psp);
vbat = DIV_ROUND_CLOSEST(psp.intval, 1000);
}
#else
if (psy && psy->desc && psy->desc->get_property) {
// battery temperatrue
psy->desc->get_property(psy, POWER_SUPPLY_PROP_TEMP, &psp);
tempr = DIV_ROUND_CLOSEST(psp.intval, 10);
psy->desc->get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &psp);
vbat = DIV_ROUND_CLOSEST(psp.intval, 1000);
}
#endif
pr_info("vbat:%d, tempr:%d", vbat, tempr);
return tempr;
}
void *fsm_devm_kstrdup(struct device *dev, void *buf, size_t size)
{
char *devm_buf = devm_kzalloc(dev, size + 1, GFP_KERNEL);
if (!devm_buf) {
return devm_buf;
}
memcpy(devm_buf, buf, size);
return devm_buf;
}
static int fsm_set_irq(fsm_dev_t *fsm_dev, bool enable)
{
if (!fsm_dev || fsm_dev->irq_id <= 0) {
return -EINVAL;
}
if (enable)
enable_irq(fsm_dev->irq_id);
else
disable_irq(fsm_dev->irq_id);
return 0;
}
int fsm_set_monitor(fsm_dev_t *fsm_dev, bool enable)
{
fsm_config_t *cfg = fsm_get_config();
if (!cfg || !fsm_dev || !fsm_dev->fsm_wq) {
return -EINVAL;
}
if (!cfg->use_monitor) {
return 0;
}
if (fsm_dev->use_irq) {
return fsm_set_irq(fsm_dev, enable);
}
if (enable) {
queue_delayed_work(fsm_dev->fsm_wq,
&fsm_dev->monitor_work, 5*HZ);
}
else {
if (delayed_work_pending(&fsm_dev->monitor_work)) {
cancel_delayed_work_sync(&fsm_dev->monitor_work);
}
}
return 0;
}
static int fsm_ext_reset(fsm_dev_t *fsm_dev)
{
fsm_config_t *cfg = fsm_get_config();
uint16_t id = 0;
int addr;
int ret;
if (!cfg || !fsm_dev) {
return -EINVAL;
}
if (cfg->reset_chip) {
return 0;
}
if (gpio_is_valid(fsm_dev->rst_gpio)) {
gpio_set_value(fsm_dev->rst_gpio, 0);
fsm_delay_ms(10); // mdelay
gpio_set_value(fsm_dev->rst_gpio, 1);
fsm_delay_ms(1); // mdelay
// TODO: for sharing reset pin in multi-pa application
// cfg->reset_chip = true;
}
fsm_mutex_lock();
/* soft reset */
addr = fsm_dev->i2c->addr;
ret = fsm_reg_read(fsm_dev, 0x01, &id);
if (ret && addr != 0x34) {
fsm_dev->i2c->addr = 0x34;
ret = fsm_reg_read(fsm_dev, 0x01, &id);
}
if (!ret && LOW8(id) == FS1815_DEV_ID) {
fsm_reg_write(fsm_dev, 0x10, 0x0002);
fsm_delay_ms(15);
} else {
ret = -ENODEV;
}
fsm_dev->i2c->addr = addr;
fsm_mutex_unlock();
return 0;
}
static irqreturn_t fsm_irq_hander(int irq, void *data)
{
fsm_dev_t *fsm_dev = data;
queue_delayed_work(fsm_dev->fsm_wq, &fsm_dev->interrupt_work, 0);
return IRQ_HANDLED;
}
static void fsm_work_monitor(struct work_struct *work)
{
fsm_config_t *cfg = fsm_get_config();
fsm_dev_t *fsm_dev;
//int ret;
fsm_dev = container_of(work, struct fsm_dev, monitor_work.work);
if (!cfg || cfg->skip_monitor || !fsm_dev) {
return;
}
fsm_mutex_lock();
//ret = fsm_dev_recover(fsm_dev);
fsm_mutex_unlock();
if (fsm_dev->rec_count >= 5) { // 5 time max
pr_addr(warning, "recover max time, stop it");
return;
}
/* reschedule */
queue_delayed_work(fsm_dev->fsm_wq, &fsm_dev->monitor_work,
5*HZ);
}
static void fsm_work_interrupt(struct work_struct *work)
{
fsm_config_t *cfg = fsm_get_config();
fsm_dev_t *fsm_dev;
//int ret;
fsm_dev = container_of(work, struct fsm_dev, interrupt_work.work);
if (!cfg || cfg->skip_monitor || !fsm_dev) {
return;
}
fsm_mutex_lock();
//ret = fsm_dev_recover(fsm_dev);
//fsm_get_spkr_tempr(fsm_dev);
fsm_mutex_unlock();
}
static int fsm_request_irq(fsm_dev_t *fsm_dev)
{
struct i2c_client *i2c;
int irq_flags;
int ret;
if (fsm_dev == NULL || fsm_dev->i2c == NULL) {
return -EINVAL;
}
fsm_dev->irq_id = -1;
if (!fsm_dev->use_irq || !gpio_is_valid(fsm_dev->irq_gpio)) {
pr_addr(info, "skip to request irq");
return 0;
}
i2c = fsm_dev->i2c;
/* register irq handler */
fsm_dev->irq_id = gpio_to_irq(fsm_dev->irq_gpio);
if (fsm_dev->irq_id <= 0) {
dev_err(&i2c->dev, "invalid irq %d\n", fsm_dev->irq_id);
return -EINVAL;
}
irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
ret = devm_request_threaded_irq(&i2c->dev, fsm_dev->irq_id,
NULL, fsm_irq_hander, irq_flags, "fs16xx", fsm_dev);
if (ret) {
dev_err(&i2c->dev, "failed to request IRQ %d: %d\n",
fsm_dev->irq_id, ret);
return ret;
}
disable_irq(fsm_dev->irq_id);
return 0;
}
#ifdef CONFIG_OF
static int fsm_parse_dts(struct i2c_client *i2c, fsm_dev_t *fsm_dev)
{
struct device_node *np = i2c->dev.of_node;
uint8_t dummy_addr;
char *str_name;
int ret;
if (fsm_dev == NULL || np == NULL) {
return -EINVAL;
}
str_name = devm_kzalloc(&i2c->dev, 32, GFP_KERNEL);
fsm_dev->rst_gpio = of_get_named_gpio(np, "fsm,rst-gpio", 0);
if (gpio_is_valid(fsm_dev->rst_gpio)) {
snprintf(str_name, 32, "FS1815_SDZ_%02X", i2c->addr);
ret = devm_gpio_request_one(&i2c->dev, fsm_dev->rst_gpio,
GPIOF_OUT_INIT_LOW, str_name);
if (ret)
return ret;
}
ret = of_property_read_u8(np, "fsm,dummy-addr", &dummy_addr);
if (ret)
dummy_addr = 0;
fsm_dev->addr = dummy_addr;
return 0;
}
static struct of_device_id fsm_match_tbl[] =
{
{ .compatible = "foursemi,fs16xx" },
{ .compatible = "foursemi,fs1815" },
{},
};
MODULE_DEVICE_TABLE(of, fsm_match_tbl);
#endif
static int fsm_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
fsm_config_t *cfg = fsm_get_config();
fsm_dev_t *fsm_dev;
int ret;
pr_debug("enter");
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) {
dev_err(&i2c->dev, "check I2C_FUNC_I2C failed");
return -EIO;
}
fsm_dev = devm_kzalloc(&i2c->dev, sizeof(struct fsm_dev), GFP_KERNEL);
if (fsm_dev == NULL) {
dev_err(&i2c->dev, "alloc memory fialed");
return -ENOMEM;
}
memset(fsm_dev, 0, sizeof(struct fsm_dev));
mutex_init(&fsm_dev->i2c_lock);
fsm_dev->i2c = i2c;
#ifdef CONFIG_OF
ret = fsm_parse_dts(i2c, fsm_dev);
if (ret) {
dev_err(&i2c->dev, "failed to parse DTS node");
return ret;
}
#endif
#if defined(CONFIG_FSM_REGMAP)
fsm_dev->regmap = fsm_regmap_i2c_init(i2c);
if (fsm_dev->regmap == NULL) {
devm_kfree(&i2c->dev, fsm_dev);
dev_err(&i2c->dev, "regmap init fialed");
return -EINVAL;
}
#endif
fsm_vddd_on(&i2c->dev);
fsm_ext_reset(fsm_dev);
ret = fsm_probe(fsm_dev, i2c->addr);
if (ret) {
dev_err(&i2c->dev, "detect device failed");
#if defined(CONFIG_FSM_REGMAP)
fsm_regmap_i2c_deinit(fsm_dev->regmap);
#endif
gpio_set_value(fsm_dev->rst_gpio, 0);
devm_gpio_free(&i2c->dev, fsm_dev->rst_gpio);
devm_kfree(&i2c->dev, fsm_dev);
return ret;
}
fsm_dev->id = cfg->dev_count - 1;
i2c_set_clientdata(i2c, fsm_dev);
pr_addr(info, "index:%d", fsm_dev->id);
fsm_dev->fsm_wq = create_singlethread_workqueue("fs16xx");
INIT_DELAYED_WORK(&fsm_dev->monitor_work, fsm_work_monitor);
INIT_DELAYED_WORK(&fsm_dev->interrupt_work, fsm_work_interrupt);
fsm_request_irq(fsm_dev);
if(fsm_dev->id == 0) {
// reigster only in the first device
#if !defined(CONFIG_FSM_CODEC)
fsm_set_pdev(&i2c->dev);
#endif
fsm_misc_init();
fsm_sysfs_init(&i2c->dev);
fsm_codec_register(&i2c->dev, fsm_dev->id);
}
dev_info(&i2c->dev, "i2c probe completed");
return 0;
}
static int fsm_i2c_remove(struct i2c_client *i2c)
{
fsm_dev_t *fsm_dev = i2c_get_clientdata(i2c);
pr_debug("enter");
if (fsm_dev == NULL) {
pr_err("bad parameter");
return -EINVAL;
}
if (fsm_dev->fsm_wq) {
cancel_delayed_work_sync(&fsm_dev->interrupt_work);
cancel_delayed_work_sync(&fsm_dev->monitor_work);
destroy_workqueue(fsm_dev->fsm_wq);
}
#if defined(CONFIG_FSM_REGMAP)
fsm_regmap_i2c_deinit(fsm_dev->regmap);
#endif
if (fsm_dev->id == 0) {
fsm_codec_unregister(&i2c->dev);
fsm_sysfs_deinit(&i2c->dev);
fsm_misc_deinit();
fsm_set_pdev(NULL);
}
fsm_remove(fsm_dev);
fsm_vddd_off();
if (gpio_is_valid(fsm_dev->irq_gpio)) {
devm_gpio_free(&i2c->dev, fsm_dev->irq_gpio);
}
if (gpio_is_valid(fsm_dev->rst_gpio)) {
devm_gpio_free(&i2c->dev, fsm_dev->rst_gpio);
}
devm_kfree(&i2c->dev, fsm_dev);
dev_info(&i2c->dev, "i2c removed");
return 0;
}
static void fsm_i2c_shutdown(struct i2c_client *i2c)
{
fsm_dev_t *fsm_dev = i2c_get_clientdata(i2c);
pr_debug("enter");
if (fsm_dev == NULL) {
pr_err("bad parameter");
return;
}
fsm_stub_shut_down(fsm_dev);
if (gpio_is_valid(fsm_dev->rst_gpio))
gpio_set_value(fsm_dev->rst_gpio, 0);
dev_info(&i2c->dev, "i2c shutdowned");
}
static const struct i2c_device_id fsm_i2c_id[] =
{
{ "fs16xx", 0 },
{ "fs1815", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, fsm_i2c_id);
static struct i2c_driver fsm_i2c_driver =
{
.driver = {
.name = FSM_DRV_NAME,
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = of_match_ptr(fsm_match_tbl),
#endif
},
.probe = fsm_i2c_probe,
.remove = fsm_i2c_remove,
.shutdown = fsm_i2c_shutdown,
.id_table = fsm_i2c_id,
};
int exfsm_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
return fsm_i2c_probe(i2c, id);
}
EXPORT_SYMBOL(exfsm_i2c_probe);
int exfsm_i2c_remove(struct i2c_client *i2c)
{
return fsm_i2c_remove(i2c);
}
EXPORT_SYMBOL(exfsm_i2c_remove);
int fsm_i2c_init(void)
{
return i2c_add_driver(&fsm_i2c_driver);
}
void fsm_i2c_exit(void)
{
i2c_del_driver(&fsm_i2c_driver);
}
static int __init fsm_mod_init(void)
{
int ret;
ret = fsm_i2c_init();
if (ret) {
pr_err("init fail: %d", ret);
return ret;
}
return 0;
}
static void __exit fsm_mod_exit(void)
{
fsm_i2c_exit();
}
//module_i2c_driver(fsm_i2c_driver);
module_init(fsm_mod_init);
module_exit(fsm_mod_exit);
MODULE_AUTHOR("FourSemi SW <[email protected]>");
MODULE_DESCRIPTION("FourSemi Smart PA Driver");
MODULE_VERSION(FSM_CODE_VERSION);
MODULE_ALIAS("foursemi:"FSM_DRV_NAME);
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,470 @@
/**
* Copyright (C) Fourier Semiconductor Inc. 2016-2020. All rights reserved.
* 2018-10-16 File created.
*/
#if defined(CONFIG_FSM_MISC)
#include "fsm_public.h"
#ifdef CONFIG_FSM_NONDSP
#include "fsm_q6afe.h"
#endif
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#define FSM_I2C_MAX_LEN (8192)
/*
* misc driver for foursemi devices.
*/
struct fsm_misc {
struct fsm_dev *fsm_dev[FSM_DEV_MAX];
uint8_t addr;
uint8_t index;
};
static int g_misc_opened;
static int fsm_misc_check_params(unsigned int cmd, unsigned long arg)
{
int ret = 0;
if (cmd == FSM_IOC_SET_SLAVE) {
return 0;
}
if (_IOC_TYPE(cmd) != FSM_IOC_MAGIC || _IOC_NR(cmd) >= FSM_IOC_MAXNR) {
return -ENOTTY;
}
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0))
if (_IOC_DIR(cmd) & _IOC_READ) {
ret = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
} else if (_IOC_DIR(cmd) & _IOC_WRITE) {
ret = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
}
#else
ret = !access_ok((void __user *)arg, _IOC_SIZE(cmd));
#endif
return (ret ? -EFAULT : 0);
}
static int fsm_misc_open(struct inode *inode, struct file *filp)
{
struct fsm_misc *fsm_misc;
pr_debug("enter");
if (xchg(&g_misc_opened, 1)) {
pr_warning("device busy now");
return -EBUSY;
}
fsm_misc = fsm_alloc_mem(sizeof(struct fsm_misc));
if (fsm_misc == NULL) {
pr_err("allocat memory fail");
return -EINVAL;
}
memset(fsm_misc, 0, sizeof(struct fsm_misc));
filp->private_data = fsm_misc;
return 0;
}
static int fsm_misc_release(struct inode *inode, struct file *filp)
{
struct fsm_misc *fsm_misc;
pr_debug("enter");
if (!filp) {
return -EINVAL;
}
fsm_misc = filp->private_data;
g_misc_opened = 0;
fsm_free_mem((void **)&fsm_misc);
return 0;
}
static int fsm_misc_set_slave(struct fsm_misc *fsm_misc, uint8_t slave)
{
int index;
if (fsm_misc == NULL) {
return -EINVAL;
}
if (slave < FSM_ADDR_BASE || slave >= FSM_ADDR_BASE + FSM_DEV_MAX) {
pr_err("invalid address:%02X", slave);
return -EINVAL;
}
index = slave - FSM_ADDR_BASE;
if (fsm_misc->fsm_dev[index] == 0) {
fsm_misc->fsm_dev[index] = fsm_get_fsm_dev(slave);
if (fsm_misc->fsm_dev[index] == NULL) {
pr_debug("not found device:%02X", slave);
fsm_misc->addr = 0;
fsm_misc->index = 0;
return -EINVAL;
}
}
fsm_misc->index = index;
fsm_misc->addr = slave;
return 0;
}
static int fsm_misc_cmd_with_args(unsigned int cmd, uint8_t addr,
struct fsm_misc_args *args)
{
fsm_config_t *cfg = fsm_get_config();
if (!cfg || !args) {
pr_err("bad parameters");
return -EINVAL;
}
switch (cmd) {
case FSM_IOC_SET_SRATE:
fsm_set_i2s_clocks(args->srate, args->bclk);
break;
case FSM_IOC_SET_SCENE:
fsm_set_scene(args->scene);
break;
case FSM_IOC_INIT:
cfg->force_init = args->force_init;
fsm_init();
cfg->force_init = 0;
break;
case FSM_IOC_CALIBRATE:
break;
case FSM_IOC_F0_TEST:
break;
default:
pr_err("invalid cmd: %X", cmd);
return -EINVAL;
}
return 0;
}
#ifdef CONFIG_FSM_NONDSP
int fsm_misc_send_apr(void __user *buf)
{
uint32_t header[FSM_AFE_HEADER_LEN];
uint32_t *ptr_data;
struct fsm_afe afe;
int buf_size;
void *buffer;
int ret;
if (!buf) {
pr_err("bad parameter");
return -EINVAL;
}
ret = copy_from_user(header, (void *)buf, sizeof(header));
if (ret) {
pr_err("Copy from user failed! buf = 0x%pK", buf);
return ret;
}
/* buffer:
* [0]: buf_size
* [1]: cmd_size
* [2]: module_id
* [3]: param_id
* [4]: opcode
* [...]: data
*/
buf_size = header[0];
if (buf_size <= 0) {
pr_err("Invalid buffer size = %d", buf_size);
return -EINVAL;
}
buffer = fsm_alloc_mem(buf_size);
afe.module_id = header[2];
if (afe.module_id == AFE_MODULE_ID_FSADSP_TX) {
afe.port_id = fsm_afe_get_tx_port();
} else {
afe.port_id = fsm_afe_get_rx_port();
}
afe.param_id = header[3];
ptr_data = (uint32_t *)buffer;
if (header[4]) { // op_set = 1
ret = copy_from_user(buffer, (void *)buf, buf_size);
if (ret) {
pr_err("copy from user fail:%d", ret);
goto exit;
}
afe.op_set = true;
ret = fsm_afe_send_apr(&afe, &ptr_data[5],
(buf_size - FSM_AFE_HEADER_LEN * sizeof(uint32_t)));
if (ret) {
pr_err("set params fail:%d", ret);
goto exit;
}
} else {
afe.op_set = false;
ret = fsm_afe_send_apr(&afe, &ptr_data[5],
(buf_size - FSM_AFE_HEADER_LEN * sizeof(uint32_t)));
if (ret) {
pr_err("get params fail:%d", ret);
goto exit;
}
// set ptr_data[0] = total size
ptr_data[0] = afe.param_size + FSM_AFE_HEADER_LEN * sizeof(uint32_t);
ret = copy_to_user((void __user *)buf, buffer, ptr_data[0]);
if (ret) {
pr_err("copy to user fail:%d", ret);
goto exit;
}
}
exit:
fsm_free_mem((void **)&buffer);
return ret;
}
#endif
static long fsm_misc_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
struct fsm_misc_args misc_args;
struct fsm_misc *fsm_misc;
int count;
int ret;
if (filp == NULL || filp->private_data == NULL) {
pr_err("invalid parameter");
return -EINVAL;
}
fsm_misc = filp->private_data;
ret = fsm_misc_check_params(cmd, arg);
if (ret) {
pr_err("invalid params: %X, %lX", cmd, arg);
return ret;
}
pr_debug("cmd:%X, arg:%lX", cmd, arg);
switch (cmd) {
case FSM_IOC_SET_SLAVE:
case FSM_IOC_SET_ADDR:
ret = fsm_misc_set_slave(fsm_misc, arg & 0xFF);
break;
case FSM_IOC_GET_DEVICE:
count = fsm_dev_count();
ret = copy_to_user((int *)arg, &count, sizeof(count));
if (ret) {
pr_err("cmd:%X, copy to user fail:%d", cmd, ret);
return -EFAULT;
}
break;
case FSM_IOC_SET_SRATE:
case FSM_IOC_SET_SCENE:
case FSM_IOC_INIT:
case FSM_IOC_CALIBRATE:
case FSM_IOC_F0_TEST:
ret = copy_from_user(&misc_args, (void *)arg, sizeof(misc_args));
if (ret) {
pr_err("cmd:%X, copy from user fail:%d", cmd, ret);
return -EFAULT;
}
ret = fsm_misc_cmd_with_args(cmd, fsm_misc->addr, &misc_args);
if (ret) {
pr_err("cmd:%X, error:%d", cmd, ret);
}
break;
case FSM_IOC_SPEAKER_ON:
fsm_speaker_onn();
break;
case FSM_IOC_SPEAKER_OFF:
fsm_speaker_off();
break;
case FSM_IOC_GET_RESULT:
break;
#ifdef CONFIG_FSM_NONDSP
case FSM_IOC_SEND_APR:
ret = fsm_misc_send_apr((void __user *)arg);
if (ret) {
pr_err("send apr fail:%d", ret);
}
break;
#endif
default:
pr_err("unknown cmd:%X", cmd);
ret = -EINVAL;
}
return ret;
}
#if defined(CONFIG_COMPAT)
static long fsm_misc_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
switch (cmd) {
case FSM_IOC_GET_RESULT32:
cmd = FSM_IOC_GET_RESULT;
break;
#ifdef CONFIG_FSM_NONDSP
case FSM_IOC_SEND_APR:
case FSM_IOC_SEND_APR32:
cmd = FSM_IOC_SEND_APR;
break;
#endif
default:
break;
}
return fsm_misc_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
}
#endif
static ssize_t fsm_misc_read(struct file *filp, char __user *buf,
size_t count, loff_t *offset)
{
fsm_config_t *cfg = fsm_get_config();
struct fsm_misc *fsm_misc;
struct fsm_dev *fsm_dev;
int retries = FSM_I2C_RETRY;
uint8_t *tmp;
int ret;
if (cfg == NULL || filp == NULL || filp->private_data == NULL) {
pr_err("invalid parameter");
return -EINVAL;
}
if (count > FSM_I2C_MAX_LEN) {
count = FSM_I2C_MAX_LEN;
}
tmp = fsm_alloc_mem(count);
if (tmp == NULL) {
return -ENOMEM;
}
if (cfg->skip_monitor == false) {
cfg->skip_monitor = true;
}
fsm_misc = filp->private_data;
do {
fsm_dev = fsm_misc->fsm_dev[fsm_misc->index];
if (fsm_dev == NULL || fsm_dev->i2c == NULL) {
ret = -EINVAL;
break;
}
mutex_lock(&fsm_dev->i2c_lock);
ret = i2c_master_recv(fsm_dev->i2c, tmp, count);
mutex_unlock(&fsm_dev->i2c_lock);
if (ret != count) {
fsm_delay_ms(5);
}
// pr_debug("data: 0x%02x", tmp[0]);
} while((ret != count) && (--retries >= 0));
if (ret == count) {
ret = (copy_to_user(buf, tmp, count) ? -EFAULT : ret);
} else {
pr_err("%02X: reading %zu bytes failed:%d",
fsm_misc->addr, count, ret);
}
fsm_free_mem((void **)&tmp);
return ret;
}
static ssize_t fsm_misc_write(struct file *filp, const char __user *buf,
size_t count, loff_t *offset)
{
fsm_config_t *cfg = fsm_get_config();
struct fsm_misc *fsm_misc;
struct fsm_dev *fsm_dev;
int retries = FSM_I2C_RETRY;
uint8_t *tmp;
int ret;
if (cfg == NULL || filp == NULL || filp->private_data == NULL) {
pr_err("invalid parameter");
return -EINVAL;
}
if (count > FSM_I2C_MAX_LEN) {
count = FSM_I2C_MAX_LEN;
}
tmp = memdup_user(buf, count);
if (IS_ERR(tmp)) {
return PTR_ERR(tmp);
}
if (cfg->skip_monitor == false) {
cfg->skip_monitor = true;
}
fsm_misc = filp->private_data;
do {
fsm_dev = fsm_misc->fsm_dev[fsm_misc->index];
if (fsm_dev == NULL || fsm_dev->i2c == NULL) {
ret = -EINVAL;
break;
}
// pr_debug("data: 0x%02x-0x%02x", buf[0], tmp[0]);
mutex_lock(&fsm_dev->i2c_lock);
ret = i2c_master_send(fsm_dev->i2c, tmp, count);
mutex_unlock(&fsm_dev->i2c_lock);
if (ret != count) {
fsm_delay_ms(5);
}
} while((ret != count) && (--retries >= 0));
if (ret != count) {
pr_err("%02X: writing %zu bytes failed:%d",
fsm_misc->addr, count, ret);
}
kfree(tmp);
return ret;
}
static const struct file_operations g_fsm_misc_ops = {
.owner = THIS_MODULE,
.open = fsm_misc_open,
.read = fsm_misc_read,
.write = fsm_misc_write,
.release = fsm_misc_release,
.llseek = no_llseek,
.unlocked_ioctl = fsm_misc_ioctl,
#if defined(CONFIG_COMPAT)
.compat_ioctl = fsm_misc_compat_ioctl,
#endif
};
struct miscdevice g_fsm_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = FSM_DRV_NAME,
.fops = &g_fsm_misc_ops,
.this_device = NULL,
};
int fsm_misc_init(void)
{
struct miscdevice *misc = &g_fsm_misc;
int ret;
pr_debug("enter");
if (misc->this_device) {
return 0;
}
ret = misc_register(misc);
if (ret) {
misc->this_device = NULL;
}
FSM_FUNC_EXIT(ret);
return ret;
}
void fsm_misc_deinit(void)
{
struct miscdevice *misc = &g_fsm_misc;
pr_debug("enter");
if (misc->this_device == NULL) {
return;
}
misc_deregister(misc);
}
#endif

View file

@ -0,0 +1,241 @@
/**
* Copyright (C) Fourier Semiconductor Inc. 2016-2020. All rights reserved.
* 2018-10-18 File created.
*/
#ifndef __FSM_PUBLIC_H__
#define __FSM_PUBLIC_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "fsm-dev.h"
#include <sound/soc.h>
#include <linux/version.h>
/*
* module: fsm_regmap
*/
#if defined(CONFIG_FSM_REGMAP)
#include <linux/regmap.h>
int fsm_regmap_write(fsm_dev_t *fsm_dev, uint8_t reg, uint16_t val);
int fsm_regmap_bulkwrite(fsm_dev_t *fsm_dev, uint8_t reg, uint8_t *pval, uint32_t len);
int fsm_regmap_read(fsm_dev_t *fsm_dev, uint8_t reg, uint16_t *pval);
int fsm_regmap_bulkread(fsm_dev_t *fsm_dev, uint8_t reg, uint8_t *pval, uint32_t len);
int fsm_regmap_update_bits(fsm_dev_t *fsm_dev, uint8_t reg, uint8_t mask, uint8_t val);
struct regmap *fsm_regmap_i2c_init(struct i2c_client *i2c);
int fsm_regmap_i2c_deinit(struct regmap *map);
#else
#define fsm_regmap_i2c_deinit(...)
#endif
/*
* module: fsm_i2c
*/
#if defined(CONFIG_FSM_I2C)
#include <linux/i2c.h>
bool fsm_set_pdev(struct device *dev);
struct device *fsm_get_pdev(void);
void *fsm_devm_kstrdup(struct device *dev, void *buf, size_t size);
int fsm_i2c_reg_read(fsm_dev_t *fsm_dev, uint8_t reg, uint16_t *pVal);
int fsm_i2c_reg_write(fsm_dev_t *fsm_dev, uint8_t reg, uint16_t val);
int fsm_i2c_bulkwrite(fsm_dev_t *fsm_dev, uint8_t reg,
uint8_t *data, int len);
int fsm_get_amb_tempr(void);
int fsm_read_efsdata(struct fsm_calib_v2 *data);
int fsm_write_efsdata(struct fsm_calib_v2 *data);
int fsm_i2c_save_re25(struct fsm_calib_v2 *calib_data);
int fsm_i2c_init(void);
void fsm_i2c_exit(void);
#else
#define fsm_get_amb_tempr(...) (FSM_DFT_AMB_TEMPR)
#endif
void fsm_mutex_lock(void);
void fsm_mutex_unlock(void);
/*
* module: fsm_misc
*/
#if defined(CONFIG_FSM_MISC)
int fsm_misc_init(void);
void fsm_misc_deinit(void);
#else
#define fsm_misc_init(...)
#define fsm_misc_deinit(...)
#endif
/*
* module: fsm_sysfs
*/
#if defined(CONFIG_FSM_SYSFS)
int fsm_sysfs_init(struct device *dev);
void fsm_sysfs_deinit(struct device *dev);
#else
#define fsm_sysfs_init(...)
#define fsm_sysfs_deinit(...)
#endif
/*
* module: fsm_firmware
*/
#if defined(CONFIG_FSM_FIRMWARE)
int fsm_firmware_init(char *fw_name);
int fsm_firmware_init_sync(char *fw_name);
void fsm_firmware_deinit(void);
#elif defined(FSM_HAL_SUPPORT)
int fsm_firmware_init_sync(char *fw_name);
void fsm_firmware_deinit(void);
#else
#define fsm_firmware_init(...) (-1)
#define fsm_firmware_init_sync(...) (-1)
#define fsm_firmware_deinit(...)
#endif
/*
* module: fsm_codec
*/
#if defined(CONFIG_FSM_CODEC)
int fsm_codec_register(struct device *dev, int id);
void fsm_codec_unregister(struct device *dev);
#else
#define fsm_codec_register(...)
#define fsm_codec_unregister(...)
#endif
/*
* module: fsm_core
*/
fsm_config_t *fsm_get_config(void);
void *fsm_get_presets(void);
void fsm_set_presets(void *preset);
void fsm_get_version(fsm_version_t *version);
void fsm_delay_ms(uint32_t delay_ms);
void *fsm_alloc_mem(int size);
void fsm_free_mem(void **buf);
uint16_t set_bf_val(uint16_t *pval, const uint16_t bf, const uint16_t bf_val);
uint16_t get_bf_val(const uint16_t bf, const uint16_t val);
int fsm_set_bf(fsm_dev_t *fsm_dev, const uint16_t bf, const uint16_t val);
int fsm_get_bf(fsm_dev_t *fsm_dev, const uint16_t bf, uint16_t *pval);
int fsm_reg_write(fsm_dev_t *fsm_dev, uint8_t reg, uint16_t val);
int fsm_reg_read(fsm_dev_t *fsm_dev, uint8_t reg, uint16_t *pval);
int fsm_reg_update_bits(fsm_dev_t *fsm_dev, reg_unit_t *reg);
int fsm_reg_update(fsm_dev_t *fsm_dev, uint8_t reg, uint16_t val);
int fsm_reg_multiread(fsm_dev_t *fsm_dev, uint8_t reg, uint16_t *pval);
int fsm_burst_write(fsm_dev_t *fsm_dev, uint8_t reg, uint8_t *data, int len);
uint16_t fsm_calc_checksum(uint16_t *data, int len);
struct fsm_dev *fsm_get_fsm_dev(uint8_t addr);
struct fsm_dev *fsm_get_fsm_dev_by_id(int id);
int fsm_read_vbat(fsm_dev_t *fsm_dev, uint16_t *vbat);
int fsm_get_srate_bits(fsm_dev_t *fsm_dev, uint32_t srate);
int fsm_access_key(fsm_dev_t *fsm_dev, int access);
int fsm_reg_dump(fsm_dev_t *fsm_dev);
int fsm_init_dev_list(fsm_dev_t *fsm_dev);
int fsm_init_info(fsm_dev_t *fsm_dev);
void *fsm_get_list_by_idx(fsm_dev_t *fsm_dev, int idx);
void *fsm_get_data_list(fsm_dev_t *fsm_dev, int type);
int fsm_get_spk_info(fsm_dev_t *fsm_dev, uint16_t info_type);
int zero_bit_counter(uint8_t byte);
int get_otp_counter(uint16_t byte);
int get_otp_max_count(fsm_dev_t *fsm_dev);
void convert_data_to_bytes(uint32_t val, uint8_t *buf);
int get_re25_from_buf(struct fsm_calib_v2 *data,
char *buf, int buf_len);
int set_re25_to_buf(struct fsm_calib_v2 *data,
char *buf, int buf_len);
int fsm_parse_preset(const void *data, uint32_t size);
int fsm_write_preset(fsm_dev_t *fsm_dev);
int fsm_swap_channel(fsm_dev_t *fsm_dev, int next_angle);
int fsm_set_monitor(fsm_dev_t *fsm_dev, bool enable);
int fsm_wait_stable(fsm_dev_t *fsm_dev, int type);
int fsm_parse_otp(fsm_dev_t *fsm_dev, uint16_t value, int *re25, int *count);
int fsm_config_vol(fsm_dev_t *fsm_dev);
int fsm_dev_recover(fsm_dev_t *fsm_dev);
int fsm_get_spkr_tempr(fsm_dev_t *fsm_dev);
int fsm_ops_dummy(fsm_dev_t *fsm_dev);
int fsm_write_reg_tbl(fsm_dev_t *fsm_dev, uint16_t scene);
int fsm_set_cal_scene(fsm_dev_t *fsm_dev);
int fsm_get_livedata(fsm_msg_t *data);
int fsm_save_re25(struct fsm_calib_v2 *data);
int fsm_get_re25(struct fsm_calib_v2 *data);
uint32_t fsm_cal_spkr_zmimp(fsm_dev_t *fsm_dev, uint16_t data);
int fsm_skip_device(fsm_dev_t *fsm_dev);
int fsm_cal_zmdata(fsm_dev_t *fsm_dev);
int fsm_get_rstrim(fsm_dev_t *fsm_dev);
uint16_t fsm_cal_threshold(fsm_dev_t *fsm_dev,
int mt_type, uint16_t zmdata);
int fsm_check_otp(fsm_dev_t *fsm_dev);
int fsm_check_without_otp(fsm_dev_t *fsm_dev);
int fsm_stub_dev_init(fsm_dev_t *fsm_dev);
int fsm_stub_start_up(fsm_dev_t *fsm_dev);
int fsm_stub_check_stable(fsm_dev_t *fsm_dev, int type);
int fsm_stub_store_re25(fsm_dev_t *fsm_dev);
int fsm_stub_pre_calib(fsm_dev_t *fsm_dev);
int fsm_stub_post_calib(fsm_dev_t *fsm_dev);
int fsm_stub_set_mute(fsm_dev_t *fsm_dev, bool mute);
int fsm_stub_set_tsignal(fsm_dev_t *fsm_dev, bool enable);
int fsm_stub_shut_down(fsm_dev_t *fsm_dev);
int fsm_stub_dev_deinit(fsm_dev_t *fsm_dev);
/*
* module: fsm_hal
*/
#if defined(FSM_HAL_SUPPORT)
int fsm_open_device(void);
void fsm_close_device(void);
int fsm_check_device(char *dev_name);
int fsm_hal_open(void);
int fsm_hal_reg_read(fsm_dev_t *fsm_dev, uint8_t reg, uint16_t *val);
int fsm_hal_reg_write(fsm_dev_t *fsm_dev, uint8_t reg, uint16_t val);
int fsm_hal_bulkwrite(fsm_dev_t *fsm_dev, uint8_t reg, uint8_t *val, uint32_t len);
int fsm_hal_bulkread(fsm_dev_t *fsm_dev, uint8_t reg, uint32_t len, uint8_t *val);
int fsm_hal_get_livedata(fsm_msg_t *data);
int fsm_hal_save_re25(struct fsm_calib_v2 *data);
int fsm_hal_get_re25(struct fsm_calib_v2 *data);
int fstool_reg_read(uint8_t addr, uint8_t reg, uint16_t *val);
int fstool_reg_write(uint8_t addr, uint8_t reg, uint16_t val);
int fstool_bulkwrite(uint8_t addr, uint8_t reg,
uint32_t len, uint8_t *val);
int fstool_bulkread(uint8_t addr, uint8_t reg,
uint32_t len, uint8_t *val);
void fsm_hal_close(void);
#else
#define fsm_hal_open(...) (0)
#define fsm_hal_close(...)
#endif
void fsm_set_fw_name(char *name);
int fsm_probe(fsm_dev_t *fsm_dev, int addr);
void fsm_remove(fsm_dev_t *fsm_dev);
int fsm_dev_count(void);
void fsm_set_i2s_clocks(uint32_t rate, uint32_t bclk);
void fsm_set_tx_format(uint32_t format);
void fsm_set_scene(int scene);
void fsm_set_volume(int volume);
void fsm_set_cfg_flag(int pos, int mark);
void fsm_init(void);
void fsm_speaker_onn(void);
void fsm_speaker_off(void);
void fsm_stereo_rotation(int next_angle);
void fsm_batv_monitor(void);
void fsm_re25_test(bool force);
void fsm_f0_test(void);
int fsm_test_result(struct fsm_cal_result *result, int size);
void fsm_dump(void);
void fsm_deinit(void);
void fs1815_ops(fsm_dev_t *fsm_dev);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0))
#define snd_soc_codec snd_soc_component
#define snd_soc_add_codec_controls snd_soc_add_component_controls
#define snd_soc_codec_get_drvdata snd_soc_component_get_drvdata
#endif
void fsm_add_codec_controls(struct snd_soc_codec *codec);
void fsm_add_card_controls(struct snd_soc_card *card);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -604,7 +604,7 @@ void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
mbhc->hph_type = WCD_MBHC_HPH_NONE;
mbhc->zl = mbhc->zr = 0;
pr_debug("%s: Reporting removal %d(%x)\n", __func__,
pr_info("%s: Reporting removal %d(%x)\n", __func__,
jack_type, mbhc->hph_status);
wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
mbhc->hph_status, WCD_MBHC_JACK_MASK);
@ -647,7 +647,7 @@ void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
mbhc->hph_type = WCD_MBHC_HPH_NONE;
mbhc->zl = mbhc->zr = 0;
if (!mbhc->force_linein) {
pr_debug("%s: Reporting removal (%x)\n",
pr_info("%s: Reporting removal (%x)\n",
__func__, mbhc->hph_status);
wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
0, WCD_MBHC_JACK_MASK);
@ -711,8 +711,12 @@ void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
&mbhc->zl, &mbhc->zr);
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN,
fsm_en);
if ((mbhc->zl > mbhc->mbhc_cfg->linein_th) &&
(mbhc->zr > mbhc->mbhc_cfg->linein_th) &&
pr_info("%s,compute impedance,zl = %d,zr = %d\n",
__func__, mbhc->zl, mbhc->zr);
if ((((mbhc->zl > mbhc->mbhc_cfg->linein_th) &&
(mbhc->zr > mbhc->mbhc_cfg->linein_th)) ||
(mbhc->zl == 0) ||
(mbhc->zr == 0)) &&
(jack_type == SND_JACK_HEADPHONE)) {
jack_type = SND_JACK_LINEOUT;
mbhc->force_linein = true;
@ -731,7 +735,7 @@ void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
mbhc->hph_status,
WCD_MBHC_JACK_MASK);
}
pr_debug("%s: Marking jack type as SND_JACK_LINEOUT\n",
pr_info("%s: Marking jack type as SND_JACK_LINEOUT\n",
__func__);
}
}
@ -766,7 +770,7 @@ void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
mbhc->mbhc_cb->mbhc_micb_ramp_control)
mbhc->mbhc_cb->mbhc_micb_ramp_control(component, false);
pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
pr_info("%s: Reporting insertion %d(%x)\n", __func__,
jack_type, mbhc->hph_status);
wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
(mbhc->hph_status | SND_JACK_MECHANICAL),
@ -789,7 +793,7 @@ void wcd_mbhc_elec_hs_report_unplug(struct wcd_mbhc *mbhc)
else
pr_info("%s: hs_detect_plug work not cancelled\n", __func__);
pr_debug("%s: Report extension cable\n", __func__);
pr_info("%s: Report extension cable\n", __func__);
wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
/*
* If PA is enabled HPHL schmitt trigger can
@ -1096,7 +1100,7 @@ static irqreturn_t wcd_mbhc_mech_plug_detect_irq(int irq, void *data)
int r = IRQ_HANDLED;
struct wcd_mbhc *mbhc = data;
pr_debug("%s: enter\n", __func__);
pr_info("%s: enter\n", __func__);
if (mbhc == NULL) {
pr_err("%s: NULL irq data\n", __func__);
return IRQ_NONE;
@ -1279,7 +1283,7 @@ static irqreturn_t wcd_mbhc_release_handler(int irq, void *data)
if (mbhc->buttons_pressed & WCD_MBHC_JACK_BUTTON_MASK) {
ret = wcd_cancel_btn_work(mbhc);
if (ret == 0) {
pr_debug("%s: Reporting long button release event\n",
pr_info("%s: Reporting long button release event\n",
__func__);
wcd_mbhc_jack_report(mbhc, &mbhc->button_jack,
0, mbhc->buttons_pressed);
@ -1288,7 +1292,7 @@ static irqreturn_t wcd_mbhc_release_handler(int irq, void *data)
pr_debug("%s: Switch irq kicked in, ignore\n",
__func__);
} else {
pr_debug("%s: Reporting btn press\n",
pr_info("%s: Reporting btn press\n",
__func__);
wcd_mbhc_jack_report(mbhc,
&mbhc->button_jack,
@ -1653,6 +1657,7 @@ int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *mbhc_cfg)
struct snd_soc_component *component;
struct snd_soc_card *card;
const char *usb_c_dt = "qcom,msm-mbhc-usbc-audio-supported";
const char *linein_th = "qcom,msm-hs-linein-threshold";
if (!mbhc || !mbhc_cfg)
return -EINVAL;
@ -1679,6 +1684,12 @@ int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *mbhc_cfg)
"%s: skipping USB c analog configuration\n", __func__);
}
if (of_find_property(card->dev->of_node, linein_th, NULL)) {
rc = of_property_read_u32(card->dev->of_node, linein_th,
&mbhc->mbhc_cfg->linein_th);
}
pr_info("%s, LINEIN threshold = %d\n", __func__, mbhc->mbhc_cfg->linein_th);
/* Parse fsa switch handle */
if (mbhc_cfg->enable_usbc_analog) {
dev_dbg(mbhc->component->dev, "%s: usbc analog enabled\n",

View file

@ -1959,6 +1959,57 @@ static int wcd937x_tx_ch_pwr_level_put(struct snd_kcontrol *kcontrol,
return 0;
}
static int wcd937x_aux_path_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int aux_mode;
struct snd_soc_component *component =
snd_soc_kcontrol_component(kcontrol);
aux_mode = ((snd_soc_component_read32(component,
WCD937X_DIGITAL_CDC_PATH_MODE) & 0x40)>>6);
ucontrol->value.integer.value[0] = aux_mode;
dev_dbg(component->dev, "%s: aux_mode = 0x%x ", __func__,
aux_mode);
return 0;
}
static int wcd937x_aux_path_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int aux_mode;
struct snd_soc_component *component =
snd_soc_kcontrol_component(kcontrol);
struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
dev_dbg(component->dev, "%s: codec version %u, ucontrol->value.integer.value[0] = %ld ",
__func__, wcd937x->version, ucontrol->value.integer.value[0]);
dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld",
__func__, ucontrol->value.integer.value[0]);
aux_mode = ucontrol->value.integer.value[0];
if (aux_mode) {
snd_soc_component_update_bits(component,
WCD937X_DIGITAL_CDC_PATH_MODE,
0x40, 0x40);
snd_soc_component_update_bits(component,
WCD937X_AUX_AUXPA,
0x10, 0x10);
} else {
snd_soc_component_update_bits(component,
WCD937X_DIGITAL_CDC_PATH_MODE,
0x40, 0x00);
snd_soc_component_update_bits(component,
WCD937X_AUX_AUXPA,
0x10, 0x00);
}
return 0;
}
static int wcd937x_ear_pa_gain_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@ -2092,6 +2143,11 @@ static int wcd937x_codec_enable_vdd_buck(struct snd_soc_dapm_widget *w,
return 0;
}
static const char * const wcd937x_aux_path_mode_text[] = {
"HP_MODE", "NORMAL_MODE",
};
static const char * const rx_hph_mode_mux_text[] = {
"CLS_H_INVALID", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB", "CLS_H_LOHIFI",
"CLS_H_ULP", "CLS_AB_HIFI",
@ -2221,6 +2277,11 @@ static const struct soc_enum rx_hph_mode_mux_enum =
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text),
rx_hph_mode_mux_text);
static const struct soc_enum wcd937x_aux_path_mode_enum =
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wcd937x_aux_path_mode_text),
wcd937x_aux_path_mode_text);
static SOC_ENUM_SINGLE_EXT_DECL(wcd937x_ear_pa_gain_enum,
wcd937x_ear_pa_gain_text);
@ -2269,6 +2330,9 @@ static const struct snd_kcontrol_new wcd937x_snd_controls[] = {
wcd937x_tx_ch_pwr_level_get, wcd937x_tx_ch_pwr_level_put),
SOC_ENUM_EXT("TX CH3 PWR", wcd937x_tx_ch_pwr_level_enum,
wcd937x_tx_ch_pwr_level_get, wcd937x_tx_ch_pwr_level_put),
SOC_ENUM_EXT("AUX PATH Mode", wcd937x_aux_path_mode_enum,
wcd937x_aux_path_mode_get, wcd937x_aux_path_mode_put),
};
static const struct snd_kcontrol_new adc1_switch[] = {

View file

@ -46,6 +46,14 @@
#define __CHIPSET__ "HOLI "
#define MSM_DAILINK_NAME(name) (__CHIPSET__#name)
#ifdef CONFIG_SND_SOC_AW87XXX
extern int aw87xxx_add_codec_controls(void *codec);
#endif
#ifdef CONFIG_SND_SOC_FS1815
extern int fsm_add_codec_controls(struct snd_soc_component *codec);
#endif
#define SAMPLING_RATE_8KHZ 8000
#define SAMPLING_RATE_11P025KHZ 11025
#define SAMPLING_RATE_16KHZ 16000
@ -576,6 +584,7 @@ static char const *bt_sample_rate_tx_text[] = {"KHZ_8", "KHZ_16",
"KHZ_44P1", "KHZ_48",
"KHZ_88P2", "KHZ_96"};
static const char *const afe_loopback_tx_ch_text[] = {"One", "Two"};
static const char *const earpiece_dsense_text[] = {"On", "Off"};
static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_sample_rate, usb_sample_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text);
@ -710,6 +719,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate, bt_sample_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate_rx, bt_sample_rate_rx_text);
static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate_tx, bt_sample_rate_tx_text);
static SOC_ENUM_SINGLE_EXT_DECL(afe_loopback_tx_chs, afe_loopback_tx_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(earpiece_dsense_en, earpiece_dsense_text);
static bool is_initial_boot;
static bool codec_reg_done;
@ -717,6 +727,8 @@ static struct snd_soc_card snd_soc_card_holi_msm;
static int dmic_0_1_gpio_cnt;
static int dmic_2_3_gpio_cnt;
static int dmic_4_5_gpio_cnt;
static int earpiece_dsense_en_gpio;
static bool is_earpiece_dsense_disable;
static void *def_wcd_mbhc_cal(void);
@ -3217,6 +3229,36 @@ static int msm_bt_sample_rate_tx_put(struct snd_kcontrol *kcontrol,
return 0;
}
/* when gpio output is high, means earpiece dsense is off */
static int earpiece_dsense_en_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.integer.value[0] = is_earpiece_dsense_disable;
pr_debug("get earpiece_dsense_pin state: %s\n",
is_earpiece_dsense_disable ? "high" : "low");
return 0;
}
static int earpiece_dsense_en_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
switch (ucontrol->value.integer.value[0]) {
case 0:
gpio_direction_output(earpiece_dsense_en_gpio, 0);
is_earpiece_dsense_disable = 0;
break;
case 1:
gpio_direction_output(earpiece_dsense_en_gpio, 1);
is_earpiece_dsense_disable = 1;
break;
default:
return -EINVAL;
}
pr_debug("set earpiece_dsense_pin: %s\n",
ucontrol->value.integer.value[0] ? "high" : "low");
return 0;
}
static const struct snd_kcontrol_new msm_int_wcd937x_snd_controls[] = {
SOC_ENUM_EXT("RX_CDC_DMA_RX_0 Format", rx_cdc_dma_rx_0_format,
cdc_dma_rx_format_get, cdc_dma_rx_format_put),
@ -3591,6 +3633,8 @@ static const struct snd_kcontrol_new msm_common_snd_controls[] = {
msm_vi_feed_tx_ch_get, msm_vi_feed_tx_ch_put),
SOC_SINGLE_MULTI_EXT("TDM Slot Map", SND_SOC_NOPM, 0, 255, 0,
TDM_MAX_SLOTS + MAX_PATH, NULL, tdm_slot_map_put),
SOC_ENUM_EXT("Earpiece Dsense Enable", earpiece_dsense_en,
earpiece_dsense_en_get, earpiece_dsense_en_put),
};
static const struct snd_kcontrol_new msm_snd_controls[] = {
@ -4756,8 +4800,8 @@ static void *def_wcd_mbhc_cal(void)
btn_high = ((void *)&btn_cfg->_v_btn_low) +
(sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn);
btn_high[0] = 75;
btn_high[1] = 150;
btn_high[0] = 88;
btn_high[1] = 138;
btn_high[2] = 237;
btn_high[3] = 500;
btn_high[4] = 500;
@ -5212,6 +5256,38 @@ static struct snd_soc_dai_link msm_common_dai_links[] = {
},
};
#ifdef CONFIG_AW882XX_STEREO_SMARTPA_PRI
static struct snd_soc_dai_link msm_pri_mi2s_tx_hotless_dai_links[] = {
{
.name = "Primary MI2S_TX Hostless",
.stream_name = "Primary MI2S_TX Hostless Capture",
.dynamic = 1,
.dpcm_capture = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
.ignore_pmdown_time = 1,
SND_SOC_DAILINK_REG(pri_mi2s_tx_hostless),
},
};
#else
static struct snd_soc_dai_link msm_sec_mi2s_tx_hotless_dai_links[] = {
{
.name = "Secondary MI2S_TX Hostless",
.stream_name = "Secondary MI2S_TX Hostless Capture",
.dynamic = 1,
.dpcm_capture = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
.ignore_pmdown_time = 1,
SND_SOC_DAILINK_REG(sec_mi2s_tx_hostless),
},
};
#endif
static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = {
{/* hw:x,33 */
.name = MSM_DAILINK_NAME(ASM Loopback),
@ -5921,7 +5997,12 @@ static struct snd_soc_dai_link msm_holi_dai_links[
ARRAY_SIZE(msm_rx_tx_cdc_dma_be_dai_links) +
ARRAY_SIZE(msm_va_cdc_dma_be_dai_links) +
ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link) +
ARRAY_SIZE(msm_wcn_btfm_be_dai_links)];
ARRAY_SIZE(msm_wcn_btfm_be_dai_links) +
#ifdef CONFIG_AW882XX_STEREO_SMARTPA_PRI
ARRAY_SIZE(msm_pri_mi2s_tx_hotless_dai_links)];
#else
ARRAY_SIZE(msm_sec_mi2s_tx_hotless_dai_links)];
#endif
static int msm_populate_dai_link_component_of_node(
struct snd_soc_card *card)
@ -6164,6 +6245,69 @@ static const struct of_device_id holi_asoc_machine_of_match[] = {
{},
};
#ifdef CONFIG_AW882XX_STEREO_SMARTPA
struct snd_soc_dai_link_component aw_codecs[4];
static unsigned int aw_codecs_num;
static DEFINE_MUTEX(aw_dailink_mutex);
void awinic_set_dai_name(const char* drvdainame, const char*drvname)
{
mutex_lock(&aw_dailink_mutex);
if (aw_codecs_num < ARRAY_SIZE(aw_codecs)) {
aw_codecs[aw_codecs_num].dai_name = drvdainame;
aw_codecs[aw_codecs_num].name = drvname;
aw_codecs[aw_codecs_num].of_node = NULL;
pr_info("aw_codecs_num[%d] codec name %s dai name %s\n",
aw_codecs_num, aw_codecs[aw_codecs_num].name, aw_codecs[aw_codecs_num].dai_name);
aw_codecs_num++;
}
mutex_unlock(&aw_dailink_mutex);
}
EXPORT_SYMBOL(awinic_set_dai_name);
#ifdef CONFIG_AW882XX_STEREO_SMARTPA_PRI
static int aw_update_dai_link_name(struct snd_soc_dai_link *dailink, int len1)
{
int i;
if (aw_codecs_num != 0) {
for (i = 0; i < len1; i++) {
if((!strcmp(dailink[i].stream_name, "Primary MI2S Playback")) ||
(!strcmp(dailink[i].stream_name, "Primary MI2S Capture"))){
dailink[i].num_codecs = aw_codecs_num;
dailink[i].codecs = aw_codecs;
}
}
} else {
pr_err("aw_codecs is empty\n");
return -EINVAL;
}
return 0;
}
#else
static int aw_update_dai_link_name(struct snd_soc_dai_link *dailink, int len1)
{
int i;
if (aw_codecs_num != 0) {
for (i = 0; i < len1; i++) {
if((!strcmp(dailink[i].stream_name, "Secondary MI2S Playback")) ||
(!strcmp(dailink[i].stream_name, "Secondary MI2S Capture"))){
dailink[i].num_codecs = aw_codecs_num;
dailink[i].codecs = aw_codecs;
}
}
} else {
pr_err("aw_codecs is empty\n");
return -EINVAL;
}
return 0;
}
#endif
#endif
static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
{
struct snd_soc_card *card = NULL;
@ -6270,6 +6414,22 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
ARRAY_SIZE(msm_wcn_btfm_be_dai_links);
}
}
if (mi2s_audio_intf) {
#ifdef CONFIG_AW882XX_STEREO_SMARTPA_PRI
memcpy(msm_holi_dai_links + total_links,
msm_pri_mi2s_tx_hotless_dai_links,
sizeof(msm_pri_mi2s_tx_hotless_dai_links));
total_links += ARRAY_SIZE(msm_pri_mi2s_tx_hotless_dai_links);
#else
memcpy(msm_holi_dai_links + total_links,
msm_sec_mi2s_tx_hotless_dai_links,
sizeof(msm_sec_mi2s_tx_hotless_dai_links));
total_links += ARRAY_SIZE(msm_sec_mi2s_tx_hotless_dai_links);
#endif
}
dailink = msm_holi_dai_links;
} else if (!strcmp(match->data, "stub_codec")) {
card = &snd_soc_card_stub_msm;
@ -6287,6 +6447,10 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
total_links = len_2;
}
#ifdef CONFIG_AW882XX_STEREO_SMARTPA
aw_update_dai_link_name(dailink, total_links);
#endif
if (card) {
card->dai_link = dailink;
card->num_links = total_links;
@ -6329,6 +6493,24 @@ static int msm_int_audrx_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
#ifdef CONFIG_SND_SOC_AW87XXX
ret = aw87xxx_add_codec_controls((void *)component);
if (ret < 0) {
pr_err("%s: add_codec_controls failed, ret %d\n",
__func__, ret);
return ret;
};
#endif
#ifdef CONFIG_SND_SOC_FS1815
ret = fsm_add_codec_controls(component);
if (ret < 0) {
pr_err("%s: add_codec_controls failed, ret %d\n",
__func__, ret);
return ret;
};
#endif
snd_soc_dapm_new_controls(dapm, msm_int_dapm_widgets,
ARRAY_SIZE(msm_int_dapm_widgets));
@ -6817,6 +6999,19 @@ static int msm_asoc_machine_probe(struct platform_device *pdev)
for (index = PRIM_MI2S; index < MI2S_MAX; index++)
atomic_set(&(pdata->mi2s_gpio_ref_count[index]), 0);
earpiece_dsense_en_gpio = of_get_named_gpio(pdev->dev.of_node,
"earpiece-dsense-enable", 0);
if (earpiece_dsense_en_gpio < 0) {
pr_err("missing earpiece_dsense_en_gpio in dt node\n");
} else {
if (!gpio_is_valid(earpiece_dsense_en_gpio)) {
pr_err("Invalid earpiece_dsense_en_gpio\n");
} else {
gpio_direction_output(earpiece_dsense_en_gpio, 1);
is_earpiece_dsense_disable = 1;
}
}
/* Register LPASS audio hw vote */
lpass_audio_hw_vote = devm_clk_get(&pdev->dev, "lpass_audio_hw_vote");
if (IS_ERR(lpass_audio_hw_vote)) {

View file

@ -752,6 +752,13 @@ void hpcm_notify_evt_processing(uint8_t *data, char *session,
return;
}
if (prtd->mixer_conf.sess_indx < VOICE_INDEX ||
prtd->mixer_conf.sess_indx >= MAX_SESSION) {
pr_err("%s:: Invalid session idx %d\n",
__func__, prtd->mixer_conf.sess_indx);
return;
}
if (notify_evt->tap_point == VSS_IVPCM_TAP_POINT_TX_DEFAULT) {
tp = &prtd->session[prtd->mixer_conf.sess_indx].tx_tap_point;
tmd = &prtd->mixer_conf.tx;

View file

@ -33282,6 +33282,15 @@ static const char * const mi2s_rx_vi_fb_tx_mux_text[] = {
"ZERO", "SENARY_TX"
};
static const char * const pri_mi2s_rx_vi_fb_tx_mux_text[] = {
"ZERO", "PRI_MI2S_TX"
};
static const char * const sec_mi2s_rx_vi_fb_tx_mux_text[] = {
"ZERO", "SEC_MI2S_TX"
};
static const char * const int4_mi2s_rx_vi_fb_tx_mono_mux_text[] = {
"ZERO", "INT5_MI2S_TX"
};
@ -33314,6 +33323,13 @@ static const int wsa_rx_0_vi_fb_tx_rch_value[] = {
MSM_BACKEND_DAI_MAX, MSM_BACKEND_DAI_WSA_CDC_DMA_TX_0
};
static const int pri_mi2s_rx_vi_fb_tx_value[] = {
MSM_BACKEND_DAI_MAX, MSM_BACKEND_DAI_PRI_MI2S_TX
};
static const int sec_mi2s_rx_vi_fb_tx_value[] = {
MSM_BACKEND_DAI_MAX, MSM_BACKEND_DAI_SECONDARY_MI2S_TX
};
static const int mi2s_rx_vi_fb_tx_value[] = {
MSM_BACKEND_DAI_MAX, MSM_BACKEND_DAI_SENARY_MI2S_TX
@ -33362,6 +33378,16 @@ static const struct soc_enum mi2s_rx_vi_fb_mux_enum =
ARRAY_SIZE(mi2s_rx_vi_fb_tx_mux_text),
mi2s_rx_vi_fb_tx_mux_text, mi2s_rx_vi_fb_tx_value);
static const struct soc_enum pri_mi2s_rx_vi_fb_mux_enum =
SOC_VALUE_ENUM_DOUBLE(0, MSM_BACKEND_DAI_PRI_MI2S_RX, 0, 0,
ARRAY_SIZE(pri_mi2s_rx_vi_fb_tx_mux_text),
pri_mi2s_rx_vi_fb_tx_mux_text, pri_mi2s_rx_vi_fb_tx_value);
static const struct soc_enum sec_mi2s_rx_vi_fb_mux_enum =
SOC_VALUE_ENUM_DOUBLE(0, MSM_BACKEND_DAI_SEC_I2S_RX, 0, 0,
ARRAY_SIZE(sec_mi2s_rx_vi_fb_tx_mux_text),
sec_mi2s_rx_vi_fb_tx_mux_text, sec_mi2s_rx_vi_fb_tx_value);
static const struct soc_enum int4_mi2s_rx_vi_fb_mono_ch_mux_enum =
SOC_VALUE_ENUM_DOUBLE(SND_SOC_NOPM, MSM_BACKEND_DAI_INT4_MI2S_RX, 0, 0,
ARRAY_SIZE(int4_mi2s_rx_vi_fb_tx_mono_mux_text),
@ -33409,6 +33435,16 @@ static const struct snd_kcontrol_new mi2s_rx_vi_fb_mux =
mi2s_rx_vi_fb_mux_enum, spkr_prot_get_vi_lch_port,
spkr_prot_put_vi_lch_port);
static const struct snd_kcontrol_new pri_mi2s_rx_vi_fb_mux =
SOC_DAPM_ENUM_EXT("PRI_MI2S_RX_VI_FB_MUX",
pri_mi2s_rx_vi_fb_mux_enum, spkr_prot_get_vi_lch_port,
spkr_prot_put_vi_lch_port);
static const struct snd_kcontrol_new sec_mi2s_rx_vi_fb_mux =
SOC_DAPM_ENUM_EXT("SEC_MI2S_RX_VI_FB_MUX",
sec_mi2s_rx_vi_fb_mux_enum, spkr_prot_get_vi_lch_port,
spkr_prot_put_vi_lch_port);
static const struct snd_kcontrol_new int4_mi2s_rx_vi_fb_mono_ch_mux =
SOC_DAPM_ENUM_EXT("INT4_MI2S_RX_VI_FB_MONO_CH_MUX",
int4_mi2s_rx_vi_fb_mono_ch_mux_enum, spkr_prot_get_vi_lch_port,
@ -33424,6 +33460,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
/* Widget name equals to Front-End DAI name<Need confirmation>,
* Stream name must contains substring of front-end dai name
*/
SND_SOC_DAPM_MUX("PRI_MI2S_RX_VI_FB_MUX", SND_SOC_NOPM, 0, 0,
&pri_mi2s_rx_vi_fb_mux),
SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, 0, 0, 0),
@ -34410,6 +34448,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets_mi2s[] = {
ARRAY_SIZE(int4_mi2s_rx_port_mixer_controls)),
SND_SOC_DAPM_MUX("PRI_MI2S_RX_VI_FB_MUX", SND_SOC_NOPM, 0, 0,
&mi2s_rx_vi_fb_mux),
SND_SOC_DAPM_MUX("SEC_MI2S_RX_VI_FB_MUX", SND_SOC_NOPM, 0, 0,
&sec_mi2s_rx_vi_fb_mux),
SND_SOC_DAPM_MUX("INT4_MI2S_RX_VI_FB_MONO_CH_MUX", SND_SOC_NOPM, 0, 0,
&int4_mi2s_rx_vi_fb_mono_ch_mux),
SND_SOC_DAPM_MUX("INT4_MI2S_RX_VI_FB_STEREO_CH_MUX", SND_SOC_NOPM, 0, 0,
@ -35612,6 +35652,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets_tdm[] = {
#endif
static const struct snd_soc_dapm_route intercon[] = {
{"PRI_MI2S_RX_VI_FB_MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"PRI_MI2S_RX", NULL, "PRI_MI2S_RX_VI_FB_MUX"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
@ -42094,9 +42136,11 @@ static const struct snd_soc_dapm_route intercon_mi2s[] = {
{"SENARY_MI2S_TX", NULL, "BE_IN"},
{"PRI_MI2S_RX_VI_FB_MUX", "SENARY_TX", "SENARY_TX"},
{"SEC_MI2S_RX_VI_FB_MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
{"INT4_MI2S_RX_VI_FB_MONO_CH_MUX", "INT5_MI2S_TX", "INT5_MI2S_TX"},
{"INT4_MI2S_RX_VI_FB_STEREO_CH_MUX", "INT5_MI2S_TX", "INT5_MI2S_TX"},
{"PRI_MI2S_RX", NULL, "PRI_MI2S_RX_VI_FB_MUX"},
{"SEC_MI2S_RX", NULL, "SEC_MI2S_RX_VI_FB_MUX"},
{"INT4_MI2S_RX", NULL, "INT4_MI2S_RX_VI_FB_MONO_CH_MUX"},
{"INT4_MI2S_RX", NULL, "INT4_MI2S_RX_VI_FB_STEREO_CH_MUX"},
};

View file

@ -316,6 +316,18 @@ SND_SOC_DAILINK_DEFS(slimbus_8_tx,
"btfm_fm_slim_tx")),
DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing")));
#if defined(CONFIG_AW882XX_STEREO_SMARTPA_PRI)
SND_SOC_DAILINK_DEFS(pri_mi2s_rx,
DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-mi2s.0")),
DAILINK_COMP_ARRAY(COMP_CODEC("aw882xxacf_smartpa.2-0034", "aw882xx-aif-2-34"),
COMP_CODEC("aw882xxacf_smartpa.2-0035", "aw882xx-aif-2-35")),
DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing")));
SND_SOC_DAILINK_DEFS(pri_mi2s_tx,
DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-mi2s.1")),
DAILINK_COMP_ARRAY(COMP_CODEC("aw882xxacf_smartpa.2-0034", "aw882xx-aif-2-34"),
COMP_CODEC("aw882xxacf_smartpa.2-0035", "aw882xx-aif-2-35")),
DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing")));
#else
SND_SOC_DAILINK_DEFS(pri_mi2s_rx,
DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-mi2s.0")),
DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")),
@ -325,16 +337,38 @@ SND_SOC_DAILINK_DEFS(pri_mi2s_tx,
DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-mi2s.1")),
DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")),
DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing")));
#endif
#if defined(CONFIG_AW882XX_STEREO_SMARTPA_PRI)
SND_SOC_DAILINK_DEFS(sec_mi2s_rx,
DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-mi2s.2")),
DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")),
DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing")));
SND_SOC_DAILINK_DEFS(sec_mi2s_tx,
DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-mi2s.3")),
DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")),
DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing")));
#elif defined(CONFIG_AW882XX_STEREO_SMARTPA)
SND_SOC_DAILINK_DEFS(sec_mi2s_rx,
DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-mi2s.2")),
DAILINK_COMP_ARRAY(COMP_CODEC("aw882xxacf_smartpa.2-0034", "aw882xx-aif-2-34"),
COMP_CODEC("aw882xxacf_smartpa.2-0035", "aw882xx-aif-2-35")),
DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing")));
SND_SOC_DAILINK_DEFS(sec_mi2s_tx,
DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-mi2s.3")),
DAILINK_COMP_ARRAY(COMP_CODEC("aw882xxacf_smartpa.2-0034", "aw882xx-aif-2-34"),
COMP_CODEC("aw882xxacf_smartpa.2-0035", "aw882xx-aif-2-35")),
DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing")));
#else
SND_SOC_DAILINK_DEFS(sec_mi2s_rx,
DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-mi2s.2")),
DAILINK_COMP_ARRAY(COMP_CODEC("aw882xx_codec", "aw882xx-aif")),
DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing")));
SND_SOC_DAILINK_DEFS(sec_mi2s_tx,
DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-mi2s.3")),
DAILINK_COMP_ARRAY(COMP_CODEC("aw882xx_codec", "aw882xx-aif")),
DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing")));
#endif
SND_SOC_DAILINK_DEFS(tert_mi2s_rx,
DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-mi2s.4")),
@ -469,3 +503,15 @@ SND_SOC_DAILINK_DEFS(proxy_rx,
DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-dev.8194")),
DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")),
DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing")));
#if defined(CONFIG_AW882XX_STEREO_SMARTPA_PRI)
SND_SOC_DAILINK_DEFS(pri_mi2s_tx_hostless,
DAILINK_COMP_ARRAY(COMP_CPU("PRI_MI2S_TX_HOSTLESS")),
DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")),
DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-hostless")));
#else
SND_SOC_DAILINK_DEFS(sec_mi2s_tx_hostless,
DAILINK_COMP_ARRAY(COMP_CPU("SEC_MI2S_TX_HOSTLESS")),
DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")),
DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-hostless")));
#endif

View file

@ -33,6 +33,5 @@ export CONFIG_WSA881X_TEMP_SENSOR_DISABLE=m
export CONFIG_SND_SOC_HOLI=m
export CONFIG_SND_EVENT=m
export CONFIG_TDM_DISABLE=m
export CONFIG_MI2S_DISABLE=m
export CONFIG_AUXPCM_DISABLE=m
export CONFIG_DIGITAL_CDC_RSC_MGR=m

View file

@ -37,6 +37,5 @@
#define CONFIG_SND_SOC_HOLI 1
#define CONFIG_SND_EVENT 1
#define CONFIG_TDM_DISABLE 1
#define CONFIG_MI2S_DISABLE 1
#define CONFIG_AUXPCM_DISABLE 1
#define CONFIG_DIGITAL_CDC_RSC_MGR 1

View file

@ -13,6 +13,24 @@ ifeq ($(KERNEL_BUILD), 1)
AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio
endif
EXTRA_CFLAGS += -DCONFIG_SND_SOC_AWINIC_AW882XX
ifeq ($(CONFIG_AW882XX_PARAMS_FROM_BIN), y)
CDEFINES += -DCONFIG_AW882XX_PARAMS_STORED_IN_BIN
endif
ifeq ($(CONFIG_AW882XX_MAPSIZE_16K), y)
CDEFINES += -DCONFIG_AW882XX_MAPSIZE_16K
endif
ifdef CONFIG_SND_SOC_AW87XXX
CDEFINES += -DCONFIG_SND_SOC_AW87XXX
endif
ifdef CONFIG_SND_SOC_FS1815
CDEFINES += -DCONFIG_SND_SOC_FS1815
endif
ifeq ($(CONFIG_SND_SOC_AUTO), y)
ifdef CONFIG_SND_SOC_SA8155
include $(AUDIO_ROOT)/config/sa8155auto.conf

View file

@ -3507,7 +3507,8 @@ int adm_open_v2(int port_id, int path, int rate, int channel_mode, int topology,
if (topology == VPM_TX_VOICE_SMECNS_V2_COPP_TOPOLOGY ||
topology == VPM_TX_VOICE_FLUENCE_SM_COPP_TOPOLOGY ||
topology == VPM_TX_VOICE_FLUENCE_NN_COPP_TOPOLOGY ||
topology == AUDIO_RX_MONO_VOIP_COPP_TOPOLOGY)
topology == AUDIO_RX_MONO_VOIP_COPP_TOPOLOGY ||
topology == VOICE_TX_FNN_COPP_TOPOLOGY)
channel_mode = 1;
/*
@ -5179,6 +5180,49 @@ int adm_set_ffecns_freeze_event(bool ffecns_freeze_event)
return rc;
}
EXPORT_SYMBOL(adm_set_ffecns_freeze_event);
#ifdef CONFIG_SND_SOC_AWINIC_AW882XX
int aw_adm_param_enable(int port_id, int module_id, int param_id, int enable)
{
int copp_idx = 0;
uint32_t enable_param;
struct param_hdr_v3 param_hdr;
int rc = 0;
pr_debug("%s port_id %d, module_id 0x%x, enable %d\n",
__func__, port_id, module_id, enable);
copp_idx = adm_get_default_copp_idx(port_id);
if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
return -EINVAL;
}
if (enable < 0 || enable > 1) {
pr_err("%s: Invalid value for enable %d\n", __func__, enable);
return -EINVAL;
}
pr_debug("%s port_id %d, module_id 0x%x, copp_idx 0x%x, enable %d\n",
__func__, port_id, module_id, copp_idx, enable);
memset(&param_hdr, 0, sizeof(param_hdr));
param_hdr.module_id = module_id;
param_hdr.instance_id = INSTANCE_ID_0;
param_hdr.param_id = param_id;
param_hdr.param_size = sizeof(enable_param);
enable_param = enable;
rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
(uint8_t *) &enable_param);
if (rc)
pr_err("%s: Failed to set enable of module(%d) instance(%d) to %d, err %d\n",
__func__, module_id, INSTANCE_ID_0, enable, rc);
return rc;
}
EXPORT_SYMBOL(aw_adm_param_enable);
#endif
/**
* adm_param_enable -

View file

@ -24,6 +24,32 @@
#include "adsp_err.h"
#include "q6afecal-hwdep.h"
#ifdef CONFIG_SND_SOC_FS1815
#include <dsp/q6fsm-v3.h>
#endif
#ifdef CONFIG_SND_SOC_AWINIC_AW882XX
#define AFE_MODULE_ID_AWDSP_TX (0x10013D00)
#define AFE_MODULE_ID_AWDSP_RX (0x10013D01)
#define AFE_PARAM_ID_AWDSP_RX_SET_ENABLE (0x10013D11)
#define AFE_PARAM_ID_AWDSP_TX_SET_ENABLE (0x10013D13)
#define AFE_PARAM_ID_AWDSP_RX_PARAMS (0x10013D12)
void aw_cal_unmap_memory(void);
#endif /* #ifdef CONFIG_SND_SOC_AWINIC_AW882XX */
#ifdef CONFIG_SND_SOC_AW87XXX
static int g_rx_port_id = 0;
void aw_set_port_id(int rx_port_id)
{
g_rx_port_id = rx_port_id;
}
EXPORT_SYMBOL(aw_set_port_id);
#endif /* #ifdef CONFIG_SND_SOC_AW87XXX */
#define WAKELOCK_TIMEOUT 5000
#define AFE_CLK_TOKEN 1024
#define AFE_NOWAIT_TOKEN 2048
@ -275,6 +301,10 @@ struct afe_ctl {
uint32_t cps_ch_mask;
struct afe_cps_hw_intf_cfg *cps_config;
int lsm_afe_ports[MAX_LSM_SESSIONS];
#ifdef CONFIG_SND_SOC_AWINIC_AW882XX
struct rtac_cal_block_data aw_cal;
atomic_t aw_state;
#endif /*CONFIG_SND_SOC_AWINIC_AW882XX*/
};
struct afe_clkinfo_per_port {
@ -596,6 +626,7 @@ int afe_get_topology(int port_id)
done:
return topology;
}
EXPORT_SYMBOL(afe_get_topology);
/**
* afe_set_aanc_info -
@ -1078,6 +1109,10 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv)
return -EINVAL;
}
if (data->opcode == RESET_EVENTS) {
#ifdef CONFIG_SND_SOC_AWINIC_AW882XX
aw_cal_unmap_memory();
#endif /*CONFIG_SND_SOC_AWINIC_AW882XX*/
pr_debug("%s: reset event = %d %d apr[%pK]\n",
__func__,
data->reset_event, data->reset_proc, this_afe.apr);
@ -1153,7 +1188,31 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv)
payload, data->token);
return -EINVAL;
}
#ifdef CONFIG_SND_SOC_AWINIC_AW882XX
if (atomic_read(&this_afe.aw_state) == 1) {
if (!payload[0]) {
atomic_set(&this_afe.state, 0);
} else {
pr_debug("%s: status: %d", __func__, payload[0]);
atomic_set(&this_afe.state, -1);
}
atomic_set(&this_afe.aw_state, 0);
wake_up(&this_afe.wait[data->token]);
return 0;
}
#endif /*CONFIG_SND_SOC_AWINIC_AW882XX*/
#ifdef CONFIG_SND_SOC_FS1815
if (!q6fsm_afe_callback(data->payload, data->payload_size)) {
atomic_set(&this_afe.state, 0);
if (afe_token_is_valid(data->token)) {
wake_up(&this_afe.wait[data->token]);
return 0;
} else {
return -EINVAL;
}
}
#endif
if (rtac_make_afe_callback(data->payload,
data->payload_size))
return 0;
@ -2547,6 +2606,15 @@ static int afe_spk_prot_prepare(int src_port, int dst_port, int param_id,
case AFE_PARAM_ID_SP_V4_EX_VI_FTM_CFG:
param_info.module_id = AFE_MODULE_SPEAKER_PROTECTION_V4_VI;
break;
#ifdef CONFIG_SND_SOC_AWINIC_AW882XX
case AFE_PARAM_ID_AWDSP_RX_SET_ENABLE:
case AFE_PARAM_ID_AWDSP_RX_PARAMS:
param_info.module_id = AFE_MODULE_ID_AWDSP_RX;
break;
case AFE_PARAM_ID_AWDSP_TX_SET_ENABLE:
param_info.module_id = AFE_MODULE_ID_AWDSP_TX;
break;
#endif /*CONFIG_SND_SOC_AWINIC_AW882XX*/
default:
pr_err("%s: default case 0x%x\n", __func__, param_id);
goto fail_cmd;
@ -3956,6 +4024,233 @@ done:
return ret;
}
#ifdef CONFIG_SND_SOC_AWINIC_AW882XX
int aw_send_afe_rx_module_enable(uint32_t rx_port_id, void *buf, int cmd_size)
{
union afe_spkr_prot_config config;
if (cmd_size > sizeof(config))
return -EINVAL;
memcpy(&config, buf, cmd_size);
if (afe_spk_prot_prepare(rx_port_id, 0,
AFE_PARAM_ID_AWDSP_RX_SET_ENABLE, &config,sizeof(union afe_spkr_prot_config))) {
pr_err("%s: set bypass failed \n", __func__);
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL(aw_send_afe_rx_module_enable);
int aw_send_afe_tx_module_enable(uint32_t tx_port_id, void *buf, int cmd_size)
{
union afe_spkr_prot_config config;
if (cmd_size > sizeof(config))
return -EINVAL;
memcpy(&config, buf, cmd_size);
if (afe_spk_prot_prepare(tx_port_id, 0,
AFE_PARAM_ID_AWDSP_TX_SET_ENABLE, &config,sizeof(union afe_spkr_prot_config))) {
pr_err("%s: set bypass failed \n", __func__);
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL(aw_send_afe_tx_module_enable);
#ifdef CONFIG_SND_SOC_AW87XXX
int aw_send_afe_cal_apr(uint32_t param_id, void *buf, int cmd_size, bool write) /*aw87xxx*/
#else
int aw_send_afe_cal_apr(uint32_t rx_port_id, uint32_t tx_port_id,
uint32_t param_id, void *buf, int cmd_size, bool write) /*aw882xx*/
#endif
{
int32_t result = 0;
#ifdef CONFIG_SND_SOC_AW87XXX
uint32_t port_id = g_rx_port_id;
#else
uint32_t port_id = rx_port_id; /*aw882xx*/
#endif
int32_t module_id = AFE_MODULE_ID_AWDSP_RX;
uint32_t port_index = 0;
uint32_t payload_size = 0;
size_t len;
struct rtac_cal_block_data *aw_cal = &(this_afe.aw_cal);
struct mem_mapping_hdr mem_hdr;
struct param_hdr_v3 param_hdr;
pr_debug("%s: enter\n", __func__);
#ifndef CONFIG_SND_SOC_AW87XXX
if (param_id == AFE_PARAM_ID_AWDSP_TX_SET_ENABLE) {
port_id = tx_port_id;
module_id = AFE_MODULE_ID_AWDSP_TX;
}
#endif
if (aw_cal->map_data.dma_buf == 0) {
/*Minimal chunk size is 8K*/
#ifdef CONFIG_AW882XX_MAPSIZE_16K
aw_cal->map_data.map_size = SZ_16K;
#else
aw_cal->map_data.map_size = SZ_8K;
#endif
result = msm_audio_ion_alloc(&(aw_cal->map_data.dma_buf),
aw_cal->map_data.map_size,
&(aw_cal->cal_data.paddr),&len,
&(aw_cal->cal_data.kvaddr));
if (result < 0) {
pr_err("%s: allocate buffer failed! ret = %d\n",
__func__, result);
goto err;
}
}
if (aw_cal->map_data.map_handle == 0) {
result = afe_map_rtac_block(aw_cal);
if (result < 0) {
pr_err("%s: map buffer failed! ret = %d\n",
__func__, result);
goto err;
}
}
port_index = q6audio_get_port_index(port_id);
if (port_index >= AFE_MAX_PORTS) {
pr_err("%s: Invalid AFE port = 0x%x\n", __func__, port_id);
goto err;
}
#ifdef CONFIG_AW882XX_MAPSIZE_16K
if (cmd_size > (SZ_16K - sizeof(struct param_hdr_v3))) {
#else
if (cmd_size > (SZ_8K - sizeof(struct param_hdr_v3))) {
#endif
pr_err("%s: Invalid payload size = %d\n", __func__, cmd_size);
result = -EINVAL;
goto err;
}
/* Pack message header with data */
param_hdr.module_id = module_id;
param_hdr.instance_id = INSTANCE_ID_0;
param_hdr.param_size = cmd_size;
if (write) {
param_hdr.param_id = param_id;
q6common_pack_pp_params(aw_cal->cal_data.kvaddr,
&param_hdr,
buf,
&payload_size);
aw_cal->cal_data.size = payload_size;
} else {
param_hdr.param_id = param_id;
aw_cal->cal_data.size = cmd_size + sizeof(struct param_hdr_v3);
}
/*Send/Get package to/from ADSP*/
mem_hdr.data_payload_addr_lsw =
lower_32_bits(aw_cal->cal_data.paddr);
mem_hdr.data_payload_addr_msw =
msm_audio_populate_upper_32_bits(aw_cal->cal_data.paddr);
mem_hdr.mem_map_handle =
aw_cal->map_data.map_handle;
pr_debug("%s: Sending aw_cal port = 0x%x, cal size = %zd, cal addr = 0x%pK\n",
__func__, port_id, aw_cal->cal_data.size, &aw_cal->cal_data.paddr);
result = afe_q6_interface_prepare();
if (result != 0) {
pr_err("%s: Q6 interface prepare failed %d\n", __func__, result);
goto err;
}
if (write) {
if (q6common_is_instance_id_supported())
result = q6afe_set_params_v3(port_id, port_index, &mem_hdr, NULL, payload_size);
else
result = q6afe_set_params_v2(port_id, port_index, &mem_hdr, NULL, payload_size);
} else {
int8_t *resp = (int8_t *)aw_cal->cal_data.kvaddr;
atomic_set(&this_afe.aw_state, 1);
if (q6common_is_instance_id_supported()) {
result = q6afe_get_params_v3(port_id, port_index, &mem_hdr, &param_hdr);
resp += sizeof(struct param_hdr_v3);
} else {
result = q6afe_get_params_v2(port_id, port_index, &mem_hdr, &param_hdr);
resp += sizeof(struct param_hdr_v1);
}
if (result) {
pr_err("%s: get response from port 0x%x failed %d\n",
__func__, port_id, result);
goto err;
}
else {
/*Copy response data to command buffer*/
memcpy(buf, resp, cmd_size);
}
}
err:
return result;
}
EXPORT_SYMBOL(aw_send_afe_cal_apr);
void aw_cal_unmap_memory(void)
{
int result = 0;
if (this_afe.aw_cal.map_data.map_handle) {
result = afe_unmap_rtac_block(&this_afe.aw_cal.map_data.map_handle);
/*Force to remap after unmap failed*/
if (result)
this_afe.aw_cal.map_data.map_handle = 0;
}
}
EXPORT_SYMBOL(aw_cal_unmap_memory);
int aw_send_rx_module_enable(uint32_t rx_port_id, void *buf, int cmd_size)
{
union afe_spkr_prot_config config;
if (cmd_size > sizeof(config))
return -EINVAL;
memcpy(&config, buf, cmd_size);
if (afe_spk_prot_prepare(rx_port_id, 0,
AFE_PARAM_ID_AWDSP_RX_SET_ENABLE,
&config,sizeof(union afe_spkr_prot_config))) {
pr_err("%s: AW set rx bypass failed\n",
__func__);
}
return 0;
}
EXPORT_SYMBOL(aw_send_rx_module_enable);
int aw_send_tx_module_enable(uint32_t tx_port_id, void *buf, int cmd_size)
{
union afe_spkr_prot_config config;
if (cmd_size > sizeof(config))
return -EINVAL;
memcpy(&config, buf, cmd_size);
if (afe_spk_prot_prepare(tx_port_id, 0,
AFE_PARAM_ID_AWDSP_TX_SET_ENABLE,
&config,sizeof(union afe_spkr_prot_config))) {
pr_err("%s: AW set tx module enable failed\n",
__func__);
}
return 0;
}
EXPORT_SYMBOL(aw_send_tx_module_enable);
#endif
static int afe_init_cdc_reg_config(void)
{
struct param_hdr_v3 param_hdr;
@ -4404,6 +4699,16 @@ static int afe_send_cmd_port_start(u16 port_id)
pr_err("%s: AFE enable for port 0x%x failed %d\n", __func__,
port_id, ret);
#ifdef CONFIG_SND_SOC_FS1815
//TODO:
// Set the monitor enable when:
// 1) Speaker PA type is matched
// 2) In speaker playback
// 3) The RX Port is the same as the one of speaker playback
if (port_id == Q6FSM_AFE_RX_PORT)
q6fsm_monitor_switch(true);
#endif
return ret;
}
@ -9459,6 +9764,11 @@ int afe_close(int port_id)
memset(&stop, 0, sizeof(stop));
#ifdef CONFIG_SND_SOC_FS1815
if (port_id == Q6FSM_AFE_RX_PORT)
q6fsm_monitor_switch(false);
#endif
if (this_afe.apr == NULL) {
pr_err("%s: AFE is already closed\n", __func__);
@ -11930,6 +12240,9 @@ static int afe_unmap_cal_data(int32_t cal_type,
ret = afe_cmd_memory_unmap(
cal_block->map_data.q6map_handle);
atomic_set(&this_afe.mem_map_cal_index, -1);
#if defined(CONFIG_AW882XX_PARAMS_STORED_IN_BIN) || defined(CONFIG_SND_SOC_AW87XXX)
atomic_set(&this_afe.mem_map_cal_handles[cal_index],0);
#endif
if (ret < 0) {
pr_err("%s: unmap did not work! cal_type %i ret %d\n",
__func__, cal_index, ret);
@ -12191,11 +12504,17 @@ int __init afe_init(void)
this_afe.event_notifier.notifier_call = afe_aud_event_notify;
msm_aud_evt_blocking_register_client(&this_afe.event_notifier);
#ifdef CONFIG_SND_SOC_FS1815
q6fsm_afe_init();
#endif
return 0;
}
void afe_exit(void)
{
#ifdef CONFIG_SND_SOC_FS1815
q6fsm_afe_deinit();
#endif
if (this_afe.apr) {
apr_reset(this_afe.apr);
atomic_set(&this_afe.state, 0);
@ -12205,6 +12524,9 @@ void afe_exit(void)
q6core_destroy_uevent_data(this_afe.uevent_data);
#ifdef CONFIG_SND_SOC_AWINIC_AW882XX
aw_cal_unmap_memory();
#endif /*CONFIG_SND_SOC_AWINIC_AW882XX*/
afe_delete_cal_data();
config_debug_fs_exit();

View file

@ -247,6 +247,7 @@ static int q6lsm_callback(struct apr_client_data *data, void *priv)
ret = -EINVAL;
goto done;
}
memcpy((u8 *)client->get_param_payload,
(u8 *)payload + payload_min_size_expected, param_size);
done:
@ -538,6 +539,7 @@ static int q6lsm_apr_send_pkt(struct lsm_client *client, void *handle,
if (wait)
mutex_unlock(&lsm_common.apr_lock);
mmap_handle_p = NULL;
if (mmap_p && *mmap_p == 0)
ret = -ENOMEM;
mmap_handle_p = NULL;

View file

@ -5798,6 +5798,7 @@ struct afe_param_id_lpass_core_shared_clk_cfg {
#define VPM_TX_DM_FLUENCE_EF_COPP_TOPOLOGY 0x10000005
#define AUDIO_RX_MONO_VOIP_COPP_TOPOLOGY 0x11000101
#define VPM_TX_VOICE_FLUENCE_NN_COPP_TOPOLOGY 0x10028008
#define VOICE_TX_FNN_COPP_TOPOLOGY 0x10010B0F
/* Memory map regions command payload used by the
* #ASM_CMD_SHARED_MEM_MAP_REGIONS ,#ADM_CMD_SHARED_MEM_MAP_REGIONS

View file

@ -0,0 +1,776 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/**
* Copyright (C) Shanghai FourSemi Semiconductor Co.,Ltd 2016-2022. All rights reserved.
* 2022-12-23 File created.
*/
#ifndef __Q6FSM_V3_H__
#define __Q6FSM_V3_H__
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/kobject.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
#include <linux/power_supply.h>
#include <dsp/msm_audio_ion.h>
#include <dsp/apr_audio-v2.h>
#include <dsp/q6audio-v2.h>
#define fsm_info(fmt, args...) pr_info("%s: " fmt "\n", __func__, ##args)
#define fsm_dbg(fmt, args...) pr_debug("%s: " fmt "\n", __func__, ##args)
#define fsm_err(fmt, args...) pr_err("%s: " fmt "\n", __func__, ##args)
#define Q6FSM_VERSION "v1.1.1"
// TODO update
#define Q6FSM_AFE_RX_PORT (AFE_PORT_ID_RX_CODEC_DMA_RX_0)
#define Q6FSM_AFE_TX_PORT (AFE_PORT_ID_TX_CODEC_DMA_TX_0)
#define Q6FSM_CHUNK_SIZE (256)
// FSADSP MODULE ID
#define AFE_MODULE_ID_FSADSP_TX (0x10001110)
#define AFE_MODULE_ID_FSADSP_RX (0x10001111)
// FSADSP PARAM ID
#define CAPI_V2_PARAM_FSADSP_TX_ENABLE 0x11111601
#define CAPI_V2_PARAM_FSADSP_RX_ENABLE 0x11111611
#define CAPI_V2_PARAM_FSADSP_MODULE_ENABLE 0x10001FA1
#define CAPI_V2_PARAM_FSADSP_ROTATION 0x10001FB1
#define CAPI_V2_PARAM_FSADSP_BSG_VBAT 0x10001FB2
#define CAPI_V2_PARAM_FSADSP_BSGV2_PARAM 0x10001FB5 //set
#define CAPI_V2_PARAM_FSADSP_BSGV2_CONFIG 0x10001FB6 //get
#define CAPI_V2_PARAM_FSADSP_ROTATION 0x10001FB1
#define CAPI_V2_PARAM_FSADSP_FADE 0x10001FB7
#define Q6FSM_RETRY_TIME (1)
#define Q6FSM_SLEEP_TIME (10)
struct bsg_config_v2 {
int bsg_mode;
int bsg_enable;
int bsg_interval;
int tc_mode;
int tc_mode_enable;
int tc_interval;
};
struct bsg_param_v2 {
int bsg_mode;
int bsg_val;
int tc_mode;
int tc_val;
};
struct q6fsm_afe {
struct workqueue_struct *vbat_wq;
struct delayed_work vbat_work;
struct power_supply *psy;
struct mutex cmd_lock;
atomic_t bsg_switch;
unsigned long delay_period;
bool monitor_en;
int bsg_version;
struct bsg_config_v2 config;
};
typedef enum _fs__chann_t
{
FS_CH_LEFT = 1 << 0,
FS_CH_RIGHT = 1 << 1,
FS_CH_MONO = (FS_CH_LEFT|FS_CH_RIGHT),
}fs_chann_t;
typedef struct _fsm_fade_info_t
{
int fade_type; //0x10 mute, 0x11 fade in,0x12 fade out
int fade_time; // fade length time, unit is ms
int start_db;
fs_chann_t ch; // left or right channel
}fsm_fade_info_t;
typedef struct _fsm_rotation_info_t
{
int angle; // 0,90,180,270
int8_t ch_sequence[8];
}fsm_rotation_info_t;
static struct q6fsm_afe *g_fsm_afe;
static uint32_t *q6fsm_get_buffer;
static bool fsm_scene_status = false;
static int q6afe_set_params(u16 port_id, int index,
struct mem_mapping_hdr *mem_hdr,
u8 *packed_param_data, u32 packed_data_size);
static int q6afe_get_params(u16 port_id,
struct mem_mapping_hdr *mem_hdr,
struct param_hdr_v3 *param_hdr);
static int q6fsm_afe_callback(void *payload, int size)
{
uint32_t *payload32 = payload;
if (payload32[0] != 0) {
pr_err("invalid status: %d", payload32[0]);
return -EINVAL;
}
fsm_dbg("payload size: %d", size);
switch (payload32[1]) {
case AFE_MODULE_ID_FSADSP_TX:
case AFE_MODULE_ID_FSADSP_RX:
memcpy(q6fsm_get_buffer, payload32 + 1, size - 4);
break;
default:
return -EINVAL;
}
return 0;
}
static bool q6fsm_check_dsp_ready(void)
{
int topo_id;
topo_id = afe_get_topology(Q6FSM_AFE_RX_PORT);
fsm_dbg("topo_id: 0x%x", topo_id);
if (topo_id <= 0)
return false;
else
return true;
}
static int q6fsm_afe_set_params(struct param_hdr_v3 *param_hdr,
uint8_t *params, uint32_t param_size)
{
u8 *packed_param_data;
int packed_data_size;
int port_id, index;
int retry = 0;
int ret;
if (param_hdr == NULL || params == NULL) {
fsm_err("Bad parameters");
return -EINVAL;
}
if (param_size >= Q6FSM_CHUNK_SIZE) {
fsm_err("Invalid param_size: %d\n", param_size);
return -EINVAL;
}
if (param_hdr->module_id == AFE_MODULE_ID_FSADSP_RX)
port_id = Q6FSM_AFE_RX_PORT;
else
port_id = Q6FSM_AFE_TX_PORT;
index = afe_get_port_index(port_id);
if (index < 0) {
fsm_err("invalid port: %x", port_id);
return -EINVAL;
}
mutex_lock(&g_fsm_afe->cmd_lock);
packed_data_size = sizeof(union param_hdrs) + param_size;
packed_param_data = kzalloc(packed_data_size, GFP_KERNEL);
if (packed_param_data == NULL) {
fsm_err("alloc memory failed!");
mutex_unlock(&g_fsm_afe->cmd_lock);
return -ENOMEM;
}
do {
ret = q6common_pack_pp_params(packed_param_data, param_hdr,
params, &packed_data_size);
if (ret) {
fsm_err("Failed to pack data: %d", ret);
break;
}
while (retry++ < Q6FSM_RETRY_TIME) {
if (q6fsm_check_dsp_ready()) {
ret = q6afe_set_params(port_id, index, NULL,
packed_param_data, packed_data_size);
break;
}
msleep(Q6FSM_SLEEP_TIME);
ret = -ETIMEDOUT;
}
} while (0);
if (ret)
fsm_err("Failed to set params: %d", ret);
mutex_unlock(&g_fsm_afe->cmd_lock);
kfree(packed_param_data);
packed_param_data = NULL;
return ret;
}
static int q6fsm_afe_get_params(struct param_hdr_v3 *param_hdr,
uint8_t *params, uint32_t length)
{
int port_id;
int retry = 0;
int ret;
if (param_hdr == NULL || params == NULL) {
fsm_err("Bad parameters");
return -EINVAL;
}
mutex_lock(&g_fsm_afe->cmd_lock);
q6fsm_get_buffer = kzalloc(length + 16, GFP_KERNEL);
if (q6fsm_get_buffer == NULL) {
fsm_err("Memory allocation failed!");
mutex_unlock(&g_fsm_afe->cmd_lock);
return -ENOMEM;
}
if (param_hdr->module_id == AFE_MODULE_ID_FSADSP_RX)
port_id = Q6FSM_AFE_RX_PORT;
else
port_id = Q6FSM_AFE_TX_PORT;
do {
while (retry++ < Q6FSM_RETRY_TIME) {
if (q6fsm_check_dsp_ready()) {
ret = q6afe_get_params(port_id, NULL, param_hdr);
break;
}
msleep(Q6FSM_SLEEP_TIME);
ret = -ETIMEDOUT;
}
if (!ret)
memcpy(params, &q6fsm_get_buffer[4], length);
else
fsm_err("Get params failed: %d", ret);
} while (0);
kfree(q6fsm_get_buffer);
q6fsm_get_buffer = NULL;
mutex_unlock(&g_fsm_afe->cmd_lock);
return ret;
}
bool q6fsm_get_rx_status(void)
{
struct param_hdr_v3 param_hdr;
uint32_t enable;
int ret;
if(fsm_scene_status == false){
return -EINVAL;
}
if (!q6fsm_check_dsp_ready()) {
fsm_info("DSP not ready yet!");
return -EINVAL;
}
param_hdr.module_id = AFE_MODULE_ID_FSADSP_RX;
param_hdr.instance_id = 0;
param_hdr.reserved = 0;
param_hdr.param_id = CAPI_V2_PARAM_FSADSP_RX_ENABLE;
param_hdr.param_size = sizeof(enable);
ret = q6fsm_afe_get_params(&param_hdr,
(uint8_t *)&enable, sizeof(enable));
if (ret) {
fsm_err("Get params failed: %d", ret);
return false;
}
return !!enable;
}
EXPORT_SYMBOL(q6fsm_get_rx_status);
int q6fsm_set_rx_enable(int enable)
{
struct param_hdr_v3 param_hdr;
uint32_t param;
int ret;
if(fsm_scene_status == false){
return -EINVAL;
}
if (!q6fsm_check_dsp_ready()) {
fsm_info("DSP not ready yet!");
return -EINVAL;
}
param = (uint32_t)enable;
param_hdr.module_id = AFE_MODULE_ID_FSADSP_RX;
param_hdr.instance_id = 0;
param_hdr.reserved = 0;
param_hdr.param_id = CAPI_V2_PARAM_FSADSP_RX_ENABLE;
param_hdr.param_size = sizeof(param);
ret = q6fsm_afe_set_params(&param_hdr,
(uint8_t *)&param, sizeof(param));
if (ret) {
fsm_err("Set params fail:%d", ret);
return ret;
}
return 0;
}
EXPORT_SYMBOL(q6fsm_set_rx_enable);
int q6fsm_set_rotation(int angle)
{
struct param_hdr_v3 param_hdr;
fsm_rotation_info_t param = {0};
int ret;
if (!q6fsm_get_rx_status()) {
fsm_info("RX module isn't ready");
return -EINVAL;
}
if(angle == 0){
param.angle = 0;
param.ch_sequence[0] = 0;
param.ch_sequence[1] = 1;
}else if(angle == 1){
param.angle = 180;
param.ch_sequence[0] = 1;
param.ch_sequence[1] = 0;
}else{
fsm_err("not support angle:%d",angle);
return -EINVAL;
}
param_hdr.module_id = AFE_MODULE_ID_FSADSP_RX;
param_hdr.instance_id = 0;
param_hdr.reserved = 0;
param_hdr.param_id = CAPI_V2_PARAM_FSADSP_ROTATION;
param_hdr.param_size = sizeof(fsm_rotation_info_t);
ret = q6fsm_afe_set_params(&param_hdr,
(uint8_t *)&param, sizeof(fsm_rotation_info_t));
if (ret) {
fsm_err("Set params fail:%d", ret);
return ret;
}
return 0;
}
EXPORT_SYMBOL(q6fsm_set_rotation);
void q6fsm_fsm_check_scene_status(bool status)
{
fsm_scene_status = status;
}
EXPORT_SYMBOL(q6fsm_fsm_check_scene_status);
#define PSY_DESC psy->desc
static int q6fsm_get_batv(struct q6fsm_afe *q6fsm, uint32_t *batv)
{
union power_supply_propval prop = { 0 };
struct power_supply *psy;
if (q6fsm == NULL || batv == NULL) {
fsm_err("Bad paramters");
return -EINVAL;
}
q6fsm->psy = power_supply_get_by_name("battery");
if (q6fsm->psy == NULL) {
fsm_err("get power supply failed");
return -EINVAL;
}
psy = q6fsm->psy;
if (PSY_DESC == NULL || PSY_DESC->get_property == NULL) {
fsm_err("Power desc/get_property is null!");
return -EINVAL;
}
PSY_DESC->get_property(psy,
POWER_SUPPLY_PROP_VOLTAGE_NOW, &prop);
*batv = prop.intval;
fsm_dbg("voltage: %d", *batv);
return 0;
}
static int q6fsm_get_bsg_config(struct q6fsm_afe *q6fsm)
{
struct param_hdr_v3 param_hdr;
struct bsg_config_v2 *config;
int interval;
int ret;
if (q6fsm == NULL)
return -EINVAL;
if (q6fsm->delay_period > 0)
return 0;
param_hdr.module_id = AFE_MODULE_ID_FSADSP_RX;
param_hdr.instance_id = 0;
param_hdr.reserved = 0;
param_hdr.param_id = CAPI_V2_PARAM_FSADSP_BSGV2_CONFIG;
param_hdr.param_size = sizeof(q6fsm->config);
ret = q6fsm_afe_get_params(&param_hdr,
(uint8_t *)&q6fsm->config, sizeof(q6fsm->config));
if (ret) {
fsm_err("Get params fail:%d", ret);
return ret;
}
config = &q6fsm->config;
if (!config->bsg_enable && !config->tc_mode_enable) {
fsm_info("BSG/CSG is disabled");
return 0x1000; /* Not enabled, stop the monitor */
}
if (config->bsg_enable)
interval = config->bsg_interval;
if (config->tc_mode_enable)
interval = config->tc_interval;
fsm_info("interval: %d", interval);
q6fsm->delay_period = interval*HZ/1000;
return 0;
}
static int q6fsm_gen_bsg_param(struct q6fsm_afe *q6fsm,
struct bsg_param_v2 *param)
{
union power_supply_propval prop = { 0 };
struct power_supply *psy;
if (q6fsm == NULL || param == NULL) {
fsm_err("Bad paramters");
return -EINVAL;
}
q6fsm->psy = power_supply_get_by_name("battery");
if (q6fsm->psy == NULL) {
fsm_err("get power supply failed");
return -EINVAL;
}
psy = q6fsm->psy;
if (PSY_DESC == NULL || PSY_DESC->get_property == NULL) {
fsm_err("Power desc/get_property is null!");
return -EINVAL;
}
param->bsg_mode = q6fsm->config.bsg_mode;
if (param->bsg_mode == 1) {
PSY_DESC->get_property(psy,
POWER_SUPPLY_PROP_VOLTAGE_NOW, &prop);
param->bsg_val = prop.intval;
} else if (param->bsg_mode == 2) {
PSY_DESC->get_property(psy,
POWER_SUPPLY_PROP_CAPACITY, &prop);
param->bsg_val = prop.intval;
} else {
param->bsg_val = 0;
}
param->tc_mode = q6fsm->config.tc_mode;
if (param->tc_mode == 3) {
PSY_DESC->get_property(psy,
POWER_SUPPLY_PROP_TEMP, &prop);
param->tc_val = prop.intval;
} else {
param->tc_val = 0;
}
fsm_dbg("bsg:%d-%d, tc:%d-%d",
param->bsg_mode, param->bsg_val,
param->tc_mode, param->tc_val);
return 0;
}
static int q6fsm_vbat_monitor_work_v2(struct q6fsm_afe *q6fsm)
{
struct param_hdr_v3 param_hdr;
struct bsg_param_v2 param;
int ret;
if (q6fsm == NULL)
return -EINVAL;
ret = q6fsm_get_bsg_config(q6fsm);
if (ret) {
if (ret != 0x1000)
fsm_err("Get bsg config fail:%d", ret);
return ret;
}
ret = q6fsm_gen_bsg_param(q6fsm, &param);
if (ret) {
fsm_err("Get batt voltage fail:%d", ret);
return ret;
}
param_hdr.module_id = AFE_MODULE_ID_FSADSP_RX;
param_hdr.instance_id = 0;
param_hdr.reserved = 0;
param_hdr.param_id = CAPI_V2_PARAM_FSADSP_BSGV2_PARAM;
param_hdr.param_size = sizeof(param);
ret = q6fsm_afe_set_params(&param_hdr,
(uint8_t *)&param, sizeof(param));
if (ret) {
fsm_err("Set params fail:%d", ret);
return ret;
}
return 0;
}
static int q6fsm_vbat_monitor_work(struct q6fsm_afe *q6fsm)
{
struct param_hdr_v3 param_hdr;
uint32_t batv;
int ret;
if (q6fsm == NULL)
return -EINVAL;
if (!q6fsm_get_rx_status()) {
fsm_info("RX module isn't ready");
return -EINVAL;
}
if (q6fsm->bsg_version == 2) {
ret = q6fsm_vbat_monitor_work_v2(q6fsm);
if (!ret || ret == 0x1000)
return ret;
}
q6fsm->bsg_version = 1;
q6fsm->delay_period = 2*HZ;
ret = q6fsm_get_batv(q6fsm, &batv);
if (ret) {
fsm_err("Get batt voltage fail:%d", ret);
return ret;
}
param_hdr.module_id = AFE_MODULE_ID_FSADSP_RX;
param_hdr.instance_id = 0;
param_hdr.reserved = 0;
param_hdr.param_id = CAPI_V2_PARAM_FSADSP_BSG_VBAT;
param_hdr.param_size = sizeof(batv);
ret = q6fsm_afe_set_params(&param_hdr,
(uint8_t *)&batv, sizeof(batv));
if (ret) {
fsm_err("Set params fail:%d", ret);
return ret;
}
return 0;
}
static void q6fsm_vbat_monitor(struct work_struct *work)
{
struct q6fsm_afe *q6fsm = g_fsm_afe;
int ret;
if (q6fsm == NULL)
return;
ret = q6fsm_vbat_monitor_work(q6fsm);
if (ret)
return;
/* reschedule */
queue_delayed_work(q6fsm->vbat_wq,
&q6fsm->vbat_work, q6fsm->delay_period);
}
static void q6fsm_monitor_switch(bool enable)
{
struct q6fsm_afe *q6fsm = g_fsm_afe;
if (q6fsm == NULL)
return;
fsm_info("%s", enable ? "enable" : "disable");
if (enable) {
if (q6fsm->monitor_en)
return;
if(fsm_scene_status == false){
fsm_info("no need to start vbat monitor");
return;
}
q6fsm->monitor_en = true;
queue_delayed_work(q6fsm->vbat_wq, &q6fsm->vbat_work, 0);
} else {
if (!q6fsm->monitor_en)
return;
q6fsm->monitor_en = false;
q6fsm->delay_period = 0;
cancel_delayed_work_sync(&q6fsm->vbat_work);
}
}
static ssize_t q6fsm_rx_show(struct class *class,
struct class_attribute *attr, char *buf)
{
struct param_hdr_v3 param_hdr;
int len, enable;
int ret;
if (!q6fsm_check_dsp_ready()) {
fsm_info("DSP not ready yet!");
return -EINVAL;
}
param_hdr.module_id = AFE_MODULE_ID_FSADSP_RX;
param_hdr.instance_id = 0;
param_hdr.reserved = 0;
param_hdr.param_id = CAPI_V2_PARAM_FSADSP_RX_ENABLE;
param_hdr.param_size = sizeof(enable);
ret = q6fsm_afe_get_params(&param_hdr,
(uint8_t *)&enable, sizeof(enable));
if (ret) {
fsm_err("Get params failed: %d", ret);
return ret;
}
len = scnprintf(buf, PAGE_SIZE, "%s\n",
enable ? "On" : "Off");
return len;
}
static ssize_t q6fsm_rx_store(struct class *class,
struct class_attribute *attr, const char *buf, size_t len)
{
struct param_hdr_v3 param_hdr;
int enable;
int ret = -1;
if (buf == NULL)
return -ENOMEM;
enable = simple_strtoul(buf, NULL, 0);
if (!q6fsm_check_dsp_ready()) {
fsm_info("DSP not ready yet!");
return ret;
}
param_hdr.module_id = AFE_MODULE_ID_FSADSP_RX;
param_hdr.instance_id = 0;
param_hdr.reserved = 0;
param_hdr.param_id = CAPI_V2_PARAM_FSADSP_RX_ENABLE;
param_hdr.param_size = sizeof(enable);
enable = !!enable;
ret = q6fsm_afe_set_params(&param_hdr,
(uint8_t *)&enable, sizeof(enable));
if (ret) {
fsm_err("Set params failed: %d", ret);
return ret;
}
return len;
}
static ssize_t q6fsm_bsg_show(struct class *class,
struct class_attribute *attr, char *buf)
{
struct q6fsm_afe *q6fsm = g_fsm_afe;
int len;
if (q6fsm == NULL)
return -EINVAL;
len = scnprintf(buf, PAGE_SIZE, "%s\n",
q6fsm->monitor_en ? "On" : "Off");
return len;
}
static ssize_t q6fsm_bsg_store(struct class *class,
struct class_attribute *attr, const char *buf, size_t len)
{
int enable;
if (buf == NULL)
return -ENOMEM;
enable = simple_strtoul(buf, NULL, 0);
q6fsm_monitor_switch(!!enable);
return len;
}
static CLASS_ATTR_RW(q6fsm_rx);
static CLASS_ATTR_RW(q6fsm_bsg);
static struct attribute *q6fsm_class_attrs[] = {
&class_attr_q6fsm_rx.attr,
&class_attr_q6fsm_bsg.attr,
NULL,
};
ATTRIBUTE_GROUPS(q6fsm_class);
/** Device model classes */
struct class g_q6fsm_class = {
.name = "q6fsm",
.class_groups = q6fsm_class_groups,
};
static int __init q6fsm_afe_init(void)
{
struct q6fsm_afe *q6fsm;
fsm_info("version: %s", Q6FSM_VERSION);
q6fsm = kzalloc(sizeof(struct q6fsm_afe), GFP_KERNEL);
if (q6fsm == NULL) {
fsm_err("alloc memery failed");
return -ENOMEM;
}
mutex_init(&q6fsm->cmd_lock);
atomic_set(&q6fsm->bsg_switch, 0);
/* BSG V1 */
//q6fsm->delay_period = 2*HZ;
//q6fsm->bsg_version = 1;
/* BSG V2 */
q6fsm->delay_period = 0; /* Get from adsp */
q6fsm->bsg_version = 2;
q6fsm->monitor_en = false;
q6fsm->vbat_wq = create_singlethread_workqueue("q6fsm-vbat");
INIT_DELAYED_WORK(&q6fsm->vbat_work, q6fsm_vbat_monitor);
/* path: sys/class/$(CLASS NAME) */
class_register(&g_q6fsm_class);
g_fsm_afe = q6fsm;
return 0;
}
static void q6fsm_afe_deinit(void)
{
struct q6fsm_afe *q6fsm = g_fsm_afe;
if (q6fsm == NULL)
return;
cancel_delayed_work_sync(&q6fsm->vbat_work);
destroy_workqueue(q6fsm->vbat_wq);
mutex_destroy(&q6fsm->cmd_lock);
kfree(g_fsm_afe);
g_fsm_afe = NULL;
}
#endif // __Q6FSM_V3_H__

View file

@ -3874,7 +3874,21 @@ static int swrm_suspend(struct device *dev)
dev_dbg(swrm->dev, "%s: suspending system, state %d, wlock %d\n",
__func__, swrm->pm_state,
swrm->wlock_holders);
swrm->pm_state = SWRM_PM_ASLEEP;
/*
* before updating the pm_state to ASLEEP, check if device is
* runtime suspended or not. If it is not, then first make it
* runtime suspend, and then update the pm_state to ASLEEP.
*/
mutex_unlock(&swrm->pm_lock); /* release pm_lock before dev suspend */
swrm_device_suspend(swrm->dev); /* runtime suspend the device */
mutex_lock(&swrm->pm_lock); /* acquire pm_lock and update state */
if (swrm->pm_state == SWRM_PM_SLEEPABLE) {
swrm->pm_state = SWRM_PM_ASLEEP;
} else if (swrm->pm_state == SWRM_PM_AWAKE) {
ret = -EBUSY;
mutex_unlock(&swrm->pm_lock);
goto check_ebusy;
}
} else if (swrm->pm_state == SWRM_PM_AWAKE) {
/*
* unlock to wait for pm_state == SWRM_PM_SLEEPABLE
@ -3927,6 +3941,7 @@ static int swrm_suspend(struct device *dev)
pm_runtime_enable(dev);
}
}
check_ebusy:
if (ret == -EBUSY) {
/*
* There is a possibility that some audio stream is active