// SPDX-License-Identifier: GPL-2.0 /* aw882xx_calib.c cali_module * * Copyright (c) 2020 AWINIC Technology CO., LTD * * Author: Nick Li * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ /*#define DEBUG*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "aw882xx.h" #include "aw882xx_dsp.h" #include "aw882xx_log.h" #include "aw882xx_calib.h" static bool is_single_cali; /*if mutli_dev cali false, single dev true*/ static const char *cali_str[CALI_STR_MAX] = {"none", "start_cali", "cali_re", "cali_f0", "store_re", "show_re", "show_r0", "show_cali_f0", "show_f0", "show_te", "show_st", "dev_sel", "get_ver", "get_dev_num", "cali_q_f0", "show_q_f0", "get_re_range" }; static char *ch_name[AW_DEV_CH_MAX] = {"pri_l", "pri_r", "sec_l", "sec_r", "tert_l", "tert_r", "quat_l", "quat_r"}; static unsigned int g_cali_re_time = AW_CALI_RE_DEFAULT_TIMER; static unsigned int g_msic_wr_flag = CALI_STR_NONE; static unsigned int g_dev_select = AW_DEV_CH_PRI_L; static unsigned int g_cali_status; static struct miscdevice *g_misc_dev; static DEFINE_MUTEX(g_cali_lock); #ifndef AW_AUDIOREACH_PLATFORM #define AW_CALI_STORE_EXAMPLE #endif #ifdef AW_CALI_STORE_EXAMPLE /*write cali to persist file example*/ #define AWINIC_CALI_FILE "/mnt/vendor/persist/factory/audio/aw_cali.bin" #define AW_INT_DEC_DIGIT 10 static void aw_fs_read(struct file *file, char *buf, size_t count, loff_t *pos) { #ifdef AW_KERNEL_VER_OVER_5_4_0 kernel_read(file, buf, count, pos); #else vfs_read(file, buf, count, pos); #endif } static void aw_fs_write(struct file *file, char *buf, size_t count, loff_t *pos) { #ifdef AW_KERNEL_VER_OVER_5_4_0 kernel_write(file, buf, count, pos); #else vfs_write(file, buf, count, pos); #endif } static int aw_cali_write_cali_re_to_file(int32_t cali_re, int channel) { struct file *fp = NULL; char buf[50] = {0}; loff_t pos = 0; #if !defined AW_KERNEL_VER_OVER_6_1_0 mm_segment_t fs; #endif fp = filp_open(AWINIC_CALI_FILE, O_RDWR | O_CREAT, 0644); if (IS_ERR(fp)) { aw_pr_err("channel:%d open %s failed, error=%ld", channel, AWINIC_CALI_FILE, PTR_ERR(fp)); return -EINVAL; } pos = AW_INT_DEC_DIGIT * channel; snprintf(buf, sizeof(buf), "%10d", cali_re); #ifdef AW_KERNEL_VER_OVER_6_1_0 #elif defined AW_KERNEL_VER_OVER_5_10_0 fs = force_uaccess_begin(); #else fs = get_fs(); set_fs(KERNEL_DS); #endif aw_fs_write(fp, buf, strlen(buf), &pos); #ifdef AW_KERNEL_VER_OVER_6_1_0 #elif defined AW_KERNEL_VER_OVER_5_10_0 force_uaccess_end(fs); #else set_fs(fs); #endif aw_pr_info("channel:%d buf:%s cali_re:%d", channel, buf, cali_re); filp_close(fp, NULL); return 0; } static int aw_cali_get_read_cali_re(int32_t *cali_re, int channel) { struct file *fp = NULL; /*struct inode *node;*/ int f_size; char *buf = NULL; int32_t int_cali_re = 0; loff_t pos = 0; #if !defined AW_KERNEL_VER_OVER_6_1_0 mm_segment_t fs; #endif char *re_buf = NULL; fp = filp_open(AWINIC_CALI_FILE, O_RDONLY, 0); if (IS_ERR(fp)) { aw_pr_err("channel:%d open %s failed, error=%ld", channel, AWINIC_CALI_FILE, PTR_ERR(fp)); return -EINVAL; } pos = AW_INT_DEC_DIGIT * channel; /*node = fp->f_dentry->d_inode;*/ /*f_size = node->i_size;*/ f_size = AW_INT_DEC_DIGIT; buf = kzalloc(f_size + 1, GFP_ATOMIC); if (!buf) { filp_close(fp, NULL); return -ENOMEM; } #ifdef AW_KERNEL_VER_OVER_6_1_0 #elif defined AW_KERNEL_VER_OVER_5_10_0 fs = force_uaccess_begin(); #else fs = get_fs(); set_fs(KERNEL_DS); #endif aw_fs_read(fp, buf, f_size, &pos); #ifdef AW_KERNEL_VER_OVER_6_1_0 #elif defined AW_KERNEL_VER_OVER_5_10_0 force_uaccess_end(fs); #else set_fs(fs); #endif re_buf = skip_spaces(buf); if (kstrtoint(re_buf, 10, &int_cali_re) == 0) *cali_re = int_cali_re; else *cali_re = AW_ERRO_CALI_VALUE; re_buf = NULL; aw_pr_info("channel:%d buf:%s int_cali_re: %d", channel, buf, int_cali_re); kfree(buf); buf = NULL; filp_close(fp, NULL); return 0; } #endif /*custom need add to set/get cali_re form/to nv*/ static int aw_cali_write_re_to_nvram(int32_t cali_re, int32_t channel) { #ifdef AW_CALI_STORE_EXAMPLE if (channel >= AW_DEV_CH_MAX) { aw_pr_err("unsupported channel [%d]", channel); return -EINVAL; } return aw_cali_write_cali_re_to_file(cali_re, channel); #else return 0; #endif } int aw882xx_cali_read_re_from_nvram(int32_t *cali_re, int32_t channel) { /*custom add, if success return value is 0 , else -1*/ #ifdef AW_CALI_STORE_EXAMPLE if (channel >= AW_DEV_CH_MAX) { aw_pr_err("unsupported channel [%d]", channel); return -EINVAL; } return aw_cali_get_read_cali_re(cali_re, channel); #else return 0; #endif } bool aw882xx_cali_check_result(struct aw_cali_desc *cali_desc) { if (cali_desc->cali_check_st && (cali_desc->cali_result == CALI_RESULT_ERROR)) { return false; } else { return true; } } static void aw_cali_svc_run_mute(struct aw_device *aw_dev, int8_t cali_result) { aw_dev_dbg(aw_dev->dev, "enter"); if (aw_dev->cali_desc.cali_check_st) { if (cali_result == CALI_RESULT_ERROR) aw882xx_dev_mute(aw_dev, true); else if (cali_result == CALI_RESULT_NORMAL) aw882xx_dev_mute(aw_dev, false); else aw_dev_info(aw_dev->dev, "unsupported result"); } else { aw_dev_info(aw_dev->dev, "cali check disable"); } aw_dev_info(aw_dev->dev, "done"); } static int aw_cali_svc_get_dev_re_range(struct aw_device *aw_dev, uint32_t *data_buf) { data_buf[RE_MIN_FLAG] = aw_dev->re_min; data_buf[RE_MAX_FLAG] = aw_dev->re_max; return 0; } static int aw_cali_svc_get_devs_re_range(struct aw_device *aw_dev, uint32_t *data_buf, int num) { int ret, cnt = 0; struct list_head *dev_list = NULL; struct list_head *pos = NULL; struct aw_device *local_dev = NULL; /*get dev list*/ ret = aw882xx_dev_get_list_head(&dev_list); if (ret) { aw_dev_err(aw_dev->dev, "get dev list failed"); return ret; } list_for_each(pos, dev_list) { local_dev = container_of(pos, struct aw_device, list_node); if (local_dev->channel < num) { /*buf[0]:pri_l_re_min, buf[1]:pri_l_re_min, buf[2]:pri_r_re_min, buf[3]:pri_r_re_min*/ data_buf[RE_MIN_FLAG + local_dev->channel * 2] = local_dev->re_min; data_buf[RE_MAX_FLAG + local_dev->channel * 2] = local_dev->re_max; cnt++; } else { aw_dev_err(local_dev->dev, "channel num[%d] overflow buf num[%d]", local_dev->channel, num); return -EINVAL; } } return cnt; } static int aw_cali_store_cali_re(struct aw_device *aw_dev, int32_t re) { int ret = 0; if (((re >= aw_dev->re_min) && (re <= aw_dev->re_max)) || aw_dev->cali_desc.cali_check_st) { aw_dev->cali_desc.cali_re = re; ret = aw_cali_write_re_to_nvram(re, aw_dev->channel); if (ret) { aw_dev_err(aw_dev->dev, "write re to nvram failed!"); goto store_cali_re_failed; } aw_dev_info(aw_dev->dev, "store cali re is %d", re); } if ((re < aw_dev->re_min) || (re > aw_dev->re_max)) { aw_dev_info(aw_dev->dev, "re[%d] out of range {%d, %d}", re, aw_dev->re_min, aw_dev->re_max); ret = -EINVAL; goto store_cali_re_failed; } if (aw_dev->cali_desc.cali_check_st) aw_dev->cali_desc.cali_result = CALI_RESULT_NORMAL; return 0; store_cali_re_failed: if (aw_dev->cali_desc.cali_check_st) { aw_dev->cali_desc.cali_result = CALI_RESULT_ERROR; aw_cali_svc_run_mute(aw_dev, aw_dev->cali_desc.cali_result); } return ret; } /*********************************aw_cali_sevice*********************************************************/ static void aw_cali_svc_set_cali_status(struct aw_device *aw_dev, int status) { if (status) g_cali_status = true; else g_cali_status = false; aw_dev_info(aw_dev->dev, "cali %s", (status == 0) ? ("disable") : ("enable")); } int aw882xx_cali_svc_get_cali_status(void) { return g_cali_status; } static int aw_cali_svc_dev_get_re(struct aw_device *aw_dev) { int ret, i; int32_t re[AW_CALI_READ_RE_TIMES] = {0}; int32_t sum = 0; for (i = 0; i < AW_CALI_READ_RE_TIMES; i++) { ret = aw882xx_dsp_read_r0(aw_dev, &re[i]); if (ret) { aw_dev_err(aw_dev->dev, "get re failed!"); if (aw_dev->cali_desc.cali_check_st) { aw_dev->cali_desc.cali_result = CALI_RESULT_ERROR; aw_cali_svc_run_mute(aw_dev, aw_dev->cali_desc.cali_result); } return ret; } sum += re[i]; usleep_range(AW_32000_US, AW_32000_US + 10); } re[0] = sum / AW_CALI_READ_RE_TIMES; aw_dev->cali_desc.cali_re = re[0]; ret = aw_cali_store_cali_re(aw_dev, aw_dev->cali_desc.cali_re); return ret; } static int aw_cali_svc_dev_get_f0(struct aw_device *aw_dev) { int ret, i; int32_t f0[AW_CALI_READ_F0_Q_TIMES] = {0}; int32_t sum = 0; for (i = 0; i < AW_CALI_READ_F0_Q_TIMES; i++) { ret = aw882xx_dsp_read_f0(aw_dev, &f0[i]); if (ret) { aw_dev_err(aw_dev->dev, "get f0 failed!"); return ret; } sum += f0[i]; usleep_range(AW_70000_US, AW_70000_US + 10); } f0[0] = sum / AW_CALI_READ_F0_Q_TIMES; aw_dev->cali_desc.cali_f0 = f0[0]; return 0; } static int aw_cali_svc_dev_get_f0_q(struct aw_device *aw_dev) { int ret, i; int32_t f0[AW_CALI_READ_F0_Q_TIMES] = {0}; int32_t q[AW_CALI_READ_F0_Q_TIMES] = {0}; int32_t sum_f0 = 0, sum_q = 0; for (i = 0; i < AW_CALI_READ_F0_Q_TIMES; i++) { ret = aw882xx_dsp_read_f0_q(aw_dev, &f0[i], &q[i]); if (ret) { aw_dev_err(aw_dev->dev, "get f0 failed!"); return ret; } sum_f0 += f0[i]; sum_q += q[i]; usleep_range(AW_70000_US, AW_70000_US + 10); } f0[0] = sum_f0 / AW_CALI_READ_F0_Q_TIMES; q[0] = sum_q / AW_CALI_READ_F0_Q_TIMES; aw_dev->cali_desc.cali_f0 = f0[0]; aw_dev->cali_desc.cali_q = q[0]; aw_dev_dbg(aw_dev->dev, "cali f0 is %d, q is %d", aw_dev->cali_desc.cali_f0, aw_dev->cali_desc.cali_q); return 0; } static int aw_cali_svc_dev_cali_mode_en(struct aw_device *aw_dev, int type, bool is_enable, unsigned int flag) { int ret; /* open cali mode */ if (is_enable) { aw882xx_dev_iv_forbidden_output(aw_dev, false); aw_cali_svc_set_cali_status(aw_dev, true); if (type == CALI_TYPE_RE) { if (flag & CALI_OPS_HMUTE) { ret = aw882xx_dsp_hmute_en(aw_dev, true); if (ret < 0) return ret; } ret = aw882xx_dsp_cali_en(aw_dev, MSG_CALI_RE_ENABLE_DATA); if (ret < 0) return ret; } else { if (flag & CALI_OPS_NOISE) { ret = aw882xx_dsp_noise_en(aw_dev, true); if (ret < 0) return ret; } ret = aw882xx_dsp_cali_en(aw_dev, MSG_CALI_F0_ENABLE_DATA); if (ret < 0) return ret; } } else { aw882xx_dsp_cali_en(aw_dev, MSG_CALI_DISABLE_DATA); if (type == CALI_TYPE_RE) { /*close mute*/ if (flag & CALI_OPS_HMUTE) aw882xx_dsp_hmute_en(aw_dev, false); } else { /*close mute*/ if (flag & CALI_OPS_NOISE) aw882xx_dsp_noise_en(aw_dev, false); } /*close cali mode*/ aw_cali_svc_set_cali_status(aw_dev, false); aw882xx_dev_iv_forbidden_output(aw_dev, true); } return 0; } static int aw_cali_svc_dev_cali_re(struct aw_device *aw_dev, unsigned int flag) { int ret; aw_cali_svc_run_mute(aw_dev, CALI_RESULT_NORMAL); ret = aw_cali_svc_dev_cali_mode_en(aw_dev, CALI_TYPE_RE, true, flag); if (ret < 0) goto exit; /*wait time*/ msleep(g_cali_re_time); /*dev get echo cali re*/ ret = aw_cali_svc_dev_get_re(aw_dev); exit: aw_cali_svc_dev_cali_mode_en(aw_dev, CALI_TYPE_RE, false, flag); return ret; } static int aw_cali_svc_devs_get_cali_cali_data(struct list_head *dev_list, unsigned int data_type) { int ret = -1; struct list_head *pos = NULL; struct aw_device *local_dev = NULL; list_for_each(pos, dev_list) { local_dev = container_of(pos, struct aw_device, list_node); if (data_type == CALI_DATA_RE) { ret = aw_cali_svc_dev_get_re(local_dev); } else if (data_type == CALI_DATA_F0) { ret = aw_cali_svc_dev_get_f0(local_dev); } else if (data_type == CALI_DATA_F0_Q) { ret = aw_cali_svc_dev_get_f0_q(local_dev); } else { aw_dev_err(local_dev->dev, "unsupport cali data type :%d", data_type); return -EINVAL; } if (ret < 0) { aw_dev_err(local_dev->dev, "get cali data type[%d] failed", data_type); return ret; } } return ret; } static int aw_cali_svc_devs_cali_mode_enable(struct list_head *dev_list, int type, unsigned int flag, bool is_enable) { int ret = -1; struct list_head *pos = NULL; struct aw_device *local_dev = NULL; list_for_each(pos, dev_list) { local_dev = container_of(pos, struct aw_device, list_node); if (is_enable) aw_cali_svc_run_mute(local_dev, CALI_RESULT_NORMAL); ret = aw_cali_svc_dev_cali_mode_en(local_dev, type, is_enable, flag); if (ret < 0) return ret; if (!is_enable && (type == CALI_TYPE_F0)) aw_cali_svc_run_mute(local_dev, local_dev->cali_desc.cali_result); } return ret; } static int aw_cali_svc_devs_cali_re(struct aw_device *aw_dev, unsigned int flag) { int ret; struct list_head *dev_list = NULL; aw_dev_info(aw_dev->dev, "enter"); ret = aw882xx_dev_get_list_head(&dev_list); if (ret) { aw_dev_err(aw_dev->dev, " get dev list failed"); return ret; } ret = aw_cali_svc_devs_cali_mode_enable(dev_list, CALI_TYPE_RE, flag, true); if (ret < 0) goto exit; msleep(g_cali_re_time); ret = aw_cali_svc_devs_get_cali_cali_data(dev_list, CALI_DATA_RE); exit: aw_cali_svc_devs_cali_mode_enable(dev_list, CALI_TYPE_RE, flag, false); return ret; } static int aw_cali_svc_cali_re(struct aw_device *aw_dev, bool is_single, unsigned int flag) { if (is_single) return aw_cali_svc_dev_cali_re(aw_dev, flag); else return aw_cali_svc_devs_cali_re(aw_dev, flag); return 0; } static int aw_cali_svc_dev_cali_f0(struct aw_device *aw_dev, unsigned int flag) { int ret; aw_cali_svc_run_mute(aw_dev, CALI_RESULT_NORMAL); ret = aw_cali_svc_dev_cali_mode_en(aw_dev, CALI_TYPE_F0, true, flag); if (ret < 0) goto exit; /*wait time*/ msleep(5 * 1000); /*dev get cali f0*/ ret = aw_cali_svc_dev_get_f0(aw_dev); exit: aw_cali_svc_dev_cali_mode_en(aw_dev, CALI_TYPE_F0, false, flag); aw_cali_svc_run_mute(aw_dev, aw_dev->cali_desc.cali_result); return ret; } static int aw_cali_svc_devs_cali_f0(struct aw_device *aw_dev, unsigned int flag) { int ret; struct list_head *dev_list = NULL; ret = aw882xx_dev_get_list_head(&dev_list); if (ret) { aw_dev_err(aw_dev->dev, " get dev list failed"); return ret; } ret = aw_cali_svc_devs_cali_mode_enable(dev_list, CALI_TYPE_F0, flag, true); if (ret < 0) goto exit; /*wait time*/ msleep(5 * 1000); ret = aw_cali_svc_devs_get_cali_cali_data(dev_list, CALI_DATA_F0); exit: aw_cali_svc_devs_cali_mode_enable(dev_list, CALI_TYPE_F0, flag, false); return ret; } static int aw_cali_svc_cali_f0(struct aw_device *aw_dev, bool is_single, unsigned int flag) { if (is_single) return aw_cali_svc_dev_cali_f0(aw_dev, flag); else return aw_cali_svc_devs_cali_f0(aw_dev, flag); return 0; } static int aw_cali_svc_dev_cali_f0_q(struct aw_device *aw_dev, unsigned int flag) { int ret; aw_cali_svc_run_mute(aw_dev, CALI_RESULT_NORMAL); ret = aw_cali_svc_dev_cali_mode_en(aw_dev, CALI_TYPE_F0, true, flag); if (ret < 0) goto exit; /*wait time*/ msleep(5 * 1000); /*dev get cali f0 q*/ ret = aw_cali_svc_dev_get_f0_q(aw_dev); exit: aw_cali_svc_dev_cali_mode_en(aw_dev, CALI_TYPE_F0, false, flag); aw_cali_svc_run_mute(aw_dev, aw_dev->cali_desc.cali_result); return ret; } static int aw_cali_svc_devs_cali_f0_q(struct aw_device *aw_dev, unsigned int flag) { int ret; struct list_head *dev_list = NULL; ret = aw882xx_dev_get_list_head(&dev_list); if (ret) { aw_dev_err(aw_dev->dev, "get dev list failed "); return ret; } ret = aw_cali_svc_devs_cali_mode_enable(dev_list, CALI_TYPE_F0, flag, true); if (ret < 0) goto exit; /*wait time*/ msleep(5 * 1000); /*dev get cali f0 q*/ ret = aw_cali_svc_devs_get_cali_cali_data(dev_list, CALI_DATA_F0_Q); exit: aw_cali_svc_devs_cali_mode_enable(dev_list, CALI_TYPE_F0, flag, false); return ret; } static int aw_cali_svc_cali_f0_q(struct aw_device *aw_dev, bool is_single, unsigned int flag) { if (is_single) return aw_cali_svc_dev_cali_f0_q(aw_dev, flag); else return aw_cali_svc_devs_cali_f0_q(aw_dev, flag); return 0; } static int aw_cali_svc_cali_re_f0(struct aw_device *aw_dev, bool is_single, unsigned int flag) { int ret; ret = aw_cali_svc_cali_re(aw_dev, is_single, flag); if (ret) return ret; ret = aw_cali_svc_cali_f0(aw_dev, is_single, flag); if (ret) return ret; return 0; } static int aw_cali_svc_cali_re_f0_q(struct aw_device *aw_dev, bool is_single, unsigned int flag) { int ret; ret = aw_cali_svc_cali_re(aw_dev, is_single, flag); if (ret) return ret; ret = aw_cali_svc_cali_f0_q(aw_dev, is_single, flag); if (ret) return ret; return 0; } static int aw_cali_svc_cali_cmd(struct aw_device *aw_dev, int cali_cmd, bool is_single, unsigned int flag) { switch (cali_cmd) { case AW_CALI_CMD_RE: return aw_cali_svc_cali_re(aw_dev, is_single, flag); case AW_CALI_CMD_F0: return aw_cali_svc_cali_f0(aw_dev, is_single, flag); case AW_CALI_CMD_F0_Q: return aw_cali_svc_cali_f0_q(aw_dev, is_single, flag); case AW_CALI_CMD_RE_F0: return aw_cali_svc_cali_re_f0(aw_dev, is_single, flag); case AW_CALI_CMD_RE_F0_Q: return aw_cali_svc_cali_re_f0_q(aw_dev, is_single, flag); default: aw_dev_err(aw_dev->dev, "unsupported cmd %d", cali_cmd); return -EINVAL; } return 0; } static int aw_cali_svc_get_devs_cali_re(struct aw_device *aw_dev, int32_t *re_buf, int num) { int ret, cnt = 0; struct list_head *dev_list = NULL; struct list_head *pos = NULL; struct aw_device *local_dev = NULL; /* get dev list */ ret = aw882xx_dev_get_list_head(&dev_list); if (ret) { aw_dev_err(aw_dev->dev, "get dev list failed"); return ret; } list_for_each(pos, dev_list) { local_dev = container_of(pos, struct aw_device, list_node); if (local_dev->channel < num) { re_buf[local_dev->channel] = local_dev->cali_desc.cali_re; cnt++; } else { aw_dev_err(aw_dev->dev, "channel num[%d] overflow buf num[%d]", local_dev->channel, num); return -EINVAL; } } return cnt; } static int aw_cali_svc_get_devs_r0(struct aw_device *aw_dev, int32_t *re_buf, int num) { int ret, cnt = 0; struct list_head *dev_list = NULL; struct list_head *pos = NULL; struct aw_device *local_dev = NULL; /* get dev list */ ret = aw882xx_dev_get_list_head(&dev_list); if (ret) { aw_dev_err(aw_dev->dev, "get dev list failed"); return ret; } list_for_each(pos, dev_list) { local_dev = container_of(pos, struct aw_device, list_node); if (local_dev->channel < num) { ret = aw882xx_dsp_read_r0(local_dev, &re_buf[local_dev->channel]); if (ret) { aw_dev_err(local_dev->dev, "get re failed!"); return ret; } cnt++; } else { aw_dev_err(aw_dev->dev, "channel num[%d] overflow buf num[%d] ", local_dev->channel, num); } } return cnt; } static int aw_cali_svc_get_devs_te(struct aw_device *aw_dev, int32_t *te_buf, int num) { int ret, cnt = 0; struct list_head *dev_list = NULL; struct list_head *pos = NULL; struct aw_device *local_dev = NULL; /* get dev list */ ret = aw882xx_dev_get_list_head(&dev_list); if (ret) { aw_dev_err(aw_dev->dev, "get dev list failed"); return ret; } list_for_each(pos, dev_list) { local_dev = container_of(pos, struct aw_device, list_node); if (local_dev->channel < num) { ret = aw882xx_dsp_read_te(local_dev, &te_buf[local_dev->channel]); if (ret) { aw_dev_err(local_dev->dev, "get re failed!"); return ret; } cnt++; } else { aw_dev_err(aw_dev->dev, "channel num[%d] overflow buf num[%d]", local_dev->channel, num); } } return cnt; } static int aw_cali_svc_get_devs_st(struct aw_device *aw_dev, int32_t *st_buf, int num) { int ret, cnt = 0; struct list_head *dev_list = NULL; struct list_head *pos = NULL; struct aw_device *local_dev = NULL; /*get dev list*/ ret = aw882xx_dev_get_list_head(&dev_list); if (ret) { aw_dev_err(aw_dev->dev, "get dev list failed"); return ret; } list_for_each(pos, dev_list) { local_dev = container_of(pos, struct aw_device, list_node); if (local_dev->channel < num) { ret = aw882xx_dsp_read_st(local_dev, &st_buf[local_dev->channel << 1], &st_buf[(local_dev->channel << 1) + 1]); if (ret) { aw_dev_err(local_dev->dev, "get re failed!"); return ret; } cnt++; } else { aw_dev_err(aw_dev->dev, "channel num[%d] overflow buf num[%d]", local_dev->channel, num); } } return cnt; } static int aw_cali_svc_get_devs_cali_f0(struct aw_device *aw_dev, int32_t *f0_buf, int num) { int ret, cnt = 0; struct list_head *dev_list = NULL; struct list_head *pos = NULL; struct aw_device *local_dev = NULL; /*get dev list*/ ret = aw882xx_dev_get_list_head(&dev_list); if (ret) { aw_dev_err(aw_dev->dev, "get dev list failed"); return ret; } list_for_each(pos, dev_list) { local_dev = container_of(pos, struct aw_device, list_node); if (local_dev->channel < num) { f0_buf[local_dev->channel] = local_dev->cali_desc.cali_f0; cnt++; } else { aw_dev_err(aw_dev->dev, "channel num[%d] overflow buf num[%d]", local_dev->channel, num); } } return cnt; } static int aw_cali_svc_get_devs_f0(struct aw_device *aw_dev, int32_t *f0_buf, int num) { int ret, cnt = 0; struct list_head *dev_list = NULL; struct list_head *pos = NULL; struct aw_device *local_dev = NULL; /* get dev list */ ret = aw882xx_dev_get_list_head(&dev_list); if (ret) { aw_dev_err(aw_dev->dev, "get dev list failed"); return ret; } list_for_each(pos, dev_list) { local_dev = container_of(pos, struct aw_device, list_node); if (local_dev->channel < num) { ret = aw882xx_dsp_read_f0(local_dev, &f0_buf[local_dev->channel]); if (ret) { aw_dev_err(local_dev->dev, "get re failed!"); return ret; } cnt++; } else { aw_dev_err(aw_dev->dev, "channel num[%d] overflow buf num[%d]", local_dev->channel, num); } } return cnt; } static int aw_cali_svc_get_devs_cali_f0_q(struct aw_device *aw_dev, int32_t *f0_buf, int32_t *q_buf, int num) { int ret, cnt = 0; struct list_head *dev_list = NULL; struct list_head *pos = NULL; struct aw_device *local_dev = NULL; /*get dev list*/ ret = aw882xx_dev_get_list_head(&dev_list); if (ret) { aw_dev_err(aw_dev->dev, "get dev list failed"); return ret; } list_for_each(pos, dev_list) { local_dev = container_of(pos, struct aw_device, list_node); if (local_dev->channel < num) { f0_buf[local_dev->channel] = local_dev->cali_desc.cali_f0; q_buf[local_dev->channel] = local_dev->cali_desc.cali_q; cnt++; } else { aw_dev_err(aw_dev->dev, "channel num[%d] overflow buf num[%d]", local_dev->channel, num); } } return cnt; } static int aw_cali_svc_set_devs_re_str(struct aw_device *aw_dev, const char *re_str) { int ret, cnt = 0; struct list_head *dev_list, *pos = NULL; struct aw_device *local_dev = NULL; int re_data[AW_DEV_CH_MAX] = {0}; /* get dev list */ ret = aw882xx_dev_get_list_head(&dev_list); if (ret) { aw_dev_err(aw_dev->dev, "get dev list failed"); return ret; } ret = sscanf(re_str, "pri_l:%d pri_r:%d sec_l:%d sec_r:%d tert_l:%d tert_r:%d quat_l:%d quat_r:%d", &re_data[AW_DEV_CH_PRI_L], &re_data[AW_DEV_CH_PRI_R], &re_data[AW_DEV_CH_SEC_L], &re_data[AW_DEV_CH_SEC_R], &re_data[AW_DEV_CH_TERT_L], &re_data[AW_DEV_CH_TERT_R], &re_data[AW_DEV_CH_QUAT_L], &re_data[AW_DEV_CH_QUAT_R]); if (ret <= 0) { aw_dev_err(aw_dev->dev, "unsupport str[%s]", re_str); return -EINVAL; } aw_dev_dbg(aw_dev->dev, "pri_l:%d pri_r:%d sec_l:%d sec_r:%d tert_l:%d tert_r:%d quat_l:%d quat_r:%d", re_data[AW_DEV_CH_PRI_L], re_data[AW_DEV_CH_PRI_R], re_data[AW_DEV_CH_SEC_L], re_data[AW_DEV_CH_SEC_R], re_data[AW_DEV_CH_TERT_L], re_data[AW_DEV_CH_TERT_R], re_data[AW_DEV_CH_QUAT_L], re_data[AW_DEV_CH_QUAT_R]); list_for_each(pos, dev_list) { local_dev = container_of(pos, struct aw_device, list_node); if (local_dev->channel < AW_DEV_CH_MAX) { ret = aw_cali_store_cali_re(local_dev, re_data[local_dev->channel]); if (ret < 0) return ret; cnt++; } } return cnt; } static int aw_cali_svc_get_cmd_form_str(struct aw_device *aw_dev, const char *buf) { int i; for (i = 0; i < CALI_STR_MAX; i++) { if (!strncmp(cali_str[i], buf, strlen(cali_str[i]))) break; } if (i == CALI_STR_MAX) { aw_dev_err(aw_dev->dev, "supported cmd [%s]!", buf); return -EINVAL; } aw_dev_info(aw_dev->dev, "find str [%s]", cali_str[i]); return i; } /*********************************aw_cali_sevice*********************************************************/ /*****************************attr start***************************************************/ static ssize_t cali_time_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret; uint32_t time; struct aw882xx *aw882xx = dev_get_drvdata(dev); struct aw_device *aw_dev = aw882xx->aw_pa; ret = kstrtoint(buf, 0, &time); if (ret < 0) { aw_dev_err(aw_dev->dev, "read buf %s failed\n", buf); return ret; } if (time < 400) { aw_dev_err(aw_dev->dev, "time:%d is too short, no set", time); return -EINVAL; } g_cali_re_time = time; aw_dev_dbg(aw_dev->dev, "time:%d", time); return count; } static ssize_t cali_time_show(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t len = 0; len += snprintf(buf+len, PAGE_SIZE-len, "time: %d\n", g_cali_re_time); return len; } static ssize_t cali_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret; struct aw882xx *aw882xx = dev_get_drvdata(dev); struct aw_device *aw_dev = aw882xx->aw_pa; ret = aw_cali_svc_get_cmd_form_str(aw_dev, buf); if (ret < 0) { aw_dev_err(aw_dev->dev, "supported cmd [%s]!", buf); return -EPERM; } switch (ret) { case CALI_STR_CALI_RE_F0: aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_RE_F0, is_single_cali, CALI_OPS_HMUTE|CALI_OPS_NOISE); return count; case CALI_STR_CALI_RE: aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_RE, is_single_cali, CALI_OPS_HMUTE); return count; case CALI_STR_CALI_F0: aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_F0, is_single_cali, CALI_OPS_NOISE); return count; default: aw_dev_err(aw_dev->dev, "supported cmd [%s]!", buf); return -EPERM; } } static ssize_t cali_re_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret; struct aw882xx *aw882xx = dev_get_drvdata(dev); struct aw_device *aw_dev = aw882xx->aw_pa; int data = 0; if (is_single_cali) { ret = kstrtoint(buf, 0, &data); if (ret < 0) { aw_dev_err(aw882xx->dev, " read buf %s failed", buf); return ret; } ret = aw_cali_store_cali_re(aw_dev, data); if (ret < 0) { aw_dev_err(aw_dev->dev, "set re %d failed", data); return -EPERM; } } else { ret = aw_cali_svc_set_devs_re_str(aw_dev, buf); if (ret <= 0) { aw_dev_err(aw_dev->dev, "set re str %s failed", buf); return -EPERM; } } return count; } static ssize_t cali_re_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret, i; struct aw882xx *aw882xx = dev_get_drvdata(dev); struct aw_device *aw_dev = aw882xx->aw_pa; ssize_t len = 0; int32_t cali_re[AW_DEV_CH_MAX] = {0}; ret = aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_RE, is_single_cali, CALI_OPS_HMUTE); if (ret < 0) { len += snprintf(buf+len, PAGE_SIZE-len, "cali Re cmd failed\n"); return len; } if (is_single_cali) { len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw_dev->cali_desc.cali_re); } else { ret = aw_cali_svc_get_devs_cali_re(aw_dev, cali_re, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(aw_dev->dev, "get re failed "); len += snprintf(buf+len, PAGE_SIZE-len, "get re failed\n"); } else { for (i = 0; i < ret; i++) len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d mOhms ", ch_name[i], cali_re[i]); len += snprintf(buf+len, PAGE_SIZE-len, "\n"); } } return len; } static ssize_t cali_f0_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct aw882xx *aw882xx = dev_get_drvdata(dev); struct aw_device *aw_dev = aw882xx->aw_pa; aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_F0, is_single_cali, CALI_OPS_NOISE); return count; } static ssize_t cali_f0_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret, i; struct aw882xx *aw882xx = dev_get_drvdata(dev); struct aw_device *aw_dev = aw882xx->aw_pa; ssize_t len = 0; int32_t cali_f0[AW_DEV_CH_MAX] = {0}; ret = aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_F0, is_single_cali, CALI_OPS_NOISE); if (ret < 0) { len += snprintf(buf+len, PAGE_SIZE-len, "cali f0 cmd failed\n"); return len; } if (is_single_cali) { len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw_dev->cali_desc.cali_f0); } else { ret = aw_cali_svc_get_devs_cali_f0(aw_dev, cali_f0, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(aw_dev->dev, "get f0 failed "); len += snprintf(buf+len, PAGE_SIZE-len, "get f0 failed\n"); } else { for (i = 0; i < ret; i++) len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d ", ch_name[i], cali_f0[i]); len += snprintf(buf+len, PAGE_SIZE-len, "\n"); } } return len; } static ssize_t re_show_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret, i; struct aw882xx *aw882xx = dev_get_drvdata(dev); struct aw_device *aw_dev = aw882xx->aw_pa; ssize_t len = 0; int32_t cali_re[AW_DEV_CH_MAX] = {0}; if (is_single_cali) { len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw_dev->cali_desc.cali_re); } else { ret = aw_cali_svc_get_devs_cali_re(aw_dev, cali_re, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(aw_dev->dev, "get re failed "); } else { for (i = 0; i < ret; i++) len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d mOhms ", ch_name[i], cali_re[i]); } len += snprintf(buf+len, PAGE_SIZE-len, "\n"); } return len; } static ssize_t f0_show_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret, i; struct aw882xx *aw882xx = dev_get_drvdata(dev); struct aw_device *aw_dev = aw882xx->aw_pa; ssize_t len = 0; int32_t cali_f0[AW_DEV_CH_MAX] = {0}; if (is_single_cali) { len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw_dev->cali_desc.cali_f0); } else { ret = aw_cali_svc_get_devs_cali_f0(aw_dev, cali_f0, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(aw_dev->dev, "get f0 failed"); } else { for (i = 0; i < ret; i++) len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d", ch_name[i], cali_f0[i]); len += snprintf(buf+len, PAGE_SIZE-len, "\n"); } } return len; } static ssize_t re_range_show(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t len = 0; struct aw882xx *aw882xx = dev_get_drvdata(dev); struct aw_device *aw_dev = aw882xx->aw_pa; uint32_t range_buf[RE_RANGE_NUM] = { 0 }; aw_cali_svc_get_dev_re_range(aw_dev, range_buf); len += snprintf(buf + len, PAGE_SIZE - len, "re_min value: [%d] mOhms\n", range_buf[RE_MIN_FLAG]); len += snprintf(buf + len, PAGE_SIZE - len, "re_max value: [%d] mOhms\n", range_buf[RE_MAX_FLAG]); return len; } /*set cali time*/ static DEVICE_ATTR_RW(cali_time); /*start cali*/ static DEVICE_ATTR_WO(cali); /*cali re*/ static DEVICE_ATTR_RW(cali_re); /*cali_f0*/ static DEVICE_ATTR_RW(cali_f0); /*show cali_re*/ static DEVICE_ATTR_RO(re_show); /*show cali_f0*/ static DEVICE_ATTR_RO(f0_show); /*show re_range*/ static DEVICE_ATTR_RO(re_range); static struct attribute *aw_cali_attr[] = { &dev_attr_cali_time.attr, &dev_attr_cali.attr, &dev_attr_cali_re.attr, &dev_attr_cali_f0.attr, &dev_attr_re_show.attr, &dev_attr_f0_show.attr, &dev_attr_re_range.attr, NULL }; static struct attribute_group aw_cali_attr_group = { .attrs = aw_cali_attr }; static void aw_cali_attr_init(struct aw_device *aw_dev) { int ret; aw_dev_info(aw_dev->dev, "enter"); ret = sysfs_create_group(&aw_dev->dev->kobj, &aw_cali_attr_group); if (ret < 0) aw_dev_info(aw_dev->dev, "error creating sysfs cali attr files"); } static void aw_cali_attr_deinit(struct aw_device *aw_dev) { sysfs_remove_group(&aw_dev->dev->kobj, &aw_cali_attr_group); aw_dev_info(aw_dev->dev, "attr files deinit"); } /*****************************attr end***************************************************/ /*****************************class node******************************************************/ static ssize_t aw_cali_class_time_show(struct class *class, struct class_attribute *attr, char *buf) { ssize_t len = 0; len += snprintf(buf+len, PAGE_SIZE-len, "time: %d\n", g_cali_re_time); return len; } static ssize_t aw_cali_class_time_store(struct class *class, struct class_attribute *attr, const char *buf, size_t len) { int ret; uint32_t time; ret = kstrtoint(buf, 0, &time); if (ret < 0) { aw_pr_err("read buf %s failed", buf); return ret; } if (time < 400) { aw_pr_err("time:%d is too short, no set", time); return -EINVAL; } g_cali_re_time = time; aw_pr_dbg("time:%d", time); return len; } static ssize_t aw_cali_class_cali_re_show(struct class *class, struct class_attribute *attr, char *buf) { int ret, i; struct list_head *dev_list = NULL; struct aw_device *local_dev = NULL; ssize_t len = 0; int32_t cali_re[AW_DEV_CH_MAX] = {0}; ret = aw882xx_dev_get_list_head(&dev_list); if (ret) { aw_pr_err("get dev list failed"); return ret; } local_dev = list_first_entry(dev_list, struct aw_device, list_node); ret = aw_cali_svc_cali_cmd(local_dev, AW_CALI_CMD_RE, false, CALI_OPS_HMUTE); if (ret < 0) { len += snprintf(buf+len, PAGE_SIZE-len, "cali Re cmd failed\n"); return len; } ret = aw_cali_svc_get_devs_cali_re(local_dev, cali_re, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(local_dev->dev, "get re failed"); len += snprintf(buf+len, PAGE_SIZE-len, "get re failed\n"); } else { for (i = 0; i < ret; i++) len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d mOhms ", ch_name[i], cali_re[i]); len += snprintf(buf+len, PAGE_SIZE-len, "\n"); } return len; } static ssize_t aw_cali_class_cali_re_store(struct class *class, struct class_attribute *attr, const char *buf, size_t len) { int ret; struct list_head *dev_list = NULL; struct aw_device *local_dev = NULL; ret = aw882xx_dev_get_list_head(&dev_list); if (ret) { aw_pr_err("get dev list failed"); return ret; } local_dev = list_first_entry(dev_list, struct aw_device, list_node); ret = aw_cali_svc_set_devs_re_str(local_dev, buf); if (ret <= 0) { aw_dev_err(local_dev->dev, "set re str %s failed", buf); return -EPERM; } return len; } static ssize_t aw_cali_class_cali_f0_show(struct class *class, struct class_attribute *attr, char *buf) { int ret, i; struct list_head *dev_list = NULL; struct aw_device *local_dev = NULL; ssize_t len = 0; int32_t cali_f0[AW_DEV_CH_MAX] = {0}; ret = aw882xx_dev_get_list_head(&dev_list); if (ret) { aw_pr_err("get dev list failed"); return ret; } local_dev = list_first_entry(dev_list, struct aw_device, list_node); ret = aw_cali_svc_cali_cmd(local_dev, AW_CALI_CMD_F0, false, CALI_OPS_NOISE); if (ret < 0) { len += snprintf(buf+len, PAGE_SIZE-len, "cali f0 cmd failed\n"); return len; } ret = aw_cali_svc_get_devs_cali_f0(local_dev, cali_f0, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(local_dev->dev, "get f0 failed "); len += snprintf(buf+len, PAGE_SIZE-len, "get f0 failed\n"); } else { for (i = 0; i < ret; i++) len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d ", ch_name[i], cali_f0[i]); len += snprintf(buf+len, PAGE_SIZE-len, "\n"); } return len; } static ssize_t aw_cali_class_cali_f0_store(struct class *class, struct class_attribute *attr, const char *buf, size_t len) { int ret; struct list_head *dev_list = NULL; struct aw_device *local_dev = NULL; ret = aw882xx_dev_get_list_head(&dev_list); if (ret) { aw_pr_err("get dev list failed"); return ret; } local_dev = list_first_entry(dev_list, struct aw_device, list_node); aw_cali_svc_cali_cmd(local_dev, AW_CALI_CMD_F0, false, CALI_OPS_NOISE); return len; } static ssize_t aw_cali_class_f0_show(struct class *class, struct class_attribute *attr, char *buf) { int ret, i; struct list_head *dev_list = NULL; struct aw_device *local_dev = NULL; ssize_t len = 0; int32_t cali_f0[AW_DEV_CH_MAX] = {0}; ret = aw882xx_dev_get_list_head(&dev_list); if (ret) { aw_pr_err("get dev list failed"); return ret; } local_dev = list_first_entry(dev_list, struct aw_device, list_node); ret = aw_cali_svc_get_devs_cali_f0(local_dev, cali_f0, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(local_dev->dev, "get re failed"); } else { for (i = 0; i < ret; i++) len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d", ch_name[i], cali_f0[i]); len += snprintf(buf+len, PAGE_SIZE-len, "\n"); } return len; } static ssize_t aw_cali_class_re_show(struct class *class, struct class_attribute *attr, char *buf) { int ret, i; struct list_head *dev_list = NULL; struct aw_device *local_dev = NULL; ssize_t len = 0; int32_t cali_re[AW_DEV_CH_MAX] = {0}; ret = aw882xx_dev_get_list_head(&dev_list); if (ret) { aw_pr_err("get dev list failed"); return ret; } local_dev = list_first_entry(dev_list, struct aw_device, list_node); ret = aw_cali_svc_get_devs_cali_re(local_dev, cali_re, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(local_dev->dev, "get re failed"); } else { for (i = 0; i < ret; i++) len += snprintf(buf+len, PAGE_SIZE-len, "%s:%d mOhms", ch_name[i], cali_re[i]); len += snprintf(buf+len, PAGE_SIZE-len, "\n"); } return len; } static ssize_t aw_class_re_range_show(struct class *class, struct class_attribute *attr, char *buf) { int ret, i; ssize_t len = 0; struct list_head *dev_list = NULL; struct aw_device *local_dev = NULL; uint32_t re_value[AW_DEV_RE_RANGE] = { 0 }; aw_pr_info("enter"); ret = aw882xx_dev_get_list_head(&dev_list); if (ret < 0) { aw_pr_err("get dev list failed"); return ret; } local_dev = list_first_entry(dev_list, struct aw_device, list_node); ret = aw_cali_svc_get_devs_re_range(local_dev, re_value, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(local_dev->dev, "get re range failed"); return -EINVAL; } for (i = 0; i < ret; i++) { len += snprintf(buf+len, PAGE_SIZE-len, "%s:re_min:%d mOhms re_max:%d mOhms ", ch_name[i], re_value[RE_MIN_FLAG + i * RE_RANGE_NUM], re_value[RE_MAX_FLAG + i * RE_RANGE_NUM]); } len += snprintf(buf+len, PAGE_SIZE-len, "\n"); return len; } static struct class_attribute class_attr_cali_time = __ATTR(cali_time, 0644, aw_cali_class_time_show, aw_cali_class_time_store); static struct class_attribute class_attr_re25_calib = __ATTR(re25_calib, 0644, aw_cali_class_cali_re_show, aw_cali_class_cali_re_store); static struct class_attribute class_attr_f0_calib = __ATTR(f0_calib, 0644, aw_cali_class_cali_f0_show, aw_cali_class_cali_f0_store); static struct class_attribute class_attr_re_show = __ATTR(re_show, 0444, aw_cali_class_re_show, NULL); static struct class_attribute class_attr_f0_show = __ATTR(f0_show, 0444, aw_cali_class_f0_show, NULL); static struct class_attribute class_att_re_range = __ATTR(re_range, 0444, aw_class_re_range_show, NULL); static struct class aw_cali_class = { .name = "smartpa", .owner = THIS_MODULE, }; static void aw_cali_class_attr_init(struct aw_device *aw_dev) { int ret; if (aw_dev->channel != 0) { aw_dev_info(aw_dev->dev, "class node already register"); return; } ret = class_register(&aw_cali_class); if (ret < 0) { aw_dev_info(aw_dev->dev, "error creating class node"); return; } ret = class_create_file(&aw_cali_class, &class_attr_re25_calib); if (ret) aw_dev_info(aw_dev->dev, "creat class_attr_re25_calib fail"); ret = class_create_file(&aw_cali_class, &class_attr_f0_calib); if (ret) aw_dev_info(aw_dev->dev, "creat class_attr_re25_calib fail"); ret = class_create_file(&aw_cali_class, &class_attr_cali_time); if (ret) aw_dev_info(aw_dev->dev, "creat class_attr_cali_time fail"); ret = class_create_file(&aw_cali_class, &class_attr_re_show); if (ret) aw_dev_info(aw_dev->dev, "creat class_attr_re_show fail"); ret = class_create_file(&aw_cali_class, &class_attr_f0_show); if (ret) aw_dev_info(aw_dev->dev, "creat class_attr_f0_show fail"); ret = class_create_file(&aw_cali_class, &class_att_re_range); if (ret) aw_dev_err(aw_dev->dev, "creat class_att_re_range fail"); } static void aw_cali_class_attr_deinit(struct aw_device *aw_dev) { class_remove_file(&aw_cali_class, &class_att_re_range); class_remove_file(&aw_cali_class, &class_attr_re25_calib); class_remove_file(&aw_cali_class, &class_attr_f0_calib); class_remove_file(&aw_cali_class, &class_attr_cali_time); class_remove_file(&aw_cali_class, &class_attr_re_show); class_remove_file(&aw_cali_class, &class_attr_f0_show); class_unregister(&aw_cali_class); aw_dev_info(aw_dev->dev, "unregister class node"); } /*****************************class node******************************************************/ /*****************************misc node******************************************************/ static int aw_cali_misc_open(struct inode *inode, struct file *file) { int ret; struct list_head *dev_list = NULL; struct list_head *pos = NULL; struct aw_device *local_dev = NULL; ret = aw882xx_dev_get_list_head(&dev_list); if (ret) { aw_pr_err("get dev list failed"); file->private_data = NULL; return -EINVAL; } /* find select dev */ list_for_each(pos, dev_list) { local_dev = container_of(pos, struct aw_device, list_node); if (local_dev->channel == g_dev_select) break; } if (local_dev == NULL) { aw_pr_err("can't find dev num %d", g_dev_select); return -EINVAL; } /* cannot find sel dev, use list first dev */ if (local_dev->channel != g_dev_select) { local_dev = list_first_entry(dev_list, struct aw_device, list_node); aw_dev_dbg(local_dev->dev, "can not find dev num %d, use default", g_dev_select); } file->private_data = (void *)local_dev; aw_dev_dbg(local_dev->dev, "misc open success"); return 0; } static int aw_cali_misc_release(struct inode *inode, struct file *file) { file->private_data = (void *)NULL; aw_pr_dbg("misc release success"); return 0; } static int aw_cali_misc_params_ptr(struct aw_device *aw_dev, struct ptr_params_data *p_params) { int ret = 0; char *p_data = NULL; if (p_params->data == NULL || (!p_params->len)) { aw_dev_err(aw_dev->dev, "p_params error"); ret = -EFAULT; return ret; } p_data = kzalloc(p_params->len, GFP_KERNEL); if (p_data == NULL) { ret = -ENOMEM; goto exit; } if (copy_from_user(p_data, (void __user *)p_params->data, p_params->len)) { ret = -EFAULT; goto exit; } ret = aw882xx_dsp_write_params(aw_dev, p_data, p_params->len); if (ret < 0) { aw_dev_err(aw_dev->dev, "write params failed "); ret = -EFAULT; goto exit; } exit: if (p_data != NULL) { kfree(p_data); p_data = NULL; } return ret; } static int aw_cali_misc_ops_write(struct aw_device *aw_dev, unsigned int cmd, unsigned long arg) { int ret = 0; unsigned int data_len = _IOC_SIZE(cmd); char *data_ptr = NULL; int32_t data = 0; data_ptr = kzalloc(data_len, GFP_KERNEL); if (!data_ptr) return -ENOMEM; if (copy_from_user(data_ptr, (void __user *)arg, data_len)) { ret = -EFAULT; goto exit; } switch (cmd) { case AW_IOCTL_ENABLE_CALI: { if (aw_dev->cali_desc.cali_check_st) { if (data_ptr[0]) aw_cali_svc_run_mute(aw_dev, CALI_RESULT_NORMAL); else aw_cali_svc_run_mute(aw_dev, aw_dev->cali_desc.cali_result); } aw_cali_svc_set_cali_status(aw_dev, data_ptr[0]); } break; case AW_IOCTL_SET_CALI_CFG: { ret = aw882xx_dsp_write_cali_cfg(aw_dev, data_ptr, data_len); } break; case AW_IOCTL_SET_NOISE: { data = *(int32_t *)data_ptr; ret = aw882xx_dsp_noise_en(aw_dev, data); } break; case AW_IOCTL_SET_VMAX: { ret = aw882xx_dsp_write_vmax(aw_dev, data_ptr, data_len); } break; case AW_IOCTL_SET_PARAM: { ret = aw882xx_dsp_write_params(aw_dev, data_ptr, data_len); } break; case AW_IOCTL_SET_PTR_PARAM_NUM: { ret = aw_cali_misc_params_ptr(aw_dev, (struct ptr_params_data *)data_ptr); } break; case AW_IOCTL_SET_CALI_RE: { ret = aw_cali_store_cali_re(aw_dev, *((int32_t *)data_ptr)); /*ret = aw882xx_dsp_write_cali_re(aw_dev, *(int32_t *)data_ptr);*/ } break; case AW_IOCTL_SET_DSP_HMUTE: { data = *(int32_t *)data_ptr; ret = aw882xx_dsp_hmute_en(aw_dev, data); } break; case AW_IOCTL_SET_CALI_CFG_FLAG: { data = *(int32_t *)data_ptr; /*aw_cali_svc_set_cali_status(aw_dev, data);*/ ret = aw882xx_dsp_cali_en(aw_dev, data); } break; default:{ aw_dev_err(aw_dev->dev, "unsupported cmd %d", cmd); ret = -EINVAL; } break; } exit: kfree(data_ptr); return ret; } static int aw_cali_misc_ops_read(struct aw_device *aw_dev, unsigned int cmd, unsigned long arg) { int ret = 0; int16_t data_len = _IOC_SIZE(cmd); char *data_ptr = NULL; int32_t *data_32_ptr = NULL; data_ptr = kzalloc(data_len, GFP_KERNEL); if (!data_ptr) return -ENOMEM; switch (cmd) { case AW_IOCTL_GET_CALI_CFG: { ret = aw882xx_dsp_read_cali_cfg(aw_dev, data_ptr, data_len); } break; case AW_IOCTL_GET_CALI_DATA: { ret = aw882xx_dsp_read_cali_data(aw_dev, data_ptr, data_len); } break; case AW_IOCTL_GET_F0: { data_32_ptr = (int32_t *)data_ptr; ret = aw882xx_dsp_read_f0(aw_dev, data_32_ptr); } break; case AW_IOCTL_GET_CALI_RE: { data_32_ptr = (int32_t *)data_ptr; ret = aw882xx_dsp_read_cali_re(aw_dev, data_32_ptr); } break; case AW_IOCTL_GET_VMAX: { ret = aw882xx_dsp_read_vmax(aw_dev, data_ptr, data_len); } break; case AW_IOCTL_GET_F0_Q: { data_32_ptr = (int32_t *)data_ptr; ret = aw882xx_dsp_read_f0_q(aw_dev, &data_32_ptr[0], &data_32_ptr[1]); } break; case AW_IOCTL_GET_RE_RANGE: { data_32_ptr = (uint32_t *)data_ptr; ret = aw_cali_svc_get_dev_re_range(aw_dev, data_32_ptr); } break; default:{ aw_dev_err(aw_dev->dev, "unsupported cmd %d", cmd); ret = -EINVAL; } break; } if (copy_to_user((void __user *)arg, data_ptr, data_len)) { ret = -EFAULT; } kfree(data_ptr); return ret; } static int aw_cali_misc_read_dsp(struct aw_device *aw_dev, aw_ioctl_msg_t *msg) { int ret; char __user *user_data = (char __user *)msg->data_buf; uint32_t dsp_msg_id = (uint32_t)msg->opcode_id; int data_len = msg->data_len; char *data_ptr = NULL; data_ptr = kzalloc(data_len, GFP_KERNEL); if (!data_ptr) return -ENOMEM; ret = aw882xx_dsp_read_dsp_msg(aw_dev, dsp_msg_id, data_ptr, data_len); if (ret) { aw_dev_err(aw_dev->dev, " write failed"); goto exit; } if (copy_to_user((void __user *)user_data, data_ptr, data_len)) ret = -EFAULT; exit: kfree(data_ptr); return ret; } static int aw_cali_misc_write_dsp(struct aw_device *aw_dev, aw_ioctl_msg_t *msg) { int ret; char __user *user_data = (char __user *)msg->data_buf; uint32_t dsp_msg_id = (uint32_t)msg->opcode_id; int data_len = msg->data_len; char *data_ptr = NULL; data_ptr = kzalloc(data_len, GFP_KERNEL); if (!data_ptr) return -ENOMEM; if (copy_from_user(data_ptr, (void __user *)user_data, data_len)) { aw_dev_err(aw_dev->dev, "copy data failed"); ret = -EFAULT; goto exit; } ret = aw882xx_dsp_write_dsp_msg(aw_dev, dsp_msg_id, data_ptr, data_len); if (ret) aw_dev_err(aw_dev->dev, "write failed"); exit: kfree(data_ptr); return ret; } static int aw_cali_misc_ops(struct aw_device *aw_dev, unsigned int cmd, unsigned long arg); static int aw_cali_misc_ops_msg(struct aw_device *aw_dev, unsigned long arg) { aw_ioctl_msg_t ioctl_msg; if (copy_from_user(&ioctl_msg, (void __user *)arg, sizeof(aw_ioctl_msg_t))) return -EFAULT; if (ioctl_msg.version != AW_IOCTL_MSG_VERSION) { aw_dev_err(aw_dev->dev, "unsupported msg version %d", ioctl_msg.version); return -EINVAL; } switch (ioctl_msg.type) { case AW_IOCTL_MSG_RD_DSP: return aw_cali_misc_read_dsp(aw_dev, &ioctl_msg); case AW_IOCTL_MSG_WR_DSP: return aw_cali_misc_write_dsp(aw_dev, &ioctl_msg); case AW_IOCTL_MSG_IOCTL: return aw_cali_misc_ops(aw_dev, ioctl_msg.opcode_id, (unsigned long)ioctl_msg.data_buf); default: aw_dev_err(aw_dev->dev, "unsupported msg type %d", ioctl_msg.type); return -EINVAL; } } static int aw_cali_misc_ops(struct aw_device *aw_dev, unsigned int cmd, unsigned long arg) { int ret = 0; switch (cmd) { case AW_IOCTL_ENABLE_CALI: case AW_IOCTL_SET_CALI_CFG: case AW_IOCTL_SET_NOISE: case AW_IOCTL_SET_VMAX: case AW_IOCTL_SET_PARAM: case AW_IOCTL_SET_PTR_PARAM_NUM: case AW_IOCTL_SET_CALI_RE: case AW_IOCTL_SET_DSP_HMUTE: case AW_IOCTL_SET_CALI_CFG_FLAG: ret = aw_cali_misc_ops_write(aw_dev, cmd, arg); break; case AW_IOCTL_GET_CALI_CFG: case AW_IOCTL_GET_CALI_DATA: case AW_IOCTL_GET_F0: case AW_IOCTL_GET_CALI_RE: case AW_IOCTL_GET_VMAX: case AW_IOCTL_GET_F0_Q: case AW_IOCTL_GET_RE_RANGE: ret = aw_cali_misc_ops_read(aw_dev, cmd, arg); break; case AW_IOCTL_MSG: { ret = aw_cali_misc_ops_msg(aw_dev, arg); } break; default: aw_dev_err(aw_dev->dev, "unsupported cmd %d", cmd); ret = -EINVAL; break; } return ret; } static long aw_cali_misc_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = 0; struct aw_device *aw_dev = NULL; if (((_IOC_TYPE(cmd)) != (AW_IOCTL_MAGIC))) { aw_pr_err("cmd magic err"); return -EINVAL; } aw_dev = (struct aw_device *)file->private_data; ret = aw_cali_misc_ops(aw_dev, cmd, arg); if (ret) return -EINVAL; return 0; } #ifdef CONFIG_COMPAT static long aw_cali_misc_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = 0; struct aw_device *aw_dev = NULL; if (((_IOC_TYPE(cmd)) != (AW_IOCTL_MAGIC))) { aw_pr_err("cmd magic err"); return -EINVAL; } aw_dev = (struct aw_device *)file->private_data; ret = aw_cali_misc_ops(aw_dev, cmd, arg); if (ret) return -EINVAL; return 0; } #endif static ssize_t aw_cali_misc_read(struct file *filp, char __user *buf, size_t size, loff_t *pos) { int i, ret; int len = 0; struct aw_device *aw_dev = (struct aw_device *)filp->private_data; char local_buf[256] = { 0 }; unsigned int dev_num; int32_t temp_data[AW_DEV_CH_MAX << 1] = {0}; int32_t temp_data1[AW_DEV_CH_MAX << 1] = {0}; uint32_t re_value[AW_DEV_RE_RANGE] = { 0 }; aw_dev_info(aw_dev->dev, "enter"); if (*pos) { *pos = 0; return 0; } switch (g_msic_wr_flag) { case CALI_STR_SHOW_RE: { ret = aw_cali_svc_get_devs_cali_re(aw_dev, temp_data, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(aw_dev->dev, "get cali_re failed"); return ret; } for (i = 0; i < ret; i++) len += snprintf(local_buf+len, sizeof(local_buf)-len, "%s:%d mOhms ", ch_name[i], temp_data[i]); len += snprintf(local_buf+len, sizeof(local_buf)-len, "\n"); } break; case CALI_STR_SHOW_CALI_F0: { ret = aw_cali_svc_get_devs_cali_f0(aw_dev, temp_data, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(aw_dev->dev, "get cali f0 failed"); return ret; } for (i = 0; i < ret; i++) len += snprintf(local_buf+len, sizeof(local_buf)-len, "%s:%d ", ch_name[i], temp_data[i]); len += snprintf(local_buf+len, sizeof(local_buf)-len, "\n"); } break; case CALI_STR_SHOW_R0: { ret = aw_cali_svc_get_devs_r0(aw_dev, temp_data, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(aw_dev->dev, "get r0 failed"); return ret; } for (i = 0; i < ret; i++) len += snprintf(local_buf+len, sizeof(local_buf)-len, "%s:%d mOhms ", ch_name[i], temp_data[i]); len += snprintf(local_buf+len, sizeof(local_buf)-len, "\n"); } break; case CALI_STR_SHOW_TE: { ret = aw_cali_svc_get_devs_te(aw_dev, temp_data, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(aw_dev->dev, "get te failed"); return ret; } for (i = 0; i < ret; i++) len += snprintf(local_buf+len, sizeof(local_buf)-len, "%s:%d ", ch_name[i], temp_data[i]); len += snprintf(local_buf+len, sizeof(local_buf)-len, "\n"); } break; case CALI_STR_SHOW_ST: { ret = aw_cali_svc_get_devs_st(aw_dev, temp_data, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(aw_dev->dev, "get spkr status failed"); return ret; } for (i = 0; i < ret; i++) { len += snprintf(local_buf+len, sizeof(local_buf)-len, "%s:R0 %d mOhms Te %d ", ch_name[i], temp_data[i << 1], temp_data[(i << 1) + 1]); } len += snprintf(local_buf+len, sizeof(local_buf)-len, "\n"); } break; case CALI_STR_SHOW_F0: { ret = aw_cali_svc_get_devs_f0(aw_dev, temp_data, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(aw_dev->dev, "get f0 failed"); return ret; } for (i = 0; i < ret; i++) len += snprintf(local_buf+len, sizeof(local_buf)-len, "%s:%d ", ch_name[i], temp_data[i]); len += snprintf(local_buf+len, sizeof(local_buf) - len, "\n"); } break; case CALI_STR_VER: { if (aw_dev->ops.aw_get_version) { len = aw_dev->ops.aw_get_version(local_buf, sizeof(local_buf)); if (len < 0) { aw_dev_err(aw_dev->dev, "get version failed"); return -EINVAL; } len += snprintf(local_buf+len, sizeof(local_buf) - len, "\n"); } else { aw_dev_err(aw_dev->dev, "get version is NULL"); return -EINVAL; } } break; case CALI_STR_DEV_NUM: { if (aw_dev->ops.aw_get_dev_num) { dev_num = aw_dev->ops.aw_get_dev_num(); len += snprintf(local_buf + len, sizeof(local_buf) - len, "dev_num:%d\n", dev_num); } else { aw_dev_err(aw_dev->dev, "get dev num is NULL"); return -EINVAL; } break; } case CALI_STR_SHOW_F0_Q: { ret = aw_cali_svc_get_devs_cali_f0_q(aw_dev, temp_data, temp_data1, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(aw_dev->dev, "get q f0 failed"); return ret; } for (i = 0; i < ret; i++) len += snprintf(local_buf + len, sizeof(local_buf)-len, "%s:f0:%d q:%d", ch_name[i], temp_data[i], temp_data1[i]); len += snprintf(local_buf+len, sizeof(local_buf) - len, "\n"); } break; case CALI_STR_SHOW_RE_RANGE: { ret = aw_cali_svc_get_devs_re_range(aw_dev, re_value, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(aw_dev->dev, "get re range failed"); return -EINVAL; } for (i = 0; i < ret; i++) len += snprintf(local_buf + len, sizeof(local_buf) - len, "%s:re_min:%d re_max:%d ", ch_name[i], re_value[RE_MIN_FLAG + i * RE_RANGE_NUM], re_value[RE_MAX_FLAG + i * RE_RANGE_NUM]); len += snprintf(local_buf + len, sizeof(local_buf) - len, "\n"); } break; default: { if (g_msic_wr_flag == CALI_STR_NONE) { aw_dev_info(aw_dev->dev, "please write cmd first"); return -EINVAL; } aw_dev_err(aw_dev->dev, "unsupported flag [%d]", g_msic_wr_flag); g_msic_wr_flag = CALI_STR_NONE; return -EINVAL; } break; } if (copy_to_user((void __user *)buf, local_buf, len)) { aw_dev_err(aw_dev->dev, "copy_to_user error"); g_msic_wr_flag = CALI_STR_NONE; return -EFAULT; } g_msic_wr_flag = CALI_STR_NONE; *pos += len; return len; } static int aw_cali_misc_switch_dev(struct file *filp, struct aw_device *aw_dev, char *cmd_buf) { int ret; int i; char dev_select[50] = { 0 }; struct list_head *dev_list = NULL; struct list_head *pos = NULL; struct aw_device *local_dev = NULL; /* get sel dev str */ ret = sscanf(cmd_buf, "dev_sel:%s", dev_select); if (ret <= 0) return -EINVAL; for (i = 0; i < AW_DEV_CH_MAX; i++) { if (strnstr(dev_select, ch_name[i], strlen(ch_name[i]))) break; } if (i == AW_DEV_CH_MAX) { aw_dev_err(aw_dev->dev, "unsupport dev [%s]", dev_select); return -EINVAL; } /* get dev list */ ret = aw882xx_dev_get_list_head(&dev_list); if (ret) { aw_dev_err(aw_dev->dev, "get dev list failed "); return ret; } /* find sel dev */ list_for_each(pos, dev_list) { local_dev = container_of(pos, struct aw_device, list_node); if (local_dev->channel == i) { filp->private_data = (void *)local_dev; g_dev_select = i; aw_dev_info(local_dev->dev, "switch dev to [%s]", ch_name[i]); return 0; } } aw_dev_err(aw_dev->dev, " unsupport [%s]", dev_select); return -EINVAL; } static ssize_t aw_cali_misc_write(struct file *filp, const char __user *buf, size_t size, loff_t *pos) { int ret = 0; char *kernel_buf = NULL; struct aw_device *aw_dev = (struct aw_device *)filp->private_data; aw_dev_info(aw_dev->dev, "enter, write size:%d", (int)size); kernel_buf = kzalloc(size + 1, GFP_KERNEL); if (kernel_buf == NULL) return -ENOMEM; if (copy_from_user(kernel_buf, (void __user *)buf, size)) { ret = -EFAULT; goto exit; } ret = aw_cali_svc_get_cmd_form_str(aw_dev, kernel_buf); if (ret < 0) { aw_dev_err(aw_dev->dev, "upported cmd [%s]! ", kernel_buf); ret = -EINVAL; goto exit; } switch (ret) { case CALI_STR_CALI_RE_F0: { ret = aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_RE_F0, is_single_cali, CALI_OPS_HMUTE|CALI_OPS_NOISE); } break; case CALI_STR_CALI_RE: { ret = aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_RE, is_single_cali, CALI_OPS_HMUTE); } break; case CALI_STR_CALI_F0: { ret = aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_F0, is_single_cali, CALI_OPS_HMUTE|CALI_OPS_NOISE); } break; case CALI_STR_SET_RE: { /*skip store_re*/ kernel_buf[size] = '\0'; ret = aw_cali_svc_set_devs_re_str(aw_dev, kernel_buf + strlen(cali_str[CALI_STR_SET_RE]) + 1); } break; case CALI_STR_DEV_SEL: { ret = aw_cali_misc_switch_dev(filp, aw_dev, kernel_buf); } break; case CALI_STR_CALI_F0_Q: { ret = aw_cali_svc_cali_cmd(aw_dev, AW_CALI_CMD_F0_Q, is_single_cali, CALI_OPS_HMUTE|CALI_OPS_NOISE); } break; case CALI_STR_SHOW_RE: /*show cali_re*/ case CALI_STR_SHOW_R0: /*show real r0*/ case CALI_STR_SHOW_CALI_F0: /*GET DEV CALI_F0*/ case CALI_STR_SHOW_F0: /*SHOW REAL F0*/ case CALI_STR_SHOW_TE: case CALI_STR_SHOW_ST: case CALI_STR_VER: case CALI_STR_DEV_NUM: case CALI_STR_SHOW_F0_Q: case CALI_STR_SHOW_RE_RANGE:{ g_msic_wr_flag = ret; ret = 0; } break; default: { aw_dev_err(aw_dev->dev, "unsupported [%s]! ", kernel_buf); ret = -EINVAL; } break; }; exit: aw_dev_info(aw_dev->dev, "cmd [%s]! ", kernel_buf); kfree(kernel_buf); kernel_buf = NULL; if (ret < 0) return -EINVAL; else return size; } static const struct file_operations aw_cali_misc_fops = { .owner = THIS_MODULE, .open = aw_cali_misc_open, .read = aw_cali_misc_read, .write = aw_cali_misc_write, .release = aw_cali_misc_release, .unlocked_ioctl = aw_cali_misc_unlocked_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = aw_cali_misc_compat_ioctl, #endif }; static struct miscdevice misc_cali = { .name = "aw882xx_smartpa", .minor = MISC_DYNAMIC_MINOR, .fops = &aw_cali_misc_fops, }; static int aw_cali_misc_init(struct aw_device *aw_dev) { int ret; mutex_lock(&g_cali_lock); if (g_misc_dev == NULL) { ret = misc_register(&misc_cali); if (ret) { aw_dev_err(aw_dev->dev, "misc register fail: %d\n", ret); mutex_unlock(&g_cali_lock); return -EINVAL; } g_misc_dev = &misc_cali; aw_dev_dbg(aw_dev->dev, "misc register success"); } else { aw_dev_dbg(aw_dev->dev, "misc already register"); } mutex_unlock(&g_cali_lock); return 0; } static void aw_cali_misc_deinit(struct aw_device *aw_dev) { mutex_lock(&g_cali_lock); if (g_misc_dev) { misc_deregister(g_misc_dev); g_misc_dev = NULL; } mutex_unlock(&g_cali_lock); aw_dev_dbg(aw_dev->dev, " misc unregister done"); } /*****************************misc node******************************************************/ static void aw_cali_parse_dt(struct aw_device *aw_dev) { int ret = -1; struct device_node *np = aw_dev->dev->of_node; const char *cali_mode_str = NULL; uint32_t cali_check = CALI_CHECK_DISABLE; struct aw_cali_desc *desc = &aw_dev->cali_desc; ret = of_property_read_u32(np, "aw-cali-check", &cali_check); if (ret < 0) { aw_dev_info(aw_dev->dev, "cali-check get failed ,default turn off"); cali_check = CALI_CHECK_DISABLE; } desc->cali_check_st = cali_check; aw_dev_info(aw_dev->dev, "cali check :%s", (desc->cali_check_st) ? "enable" : "disable"); ret = of_property_read_string(np, "aw-cali-mode", &cali_mode_str); if (ret < 0) { desc->mode = AW_CALI_MODE_ALL; aw_dev_info(aw_dev->dev, "cali function in use"); return; } if (!strcmp(cali_mode_str, "none")) desc->mode = AW_CALI_MODE_NONE; else desc->mode = AW_CALI_MODE_ALL; aw_dev_info(aw_dev->dev, "cali mode is %d", desc->mode); } static int aw_cali_parse_re_dt(struct aw_device *aw_dev) { int ret; ret = of_property_read_u32(aw_dev->dev->of_node, "aw-re-min", &aw_dev->re_min); if (ret < 0) { aw_dev->re_min = AW_CALI_RE_DEFAULT_MIN; aw_dev_info(aw_dev->dev, "read aw-re-min failed, use default"); } ret = of_property_read_u32(aw_dev->dev->of_node, "aw-re-max", &aw_dev->re_max); if (ret < 0) { aw_dev->re_max = AW_CALI_RE_DEFAULT_MAX; aw_dev_info(aw_dev->dev, "read aw-re-max failed, use default"); } if (aw_dev->re_min >= aw_dev->re_max) { aw_dev_err(aw_dev->dev, "re max must be greater than re min"); return -EINVAL; } aw_dev_info(aw_dev->dev, "re min: %d, re max: %d", aw_dev->re_min, aw_dev->re_max); return 0; } int aw882xx_cali_init(struct aw_cali_desc *cali_desc) { int ret; struct aw_device *aw_dev = container_of(cali_desc, struct aw_device, cali_desc); cali_desc->cali_f0 = 0; cali_desc->cali_re = 0; cali_desc->cali_q = 0; cali_desc->status = 0; aw_cali_parse_dt(aw_dev); if (cali_desc->mode == AW_CALI_MODE_ALL) { aw_cali_attr_init(aw_dev); aw_cali_class_attr_init(aw_dev); } else { aw_dev_info(aw_dev->dev, "cali mode is %d", cali_desc->mode); } aw_cali_misc_init(aw_dev); ret = aw_cali_parse_re_dt(aw_dev); cali_desc->cali_result = CALI_RESULT_NONE; return ret; } void aw882xx_cali_deinit(struct aw_cali_desc *cali_desc) { struct aw_device *aw_dev = container_of(cali_desc, struct aw_device, cali_desc); if (cali_desc->mode == AW_CALI_MODE_ALL) { aw_cali_attr_deinit(aw_dev); aw_cali_class_attr_deinit(aw_dev); } aw_cali_misc_deinit(aw_dev); }