audio:add fs1815 bypass algo code and logic.

fogor use fs1815.
need set fsadsp algo on/off,rotation,battery and so.
add related code to support.

Change-Id: Ie7a23814a00ee0962f7e9c20782974162d4374f0
Signed-off-by: liaohj <liaohj@lenovo.com>
Reviewed-on: https://gerrit.mot.com/2666214
SME-Granted: SME Approvals Granted
SLTApproved: Slta Waiver
Tested-by: Jira Key
Reviewed-by: Wanlong Zhou <zhouwl@motorola.com>
Reviewed-by: Huosheng Liao <liaohs@motorola.com>
Submit-Approved: Jira Key
This commit is contained in:
liaohj 2023-07-05 16:42:41 +08:00 • committed by panyq6
commit 6505e846cc
4 changed files with 884 additions and 0 deletions

View file

@ -13,6 +13,12 @@ static int fsm_try_init(void);
static int g_dev_inited = 0;
static atomic_t fsm_amp_switch;
static atomic_t fsm_adsp_enable;
//include "q6fsm-v3.h"
extern int q6fsm_set_rotation(int angle);
extern int q6fsm_set_rx_enable(int enable);
static LIST_HEAD(fsm_dev_list);
#define fsm_list_init(fsm_dev) \
@ -1613,6 +1619,64 @@ int fsm_init_get(struct snd_kcontrol *kcontrol,
return 0;
}
int fsm_rotation_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
fsm_config_t *cfg = fsm_get_config();
if (!cfg) {
ucontrol->value.integer.value[0] = -1;
return 0;
}
ucontrol->value.integer.value[0] = cfg->next_angle;
return 0;
}
int fsm_rotation_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
fsm_config_t *cfg = fsm_get_config();
int angle = ucontrol->value.integer.value[0];
if(!cfg){
pr_err("cfg is null");
return 0;
}
pr_info("angle: %d", angle);
if(q6fsm_set_rotation(angle) == 0){
cfg->next_angle = angle;
}
return 0;
}
int fsm_adsp_enable_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int enable = atomic_read(&fsm_adsp_enable);
ucontrol->value.integer.value[0] = enable;
pr_info("get: %s", (enable) ? "Enable" : "Disable");
return 0;
}
int fsm_adsp_enable_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int enable = ucontrol->value.integer.value[0];
pr_info("switch: %s", enable ? "Enable" : "Disable");
if(q6fsm_set_rx_enable(enable) == 0){
atomic_set(&fsm_adsp_enable, enable);
}
return 0;
}
const struct snd_kcontrol_new fsm_snd_controls[] =
{
SOC_SINGLE_EXT("FSM_Scene", SND_SOC_NOPM, 0, FSM_SCENE_MAX, 0,
@ -1621,6 +1685,10 @@ const struct snd_kcontrol_new fsm_snd_controls[] =
fsm_amp_switch_get, fsm_amp_switch_put),
SOC_SINGLE_EXT("FSM_Init", SND_SOC_NOPM, 0, 1, 0,
fsm_init_get, fsm_init_put),
SOC_SINGLE_EXT("FSM_Rotation", SND_SOC_NOPM, 0, 360, 0,
fsm_rotation_get, fsm_rotation_put),
SOC_SINGLE_EXT("FSM_ADSP_Enable", SND_SOC_NOPM, 0, 1, 0,
fsm_adsp_enable_get, fsm_adsp_enable_put),
};
void fsm_add_codec_controls(struct snd_soc_codec *codec)

View file

@ -27,6 +27,10 @@ ifdef CONFIG_SND_SOC_AW87XXX
CDEFINES += -DCONFIG_SND_SOC_AW87XXX
endif
ifdef CONFIG_SND_SOC_FS1815
CDEFINES += -DCONFIG_SND_SOC_FS1815
endif
ifeq ($(CONFIG_SND_SOC_AUTO), y)
ifdef CONFIG_SND_SOC_SA8155
include $(AUDIO_ROOT)/config/sa8155auto.conf

View file

@ -24,6 +24,12 @@
#include "adsp_err.h"
#include "q6afecal-hwdep.h"
#ifdef CONFIG_SND_SOC_FS1815
#include <dsp/q6fsm-v3.h>
#endif
#ifdef CONFIG_SND_SOC_AWINIC_AW882XX
#define AFE_MODULE_ID_AWDSP_TX (0x10013D00)
#define AFE_MODULE_ID_AWDSP_RX (0x10013D01)
@ -1159,6 +1165,18 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv)
return 0;
}
#endif /*CONFIG_SND_SOC_AWINIC_AW882XX*/
#ifdef CONFIG_SND_SOC_FS1815
if (!q6fsm_afe_callback(data->payload, data->payload_size)) {
atomic_set(&this_afe.state, 0);
if (afe_token_is_valid(data->token)) {
wake_up(&this_afe.wait[data->token]);
return 0;
} else {
return -EINVAL;
}
}
#endif
if (rtac_make_afe_callback(data->payload,
data->payload_size))
return 0;
@ -4645,6 +4663,16 @@ static int afe_send_cmd_port_start(u16 port_id)
pr_err("%s: AFE enable for port 0x%x failed %d\n", __func__,
port_id, ret);
#ifdef CONFIG_SND_SOC_FS1815
//TODO:
// Set the monitor enable when:
// 1) Speaker PA type is matched
// 2) In speaker playback
// 3) The RX Port is the same as the one of speaker playback
if (port_id == Q6FSM_AFE_RX_PORT)
q6fsm_monitor_switch(true);
#endif
return ret;
}
@ -9700,6 +9728,11 @@ int afe_close(int port_id)
memset(&stop, 0, sizeof(stop));
#ifdef CONFIG_SND_SOC_FS1815
if (port_id == Q6FSM_AFE_RX_PORT)
q6fsm_monitor_switch(false);
#endif
if (this_afe.apr == NULL) {
pr_err("%s: AFE is already closed\n", __func__);
@ -12344,11 +12377,17 @@ int __init afe_init(void)
this_afe.event_notifier.notifier_call = afe_aud_event_notify;
msm_aud_evt_blocking_register_client(&this_afe.event_notifier);
#ifdef CONFIG_SND_SOC_FS1815
q6fsm_afe_init();
#endif
return 0;
}
void afe_exit(void)
{
#ifdef CONFIG_SND_SOC_FS1815
q6fsm_afe_deinit();
#endif
if (this_afe.apr) {
apr_reset(this_afe.apr);
atomic_set(&this_afe.state, 0);

773
include/dsp/q6fsm-v3.h Normal file
View file

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