ASoC: msm: Add support to query speaker parameters

Add SET and GET parameter APIs to query speaker
parameters in feedback speaker protection FTM mode.

CRs-Fixed: 974621
Change-Id: I1a51e5033d7836c0c996621593cd2f4dd6982dcd
Signed-off-by: Vidyakumar Athota <vathota@codeaurora.org>
This commit is contained in:
Vidyakumar Athota 2016-02-02 14:10:42 -08:00 committed by David Keitel
parent 41a12ff0ed
commit a15e630662
4 changed files with 755 additions and 47 deletions

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -7501,11 +7501,184 @@ struct asm_mode_vi_proc_cfg {
uint32_t cal_mode;
} __packed;
#define AFE_MODULE_SPEAKER_PROTECTION_V2_TH_VI 0x0001026A
#define AFE_PARAM_ID_SP_V2_TH_VI_MODE_CFG 0x0001026B
#define AFE_PARAM_ID_SP_V2_TH_VI_FTM_CFG 0x0001029F
#define AFE_PARAM_ID_SP_V2_TH_VI_FTM_PARAMS 0x000102A0
struct afe_sp_th_vi_mode_cfg {
uint32_t minor_version;
uint32_t operation_mode;
/*
* Operation mode of thermal VI module.
* 0 -- Normal Running mode
* 1 -- Calibration mode
* 2 -- FTM mode
*/
uint32_t r0t0_selection_flag[SP_V2_NUM_MAX_SPKR];
/*
* Specifies which set of R0, T0 values the algorithm will use.
* This field is valid only in Normal mode (operation_mode = 0).
* 0 -- Use calibrated R0, T0 value
* 1 -- Use safe R0, T0 value
*/
int32_t r0_cali_q24[SP_V2_NUM_MAX_SPKR];
/*
* Calibration point resistance per device. This field is valid
* only in Normal mode (operation_mode = 0).
* values 33554432 to 1073741824 Ohms (in Q24 format)
*/
int16_t t0_cali_q6[SP_V2_NUM_MAX_SPKR];
/*
* Calibration point temperature per device. This field is valid
* in both Normal mode and Calibration mode.
* values -1920 to 5120 degrees C (in Q6 format)
*/
uint32_t quick_calib_flag;
/*
* Indicates whether calibration is to be done in quick mode or not.
* This field is valid only in Calibration mode (operation_mode = 1).
* 0 -- Disabled
* 1 -- Enabled
*/
} __packed;
struct afe_sp_th_vi_ftm_cfg {
uint32_t minor_version;
uint32_t wait_time_ms[SP_V2_NUM_MAX_SPKR];
/*
* Wait time to heat up speaker before collecting statistics
* for ftm mode in ms.
* values 0 to 4294967295 ms
*/
uint32_t ftm_time_ms[SP_V2_NUM_MAX_SPKR];
/*
* duration for which FTM statistics are collected in ms.
* values 0 to 2000 ms
*/
} __packed;
struct afe_sp_th_vi_ftm_params {
uint32_t minor_version;
int32_t dc_res_q24[SP_V2_NUM_MAX_SPKR];
/*
* DC resistance value in q24 format
* values 0 to 2147483647 Ohms (in Q24 format)
*/
int32_t temp_q22[SP_V2_NUM_MAX_SPKR];
/*
* temperature value in q22 format
* values -125829120 to 2147483647 degC (in Q22 format)
*/
uint32_t status[SP_V2_NUM_MAX_SPKR];
/*
* FTM packet status
* 0 - Incorrect operation mode.This status is returned
* when GET_PARAM is called in non FTM Mode
* 1 - Inactive mode -- Port is not yet started.
* 2 - Wait state. wait_time_ms has not yet elapsed
* 3 - In progress state. ftm_time_ms has not yet elapsed.
* 4 - Success.
* 5 - Failed.
*/
} __packed;
struct afe_sp_th_vi_get_param {
struct apr_hdr hdr;
struct afe_port_cmd_get_param_v2 get_param;
struct afe_port_param_data_v2 pdata;
struct afe_sp_th_vi_ftm_params param;
} __packed;
struct afe_sp_th_vi_get_param_resp {
uint32_t status;
struct afe_port_param_data_v2 pdata;
struct afe_sp_th_vi_ftm_params param;
} __packed;
#define AFE_MODULE_SPEAKER_PROTECTION_V2_EX_VI 0x0001026F
#define AFE_PARAM_ID_SP_V2_EX_VI_MODE_CFG 0x000102A1
#define AFE_PARAM_ID_SP_V2_EX_VI_FTM_CFG 0x000102A2
#define AFE_PARAM_ID_SP_V2_EX_VI_FTM_PARAMS 0x000102A3
struct afe_sp_ex_vi_mode_cfg {
uint32_t minor_version;
uint32_t operation_mode;
/*
* Operation mode of Excursion VI module.
* 0 - Normal Running mode
* 2 - FTM mode
*/
} __packed;
struct afe_sp_ex_vi_ftm_cfg {
uint32_t minor_version;
uint32_t wait_time_ms[SP_V2_NUM_MAX_SPKR];
/*
* Wait time to heat up speaker before collecting statistics
* for ftm mode in ms.
* values 0 to 4294967295 ms
*/
uint32_t ftm_time_ms[SP_V2_NUM_MAX_SPKR];
/*
* duration for which FTM statistics are collected in ms.
* values 0 to 2000 ms
*/
} __packed;
struct afe_sp_ex_vi_ftm_params {
uint32_t minor_version;
int32_t freq_q20[SP_V2_NUM_MAX_SPKR];
/*
* Resonance frequency in q20 format
* values 0 to 2147483647 Hz (in Q20 format)
*/
int32_t resis_q24[SP_V2_NUM_MAX_SPKR];
/*
* Mechanical resistance in q24 format
* values 0 to 2147483647 Ohms (in Q24 format)
*/
int32_t qmct_q24[SP_V2_NUM_MAX_SPKR];
/*
* Mechanical Qfactor in q24 format
* values 0 to 2147483647 (in Q24 format)
*/
uint32_t status[SP_V2_NUM_MAX_SPKR];
/*
* FTM packet status
* 0 - Incorrect operation mode.This status is returned
* when GET_PARAM is called in non FTM Mode.
* 1 - Inactive mode -- Port is not yet started.
* 2 - Wait state. wait_time_ms has not yet elapsed
* 3 - In progress state. ftm_time_ms has not yet elapsed.
* 4 - Success.
* 5 - Failed.
*/
} __packed;
struct afe_sp_ex_vi_get_param {
struct apr_hdr hdr;
struct afe_port_cmd_get_param_v2 get_param;
struct afe_port_param_data_v2 pdata;
struct afe_sp_ex_vi_ftm_params param;
} __packed;
struct afe_sp_ex_vi_get_param_resp {
uint32_t status;
struct afe_port_param_data_v2 pdata;
struct afe_sp_ex_vi_ftm_params param;
} __packed;
union afe_spkr_prot_config {
struct asm_fbsp_mode_rx_cfg mode_rx_cfg;
struct asm_spkr_calib_vi_proc_cfg vi_proc_cfg;
struct asm_feedback_path_cfg feedback_path_cfg;
struct asm_mode_vi_proc_cfg mode_vi_proc_cfg;
struct afe_sp_th_vi_mode_cfg th_vi_mode_cfg;
struct afe_sp_th_vi_ftm_cfg th_vi_ftm_cfg;
struct afe_sp_ex_vi_mode_cfg ex_vi_mode_cfg;
struct afe_sp_ex_vi_ftm_cfg ex_vi_ftm_cfg;
} __packed;
struct afe_spkr_prot_config_command {

View file

@ -96,9 +96,14 @@ enum {
ADM_RTAC_AUDVOL_CAL_TYPE,
ULP_LSM_TOPOLOGY_ID_CAL_TYPE,
AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE,
AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE,
MAX_CAL_TYPES,
};
#define AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE
#define AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE
enum {
VERSION_0_0,
};
@ -271,7 +276,9 @@ enum msm_spkr_prot_states {
MSM_SPKR_PROT_DISABLED,
MSM_SPKR_PROT_NOT_CALIBRATED,
MSM_SPKR_PROT_PRE_CALIBRATED,
MSM_SPKR_PROT_IN_FTM_MODE
};
#define MSM_SPKR_PROT_IN_FTM_MODE MSM_SPKR_PROT_IN_FTM_MODE
enum msm_spkr_count {
SP_V2_SPKR_1,
@ -283,9 +290,46 @@ struct audio_cal_info_spk_prot_cfg {
int32_t r0[SP_V2_NUM_MAX_SPKRS];
int32_t t0[SP_V2_NUM_MAX_SPKRS];
uint32_t quick_calib_flag;
uint32_t mode; /*0 - Start spk prot
1 - Start calib
2 - Disable spk prot*/
uint32_t mode;
/*
* 0 - Start spk prot
* 1 - Start calib
* 2 - Disable spk prot
*/
};
struct audio_cal_info_sp_th_vi_ftm_cfg {
uint32_t wait_time[SP_V2_NUM_MAX_SPKRS];
uint32_t ftm_time[SP_V2_NUM_MAX_SPKRS];
uint32_t mode;
/*
* 0 - normal running mode
* 1 - Calibration
* 2 - FTM mode
*/
};
struct audio_cal_info_sp_ex_vi_ftm_cfg {
uint32_t wait_time[SP_V2_NUM_MAX_SPKRS];
uint32_t ftm_time[SP_V2_NUM_MAX_SPKRS];
uint32_t mode;
/*
* 0 - normal running mode
* 2 - FTM mode
*/
};
struct audio_cal_info_sp_ex_vi_param {
int32_t freq_q20[SP_V2_NUM_MAX_SPKRS];
int32_t resis_q24[SP_V2_NUM_MAX_SPKRS];
int32_t qmct_q24[SP_V2_NUM_MAX_SPKRS];
int32_t status[SP_V2_NUM_MAX_SPKRS];
};
struct audio_cal_info_sp_th_vi_param {
int32_t r_dc_q24[SP_V2_NUM_MAX_SPKRS];
int32_t temp_q22[SP_V2_NUM_MAX_SPKRS];
int32_t status[SP_V2_NUM_MAX_SPKRS];
};
struct audio_cal_info_msm_spk_prot_status {
@ -493,6 +537,27 @@ struct audio_cal_fb_spk_prot_cfg {
struct audio_cal_type_fb_spk_prot_cfg cal_type;
};
struct audio_cal_type_sp_th_vi_ftm_cfg {
struct audio_cal_type_header cal_hdr;
struct audio_cal_data cal_data;
struct audio_cal_info_sp_th_vi_ftm_cfg cal_info;
};
struct audio_cal_sp_th_vi_ftm_cfg {
struct audio_cal_header hdr;
struct audio_cal_type_sp_th_vi_ftm_cfg cal_type;
};
struct audio_cal_type_sp_ex_vi_ftm_cfg {
struct audio_cal_type_header cal_hdr;
struct audio_cal_data cal_data;
struct audio_cal_info_sp_ex_vi_ftm_cfg cal_info;
};
struct audio_cal_sp_ex_vi_ftm_cfg {
struct audio_cal_header hdr;
struct audio_cal_type_sp_ex_vi_ftm_cfg cal_type;
};
struct audio_cal_type_hw_delay {
struct audio_cal_type_header cal_hdr;
struct audio_cal_data cal_data;
@ -604,4 +669,24 @@ struct audio_cal_fb_spk_prot_status {
struct audio_cal_type_fb_spk_prot_status cal_type;
};
struct audio_cal_type_sp_th_vi_param {
struct audio_cal_type_header cal_hdr;
struct audio_cal_data cal_data;
struct audio_cal_info_sp_th_vi_param cal_info;
};
struct audio_cal_sp_th_vi_param {
struct audio_cal_header hdr;
struct audio_cal_type_sp_th_vi_param cal_type;
};
struct audio_cal_type_sp_ex_vi_param {
struct audio_cal_type_header cal_hdr;
struct audio_cal_data cal_data;
struct audio_cal_info_sp_ex_vi_param cal_info;
};
struct audio_cal_sp_ex_vi_param {
struct audio_cal_header hdr;
struct audio_cal_type_sp_ex_vi_param cal_type;
};
#endif /* _UAPI_MSM_AUDIO_CALIBRATION_H */

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -89,6 +89,22 @@ size_t get_cal_info_size(int32_t cal_type)
case AFE_FB_SPKR_PROT_CAL_TYPE:
size = sizeof(struct audio_cal_info_spk_prot_cfg);
break;
case AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE:
/*
* Since get and set parameter structures are different in size
* use the maximum size of get and set parameter structure
*/
size = max(sizeof(struct audio_cal_info_sp_th_vi_ftm_cfg),
sizeof(struct audio_cal_info_sp_th_vi_param));
break;
case AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE:
/*
* Since get and set parameter structures are different in size
* use the maximum size of get and set parameter structure
*/
size = max(sizeof(struct audio_cal_info_sp_ex_vi_ftm_cfg),
sizeof(struct audio_cal_info_sp_ex_vi_param));
break;
case AFE_ANC_CAL_TYPE:
size = 0;
break;
@ -219,6 +235,22 @@ size_t get_user_cal_type_size(int32_t cal_type)
case AFE_FB_SPKR_PROT_CAL_TYPE:
size = sizeof(struct audio_cal_type_fb_spk_prot_cfg);
break;
case AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE:
/*
* Since get and set parameter structures are different in size
* use the maximum size of get and set parameter structure
*/
size = max(sizeof(struct audio_cal_type_sp_th_vi_ftm_cfg),
sizeof(struct audio_cal_type_sp_th_vi_param));
break;
case AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE:
/*
* Since get and set parameter structures are different in size
* use the maximum size of get and set parameter structure
*/
size = max(sizeof(struct audio_cal_type_sp_ex_vi_ftm_cfg),
sizeof(struct audio_cal_type_sp_ex_vi_param));
break;
case AFE_ANC_CAL_TYPE:
size = 0;
break;

View file

@ -37,26 +37,28 @@ enum {
AFE_SIDETONE_CAL,
AFE_TOPOLOGY_CAL,
AFE_CUST_TOPOLOGY_CAL,
AFE_FB_SPKR_PROT_TH_VI_CAL,
AFE_FB_SPKR_PROT_EX_VI_CAL,
MAX_AFE_CAL_TYPES
};
enum calibration_state {
CALIB_INCORRECT_OP_MODE,
CALIB_INACTIVE,
CALIB_WARMUP,
CALIB_IN_PROGRESS,
CALIB_SUCCESS,
CALIB_FAILED,
MAX_CALIB_STATE
enum fbsp_state {
FBSP_INCORRECT_OP_MODE,
FBSP_INACTIVE,
FBSP_WARMUP,
FBSP_IN_PROGRESS,
FBSP_SUCCESS,
FBSP_FAILED,
MAX_FBSP_STATE
};
static char cali_state[MAX_CALIB_STATE][50] = {
[CALIB_INCORRECT_OP_MODE] = "incorrect operation mode",
[CALIB_INACTIVE] = "port not started",
[CALIB_WARMUP] = "waiting for warmup",
[CALIB_IN_PROGRESS] = "in calibration state",
[CALIB_SUCCESS] = "success",
[CALIB_FAILED] = "failed"
static char fbsp_state[MAX_FBSP_STATE][50] = {
[FBSP_INCORRECT_OP_MODE] = "incorrect operation mode",
[FBSP_INACTIVE] = "port not started",
[FBSP_WARMUP] = "waiting for warmup",
[FBSP_IN_PROGRESS] = "in progress state",
[FBSP_SUCCESS] = "success",
[FBSP_FAILED] = "failed"
};
enum {
@ -69,6 +71,12 @@ enum {
QUICK_CALIB_ENABLE
};
enum {
Q6AFE_MSM_SPKR_PROCESSING = 0,
Q6AFE_MSM_SPKR_CALIBRATION,
Q6AFE_MSM_SPKR_FTM_MODE
};
struct wlock {
struct wakeup_source ws;
};
@ -99,6 +107,10 @@ struct afe_ctl {
u16 dtmf_gen_rx_portid;
struct audio_cal_info_spk_prot_cfg prot_cfg;
struct afe_spkr_prot_calib_get_resp calib_data;
struct audio_cal_info_sp_th_vi_ftm_cfg th_ftm_cfg;
struct audio_cal_info_sp_ex_vi_ftm_cfg ex_ftm_cfg;
struct afe_sp_th_vi_get_param_resp th_vi_resp;
struct afe_sp_ex_vi_get_param_resp ex_vi_resp;
int vi_tx_port;
int vi_rx_port;
uint32_t afe_sample_rates[AFE_MAX_PORTS];
@ -115,9 +127,6 @@ static struct afe_ctl this_afe;
#define TIMEOUT_MS 1000
#define Q6AFE_MAX_VOLUME 0x3FFF
#define Q6AFE_MSM_SPKR_PROCESSING 0
#define Q6AFE_MSM_SPKR_CALIBRATION 1
static int pcm_afe_instance[2];
static int proxy_afe_instance[2];
bool afe_close_done[2] = {true, true};
@ -176,6 +185,73 @@ static void afe_callback_debug_print(struct apr_client_data *data)
__func__, data->opcode, data->payload_size);
}
static int32_t sp_make_afe_callback(uint32_t *payload, uint32_t payload_size)
{
u32 param_id;
struct afe_spkr_prot_calib_get_resp *resp =
(struct afe_spkr_prot_calib_get_resp *) payload;
if (!(&(resp->pdata))) {
pr_err("%s: Error: resp pdata is NULL\n", __func__);
return -EINVAL;
}
param_id = resp->pdata.param_id;
if (param_id == AFE_PARAM_ID_CALIB_RES_CFG_V2) {
if (payload_size < sizeof(this_afe.calib_data)) {
pr_err("%s: Error: received size %d, calib_data size %zu\n",
__func__, payload_size,
sizeof(this_afe.calib_data));
return -EINVAL;
}
memcpy(&this_afe.calib_data, payload,
sizeof(this_afe.calib_data));
if (!this_afe.calib_data.status) {
atomic_set(&this_afe.state, 0);
} else {
pr_debug("%s: calib resp status: %d", __func__,
this_afe.calib_data.status);
atomic_set(&this_afe.state, -1);
}
}
if (param_id == AFE_PARAM_ID_SP_V2_TH_VI_FTM_PARAMS) {
if (payload_size < sizeof(this_afe.th_vi_resp)) {
pr_err("%s: Error: received size %d, th_vi_resp size %zu\n",
__func__, payload_size,
sizeof(this_afe.th_vi_resp));
return -EINVAL;
}
memcpy(&this_afe.th_vi_resp, payload,
sizeof(this_afe.th_vi_resp));
if (!this_afe.th_vi_resp.status) {
atomic_set(&this_afe.state, 0);
} else {
pr_debug("%s: th vi resp status: %d", __func__,
this_afe.th_vi_resp.status);
atomic_set(&this_afe.state, -1);
}
}
if (param_id == AFE_PARAM_ID_SP_V2_EX_VI_FTM_PARAMS) {
if (payload_size < sizeof(this_afe.ex_vi_resp)) {
pr_err("%s: Error: received size %d, ex_vi_resp size %zu\n",
__func__, payload_size,
sizeof(this_afe.ex_vi_resp));
return -EINVAL;
}
memcpy(&this_afe.ex_vi_resp, payload,
sizeof(this_afe.ex_vi_resp));
if (!this_afe.ex_vi_resp.status) {
atomic_set(&this_afe.state, 0);
} else {
pr_debug("%s: ex vi resp status: %d", __func__,
this_afe.ex_vi_resp.status);
atomic_set(&this_afe.state, -1);
}
}
return 0;
}
static int32_t afe_callback(struct apr_client_data *data, void *priv)
{
if (!data) {
@ -216,23 +292,15 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv)
if (rtac_make_afe_callback(data->payload, data->payload_size))
return 0;
if ((data->payload_size < sizeof(this_afe.calib_data))
|| !payload || (data->token >= AFE_MAX_PORTS)) {
if (!payload || (data->token >= AFE_MAX_PORTS)) {
pr_err("%s: Error: size %d payload %p token %d\n",
__func__, data->payload_size,
payload, data->token);
return -EINVAL;
}
memcpy(&this_afe.calib_data, payload,
sizeof(this_afe.calib_data));
if (!this_afe.calib_data.status) {
atomic_set(&this_afe.state, 0);
pr_err("%s: rest = %d %d state = %s\n", __func__
, this_afe.calib_data.res_cfg.r0_cali_q24[SP_V2_SPKR_1],
this_afe.calib_data.res_cfg.r0_cali_q24[SP_V2_SPKR_2],
cali_state[this_afe.calib_data.res_cfg.th_vi_ca_state]);
} else
atomic_set(&this_afe.state, -1);
if (sp_make_afe_callback(data->payload, data->payload_size))
return -EINVAL;
wake_up(&this_afe.wait[data->token]);
} else if (data->payload_size) {
uint32_t *payload;
@ -839,8 +907,17 @@ static int afe_spk_prot_prepare(int src_port, int dst_port, int param_id,
this_afe.vi_rx_port = dst_port;
config.pdata.module_id = AFE_MODULE_FEEDBACK;
break;
/*
* AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG_V2 is same as
* AFE_PARAM_ID_SP_V2_TH_VI_MODE_CFG
*/
case AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG_V2:
config.pdata.module_id = AFE_MODULE_FB_SPKR_PROT_VI_PROC_V2;
case AFE_PARAM_ID_SP_V2_TH_VI_FTM_CFG:
config.pdata.module_id = AFE_MODULE_SPEAKER_PROTECTION_V2_TH_VI;
break;
case AFE_PARAM_ID_SP_V2_EX_VI_MODE_CFG:
case AFE_PARAM_ID_SP_V2_EX_VI_FTM_CFG:
config.pdata.module_id = AFE_MODULE_SPEAKER_PROTECTION_V2_EX_VI;
break;
default:
pr_err("%s: default case 0x%x\n", __func__, param_id);
@ -897,14 +974,14 @@ static void afe_send_cal_spkr_prot_tx(int port_id)
{
union afe_spkr_prot_config afe_spk_config;
if (this_afe.cal_data[AFE_FB_SPKR_PROT_CAL] == NULL)
goto done;
if (this_afe.cal_data[AFE_FB_SPKR_PROT_CAL] == NULL ||
this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL ||
this_afe.cal_data[AFE_FB_SPKR_PROT_EX_VI_CAL] == NULL)
return;
mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_CAL]->lock);
if ((this_afe.prot_cfg.mode != MSM_SPKR_PROT_DISABLED) &&
(this_afe.vi_tx_port == port_id)) {
afe_spk_config.mode_rx_cfg.minor_version = 1;
if (this_afe.prot_cfg.mode ==
MSM_SPKR_PROT_CALIBRATION_IN_PROGRESS) {
afe_spk_config.vi_proc_cfg.operation_mode =
@ -913,8 +990,12 @@ static void afe_send_cal_spkr_prot_tx(int port_id)
this_afe.prot_cfg.quick_calib_flag;
} else {
afe_spk_config.vi_proc_cfg.operation_mode =
Q6AFE_MSM_SPKR_PROCESSING;
Q6AFE_MSM_SPKR_PROCESSING;
}
if (this_afe.th_ftm_cfg.mode == MSM_SPKR_PROT_IN_FTM_MODE)
afe_spk_config.vi_proc_cfg.operation_mode =
Q6AFE_MSM_SPKR_FTM_MODE;
afe_spk_config.vi_proc_cfg.minor_version = 1;
afe_spk_config.vi_proc_cfg.r0_cali_q24[SP_V2_SPKR_1] =
(uint32_t) this_afe.prot_cfg.r0[SP_V2_SPKR_1];
@ -946,8 +1027,57 @@ static void afe_send_cal_spkr_prot_tx(int port_id)
__func__);
}
mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_CAL]->lock);
done:
return;
mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
if ((this_afe.th_ftm_cfg.mode == MSM_SPKR_PROT_IN_FTM_MODE) &&
(this_afe.vi_tx_port == port_id)) {
afe_spk_config.th_vi_ftm_cfg.minor_version = 1;
afe_spk_config.th_vi_ftm_cfg.wait_time_ms[SP_V2_SPKR_1] =
this_afe.th_ftm_cfg.wait_time[SP_V2_SPKR_1];
afe_spk_config.th_vi_ftm_cfg.wait_time_ms[SP_V2_SPKR_2] =
this_afe.th_ftm_cfg.wait_time[SP_V2_SPKR_2];
afe_spk_config.th_vi_ftm_cfg.ftm_time_ms[SP_V2_SPKR_1] =
this_afe.th_ftm_cfg.ftm_time[SP_V2_SPKR_1];
afe_spk_config.th_vi_ftm_cfg.ftm_time_ms[SP_V2_SPKR_2] =
this_afe.th_ftm_cfg.ftm_time[SP_V2_SPKR_2];
if (afe_spk_prot_prepare(port_id, 0,
AFE_PARAM_ID_SP_V2_TH_VI_FTM_CFG,
&afe_spk_config))
pr_err("%s: th vi ftm cfg failed\n", __func__);
this_afe.th_ftm_cfg.mode = MSM_SPKR_PROT_DISABLED;
}
mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_EX_VI_CAL]->lock);
if ((this_afe.ex_ftm_cfg.mode == MSM_SPKR_PROT_IN_FTM_MODE) &&
(this_afe.vi_tx_port == port_id)) {
afe_spk_config.ex_vi_mode_cfg.minor_version = 1;
afe_spk_config.ex_vi_mode_cfg.operation_mode =
Q6AFE_MSM_SPKR_FTM_MODE;
if (afe_spk_prot_prepare(port_id, 0,
AFE_PARAM_ID_SP_V2_EX_VI_MODE_CFG,
&afe_spk_config))
pr_err("%s: ex vi mode cfg failed\n", __func__);
afe_spk_config.ex_vi_ftm_cfg.minor_version = 1;
afe_spk_config.ex_vi_ftm_cfg.wait_time_ms[SP_V2_SPKR_1] =
this_afe.ex_ftm_cfg.wait_time[SP_V2_SPKR_1];
afe_spk_config.ex_vi_ftm_cfg.wait_time_ms[SP_V2_SPKR_2] =
this_afe.ex_ftm_cfg.wait_time[SP_V2_SPKR_2];
afe_spk_config.ex_vi_ftm_cfg.ftm_time_ms[SP_V2_SPKR_1] =
this_afe.ex_ftm_cfg.ftm_time[SP_V2_SPKR_1];
afe_spk_config.ex_vi_ftm_cfg.ftm_time_ms[SP_V2_SPKR_2] =
this_afe.ex_ftm_cfg.ftm_time[SP_V2_SPKR_2];
if (afe_spk_prot_prepare(port_id, 0,
AFE_PARAM_ID_SP_V2_EX_VI_FTM_CFG,
&afe_spk_config))
pr_err("%s: ex vi ftm cfg failed\n", __func__);
this_afe.ex_ftm_cfg.mode = MSM_SPKR_PROT_DISABLED;
}
mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_EX_VI_CAL]->lock);
}
static void afe_send_cal_spkr_prot_rx(int port_id)
@ -5134,6 +5264,155 @@ int q6afe_check_osr_clk_freq(u32 freq)
return ret;
}
int afe_get_sp_th_vi_ftm_data(struct afe_sp_th_vi_get_param *th_vi)
{
int ret = -EINVAL;
int index = 0, port = SLIMBUS_4_TX;
if (!th_vi) {
pr_err("%s: Invalid params\n", __func__);
goto done;
}
if (this_afe.vi_tx_port != -1)
port = this_afe.vi_tx_port;
ret = q6audio_validate_port(port);
if (ret < 0) {
pr_err("%s: invalid port 0x%x ret %d\n", __func__, port, ret);
goto done;
}
index = q6audio_get_port_index(port);
th_vi->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
th_vi->hdr.pkt_size = sizeof(*th_vi);
th_vi->hdr.src_port = 0;
th_vi->hdr.dest_port = 0;
th_vi->hdr.token = index;
th_vi->hdr.opcode = AFE_PORT_CMD_GET_PARAM_V2;
th_vi->get_param.mem_map_handle = 0;
th_vi->get_param.module_id = AFE_MODULE_SPEAKER_PROTECTION_V2_TH_VI;
th_vi->get_param.param_id = AFE_PARAM_ID_SP_V2_TH_VI_FTM_PARAMS;
th_vi->get_param.payload_address_lsw = 0;
th_vi->get_param.payload_address_msw = 0;
th_vi->get_param.payload_size = sizeof(*th_vi)
- sizeof(th_vi->get_param) - sizeof(th_vi->hdr);
th_vi->get_param.port_id = q6audio_get_port_id(port);
th_vi->pdata.module_id = AFE_MODULE_SPEAKER_PROTECTION_V2_TH_VI;
th_vi->pdata.param_id = AFE_PARAM_ID_SP_V2_TH_VI_FTM_PARAMS;
th_vi->pdata.param_size = sizeof(th_vi->param);
atomic_set(&this_afe.status, 0);
atomic_set(&this_afe.state, 1);
ret = apr_send_pkt(this_afe.apr, (uint32_t *)th_vi);
if (ret < 0) {
pr_err("%s: get param port 0x%x param id[0x%x]failed %d\n",
__func__, port, th_vi->get_param.param_id, ret);
goto done;
}
ret = wait_event_timeout(this_afe.wait[index],
(atomic_read(&this_afe.state) == 0),
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: wait_event timeout\n", __func__);
ret = -EINVAL;
goto done;
}
if (atomic_read(&this_afe.status) > 0) {
pr_err("%s: config cmd failed [%s]\n",
__func__, adsp_err_get_err_str(
atomic_read(&this_afe.status)));
ret = adsp_err_get_lnx_err_code(atomic_read(&this_afe.status));
goto done;
}
memcpy(&th_vi->param , &this_afe.th_vi_resp.param,
sizeof(this_afe.th_vi_resp.param));
pr_debug("%s: DC resistance %d %d temp %d %d status %d %d\n",
__func__, th_vi->param.dc_res_q24[SP_V2_SPKR_1],
th_vi->param.dc_res_q24[SP_V2_SPKR_2],
th_vi->param.temp_q22[SP_V2_SPKR_1],
th_vi->param.temp_q22[SP_V2_SPKR_2],
th_vi->param.status[SP_V2_SPKR_1],
th_vi->param.status[SP_V2_SPKR_2]);
ret = 0;
done:
return ret;
}
int afe_get_sp_ex_vi_ftm_data(struct afe_sp_ex_vi_get_param *ex_vi)
{
int ret = -EINVAL;
int index = 0, port = SLIMBUS_4_TX;
if (!ex_vi) {
pr_err("%s: Invalid params\n", __func__);
goto done;
}
if (this_afe.vi_tx_port != -1)
port = this_afe.vi_tx_port;
ret = q6audio_validate_port(port);
if (ret < 0) {
pr_err("%s: invalid port 0x%x ret %d\n", __func__, port, ret);
goto done;
}
index = q6audio_get_port_index(port);
ex_vi->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
ex_vi->hdr.pkt_size = sizeof(*ex_vi);
ex_vi->hdr.src_port = 0;
ex_vi->hdr.dest_port = 0;
ex_vi->hdr.token = index;
ex_vi->hdr.opcode = AFE_PORT_CMD_GET_PARAM_V2;
ex_vi->get_param.mem_map_handle = 0;
ex_vi->get_param.module_id = AFE_MODULE_SPEAKER_PROTECTION_V2_EX_VI;
ex_vi->get_param.param_id = AFE_PARAM_ID_SP_V2_EX_VI_FTM_PARAMS;
ex_vi->get_param.payload_address_lsw = 0;
ex_vi->get_param.payload_address_msw = 0;
ex_vi->get_param.payload_size = sizeof(*ex_vi)
- sizeof(ex_vi->get_param) - sizeof(ex_vi->hdr);
ex_vi->get_param.port_id = q6audio_get_port_id(port);
ex_vi->pdata.module_id = AFE_MODULE_SPEAKER_PROTECTION_V2_EX_VI;
ex_vi->pdata.param_id = AFE_PARAM_ID_SP_V2_EX_VI_FTM_PARAMS;
ex_vi->pdata.param_size = sizeof(ex_vi->param);
atomic_set(&this_afe.status, 0);
atomic_set(&this_afe.state, 1);
ret = apr_send_pkt(this_afe.apr, (uint32_t *)ex_vi);
if (ret < 0) {
pr_err("%s: get param port 0x%x param id[0x%x]failed %d\n",
__func__, port, ex_vi->get_param.param_id, ret);
goto done;
}
ret = wait_event_timeout(this_afe.wait[index],
(atomic_read(&this_afe.state) == 0),
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: wait_event timeout\n", __func__);
ret = -EINVAL;
goto done;
}
if (atomic_read(&this_afe.status) > 0) {
pr_err("%s: config cmd failed [%s]\n",
__func__, adsp_err_get_err_str(
atomic_read(&this_afe.status)));
ret = adsp_err_get_lnx_err_code(atomic_read(&this_afe.status));
goto done;
}
memcpy(&ex_vi->param , &this_afe.ex_vi_resp.param,
sizeof(this_afe.ex_vi_resp.param));
pr_debug("%s: freq %d %d resistance %d %d qfactor %d %d state %d %d\n",
__func__, ex_vi->param.freq_q20[SP_V2_SPKR_1],
ex_vi->param.freq_q20[SP_V2_SPKR_2],
ex_vi->param.resis_q24[SP_V2_SPKR_1],
ex_vi->param.resis_q24[SP_V2_SPKR_2],
ex_vi->param.qmct_q24[SP_V2_SPKR_1],
ex_vi->param.qmct_q24[SP_V2_SPKR_2],
ex_vi->param.status[SP_V2_SPKR_1],
ex_vi->param.status[SP_V2_SPKR_2]);
ret = 0;
done:
return ret;
}
int afe_spk_prot_get_calib_data(struct afe_spkr_prot_get_vi_calib *calib_resp)
{
int ret = -EINVAL;
@ -5205,7 +5484,7 @@ int afe_spk_prot_get_calib_data(struct afe_spkr_prot_get_vi_calib *calib_resp)
memcpy(&calib_resp->res_cfg , &this_afe.calib_data.res_cfg,
sizeof(this_afe.calib_data.res_cfg));
pr_info("%s: state %s resistance %d %d\n", __func__,
cali_state[calib_resp->res_cfg.th_vi_ca_state],
fbsp_state[calib_resp->res_cfg.th_vi_ca_state],
calib_resp->res_cfg.r0_cali_q24[SP_V2_SPKR_1],
calib_resp->res_cfg.r0_cali_q24[SP_V2_SPKR_2]);
ret = 0;
@ -5299,9 +5578,11 @@ int afe_alloc_cal(int32_t cal_type, size_t data_size,
{
int ret = 0;
int cal_index;
pr_debug("%s:\n", __func__);
cal_index = get_cal_type_index(cal_type);
pr_debug("%s: cal_type = %d cal_index = %d\n",
__func__, cal_type, cal_index);
if (cal_index < 0) {
pr_err("%s: could not get cal index %d!\n",
__func__, cal_index);
@ -5468,6 +5749,46 @@ done:
return ret;
}
static int afe_set_cal_sp_th_vi_ftm_cfg(int32_t cal_type, size_t data_size,
void *data)
{
int ret = 0;
struct audio_cal_type_sp_th_vi_ftm_cfg *cal_data = data;
if (this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL ||
cal_data == NULL ||
data_size != sizeof(*cal_data))
goto done;
pr_debug("%s: cal_type = %d\n", __func__, cal_type);
mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
memcpy(&this_afe.th_ftm_cfg, &cal_data->cal_info,
sizeof(this_afe.th_ftm_cfg));
mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
done:
return ret;
}
static int afe_set_cal_sp_ex_vi_ftm_cfg(int32_t cal_type, size_t data_size,
void *data)
{
int ret = 0;
struct audio_cal_type_sp_ex_vi_ftm_cfg *cal_data = data;
if (this_afe.cal_data[AFE_FB_SPKR_PROT_EX_VI_CAL] == NULL ||
cal_data == NULL ||
data_size != sizeof(*cal_data))
goto done;
pr_debug("%s: cal_type = %d\n", __func__, cal_type);
mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_EX_VI_CAL]->lock);
memcpy(&this_afe.ex_ftm_cfg, &cal_data->cal_info,
sizeof(this_afe.ex_ftm_cfg));
mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_EX_VI_CAL]->lock);
done:
return ret;
}
static int afe_set_cal_fb_spkr_prot(int32_t cal_type, size_t data_size,
void *data)
{
@ -5487,11 +5808,94 @@ static int afe_set_cal_fb_spkr_prot(int32_t cal_type, size_t data_size,
mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_CAL]->lock);
memcpy(&this_afe.prot_cfg, &cal_data->cal_info,
sizeof(this_afe.prot_cfg));
this_afe.th_ftm_cfg.mode = this_afe.prot_cfg.mode;
this_afe.ex_ftm_cfg.mode = this_afe.prot_cfg.mode;
mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_CAL]->lock);
done:
return ret;
}
static int afe_get_cal_sp_th_vi_ftm_param(int32_t cal_type, size_t data_size,
void *data)
{
int i, ret = 0;
struct audio_cal_type_sp_th_vi_param *cal_data = data;
struct afe_sp_th_vi_get_param th_vi;
pr_debug("%s: cal_type = %d\n", __func__, cal_type);
if (this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL ||
cal_data == NULL ||
data_size != sizeof(*cal_data))
goto done;
mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
for (i = 0; i < SP_V2_NUM_MAX_SPKRS; i++) {
cal_data->cal_info.status[i] = -EINVAL;
cal_data->cal_info.r_dc_q24[i] = -1;
cal_data->cal_info.temp_q22[i] = -1;
}
if (!afe_get_sp_th_vi_ftm_data(&th_vi)) {
for (i = 0; i < SP_V2_NUM_MAX_SPKRS; i++) {
pr_debug("%s: ftm param status = %d\n",
__func__, th_vi.param.status[i]);
if (th_vi.param.status[i] == FBSP_IN_PROGRESS) {
cal_data->cal_info.status[i] = -EAGAIN;
} else if (th_vi.param.status[i] == FBSP_SUCCESS) {
cal_data->cal_info.status[i] = 0;
cal_data->cal_info.r_dc_q24[i] =
th_vi.param.dc_res_q24[i];
cal_data->cal_info.temp_q22[i] =
th_vi.param.temp_q22[i];
}
}
}
mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
done:
return ret;
}
static int afe_get_cal_sp_ex_vi_ftm_param(int32_t cal_type, size_t data_size,
void *data)
{
int i, ret = 0;
struct audio_cal_type_sp_ex_vi_param *cal_data = data;
struct afe_sp_ex_vi_get_param ex_vi;
pr_debug("%s: cal_type = %d\n", __func__, cal_type);
if (this_afe.cal_data[AFE_FB_SPKR_PROT_EX_VI_CAL] == NULL ||
cal_data == NULL ||
data_size != sizeof(*cal_data))
goto done;
mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_EX_VI_CAL]->lock);
for (i = 0; i < SP_V2_NUM_MAX_SPKRS; i++) {
cal_data->cal_info.status[i] = -EINVAL;
cal_data->cal_info.freq_q20[i] = -1;
cal_data->cal_info.resis_q24[i] = -1;
cal_data->cal_info.qmct_q24[i] = -1;
}
if (!afe_get_sp_ex_vi_ftm_data(&ex_vi)) {
for (i = 0; i < SP_V2_NUM_MAX_SPKRS; i++) {
pr_debug("%s: ftm param status = %d\n",
__func__, ex_vi.param.status[i]);
if (ex_vi.param.status[i] == FBSP_IN_PROGRESS) {
cal_data->cal_info.status[i] = -EAGAIN;
} else if (ex_vi.param.status[i] == FBSP_SUCCESS) {
cal_data->cal_info.status[i] = 0;
cal_data->cal_info.freq_q20[i] =
ex_vi.param.freq_q20[i];
cal_data->cal_info.resis_q24[i] =
ex_vi.param.resis_q24[i];
cal_data->cal_info.qmct_q24[i] =
ex_vi.param.qmct_q24[i];
}
}
}
mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_EX_VI_CAL]->lock);
done:
return ret;
}
static int afe_get_cal_fb_spkr_prot(int32_t cal_type, size_t data_size,
void *data)
{
@ -5522,10 +5926,10 @@ static int afe_get_cal_fb_spkr_prot(int32_t cal_type, size_t data_size,
cal_data->cal_info.r0[SP_V2_SPKR_2] = -1;
if (!afe_spk_prot_get_calib_data(&calib_resp)) {
if (calib_resp.res_cfg.th_vi_ca_state ==
CALIB_IN_PROGRESS)
FBSP_IN_PROGRESS)
cal_data->cal_info.status = -EAGAIN;
else if (calib_resp.res_cfg.th_vi_ca_state ==
CALIB_SUCCESS) {
FBSP_SUCCESS) {
cal_data->cal_info.status = 0;
cal_data->cal_info.r0[SP_V2_SPKR_1] =
calib_resp.res_cfg.r0_cali_q24[SP_V2_SPKR_1];
@ -5547,6 +5951,8 @@ static int afe_get_cal_fb_spkr_prot(int32_t cal_type, size_t data_size,
cal_data->cal_info.r0[SP_V2_SPKR_1] = -1;
cal_data->cal_info.r0[SP_V2_SPKR_2] = -1;
}
this_afe.th_ftm_cfg.mode = this_afe.prot_cfg.mode;
this_afe.ex_ftm_cfg.mode = this_afe.prot_cfg.mode;
mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_CAL]->lock);
__pm_relax(&wl.ws);
done:
@ -5677,6 +6083,16 @@ static int afe_init_cal_data(void)
afe_set_cal, NULL, NULL} },
{afe_map_cal_data, afe_unmap_cal_data,
cal_utils_match_buf_num} },
{{AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE,
{NULL, NULL, NULL, afe_set_cal_sp_th_vi_ftm_cfg,
afe_get_cal_sp_th_vi_ftm_param, NULL} },
{NULL, NULL, cal_utils_match_buf_num} },
{{AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE,
{NULL, NULL, NULL, afe_set_cal_sp_ex_vi_ftm_cfg,
afe_get_cal_sp_ex_vi_ftm_param, NULL} },
{NULL, NULL, cal_utils_match_buf_num} },
};
pr_debug("%s:\n", __func__);
@ -5778,6 +6194,8 @@ static int __init afe_init(void)
this_afe.vi_tx_port = -1;
this_afe.vi_rx_port = -1;
this_afe.prot_cfg.mode = MSM_SPKR_PROT_DISABLED;
this_afe.th_ftm_cfg.mode = MSM_SPKR_PROT_DISABLED;
this_afe.ex_ftm_cfg.mode = MSM_SPKR_PROT_DISABLED;
mutex_init(&this_afe.afe_cmd_lock);
for (i = 0; i < AFE_MAX_PORTS; i++) {
this_afe.afe_cal_mode[i] = AFE_CAL_MODE_DEFAULT;