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:
yaozm1 authored and Gilberto Gambugge committed 2023-06-01 00:35:13 -03:00
1 parent 39d96b8ecc
commit 793f3936a6
16 files changed
+4773 -1

No files matched your search

+6
View File
@@ -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));
+8 -1
View File
@@ -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
+11
View File
@@ -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')\"
+5
View File
@@ -0,0 +1,5 @@
config SND_SOC_FS16XX
tristate "Support foursemi fs16xx chip"
depends on I2C
help
foursemi fs16xx driver
+9
View File
@@ -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
+190
View File
@@ -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
+734
View File
@@ -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;
}
+128
View File
@@ -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
+120
View File
@@ -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
+452
View File
@@ -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;
}
+99
View File
@@ -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
+81
View File
@@ -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
+1
View File
@@ -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
+1
View File
@@ -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