asoc: Add fs1818 support for guamp/guamna
Propagation of the https://gerrit.mot.com/#/c/1510671/ in order to enable fs1818 as audio PA for guamp and guamna EVT sample devices. Change-Id: I772278e04a98bd4c95443e911d228d746797a263 Signed-off-by: yaozm1 <yaozm1@lenovo.com> Reviewed-on: https://gerrit.mot.com/1510671 SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Reviewed-by: Xiangpo Zhao <zhaoxp3@motorola.com> Submit-Approved: Jira Key Reviewed-on: https://gerrit.mot.com/1914385 Reviewed-by: Monica Mabuchi <monicam@motorola.com> Reviewed-by: Nelson Guedes Paulo Junior <npaulo@motorola.com> Reviewed-by: Jian Luan <jamesluan@motorola.com>
This commit is contained in:
1 parent
39d96b8ecc
commit
793f3936a6
16 files changed
+4773
-1
No files matched your search
@@ -5441,8 +5441,13 @@ static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = {
|
||||
.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,
|
||||
@@ -6220,6 +6225,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));
|
||||
|
||||
@@ -175,7 +175,14 @@ 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
|
||||
@@ -252,6 +252,7 @@ ifeq ($(KERNEL_BUILD), 1)
|
||||
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
|
||||
@@ -293,5 +294,15 @@ 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
|
||||
|
||||
# inject some build related information
|
||||
DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\"
|
||||
@@ -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
@@ -39,3 +39,4 @@ CONFIG_SND_EVENT=m
|
||||
CONFIG_TDM_DISABLE=m
|
||||
CONFIG_AUXPCM_DISABLE=m
|
||||
CONFIG_SND_SMARTPA_AW882XX=m
|
||||
CONFIG_SND_SOC_FS16XX=m
|
||||
@@ -44,3 +44,4 @@
|
||||
#define CONFIG_AUXPCM_DISABLE 1
|
||||
#define CONFIG_SND_SMARTPA_AW882XX 1
|
||||
#define CONFIG_AW882XX_DSP 1
|
||||
#define CONFIG_SND_SOC_FS16XX 1
|
||||
Reference in new issue
Block a user