// SPDX-License-Identifier: GPL-2.0+ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "aw_device.h" #include "aw_log.h" #include "aw_calib.h" #include "aw883xx.h" static bool is_single_cali; /*if mutli_dev cali false, single dev true*/ static unsigned int g_cali_re_time = AW_CALI_RE_DEFAULT_TIMER; static unsigned int g_dev_select; static struct miscdevice *g_misc_dev; static unsigned int g_msic_wr_flag = CALI_STR_NONE; static DEFINE_MUTEX(g_cali_lock); 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", "dev_sel", "get_ver", "get_re_range" }; /******************************cali re store example start***********************************/ #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; mm_segment_t fs; fp = filp_open(AWINIC_CALI_FILE, O_RDWR | O_CREAT, 0644); if (IS_ERR(fp)) { aw_pr_err("channel:%d open %s failed!", channel, AWINIC_CALI_FILE); return -EINVAL; } pos = AW_INT_DEC_DIGIT * channel; snprintf(buf, sizeof(buf), "%10d", cali_re); fs = get_fs(); set_fs(KERNEL_DS); aw_fs_write(fp, buf, strlen(buf), &pos); set_fs(fs); 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_cali_re_from_file(int32_t *cali_re, int channel) { struct file *fp = NULL; int f_size; char *buf = NULL; int32_t int_cali_re = 0; loff_t pos = 0; mm_segment_t fs; fp = filp_open(AWINIC_CALI_FILE, O_RDONLY, 0); if (IS_ERR(fp)) { aw_pr_err("channel:%d open %s failed!", channel, AWINIC_CALI_FILE); return -EINVAL; } pos = AW_INT_DEC_DIGIT * channel; f_size = AW_INT_DEC_DIGIT; buf = kzalloc(f_size + 1, GFP_ATOMIC); if (!buf) { aw_pr_err("channel:%d malloc mem %d failed!", channel, f_size); filp_close(fp, NULL); return -EINVAL; } fs = get_fs(); set_fs(KERNEL_DS); aw_fs_read(fp, buf, f_size, &pos); set_fs(fs); if (sscanf(buf, "%d", &int_cali_re) == 1) *cali_re = int_cali_re; else *cali_re = AW_ERRO_CALI_RE_VALUE; 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 /********************cali re store example end*****************************/ /*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 return aw_cali_write_cali_re_to_file(cali_re, channel); #else return 0; #endif } static int aw_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 return aw_cali_get_cali_re_from_file(cali_re, channel); #else return 0; #endif } static void aw_run_mute_for_cali(struct aw_device *aw_dev, int8_t cali_result) { struct aw_mute_desc *mute_desc = &aw_dev->mute_desc; aw_dev_dbg(aw_dev->dev, "enter"); if (aw_dev->cali_desc.cali_check_st) { if (cali_result == CALI_RESULT_ERROR) { aw_dev->ops.aw_reg_write_bits(aw_dev, mute_desc->reg, mute_desc->mask, mute_desc->enable); } else if (cali_result == CALI_RESULT_NORMAL) { aw_dev->ops.aw_reg_write_bits(aw_dev, mute_desc->reg, mute_desc->mask, mute_desc->disable); } } 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_range.re_min; data_buf[RE_MAX_FLAG] = aw_dev->re_range.re_max; return 0; } static int aw_cali_svc_get_devs_re_range(struct aw_device *aw_dev, uint32_t *data_buf, int num) { struct list_head *dev_list = NULL; struct list_head *pos = NULL; struct aw_device *local_dev = NULL; int ret, cnt = 0; /*get dev list*/ ret = aw_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) { data_buf[RE_MIN_FLAG + local_dev->channel * 2] = local_dev->re_range.re_min; data_buf[RE_MAX_FLAG + local_dev->channel * 2] = local_dev->re_range.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; if ((re > aw_dev->re_range.re_min) && (re < aw_dev->re_range.re_max)) { aw_dev->cali_desc.cali_re = re; ret = aw_cali_write_re_to_nvram(re, aw_dev->channel); if (ret < 0) { aw_dev_err(aw_dev->dev, "write re to nvram failed!"); return ret; } } else { aw_dev_err(aw_dev->dev, "invalid cali re %d!", re); return -EINVAL; } return 0; } int aw_cali_get_cali_re(struct aw_cali_desc *cali_desc) { int ret; int32_t cali_re = 0; struct aw_device *aw_dev = container_of(cali_desc, struct aw_device, cali_desc); ret = aw_cali_read_re_from_nvram(&cali_re, aw_dev->channel); if (ret < 0) { cali_desc->cali_re = AW_ERRO_CALI_RE_VALUE; cali_desc->cali_result = CALI_RESULT_NONE; aw_dev_err(aw_dev->dev, "get re failed"); return ret; } if (cali_re < aw_dev->re_range.re_min || cali_re > aw_dev->re_range.re_max) { aw_dev_err(aw_dev->dev, "out range re value: %d", cali_re); cali_desc->cali_re = AW_ERRO_CALI_RE_VALUE; /*cali_result is error when aw-cali-check enable*/ if (aw_dev->cali_desc.cali_check_st) { cali_desc->cali_result = CALI_RESULT_ERROR; } return -EINVAL; } cali_desc->cali_re = cali_re; /*cali_result is normal when aw-cali-check enable*/ if (aw_dev->cali_desc.cali_check_st) { cali_desc->cali_result = CALI_RESULT_NORMAL; } aw_dev_info(aw_dev->dev, "get cali re %d", cali_desc->cali_re); return 0; } int aw_cali_read_cali_re_from_dsp(struct aw_cali_desc *cali_desc, uint32_t *re) { struct aw_device *aw_dev = container_of(cali_desc, struct aw_device, cali_desc); struct aw_adpz_re_desc *desc = &aw_dev->adpz_re_desc; int ret; ret = aw_dev->ops.aw_dsp_read(aw_dev, desc->dsp_reg, re, desc->data_type); if (ret < 0) { aw_dev_err(aw_dev->dev, "set cali re error"); return ret; } *re = AW_DSP_RE_TO_SHOW_RE(*re, desc->shift); *re -= aw_dev->cali_desc.ra; aw_dev_info(aw_dev->dev, "get dsp re:%d", *re); return 0; } /*************Calibration base function************/ int aw_cali_svc_set_cali_re_to_dsp(struct aw_cali_desc *cali_desc) { struct aw_device *aw_dev = container_of(cali_desc, struct aw_device, cali_desc); struct aw_adpz_re_desc *adpz_re_desc = &aw_dev->adpz_re_desc; uint32_t cali_re = 0; int ret; cali_re = AW_SHOW_RE_TO_DSP_RE((aw_dev->cali_desc.cali_re + aw_dev->cali_desc.ra), adpz_re_desc->shift); /* set cali re to aw883xx */ ret = aw_dev->ops.aw_dsp_write(aw_dev, adpz_re_desc->dsp_reg, cali_re, adpz_re_desc->data_type); if (ret < 0) { aw_dev_err(aw_dev->dev, "set cali re error"); return ret; } ret = aw_dev_modify_dsp_cfg(aw_dev, adpz_re_desc->dsp_reg, cali_re, adpz_re_desc->data_type); if (ret < 0) { aw_dev_err(aw_dev->dev, "modify dsp cfg failed"); return ret; } return 0; } int aw_cali_svc_get_ra(struct aw_cali_desc *cali_desc) { int ret; uint32_t dsp_ra; struct aw_device *aw_dev = container_of(cali_desc, struct aw_device, cali_desc); struct aw_ra_desc *desc = &aw_dev->ra_desc; ret = aw_dev->ops.aw_dsp_read(aw_dev, desc->dsp_reg, &dsp_ra, desc->data_type); if (ret < 0) { aw_dev_err(aw_dev->dev, "read ra error"); return ret; } cali_desc->ra = AW_DSP_RE_TO_SHOW_RE(dsp_ra, aw_dev->adpz_re_desc.shift); aw_dev_info(aw_dev->dev, "get ra:%d", cali_desc->ra); return 0; } static int aw_cali_svc_get_dev_realtime_re(struct aw_device *aw_dev, uint32_t *re) { int ret; struct aw_adpz_re_desc *re_desc = &aw_dev->adpz_re_desc; struct aw_ra_desc *ra_desc = &aw_dev->ra_desc; struct aw_adpz_t0_desc *t0_desc = &aw_dev->t0_desc; uint32_t dsp_re = 0; uint32_t show_re = 0; uint32_t re_cacl = 0; uint32_t ra = 0; uint32_t t0 = 0; int32_t te = 0; int32_t te_cacl = 0; uint32_t coil_alpha = 0; uint16_t pst_rpt = 0; ret = aw_dev->ops.aw_dsp_read(aw_dev, re_desc->dsp_reg, &dsp_re, re_desc->data_type); if (ret < 0) { aw_dev_err(aw_dev->dev, "dsp read re error"); return ret; } ret = aw_dev->ops.aw_dsp_read(aw_dev, ra_desc->dsp_reg, &ra, ra_desc->data_type); if (ret < 0) { aw_dev_err(aw_dev->dev, "dsp read ra error"); return ret; } re_cacl = dsp_re - ra; ret = aw_dev->ops.aw_dsp_read(aw_dev, t0_desc->dsp_reg, &t0, t0_desc->data_type); if (ret < 0) { aw_dev_err(aw_dev->dev, "dsp read t0 error"); return ret; } ret = aw_dev->ops.aw_dsp_read(aw_dev, t0_desc->coilalpha_reg, &coil_alpha, t0_desc->coil_type); if (ret < 0) { aw_dev_err(aw_dev->dev, "dsp read coil_alpha error"); return ret; } ret = aw_dev->ops.aw_reg_read(aw_dev, aw_dev->spkr_temp_desc.reg, &pst_rpt); if (ret < 0) { aw_dev_err(aw_dev->dev, "reg read pst_rpt error"); return ret; } te = (int32_t)((uint32_t)pst_rpt - t0); te_cacl = AW_TE_CACL_VALUE(te, (uint16_t)coil_alpha); show_re = AW_RE_REALTIME_VALUE((int32_t)re_cacl, te_cacl); *re = AW_DSP_RE_TO_SHOW_RE(show_re, re_desc->shift); aw_dev_dbg(aw_dev->dev, "real_r0:[%d]", *re); return 0; } static int aw_cali_svc_get_dev_re(struct aw_device *aw_dev, uint32_t *re) { int ret; struct aw_ste_re_desc *desc = &aw_dev->ste_re_desc; uint32_t dsp_re = 0; uint32_t show_re = 0; ret = aw_dev->ops.aw_dsp_read(aw_dev, desc->dsp_reg, &dsp_re, desc->data_type); if (ret < 0) { aw_dev_err(aw_dev->dev, "dsp read re error"); return ret; } show_re = AW_DSP_RE_TO_SHOW_RE(dsp_re, aw_dev->ste_re_desc.shift); *re = show_re - aw_dev->cali_desc.ra; aw_dev_dbg(aw_dev->dev, "real_r0:[%d]", *re); return 0; } static int aw_cali_svc_get_devs_r0(struct aw_device *aw_dev, int32_t *r0_buf, int num) { struct list_head *dev_list = NULL; struct list_head *pos = NULL; struct aw_device *local_dev = NULL; int ret, cnt = 0; //get dev list ret = aw_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 = aw_cali_svc_get_dev_realtime_re(local_dev, &r0_buf[local_dev->channel]); if (ret) { aw_dev_err(local_dev->dev, "get r0 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_dev_f0(struct aw_device *aw_dev, uint32_t *f0) { struct aw_f0_desc *f0_desc = &aw_dev->f0_desc; uint32_t dsp_val = 0; int ret; ret = aw_dev->ops.aw_dsp_read(aw_dev, f0_desc->dsp_reg, &dsp_val, f0_desc->data_type); if (ret < 0) { aw_dev_err(aw_dev->dev, "read f0 failed"); return ret; } *f0 = dsp_val >> f0_desc->shift; aw_dev_dbg(aw_dev->dev, "real_f0:[%d]", *f0); return 0; } static int aw_cali_svc_get_devs_f0(struct aw_device *aw_dev, int32_t *f0_buf, int num) { struct list_head *dev_list = NULL; struct list_head *pos = NULL; struct aw_device *local_dev = NULL; int ret, cnt = 0; //get dev list ret = aw_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 = aw_cali_svc_get_dev_f0(local_dev, &f0_buf[local_dev->channel]); if (ret) { aw_dev_err(local_dev->dev, "get f0 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_dev_q(struct aw_device *aw_dev, uint32_t *q) { struct aw_q_desc *q_desc = &aw_dev->q_desc; uint32_t dsp_val = 0; int ret; ret = aw_dev->ops.aw_dsp_read(aw_dev, q_desc->dsp_reg, &dsp_val, q_desc->data_type); if (ret < 0) { aw_dev_err(aw_dev->dev, "read q failed"); return ret; } *q = ((dsp_val * 1000) >> q_desc->shift); return 0; } int aw_cali_svc_get_dev_te(struct aw_cali_desc *cali_desc, int32_t *te) { struct aw_device *aw_dev = container_of(cali_desc, struct aw_device, cali_desc); uint16_t reg_val = 0; int ret; ret = aw_dev->ops.aw_reg_read(aw_dev, aw_dev->spkr_temp_desc.reg, ®_val); if (ret < 0) { aw_dev_err(aw_dev->dev, "read temperature failed"); return ret; } *te = (int32_t)((int16_t)reg_val); aw_dev_info(aw_dev->dev, "real_te:[%d]", *te); return 0; } static int aw_cali_svc_get_devs_te(struct aw_device *aw_dev, int32_t *te_buf, int num) { struct list_head *dev_list = NULL; struct list_head *pos = NULL; struct aw_device *local_dev = NULL; int ret, cnt = 0; //get dev list ret = aw_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 = aw_cali_svc_get_dev_te(&local_dev->cali_desc, &te_buf[local_dev->channel]); if (ret) { aw_dev_err(local_dev->dev, "get temperature 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 void aw_cali_svc_bubble_sort(uint32_t *data, int data_size) { int loop_num = data_size - 1; uint16_t temp_store = 0; int i; int j; if (data == NULL) { aw_pr_err("data is NULL"); return; } for (i = 0; i < loop_num; i++) { for (j = 0; j < loop_num - i; j++) { if (data[j] > data[j + 1]) { temp_store = data[j]; data[j] = data[j + 1]; data[j + 1] = temp_store; } } } } static int aw_cali_svc_del_max_min_ave_algo(uint32_t *data, int data_size) { int sum = 0; int ave = 0; int i = 0; aw_cali_svc_bubble_sort(data, data_size); for (i = 1; i < data_size - 1; i++) sum += data[i]; if ((data_size - AW_CALI_DATA_SUM_RM) == 0) { aw_pr_err("data_size id :%d less than 2", data_size); return -EINVAL; } ave = sum / (data_size - AW_CALI_DATA_SUM_RM); return ave; } static void aw_cali_svc_set_cali_status(struct aw_device *aw_dev, bool status) { aw_dev->cali_desc.status = status; if (status) aw_monitor_stop(&aw_dev->monitor_desc); else aw_monitor_start(&aw_dev->monitor_desc); aw_dev_info(aw_dev->dev, "cali %s", (status == 0) ? ("disable") : ("enable")); } bool aw_cali_svc_get_cali_status(struct aw_cali_desc *cali_desc) { return cali_desc->status; } static int aw_cali_svc_cali_init_check(struct aw_device *aw_dev) { int ret; aw_dev_dbg(aw_dev->dev, "enter"); ret = aw_dev_sysst_check(aw_dev); if (ret < 0) { aw_dev_err(aw_dev->dev, "syst_check failed"); return ret; } ret = aw_dev_get_dsp_status(aw_dev); if (ret < 0) { aw_dev_err(aw_dev->dev, "dsp status error"); return ret; } ret = aw_dev_get_hmute(aw_dev); if (ret == 1) { aw_dev_err(aw_dev->dev, "mute staus"); return -EINVAL; } return 0; } static int aw_cali_svc_get_cali_cfg(struct aw_device *aw_dev) { int ret; struct aw_cali_cfg_desc *desc = &aw_dev->cali_cfg_desc; struct cali_cfg *cali_cfg = &aw_dev->cali_desc.cali_cfg; aw_dev_dbg(aw_dev->dev, "enter"); ret = aw_dev->ops.aw_dsp_read(aw_dev, desc->actampth_reg, &cali_cfg->data[0], desc->actampth_data_type); if (ret < 0) { aw_dev_err(aw_dev->dev, "dsp read reg0x%x error", desc->actampth_reg); return ret; } ret = aw_dev->ops.aw_dsp_read(aw_dev, desc->noiseampth_reg, &cali_cfg->data[1], desc->noiseampth_data_type); if (ret < 0) { aw_dev_err(aw_dev->dev, "dsp read reg0x%x error", desc->noiseampth_reg); return ret; } ret = aw_dev->ops.aw_dsp_read(aw_dev, desc->ustepn_reg, &cali_cfg->data[2], desc->ustepn_data_type); if (ret < 0) { aw_dev_err(aw_dev->dev, "dsp read reg0x%x error", desc->ustepn_reg); return ret; } ret = aw_dev->ops.aw_dsp_read(aw_dev, desc->alphan_reg, &cali_cfg->data[3], desc->alphan_data_type); if (ret < 0) { aw_dev_err(aw_dev->dev, "dsp read reg0x%x error", desc->alphan_reg); return ret; } return 0; } static int aw_cali_svc_set_cali_cfg(struct aw_device *aw_dev, struct cali_cfg cali_cfg) { int ret; struct aw_cali_cfg_desc *desc = &aw_dev->cali_cfg_desc; aw_dev_dbg(aw_dev->dev, "enter"); ret = aw_dev->ops.aw_dsp_write(aw_dev, desc->actampth_reg, cali_cfg.data[0], desc->actampth_data_type); if (ret < 0) { aw_dev_err(aw_dev->dev, "dsp write reg0x%x error", desc->actampth_reg); return ret; } ret = aw_dev->ops.aw_dsp_write(aw_dev, desc->noiseampth_reg, cali_cfg.data[1], desc->noiseampth_data_type); if (ret < 0) { aw_dev_err(aw_dev->dev, "dsp write reg0x%x error", desc->noiseampth_reg); return ret; } ret = aw_dev->ops.aw_dsp_write(aw_dev, desc->ustepn_reg, cali_cfg.data[2], desc->ustepn_data_type); if (ret < 0) { aw_dev_err(aw_dev->dev, "dsp write reg0x%x error", desc->ustepn_reg); return ret; } ret = aw_dev->ops.aw_dsp_write(aw_dev, desc->alphan_reg, cali_cfg.data[3], desc->alphan_data_type); if (ret < 0) { aw_dev_err(aw_dev->dev, "dsp write reg0x%x error", desc->alphan_reg); return ret; } return 0; } static int aw_cali_svc_get_smooth_cali_re(struct aw_device *aw_dev) { int ret = 0; int i = 0; uint32_t re_temp[AW_CALI_READ_CNT_MAX] = { 0 }; uint32_t dsp_re; aw_dev_dbg(aw_dev->dev, "enter"); for (i = 0; i < AW_CALI_READ_CNT_MAX; i++) { ret = aw_cali_svc_get_dev_re(aw_dev, &re_temp[i]); if (ret < 0) goto cali_re_fail; msleep(30);/*delay 30 ms*/ } dsp_re = aw_cali_svc_del_max_min_ave_algo(re_temp, AW_CALI_READ_CNT_MAX); if (aw_dev->ops.aw_cali_svc_get_iv_st) { ret = aw_dev->ops.aw_cali_svc_get_iv_st(aw_dev); if (ret < 0) { aw_dev_err(aw_dev->dev, "get iv data failed"); goto cali_re_fail; } } if (dsp_re < aw_dev->re_range.re_min || dsp_re > aw_dev->re_range.re_max) { aw_dev_err(aw_dev->dev, "out range re value: [%d]mohm", dsp_re); aw_dev->cali_desc.cali_re = dsp_re; if (aw_dev->cali_desc.cali_check_st) { aw_dev->cali_desc.cali_result = CALI_RESULT_ERROR; ret = aw_cali_write_re_to_nvram(dsp_re, aw_dev->channel); if (ret < 0) { aw_dev_err(aw_dev->dev, "write re failed"); } } aw_run_mute_for_cali(aw_dev, aw_dev->cali_desc.cali_result); return 0; } ret = aw_cali_write_re_to_nvram(dsp_re, aw_dev->channel); if (ret < 0) { aw_dev_err(aw_dev->dev, "write re failed"); goto cali_re_fail; } if (aw_dev->cali_desc.cali_check_st) aw_dev->cali_desc.cali_result = CALI_RESULT_NORMAL; aw_dev->cali_desc.cali_re = dsp_re; aw_dev_info(aw_dev->dev, "re[%d]mohm", aw_dev->cali_desc.cali_re); aw_dev_dsp_enable(aw_dev, false); aw_cali_svc_set_cali_re_to_dsp(&aw_dev->cali_desc); aw_dev_dsp_enable(aw_dev, true); return 0; cali_re_fail: if (aw_dev->cali_desc.cali_check_st) aw_dev->cali_desc.cali_result = CALI_RESULT_ERROR; aw_run_mute_for_cali(aw_dev, aw_dev->cali_desc.cali_result); return -EINVAL; } static int aw_cali_svc_cali_en(struct aw_device *aw_dev, bool cali_en) { int ret = 0; struct cali_cfg set_cfg; aw_dev_info(aw_dev->dev, "cali_en:%d", cali_en); aw_dev_dsp_enable(aw_dev, false); if (cali_en) { ret = aw_cali_svc_get_cali_cfg(aw_dev); if (ret < 0) { aw_dev_err(aw_dev->dev, "get cali cfg failed"); aw_dev_dsp_enable(aw_dev, true); return ret; } set_cfg.data[0] = 0; set_cfg.data[1] = 0; set_cfg.data[2] = -1; set_cfg.data[3] = 1; ret = aw_cali_svc_set_cali_cfg(aw_dev, set_cfg); if (ret < 0) { aw_dev_err(aw_dev->dev, "set cali cfg failed"); aw_cali_svc_set_cali_cfg(aw_dev, aw_dev->cali_desc.cali_cfg); aw_dev_dsp_enable(aw_dev, true); return ret; } } else { aw_cali_svc_set_cali_cfg(aw_dev, aw_dev->cali_desc.cali_cfg); } aw_dev_dsp_enable(aw_dev, true); return 0; } static int aw_cali_svc_cali_run_dsp_vol(struct aw_device *aw_dev, int type, bool enable) { int ret; uint16_t reg_val = 0; uint16_t set_vol = 0; struct aw_dsp_vol_desc *desc = &aw_dev->dsp_vol_desc; aw_dev_info(aw_dev->dev, "type:%d, enable:%d", type, enable); if (enable) { /*set dsp vol*/ if (type == CALI_TYPE_RE) { set_vol = desc->mute_st; } else if (type == CALI_TYPE_F0) { set_vol = desc->noise_st; } else { aw_dev_err(aw_dev->dev, "type:%d unsupported", type); return -EINVAL; } ret = aw_dev->ops.aw_reg_read(aw_dev, desc->reg, ®_val); if (ret < 0) { aw_dev_err(aw_dev->dev, "read reg 0x%x failed", desc->reg); return ret; } aw_dev->cali_desc.store_vol = reg_val & (~desc->mask); reg_val &= desc->mask; reg_val |= set_vol; ret = aw_dev->ops.aw_reg_write(aw_dev, desc->reg, reg_val); if (ret < 0) { aw_dev_err(aw_dev->dev, "write reg 0x%x failed", desc->reg); return ret; } } else { /*reset dsp vol*/ ret = aw_dev->ops.aw_reg_read(aw_dev, desc->reg, ®_val); if (ret < 0) { aw_dev_err(aw_dev->dev, "read reg 0x%x failed", desc->reg); return ret; } reg_val &= desc->mask; reg_val |= aw_dev->cali_desc.store_vol; ret = aw_dev->ops.aw_reg_write(aw_dev, desc->reg, reg_val); if (ret < 0) { aw_dev_err(aw_dev->dev, "write reg 0x%x failed", desc->reg); return ret; } } return 0; } static int aw_cali_svc_set_white_noise(struct aw_device *aw_dev, bool noise_enable) { int ret; uint32_t reg_val; struct aw_noise_desc *desc = &aw_dev->noise_desc; aw_dev_info(aw_dev->dev, "set noise %s", (noise_enable == 0) ? ("disable") : ("enable")); ret = aw_dev->ops.aw_dsp_read(aw_dev, desc->dsp_reg, ®_val, desc->data_type); if (ret < 0) { aw_dev_err(aw_dev->dev, "read dsp reg 0x%x failed", desc->dsp_reg); return ret; } if (noise_enable) reg_val |= (~desc->mask); else reg_val &= desc->mask; ret = aw_dev->ops.aw_dsp_write(aw_dev, desc->dsp_reg, reg_val, desc->data_type); if (ret < 0) { aw_dev_err(aw_dev->dev, "write dsp reg 0x%x failed", desc->dsp_reg); return ret; } return 0; } static int aw_cali_svc_cali_f0_en(struct aw_device *aw_dev, bool f0_enable) { int ret; struct aw_cali_delay_desc *desc = &aw_dev->cali_delay_desc; aw_dev_info(aw_dev->dev, "cali f0 %s", (f0_enable == 0) ? ("disable") : ("enable")); if (f0_enable) { ret = aw_cali_svc_cali_run_dsp_vol(aw_dev, CALI_TYPE_F0, true); if (ret < 0) { aw_dev_err(aw_dev->dev, "run dsp volume error, ret=%d", ret); return ret; } msleep(desc->delay); ret = aw_cali_svc_set_white_noise(aw_dev, true); if (ret < 0) { aw_dev_err(aw_dev->dev, "write white noise error, ret=%d", ret); aw_cali_svc_cali_run_dsp_vol(aw_dev, CALI_TYPE_F0, false); return ret; } } else { aw_cali_svc_set_white_noise(aw_dev, false); aw_cali_svc_cali_run_dsp_vol(aw_dev, CALI_TYPE_F0, false); } return 0; } static int aw_cali_svc_get_cali_f0_q(struct aw_device *aw_dev) { int ret = -1; int cnt = 0; uint32_t f0 = 0; uint32_t q = 0; uint32_t f0_sum = 0; uint32_t q_sum = 0; struct aw_cali_desc *cali_desc = &aw_dev->cali_desc; aw_dev_dbg(aw_dev->dev, "enter"); for (cnt = 0; cnt < F0_READ_CNT_MAX; cnt++) { /*f0*/ ret = aw_cali_svc_get_dev_f0(aw_dev, &f0); if (ret < 0) return ret; f0_sum += f0; /*q*/ ret = aw_cali_svc_get_dev_q(aw_dev, &q); if (ret < 0) return ret; q_sum += q; msleep(30); } cali_desc->f0 = f0_sum / cnt; cali_desc->q = q_sum / cnt; if (aw_dev->ops.aw_cali_svc_get_iv_st) { ret = aw_dev->ops.aw_cali_svc_get_iv_st(aw_dev); if (ret < 0) { aw_dev_err(aw_dev->dev, "get iv data failed, set default f0: 2600 q: 2600"); cali_desc->f0 = 2600; cali_desc->q = 2600; } } aw_dev_info(aw_dev->dev, "f0[%d] q[%d]", cali_desc->f0, cali_desc->q); return 0; } static int aw_cali_svc_cali_mode_enable(struct aw_device *aw_dev, int type, unsigned int flag, bool is_enable) { int ret = 0; aw_dev_info(aw_dev->dev, "type:%d, flag:0x%x, is_enable:%d", type, flag, is_enable); if (is_enable) { ret = aw_cali_svc_cali_init_check(aw_dev); if (ret < 0) { aw_dev_err(aw_dev->dev, "init check failed"); return ret; } aw_cali_svc_set_cali_status(aw_dev, true); ret = aw_cali_svc_cali_en(aw_dev, true); if (ret < 0) { aw_cali_svc_set_cali_status(aw_dev, false); return ret; } if ((type == CALI_TYPE_RE) && (flag & CALI_OPS_HMUTE)) { ret = aw_cali_svc_cali_run_dsp_vol(aw_dev, CALI_TYPE_RE, true); if (ret < 0) { aw_cali_svc_cali_en(aw_dev, false); aw_cali_svc_set_cali_status(aw_dev, false); return ret; } } else if ((type == CALI_TYPE_F0) && (flag & CALI_OPS_NOISE)) { ret = aw_cali_svc_cali_f0_en(aw_dev, true); if (ret < 0) { aw_cali_svc_cali_en(aw_dev, false); aw_cali_svc_set_cali_status(aw_dev, false); return ret; } } } else { if ((type == CALI_TYPE_RE) && (flag & CALI_OPS_HMUTE)) aw_cali_svc_cali_run_dsp_vol(aw_dev, CALI_TYPE_RE, false); else if ((type == CALI_TYPE_F0) && (flag & CALI_OPS_NOISE)) aw_cali_svc_cali_f0_en(aw_dev, false); aw_cali_svc_cali_en(aw_dev, false); aw_dev_clear_int_status(aw_dev); aw_cali_svc_set_cali_status(aw_dev, false); } return 0; } static int aw_cali_svc_devs_cali_mode_enable(struct list_head *dev_list, int type, unsigned int flag, bool is_enable) { int ret = 0; 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_run_mute_for_cali(local_dev, CALI_RESULT_NORMAL); ret = aw_cali_svc_cali_mode_enable(local_dev, type, flag, is_enable); if (ret < 0) return ret; if (!is_enable && (type == CALI_TYPE_F0)) aw_run_mute_for_cali(local_dev, local_dev->cali_desc.cali_result); } return ret; } static int aw_cali_svc_dev_cali_re(struct aw_device *aw_dev, unsigned int flag) { int ret = 0; aw_dev_info(aw_dev->dev, "enter"); aw_run_mute_for_cali(aw_dev, CALI_RESULT_NORMAL); ret = aw_cali_svc_cali_mode_enable(aw_dev, CALI_TYPE_RE, flag, true); if (ret < 0) return ret; msleep(g_cali_re_time); ret = aw_cali_svc_get_smooth_cali_re(aw_dev); if (ret < 0) aw_dev_err(aw_dev->dev, "cali re failed"); aw_cali_svc_cali_mode_enable(aw_dev, CALI_TYPE_RE, flag, false); return ret; } static int aw_cali_svc_devs_get_cali_re(struct list_head *dev_list) { int ret = 0; 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); ret = aw_cali_svc_get_smooth_cali_re(local_dev); if (ret < 0) { aw_dev_err(local_dev->dev, "get re failed"); return ret; } } return ret; } static int aw_cali_svc_devs_cali_re(struct aw_device *aw_dev, unsigned int flag) { int ret = 0; struct list_head *dev_list = NULL; aw_dev_info(aw_dev->dev, "enter"); ret = aw_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 error; msleep(g_cali_re_time); ret = aw_cali_svc_devs_get_cali_re(dev_list); if (ret < 0) goto error; aw_cali_svc_devs_cali_mode_enable(dev_list, CALI_TYPE_RE, flag, false); return 0; error: 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); } static int aw_cali_svc_set_devs_re_str(struct aw_device *aw_dev, const char *re_str) { struct list_head *dev_list = NULL, *pos = NULL; struct aw_device *local_dev = NULL; int ret, cnt = 0; int re_data[AW_DEV_CH_MAX] = { 0 }; char str_data[32] = { 0 }; int i, len = 0; int dev_num = 0; /*get dev list*/ ret = aw_dev_get_list_head(&dev_list); if (ret < 0) { aw_dev_err(aw_dev->dev, "get dev list failed"); return ret; } dev_num = aw_dev->ops.aw_get_dev_num(); for (i = 0 ; i < dev_num; i++) { memset(str_data, 0, sizeof(str_data)); snprintf(str_data, sizeof(str_data), "dev[%d]:%s ", i, "%d"); ret = sscanf(re_str + len, str_data, &re_data[i]); if (ret <= 0) { aw_dev_err(aw_dev->dev, "unsupported str: %s", re_str); return -EINVAL; } len += snprintf(str_data, sizeof(str_data), "dev[%d]:%d ", i, re_data[i]); if (len > strlen(re_str)) { aw_dev_err(aw_dev->dev, "%s: unsupported", re_str); return -EINVAL; } } 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) { aw_dev_err(local_dev->dev, "store cali re failed"); return ret; } cnt++; } } return cnt; } static int aw_cali_svc_dev_cali_f0_q(struct aw_device *aw_dev, unsigned int flag) { int ret; aw_run_mute_for_cali(aw_dev, CALI_RESULT_NORMAL); ret = aw_cali_svc_cali_mode_enable(aw_dev, CALI_TYPE_F0, flag, true); if (ret < 0) return ret; msleep(AW_CALI_F0_TIME); ret = aw_cali_svc_get_cali_f0_q(aw_dev); if (ret < 0) aw_dev_err(aw_dev->dev, "get f0 q failed"); aw_cali_svc_cali_mode_enable(aw_dev, CALI_TYPE_F0, flag, false); aw_run_mute_for_cali(aw_dev, aw_dev->cali_desc.cali_result); return ret; } static int aw_cali_svc_devs_get_cali_f0_q(struct list_head *dev_list) { int ret = 0; 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); ret = aw_cali_svc_get_cali_f0_q(local_dev); if (ret < 0) { aw_dev_err(local_dev->dev, "get f0 q failed"); return ret; } } 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 = aw_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 error; msleep(AW_CALI_F0_TIME); ret = aw_cali_svc_devs_get_cali_f0_q(dev_list); if (ret < 0) goto error; aw_cali_svc_devs_cali_mode_enable(dev_list, CALI_TYPE_F0, flag, false); return 0; error: 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); } static int aw_cali_svc_get_dev_cali_val(struct aw_device *aw_dev, int type, uint32_t *data_buf) { switch (type) { case GET_RE_TYPE: *data_buf = aw_dev->cali_desc.cali_re; break; case GET_F0_TYPE: *data_buf = aw_dev->cali_desc.f0; break; case GET_Q_TYPE: *data_buf = aw_dev->cali_desc.q; break; default: aw_dev_err(aw_dev->dev, "type:%d not support", type); return -EINVAL; } return 0; } static int aw_cali_svc_get_devs_cali_val(struct aw_device *aw_dev, int type, uint32_t *data_buf, int num) { struct list_head *dev_list = NULL; struct list_head *pos = NULL; struct aw_device *local_dev = NULL; int ret, cnt = 0; /*get dev list*/ ret = aw_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) { switch (type) { case GET_RE_TYPE: data_buf[local_dev->channel] = local_dev->cali_desc.cali_re; break; case GET_F0_TYPE: data_buf[local_dev->channel] = local_dev->cali_desc.f0; break; case GET_Q_TYPE: data_buf[local_dev->channel] = local_dev->cali_desc.q; break; default: aw_dev_err(local_dev->dev, "type:%d not support", type); return -EINVAL; } 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_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 < 0) return ret; ret = aw_cali_svc_cali_f0_q(aw_dev, is_single, flag); if (ret < 0) 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); } break; case AW_CALI_CMD_F0: case AW_CALI_CMD_F0_Q: { return aw_cali_svc_cali_f0_q(aw_dev, is_single, flag); } break; case AW_CALI_CMD_RE_F0: 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_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_dbg(aw_dev->dev, "find str [%s]", cali_str[i]); return i; } /*****************************attr cali***************************************************/ static ssize_t aw_cali_attr_time_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret; uint32_t time; struct aw883xx *aw883xx = dev_get_drvdata(dev); struct aw_device *aw_dev = aw883xx->aw_pa; ret = kstrtoint(buf, 0, &time); if (ret < 0) { aw_dev_err(aw_dev->dev, "read buf %s failed", buf); return ret; } if (time < 1000) { 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:%u", time); return count; } static ssize_t aw_cali_attr_time_show(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t len = 0; len += snprintf(buf+len, PAGE_SIZE-len, "time: %u\n", g_cali_re_time); return len; } static ssize_t aw_cali_attr_re_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct aw883xx *aw883xx = dev_get_drvdata(dev); struct aw_device *aw_dev = aw883xx->aw_pa; int ret; int re; if (is_single_cali) { ret = kstrtoint(buf, 0, &re); if (ret < 0) { aw_dev_err(aw_dev->dev, "read buf %s failed", buf); return ret; } ret = aw_cali_store_cali_re(aw_dev, re); if (ret < 0) { aw_dev_err(aw_dev->dev, "store cali re failed!"); return ret; } } else { ret = aw_cali_svc_set_devs_re_str(aw_dev, buf); if (ret <= 0) { aw_pr_err("set re str %s failed", buf); return -EPERM; } } return count; } static ssize_t aw_cali_attr_re_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret, i; struct aw883xx *aw883xx = dev_get_drvdata(dev); struct aw_device *aw_dev = aw883xx->aw_pa; ssize_t len = 0; int32_t re[AW_DEV_CH_MAX] = { 0 }; ret = aw_cali_svc_cali_re(aw_dev, is_single_cali, CALI_OPS_HMUTE); if (ret < 0) { aw_dev_err(aw_dev->dev, "cali re failed"); return ret; } if (is_single_cali) { len += snprintf(buf+len, PAGE_SIZE-len, "dev[%d]: %umOhms \n", aw_dev->channel, aw_dev->cali_desc.cali_re); } else { ret = aw_cali_svc_get_devs_cali_val(aw_dev, GET_RE_TYPE, 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, "dev[%d]: %umOhms ", i, re[i]); len += snprintf(buf+len, PAGE_SIZE-len, " \n"); } } return len; } static ssize_t aw_cali_attr_f0_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret, i; struct aw883xx *aw883xx = dev_get_drvdata(dev); struct aw_device *aw_dev = aw883xx->aw_pa; ssize_t len = 0; uint32_t f0[AW_DEV_CH_MAX] = { 0 }; ret = aw_cali_svc_cali_f0_q(aw_dev, is_single_cali, CALI_OPS_NOISE); if (ret < 0) { aw_dev_err(aw_dev->dev, "cali f0 failed"); return ret; } if (is_single_cali) { len += snprintf(buf+len, PAGE_SIZE-len, "dev[%d]:%u Hz\n", aw_dev->channel, aw_dev->cali_desc.f0); } else { ret = aw_cali_svc_get_devs_cali_val(aw_dev, GET_F0_TYPE, f0, 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, "dev[%d]:%u Hz ", i, f0[i]); len += snprintf(buf+len, PAGE_SIZE-len, " \n"); } } return len; } static ssize_t aw_cali_attr_f0_q_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret, i; struct aw883xx *aw883xx = dev_get_drvdata(dev); struct aw_device *aw_dev = aw883xx->aw_pa; ssize_t len = 0; uint32_t f0[AW_DEV_CH_MAX] = { 0 }; uint32_t q[AW_DEV_CH_MAX] = { 0 }; ret = aw_cali_svc_cali_f0_q(aw_dev, is_single_cali, CALI_OPS_NOISE); if (ret < 0) { aw_dev_err(aw_dev->dev, "cali f0 q failed"); return ret; } if (is_single_cali) { len += snprintf(buf+len, PAGE_SIZE-len, "dev[%d]f0:%u Hz q:%u\n", aw_dev->channel, aw_dev->cali_desc.f0, aw_dev->cali_desc.q); } else { ret = aw_cali_svc_get_devs_cali_val(aw_dev, GET_F0_TYPE, f0, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(aw_dev->dev, "get f0 failed"); return -EINVAL; } ret = aw_cali_svc_get_devs_cali_val(aw_dev, GET_Q_TYPE, q, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(aw_dev->dev, "get q failed"); return -EINVAL; } for (i = 0; i < ret; i++) len += snprintf(buf+len, PAGE_SIZE-len, "dev[%d]:f0:%u Hz q:%u ", i, f0[i], q[i]); len += snprintf(buf+len, PAGE_SIZE-len, " \n"); } return len; } static ssize_t aw_re_range_show(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t len = 0; struct aw883xx *aw883xx = dev_get_drvdata(dev); struct aw_device *aw_dev = aw883xx->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]\n", range_buf[RE_MIN_FLAG]); len += snprintf(buf + len, PAGE_SIZE - len, "re_max value: [%d]\n", range_buf[RE_MAX_FLAG]); return len; } static DEVICE_ATTR(cali_time, S_IWUSR | S_IRUGO, aw_cali_attr_time_show, aw_cali_attr_time_store); static DEVICE_ATTR(cali_re, S_IRUGO | S_IWUSR, aw_cali_attr_re_show, aw_cali_attr_re_store); static DEVICE_ATTR(cali_f0, S_IRUGO, aw_cali_attr_f0_show, NULL); static DEVICE_ATTR(cali_f0_q, S_IRUGO, aw_cali_attr_f0_q_show, NULL); static DEVICE_ATTR(re_range, S_IRUGO, aw_re_range_show, NULL); static struct attribute *aw_cali_attr[] = { &dev_attr_cali_time.attr, &dev_attr_cali_re.attr, &dev_attr_cali_f0.attr, &dev_attr_cali_f0_q.attr, &dev_attr_re_range.attr, NULL }; static struct attribute_group aw_cali_attr_group = { .attrs = aw_cali_attr, NULL }; static void aw_cali_attr_init(struct aw_device *aw_dev) { int ret; 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"); } /*****************************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 < 1000) { 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) { struct list_head *dev_list; struct aw_device *local_dev; int ret, i; ssize_t len = 0; uint32_t cali_re[AW_DEV_CH_MAX] = { 0 }; aw_pr_info("enter"); ret = aw_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_re(local_dev, false, CALI_OPS_HMUTE); if (ret < 0) return ret; ret = aw_cali_svc_get_devs_cali_val(local_dev, GET_RE_TYPE, 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, "dev[%d]:%u mOhms ", 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) { struct list_head *dev_list = NULL; struct aw_device *local_dev = NULL; int ret; ret = aw_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_pr_err("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) { struct list_head *dev_list = NULL; struct aw_device *local_dev = NULL; int ret = -1; int i = 0; ssize_t len = 0; uint32_t f0[AW_DEV_CH_MAX] = { 0 }; aw_pr_info("enter"); ret = aw_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_cali_f0_q(local_dev, is_single_cali, CALI_OPS_NOISE); if (ret < 0) { aw_pr_err("cali f0 failed"); return ret; } ret = aw_cali_svc_get_devs_cali_val(local_dev, GET_F0_TYPE, f0, AW_DEV_CH_MAX); if (ret <= 0) { aw_pr_err("get f0 failed"); } else { for (i = 0; i < ret; i++) len += snprintf(buf+len, PAGE_SIZE-len, "dev[%d]:%u Hz ", i, f0[i]); len += snprintf(buf+len, PAGE_SIZE-len, " \n"); } return len; } static ssize_t aw_cali_class_cali_f0_q_show(struct class *class, struct class_attribute *attr, char *buf) { struct list_head *dev_list = NULL; struct aw_device *local_dev = NULL; int ret, i; ssize_t len = 0; uint32_t f0[AW_DEV_CH_MAX] = { 0 }; uint32_t q[AW_DEV_CH_MAX] = { 0 }; aw_pr_info("enter"); ret = aw_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_cali_f0_q(local_dev, is_single_cali, CALI_OPS_NOISE); if (ret < 0) { aw_dev_err(local_dev->dev, "cali f0 q failed"); return ret; } ret = aw_cali_svc_get_devs_cali_val(local_dev, GET_F0_TYPE, f0, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(local_dev->dev, "get f0 failed"); return -EINVAL; } ret = aw_cali_svc_get_devs_cali_val(local_dev, GET_Q_TYPE, q, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(local_dev->dev, "get q failed"); return -EINVAL; } for (i = 0; i < ret; i++) len += snprintf(buf+len, PAGE_SIZE-len, "dev[%d]:f0:%u Hz q:%u ", i, f0[i], q[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 = aw_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, "dev[%d]:re_min:%d re_max:%d ", 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, S_IWUSR | S_IRUGO, \ aw_cali_class_time_show, aw_cali_class_time_store); static struct class_attribute class_attr_re25_calib = \ __ATTR(re25_calib, S_IWUSR | S_IRUGO, \ aw_cali_class_cali_re_show, aw_cali_class_cali_re_store); static struct class_attribute class_attr_f0_calib = \ __ATTR(f0_calib, S_IRUGO, \ aw_cali_class_cali_f0_show, NULL); static struct class_attribute class_attr_f0_q_calib = \ __ATTR(f0_q_calib, S_IRUGO, \ aw_cali_class_cali_f0_q_show, NULL); static struct class_attribute class_att_re_range = \ __ATTR(re_range, S_IRUGO, \ 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_err(aw_dev->dev, "class node already register"); return; } ret = class_register(&aw_cali_class); if (ret < 0) { aw_dev_err(aw_dev->dev, "error creating class node"); return; } ret = class_create_file(&aw_cali_class, &class_attr_cali_time); if (ret) aw_dev_err(aw_dev->dev, "creat class_attr_cali_time fail"); ret = class_create_file(&aw_cali_class, &class_attr_re25_calib); if (ret) aw_dev_err(aw_dev->dev, "creat class_attr_re25_calib fail"); ret = class_create_file(&aw_cali_class, &class_attr_f0_calib); if (ret) aw_dev_err(aw_dev->dev, "creat class_attr_f0_calib fail"); ret = class_create_file(&aw_cali_class, &class_attr_f0_q_calib); if (ret) aw_dev_err(aw_dev->dev, "creat class_attr_f0_q_calib 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_f0_q_calib); class_remove_file(&aw_cali_class, &class_attr_f0_calib); class_remove_file(&aw_cali_class, &class_attr_re25_calib); class_remove_file(&aw_cali_class, &class_attr_cali_time); class_unregister(&aw_cali_class); aw_dev_info(aw_dev->dev, "unregister class node"); } /*****************************class node******************************************************/ /*****************************misc cali******************************************************/ static int aw_cali_misc_open(struct inode *inode, struct file *file) { struct list_head *dev_list = NULL; struct list_head *pos = NULL; struct aw_device *local_dev = NULL; int ret; aw_pr_dbg("misc open success"); ret = aw_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("get dev failed"); 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[%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_ops_write(struct aw_device *aw_dev, unsigned int cmd, unsigned long arg) { unsigned int data_len = _IOC_SIZE(cmd); char *data_ptr = NULL; int ret = 0; data_ptr = devm_kzalloc(aw_dev->dev, data_len, GFP_KERNEL); if (!data_ptr) { aw_dev_err(aw_dev->dev, "malloc failed !"); return -ENOMEM; } if (copy_from_user(data_ptr, (void __user *)arg, data_len)) { ret = -EFAULT; goto exit; } switch (cmd) { case AW_IOCTL_SET_CALI_RE: { aw_cali_store_cali_re(aw_dev, *((int32_t *)data_ptr)); } break; default:{ aw_dev_err(aw_dev->dev, "unsupported cmd %d", cmd); ret = -EINVAL; } break; } exit: devm_kfree(aw_dev->dev, data_ptr); data_ptr = NULL; return ret; } static int aw_cali_misc_ops_read(struct aw_device *aw_dev, unsigned int cmd, unsigned long arg) { int16_t data_len = _IOC_SIZE(cmd); char *data_ptr = NULL; int32_t *data_32_ptr = NULL; int ret = 0; data_ptr = devm_kzalloc(aw_dev->dev, data_len, GFP_KERNEL); if (!data_ptr) { aw_dev_err(aw_dev->dev, "malloc failed !"); return -ENOMEM; } data_32_ptr = (int32_t *)data_ptr; switch (cmd) { case AW_IOCTL_GET_RE: { ret = aw_cali_svc_dev_cali_re(aw_dev, CALI_OPS_HMUTE); if (ret < 0) goto exit; ret = aw_cali_svc_get_dev_cali_val(aw_dev, GET_RE_TYPE, data_32_ptr); } break; case AW_IOCTL_GET_CALI_F0: { ret = aw_cali_svc_dev_cali_f0_q(aw_dev, CALI_OPS_NOISE); if (ret < 0) goto exit; ret = aw_cali_svc_get_dev_cali_val(aw_dev, GET_F0_TYPE, data_32_ptr); } break; case AW_IOCTL_GET_F0: { ret = aw_cali_svc_get_dev_f0(aw_dev, data_32_ptr); } break; case AW_IOCTL_GET_TE: { ret = aw_cali_svc_get_dev_te(&aw_dev->cali_desc, data_32_ptr); } break; case AW_IOCTL_GET_REAL_R0: { ret = aw_cali_svc_get_dev_realtime_re(aw_dev, data_32_ptr); } break; case AW_IOCTL_GET_RE_RANGE: { 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; } exit: if (copy_to_user((void __user *)arg, data_ptr, data_len)) { ret = -EFAULT; } devm_kfree(aw_dev->dev, data_ptr); data_ptr = NULL; return ret; } 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_SET_CALI_RE: return aw_cali_misc_ops_write(aw_dev, cmd, arg); case AW_IOCTL_GET_F0: case AW_IOCTL_GET_CALI_F0: case AW_IOCTL_GET_RE: case AW_IOCTL_GET_REAL_R0: case AW_IOCTL_GET_TE: case AW_IOCTL_GET_RE_RANGE: return aw_cali_misc_ops_read(aw_dev, cmd, arg); 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 < 0) 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 < 0) 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 len = 0; int i, ret; struct aw_device *aw_dev = (struct aw_device *)filp->private_data; char local_buf[512] = { 0 }; uint32_t temp_data[AW_DEV_CH_MAX] = { 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_val(aw_dev, GET_RE_TYPE, temp_data, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(aw_dev->dev, "get re failed"); return -EINVAL; } else { for (i = 0; i < ret; i++) len += snprintf(local_buf+len, sizeof(local_buf) - len, "dev[%d]:%u ", 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 -EINVAL; } else { for (i = 0; i < ret; i++) len += snprintf(local_buf+len, sizeof(local_buf)-len, "dev[%d]:%d ", 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_val(aw_dev, GET_F0_TYPE, temp_data, AW_DEV_CH_MAX); if (ret <= 0) { aw_dev_err(aw_dev->dev, "get cali f0 failed"); return -EINVAL; } else { for (i = 0; i < ret; i++) len += snprintf(local_buf+len, sizeof(local_buf)-len, "dev[%d]:%d ", i, temp_data[i]); 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 -EINVAL; } else { for (i = 0; i < ret; i++) len += snprintf(local_buf+len, sizeof(local_buf)-len, "dev[%d]:%d ", 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 -EINVAL; } else { for (i = 0; i < ret; i++) len += snprintf(local_buf+len, sizeof(local_buf)-len, "dev[%d]:%d ", 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_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; } else { for (i = 0; i < ret; i++) { len += snprintf(local_buf+len, sizeof(local_buf)-len, "dev[%d]:re_min:%d re_max:%d\n", i, re_value[RE_MIN_FLAG + i * RE_RANGE_NUM], re_value[RE_MAX_FLAG + i * RE_RANGE_NUM]); } } } break; default: { if (g_msic_wr_flag == CALI_STR_NONE) { aw_dev_info(aw_dev->dev, "please write cmd first"); return -EINVAL; } else { 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 dev_select_num; struct list_head *dev_list = NULL; struct list_head *pos = NULL; struct aw_device *local_dev = NULL; int ret; /*get sel dev str*/ sscanf(cmd_buf, "dev_sel:dev[%d]", &dev_select_num); if (dev_select_num >= AW_DEV_CH_MAX) { aw_dev_err(aw_dev->dev, "unsupport str [%s]", cmd_buf); return -EINVAL; } /*get dev list*/ ret = aw_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 == dev_select_num) { filp->private_data = (void *)local_dev; g_dev_select = dev_select_num; aw_dev_info(local_dev->dev, "switch to dev[%d]", dev_select_num); return 0; } } aw_dev_err(aw_dev->dev, " unsupport [%s]", cmd_buf); return -EINVAL; } static ssize_t aw_cali_misc_write(struct file *filp, const char __user *buf, size_t size, loff_t *pos) { char *kernel_buf = NULL; struct aw_device *aw_dev = (struct aw_device *)filp->private_data; int ret = 0; aw_dev_info(aw_dev->dev, "enter, write size:%d", (int)size); kernel_buf = kzalloc(size + 1, GFP_KERNEL); if (kernel_buf == NULL) { aw_dev_err(aw_dev->dev, "kzalloc failed !"); 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*/ 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_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_VER: 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_dbg(aw_dev->dev, "cmd [%s]!", kernel_buf); if (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 }; struct miscdevice misc_cali = { .name = "aw_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 cali******************************************************/ static void aw_cali_parse_dt(struct aw_device *aw_dev) { struct device_node *np = aw_dev->dev->of_node; int ret = -1; 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"); } void aw_cali_init(struct aw_cali_desc *cali_desc) { struct aw_device *aw_dev = container_of(cali_desc, struct aw_device, cali_desc); memset(cali_desc, 0, sizeof(struct aw_cali_desc)); aw_cali_parse_dt(aw_dev); aw_cali_attr_init(aw_dev); aw_cali_class_attr_init(aw_dev); aw_cali_misc_init(aw_dev); cali_desc->cali_result = CALI_RESULT_NONE; } void aw_cali_deinit(struct aw_cali_desc *cali_desc) { struct aw_device *aw_dev = container_of(cali_desc, struct aw_device, cali_desc); aw_cali_attr_deinit(aw_dev); aw_cali_class_attr_deinit(aw_dev); aw_cali_misc_deinit(aw_dev); }