"Devon push for Android 13"

* tag 'MMI-T2SN33.73-22-3' of https://github.com/MotorolaMobilityLLC/vendor-qcom-opensource-audio-kernel:
  ASoC: msm-pcm-host-voice: Address buffer overflow in hpcm capture copy
  dsp: q6adm: Resolve mem corruption in adm cb
  dsp: afe: check for param size before copying
  asoc: update q6afe for aw882xx
  mbhc: set the type to lineout when zl or zr is zero.
  asoc: update aw882xx driver to v1.9.0.9
  asoc: change linein threshold
  asoc: update aw88261 driver's spin relase function
  asoc: devon support get awinic skt params from ram
  audio-kernel: enable CONFIG_AW882XX_MAPSIZE_16K for rhode
  audio-kernel: enlarge map size for aw882xx algo
  asoc: audio:update aw882xx driver to v1.9.0.7
  asoc: upgrade aw88261 driver to v1.9.0.6
  asoc: fix wcd937x build error
  audio: wcd937x_slave: Add retry while getting logical addr for wcd937x slave
  audio-kernel: modify rcv and spk smartpa config
  audio-kernel: devon fix build error
  audio-kernel: devon audio bring up
  asoc: upgrade aw88261 driver to v1.9.0.5
  asoc:update aw88261 spin config
  asoc:remove debug info for aw88261
  asoc:upgrade aw88261 driver to v 1.9.0.4
  asoc:upgrade aw88261 driver to v1.9.0.3
  hawaii OLED: hawao audio bringup
  hawaii OLED: hawao audio bringup
  asoc:upgrade aw88261 driver to v1.9.0.2
  asoc:upgrade aw88261 driver to v1.9 debug version
  rhode:mbhc:enable moisture detect for rhode
  rhode: audio: update awinic smartpa driver to V1.8.0.1
  rhode: audio: enable aw882xx algo param store in aw_skt.bin
  asoc:update audio config for rhode
  mbhc:disable moisture detect for rhode
  asoc:init rhode audio
  asoc:add aw88261 codec driver
  asoc: Add fs1818 support for guamp/guamna
  ASoC: update aw882xx driver to v0.1.17
  update aw882xx driver to v0.1.16
  soc: soundwire: Update hw_ctl on HCLK at bootup
  asoc:Enable necessary log for mbhc
  Audio bringup: asoc: add aw882xx support

 Conflicts:
	techpack/audio/asoc/codecs/Kbuild
	techpack/audio/asoc/msm-pcm-host-voice-v2.c
	techpack/audio/dsp/q6adm.c

Change-Id: Ia248afaace87b74c0003a41fd7c8087e5c77e8dd
This commit is contained in:
Michael Bestas committed 2024-01-03 01:17:26 +02:00
commit 70b29d0d24
53 files changed
+36638 -21

No files matched your search

+11
View File
@@ -96,6 +96,17 @@ ifeq ($(KERNEL_BUILD), 0)
export
INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h
endif
ifneq (,$(filter rhode%, $(TARGET_PRODUCT)))
INCS += -include $(AUDIO_ROOT)/config/rhodeautoconf.h
endif
ifneq (,$(filter hawao%, $(TARGET_PRODUCT)))
INCS += -include $(AUDIO_ROOT)/config/hawaoautoconf.h
endif
ifneq (,$(filter devon%, $(TARGET_PRODUCT)))
INCS += -include $(AUDIO_ROOT)/config/devonautoconf.h
endif
endif
# As per target team, build is done as follows:
+176 -3
View File
@@ -378,7 +378,11 @@ static struct dev_config mi2s_rx_cfg[] = {
};
static struct dev_config mi2s_tx_cfg[] = {
#ifdef CONFIG_SND_SMARTPA_AW882XX
[PRIM_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
#else
[PRIM_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
#endif
[SEC_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
[TERT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
[QUAT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
@@ -579,7 +583,7 @@ static struct wcd_mbhc_config wcd_mbhc_cfg = {
.key_code[5] = 0,
.key_code[6] = 0,
.key_code[7] = 0,
.linein_th = 5000,
.linein_th = 4000,
.moisture_en = false,
.mbhc_micbias = MIC_BIAS_2,
.anc_micbias = MIC_BIAS_2,
@@ -4389,8 +4393,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;//75;
btn_high[1] = 138;//150;
btn_high[2] = 237;
btn_high[3] = 500;
btn_high[4] = 500;
@@ -5060,6 +5064,26 @@ static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = {
},
};
#ifdef CONFIG_SND_SMARTPA_AW882XX
static struct snd_soc_dai_link msm_awinic_fe_dai_links[] = {
{
.name = "Primary MI2S TX_Hostless",
.stream_name = "Primary MI2S_TX Hostless Capture",
.cpu_dai_name = "PRI_MI2S_TX_HOSTLESS",
.platform_name = "msm-pcm-hostless",
.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,
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
};
#endif
static struct snd_soc_dai_link msm_common_be_dai_links[] = {
/* Backend AFE DAI Links */
{
@@ -5376,14 +5400,113 @@ static struct snd_soc_dai_link msm_wcn_btfm_be_dai_links[] = {
},
};
#ifdef CONFIG_SND_SMARTPA_AW882XX
static struct snd_soc_dai_link msm_awinic_be_dai_links[] = {
{
.name = LPASS_BE_PRI_MI2S_RX,
.stream_name = "Primary MI2S Playback",
.cpu_dai_name = "msm-dai-q6-mi2s.0",
.platform_name = "msm-pcm-routing",
.codec_name = "aw882xx_smartpa.1-0034",
.codec_dai_name = "aw882xx-aif",
.no_pcm = 1,
.dpcm_playback = 1,
.id = MSM_BACKEND_DAI_PRI_MI2S_RX,
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ops = &msm_mi2s_be_ops,
.ignore_suspend = 1,
.ignore_pmdown_time = 1,
},
{
.name = LPASS_BE_PRI_MI2S_TX,
.stream_name = "Primary MI2S Capture",
.cpu_dai_name = "msm-dai-q6-mi2s.0",
.platform_name = "msm-pcm-routing",
.codec_name = "aw882xx_smartpa.1-0034",
.codec_dai_name = "aw882xx-aif",
.no_pcm = 1,
.dpcm_capture = 1,
.id = MSM_BACKEND_DAI_PRI_MI2S_TX,
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ops = &msm_mi2s_be_ops,
.ignore_suspend = 1,
},
};
static struct snd_soc_dai_link_component awinic_codecs[] = {
{
.of_node = NULL,
.dai_name = "aw882xx-aif-1-34",
.name = "aw882xxacf_smartpa.1-0034",
},
#ifdef CONFIG_HAWAO_AW882XX_SMARTPA
{
.of_node = NULL,
.dai_name = "aw882xx-aif-1-35",
.name = "aw882xxacf_smartpa.1-0035",
},
#elif defined(CONFIG_DEVON_AW882XX_SMARTPA)
{
.of_node = NULL,
.dai_name = "aw882xx-aif-1-35",
.name = "aw882xxacf_smartpa.1-0035",
},
#else
{
.of_node = NULL,
.dai_name = "aw882xx-aif-1-37",
.name = "aw882xxacf_smartpa.1-0037",
},
#endif
};
static struct snd_soc_dai_link msm_stereo_awinic_be_dai_links[] = {
{
.name = LPASS_BE_PRI_MI2S_RX,
.stream_name = "Primary MI2S Playback",
.cpu_dai_name = "msm-dai-q6-mi2s.0",
.platform_name = "msm-pcm-routing",
.num_codecs = ARRAY_SIZE(awinic_codecs),
.codecs = awinic_codecs,
.no_pcm = 1,
.dpcm_playback = 1,
.id = MSM_BACKEND_DAI_PRI_MI2S_RX,
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ops = &msm_mi2s_be_ops,
.ignore_suspend = 1,
.ignore_pmdown_time = 1,
},
{
.name = LPASS_BE_PRI_MI2S_TX,
.stream_name = "Primary MI2S Capture",
.cpu_dai_name = "msm-dai-q6-mi2s.0",
.platform_name = "msm-pcm-routing",
.num_codecs = ARRAY_SIZE(awinic_codecs),
.codecs = awinic_codecs,
.no_pcm = 1,
.dpcm_capture = 1,
.id = MSM_BACKEND_DAI_PRI_MI2S_TX,
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ops = &msm_mi2s_be_ops,
.ignore_suspend = 1,
},
};
#endif
#if !defined(CONFIG_SND_SMARTPA_AW882XX)
static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = {
{
.name = LPASS_BE_PRI_MI2S_RX,
.stream_name = "Primary MI2S Playback",
.cpu_dai_name = "msm-dai-q6-mi2s.0",
.platform_name = "msm-pcm-routing",
#ifdef CONFIG_SND_SOC_FS16XX
.codec_name = "fs16xx.1-0034",
.codec_dai_name = "fs16xx_codec_left",
#else
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-rx",
#endif
.no_pcm = 1,
.dpcm_playback = 1,
.id = MSM_BACKEND_DAI_PRI_MI2S_RX,
@@ -5494,6 +5617,7 @@ static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = {
.ignore_suspend = 1,
},
};
#endif
static struct snd_soc_dai_link msm_auxpcm_be_dai_links[] = {
/* Primary AUX PCM Backend DAI Links */
@@ -5780,12 +5904,18 @@ static struct snd_soc_dai_link msm_bengal_dai_links[
ARRAY_SIZE(msm_common_dai_links) +
ARRAY_SIZE(msm_common_misc_fe_dai_links) +
ARRAY_SIZE(msm_common_be_dai_links) +
#if !defined(CONFIG_SND_SMARTPA_AW882XX)
ARRAY_SIZE(msm_mi2s_be_dai_links) +
#endif
ARRAY_SIZE(msm_auxpcm_be_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) +
#ifdef CONFIG_SND_SMARTPA_AW882XX
ARRAY_SIZE(msm_awinic_fe_dai_links) +
ARRAY_SIZE(msm_awinic_be_dai_links) +
#endif
ARRAY_SIZE(msm_tdm_be_dai_links)];
static int msm_populate_dai_link_component_of_node(
@@ -6048,13 +6178,18 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
int len_2 = 0;
int total_links = 0;
int rc = 0;
#if !defined(CONFIG_SND_SMARTPA_AW882XX)
u32 mi2s_audio_intf = 0;
#endif
u32 auxpcm_audio_intf = 0;
u32 rxtx_bolero_codec = 0;
u32 va_bolero_codec = 0;
u32 val = 0;
u32 wcn_btfm_intf = 0;
const struct of_device_id *match;
#ifdef CONFIG_SND_SMARTPA_AW882XX
u32 has_awinic_pa = 0;
#endif
match = of_match_node(bengal_asoc_machine_of_match, dev->of_node);
if (!match) {
@@ -6113,6 +6248,7 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
}
}
#if !defined(CONFIG_SND_SMARTPA_AW882XX)
rc = of_property_read_u32(dev->of_node, "qcom,mi2s-audio-intf",
&mi2s_audio_intf);
if (rc) {
@@ -6127,6 +6263,7 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
ARRAY_SIZE(msm_mi2s_be_dai_links);
}
}
#endif
rc = of_property_read_u32(dev->of_node,
"qcom,auxpcm-audio-intf",
@@ -6147,6 +6284,7 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
rc = of_property_read_u32(dev->of_node, "qcom,afe-rxtx-lb",
&val);
if (!rc && val) {
memcpy(msm_bengal_dai_links + total_links,
msm_afe_rxtx_lb_be_dai_link,
sizeof(msm_afe_rxtx_lb_be_dai_link));
@@ -6178,6 +6316,41 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
ARRAY_SIZE(msm_wcn_btfm_be_dai_links);
}
}
#ifdef CONFIG_SND_SMARTPA_AW882XX
rc = of_property_read_u32(dev->of_node, "aw,have-882xx",
&has_awinic_pa);
if (rc) {
dev_dbg(dev, "%s: No DT match awinic audio interface\n",
__func__);
} else {
dev_dbg(dev,"%s,aw,has-882xx=%d\n",__func__,has_awinic_pa);
if (has_awinic_pa == 1) {
memcpy(msm_bengal_dai_links + total_links,
msm_awinic_fe_dai_links,
sizeof(msm_awinic_fe_dai_links));
total_links +=
ARRAY_SIZE(msm_awinic_fe_dai_links);
memcpy(msm_bengal_dai_links + total_links,
msm_awinic_be_dai_links,
sizeof(msm_awinic_be_dai_links));
total_links +=
ARRAY_SIZE(msm_awinic_be_dai_links);
} else if (has_awinic_pa == 2) {
memcpy(msm_bengal_dai_links + total_links,
msm_awinic_fe_dai_links,
sizeof(msm_awinic_fe_dai_links));
total_links +=
ARRAY_SIZE(msm_awinic_fe_dai_links);
memcpy(msm_bengal_dai_links + total_links,
msm_stereo_awinic_be_dai_links,
sizeof(msm_stereo_awinic_be_dai_links));
total_links +=
ARRAY_SIZE(msm_stereo_awinic_be_dai_links);
}
}
#endif
dailink = msm_bengal_dai_links;
} else if (!strcmp(match->data, "stub_codec")) {
card = &snd_soc_card_stub_msm;
+16
View File
@@ -167,6 +167,22 @@ LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
include $(DLKM_DIR)/AndroidKernelModule.mk
endif
###########################################################
include $(CLEAR_VARS)
LOCAL_MODULE := $(AUDIO_CHIPSET)_snd_soc_aw882xx.ko
LOCAL_MODULE_KBUILD_NAME := aw882xx_dlkm.ko
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_DEBUG_ENABLE := true
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
include $(DLKM_DIR)/AndroidKernelModule.mk
###########################################################
include $(CLEAR_VARS)
LOCAL_MODULE := $(AUDIO_CHIPSET)_snd_soc_fs16xx.ko
LOCAL_MODULE_KBUILD_NAME := fs16xx_dlkm.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
+41
View File
@@ -90,6 +90,17 @@ ifeq ($(KERNEL_BUILD), 0)
export
INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h
endif
ifneq (,$(filter rhode%, $(TARGET_PRODUCT)))
INCS += -include $(AUDIO_ROOT)/config/rhodeautoconf.h
endif
ifneq (,$(filter hawao%, $(TARGET_PRODUCT)))
INCS += -include $(AUDIO_ROOT)/config/hawaoautoconf.h
endif
ifneq (,$(filter devon%, $(TARGET_PRODUCT)))
INCS += -include $(AUDIO_ROOT)/config/devonautoconf.h
endif
endif
# As per target team, build is done as follows:
@@ -252,6 +263,8 @@ ifeq ($(KERNEL_BUILD), 1)
obj-y += rouleur/
obj-y += wsa883x/
obj-y += sdm660_cdc/
obj-y += awinic/
obj-y += foursemi/
endif
# Module information used by KBuild framework
obj-$(CONFIG_WCD9XXX_CODEC_CORE) += wcd_core_dlkm.o
@@ -284,3 +297,31 @@ mbhc_dlkm-y := $(MBHC_OBJS)
obj-$(CONFIG_SND_SOC_MSM_HDMI_CODEC_RX) += hdmi_dlkm.o
hdmi_dlkm-y := $(HDMICODEC_OBJS)
#Add awinic driver begain
ifdef CONFIG_SND_SMARTPA_AW882XX
ifneq (,$(filter rhode% hawao% devon%, $(TARGET_PRODUCT)))
SND_SOC_AW882XX_OBJS += aw88261/aw882xx.o
SND_SOC_AW882XX_OBJS += aw88261/aw_init.o
SND_SOC_AW882XX_OBJS += aw88261/aw_bin_parse.o
SND_SOC_AW882XX_OBJS += aw88261/aw_calib.o
SND_SOC_AW882XX_OBJS += aw88261/aw_device.o
SND_SOC_AW882XX_OBJS += aw88261/aw_dsp.o
SND_SOC_AW882XX_OBJS += aw88261/aw_monitor.o
else
SND_SOC_AW882XX_OBJS += awinic/aw882xx.o
endif
endif
obj-$(CONFIG_SND_SMARTPA_AW882XX) += aw882xx_dlkm.o
aw882xx_dlkm-y := $(SND_SOC_AW882XX_OBJS)
#Add awinic driver end
#Add fs1818 driver begain
ifdef CONFIG_SND_SOC_FS16XX
SND_SOC_FS16XX_OBJS += foursemi/fs16xx.o
SND_SOC_FS16XX_OBJS += foursemi/fs16xx_preset.o
SND_SOC_FS16XX_OBJS += foursemi/fs16xx_calibration.o
endif
obj-$(CONFIG_SND_SOC_FS16XX) += fs16xx_dlkm.o
fs16xx_dlkm-y := $(SND_SOC_FS16XX_OBJS)
#Add fs1818 driver end
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,278 @@
#ifndef _AW882XX_H_
#define _AW882XX_H_
#include <linux/version.h>
#include <linux/kernel.h>
#ifndef AW_SPIN_ENABLE
#define AW_SPIN_ENABLE 1
#endif
#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 CONFIG_AW882XX_ALGO_BIN_PARAMS
#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_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
@@ -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;
}
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,325 @@
#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);
int aw_dev_set_algo_params_path(struct aw_device *aw_dev);
int aw_device_probe(struct aw_device *aw_dev);
int aw_device_remove(struct aw_device *aw_dev);
int aw_dev_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
@@ -0,0 +1,83 @@
#ifndef __AWINIC_DSP_H__
#define __AWINIC_DSP_H__
#define AW_QCOM_PLATFORM
#ifndef AW_SPIN_ENABLE
#define AW_SPIN_ENABLE 1
#endif
/*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
@@ -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
@@ -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
File diff suppressed because it is too large. Load diff
+282
View File
@@ -0,0 +1,282 @@
#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 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)
enum {
AW_FIRST_ENTRY = 0,
AW_NOT_FIRST_ENTRY = 1,
};
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,
};
#define AW882XX_CALI_CFG_NUM 3
#define AW882XX_CALI_DATA_NUM 6
#define AW882XX_PARAMS_NUM 400
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;
};
#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)
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
@@ -0,0 +1,5 @@
config SND_SOC_FS16XX
tristate "Support foursemi fs16xx chip"
depends on I2C
help
foursemi fs16xx driver
@@ -0,0 +1,9 @@
###
# Copyright (C) 2018 Fourier Semiconductor Inc. All rights reserved.
#
# FS16XX VERSION INFO, DON'T REMOVE THIS LINE!!!
snd-soc-fs16xx-objs := fs16xx.o
snd-soc-fs16xx-objs += fs16xx_preset.o
snd-soc-fs16xx-objs += fs16xx_calibration.o
obj-$(CONFIG_SND_SOC_FS16XX) += snd-soc-fs16xx.o
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,190 @@
/*
* Fs16xx device driver header file.
* Copyright (C) 2017 FourSemi Inc.
*
* 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 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FS16XX_DRIVER_H__
#define __FS16XX_DRIVER_H__
#ifdef __KERNEL__
#include <linux/version.h>
#include <linux/cdev.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include <sound/core.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#endif
#include "fs16xx_define.h"
#include "fs16xx_preset.h"
#include "fs16xx_calibration.h"
// Macro for kernel mode implementation
#define FS16XX_KERNEL_IMPL
#define MAX_DEV_HANDLES 4
struct Fs16xx_device_handle {
int in_use;
unsigned char device_address;
unsigned char device_id;
unsigned char revision;
void *fs16xx; /* Pointer to fs16xx_dev_t */
};
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof((arr)[0]))
#endif
struct fs16xx_regs {
int reg;
int value;
};
/* I2S_CONTROL bits for sample rates */
#define FS16XX_I2SCTRL_RATE_08000 (0<<FS16XX_I2SCTRL_REG_I2SSR_POS)
#define FS16XX_I2SCTRL_RATE_16000 (3<<FS16XX_I2SCTRL_REG_I2SSR_POS)
#define FS16XX_I2SCTRL_RATE_44100 (7<<FS16XX_I2SCTRL_REG_I2SSR_POS)
#define FS16XX_I2SCTRL_RATE_48000 (8<<FS16XX_I2SCTRL_REG_I2SSR_POS)
#define UNUSED(x) (void)(x)
#ifdef __KERNEL__
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 10, 40))
#define Sleep(ms) usleep(1000*(ms))
#else
#define Sleep(ms) usleep_range(1000*(ms),1000*(ms))
#endif
#elif defined(__ANDROID__)
#define Sleep(ms) usleep(ms * 1000)
#endif
#define ACS_DRC_CTRL_LEN 3
#define FS16XX_GIT_BRANCH "tinno_qcom_fs1818_mono"
#define FS16XX_GIT_COMMIT "47e83a9"
#define FS16XX_CODE_DATE "20200217_1111"
#define FS16XX_CODE_VERSION "v1.3.2"
#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_register_codec devm_snd_soc_register_component
#define snd_soc_unregister_codec snd_soc_unregister_component
#define snd_soc_codec_driver snd_soc_component_driver
#endif
struct _fs_dev_state {
int cur_preset;
bool ras;
unsigned short tmax;
unsigned short tempr_coef;
unsigned short tempr_sel;
unsigned short spk_set;
unsigned short adp_bst;
unsigned short bst_ctrl;
unsigned short ts_ctrl;
unsigned short acs_drc_ctrl[ACS_DRC_CTRL_LEN];
Fs16xx_preset *dev_preset;
Fs16xx_Calib_State_t calib_state;
Fs16xx_Calib_Result_t calib_result;
};
typedef struct _fs_dev_state Fs_Dev_State;
struct fs16xx_priv {
#ifdef __KERNEL__
struct i2c_client *control_data;
struct regulator *vdd;
struct snd_soc_codec *codec;
struct workqueue_struct *fs16xx_wq;
struct work_struct init_work;
struct work_struct calib_work;
struct delayed_work mode_work;
struct work_struct load_preset;
struct delayed_work delay_work;
struct mutex i2c_rw_lock;
#elif defined(__ANDROID__)
int fd; /* file handle of opening i2c node. */
struct i2c_client *client[2]; /* i2c client for i2c operation in kernel. */
#endif
int dsp_init;
int speaker_imp;
int sysclk;
int mode;
int mode_switched;
int curr_mode;
int cfg_preset;
int ic_version;
char const *fs16xx_dev;
char const *fw_path;
char const *fw_name;
int is_spkr_prot_en;
int update_eq;
int update_cfg;
int is_pcm_triggered;
Fs_Dev_State dev_state;
Fs16xx_devId_t id;
};
typedef struct fs16xx_priv fs16xx_dev_t;
struct fs16xx_pdata {
int reset_gpio;
int max_vol_steps;
const char *fs_dev;
const char *fw_path;
const char *fw_name;
};
/* DSP init status */
#define FS16XX_DSP_INIT_PENDING 0
#define FS16XX_DSP_INIT_OK 1
#define FS16XX_DSP_INIT_FAIL -1
/* FsDbg print for Linux kernel */
#define PRINT(msg,va...) pr_info(msg "\n", ##va) //pr_info
#define PRINT_ERROR(msg,va...) pr_err(msg "\n", ##va)
#define DEBUGPRINT(msg,va...) pr_debug(msg "\n", ##va) //pr_debug
Fs16xx_Error_t fs16xx_write_register16(Fs16xx_devId_t id,
unsigned char subaddress,
unsigned short value);
Fs16xx_Error_t fs16xx_read_register16(Fs16xx_devId_t id,
unsigned char subaddress,
unsigned short *pValue);
Fs16xx_Error_t fs16xx_handle_is_open(Fs16xx_devId_t id);
Fs_Dev_State* fs16xx_get_dev_state_by_id(Fs16xx_devId_t id);
struct snd_soc_codec * fs16xx_get_codec_by_id(Fs16xx_devId_t id);
Fs16xx_Error_t fs16xx_wait_boost_ssend(struct snd_soc_codec *codec);
Fs16xx_Error_t fs16xx_wait_dsp_off(Fs16xx_devId_t id, int wait_for_adc, int max_try);
#endif
@@ -0,0 +1,734 @@
#include "fs16xx.h"
#include "fs16xx_regs.h"
#include "fs16xx_calibration.h"
static int calib_r0 = R0_DEFAULT;
static int calib_allow_low = R0_ALLOWANCE_LOW;
static int calib_allow_high = R0_ALLOWANCE_HIGH;
static int calib_r0_step = FS16XX_CALIB_OTP_R25_STEP;
static int calib_r0_delta = OTP_MIN_DELTA;
//#ifdef USE_RAS_MODE
static int calib_r0_ras = R0_DEFAULT_RAS;
static int calib_allow_low_ras = R0_ALLOWANCE_LOW_RAS;
static int calib_allow_high_ras = R0_ALLOWANCE_HIGH_RAS;
static int calib_r0_step_ras = FS16XX_CALIB_OTP_R25_STEP_RAS;
//#endif
Fs16xx_Error_t fs16xx_calibration(Fs16xx_devId_t id, int force, int storeResult) {
int count = 0, maxTryCount = 100;
unsigned short val, preVal = 0, minVal = 0;
unsigned int done = 0;
const int zmReadCount = 10;
Fs_Dev_State *dev_state = NULL;
PRINT("%s enter. id=%d force=%d storeResult=%d", __func__, id, force, storeResult);
dev_state = fs16xx_get_dev_state_by_id(id);
if(!dev_state) {
PRINT_ERROR("%s invalid id, exit!", __func__);
return Fs16xx_Error_StateInvalid;
}
if(force || dev_state->calib_state == Fs16xx_Calib_NotStarted
|| dev_state->calib_state == Fs16xx_Calib_Failed
|| dev_state->calib_state == Fs16xx_Calib_OTP_Failed) {
fs16xx_write_register16(id, FS16XX_OTPACC_REG, FS16XX_OTP_ACC_KEY2);
// Start calibration
fs16xx_write_register16(id, FS16XX_ZMCONFIG_REG, 0x0010);
fs16xx_write_register16(id, 0xAF, CALIB_REG_CALIB_MODE_AF);
fs16xx_write_register16(id, FS16XX_AUDIOCTRL_REG, 0x8F00);
fs16xx_write_register16(id, 0xC9, 0x0000);
fs16xx_write_register16(id, 0xCA, 0x0000);
fs16xx_write_register16(id, 0xCB, 0x0000);
fs16xx_write_register16(id, 0xCC, 0x0000);
fs16xx_write_register16(id, 0xB9, 0xFFFF);
fs16xx_write_register16(id, 0xBA, CALIB_REG_NORMAL_BA);
if(!force && dev_state->calib_state == Fs16xx_Calib_NotStarted) {
// Sleep during the first time calibration
Sleep(2500);
}
(dev_state->calib_result).calib_count++;
dev_state->calib_state = Fs16xx_Calib_OnGoing;
while((!done) && (maxTryCount > 0)) {
Sleep(100);
maxTryCount--;
if(Fs16xx_Error_OK == fs16xx_read_register16(id, FS16XX_ZMDATA_REG, &val)) {
if(val != 0 && val != 0xFFFF) {
if (preVal == 0 || abs(preVal - val) > SPK_CALIBRATION_MAX_ZMDELTA) {
preVal = val;
count = 1; // Reset counter
minVal = val;
} else {
count++;
if(val < minVal) {
minVal = val;
}
}
}
}
if(count >= zmReadCount) {
done = 1;
}
}
if(done && minVal != 0) {
dev_state->calib_state = fs16xx_calc_coef_from_zm(id, minVal, storeResult);
if(Fs16xx_Calib_OK == dev_state->calib_state) {
fs16xx_write_register16(id, FS16XX_AUDIOCTRL_REG, 0xFF00);
// Calibration OK, exit calibration
fs16xx_write_register16(id, FS16XX_ZMCONFIG_REG, 0x0000);
fs16xx_write_register16(id, 0xAF, CALIB_REG_NORMAL_AF);
}
if(Fs16xx_Calib_OTP_ExcceedMaxTry == dev_state->calib_state) {
// Calibration was done. However, OTP write failed due to counter limitation.
// In this case, we will NOT exit calibration mode in order to report calibration failure.
}
} else {
// Calibration failed
dev_state->calib_state = Fs16xx_Calib_Failed;
PRINT_ERROR("%s calibration failed. done=%d minVal=0x%04X", __func__, done, minVal);
}
} else {
fs16xx_write_register16(id, FS16XX_OTPACC_REG, 0);
return Fs16xx_Error_Calib_Error;
}
PRINT("%s calibration end, result = %s.", __func__, dev_state->calib_state == Fs16xx_Calib_OK ? "OK" : "Failed");
fs16xx_write_register16(id, FS16XX_OTPACC_REG, 0);
return Fs16xx_Error_OK;
}
Fs16xx_Calib_State_t fs16xx_check_calibration(Fs16xx_devId_t id) {
#ifndef FS16XX_CALIB_STORE_TO_OTP
FILE *fp;
#endif
int count;
Fs16xx_Error_t err = Fs16xx_Error_OK;
unsigned short value = 0, valueC4 = 0;
unsigned int r25;
Fs_Dev_State *dev_state = NULL;
Fs16xx_Calib_Result_t *calib_result;
DEBUGPRINT("%s enter. id=%d", __func__, id);
dev_state = fs16xx_get_dev_state_by_id(id);
if(!dev_state) {
PRINT_ERROR("%s invalid id, exit!", __func__);
//return Fs16xx_Error_StateInvalid;
return Fs16xx_Calib_Unknown;
}
calib_result = &(dev_state->calib_result);
PRINT("%s enter id=%d, calib_state=%d", __func__, id, dev_state->calib_state);
if(Fs16xx_Calib_Unknown != dev_state->calib_state) {
return dev_state->calib_state;
}
// Apply values from preset
fs16xx_spkset_to_calib_coef(dev_state->ras,dev_state->spk_set);
calib_result->calib_count = 0;
err |= fs16xx_read_register16(id, FS16XX_PLLCTRL4_REG, &valueC4);
err |= fs16xx_write_register16(id, FS16XX_PLLCTRL4_REG, 0x000F);
err |= fs16xx_write_register16(id, FS16XX_OTPACC_REG, FS16XX_OTP_ACC_KEY2);
#ifdef FS16XX_CALIB_STORE_TO_OTP
// Read from 0xE8 first
err |= fs16xx_read_register16(id, 0xE8, &value);
if(Fs16xx_Error_OK != err) {
PRINT_ERROR("%s failed to read calibration result by otp cmd.", __func__);
}
if(value == OTP_INIT_VALUE) {
count = 0;
} else {
count = fs16xx_get_otp_write_count(value & 0xFF);
}
PRINT("%s read calibration result = 0x%04x count=%d.", __func__, value, count);
// Calibration Count
if(count > 0) {
PRINT("%s calibrated already done.", __func__);
calib_result->calib_count = count;
} else {
// Need calibration
dev_state->calib_state = Fs16xx_Calib_NotStarted;
PRINT("%s calibrated not started.", __func__);
goto calib_exit;
}
r25 = fs16xx_byte_to_r25(dev_state->ras,(unsigned char)((value >> 8) & 0xFF));
PRINT("%s read calibration result from otp r25=%d.", __func__, r25);
dev_state->calib_state = fs16xx_update_coef_from_r25(id, r25);
// ADC EN and TS EN should be set when osc is enabled.
fs16xx_write_register16(id, FS16XX_ADCTIME_REG, CALIB_REG_NORMAL_BA);
fs16xx_write_register16(id, FS16XX_TSCTRL_REG, CALIB_REG_NORMAL_AF);
#else
fp = fopen( FS16XX_PARAM_DIR FS16XX_CALIB_RESULT_FILE_NAME, "rb");
if (!fp)
{
PRINT_ERROR("%s read calibration result failed.", __func__);
dev_state->calib_state = Fs16xx_Calib_NotStarted;
goto calib_exit;
}
count = fread( (void*)calib_result, 1, sizeof(Fs16xx_Calib_Result_t), fp );
fclose(fp);
PRINT("%s read calibration file, count=%d.", __func__, count);
if(count != sizeof(Fs16xx_Calib_Result_t)) {
// Calibration result file corrupted.
PRINT_ERROR("%s read calibration result corrupted.", __func__);
dev_state->calib_state = Fs16xx_Calib_NotStarted;
goto calib_exit;
}
fs16xx_calc_coef_from_zm(id, calib_result->calib_result_zm, 0);
#endif
calib_exit:
err |= fs16xx_write_register16(id, FS16XX_OTPACC_REG, 0);
err |= fs16xx_write_register16(id, FS16XX_PLLCTRL4_REG, valueC4);
DEBUGPRINT("%s Exit.", __func__);
return dev_state->calib_state;
}
Fs16xx_Error_t fs16xx_get_calibration_result(Fs16xx_devId_t id, int *r25) {
Fs_Dev_State *dev_state = NULL;
dev_state = fs16xx_get_dev_state_by_id(id);
if(!dev_state) {
PRINT_ERROR("%s invalid id, exit!", __func__);
return Fs16xx_Error_StateInvalid;
}
if(dev_state->calib_state != Fs16xx_Calib_OK) {
PRINT_ERROR("%s calibration invalid result: %d", __func__, dev_state->calib_state);
return Fs16xx_Error_Calib_Error;
}
*r25 = (int)(dev_state->calib_result.r25);
PRINT("%s r25=%d.", __func__, dev_state->calib_result.r25);
return Fs16xx_Error_OK;
}
int fs16xx_otp_is_busy(Fs16xx_devId_t id) {
int retry = 20;
unsigned short value = 0;
Sleep(5);
while(retry > 0) {
// Checking OTP busy bit
fs16xx_read_register16(id, FS16XX_OTPCMD_REG, &value);
if((value & FS16XX_OTPCMD_REG_BUSY_MSK) == 0) {
return 0;
}
Sleep(1);
retry--;
}
// Return non-0, otp op timeout...
return -1;
}
int fs16xx_get_otp_write_count(unsigned short val) {
// OTP offset start from 0x10 to 0x20(Totally 16)
return (val >= OTP_OP_COUNTER_OFFSET) ? (val - OTP_OP_COUNTER_OFFSET + 1): 0;
}
unsigned char fs16xx_r25_to_byte(bool ras,int r25) {
unsigned char val;
if(ras){
val = (unsigned char)((int)abs(r25 - calib_r0_ras) * FS16XX_CALIB_STEP_MAGNIF_FACTOR / calib_r0_step_ras);
if (val > 0x7F) val = 0x7F;
val = (r25 >= calib_r0_ras) ? val : (unsigned char)(val | 0x80);
} else {
val = (unsigned char)((int)abs(r25 - calib_r0) * FS16XX_CALIB_STEP_MAGNIF_FACTOR / calib_r0_step);
if (val > 0x7F) val = 0x7F;
val = (r25 >= calib_r0) ? val : (unsigned char)(val | 0x80);
}
// For Fs1801/Fs1818 otp value cannot be 0xFF(0xFF is reserved value).
if(0xFF == val) val -= 1;
return val;
}
int fs16xx_byte_to_r25(bool ras,unsigned char b) {
if(ras){
if((b & 0x80) != 0) {
// minus value
return calib_r0_ras - calib_r0_step_ras * (b & 0x7F) / FS16XX_CALIB_STEP_MAGNIF_FACTOR;
}
return calib_r0_ras + calib_r0_step_ras * b / FS16XX_CALIB_STEP_MAGNIF_FACTOR;
} else {
if((b & 0x80) != 0) {
// minus value
return calib_r0 - calib_r0_step * (b & 0x7F) / FS16XX_CALIB_STEP_MAGNIF_FACTOR;
}
return calib_r0 + calib_r0_step * b / FS16XX_CALIB_STEP_MAGNIF_FACTOR;
}
}
int fs16xx_spkset_to_calib_coef(bool ras, unsigned short spkset) {
int spkset_idx = (spkset & FS16XX_SPKSET_REG_SPKR_MSK) >> FS16XX_SPKSET_REG_SPKR_POS;
int r = 0;
if( ras ){
r=32;
} else {
switch(spkset_idx) {
case 0:
r = 4;
break;
case 1:
r = 6;
break;
case 2:
r = 7;
break;
case 3:
default:
r = 8;
break;
}
}
if(ras){
//#ifdef USE_RAS_MODE
calib_r0_ras = r * MAGNIF_FACTOR;;
calib_allow_low_ras = (r * R0_ALLOWANCE_LOW_RAS) / 32;
calib_allow_high_ras = (r * R0_ALLOWANCE_HIGH_RAS) / 32;
calib_r0_step_ras = (r * FS16XX_CALIB_OTP_R25_STEP_RAS) / 32;
//#endif
} else {
calib_r0 = r * MAGNIF_FACTOR;
calib_allow_low = (r * R0_ALLOWANCE_LOW) / 8;
calib_allow_high = (r * R0_ALLOWANCE_HIGH) / 8;
calib_r0_step = (r * FS16XX_CALIB_OTP_R25_STEP) / 8;
calib_r0_delta = (r * OTP_MIN_DELTA) / 8;
}
if(ras){
PRINT("%s calib_r0_ras=0x%X calib_allow_low_ras=0x%X calib_allow_high_ras=0x%X calib_r0_step_ras = 0x%X.", \
__func__, calib_r0_ras, calib_allow_low_ras, calib_allow_high_ras, calib_r0_step_ras);
} else {
PRINT("%s calib_r0=0x%X calib_allow_low=0x%X calib_allow_high=0x%X calib_r0_step = 0x%X calib_r0_delta = %d.", \
__func__, calib_r0, calib_allow_low, calib_allow_high, calib_r0_step,calib_r0_delta);
}
return r;
}
Fs16xx_Calib_State_t fs16xx_calc_coef_from_zm(Fs16xx_devId_t id, unsigned short zm, int storeResult) {
int r25;
unsigned short spk_err, spk_m24, spk_m6, spk_rec, ext_tempr, value = 0;
Fs16xx_Error_t err = Fs16xx_Error_OK;
Fs_Dev_State *dev_state = NULL;
Fs16xx_Calib_Result_t *calib_result;
dev_state = fs16xx_get_dev_state_by_id(id);
if(!dev_state) {
PRINT_ERROR("%s invalid id, exit!", __func__);
return Fs16xx_Calib_Failed;
}
calib_result = &(dev_state->calib_result);
ext_tempr = (dev_state->tempr_sel >> 1);
// Read spk_set everytime to make sure spk_set value updated.
err |= fs16xx_read_register16(id, FS16XX_SPKSET_REG, &(dev_state->spk_set));
// Apply values from preset
fs16xx_spkset_to_calib_coef(dev_state->ras,dev_state->spk_set);
if(zm != 0) {
// Read 0xE6
fs16xx_read_register16(id, FS16XX_OTPPG1W2_REG, &value);
if(value != 0) {
value = value & 0xFF;
} else {
PRINT_ERROR("%s OTPPG1W2_REG unexpected! Set default value.", __func__);
value = RS_TRIM_DEFAULT;
}
r25 = value * RS2RL_RATIO * MAGNIF_FACTOR / zm;
} else {
r25 = 0xFFFF; // Invalid r25 value
}
// Update calibration result even if the result is not valid
calib_result->r25 = r25;
calib_result->calib_ver = FS16XX_CALIB_VERSION;
calib_result->calib_result_zm = zm;
PRINT("%s calibration result zm=0x%04X r25=%d.", __func__, zm, r25);
if(dev_state->ras){
if (r25 > calib_allow_low_ras && r25 < calib_allow_high_ras) {
PRINT("%s Receiver r25=%d.", __func__, r25);
} else {
// Calibration result invalid, need to re-calibrate
PRINT("%s Receiver invalid result r25=%d.", __func__, r25);
return Fs16xx_Calib_Failed;
}
} else {
if(r25 < calib_allow_high && r25 > calib_allow_low) {
PRINT("%s Speaker r25=%d.",__func__,r25);
} else {
// Calibration result invalid, need to re-calibrate
PRINT("%s Speaker invalid result r25=%d.", __func__, r25);
return Fs16xx_Calib_Failed;
}
}
spk_m24 = (unsigned short)((unsigned int)zm * MAGNIF_TEMPR_COEF /
(MAGNIF_TEMPR_COEF + dev_state->tempr_coef * (((dev_state->tmax + 20)- ext_tempr))));
spk_err = spk_m24 / 2;
spk_m6 = (unsigned short)((unsigned int)zm * MAGNIF_TEMPR_COEF /
(MAGNIF_TEMPR_COEF + dev_state->tempr_coef * (((dev_state->tmax) - ext_tempr))));
spk_rec = (unsigned short)((unsigned int)zm * MAGNIF_TEMPR_COEF /
(MAGNIF_TEMPR_COEF + dev_state->tempr_coef * (((dev_state->tmax - 10) - ext_tempr))));
calib_result->spk_err = spk_err;
calib_result->spk_m24 = spk_m24;
calib_result->spk_m6 = spk_m6;
calib_result->spk_recover = spk_rec;
err |= fs16xx_write_register16(id, FS16XX_SPKERR_REG, spk_err);
err |= fs16xx_write_register16(id, FS16XX_SPKM24_REG, spk_m24);
err |= fs16xx_write_register16(id, FS16XX_SPKM6_REG, spk_m6);
err |= fs16xx_write_register16(id, FS16XX_SPKRE_REG, spk_rec);
fs16xx_write_register16(id, FS16XX_ADCTIME_REG, CALIB_REG_NORMAL_BA);
fs16xx_write_register16(id, FS16XX_TSCTRL_REG, CALIB_REG_NORMAL_AF);
if(storeResult) {
#ifdef FS16XX_CALIB_STORE_TO_OTP
err |= fs16xx_write_to_otp(id, fs16xx_r25_to_byte(dev_state->ras,r25));
#else
err |= fs16xx_save_calib_result(id, zm);
#endif
}
PRINT("%s calibration result spk_err=0x%04X spk_m24=0x%04X spk_m6=0x%04X spk_rec=0x%04X reg set-%s.",
__func__, spk_err, spk_m24, spk_m6, spk_rec, (Fs16xx_Error_OK == err) ? "OK" : "Fail");
return (Fs16xx_Error_OK == err) ? Fs16xx_Calib_OK : dev_state->calib_state;
}
Fs16xx_Calib_State_t fs16xx_update_coef_from_r25(Fs16xx_devId_t id, int r25) {
unsigned short spk_err, spk_m24, spk_m6, spk_rec, value = 0;
Fs16xx_Error_t err = Fs16xx_Error_OK;
unsigned int zm, ext_tempr;
Fs_Dev_State *dev_state = NULL;
Fs16xx_Calib_Result_t *calib_result;
dev_state = fs16xx_get_dev_state_by_id(id);
if(!dev_state) {
PRINT_ERROR("%s invalid id, exit!", __func__);
return Fs16xx_Calib_Failed;
}
calib_result = &(dev_state->calib_result);
ext_tempr = (dev_state->tempr_sel >> 1);
if(dev_state->ras){
if (r25 < calib_allow_low_ras || r25 > calib_allow_high_ras) {
// Calibration result invalide, need to re-calibrate
PRINT_ERROR("%s calibration result out of range r25=%d.", __func__, r25);
return Fs16xx_Calib_Failed;
}
} else {
if (r25 < calib_allow_low || r25 > calib_allow_high) {
// Calibration result invalide, need to re-calibrate
PRINT_ERROR("%s calibration result out of range r25=%d.", __func__, r25);
return Fs16xx_Calib_Failed;
}
}
if(r25 != 0) {
// Read 0xE6
fs16xx_read_register16(id, FS16XX_OTPPG1W2_REG, &value);
if(value != 0) {
value = value & 0xFF;
} else {
PRINT_ERROR("%s OTPPG1W2_REG unexpected! Set default value.", __func__);
value = RS_TRIM_DEFAULT;
}
zm = value * RS2RL_RATIO * MAGNIF_FACTOR / r25;
} else {
PRINT_ERROR("%s Invalid r25!", __func__);
return Fs16xx_Calib_Failed;
}
spk_m24 = (unsigned short)((unsigned int)zm * MAGNIF_TEMPR_COEF /
(MAGNIF_TEMPR_COEF + dev_state->tempr_coef * (((dev_state->tmax + 20) - ext_tempr))));
spk_err = spk_m24 / 2;
spk_m6 = (unsigned short)((unsigned int)zm * MAGNIF_TEMPR_COEF /
(MAGNIF_TEMPR_COEF + dev_state->tempr_coef * (((dev_state->tmax) - ext_tempr))));
spk_rec = (unsigned short)((unsigned int)zm * MAGNIF_TEMPR_COEF /
(MAGNIF_TEMPR_COEF + dev_state->tempr_coef * (((dev_state->tmax - 10) - ext_tempr))));
calib_result->spk_err = spk_err;
calib_result->spk_m24 = spk_m24;
calib_result->spk_m6 = spk_m6;
calib_result->spk_recover = spk_rec;
calib_result->r25 = r25;
err |= fs16xx_write_register16(id, FS16XX_SPKERR_REG, spk_err);
err |= fs16xx_write_register16(id, FS16XX_SPKM24_REG, spk_m24);
err |= fs16xx_write_register16(id, FS16XX_SPKM6_REG, spk_m6);
err |= fs16xx_write_register16(id, FS16XX_SPKRE_REG, spk_rec);
PRINT("%s read calibration result spk_err=0x%04X spk_m24=0x%04X spk_m6=0x%04X spk_rec=0x%04X reg set-%s.",
__func__, spk_err, spk_m24, spk_m6, spk_rec, (Fs16xx_Error_OK == err) ? "OK" : "Fail");
return (Fs16xx_Error_OK == err) ? Fs16xx_Calib_OK : Fs16xx_Calib_Failed;
}
#ifdef FS16XX_CALIB_STORE_TO_OTP
Fs16xx_Error_t fs16xx_write_to_otp(Fs16xx_devId_t id, unsigned char valOTP) {
int count, delta;
Fs16xx_Error_t err = Fs16xx_Error_OK;
unsigned short value = 0, valPwr = 0, valueC0 = 0, valueC4 = 0;
Fs_Dev_State *dev_state = NULL;
Fs16xx_Calib_Result_t *calib_result;
dev_state = fs16xx_get_dev_state_by_id(id);
if(!dev_state) {
PRINT_ERROR("%s invalid id, exit!", __func__);
return Fs16xx_Error_StateInvalid;
}
calib_result = &(dev_state->calib_result);
PRINT("%s enter valOTP=0x%02x.", __func__, valOTP);
err |= fs16xx_read_register16(id, FS16XX_SYSCTRL_REG, &valPwr);
// power up, amp off
err |= fs16xx_write_register16(id, FS16XX_SYSCTRL_REG, 0x0000);
err |= fs16xx_read_register16(id, FS16XX_PLLCTRL4_REG, &valueC4);
err |= fs16xx_write_register16(id, FS16XX_PLLCTRL4_REG, 0x000A);
err |= fs16xx_read_register16(id, FS16XX_BSTCTRL_REG, &valueC0);
err |= fs16xx_write_register16(id, FS16XX_BSTCTRL_REG, 0x0000);
// OTP page
err |= fs16xx_write_register16(id, FS16XX_OTPADDR_REG, 0x0010);
// OTP read clear
err |= fs16xx_write_register16(id, FS16XX_OTPCMD_REG, 0x0000);
// OTP read
err |= fs16xx_write_register16(id, FS16XX_OTPCMD_REG, 0x0001);
if(fs16xx_otp_is_busy(id) != 0) {
dev_state->calib_state= Fs16xx_Calib_OTP_Failed;
PRINT_ERROR("%s, Error, otp busy bit not cleared!", __func__);
goto otp_op_exit;
}
fs16xx_read_register16(id, FS16XX_OTPRDATA_REG, &value);
if(value == OTP_INIT_VALUE) {
count = 0;
} else {
count = fs16xx_get_otp_write_count(value & 0xFF);
}
PRINT("%s read calibration result = 0x%04x otp write count=%d.",
__func__, value, count);
delta = (int)fs16xx_byte_to_r25(dev_state->ras,valOTP)
- fs16xx_byte_to_r25(dev_state->ras,(value >> 8) & 0xFF);
if(delta < 0) delta *= -1;
// OTP won't updated if calibrated r25 is not changed much(defined by otpDelta).
if(dev_state->ras) {
PRINT("%s delta = %d otpDelta_ras = %d.", __func__, delta, OTP_MIN_DELTA_RAS);
} else {
PRINT("%s delta = %d otpDelta = %d.", __func__, delta, calib_r0_delta);
}
if(dev_state->ras){
if(count > 0 && delta < OTP_MIN_DELTA_RAS) {
PRINT("%s recevier no need to write to otp.", __func__);
goto otp_op_exit;
}
}else{
if(count > 0 && delta < calib_r0_delta) {
PRINT("%s no need to write to otp.", __func__);
goto otp_op_exit;
}
}
// Calibration Count
if(count >= FS16XX_CALIB_MAX_USER_TRY) {
PRINT_ERROR("%s calibrated count exceeds max.", __func__);
calib_result->calib_count = count;
dev_state->calib_state = Fs16xx_Calib_OTP_ExcceedMaxTry;
err = Fs16xx_Error_Calib_Error;
goto otp_op_exit;
}
err |= fs16xx_write_register16(id, FS16XX_PLLCTRL4_REG, 0x000B);
// enable Boost, and set it to follow mode
err |= fs16xx_write_register16(id, FS16XX_BSTCTRL_REG, 0x0008);
// Write OTP page
err |= fs16xx_write_register16(id, FS16XX_OTPADDR_REG, 0x0010);
// OTP write byte
err |= fs16xx_write_register16(id, FS16XX_OTPWDATA_REG, (unsigned short)valOTP);
// Clear OTP commands
err |= fs16xx_write_register16(id, FS16XX_OTPCMD_REG, 0x0000);
// OTP enable Boost 7.6V mode
err |= fs16xx_write_register16(id, FS16XX_OTPCMD_REG, 0x2000);
// Wait until ss_end
if(fs16xx_wait_boost_ssend(fs16xx_get_codec_by_id(id)) != Fs16xx_Error_OK) {
PRINT_ERROR("%s, Error, failed to wait for boost ssend!", __func__);
goto otp_op_exit;
}
// Send single-byte write command
err |= fs16xx_write_register16(id, FS16XX_OTPCMD_REG, 0x2002);
// Wait for 5ms for otp operation to complete.
Sleep(5);
if(fs16xx_otp_is_busy(id) != 0) {
dev_state->calib_state = Fs16xx_Calib_OTP_Failed;
err = Fs16xx_Error_Calib_Error;
goto otp_op_exit;
}
// Clear OTP commands
err |= fs16xx_write_register16(id, FS16XX_OTPCMD_REG, 0x0000);
Sleep(1);
// disable boost
err |= fs16xx_write_register16(id, FS16XX_BSTCTRL_REG, 0x0000);
calib_result->calib_count = count + 1;
// Read back
err |= fs16xx_write_register16(id, FS16XX_PLLCTRL4_REG, 0x000A);
err |= fs16xx_write_register16(id, FS16XX_BSTCTRL_REG, 0x0000);
// OTP page
err |= fs16xx_write_register16(id, FS16XX_OTPADDR_REG, 0x0010);
// OTP read clear
err |= fs16xx_write_register16(id, FS16XX_OTPCMD_REG, 0x0000);
// OTP read
err |= fs16xx_write_register16(id, FS16XX_OTPCMD_REG, 0x0001);
if(fs16xx_otp_is_busy(id) != 0) {
dev_state->calib_state = Fs16xx_Calib_OTP_Failed;
err = Fs16xx_Error_Calib_Error;
goto otp_op_exit;
}
fs16xx_read_register16(id, FS16XX_OTPRDATA_REG, &value);
if(((value >> 8) & 0xFF) == valOTP) {
// Update count
calib_result->calib_count = fs16xx_get_otp_write_count(value & 0xFF);
PRINT("%s readback succeeded with count = %d.", __func__, calib_result->calib_count);
} else {
err = Fs16xx_Error_Calib_Error;
PRINT_ERROR("%s calibrated read back failed with value = 0x%04X(expected = 0x%02X--). Should not happen.",
__func__, value, valOTP);
}
otp_op_exit:
err |= fs16xx_write_register16(id, FS16XX_BSTCTRL_REG, valueC0);
err |= fs16xx_write_register16(id, FS16XX_PLLCTRL4_REG, valueC4);
// Recover power state
err |= fs16xx_write_register16(id, FS16XX_SYSCTRL_REG, valPwr);
DEBUGPRINT("%s exit, error = %d.", __func__, err);
return err;
}
#else
Fs16xx_Error_t fs16xx_save_calib_result(Fs16xx_devId_t id, unsigned short zmdata) {
FILE *fp;
int count;
Fs_Dev_State *dev_state = NULL;
Fs16xx_Calib_Result_t *calib_result;
dev_state = fs16xx_get_dev_state_by_id(id);
if(!dev_state) {
PRINT_ERROR("%s invalid id, exit!", __func__);
return Fs16xx_Error_StateInvalid;
}
calib_result = &(dev_state->calib_result);
DEBUGPRINT("%s enter.", __func__);
// Write to file
fp = fopen( FS16XX_PARAM_DIR FS16XX_CALIB_RESULT_FILE_NAME, "wb");
if (!fp)
{
PRINT_ERROR("%s open calibration file failed.", __func__);
return Fs16xx_Error_Calib_Error;
}
calib_result.calib_count = g_calib_count;
calib_result.calib_ver = FS16XX_CALIB_VERSION;
calib_result.calib_result_zm = zmdata;
count = fwrite( (void*)&calib_result, 1, sizeof(Fs16xx_Calib_Result_t), fp );
fclose(fp);
PRINT("%s write to calibration file, count=%d.", __func__, count);
return Fs16xx_Error_OK;
}
#endif
Fs16xx_Error_t fs16xx_set_tempr_protection(Fs16xx_devId_t id, int enable) {
Fs16xx_Error_t err = Fs16xx_Error_OK;
Fs_Dev_State *dev_state = NULL;
Fs16xx_Calib_Result_t *calib_result;
dev_state = fs16xx_get_dev_state_by_id(id);
if(!dev_state) {
PRINT_ERROR("%s invalid id, exit!", __func__);
return Fs16xx_Error_StateInvalid;
}
calib_result = &(dev_state->calib_result);
PRINT("%s enter. enable=%d", __func__, enable);
if(enable) {
// TS on
err = fs16xx_write_register16(id, FS16XX_TSCTRL_REG, CALIB_REG_NORMAL_AF);
if(Fs16xx_Calib_Unknown == dev_state->calib_state) {
fs16xx_check_calibration(id);
}
if(Fs16xx_Calib_OK != dev_state->calib_state
&& Fs16xx_Calib_OnGoing != dev_state->calib_state
&& Fs16xx_Calib_OTP_ExcceedMaxTry != dev_state->calib_state) {
fs16xx_calibration(id, 0, 1);
}
}else {
// TS off
err = fs16xx_write_register16(id, FS16XX_TSCTRL_REG, CALIB_REG_TSOFF_AF);
// Delay enough time for ts off gracefully to avoid pop.
Sleep(35);
//fs16xx_wait_ts_off(id, 60);
}
DEBUGPRINT("%s exit.", __func__);
return err;
}
@@ -0,0 +1,128 @@
/*
* Copyright (C) 2016 Fourier Semiconductor Inc.
*
*/
#ifndef FS16XX_CALIBRATION_H
#define FS16XX_CALIBRATION_H
#include "fs16xx_define.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MAGNIF_FACTOR 0x400
#define RS2RL_RATIO 2700
// TODO: to be loaded from preset
#define RS_TRIM_DEFAULT 0x8F
#define R0_DEFAULT (8 * MAGNIF_FACTOR)
#define R0_ALLOWANCE 30 // 30%
#define FS16XX_CALIB_STEP_MAGNIF_FACTOR 100
#define R0_ALLOWANCE_LOW ((R0_DEFAULT * (100 - R0_ALLOWANCE)) / FS16XX_CALIB_STEP_MAGNIF_FACTOR)
#define R0_ALLOWANCE_HIGH ((R0_DEFAULT * (100 + R0_ALLOWANCE)) / FS16XX_CALIB_STEP_MAGNIF_FACTOR)
#define FS16XX_CALIB_OTP_R25_STEP ((int)(R0_ALLOWANCE * R0_DEFAULT) / 0x7F)
#define OTP_MIN_DELTA (int)(R0_DEFAULT * 0.05f)
//RAS MODE
//#ifdef USE_RAS_MODE
#define R0_DEFAULT_RAS (32 * MAGNIF_FACTOR)
#define R0_ALLOWANCE_RAS 20
#define R0_ALLOWANCE_LOW_RAS ((R0_DEFAULT_RAS * (100 - R0_ALLOWANCE_RAS)) / FS16XX_CALIB_STEP_MAGNIF_FACTOR)
#define R0_ALLOWANCE_HIGH_RAS ((R0_DEFAULT_RAS * (100 + R0_ALLOWANCE_RAS)) / FS16XX_CALIB_STEP_MAGNIF_FACTOR)
#define FS16XX_CALIB_OTP_R25_STEP_RAS ((int)(R0_ALLOWANCE_RAS * R0_DEFAULT_RAS) / 0x7F)
#define OTP_MIN_DELTA_RAS (int)(R0_DEFAULT_RAS * 0.05f)
//#endif
#define MAGNIF_TEMPR_COEF 0xFFFF
#define TMAX 120
#define TMIN -20
#define SPKTMPRM24 115
#define SPKTMPRM6 110
#define SPKTMPRECOVERY 100
#define OTP_OP_COUNTER_OFFSET 16
#define OTP_INIT_VALUE 0xFF10
#define SPK_CALIBRATION_MAX_ZMDELTA 0x150
#define FS16XX_CALIB_VERSION 1
// Store calibration result to OTP, remove following macro to store calibration result to file system.
#define FS16XX_CALIB_STORE_TO_OTP 1
#define FS16XX_CALIB_RESULT_FILE_NAME "fs16xxcali.bin"
#define CALIB_REG_NORMAL_BA 0x0031
#define CALIB_REG_CALIB_MODE_AF 0x162B
#define CALIB_REG_NORMAL_AF 0x362B
#define CALIB_REG_TSOFF_AF 0x3623
/* DO NOT CHANGE THIS VALUE */
#define FS16XX_CALIB_MAX_USER_TRY 15
/* Type containing all the possible errors that can occur
*
*/
enum Fs16xx_Calib_State {
Fs16xx_Calib_OK = 0,
Fs16xx_Calib_NotStarted = 1,
Fs16xx_Calib_OnGoing = 2,
Fs16xx_Calib_Failed = 3,
Fs16xx_Calib_OTP_Failed = 4,
Fs16xx_Calib_OTP_ExcceedMaxTry = 5,
Fs16xx_Calib_Unknown = 10
};
typedef enum Fs16xx_Calib_State Fs16xx_Calib_State_t;
struct Fs16xx_Calib_Result {
unsigned short calib_ver;
unsigned short calib_count;
unsigned short calib_result_zm;
unsigned short spk_err;
unsigned short spk_m24;
unsigned short spk_m6;
unsigned short spk_recover;
int r25;
};
typedef struct Fs16xx_Calib_Result Fs16xx_Calib_Result_t;
Fs16xx_Error_t fs16xx_calibration(Fs16xx_devId_t id, int force, int storeResult);
Fs16xx_Calib_State_t fs16xx_check_calibration(Fs16xx_devId_t id);
Fs16xx_Error_t fs16xx_get_calibration_result(Fs16xx_devId_t id, int *r25);
Fs16xx_Calib_State_t fs16xx_calc_coef_from_zm(Fs16xx_devId_t id, unsigned short zm, int storeResult);
Fs16xx_Calib_State_t fs16xx_update_coef_from_r25(Fs16xx_devId_t id, int r25);
int fs16xx_otp_is_busy(Fs16xx_devId_t id);
int fs16xx_get_otp_write_count(unsigned short val);
unsigned char fs16xx_r25_to_byte(bool ras,int r25);
int fs16xx_byte_to_r25(bool ras,unsigned char b);
int fs16xx_spkset_to_calib_coef(bool ras,unsigned short spkset);
Fs16xx_Error_t fs16xx_set_tempr_protection(Fs16xx_devId_t id, int enable);
#ifdef FS16XX_CALIB_STORE_TO_OTP
Fs16xx_Error_t fs16xx_write_to_otp(Fs16xx_devId_t id, unsigned char valOTP);
#else
Fs16xx_Error_t fs16xx_save_calib_result(Fs16xx_devId_t id, unsigned short zmdata);
#endif
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,120 @@
/*
* Fs16xx device driver header file.
* Copyright (C) 2017 FourSemi Inc.
*
* 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 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FS16XX_DEFINE_H__
#define __FS16XX_DEFINE_H__
#define FS16XX_MAX_REGISTER 0xE8
#define I2C_RETRY_DELAY 5 /* ms */
#define I2C_RETRIES 20
#define PLL_SYNC_RETRIES 10
#define MTPB_RETRIES 5
#define MAX_DEV_COUNT 2
/* DSP Firmware Size in bytes*/
#define FS16XX_SPK_FW_SIZE 512
#define FS16XX_CFG_FW_SIZE 512
#define FS16XX_PST_FW_SIZE 512
#define FS16XX_COEFF_FW_SIZE 512
#define FS16XX_DEV_STATE_SIZE 24
#define FS16XX_SPK_EX_FW_SIZE 512
#define FS16XX_REG_CACHE_SIZE 193
#define FS16XX_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000)
#define FS16XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE|SNDRV_PCM_FMTBIT_S24_LE|SNDRV_PCM_FMTBIT_S32_LE|\
SNDRV_PCM_FORMAT_MU_LAW|SNDRV_PCM_FORMAT_S24_3LE)
#define FIRMWARE_NAME_SIZE 128
#define FS16XX_MAX_I2C_SIZE 512
#define SYS_CLK_DEFAULT 1536000
#define FS16XX_DEV_INDEX_L 0
#define FS16XX_DEV_INDEX_R 1
// DSP init status
#define FS16XX_DSP_INIT_PENDING 0
#define FS16XX_DSP_INIT_OK 1
#define FS16XX_DSP_INIT_FAILED -1
/* Type containing all the possible errors that can occur
*
*/
enum Fs16xx_Error {
Fs16xx_Error_OK = 0,
Fs16xx_Error_Bad_Parameter,
Fs16xx_Error_NotOpen,
Fs16xx_Error_OutOfHandles,
Fs16xx_Error_StateTimedOut,
Fs16xx_Error_StateInvalid,
Fs16xx_Error_Not_Implemented,
Fs16xx_Error_Not_Supported,
Fs16xx_Error_I2C_Fatal,
Fs16xx_Error_I2C_NonFatal,
Fs16xx_Error_Other = 1000,
Fs16xx_Error_Not_FsDev = 1001,
Fs16xx_Error_Calib_Error = 1002,
Fs16xx_Error_Invalid_Preset = 1003
};
typedef enum Fs16xx_Error Fs16xx_Error_t;
enum Fs16xx_Channel {
Fs16xx_Channel_L, // I2S left channel
Fs16xx_Channel_R, // I2S right channel
Fs16xx_Channel_L_R, // I2S (left + right channel)/2
Fs16xx_Channel_Stereo
};
typedef enum Fs16xx_Channel Fs16xx_Channel_t;
enum Fs16xx_Mode {
Fs16xx_Mode_Normal = 0,
Fs16xx_Mode_RCV
};
typedef enum Fs16xx_Mode Fs16xx_Mode_t;
enum Fs16xx_PwrState {
Fs16xx_PwrOn = 0,
Fs16xx_PwrOff = 1
};
typedef enum Fs16xx_PwrState Fs16xx_PwrState_t;
enum Fs16xx_OutputSel{
Fs16xx_OutputSel_None = 0,
Fs16xx_OutputSel_DataL, // I2S left channel output
Fs16xx_OutputSel_DataR, // I2S right channel output
Fs16xx_OutputSel_TS // Test tone
};
typedef enum Fs16xx_OutputSel Fs16xx_OutputSel_t;
#define FS_DISABLE 0
#define FS_ENABLE 1
#define FS_UMUTE 0
#define FS_MUTE 1
typedef int Fs16xx_devId_t;
//#define FS_STEREO_MODE
//#define USE_RAS_MODE
#endif
@@ -0,0 +1,452 @@
/*
* Copyright (C) 2016 Fourier Semiconductor Inc.
*
*/
#include "fs16xx.h"
#include "fs16xx_regs.h"
#include "fs16xx_preset.h"
static int preset_init = 0;
static Fs16xx_preset gFs16xxPresets[(int)fs16xx_preset_type_max];
#ifndef FS_STEREO_MODE
static char const *gFs16xxPresetName[(int)fs16xx_preset_type_max] = {
"fs1801_mono.preset",
"fs1801_mono.preset" // prevent from crash in kernel
};
#else
static char const *gFs16xxPresetName[(int)fs16xx_preset_type_max] = {
"fs1801_left.preset",
"fs1801_right.preset"
};
#endif
#define CRC16_TABLE_SIZE 256
const uint16_t gCrc16Polynomial = 0xA001;
static uint16_t gCrc16Table[CRC16_TABLE_SIZE];
#define PRESET_VALID 1
#define PRESET_INVALID 0
/* Initialize presets should only be called once in fs16xx_init
*/
Fs16xx_Error_t fs16xx_initialize_presets(void) {
uint16_t value;
uint16_t temp, i;
uint8_t j;
if(preset_init) return Fs16xx_Error_OK;
memset(gFs16xxPresets, 0, sizeof(Fs16xx_preset) * (int)fs16xx_preset_type_max);
// Initialize CRC16 table
for (i = 0; i < CRC16_TABLE_SIZE; ++i)
{
value = 0;
temp = i;
for (j = 0; j < 8; ++j)
{
if (((value ^ temp) & 0x0001) != 0)
{
value = (uint16_t)((value >> 1) ^ gCrc16Polynomial);
}
else
{
value >>= 1;
}
temp >>= 1;
}
gCrc16Table[i] = value;
}
preset_init = 1;
return Fs16xx_Error_OK;
}
Fs16xx_Error_t fs16xx_deinitialize_presets(void) {
int i;
for(i = 0; i < (int)fs16xx_preset_type_max; i++) {
if(PRESET_VALID == gFs16xxPresets[i].valid) {
if(gFs16xxPresets[i].preset_header.data) {
gFs16xxPresets[i].valid = PRESET_INVALID;
kfree(gFs16xxPresets[i].preset_header.data);
}
}
}
return Fs16xx_Error_OK;
}
// load_presets should only be called once after initialization
Fs16xx_Error_t fs16xx_load_presets(Fs16xx_devId_t id) {
const struct firmware *fs_firmware = NULL;
struct snd_soc_codec *codec;
int j, data_len, buf_size, ret, pos;
uint16_t *ptr_data = NULL;
uint16_t *ptr_crc_data = NULL;
int32_t *ptr_excur_prot_ram = NULL;
uint16_t checksum;
// Preset crc data length in uint16_t : size from member tmax to the start of excur_prot_ram
const int preset_header_crc_data_len =
(sizeof(Fs16xx_preset_header_t) - sizeof(int32_t *) - sizeof(uint16_t *)
- sizeof(uint16_t) * 3 - 32 - sizeof(int64_t)) / 2;
const int preset_header_len = sizeof(Fs16xx_preset_header_t) - sizeof(int32_t *)
- sizeof(uint16_t *);
PRINT("%s enter. id = %d", __func__, id);
if(FS16XX_DEV_INDEX_L != id && FS16XX_DEV_INDEX_R != id) {
PRINT_ERROR("%s invalid id[%d]", __func__, id);
return Fs16xx_Error_Bad_Parameter;
}
codec = fs16xx_get_codec_by_id(id);
if(NULL == codec) {
PRINT_ERROR("%s invalid codec with id[%d]", __func__, id);
return Fs16xx_Error_Bad_Parameter;
}
fs16xx_initialize_presets();
if(gFs16xxPresets[id].valid) {
PRINT_ERROR("%s invalid status, presets already loaded.", __func__);
return Fs16xx_Error_StateInvalid;
}
ret = request_firmware(&fs_firmware, gFs16xxPresetName[id], codec->dev);
if (ret) {
PRINT_ERROR("%s Failed to load fs preset table %s", __func__, gFs16xxPresetName[id]);
return Fs16xx_Error_Invalid_Preset;
}
PRINT("fs16xx: loaded firmware size = 0x%04X", fs_firmware->size);
if(fs_firmware->size < sizeof(Fs16xx_preset_header_t)) {
PRINT_ERROR("%s Invalid preset table %s size=%d", __func__,
gFs16xxPresetName[id], fs_firmware->size);
release_firmware(fs_firmware);
return Fs16xx_Error_Invalid_Preset;
}
// Parse header
memcpy(&(gFs16xxPresets[id].preset_header), fs_firmware->data, preset_header_len);
// Checking preset version
if(PRESET_VERSION != gFs16xxPresets[id].preset_header.preset_ver) {
PRINT_ERROR("%s preset version[0x%04X] invalid!",
__func__, gFs16xxPresets[id].preset_header.preset_ver);
release_firmware(fs_firmware);
return Fs16xx_Error_Invalid_Preset;
}
PRINT("fs16xx: customer_name: %s\n", gFs16xxPresets[id].preset_header.customer_name);
data_len = gFs16xxPresets[id].preset_header.data_len;
if(data_len <= 0 || (data_len % 2) != 0) {
PRINT_ERROR("%s preset header [%s] validation checking failed. data_len=%d",
__func__, gFs16xxPresetName[id], data_len);
release_firmware(fs_firmware);
return Fs16xx_Error_Invalid_Preset;
}
// Copy excur prot
buf_size = EXCUR_PROT_RAM_LEN * sizeof(int32_t);
ptr_excur_prot_ram = (int32_t *)kzalloc(buf_size, GFP_KERNEL);
if (!ptr_excur_prot_ram) {
PRINT_ERROR("%s failed to allocate %d bytes for excur_prot_ram.\n", __func__, buf_size);
gFs16xxPresets[id].preset_header.excur_prot_ram = 0;
release_firmware(fs_firmware);
return Fs16xx_Error_Invalid_Preset;
}
memcpy(ptr_excur_prot_ram, ((u8*)fs_firmware->data) + preset_header_len, buf_size);
buf_size = data_len * sizeof(uint16_t);
ptr_data = kzalloc(buf_size, GFP_KERNEL);
if (!ptr_data) {
PRINT_ERROR("%s failed to allocate %d bytes.", __func__, buf_size);
gFs16xxPresets[id].preset_header.data = 0;
release_firmware(fs_firmware);
return Fs16xx_Error_Invalid_Preset;
}
memcpy(ptr_data, ((u8*)fs_firmware->data) + preset_header_len
+ (EXCUR_PROT_RAM_LEN * sizeof(int32_t)), buf_size);
release_firmware(fs_firmware);
// Fill ptr_crc_data
buf_size = (data_len + preset_header_crc_data_len) * sizeof(uint16_t)
+ EXCUR_PROT_RAM_LEN * sizeof(int32_t);
DEBUGPRINT("%s buf_size = 0x%04X", __func__, buf_size);
ptr_crc_data = (uint16_t *)kzalloc(buf_size, GFP_KERNEL);
if (!ptr_crc_data) {
PRINT_ERROR("%s failed to allocate %d bytes.\n", __func__, buf_size);
gFs16xxPresets[id].preset_header.data = 0;
return Fs16xx_Error_Invalid_Preset;
}
pos = 0;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.tmax; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.tempr_coef; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.tempr_sel; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.spk_set; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.adp_bst[0]; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.adp_bst[1]; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.bst_ctrl[0]; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.bst_ctrl[1]; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.agc_ctrl[0]; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.agc_ctrl[1]; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.agc_thd[0]; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.agc_thd[1]; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.agc_para[0]; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.agc_para[1]; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.agc_mg[0]; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.agc_mg[1]; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.dac_para1[0]; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.dac_para1[1]; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.acs_drc[0]; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.acs_drc[1]; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.acs_drcs[0]; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.acs_drcs[1]; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.acs_drcp[0]; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.acs_drcp[1]; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.ts_ctrl[0]; pos++;
ptr_crc_data[pos] = gFs16xxPresets[id].preset_header.ts_ctrl[1]; pos++;
for (j = 0; j < EXCUR_PROT_RAM_LEN; j++)
{
ptr_crc_data[pos] = (uint16_t)(ptr_excur_prot_ram[j] & 0xFFFF);
ptr_crc_data[pos + 1] = (uint16_t)((ptr_excur_prot_ram[j] & 0xFF0000) >> 16);
pos += 2;
}
for (j = 0; j < data_len; j++)
{
ptr_crc_data[pos] = ptr_data[j];
pos++;
}
/*if(pos != (data_len + preset_header_crc_data_len)) {
PRINT_ERROR("%s preset length not matching! pos=%d expected=%d.\n", __func__,
pos, (data_len + preset_header_crc_data_len));
kfree(ptr_data);
kfree(ptr_crc_data);
return Fs16xx_Error_Invalid_Preset;
}*/
checksum = fs16xx_calc_checksum(ptr_crc_data, buf_size / 2);
kfree(ptr_crc_data);
if(checksum != gFs16xxPresets[id].preset_header.crc16) {
PRINT_ERROR("%s preset data [%s] checksum not match. checksum=0x%04X, expected=0x%04X",
__func__, gFs16xxPresetName[id], checksum, gFs16xxPresets[id].preset_header.crc16);
gFs16xxPresets[id].preset_header.data = 0;
kfree(ptr_data);
return Fs16xx_Error_Invalid_Preset;
}
gFs16xxPresets[id].preset_header.data = ptr_data;
gFs16xxPresets[id].preset_header.excur_prot_ram = ptr_excur_prot_ram;
gFs16xxPresets[id].valid = PRESET_VALID;
fs16xx_load_presets_to_dev(id);
PRINT("%s successfully exit. boost 0x%04X", __func__,
gFs16xxPresets[id].preset_header.bst_ctrl[0]);
return Fs16xx_Error_OK;
}
Fs16xx_Error_t fs16xx_load_presets_to_dev(Fs16xx_devId_t id) {
int i, data_len;
Fs16xx_Error_t err = Fs16xx_Error_OK;
uint16_t *ptr_data = 0;
int32_t *ptr_prot_coef = 0;
uint16_t valPwr;
Fs_Dev_State *dev_state = fs16xx_get_dev_state_by_id(id);
if(FS16XX_DEV_INDEX_L != id && FS16XX_DEV_INDEX_R != id) {
PRINT_ERROR("%s invalid id[%d]", __func__, id);
return Fs16xx_Error_Bad_Parameter;
}
if(dev_state == NULL){
PRINT_ERROR("%s dev_state is null!", __func__);
return Fs16xx_Error_Bad_Parameter;
}
if(gFs16xxPresets[id].valid != PRESET_VALID
|| gFs16xxPresets[id].preset_header.data == NULL) {
PRINT_ERROR("%s invalid preset id[%d] data=%p", __func__,
id, gFs16xxPresets[id].preset_header.data);
return Fs16xx_Error_Invalid_Preset;
}
dev_state->cur_preset = -1; // Reset preset index
dev_state->tmax = gFs16xxPresets[id].preset_header.tmax;
dev_state->tempr_coef = gFs16xxPresets[id].preset_header.tempr_coef;
dev_state->tempr_sel = gFs16xxPresets[id].preset_header.tempr_sel;
dev_state->spk_set = gFs16xxPresets[id].preset_header.spk_set;
dev_state->adp_bst = gFs16xxPresets[id].preset_header.adp_bst[0];
dev_state->bst_ctrl = gFs16xxPresets[id].preset_header.bst_ctrl[0];
dev_state->acs_drc_ctrl[0] = gFs16xxPresets[id].preset_header.acs_drc[0];
dev_state->acs_drc_ctrl[1] = gFs16xxPresets[id].preset_header.acs_drcs[0];
dev_state->acs_drc_ctrl[2] = gFs16xxPresets[id].preset_header.acs_drcp[0];
dev_state->ts_ctrl = gFs16xxPresets[id].preset_header.ts_ctrl[0];
data_len = gFs16xxPresets[id].preset_header.data_len;
ptr_data = gFs16xxPresets[id].preset_header.data;
ptr_prot_coef = gFs16xxPresets[id].preset_header.excur_prot_ram;
dev_state->dev_preset = &(gFs16xxPresets[id]);
DEBUGPRINT("%s ptr_data=%p data_len=%d", __func__, ptr_data, data_len);
// Amp off
err |= fs16xx_read_register16(id, FS16XX_SYSCTRL_REG, &valPwr);
err |= fs16xx_write_register16(id, FS16XX_SYSCTRL_REG, valPwr & (~FS16XX_SYSCTRL_REG_AMPE));
// Set spk_set
err |= fs16xx_write_register16(id, FS16XX_SPKSET_REG, gFs16xxPresets[id].preset_header.spk_set);
// Set tempr coef to TEMPSEL, refer to Bug 55
err |= fs16xx_write_register16(id, FS16XX_TEMPSEL_REG, (gFs16xxPresets[id].preset_header.tempr_coef) << 1);
fs16xx_write_register16(id, FS16XX_OTPACC_REG, FS16XX_OTP_ACC_KEY2);
if(Fs16xx_Error_OK == fs16xx_wait_dsp_off(id, 0, 100)) {
// Start from position 0
err |= fs16xx_write_register16(id, FS16XX_DACEQA_REG, 0);
// Write ACS data
for (i = 0; i < gFs16xxPresets[id].preset_header.data_len; i+=2) {
fs16xx_write_register16(id, FS16XX_DACEQWL_REG, ptr_data[i] & 0xFFFF);
fs16xx_write_register16(id, FS16XX_DACEQWH_REG, ptr_data[i + 1] & 0xFF);
//DEBUGPRINT("%s __DEBUG__ DSP write 0x%08X", __func__, ptr_data[i]);
}
// Start from position 0
err |= fs16xx_write_register16(id, FS16XX_DACEQA_REG, 0xD2);
// Write prot coef
for (i = 0; i < EXCUR_PROT_RAM_LEN; i++) {
fs16xx_write_register16(id, FS16XX_DACEQWL_REG, ptr_prot_coef[i] & 0xFFFF);
fs16xx_write_register16(id, FS16XX_DACEQWH_REG, (ptr_prot_coef[i] >> 16) & 0xFF);
//PRINT_ERROR("%s __DEBUG__ DSP write 0x%08X", __func__, ptr_prot_coef[i]);
}
} else {
PRINT_ERROR("%s failed to wait for dsp off!", __func__);
return Fs16xx_Error_StateInvalid;
}
err |= fs16xx_write_register16(id, FS16XX_OTPACC_REG, 0);
// Recover amp
err |= fs16xx_write_register16(id, FS16XX_SYSCTRL_REG, valPwr);
return err;
}
uint16_t fs16xx_calc_checksum(uint16_t *data, int len) {
uint16_t crc = 0;
uint8_t b, index;
int i;
if(len <= 0) return 0;
for (i = 0; i < len; i++)
{
b = (uint8_t)(data[i] & 0xFF);
index = (uint8_t)(crc ^ b);
crc = (uint16_t)((crc >> 8) ^ gCrc16Table[index]);
b = (uint8_t)((data[i] >> 8) & 0xFF);
index = (uint8_t)(crc ^ b);
crc = (uint16_t)((crc >> 8) ^ gCrc16Table[index]);
}
return crc;
}
/* fs16xx_set_preset must be called when osc is on */
Fs16xx_Error_t fs16xx_set_preset(Fs16xx_devId_t id, int preset) {
Fs16xx_Error_t err = Fs16xx_Error_OK;
uint16_t valPwr, valAcsCtrl, valPll, tmpC0;
int i;
Fs_Dev_State *dev_state = NULL;
Fs16xx_preset_header_t *preset_header = NULL;
PRINT("%s set preset %d.", __func__, preset);
if (Fs16xx_Error_OK != fs16xx_handle_is_open(id)) {
PRINT_ERROR("%s device not opened.", __func__);
return Fs16xx_Error_NotOpen;
}
dev_state = fs16xx_get_dev_state_by_id(id);
if(!dev_state) {
PRINT_ERROR("%s invalid id, exit!", __func__);
return Fs16xx_Error_StateInvalid;
}
if(!dev_state->dev_preset) {
PRINT_ERROR("%s invalid dev_preset, exit!", __func__);
return Fs16xx_Error_StateInvalid;
}
if(preset != 0 && preset != 1) {
PRINT_ERROR("%s invalid preset value! preset = %d", __func__, preset);
return Fs16xx_Error_Bad_Parameter;
}
if(preset == dev_state->cur_preset) {
PRINT("%s cur preset already set %d, exit.", __func__, preset);
return Fs16xx_Error_OK;
}
i = preset;
preset_header = &(dev_state->dev_preset->preset_header);
if(!dev_state->dev_preset->valid || preset_header == NULL) {
PRINT_ERROR("%s preset invalid! preset = %d preset_header = %p", __func__, preset, preset_header);
return Fs16xx_Error_Bad_Parameter;
}
// Amp off
err |= fs16xx_read_register16(id, FS16XX_SYSCTRL_REG, &valPwr);
err |= fs16xx_write_register16(id, FS16XX_SYSCTRL_REG, valPwr & (~FS16XX_SYSCTRL_REG_AMPE));
if(Fs16xx_Error_OK == fs16xx_wait_dsp_off(id, 0, 50)) {
// Enable osc
err |= fs16xx_read_register16(id, FS16XX_PLLCTRL4_REG, &valPll);
err |= fs16xx_write_register16(id, FS16XX_PLLCTRL4_REG, valPll | FS16XX_PLLCTRL4_REG_OSCEN);
dev_state->tempr_sel = preset_header->tempr_sel;
dev_state->spk_set = preset_header->spk_set;
dev_state->adp_bst = preset_header->adp_bst[i];
dev_state->bst_ctrl = preset_header->bst_ctrl[i];
dev_state->acs_drc_ctrl[0] = preset_header->acs_drc[i];
dev_state->acs_drc_ctrl[1] = preset_header->acs_drcs[i];
dev_state->acs_drc_ctrl[2] = preset_header->acs_drcp[i];
// TODO: TS control is not set to register
dev_state->ts_ctrl = preset_header->ts_ctrl[i];
err |= fs16xx_write_register16(id, FS16XX_BFLCTRL_REG, preset_header->agc_ctrl[i]);
err |= fs16xx_write_register16(id, FS16XX_BFLSET_REG, preset_header->agc_thd[i]);
err |= fs16xx_write_register16(id, FS16XX_SQC_REG, preset_header->agc_para[i]);
err |= fs16xx_write_register16(id, FS16XX_AGC_REG, preset_header->agc_mg[i]);
err |= fs16xx_write_register16(id, FS16XX_DRPARA_REG, preset_header->dac_para1[i]);
err |= fs16xx_write_register16(id, FS16XX_ACSDRC_REG, dev_state->acs_drc_ctrl[0]);
err |= fs16xx_write_register16(id, FS16XX_ACSDRCS_REG, dev_state->acs_drc_ctrl[1]);
// acs drcp not used.
// err |= fs16xx_write_register16(id, FS16XX_ACSDRCP_REG, dev_state->acs_drc_ctrl[2]);
err |= fs16xx_write_register16(id, FS16XX_ADPBST_REG, dev_state->adp_bst);
if(preset == 0) {
err |= fs16xx_write_register16(id, FS16XX_BSTCTRL_REG, dev_state->bst_ctrl);
valAcsCtrl = (uint16_t)FS16XX_ACSCTRL_REG_DEFAULT;
} else {
tmpC0 = dev_state->bst_ctrl & (~FS16XX_BSTCTRL_REG_MODE_CTRL_MSK);
tmpC0 |= (0x1 << FS16XX_BSTCTRL_REG_MODE_CTRL_POS);
err |= fs16xx_write_register16(id, FS16XX_BSTCTRL_REG, tmpC0);
valAcsCtrl = (uint16_t)(FS16XX_ACSCTRL_REG_DEFAULT | FS16XX_ACSCTRL_REG_ACS_COE_SEL_MSK);
}
err |= fs16xx_write_register16(id, FS16XX_ACSCTRL_REG, valAcsCtrl);
dev_state->cur_preset = (int)preset;
err |= fs16xx_write_register16(id, FS16XX_PLLCTRL4_REG, valPll);
} else {
PRINT_ERROR("%s failed to wait for dsp off!", __func__);
}
err |= fs16xx_write_register16(id, FS16XX_SYSCTRL_REG, valPwr);
PRINT("%s exit err=%d. __DEBUG__ boost 0x%04X", __func__, err,
dev_state->bst_ctrl);
return err;
}
@@ -0,0 +1,99 @@
/*
* Copyright (C) 2016 Fourier Semiconductor Inc.
*
*/
#ifndef FS16XX_PRESET_H
#define FS16XX_PRESET_H
#include "fs16xx_define.h"
#ifdef __cplusplus
extern "C" {
#endif
#define PRESET_NAME_SIZE 256
// Preset version for 1801 series
#define PRESET_VERSION 0x0A01
// Size in int32
#define EXCUR_PROT_RAM_LEN 0x39
#pragma pack(push, 1)
struct fs16xx_preset_header {
uint16_t preset_ver; /* Preset version, should be PRESET_VERSION */
char customer_name[32]; /* Customer info */
int64_t create_time; /* Time tick when the preset created */
uint16_t data_len;/* Length of the data in int16_t */
uint16_t crc16; /* CRC check sum of the data */
uint16_t tmax; /* speaker max temprature */
uint16_t tempr_coef; /* speaker temperature coef */
uint16_t tempr_sel; /* default value of reg TEMPSEL (0x08)*/
uint16_t spk_set; /* default value of reg SPKSET (0x0A)*/
uint16_t adp_bst[2]; /* default value of reg ADPBST (0xBF)*/
uint16_t bst_ctrl[2]; /* default value of reg BSTCTRL (0xC0)*/
uint16_t agc_ctrl[2]; /* default value of reg AGCCTRL (0xA7)*/
uint16_t agc_thd[2]; /* default value of reg AGCTHD (0xA8)*/
uint16_t agc_para[2]; /* default value of reg AGCPARA (0xA9)*/
uint16_t agc_mg[2]; /* default value of reg AGCMG (0xAA)*/
uint16_t dac_para1[2]; /* default value of reg DACPARA1 (0xCD)*/
uint16_t acs_drc[2]; /* default value of reg ACSDRC (0x8A)*/
uint16_t acs_drcs[2]; /* default value of reg ACSDRCS (0x8B)*/
uint16_t acs_drcp[2]; /* default value of reg ACSDRCP (0x8C)*/
uint16_t ts_ctrl[2]; /* default value of reg TSCTRL (0xAF)*/
int32_t *excur_prot_ram; /* excur prot coef ram */
uint16_t *data; /* Point to coef ram data */
};
typedef struct fs16xx_preset_header Fs16xx_preset_header_t;
#define FS_PRESET_HEADER_LEN (sizeof(Fs16xx_preset_header_t) - sizeof(uint16_t *))
enum _fs16xx_preset_type {
fs16xx_preset_left = 0,
fs16xx_preset_right = 1,
fs16xx_preset_type_max = 2 // Set to count of preset types
};
typedef enum _fs16xx_preset_type fs16xx_preset_type;
struct fs16xx_preset_content {
int valid;
Fs16xx_preset_header_t preset_header;
};
typedef struct fs16xx_preset_content Fs16xx_preset;
#pragma pack(pop)
/**
* Fs16xx initialize presets
*/
Fs16xx_Error_t fs16xx_initialize_presets(void);
/**
* Fs16xx deinitialize presets
*/
Fs16xx_Error_t fs16xx_deinitialize_presets(void);
/**
* Fs16xx load presets from storage
*/
Fs16xx_Error_t fs16xx_load_presets(Fs16xx_devId_t id);
/**
* Fs16xx load presets to fs16xx device
*/
Fs16xx_Error_t fs16xx_load_presets_to_dev(Fs16xx_devId_t id);
uint16_t fs16xx_calc_checksum(uint16_t *data, int len);
/**
* Fs16xx set dsp preset
* @param id to opened instance
* @param preset to set in dsp
*/
Fs16xx_Error_t fs16xx_set_preset(Fs16xx_devId_t id, int preset);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,81 @@
/*
* Copyright (C) 2016 Fourier Semiconductor Inc.
*
*/
#ifndef FS16XX_REG_DEF_H
#define FS16XX_REG_DEF_H
#include "fs16xx_regs.h"
#include "fs16xx.h"
/* I2S_CONTROL bits for sample rates */
#define FS16XX_I2SCTRL_RATE_08000 (0<<FS16XX_I2SCTRL_REG_I2SSR_POS)
#define FS16XX_I2SCTRL_RATE_16000 (3<<FS16XX_I2SCTRL_REG_I2SSR_POS)
#define FS16XX_I2SCTRL_RATE_44100 (7<<FS16XX_I2SCTRL_REG_I2SSR_POS)
#define FS16XX_I2SCTRL_RATE_48000 (8<<FS16XX_I2SCTRL_REG_I2SSR_POS)
const struct fs16xx_regs Fs16xx_reg_defaults[] = {
{
.reg = 0x06,
.value = 0xFF00, // volume to 0dB
},
{
.reg = 0x0B,
.value = 0xCA91,
},
{
.reg = 0xD3,
.value = 0x0100, // damp, key protected.
},
{
.reg = 0x0B,
.value = 0x0000,
},
{
.reg = 0xC1,
.value = 0x0260, // configure pll
},
{
.reg = 0xC2,
.value = 0x0100, // configure pll
},
{
.reg = 0xC3,
.value = 0x0004, // configure pll
},
{
.reg = 0x04,
.value = 0x881B, // DC/DC mode: Follow, enable boost
},
{
.reg = 0xC0,
.value = 0x5B80, // DC/DC mode: Follow, enable boost
},
{
.reg = 0xC4,
.value = 0x000F,
},
{
.reg = 0xAE,
.value = 0x0210,
},
{
.reg = 0xB9,
.value = 0xFFFF,
},
{
.reg = 0x09,
.value = 0x0009, // ClassD always on, power down
},
{
.reg = 0xCD,
.value = 0x2004,
},
{
.reg = 0xa1,
.value = 0x1C92,
},
};
#endif
File diff suppressed because it is too large. Load diff
+17 -11
View File
@@ -594,7 +594,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);
@@ -692,8 +692,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;
@@ -707,7 +711,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__);
}
}
@@ -737,7 +741,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),
@@ -760,7 +764,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
@@ -941,8 +945,10 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc)
/* If moisture is present, then enable polling, disable
* moisture detection and wait for interrupt
*/
if (wcd_mbhc_moisture_detect(mbhc, detection_type))
if (wcd_mbhc_moisture_detect(mbhc, detection_type)){
pr_info("%s: hwcd_mbhc_moisture_detect\n", __func__);
goto done;
}
/* Make sure MASTER_BIAS_CTL is enabled */
mbhc->mbhc_cb->mbhc_bias(component, true);
@@ -1064,7 +1070,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;
@@ -1247,7 +1253,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);
@@ -1256,8 +1262,8 @@ 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",
__func__);
pr_info("%s: Reporting btn press %x\n",
__func__, mbhc->buttons_pressed);
wcd_mbhc_jack_report(mbhc,
&mbhc->button_jack,
mbhc->buttons_pressed,
@@ -36,6 +36,15 @@ ifeq ($(KERNEL_BUILD), 0)
export
INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h
endif
ifneq (,$(filter rhode%, $(TARGET_PRODUCT)))
INCS += -include $(AUDIO_ROOT)/config/rhodeautoconf.h
endif
ifneq (,$(filter hawao%, $(TARGET_PRODUCT)))
INCS += -include $(AUDIO_ROOT)/config/hawaoautoconf.h
endif
ifneq (,$(filter devon%, $(TARGET_PRODUCT)))
INCS += -include $(AUDIO_ROOT)/config/devonautoconf.h
endif
endif
# As per target team, build is done as follows:
@@ -767,6 +767,12 @@ static bool wcd937x_mbhc_get_moisture_status(struct wcd_mbhc *mbhc)
struct snd_soc_component *component = mbhc->component;
bool ret = false;
#ifdef CONFIG_MBHC_DISABLE_MOISTURE_DETECT
pr_info("%s: disable moisture detection \n", __func__);
snd_soc_component_update_bits(component, WCD937X_MBHC_NEW_CTL_2, 0x0C, R_OFF << 2);
goto done;
#endif
if ((mbhc->moist_rref == R_OFF) ||
(mbhc->mbhc_cfg->enable_usbc_analog)) {
snd_soc_component_update_bits(component, WCD937X_MBHC_NEW_CTL_2,
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
* Copyright (c) 2018, 2021, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -8,9 +8,12 @@
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/component.h>
#include <soc/soundwire.h>
#define SWR_MAX_RETRY 5
struct wcd937x_slave_priv {
struct swr_device *swr_slave;
};
@@ -22,6 +25,7 @@ static int wcd937x_slave_bind(struct device *dev,
struct wcd937x_slave_priv *wcd937x_slave = NULL;
uint8_t devnum = 0;
struct swr_device *pdev = to_swr_device(dev);
int retry = SWR_MAX_RETRY;
if (pdev == NULL) {
dev_err(dev, "%s: pdev is NULL\n", __func__);
@@ -37,7 +41,12 @@ static int wcd937x_slave_bind(struct device *dev,
wcd937x_slave->swr_slave = pdev;
ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum);
do {
/* Add delay for soundwire enumeration */
usleep_range(100, 110);
ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum);
} while (ret && --retry);
if (ret) {
dev_dbg(&pdev->dev,
"%s get devnum %d for dev addr %lx failed\n",
+52 -3
View File
@@ -22222,6 +22222,13 @@ static const struct snd_kcontrol_new sbus_6_rx_port_mixer_controls[] = {
msm_routing_put_port_mixer),
};
static const struct snd_kcontrol_new sbus_7_rx_port_mixer_controls[] = {
SOC_DOUBLE_EXT("SLIM_8_TX", SND_SOC_NOPM,
MSM_BACKEND_DAI_SLIMBUS_7_RX,
MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
};
static const struct snd_kcontrol_new bt_sco_rx_port_mixer_controls[] = {
SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM,
MSM_BACKEND_DAI_INT_BT_SCO_RX,
@@ -22279,6 +22286,10 @@ static const struct snd_kcontrol_new usb_rx_port_mixer_controls[] = {
MSM_BACKEND_DAI_USB_RX,
MSM_BACKEND_DAI_USB_TX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
SOC_DOUBLE_EXT("SLIM_8_TX", SND_SOC_NOPM,
MSM_BACKEND_DAI_USB_RX,
MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
};
static const struct snd_kcontrol_new lsm1_mixer_controls[] = {
@@ -22826,6 +22837,11 @@ static const struct snd_kcontrol_new slim6_fm_switch_mixer_controls =
0, 1, 0, msm_routing_get_switch_mixer,
msm_routing_put_switch_mixer);
static const struct snd_kcontrol_new slim7_fm_switch_mixer_controls =
SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
0, 1, 0, msm_routing_get_switch_mixer,
msm_routing_put_switch_mixer);
static const struct snd_kcontrol_new pcm_rx_switch_mixer_controls =
SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
0, 1, 0, msm_routing_get_fm_pcmrx_switch_mixer,
@@ -24172,6 +24188,26 @@ static const char * const int4_mi2s_rx_vi_fb_tx_stereo_mux_text[] = {
"ZERO", "INT5_MI2S_TX"
};
#ifdef CONFIG_SND_SMARTPA_AW882XX
static const char * const pri_mi2s_rx_vi_fb_tx_mux_text[] = {
"ZERO", "PRI_MI2S_TX"
};
static const int const pri_mi2s_rx_vi_fb_tx_value[] = {
MSM_BACKEND_DAI_MAX, MSM_BACKEND_DAI_PRI_MI2S_TX
};
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 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);
#endif
static const int slim0_rx_vi_fb_tx_lch_value[] = {
MSM_BACKEND_DAI_MAX, MSM_BACKEND_DAI_SLIMBUS_4_TX
};
@@ -24569,6 +24605,9 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
&cdc_dma_rx_1_switch_mixer_controls),
#endif
SND_SOC_DAPM_SWITCH("SLIMBUS7_DL_HL", SND_SOC_NOPM, 0, 0,
&slim7_fm_switch_mixer_controls),
/* Mixer definitions */
SND_SOC_DAPM_MIXER("SLIMBUS_0_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
slimbus_rx_mixer_controls, ARRAY_SIZE(slimbus_rx_mixer_controls)),
@@ -25251,8 +25290,14 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets_mi2s[] = {
ARRAY_SIZE(int4_mi2s_rx_port_mixer_controls)),
/* lsm mixer definitions */
/* Virtual Pins to force backends ON atm */
#ifdef CONFIG_SND_SMARTPA_AW882XX
SND_SOC_DAPM_MUX("PRI_MI2S_RX_VI_FB_MUX", SND_SOC_NOPM, 0, 0,
&pri_mi2s_rx_vi_fb_mux),
#else
SND_SOC_DAPM_MUX("PRI_MI2S_RX_VI_FB_MUX", SND_SOC_NOPM, 0, 0,
&mi2s_rx_vi_fb_mux),
#endif
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,
@@ -27339,8 +27384,9 @@ static const struct snd_soc_dapm_route intercon[] = {
{"AFE_PCM_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
{"PCM_RX", NULL, "AFE_PCM_RX Port Mixer"},
{"USB_AUDIO_RX Port Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
{"USB_AUDIO_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
{"USB_AUDIO_RX", NULL, "USB_AUDIO_RX Port Mixer"},
{"USB_DL_HL", "Switch", "USBAUDIO_DL_HL"},
{"USB_DL_HL", "Switch", "CDC_DMA_DL_HL"},
{"USB_AUDIO_RX", NULL, "USB_DL_HL"},
{"USBAUDIO_UL_HL", NULL, "USB_AUDIO_TX"},
@@ -30374,7 +30420,7 @@ static const struct snd_soc_dapm_route intercon_mi2s[] = {
{"INT0_MI2S_RX", NULL, "INT0_MI2S_RX_DL_HL"},
{"INT4_MI2S_RX_DL_HL", "Switch", "INT4_MI2S_DL_HL"},
{"INT4_MI2S_RX", NULL, "INT4_MI2S_RX_DL_HL"},
{"PRI_MI2S_RX_DL_HL", "Switch", "PRI_MI2S_DL_HL"},
{"PRI_MI2S_RX_DL_HL", "Switch", "CDC_DMA_DL_HL"},
{"PRI_MI2S_RX", NULL, "PRI_MI2S_RX_DL_HL"},
{"SEC_MI2S_RX_DL_HL", "Switch", "SEC_MI2S_DL_HL"},
{"SEC_MI2S_RX", NULL, "SEC_MI2S_RX_DL_HL"},
@@ -30549,8 +30595,11 @@ static const struct snd_soc_dapm_route intercon_mi2s[] = {
{"INT5_MI2S_TX", NULL, "BE_IN"},
{"SEC_MI2S_TX", NULL, "BE_IN"},
{"SENARY_MI2S_TX", NULL, "BE_IN"},
#ifdef CONFIG_SND_SMARTPA_AW882XX
{"PRI_MI2S_RX_VI_FB_MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
#else
{"PRI_MI2S_RX_VI_FB_MUX", "SENARY_TX", "SENARY_TX"},
#endif
{"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"},
+2 -1
View File
@@ -37,5 +37,6 @@ CONFIG_PM2250_SPMI=m
CONFIG_SND_SOC_BENGAL=m
CONFIG_SND_EVENT=m
CONFIG_TDM_DISABLE=m
CONFIG_MI2S_DISABLE=m
CONFIG_AUXPCM_DISABLE=m
CONFIG_SND_SMARTPA_AW882XX=m
CONFIG_SND_SOC_FS16XX=m
+3 -1
View File
@@ -41,5 +41,7 @@
#define CONFIG_SND_SOC_BENGAL 1
#define CONFIG_SND_EVENT 1
#define CONFIG_TDM_DISABLE 1
#define CONFIG_MI2S_DISABLE 1
#define CONFIG_AUXPCM_DISABLE 1
#define CONFIG_SND_SMARTPA_AW882XX 1
#define CONFIG_AW882XX_DSP 1
#define CONFIG_SND_SOC_FS16XX 1
+7
View File
@@ -0,0 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#define CONFIG_AW882XX_STEREO_SMARTPA 1
#define CONFIG_AW882XX_PARAMS_STORED_IN_BIN 1
#define CONFIG_DEVON_AW882XX_SMARTPA 1
#define CONFIG_AW882XX_MAPSIZE_16K 1
+7
View File
@@ -0,0 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#define CONFIG_AW882XX_STEREO_SMARTPA 1
#define CONFIG_AW882XX_PARAMS_STORED_IN_BIN 1
#define CONFIG_HAWAO_AW882XX_SMARTPA 1
#define CONFIG_AW882XX_MAPSIZE_16K 1
+6
View File
@@ -0,0 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#define CONFIG_AW882XX_STEREO_SMARTPA 1
#define CONFIG_AW882XX_PARAMS_STORED_IN_BIN 1
#define CONFIG_AW882XX_MAPSIZE_16K 1
+11
View File
@@ -96,6 +96,17 @@ ifeq ($(KERNEL_BUILD), 0)
export
INCS += -include $(AUDIO_ROOT)/config/sdm450autoconf.h
endif
ifneq (,$(filter rhode%, $(TARGET_PRODUCT)))
INCS += -include $(AUDIO_ROOT)/config/rhodeautoconf.h
endif
ifneq (,$(filter hawao%, $(TARGET_PRODUCT)))
INCS += -include $(AUDIO_ROOT)/config/hawaoautoconf.h
endif
ifneq (,$(filter devon%, $(TARGET_PRODUCT)))
INCS += -include $(AUDIO_ROOT)/config/devonautoconf.h
endif
endif
+41
View File
@@ -4633,6 +4633,47 @@ int adm_set_ffecns_freeze_event(bool ffecns_freeze_event)
}
EXPORT_SYMBOL(adm_set_ffecns_freeze_event);
#ifdef CONFIG_AW882XX_DSP
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;
}
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 -
* command to send params to ADM for given module
+233
View File
@@ -44,6 +44,18 @@ enum {
static struct afe_avcs_payload_port_mapping *pm[MAX_ALLOWED_USE_CASES];
#ifdef CONFIG_AW882XX_DSP
#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)
//#define AFE_PORT_ID_AWDSP_RX (AFE_PORT_ID_PRIMARY_MI2S_RX)
//#define AFE_PORT_ID_AWDSP_TX (AFE_PORT_ID_PRIMARY_MI2S_TX)
void aw_cal_unmap_memory(void);
#endif
enum {
AFE_COMMON_RX_CAL = 0,
AFE_COMMON_TX_CAL,
@@ -236,6 +248,10 @@ struct afe_ctl {
struct mutex afe_apr_lock;
struct mutex afe_clk_lock;
int set_custom_topology;
#ifdef CONFIG_AW882XX_DSP
struct rtac_cal_block_data aw_cal;
atomic_t aw_state;
#endif
int dev_acdb_id[AFE_MAX_PORTS];
routing_cb rt_cb;
struct audio_uevent_data *uevent_data;
@@ -1008,6 +1024,9 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv)
return -EINVAL;
}
if (data->opcode == RESET_EVENTS) {
#ifdef CONFIG_AW882XX_DSP
aw_cal_unmap_memory();
#endif /*CONFIG_AW882XX_DSP*/
pr_debug("%s: reset event = %d %d apr[%pK]\n",
__func__,
data->reset_event, data->reset_proc, this_afe.apr);
@@ -1079,6 +1098,20 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv)
return -EINVAL;
}
#ifdef CONFIG_AW882XX_DSP
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
if (rtac_make_afe_callback(data->payload,
data->payload_size))
return 0;
@@ -2463,6 +2496,16 @@ 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_AW882XX_DSP
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
default:
pr_err("%s: default case 0x%x\n", __func__, param_id);
goto fail_cmd;
@@ -3746,6 +3789,189 @@ done:
return ret;
}
#ifdef CONFIG_AW882XX_DSP
int aw_send_afe_rx_module_enable(uint32_t rx_port_id, void *buf, int size)
{
union afe_spkr_prot_config config;
if (size > sizeof(config))
return -EINVAL;
memcpy(&config, buf, 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 size)
{
union afe_spkr_prot_config config;
if (size > sizeof(config))
return -EINVAL;
memcpy(&config, buf, 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);
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)
{
int32_t result = 0;
uint32_t port_id = 0;
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__);
port_id = rx_port_id;
if (param_id == AFE_PARAM_ID_AWDSP_TX_SET_ENABLE) {
port_id = tx_port_id;
module_id = AFE_MODULE_ID_AWDSP_TX;
}
if (aw_cal->map_data.dma_buf == 0) {
/*Minimal chunk size is 4K*/
#ifdef CONFIG_AW882XX_MAPSIZE_16K
aw_cal->map_data.map_size = SZ_16K;
#else
aw_cal->map_data.map_size = SZ_4K;
#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_4K - 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);
#endif
static int afe_init_cdc_reg_config(void)
{
struct param_hdr_v3 param_hdr;
@@ -10922,6 +11148,9 @@ static int afe_unmap_cal_data(int32_t cal_type,
ret = afe_cmd_memory_unmap_nowait(
cal_block->map_data.q6map_handle);
atomic_set(&this_afe.mem_map_cal_index, -1);
#ifdef CONFIG_AW882XX_PARAMS_STORED_IN_BIN
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);
@@ -11194,6 +11423,10 @@ void afe_exit(void)
q6core_destroy_uevent_data(this_afe.uevent_data);
#ifdef CONFIG_AW882XX_DSP
aw_cal_unmap_memory();
#endif
afe_delete_cal_data();
config_debug_fs_exit();
+8
View File
@@ -2528,6 +2528,14 @@ static int swrm_master_init(struct swr_mstr_ctrl *swrm)
swr_master_bulk_write(swrm, reg, value, len);
/* SW workaround to gate hw_ctl for SWR version >=1.6 */
if (swrm->version >= SWRM_VERSION_1_6) {
if (swrm->swrm_hctl_reg) {
temp = ioread32(swrm->swrm_hctl_reg);
temp &= 0xFFFFFFFD;
iowrite32(temp, swrm->swrm_hctl_reg);
}
}
if (!swrm_check_link_status(swrm, 0x1)) {
dev_err(swrm->dev,
"%s: swr link failed to connect\n",