diff --git a/drivers/misc/awinic/aw862x/Android.mk b/drivers/misc/awinic/aw862x/Android.mk new file mode 100644 index 000000000000..d1df194319ac --- /dev/null +++ b/drivers/misc/awinic/aw862x/Android.mk @@ -0,0 +1,12 @@ +DLKM_DIR := motorola/kernel/modules +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := aw862x.ko +LOCAL_MODULE_TAGS := optional +ifeq ($(DLKM_INSTALL_TO_VENDOR_OUT),true) +LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/modules/ +else +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +endif +include $(DLKM_DIR)/AndroidKernelModule.mk diff --git a/drivers/misc/awinic/aw862x/Kbuild b/drivers/misc/awinic/aw862x/Kbuild new file mode 100644 index 000000000000..f993301e9010 --- /dev/null +++ b/drivers/misc/awinic/aw862x/Kbuild @@ -0,0 +1,12 @@ +# add -Wall to try to catch everything we can. +EXTRA_CFLAGS += -Wall +EXTRA_CFLAGS += -I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/include \ + -I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/drivers/misc/awinic/aw862x + +obj-m += aw862x.o + +aw862x-objs += haptic_nv.o +aw862x-objs += aw8622x.o +aw862x-objs += aw86214.o +aw862x-objs += aw8624.o + diff --git a/drivers/misc/awinic/aw862x/Makefile b/drivers/misc/awinic/aw862x/Makefile new file mode 100644 index 000000000000..62a13fd28500 --- /dev/null +++ b/drivers/misc/awinic/aw862x/Makefile @@ -0,0 +1,11 @@ +KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build + +all: + $(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS) + +modules_install: + $(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install + +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean + diff --git a/drivers/misc/awinic/aw862x/aw86214.c b/drivers/misc/awinic/aw862x/aw86214.c new file mode 100644 index 000000000000..43c16b408724 --- /dev/null +++ b/drivers/misc/awinic/aw862x/aw86214.c @@ -0,0 +1,3002 @@ +/* + * aw86214.c + * + * Copyright (c) 2021 AWINIC Technology CO., LTD + * + * Author: + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aw86214.h" +#include "haptic_nv.h" + +/****************************************************** + * + * Register Access + * + ******************************************************/ +const unsigned char aw86214_reg_list[] = { + AW86214_REG_ID, + AW86214_REG_SYSST, + AW86214_REG_SYSINT, + AW86214_REG_SYSINTM, + AW86214_REG_SYSST2, + AW86214_REG_PLAYCFG2, + AW86214_REG_PLAYCFG3, + AW86214_REG_PLAYCFG4, + AW86214_REG_WAVCFG1, + AW86214_REG_WAVCFG2, + AW86214_REG_WAVCFG3, + AW86214_REG_WAVCFG4, + AW86214_REG_WAVCFG5, + AW86214_REG_WAVCFG6, + AW86214_REG_WAVCFG7, + AW86214_REG_WAVCFG8, + AW86214_REG_WAVCFG9, + AW86214_REG_WAVCFG10, + AW86214_REG_WAVCFG11, + AW86214_REG_WAVCFG12, + AW86214_REG_WAVCFG13, + AW86214_REG_CONTCFG1, + AW86214_REG_CONTCFG2, + AW86214_REG_CONTCFG3, + AW86214_REG_CONTCFG4, + AW86214_REG_CONTCFG5, + AW86214_REG_CONTCFG6, + AW86214_REG_CONTCFG7, + AW86214_REG_CONTCFG8, + AW86214_REG_CONTCFG9, + AW86214_REG_CONTCFG10, + AW86214_REG_CONTCFG11, + AW86214_REG_CONTCFG13, + AW86214_REG_CONTRD14, + AW86214_REG_CONTRD15, + AW86214_REG_CONTRD16, + AW86214_REG_CONTRD17, + AW86214_REG_RTPCFG1, + AW86214_REG_RTPCFG2, + AW86214_REG_RTPCFG3, + AW86214_REG_RTPCFG4, + AW86214_REG_RTPCFG5, + AW86214_REG_TRGCFG1, + AW86214_REG_TRGCFG4, + AW86214_REG_TRGCFG7, + AW86214_REG_TRGCFG8, + AW86214_REG_GLBCFG4, + AW86214_REG_GLBRD5, + AW86214_REG_RAMADDRH, + AW86214_REG_RAMADDRL, + AW86214_REG_SYSCTRL1, + AW86214_REG_SYSCTRL2, + AW86214_REG_SYSCTRL3, + AW86214_REG_SYSCTRL4, + AW86214_REG_SYSCTRL5, + AW86214_REG_SYSCTRL6, + AW86214_REG_SYSCTRL7, + AW86214_REG_PWMCFG1, + AW86214_REG_PWMCFG3, + AW86214_REG_PWMCFG4, + AW86214_REG_DETCFG1, + AW86214_REG_DETCFG2, + AW86214_REG_DET_RL, + AW86214_REG_DET_VBAT, + AW86214_REG_DET_LO, + AW86214_REG_TRIMCFG1, + AW86214_REG_TRIMCFG3, + AW86214_REG_ANACFG8, +}; + +/****************************************************** + * + * value + * + ******************************************************/ +static char *aw86214_ram_name = "aw86214_haptic.bin"; + +/****************************************************** + * + * functions declaration + * + ******************************************************/ +static int aw86214_analyse_duration_range(struct aw86214 *aw86214); + + /****************************************************** + * + * aw86214 i2c write/read + * + ******************************************************/ +static int aw86214_i2c_read(struct aw86214 *aw86214, unsigned char reg_addr, + unsigned char *buf, unsigned int len) +{ + int ret = 0; + + struct i2c_msg msg[2] = { + [0] = { + .addr = aw86214->i2c->addr, + .flags = 0, + .len = sizeof(uint8_t), + .buf = ®_addr, + }, + [1] = { + .addr = aw86214->i2c->addr, + .flags = I2C_M_RD, + .len = len, + .buf = buf, + }, + }; + + ret = i2c_transfer(aw86214->i2c->adapter, msg, ARRAY_SIZE(msg)); + if (ret < 0) { + aw_dev_err("%s: i2c_transfer failed\n", __func__); + return ret; + } else if (ret != AW_I2C_READ_MSG_NUM) { + aw_dev_err("%s: transfer failed(size error)\n", __func__); + return -ENXIO; + } + return ret; +} + +static int aw86214_i2c_write(struct aw86214 *aw86214, unsigned char reg_addr, + unsigned char *buf, unsigned int len) +{ + unsigned char *data = NULL; + int ret = -1; + + data = kmalloc(len + 1, GFP_KERNEL); + data[0] = reg_addr; + memcpy(&data[1], buf, len); + ret = i2c_master_send(aw86214->i2c, data, len + 1); + if (ret < 0) + aw_dev_err("%s: i2c master send 0x%02x error\n", + __func__, reg_addr); + kfree(data); + return ret; +} + +static int +aw86214_i2c_write_bits(struct aw86214 *aw86214, unsigned char reg_addr, + unsigned int mask, + unsigned char reg_data) +{ + unsigned char reg_val = 0; + int ret = -1; + + ret = aw86214_i2c_read(aw86214, reg_addr, ®_val, AW_I2C_BYTE_ONE); + if (ret < 0) { + aw_dev_err("%s: i2c read error, ret=%d\n", __func__, ret); + return ret; + } + reg_val &= mask; + reg_val |= reg_data; + ret = aw86214_i2c_write(aw86214, reg_addr, ®_val, AW_I2C_BYTE_ONE); + if (ret < 0) { + aw_dev_err("%s: i2c write error, ret=%d\n", __func__, ret); + return ret; + } + return 0; +} + +static int aw86214_parse_data(struct aw86214 *aw86214, const char *buf) +{ + unsigned char reg_num = aw86214->aw_i2c_package.reg_num; + unsigned char i = 0; + const char *temp_buf = NULL; + char data_buf[AWRW_CMD_UNIT] = { 0 }; + unsigned int value = 0; + int ret = 0; + int len = strlen(buf) - (AWRW_CMD_UNIT * 3); + + if (len < 0) { + aw_dev_err("%s: parse data error\n", __func__); + return -ERANGE; + } + temp_buf = &buf[AWRW_CMD_UNIT * 3]; + for (i = 0; i < reg_num; i++) { + if (((i + 1) * AWRW_CMD_UNIT) > len) { + aw_dev_err("%s: parse data error\n", __func__); + return -ERANGE; + } + memcpy(data_buf, &temp_buf[i * AWRW_CMD_UNIT], 4); + data_buf[4] = '\0'; + ret = kstrtouint(data_buf, 0, &value); + if (ret < 0) { + aw_dev_err("%s: kstrtouint error\n", __func__); + return ret; + } + aw86214->aw_i2c_package.reg_data[i] = (unsigned char)value; + } + return 0; +} + +irqreturn_t aw86214_irq(int irq, void *data) +{ + struct aw86214 *aw86214 = data; + unsigned char reg_val = 0; + + aw_dev_info("%s enter\n", __func__); + aw86214_i2c_read(aw86214, AW86214_REG_SYSINT, ®_val, + AW_I2C_BYTE_ONE); + aw_dev_info("%s: reg SYSINT=0x%02X\n", __func__, reg_val); + if (reg_val & AW86214_BIT_SYSINT_BST_OVPI) + aw_dev_err("%s chip ov int error\n", __func__); + if (reg_val & AW86214_BIT_SYSINT_UVLI) + aw_dev_err("%s chip uvlo int error\n", __func__); + if (reg_val & AW86214_BIT_SYSINT_OCDI) + aw_dev_err("%s chip over current int error\n", + __func__); + if (reg_val & AW86214_BIT_SYSINT_OTI) + aw_dev_err("%s chip over temperature int error\n", + __func__); + if (reg_val & AW86214_BIT_SYSINT_DONEI) + aw_dev_info("%s chip playback done\n", __func__); + + aw_dev_info("%s exit\n", __func__); + + return IRQ_HANDLED; +} + +static int aw86214_analyse_duration_range(struct aw86214 *aw86214) +{ + int i = 0; + int ret = 0; + int len = 0; + int *duration_time = NULL; + + len = ARRAY_SIZE(aw86214->dts_info.duration_time); + duration_time = aw86214->dts_info.duration_time; + if (len < 2) { + aw_dev_err("%s: duration time range error\n", __func__); + return -ERANGE; + } + for (i = (len - 1); i > 0; i--) { + if (duration_time[i] > duration_time[i-1]) + continue; + else + break; + + } + if (i > 0) { + aw_dev_err("%s: duration time range error\n", __func__); + ret = -ERANGE; + } + return ret; +} + +static int +aw86214_analyse_duration_array_size(struct aw86214 *aw86214, + struct device_node *np) +{ + int ret = 0; + + ret = of_property_count_elems_of_size(np, "aw86214_vib_duration_time", + 4); + if (ret < 0) { + aw86214->duration_time_flag = -1; + aw_dev_info("%s vib_duration_time not found\n", __func__); + return ret; + } + aw86214->duration_time_size = ret; + if (aw86214->duration_time_size > 3) { + aw86214->duration_time_flag = -1; + aw_dev_info("%s vib_duration_time error, array size = %d\n", + __func__, aw86214->duration_time_size); + return -ERANGE; + } + return 0; +} + +/***************************************************** + * + * device tree + * + *****************************************************/ +int aw86214_parse_dt(struct aw86214 *aw86214, struct device *dev, + struct device_node *np) +{ + unsigned int val = 0; + unsigned int prctmode_temp[3]; + unsigned int sine_array_temp[4] = { 0x05, 0xB2, 0xFF, 0xEF }; + unsigned int duration_time[3]; + int ret = 0; + + val = of_property_read_u32(np, "aw86214_vib_lk_f0_cali", + &aw86214->dts_info.lk_f0_cali); + if (val != 0) + aw_dev_info("aw86214_vib_mode not found\n"); + aw_dev_info("%s: aw86214_vib_lk_f0_cali = 0x%02x\n", + __func__, aw86214->dts_info.lk_f0_cali); + val = of_property_read_u32(np, "aw86214_vib_mode", + &aw86214->dts_info.mode); + if (val != 0) + aw_dev_info("%s vib_mode not found\n", __func__); + val = of_property_read_u32(np, "aw86214_vib_f0_ref", + &aw86214->dts_info.f0_ref); + if (val != 0) + aw_dev_info("%s vib_f0_ref not found\n", __func__); + val = + of_property_read_u32(np, "aw86214_vib_f0_cali_percent", + &aw86214->dts_info.f0_cali_percent); + if (val != 0) + aw_dev_info("%s vib_f0_cali_percent not found\n", __func__); + val = of_property_read_u32(np, "aw86214_vib_cont_drv1_lvl", + &aw86214->dts_info.cont_drv1_lvl_dt); + if (val != 0) + aw_dev_info("%s vib_cont_drv1_lvl not found\n", __func__); + val = + of_property_read_u32(np, "aw86214_vib_cont_drv2_lvl", + &aw86214->dts_info.cont_drv2_lvl_dt); + if (val != 0) + aw_dev_info("%s vib_cont_drv2_lvl not found\n", __func__); + val = + of_property_read_u32(np, "aw86214_vib_cont_drv1_time", + &aw86214->dts_info.cont_drv1_time_dt); + if (val != 0) + aw_dev_info("%s vib_cont_drv1_time not found\n", __func__); + val = + of_property_read_u32(np, "aw86214_vib_cont_drv2_time", + &aw86214->dts_info.cont_drv2_time_dt); + if (val != 0) + aw_dev_info("%s vib_cont_drv2_time not found\n", __func__); + val = + of_property_read_u32(np, "aw86214_vib_cont_drv_width", + &aw86214->dts_info.cont_drv_width); + if (val != 0) + aw_dev_info("%s vib_cont_drv_width not found\n", __func__); + val = + of_property_read_u32(np, "aw86214_vib_cont_brk_time", + &aw86214->dts_info.cont_brk_time_dt); + if (val != 0) + aw_dev_info("%s vib_cont_brk_time_dt not found\n", __func__); + val = + of_property_read_u32(np, "aw86214_vib_cont_wait_num", + &aw86214->dts_info.cont_wait_num_dt); + if (val != 0) + aw_dev_info("%s vib_cont_wait_num not found\n", __func__); + val = + of_property_read_u32(np, "aw86214_vib_cont_tset", + &aw86214->dts_info.cont_tset); + if (val != 0) + aw_dev_info("%s vib_cont_tset not found\n", __func__); + val = + of_property_read_u32(np, "aw86214_vib_cont_bemf_set", + &aw86214->dts_info.cont_bemf_set); + if (val != 0) + aw_dev_info("%s vib_cont_bemf_set not found\n", __func__); + val = + of_property_read_u32(np, "aw86214_vib_d2s_gain", + &aw86214->dts_info.d2s_gain); + if (val != 0) + aw_dev_info("%s vib_d2s_gain not found\n", __func__); + val = + of_property_read_u32(np, "aw86214_vib_cont_track_margin", + &aw86214->dts_info.cont_track_margin); + if (val != 0) + aw_dev_info("%s vib_cont_track_margin not found\n", __func__); + val = of_property_read_u32_array(np, "aw86214_vib_prctmode", + prctmode_temp, + ARRAY_SIZE(prctmode_temp)); + if (val != 0) + aw_dev_info("%s vib_prctmode not found\n", __func__); + memcpy(aw86214->dts_info.prctmode, prctmode_temp, + sizeof(prctmode_temp)); + val = + of_property_read_u32_array(np, + "aw86214_vib_sine_array", + sine_array_temp, + ARRAY_SIZE(sine_array_temp)); + if (val != 0) + aw_dev_info("%s vib_sine_array not found\n", __func__); + memcpy(aw86214->dts_info.sine_array, sine_array_temp, + sizeof(sine_array_temp)); + val = of_property_read_u32_array(np, "aw86214_vib_duration_time", + duration_time, ARRAY_SIZE(duration_time)); + if (val != 0) + aw_dev_info("%s vib_duration_time not found\n", __func__); + ret = aw86214_analyse_duration_array_size(aw86214, np); + if (!ret) + memcpy(aw86214->dts_info.duration_time, + duration_time, sizeof(duration_time)); + return 0; +} + +static void aw86214_haptic_upload_lra(struct aw86214 *aw86214, + unsigned int flag) +{ + switch (flag) { + case AW86214_WRITE_ZERO: + aw_dev_info("%s write zero to trim_lra!\n", __func__); + aw86214_i2c_write_bits(aw86214, AW86214_REG_TRIMCFG3, + AW86214_BIT_TRIMCFG3_TRIM_LRA_MASK, + 0x00); + break; + case AW86214_F0_CALI: + aw_dev_info("%s write f0_cali_data to trim_lra = 0x%02X\n", + __func__, aw86214->f0_cali_data); + aw86214_i2c_write_bits(aw86214, AW86214_REG_TRIMCFG3, + AW86214_BIT_TRIMCFG3_TRIM_LRA_MASK, + (char)aw86214->f0_cali_data); + break; + default: + break; + } +} + +static void aw86214_brk_en(struct aw86214 *aw86214, bool isEnable) +{ + unsigned char reg_val = 0; + + if (isEnable == false) + reg_val = 0x00; + else + reg_val = (unsigned char)aw86214->dts_info.cont_brk_time_dt; + + aw86214_i2c_write(aw86214, AW86214_REG_CONTCFG10, ®_val, + AW_I2C_BYTE_ONE); + +} + +static void aw86214_ver_a_init(struct aw86214 *aw86214) +{ + unsigned char reg_val = 0; + + aw86214_i2c_write_bits(aw86214, AW86214_REG_RTPCFG1, + (AW86214_BIT_RTPCFG1_SRAM_SIZE_2K_MASK & + AW86214_BIT_RTPCFG1_SRAM_SIZE_1K_MASK), + (AW86214_BIT_RTPCFG1_SRAM_SIZE_2K_DIS | + AW86214_BIT_RTPCFG1_SRAM_SIZE_1K_EN)); + aw86214_i2c_write_bits(aw86214, AW86214_REG_PLAYCFG3, + AW86214_BIT_PLAYCFG3_BRK_EN_MASK, + AW86214_BIT_PLAYCFG3_BRK_ENABLE); + reg_val = 0x00; + aw86214_i2c_write(aw86214, AW86214_REG_CONTCFG10, ®_val, + AW_I2C_BYTE_ONE); +} + +static int aw86214_haptic_stop(struct aw86214 *aw86214) +{ + unsigned char cnt = 40; + unsigned char reg_val = 0; + bool force_flag = true; + + aw_dev_info("%s enter\n", __func__); + aw86214->play_mode = AW86214_HAPTIC_STANDBY_MODE; + reg_val = AW86214_BIT_PLAYCFG4_STOP_ON; + aw86214_i2c_write(aw86214, AW86214_REG_PLAYCFG4, ®_val, + AW_I2C_BYTE_ONE); + while (cnt) { + aw86214_i2c_read(aw86214, AW86214_REG_GLBRD5, ®_val, + AW_I2C_BYTE_ONE); + if ((reg_val & 0x0f) == 0x00 + || (reg_val & 0x0f) == 0x0A) { + cnt = 0; + force_flag = false; + aw_dev_info("%s entered standby! glb_state=0x%02X\n", + __func__, reg_val); + } else { + cnt--; + pr_debug + ("%s wait for standby, glb_state=0x%02X\n", + __func__, reg_val); + } + usleep_range(AW86214_STOP_DELAY_MIN, AW86214_STOP_DELAY_MAX); + } + if (force_flag) { + aw_dev_err("%s force to enter standby mode!\n", __func__); + aw86214_i2c_write_bits(aw86214, AW86214_REG_SYSCTRL2, + AW86214_BIT_SYSCTRL2_STANDBY_MASK, + AW86214_BIT_SYSCTRL2_STANDBY_ON); + } + return 0; +} + +static void aw86214_haptic_raminit(struct aw86214 *aw86214, bool flag) +{ + if (flag) { + aw86214_i2c_write_bits(aw86214, AW86214_REG_SYSCTRL1, + AW86214_BIT_SYSCTRL1_RAMINIT_MASK, + AW86214_BIT_SYSCTRL1_RAMINIT_ON); + } else { + aw86214_i2c_write_bits(aw86214, AW86214_REG_SYSCTRL1, + AW86214_BIT_SYSCTRL1_RAMINIT_MASK, + AW86214_BIT_SYSCTRL1_RAMINIT_OFF); + } +} + +static int aw86214_haptic_get_vbat(struct aw86214 *aw86214) +{ + unsigned char reg_val = 0; + unsigned int vbat_code = 0; + + aw86214_haptic_stop(aw86214); + aw86214_haptic_raminit(aw86214, true); + aw86214_i2c_write_bits(aw86214, AW86214_REG_DETCFG2, + AW86214_BIT_DETCFG2_VBAT_GO_MASK, + AW86214_BIT_DETCFG2_VABT_GO_ON); + usleep_range(AW86214_VBAT_DELAY_MIN, AW86214_VBAT_DELAY_MAX); + aw86214_i2c_read(aw86214, AW86214_REG_DET_VBAT, ®_val, + AW_I2C_BYTE_ONE); + vbat_code = (vbat_code | reg_val) << 2; + aw86214_i2c_read(aw86214, AW86214_REG_DET_LO, ®_val, + AW_I2C_BYTE_ONE); + vbat_code = vbat_code | ((reg_val & AW86214_BIT_DET_LO_VBAT) >> 4); + aw86214->vbat = AW86214_VBAT_FORMULA(vbat_code); + if (aw86214->vbat > AW86214_VBAT_MAX) { + aw86214->vbat = AW86214_VBAT_MAX; + aw_dev_info("%s vbat max limit = %dmV\n", __func__, + aw86214->vbat); + } + if (aw86214->vbat < AW86214_VBAT_MIN) { + aw86214->vbat = AW86214_VBAT_MIN; + aw_dev_info("%s vbat min limit = %dmV\n", __func__, + aw86214->vbat); + } + aw_dev_info("%s aw86214->vbat=%dmV, vbat_code=0x%02X\n", __func__, + aw86214->vbat, vbat_code); + aw86214_haptic_raminit(aw86214, false); + return 0; +} +static int aw86214_haptic_set_gain(struct aw86214 *aw86214, unsigned char gain) +{ + aw86214_i2c_write(aw86214, AW86214_REG_PLAYCFG2, &gain, + AW_I2C_BYTE_ONE); + return 0; +} + +static int aw86214_haptic_ram_vbat_comp(struct aw86214 *aw86214, + bool flag) +{ + int temp_gain = 0; + + if (flag) { + if (aw86214->ram_vbat_compensate == + AW86214_HAPTIC_RAM_VBAT_COMP_ENABLE) { + aw86214_haptic_get_vbat(aw86214); + temp_gain = + aw86214->gain * AW86214_VBAT_REFER / aw86214->vbat; + if (temp_gain > + (128 * AW86214_VBAT_REFER / AW86214_VBAT_MIN)) { + temp_gain = + 128 * AW86214_VBAT_REFER / AW86214_VBAT_MIN; + aw_dev_dbg("%s gain limit=%d\n", __func__, + temp_gain); + } + aw86214_haptic_set_gain(aw86214, temp_gain); + } else { + aw86214_haptic_set_gain(aw86214, aw86214->gain); + } + } else { + aw86214_haptic_set_gain(aw86214, aw86214->gain); + } + return 0; +} + +static int aw86214_haptic_play_mode(struct aw86214 *aw86214, + unsigned char play_mode) +{ + aw_dev_info("%s enter\n", __func__); + + switch (play_mode) { + case AW86214_HAPTIC_STANDBY_MODE: + aw_dev_info("%s: enter standby mode\n", __func__); + aw86214->play_mode = AW86214_HAPTIC_STANDBY_MODE; + aw86214_haptic_stop(aw86214); + break; + case AW86214_HAPTIC_RAM_MODE: + aw_dev_info("%s: enter ram mode\n", __func__); + aw86214->play_mode = AW86214_HAPTIC_RAM_MODE; + aw86214_i2c_write_bits(aw86214, AW86214_REG_PLAYCFG3, + AW86214_BIT_PLAYCFG3_PLAY_MODE_MASK, + AW86214_BIT_PLAYCFG3_PLAY_MODE_RAM); + break; + case AW86214_HAPTIC_RAM_LOOP_MODE: + aw_dev_info("%s: enter ram loop mode\n", __func__); + aw86214->play_mode = AW86214_HAPTIC_RAM_LOOP_MODE; + aw86214_i2c_write_bits(aw86214, AW86214_REG_PLAYCFG3, + AW86214_BIT_PLAYCFG3_PLAY_MODE_MASK, + AW86214_BIT_PLAYCFG3_PLAY_MODE_RAM); + break; + case AW86214_HAPTIC_CONT_MODE: + aw_dev_info("%s: enter cont mode\n", __func__); + aw86214->play_mode = AW86214_HAPTIC_CONT_MODE; + aw86214_i2c_write_bits(aw86214, AW86214_REG_PLAYCFG3, + AW86214_BIT_PLAYCFG3_PLAY_MODE_MASK, + AW86214_BIT_PLAYCFG3_PLAY_MODE_CONT); + break; + default: + aw_dev_err("%s: play mode %d error", __func__, play_mode); + break; + } + return 0; +} + +static void aw86214_haptic_play_go(struct aw86214 *aw86214) +{ + unsigned char reg_val = AW86214_BIT_PLAYCFG4_GO_ON; + + aw86214_i2c_write(aw86214, AW86214_REG_PLAYCFG4, ®_val, + AW_I2C_BYTE_ONE); +} + +static int aw86214_haptic_set_wav_seq(struct aw86214 *aw86214, + unsigned char wav, unsigned char seq) +{ + aw86214_i2c_write(aw86214, AW86214_REG_WAVCFG1 + wav, &seq, + AW_I2C_BYTE_ONE); + return 0; +} + +static int aw86214_haptic_set_wav_loop(struct aw86214 *aw86214, + unsigned char wav, unsigned char loop) +{ + unsigned char tmp = 0; + + if (wav % 2) { + tmp = loop << 0; + aw86214_i2c_write_bits(aw86214, AW86214_REG_WAVCFG9 + (wav / 2), + AW86214_BIT_WAVLOOP_SEQ_EVEN_MASK, tmp); + } else { + tmp = loop << 4; + aw86214_i2c_write_bits(aw86214, AW86214_REG_WAVCFG9 + (wav / 2), + AW86214_BIT_WAVLOOP_SEQ_ODD_MASK, tmp); + } + return 0; +} + +/***************************************************** + * + * haptic f0 cali + * + *****************************************************/ +static int aw86214_haptic_read_lra_f0(struct aw86214 *aw86214) +{ + unsigned char reg_val[2] = {0}; + unsigned int f0_reg = 0; + unsigned long f0_tmp = 0; + + aw_dev_info("%s enter\n", __func__); + /* F_LRA_F0 */ + aw86214_i2c_read(aw86214, AW86214_REG_CONTRD14, reg_val, + AW_I2C_BYTE_TWO); + f0_reg = (f0_reg | reg_val[0]) << 8; + f0_reg |= (reg_val[1] << 0); + if (!f0_reg) { + aw_dev_err("%s didn't get lra f0 because f0_reg value is 0!\n", + __func__); + aw86214->f0 = aw86214->dts_info.f0_ref; + return -ERANGE; + } + f0_tmp = 384000 * 10 / f0_reg; + aw86214->f0 = (unsigned int)f0_tmp; + aw_dev_info("%s lra_f0=%d\n", __func__, aw86214->f0); + return 0; +} + +static int aw86214_haptic_read_cont_f0(struct aw86214 *aw86214) +{ + unsigned char reg_val[2] = {0}; + unsigned int f0_reg = 0; + unsigned long f0_tmp = 0; + + aw_dev_info("%s enter\n", __func__); + aw86214_i2c_read(aw86214, AW86214_REG_CONTRD16, reg_val, + AW_I2C_BYTE_TWO); + f0_reg = (f0_reg | reg_val[0]) << 8; + f0_reg |= (reg_val[1] << 0); + if (!f0_reg) { + aw_dev_err("%s didn't get cont f0 because f0_reg value is 0!\n", + __func__); + aw86214->cont_f0 = aw86214->dts_info.f0_ref; + return -ERANGE; + } + f0_tmp = 384000 * 10 / f0_reg; + aw86214->cont_f0 = (unsigned int)f0_tmp; + aw_dev_info("%s cont_f0=%d\n", __func__, aw86214->cont_f0); + return 0; +} + +static int aw86214_haptic_cont_get_f0(struct aw86214 *aw86214) +{ + int ret = 0; + unsigned char reg_val = 0; + unsigned char reg_array[3] = {0}; + unsigned int cnt = 200; + bool get_f0_flag = false; + unsigned char brk_en_temp = 0; + + aw_dev_info("%s enter\n", __func__); + aw86214->f0 = aw86214->dts_info.f0_ref; + /* enter standby mode */ + aw86214_haptic_stop(aw86214); + /* f0 calibrate work mode */ + aw86214_haptic_play_mode(aw86214, AW86214_HAPTIC_CONT_MODE); + /* enable f0 detect */ + aw86214_i2c_write_bits(aw86214, AW86214_REG_CONTCFG1, + AW86214_BIT_CONTCFG1_EN_F0_DET_MASK, + AW86214_BIT_CONTCFG1_F0_DET_ENABLE); + /* cont config */ + aw86214_i2c_write_bits(aw86214, AW86214_REG_CONTCFG6, + AW86214_BIT_CONTCFG6_TRACK_EN_MASK, + AW86214_BIT_CONTCFG6_TRACK_ENABLE); + /* enable auto brake */ + aw86214_i2c_read(aw86214, AW86214_REG_PLAYCFG3, ®_val, + AW_I2C_BYTE_ONE); + brk_en_temp = AW86214_BIT_PLAYCFG3_BRK & reg_val; + aw86214_i2c_write_bits(aw86214, AW86214_REG_PLAYCFG3, + AW86214_BIT_PLAYCFG3_BRK_EN_MASK, + AW86214_BIT_PLAYCFG3_BRK_ENABLE); + /* f0 driver level */ + aw86214_i2c_write_bits(aw86214, AW86214_REG_CONTCFG6, + AW86214_BIT_CONTCFG6_DRV1_LVL_MASK, + aw86214->dts_info.cont_drv1_lvl_dt); + reg_array[0] = (unsigned char)aw86214->dts_info.cont_drv2_lvl_dt; + reg_array[1] = (unsigned char)aw86214->dts_info.cont_drv1_time_dt; + reg_array[2] = (unsigned char)aw86214->dts_info.cont_drv2_time_dt; + aw86214_i2c_write(aw86214, AW86214_REG_CONTCFG7, reg_array, + AW_I2C_BYTE_THREE); + /* TRACK_MARGIN */ + if (!aw86214->dts_info.cont_track_margin) { + aw_dev_err("%s aw86214->dts_info.cont_track_margin = 0!\n", + __func__); + } else { + reg_val = (unsigned char)aw86214->dts_info.cont_track_margin; + aw86214_i2c_write(aw86214, AW86214_REG_CONTCFG11, ®_val, + AW_I2C_BYTE_ONE); + } + /* cont play go */ + aw86214_haptic_play_go(aw86214); + /* 300ms */ + while (cnt) { + aw86214_i2c_read(aw86214, AW86214_REG_GLBRD5, ®_val, + AW_I2C_BYTE_ONE); + if ((reg_val & AW86214_BIT_GLBRD5_STATE) == + AW86214_BIT_GLBRD5_STATE_STANDBY) { + cnt = 0; + get_f0_flag = true; + aw_dev_info("%s entered standby mode! glb_state=0x%02X\n", + __func__, reg_val); + } else { + cnt--; + aw_dev_info("%s waitting for standby, glb_state=0x%02X\n", + __func__, reg_val); + } + usleep_range(AW86214_F0_DELAY_MIN, AW86214_F0_DELAY_MAX); + } + if (get_f0_flag) { + aw86214_haptic_read_lra_f0(aw86214); + aw86214_haptic_read_cont_f0(aw86214); + } else { + aw_dev_err("%s enter standby mode failed, stop reading f0!\n", + __func__); + } + /* restore default config */ + aw86214_i2c_write_bits(aw86214, AW86214_REG_CONTCFG1, + AW86214_BIT_CONTCFG1_EN_F0_DET_MASK, + AW86214_BIT_CONTCFG1_F0_DET_DISABLE); + /* recover auto break config */ + aw86214_i2c_write_bits(aw86214, AW86214_REG_PLAYCFG3, + AW86214_BIT_PLAYCFG3_BRK_EN_MASK, + brk_en_temp); + return ret; +} + +static int aw86214_haptic_set_repeat_wav_seq(struct aw86214 *aw86214, + unsigned char seq) +{ + aw86214_haptic_set_wav_seq(aw86214, 0x00, seq); + aw86214_haptic_set_wav_seq(aw86214, 0x01, 0x00); + aw86214_haptic_set_wav_loop(aw86214, 0x00, + AW86214_BIT_WAVLOOP_INIFINITELY); + return 0; +} + +static int aw86214_haptic_get_lra_resistance(struct aw86214 *aw86214) +{ + unsigned char reg_val = 0; + unsigned int lra_code = 0; + unsigned int lra = 0; + unsigned char d2s_gain_temp = 0; + + mutex_lock(&aw86214->lock); + aw86214_haptic_stop(aw86214); + aw86214_i2c_read(aw86214, AW86214_REG_SYSCTRL7, ®_val, + AW_I2C_BYTE_ONE); + d2s_gain_temp = 0x07 & reg_val; + aw86214_i2c_write_bits(aw86214, AW86214_REG_SYSCTRL7, + AW86214_BIT_SYSCTRL7_D2S_GAIN_MASK, + aw86214->dts_info.d2s_gain); + aw86214_haptic_raminit(aw86214, true); + /* enter standby mode */ + aw86214_haptic_stop(aw86214); + usleep_range(AW86214_STOP_DELAY_MIN, AW86214_STOP_DELAY_MAX); + aw86214_i2c_write_bits(aw86214, AW86214_REG_SYSCTRL2, + AW86214_BIT_SYSCTRL2_STANDBY_MASK, + AW86214_BIT_SYSCTRL2_STANDBY_OFF); + aw86214_i2c_write_bits(aw86214, AW86214_REG_DETCFG1, + AW86214_BIT_DETCFG1_RL_OS_MASK, + AW86214_BIT_DETCFG1_RL); + aw86214_i2c_write_bits(aw86214, AW86214_REG_DETCFG2, + AW86214_BIT_DETCFG2_DIAG_GO_MASK, + AW86214_BIT_DETCFG2_DIAG_GO_ON); + usleep_range(AW86214_LRA_DELAY_MIN, AW86214_LRA_DELAY_MAX); + aw86214_i2c_read(aw86214, AW86214_REG_DET_RL, ®_val, + AW_I2C_BYTE_ONE); + lra_code = (lra_code | reg_val) << 2; + aw86214_i2c_read(aw86214, AW86214_REG_DET_LO, ®_val, + AW_I2C_BYTE_ONE); + lra_code = lra_code | (reg_val & AW86214_BIT_DET_LO_RL); + /* 2num */ + lra = AW86214_LRA_FORMULA(lra_code); + /* Keep up with aw8624 driver */ + aw86214->lra = lra * 10; + aw86214_haptic_raminit(aw86214, false); + aw86214_i2c_write_bits(aw86214, AW86214_REG_SYSCTRL7, + AW86214_BIT_SYSCTRL7_D2S_GAIN_MASK, + d2s_gain_temp); + mutex_unlock(&aw86214->lock); + return 0; +} + +static void aw86214_set_ram_addr(struct aw86214 *aw86214) +{ + unsigned char ram_addr[2] = {0}; + + ram_addr[0] = (unsigned char)(aw86214->ram.base_addr >> 8); + ram_addr[1] = (unsigned char)(aw86214->ram.base_addr & 0x00ff); + + aw86214_i2c_write(aw86214, AW86214_REG_RAMADDRH, ram_addr, + AW_I2C_BYTE_TWO); +} + +#ifdef AW_CHECK_RAM_DATA +static int aw86214_check_ram_data(struct aw86214 *aw86214, + unsigned char *cont_data, + unsigned char *ram_data, unsigned int len) +{ + int i = 0; + + for (i = 0; i < len; i++) { + if (ram_data[i] != cont_data[i]) { + aw_dev_err("%s: check ramdata error, addr=0x%04x, ram_data=0x%02x, file_data=0x%02x\n", + __func__, i, ram_data[i], cont_data[i]); + return -ERANGE; + } + } + return 0; +} +#endif + +static int aw86214_container_update(struct aw86214 *aw86214, + struct aw86214_container *aw86214_cont) +{ + unsigned int shift = 0; + int i = 0; + int ret = 0; + int len = 0; +#ifdef AW_CHECK_RAM_DATA + unsigned char ram_data[AW_RAMDATA_RD_BUFFER_SIZE] = {0}; +#endif + + aw_dev_info("%s enter\n", __func__); + mutex_lock(&aw86214->lock); + aw86214->ram.baseaddr_shift = 2; + aw86214->ram.ram_shift = 4; + /* RAMINIT Enable */ + aw86214_haptic_raminit(aw86214, true); + /* Enter standby mode */ + aw86214_haptic_stop(aw86214); + /* set base addr */ + shift = aw86214->ram.baseaddr_shift; + aw86214->ram.base_addr = + (unsigned int)((aw86214_cont->data[0 + shift] << 8) | + (aw86214_cont->data[1 + shift])); + aw86214_i2c_write_bits(aw86214, AW86214_REG_RTPCFG1, /*ADDRH*/ + AW86214_BIT_RTPCFG1_ADDRH_MASK, + aw86214_cont->data[0 + shift]); + + aw86214_i2c_write(aw86214, AW86214_REG_RTPCFG2, /*ADDRL*/ + &aw86214_cont->data[1 + shift], + AW_I2C_BYTE_ONE); + + /* ram */ + aw86214_set_ram_addr(aw86214); + i = aw86214->ram.ram_shift; + while (i < aw86214_cont->len) { + if ((aw86214_cont->len - i) < AW_RAMDATA_WR_BUFFER_SIZE) + len = aw86214_cont->len - i; + else + len = AW_RAMDATA_WR_BUFFER_SIZE; + + aw86214_i2c_write(aw86214, AW86214_REG_RAMDATA, + &aw86214_cont->data[i], len); + i += len; + } + +#ifdef AW_CHECK_RAM_DATA + aw86214_set_ram_addr(aw86214); + i = aw86214->ram.ram_shift; + while (i < aw86214_cont->len) { + if ((aw86214_cont->len - i) < AW_RAMDATA_RD_BUFFER_SIZE) + len = aw86214_cont->len - i; + else + len = AW_RAMDATA_RD_BUFFER_SIZE; + + aw86214_i2c_read(aw86214, AW86214_REG_RAMDATA, ram_data, len); + ret = aw86214_check_ram_data(aw86214, &aw86214_cont->data[i], + ram_data, len); + if (ret < 0) + break; + i += len; + } + if (ret) + aw_dev_err("%s: ram data check sum error\n", __func__); + else + aw_dev_info("%s: ram data check sum pass\n", __func__); + +#endif + /* RAMINIT Disable */ + aw86214_haptic_raminit(aw86214, false); + mutex_unlock(&aw86214->lock); + aw_dev_info("%s exit\n", __func__); + return ret; +} + +static int aw86214_haptic_ram_config(struct aw86214 *aw86214, int duration) +{ + int ret = 0; + + if (aw86214->duration_time_flag < 0) { + aw_dev_err("%s: duration time error, array size = %d\n", + __func__, aw86214->duration_time_size); + return -ERANGE; + } + ret = aw86214_analyse_duration_range(aw86214); + if (ret < 0) + return ret; + + if ((duration > 0) && (duration < + aw86214->dts_info.duration_time[0])) { + aw86214->index = 3; /*3*/ + aw86214->activate_mode = AW86214_HAPTIC_RAM_MODE; + } else if ((duration >= aw86214->dts_info.duration_time[0]) && + (duration < aw86214->dts_info.duration_time[1])) { + aw86214->index = 2; /*2*/ + aw86214->activate_mode = AW86214_HAPTIC_RAM_MODE; + } else if ((duration >= aw86214->dts_info.duration_time[1]) && + (duration < aw86214->dts_info.duration_time[2])) { + aw86214->index = 1; /*1*/ + aw86214->activate_mode = AW86214_HAPTIC_RAM_MODE; + } else if (duration >= aw86214->dts_info.duration_time[2]) { + aw86214->index = 4; /*4*/ + aw86214->activate_mode = AW86214_HAPTIC_RAM_LOOP_MODE; + } else { + aw_dev_err("%s: duration time error, duration= %d\n", + __func__, duration); + aw86214->index = 0; + aw86214->activate_mode = AW86214_HAPTIC_NULL; + ret = -ERANGE; + } + + return ret; +} + +static int aw86214_haptic_get_ram_number(struct aw86214 *aw86214) +{ + unsigned char ram_data[3]; + unsigned int first_wave_addr = 0; + + aw_dev_info("%s enter!\n", __func__); + if (!aw86214->ram_init) { + aw_dev_err("%s: ram init faild, ram_num = 0!\n", __func__); + return -EPERM; + } + + mutex_lock(&aw86214->lock); + /* RAMINIT Enable */ + aw86214_haptic_raminit(aw86214, true); + aw86214_haptic_stop(aw86214); + aw86214_set_ram_addr(aw86214); + aw86214_i2c_read(aw86214, AW86214_REG_RAMDATA, ram_data, + AW_I2C_BYTE_THREE); + first_wave_addr = (ram_data[1] << 8 | ram_data[2]); + aw86214->ram.ram_num = + (first_wave_addr - aw86214->ram.base_addr - 1) / 4; + aw_dev_info("%s: ram_version = 0x%02x\n", __func__, ram_data[0]); + aw_dev_info("%s: first waveform addr = 0x%04x\n", __func__, + first_wave_addr); + aw_dev_info("%s: ram_num = %d\n", __func__, aw86214->ram.ram_num); + /* RAMINIT Disable */ + aw86214_haptic_raminit(aw86214, false); + mutex_unlock(&aw86214->lock); + + return 0; +} + + +static void aw86214_ram_check(const struct firmware *cont, void *context) +{ + struct aw86214 *aw86214 = context; + struct aw86214_container *aw86214_fw; + unsigned short check_sum = 0; + int i = 0; + int ret = 0; +#ifdef AW_READ_BIN_FLEXBALLY + static unsigned char load_cont; + int ram_timer_val = 1000; + + load_cont++; +#endif + aw_dev_info("%s enter\n", __func__); + if (!cont) { + aw_dev_err("%s: failed to read %s\n", __func__, + aw86214_ram_name); + release_firmware(cont); +#ifdef AW_READ_BIN_FLEXBALLY + if (load_cont <= 20) { + schedule_delayed_work(&aw86214->ram_work, + msecs_to_jiffies(ram_timer_val)); + aw_dev_info("%s:start hrtimer: load_cont=%d\n", __func__, + load_cont); + } +#endif + return; + } + aw_dev_info("%s: loaded %s - size: %zu bytes\n", __func__, + aw86214_ram_name, cont ? cont->size : 0); +/* +* for(i=0; i < cont->size; i++) { +* aw_dev_info("%s: addr: 0x%04x, data: 0x%02X\n", +* __func__, i, *(cont->data+i)); +* } +*/ + /* check sum */ + for (i = 2; i < cont->size; i++) + check_sum += cont->data[i]; + if (check_sum == (unsigned short)((cont->data[0]<<8)|(cont->data[1]))) { + + aw_dev_info("%s: check sum pass: 0x%04x\n", __func__, + check_sum); + aw86214->ram.check_sum = check_sum; + } else { + aw_dev_err("%s: check sum err: check_sum=0x%04x\n", __func__, + check_sum); + return; + } + + /* aw86214 ram update less then 128kB */ + aw86214_fw = kzalloc(cont->size + sizeof(int), GFP_KERNEL); + if (!aw86214_fw) { + release_firmware(cont); + aw_dev_err("%s: Error allocating memory\n", __func__); + return; + } + aw86214_fw->len = cont->size; + memcpy(aw86214_fw->data, cont->data, cont->size); + release_firmware(cont); + ret = aw86214_container_update(aw86214, aw86214_fw); + if (ret) { + kfree(aw86214_fw); + aw86214->ram.len = 0; + aw_dev_err("%s: ram firmware update failed!\n", __func__); + } else { + aw86214->ram_init = 1; + aw86214->ram.len = aw86214_fw->len; + kfree(aw86214_fw); + aw_dev_info("%s: ram firmware update complete!\n", __func__); + } + aw86214_haptic_get_ram_number(aw86214); +} + +static int aw86214_ram_update(struct aw86214 *aw86214) +{ + aw86214->ram_init = 0; + + return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + aw86214_ram_name, aw86214->dev, + GFP_KERNEL, aw86214, aw86214_ram_check); +} + +static enum hrtimer_restart aw86214_vibrator_timer_func(struct hrtimer *timer) +{ + struct aw86214 *aw86214 = container_of(timer, struct aw86214, timer); + + aw_dev_info("%s enter\n", __func__); + aw86214->state = 0; + schedule_work(&aw86214->vibrator_work); + + return HRTIMER_NORESTART; +} + +/***************************************************** + * + * motor protect + * + *****************************************************/ +static int aw86214_haptic_swicth_motor_protect_config(struct aw86214 *aw86214, + unsigned char addr, + unsigned char val) +{ + aw_dev_info("%s enter\n", __func__); + if (addr == 1) { + aw86214_i2c_write_bits(aw86214, AW86214_REG_DETCFG1, + AW86214_BIT_DETCFG1_PRCT_MODE_MASK, + AW86214_BIT_DETCFG1_PRCT_MODE_VALID); + aw86214_i2c_write_bits(aw86214, AW86214_REG_PWMCFG1, + AW86214_BIT_PWMCFG1_PRC_EN_MASK, + AW86214_BIT_PWMCFG1_PRC_ENABLE); + aw86214_i2c_write_bits(aw86214, AW86214_REG_PWMCFG3, + AW86214_BIT_PWMCFG3_PR_EN_MASK, + AW86214_BIT_PWMCFG3_PR_ENABLE); + } else if (addr == 0) { + aw86214_i2c_write_bits(aw86214, AW86214_REG_DETCFG1, + AW86214_BIT_DETCFG1_PRCT_MODE_MASK, + AW86214_BIT_DETCFG1_PRCT_MODE_INVALID); + aw86214_i2c_write_bits(aw86214, AW86214_REG_PWMCFG1, + AW86214_BIT_PWMCFG1_PRC_EN_MASK, + AW86214_BIT_PWMCFG1_PRC_DISABLE); + aw86214_i2c_write_bits(aw86214, AW86214_REG_PWMCFG3, + AW86214_BIT_PWMCFG3_PR_EN_MASK, + AW86214_BIT_PWMCFG3_PR_DISABLE); + } else if (addr == 0x2d) { + aw86214_i2c_write_bits(aw86214, AW86214_REG_PWMCFG1, + AW86214_BIT_PWMCFG1_PRCTIME_MASK, val); + } else if (addr == 0x3e) { + aw86214_i2c_write_bits(aw86214, AW86214_REG_PWMCFG3, + AW86214_BIT_PWMCFG3_PRLVL_MASK, val); + } else if (addr == 0x3f) { + aw86214_i2c_write(aw86214, AW86214_REG_PWMCFG4, &val, + AW_I2C_BYTE_ONE); + } + return 0; +} + +static int aw86214_haptic_f0_calibration(struct aw86214 *aw86214) +{ + int ret = 0; + unsigned char reg_val = 0; + unsigned int f0_limit = 0; + char f0_cali_lra = 0; + int f0_cali_step = 0; + unsigned int f0_cali_min = aw86214->dts_info.f0_ref * + (100 - aw86214->dts_info.f0_cali_percent) / 100; + unsigned int f0_cali_max = aw86214->dts_info.f0_ref * + (100 + aw86214->dts_info.f0_cali_percent) / 100; + + aw_dev_info("%s enter\n", __func__); + /* + * aw86214_haptic_upload_lra(aw86214, AW86214_WRITE_ZERO); + */ + if (aw86214_haptic_cont_get_f0(aw86214)) { + aw_dev_err("%s get f0 error, user defafult f0\n", __func__); + } else { + /* max and min limit */ + f0_limit = aw86214->f0; + aw_dev_info("%s f0_ref = %d, f0_cali_min = %d, f0_cali_max = %d, f0 = %d\n", + __func__, aw86214->dts_info.f0_ref, + f0_cali_min, f0_cali_max, aw86214->f0); + + if ((aw86214->f0 < f0_cali_min) || aw86214->f0 > f0_cali_max) { + aw_dev_err("%s f0 calibration out of range = %d!\n", + __func__, aw86214->f0); + f0_limit = aw86214->dts_info.f0_ref; + return -ERANGE; + } + aw_dev_info("%s f0_limit = %d\n", __func__, (int)f0_limit); + /* calculate cali step */ + f0_cali_step = 100000 * ((int)f0_limit - + (int)aw86214->dts_info.f0_ref) / + ((int)f0_limit * 24); + aw_dev_info("%s f0_cali_step = %d\n", __func__, f0_cali_step); + if (f0_cali_step >= 0) { /*f0_cali_step >= 0 */ + if (f0_cali_step % 10 >= 5) + f0_cali_step = 32 + (f0_cali_step / 10 + 1); + else + f0_cali_step = 32 + f0_cali_step / 10; + } else { /* f0_cali_step < 0 */ + if (f0_cali_step % 10 <= -5) + f0_cali_step = 32 + (f0_cali_step / 10 - 1); + else + f0_cali_step = 32 + f0_cali_step / 10; + } + if (f0_cali_step > 31) + f0_cali_lra = (char)f0_cali_step - 32; + else + f0_cali_lra = (char)f0_cali_step + 32; + /* update cali step */ + aw86214->f0_cali_data = (int)f0_cali_lra; + aw86214_haptic_upload_lra(aw86214, AW86214_F0_CALI); + aw86214_i2c_read(aw86214, AW86214_REG_TRIMCFG3, ®_val, + AW_I2C_BYTE_ONE); + aw_dev_info("%s: final f0_cali_data = 0x%02X\n", + __func__, reg_val); + } + /* restore standby work mode */ + aw86214_haptic_stop(aw86214); + return ret; +} + +/***************************************************** + * + * haptic cont + * + *****************************************************/ +static int aw86214_haptic_cont(struct aw86214 *aw86214) +{ + unsigned char reg_val = 0; + + aw_dev_info("%s enter\n", __func__); + + /* work mode */ + aw86214_haptic_play_mode(aw86214, AW86214_HAPTIC_CONT_MODE); + /* cont config */ + aw86214_i2c_write_bits(aw86214, AW86214_REG_CONTCFG6, + AW86214_BIT_CONTCFG6_TRACK_EN_MASK, + AW86214_BIT_CONTCFG6_TRACK_ENABLE); + /* f0 driver level */ + aw86214_i2c_write_bits(aw86214, AW86214_REG_CONTCFG6, + AW86214_BIT_CONTCFG6_DRV1_LVL_MASK, + aw86214->cont_drv1_lvl); + reg_val = (unsigned char)aw86214->cont_drv2_lvl; + aw86214_i2c_write(aw86214, AW86214_REG_CONTCFG7, ®_val, + AW_I2C_BYTE_ONE); + /* DRV2_TIME */ + reg_val = 0xFF; + aw86214_i2c_write(aw86214, AW86214_REG_CONTCFG9, ®_val, + AW_I2C_BYTE_ONE); + /* cont play go */ + aw86214_haptic_play_go(aw86214); + return 0; +} + +static int aw86214_haptic_play_wav_seq(struct aw86214 *aw86214, + unsigned char flag) +{ + aw_dev_info("%s enter\n", __func__); + if (flag) { + aw86214_haptic_play_mode(aw86214, AW86214_HAPTIC_RAM_MODE); + aw86214_haptic_play_go(aw86214); + } + return 0; +} + + +static void aw86214_haptic_misc_para_init(struct aw86214 *aw86214) +{ + unsigned char reg_array[4] = {0}; + + aw_dev_info("%s enter\n", __func__); + + aw86214_ver_a_init(aw86214); + + aw86214->cont_drv1_lvl = aw86214->dts_info.cont_drv1_lvl_dt; + aw86214->cont_drv2_lvl = aw86214->dts_info.cont_drv2_lvl_dt; + aw86214->cont_drv1_time = aw86214->dts_info.cont_drv1_time_dt; + aw86214->cont_drv2_time = aw86214->dts_info.cont_drv2_time_dt; + aw86214->cont_wait_num = aw86214->dts_info.cont_wait_num_dt; + + /* SIN_H */ + reg_array[0] = (unsigned char)aw86214->dts_info.sine_array[0]; + /* SIN_L */ + reg_array[1] = (unsigned char)aw86214->dts_info.sine_array[1]; + /* COS_H */ + reg_array[2] = (unsigned char)aw86214->dts_info.sine_array[2]; + /* COS_L */ + reg_array[3] = (unsigned char)aw86214->dts_info.sine_array[3]; + + aw86214_i2c_write(aw86214, AW86214_REG_SYSCTRL3, reg_array, + AW_I2C_BYTE_FOUR); + + /* d2s_gain */ + if (!aw86214->dts_info.d2s_gain) { + aw_dev_err("%s aw86214->dts_info.d2s_gain = 0!\n", __func__); + } else { + aw86214_i2c_write_bits(aw86214, AW86214_REG_SYSCTRL7, + AW86214_BIT_SYSCTRL7_D2S_GAIN_MASK, + aw86214->dts_info.d2s_gain); + } + + if (aw86214->dts_info.cont_tset && aw86214->dts_info.cont_bemf_set) { + reg_array[0] = (unsigned char)aw86214->dts_info.cont_tset; + reg_array[1] = (unsigned char)aw86214->dts_info.cont_bemf_set; + aw86214_i2c_write_bits(aw86214, AW86214_REG_CONTCFG13, + (AW86214_BIT_CONTCFG13_TSET_MASK & + AW86214_BIT_CONTCFG13_BEME_SET_MASK), + ((reg_array[0] << 4)| + reg_array[1])); + } +} + +/***************************************************** + * + * offset calibration + * + *****************************************************/ +static int aw86214_haptic_offset_calibration(struct aw86214 *aw86214) +{ + unsigned int cont = 2000; + unsigned char reg_val = 0; + + aw_dev_info("%s enter\n", __func__); + + aw86214_haptic_raminit(aw86214, true); + + aw86214_i2c_write_bits(aw86214, AW86214_REG_DETCFG2, + AW86214_BIT_DETCFG2_DIAG_GO_MASK, + AW86214_BIT_DETCFG2_DIAG_GO_ON); + while (1) { + aw86214_i2c_read(aw86214, AW86214_REG_DETCFG2, ®_val, + AW_I2C_BYTE_ONE); + if ((reg_val & 0x01) == 0 || cont == 0) + break; + cont--; + } + if (cont == 0) + aw_dev_err("%s calibration offset failed!\n", __func__); + aw86214_haptic_raminit(aw86214, false); + return 0; +} + +static int aw86214_haptic_set_pwm(struct aw86214 *aw86214, unsigned char mode) +{ + switch (mode) { + case AW86214_PWM_48K: + aw86214_i2c_write_bits(aw86214, AW86214_REG_SYSCTRL2, + AW86214_BIT_SYSCTRL2_WAVDAT_MODE_MASK, + AW86214_BIT_SYSCTRL2_RATE_48K); + break; + case AW86214_PWM_24K: + aw86214_i2c_write_bits(aw86214, AW86214_REG_SYSCTRL2, + AW86214_BIT_SYSCTRL2_WAVDAT_MODE_MASK, + AW86214_BIT_SYSCTRL2_RATE_24K); + break; + case AW86214_PWM_12K: + aw86214_i2c_write_bits(aw86214, AW86214_REG_SYSCTRL2, + AW86214_BIT_SYSCTRL2_WAVDAT_MODE_MASK, + AW86214_BIT_SYSCTRL2_RATE_12K); + break; + default: + break; + } + return 0; +} + +/***************************************************** + * + * vbat mode + * + *****************************************************/ +static int aw86214_haptic_vbat_mode_config(struct aw86214 *aw86214, + unsigned char flag) +{ + if (flag == AW86214_HAPTIC_CONT_VBAT_HW_ADJUST_MODE) { + aw86214_i2c_write_bits(aw86214, AW86214_REG_SYSCTRL1, + AW86214_BIT_SYSCTRL1_VBAT_MODE_MASK, + AW86214_BIT_SYSCTRL1_VBAT_MODE_HW); + } else { + aw86214_i2c_write_bits(aw86214, AW86214_REG_SYSCTRL1, + AW86214_BIT_SYSCTRL1_VBAT_MODE_MASK, + AW86214_BIT_SYSCTRL1_VBAT_MODE_SW); + } + return 0; +} + +static void aw86214_ram_work_routine(struct work_struct *work) +{ + struct aw86214 *aw86214 = container_of(work, struct aw86214, + ram_work.work); + + aw_dev_info("%s enter\n", __func__); + aw86214_ram_update(aw86214); +} + +int aw86214_ram_work_init(struct aw86214 *aw86214) +{ + int ram_timer_val = 8000; + + aw_dev_info("%s enter\n", __func__); + INIT_DELAYED_WORK(&aw86214->ram_work, aw86214_ram_work_routine); + schedule_delayed_work(&aw86214->ram_work, + msecs_to_jiffies(ram_timer_val)); + return 0; +} + + +static int +aw86214_haptic_audio_ctr_list_insert(struct haptic_audio *haptic_audio, + struct haptic_ctr *haptic_ctr, + struct device *dev) +{ + struct haptic_ctr *p_new = NULL; + + p_new = kzalloc(sizeof(struct haptic_ctr), GFP_KERNEL); + if (p_new == NULL) + return -ENOMEM; + /* update new list info */ + p_new->cnt = haptic_ctr->cnt; + p_new->cmd = haptic_ctr->cmd; + p_new->play = haptic_ctr->play; + p_new->wavseq = haptic_ctr->wavseq; + p_new->loop = haptic_ctr->loop; + p_new->gain = haptic_ctr->gain; + + INIT_LIST_HEAD(&(p_new->list)); + list_add(&(p_new->list), &(haptic_audio->ctr_list)); + return 0; +} + +static int +aw86214_haptic_audio_ctr_list_clear(struct haptic_audio *haptic_audio) +{ + struct haptic_ctr *p_ctr = NULL; + struct haptic_ctr *p_ctr_bak = NULL; + + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), + list) { + list_del(&p_ctr->list); + kfree(p_ctr); + } + + return 0; +} + +static int aw86214_haptic_audio_off(struct aw86214 *aw86214) +{ + aw_dev_dbg("%s: enter\n", __func__); + mutex_lock(&aw86214->lock); + aw86214_haptic_set_gain(aw86214, 0x80); + aw86214_haptic_stop(aw86214); + aw86214->gun_type = AW_GUN_TYPE_DEF_VAL; + aw86214->bullet_nr = AW_BULLET_NR_DEF_VAL; + aw86214_haptic_audio_ctr_list_clear(&aw86214->haptic_audio); + mutex_unlock(&aw86214->lock); + return 0; +} + +static int aw86214_haptic_audio_init(struct aw86214 *aw86214) +{ + + aw_dev_dbg("%s enter\n", __func__); + aw86214_haptic_set_wav_seq(aw86214, 0x01, 0x00); + + return 0; +} + +static void aw86214_interrupt_clear(struct aw86214 *aw86214) +{ + unsigned char reg_val = 0; + + aw86214_i2c_read(aw86214, AW86214_REG_SYSINT, ®_val, + AW_I2C_BYTE_ONE); + aw_dev_dbg("%s: SYSINT=0x%02X\n", __func__, reg_val); +} + +static int aw86214_haptic_activate(struct aw86214 *aw86214) +{ + aw86214_i2c_write_bits(aw86214, AW86214_REG_SYSCTRL2, + AW86214_BIT_SYSCTRL2_STANDBY_MASK, + AW86214_BIT_SYSCTRL2_STANDBY_OFF); + aw86214_interrupt_clear(aw86214); + aw86214_i2c_write_bits(aw86214, AW86214_REG_SYSINTM, + AW86214_BIT_SYSINTM_UVLM_MASK, + AW86214_BIT_SYSINTM_UVLM_ON); + return 0; +} + +static int aw86214_haptic_start(struct aw86214 *aw86214) +{ + aw86214_haptic_activate(aw86214); + aw86214_haptic_play_go(aw86214); + return 0; +} + +static void aw86214_ctr_list_config(struct aw86214 *aw86214, + struct haptic_ctr *p_ctr, + struct haptic_ctr *p_ctr_bak, + struct haptic_audio *haptic_audio) +{ + unsigned int list_input_cnt = 0; + unsigned int list_output_cnt = 0; + unsigned int list_diff_cnt = 0; + unsigned int list_del_cnt = 0; + + list_for_each_entry_safe(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), list) { + list_input_cnt = p_ctr->cnt; + break; + } + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), list) { + list_output_cnt = p_ctr->cnt; + break; + } + if (list_input_cnt > list_output_cnt) + list_diff_cnt = list_input_cnt - list_output_cnt; + if (list_input_cnt < list_output_cnt) + list_diff_cnt = 32 + list_input_cnt - list_output_cnt; + if (list_diff_cnt > 2) { + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), list) { + if ((p_ctr->play == 0) && + (AW86214_HAPTIC_CMD_ENABLE == + (AW86214_HAPTIC_CMD_HAPTIC & p_ctr->cmd))) { + list_del(&p_ctr->list); + kfree(p_ctr); + list_del_cnt++; + } + if (list_del_cnt == list_diff_cnt) + break; + } + } +} + +static void aw86214_haptic_audio_work_routine(struct work_struct *work) +{ + struct aw86214 *aw86214 = container_of(work, + struct aw86214, + haptic_audio.work); + struct haptic_audio *haptic_audio = NULL; + struct haptic_ctr *p_ctr = NULL; + struct haptic_ctr *p_ctr_bak = NULL; + unsigned int ctr_list_flag = 0; + + aw_dev_dbg("%s enter\n", __func__); + + haptic_audio = &(aw86214->haptic_audio); + mutex_lock(&aw86214->haptic_audio.lock); + memset(&aw86214->haptic_audio.ctr, 0, + sizeof(struct haptic_ctr)); + ctr_list_flag = 0; + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), list) { + ctr_list_flag = 1; + break; + } + if (ctr_list_flag == 0) + aw_dev_info("%s: ctr list empty\n", __func__); + + if (ctr_list_flag == 1) + aw86214_ctr_list_config(aw86214, p_ctr, + p_ctr_bak, haptic_audio); + + + /* get the last data from list */ + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), list) { + aw86214->haptic_audio.ctr.cnt = p_ctr->cnt; + aw86214->haptic_audio.ctr.cmd = p_ctr->cmd; + aw86214->haptic_audio.ctr.play = p_ctr->play; + aw86214->haptic_audio.ctr.wavseq = p_ctr->wavseq; + aw86214->haptic_audio.ctr.loop = p_ctr->loop; + aw86214->haptic_audio.ctr.gain = p_ctr->gain; + list_del(&p_ctr->list); + kfree(p_ctr); + break; + } + + if (aw86214->haptic_audio.ctr.play) { + aw_dev_info("%s: cnt=%d, cmd=%d, play=%d, wavseq=%d, loop=%d, gain=%d\n", + __func__, + aw86214->haptic_audio.ctr.cnt, + aw86214->haptic_audio.ctr.cmd, + aw86214->haptic_audio.ctr.play, + aw86214->haptic_audio.ctr.wavseq, + aw86214->haptic_audio.ctr.loop, + aw86214->haptic_audio.ctr.gain); + } + mutex_unlock(&aw86214->haptic_audio.lock); + + /*haptic play control*/ + if (AW86214_HAPTIC_CMD_ENABLE == + (AW86214_HAPTIC_CMD_HAPTIC & aw86214->haptic_audio.ctr.cmd)) { + if (aw86214->haptic_audio.ctr.play == + AW86214_HAPTIC_PLAY_ENABLE) { + aw_dev_info("%s: haptic_audio_play_start\n", __func__); + aw_dev_info("%s: normal haptic start\n", __func__); + mutex_lock(&aw86214->lock); + aw86214_haptic_stop(aw86214); + aw86214_haptic_play_mode(aw86214, + AW86214_HAPTIC_RAM_MODE); + aw86214_haptic_set_wav_seq(aw86214, 0x00, + aw86214->haptic_audio.ctr.wavseq); + aw86214_haptic_set_wav_loop(aw86214, 0x00, + aw86214->haptic_audio.ctr.loop); + aw86214_haptic_set_gain(aw86214, + aw86214->haptic_audio.ctr.gain); + aw86214_haptic_start(aw86214); + mutex_unlock(&aw86214->lock); + } else if (AW86214_HAPTIC_PLAY_STOP == + aw86214->haptic_audio.ctr.play) { + mutex_lock(&aw86214->lock); + aw86214_haptic_stop(aw86214); + mutex_unlock(&aw86214->lock); + } else if (AW86214_HAPTIC_PLAY_GAIN == + aw86214->haptic_audio.ctr.play) { + mutex_lock(&aw86214->lock); + aw86214_haptic_set_gain(aw86214, + aw86214->haptic_audio.ctr.gain); + mutex_unlock(&aw86214->lock); + } + } + + +} + +static enum hrtimer_restart +aw86214_haptic_audio_timer_func(struct hrtimer *timer) +{ + struct aw86214 *aw86214 = container_of(timer, + struct aw86214, haptic_audio.timer); + + aw_dev_dbg("%s enter\n", __func__); + schedule_work(&aw86214->haptic_audio.work); + + hrtimer_start(&aw86214->haptic_audio.timer, + ktime_set(aw86214->haptic_audio.timer_val/1000000, + (aw86214->haptic_audio.timer_val%1000000)*1000), + HRTIMER_MODE_REL); + return HRTIMER_NORESTART; +} + + +#ifdef TIMED_OUTPUT +static int aw86214_vibrator_get_time(struct timed_output_dev *dev) +{ + struct aw86214 *aw86214 = container_of(dev, struct aw86214, vib_dev); + + if (hrtimer_active(&aw86214->timer)) { + ktime_t r = hrtimer_get_remaining(&aw86214->timer); + + return ktime_to_ms(r); + } + return 0; +} + +static void aw86214_vibrator_enable(struct timed_output_dev *dev, int value) +{ + struct aw86214 *aw86214 = container_of(dev, struct aw86214, vib_dev); + + aw_dev_info("%s enter\n", __func__); + if (!aw86214->ram_init) { + aw_dev_err("%s: ram init failed, not allow to play!\n", + __func__); + return; + } + mutex_lock(&aw86214->lock); + aw86214_haptic_stop(aw86214); + if (value > 0) { + aw86214_brk_en(aw86214, false); + aw86214_haptic_ram_vbat_comp(aw86214, false); + aw86214_haptic_play_wav_seq(aw86214, value); + } + mutex_unlock(&aw86214->lock); + aw_dev_info("%s exit\n", __func__); +} +#else +static enum led_brightness aw86214_haptic_brightness_get(struct led_classdev + *cdev) +{ + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + + return aw86214->amplitude; +} + +static void aw86214_haptic_brightness_set(struct led_classdev *cdev, + enum led_brightness level) +{ + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + + aw_dev_info("%s enter\n", __func__); + if (!aw86214->ram_init) { + aw_dev_err("%s: ram init failed, not allow to play!\n", + __func__); + return; + } + if (aw86214->ram_update_flag < 0) + return; + aw86214->amplitude = level; + mutex_lock(&aw86214->lock); + aw86214_haptic_stop(aw86214); + if (aw86214->amplitude > 0) { + aw86214_brk_en(aw86214, false); + aw86214_haptic_ram_vbat_comp(aw86214, false); + aw86214_haptic_play_wav_seq(aw86214, aw86214->amplitude); + } + mutex_unlock(&aw86214->lock); +} +#endif + +static ssize_t aw86214_cont_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + ssize_t len = 0; + + aw86214_haptic_read_cont_f0(aw86214); + len += snprintf(buf + len, PAGE_SIZE - len, + "%d\n", aw86214->cont_f0); + return len; +} + +static ssize_t aw86214_cont_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + + aw86214_haptic_stop(aw86214); + aw86214_brk_en(aw86214, true); + if (val) + aw86214_haptic_cont(aw86214); + return count; +} + +static ssize_t aw86214_f0_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + ssize_t len = 0; + unsigned char reg = 0; + + mutex_lock(&aw86214->lock); + /* set d2s_gain to max to get better performance when cat f0 .*/ + aw86214_i2c_write_bits(aw86214, AW86214_REG_SYSCTRL7, + AW86214_BIT_SYSCTRL7_D2S_GAIN_MASK, + AW86214_BIT_SYSCTRL7_D2S_GAIN_40); + aw86214_i2c_read(aw86214, AW86214_REG_TRIMCFG3, ®, AW_I2C_BYTE_ONE); + aw86214_haptic_upload_lra(aw86214, AW86214_WRITE_ZERO); + aw86214_haptic_cont_get_f0(aw86214); + aw86214_i2c_write(aw86214, AW86214_REG_TRIMCFG3, ®, AW_I2C_BYTE_ONE); + /* set d2s_gain to default when cat f0 is finished.*/ + aw86214_i2c_write_bits(aw86214, AW86214_REG_SYSCTRL7, + AW86214_BIT_SYSCTRL7_D2S_GAIN_MASK, + aw86214->dts_info.d2s_gain); + mutex_unlock(&aw86214->lock); + len += snprintf(buf + len, PAGE_SIZE - len, + "%d\n", aw86214->f0); + return len; +} + +static ssize_t aw86214_f0_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + + return count; +} + +static ssize_t aw86214_reg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char i = 0; + unsigned char size = 0; + unsigned char cnt = 0; + unsigned char reg_array[AW_REG_MAX] = {0}; + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + + aw_dev_dbg("%s: enter!\n", __func__); + for (i = 0; i <= (AW86214_REG_TRIMCFG3 + 1); i++) { + + if (i == aw86214_reg_list[cnt] && + (cnt < sizeof(aw86214_reg_list))) { + size++; + cnt++; + continue; + } else { + if (size != 0) { + aw86214_i2c_read(aw86214, + aw86214_reg_list[cnt-size], + ®_array[cnt-size], size); + size = 0; + + } + } + } + + for (i = 0; i < sizeof(aw86214_reg_list); i++) { + len += snprintf(buf + len, PAGE_SIZE - len, + "reg:0x%02X=0x%02X\n", aw86214_reg_list[i], + reg_array[i]); + } + + return len; +} + +static ssize_t aw86214_reg_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + unsigned char reg_val = 0; + unsigned int databuf[2] = { 0, 0 }; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + reg_val = (unsigned char)databuf[1]; + aw86214_i2c_write(aw86214, (unsigned char)databuf[0], + ®_val, AW_I2C_BYTE_ONE); + } + + return count; +} + +static ssize_t aw86214_duration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + ktime_t time_rem; + s64 time_ms = 0; + + if (hrtimer_active(&aw86214->timer)) { + time_rem = hrtimer_get_remaining(&aw86214->timer); + time_ms = ktime_to_ms(time_rem); + } + return snprintf(buf, PAGE_SIZE, "%lldms\n", time_ms); +} + +static ssize_t aw86214_duration_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + /* setting 0 on duration is NOP for now */ + if (val <= 0) + return count; + rc = aw86214_haptic_ram_config(aw86214, val); + if (rc < 0) { + aw_dev_info("%s: ram config failed!\n", __func__); + return count; + } + aw86214->duration = val; + return count; +} + +static ssize_t aw86214_activate_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + + /* For now nothing to show */ + return snprintf(buf, PAGE_SIZE, "%d\n", aw86214->state); +} + +static ssize_t aw86214_activate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + unsigned int val = 0; + int rc = 0; + + if (!aw86214->ram_init) { + aw_dev_err("%s: ram init failed, not allow to play!\n", + __func__); + return count; + } + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + aw_dev_info("%s: value=%d\n", __func__, val); + mutex_lock(&aw86214->lock); + hrtimer_cancel(&aw86214->timer); + aw86214->state = val; + mutex_unlock(&aw86214->lock); + schedule_work(&aw86214->vibrator_work); + return count; +} + +static ssize_t aw86214_seq_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + size_t count = 0; + unsigned char i = 0; + unsigned char reg_val[AW86214_SEQUENCER_SIZE] = {0}; + + aw86214_i2c_read(aw86214, AW86214_REG_WAVCFG1, reg_val, + AW86214_SEQUENCER_SIZE); + for (i = 0; i < AW86214_SEQUENCER_SIZE; i++) { + count += snprintf(buf+count, PAGE_SIZE-count, + "seq%d: 0x%02x\n", i+1, reg_val[i]); + aw86214->seq[i] = reg_val[i]; + } + return count; +} + +static ssize_t aw86214_seq_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + unsigned int databuf[2] = { 0, 0 }; + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + if (databuf[0] > AW86214_SEQUENCER_SIZE || + databuf[1] > aw86214->ram.ram_num) { + aw_dev_err("%s input value out of range\n", __func__); + return count; + } + aw_dev_info("%s: seq%d=0x%02X\n", __func__, + databuf[0], databuf[1]); + mutex_lock(&aw86214->lock); + aw86214->seq[databuf[0]] = (unsigned char)databuf[1]; + aw86214_haptic_set_wav_seq(aw86214, (unsigned char)databuf[0], + aw86214->seq[databuf[0]]); + mutex_unlock(&aw86214->lock); + } + return count; +} + +static ssize_t aw86214_loop_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + size_t count = 0; + unsigned char i = 0; + unsigned char reg_val[AW86214_SEQUENCER_LOOP_SIZE] = {0}; + + aw86214_i2c_read(aw86214, AW86214_REG_WAVCFG9, reg_val, + AW86214_SEQUENCER_LOOP_SIZE); + + for (i = 0; i < AW86214_SEQUENCER_LOOP_SIZE; i++) { + aw86214->loop[i*2+0] = (reg_val[i] >> 4) & 0x0F; + aw86214->loop[i*2+1] = (reg_val[i] >> 0) & 0x0F; + + count += snprintf(buf+count, PAGE_SIZE-count, + "seq%d_loop: 0x%02x\n", i*2+1, aw86214->loop[i*2+0]); + count += snprintf(buf+count, PAGE_SIZE-count, + "seq%d_loop: 0x%02x\n", i*2+2, aw86214->loop[i*2+1]); + } + return count; +} + +static ssize_t aw86214_loop_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + unsigned int databuf[2] = { 0, 0 }; + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + aw_dev_info("%s: seq%d loop=0x%02X\n", __func__, + databuf[0], databuf[1]); + mutex_lock(&aw86214->lock); + aw86214->loop[databuf[0]] = (unsigned char)databuf[1]; + aw86214_haptic_set_wav_loop(aw86214, (unsigned char)databuf[0], + aw86214->loop[databuf[0]]); + mutex_unlock(&aw86214->lock); + } + return count; +} + +static ssize_t aw86214_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", aw86214->state); +} + +static ssize_t aw86214_state_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return count; +} + +static ssize_t aw86214_activate_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", + aw86214->activate_mode); +} + +static ssize_t aw86214_activate_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + mutex_lock(&aw86214->lock); + aw86214->activate_mode = val; + mutex_unlock(&aw86214->lock); + return count; +} + +static ssize_t aw86214_index_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + unsigned char reg_val = 0; + + aw86214_i2c_read(aw86214, AW86214_REG_WAVCFG1, ®_val, + AW_I2C_BYTE_ONE); + aw86214->index = reg_val; + return snprintf(buf, PAGE_SIZE, "%d\n", aw86214->index); +} + +static ssize_t aw86214_index_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + if (val > aw86214->ram.ram_num) { + aw_dev_err("%s: input value out of range!\n", __func__); + return count; + } + aw_dev_info("%s: value=%d\n", __func__, val); + mutex_lock(&aw86214->lock); + aw86214->index = val; + aw86214_haptic_set_repeat_wav_seq(aw86214, aw86214->index); + mutex_unlock(&aw86214->lock); + return count; +} + +static ssize_t aw86214_gain_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + + return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw86214->gain); +} + +static ssize_t aw86214_gain_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + + aw_dev_info("%s: value=%d\n", __func__, val); + if (val >= 0x80) + val = 0x80; + mutex_lock(&aw86214->lock); + aw86214->gain = val; + aw86214_haptic_set_gain(aw86214, aw86214->gain); + mutex_unlock(&aw86214->lock); + return count; +} + +static ssize_t aw86214_ram_update_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int cnt = 0; + int i = 0; + int size = 0; + ssize_t len = 0; + unsigned char ram_data[AW_RAMDATA_RD_BUFFER_SIZE] = {0}; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + + /* RAMINIT Enable */ + aw86214_haptic_raminit(aw86214, true); + aw86214_haptic_stop(aw86214); + aw86214_set_ram_addr(aw86214); + len += snprintf(buf + len, PAGE_SIZE - len, + "haptic_ram len = %d\n", aw86214->ram.len); + while (cnt < aw86214->ram.len) { + if ((aw86214->ram.len - cnt) < AW_RAMDATA_RD_BUFFER_SIZE) + size = aw86214->ram.len - cnt; + else + size = AW_RAMDATA_RD_BUFFER_SIZE; + + aw86214_i2c_read(aw86214, AW86214_REG_RAMDATA, + ram_data, size); + for (i = 0; i < size; i++) { + len += snprintf(buf + len, PAGE_SIZE - len, + "0x%02X,", ram_data[i]); + } + cnt += size; + } + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + /* RAMINIT Disable */ + aw86214_haptic_raminit(aw86214, false); + return len; +} + +static ssize_t aw86214_ram_update_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + if (val) + aw86214_ram_update(aw86214); + return count; +} + +static ssize_t aw86214_f0_save_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, "f0_cali_data = 0x%02X\n", + aw86214->f0_cali_data); + + return len; +} + +static ssize_t aw86214_f0_save_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + aw86214->f0_cali_data = val; + return count; +} + +static ssize_t aw86214_ram_vbat_compensate_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + ssize_t len = 0; + + len += + snprintf(buf + len, PAGE_SIZE - len, "ram_vbat_compensate = %d\n", + aw86214->ram_vbat_compensate); + + return len; +} + +static ssize_t aw86214_ram_vbat_compensate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + + mutex_lock(&aw86214->lock); + if (val) + aw86214->ram_vbat_compensate = + AW86214_HAPTIC_RAM_VBAT_COMP_ENABLE; + else + aw86214->ram_vbat_compensate = + AW86214_HAPTIC_RAM_VBAT_COMP_DISABLE; + mutex_unlock(&aw86214->lock); + + return count; +} + +static ssize_t aw86214_cali_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + ssize_t len = 0; + + mutex_lock(&aw86214->lock); + aw86214_haptic_upload_lra(aw86214, AW86214_F0_CALI); + aw86214_haptic_cont_get_f0(aw86214); + mutex_unlock(&aw86214->lock); + len += snprintf(buf + len, PAGE_SIZE - len, + "%d\n", aw86214->f0); + return len; +} + +static ssize_t aw86214_cali_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + unsigned int val = 0; + int i; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + if (val) { + mutex_lock(&aw86214->lock); + aw86214_haptic_upload_lra(aw86214, AW86214_WRITE_ZERO); + for (i = 0; i < 2; i++) { + aw86214_haptic_f0_calibration(aw86214); + mdelay(20); + } + mutex_unlock(&aw86214->lock); + } + return count; +} + +static ssize_t aw86214_cont_wait_num_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "cont_wait_num = 0x%02X\n", aw86214->cont_wait_num); + return len; +} + +static ssize_t aw86214_cont_wait_num_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned char reg_val = 0; + int err, val; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + + err = kstrtoint(buf, 16, &val); + if (err != 0) { + aw_dev_err("%s format not match!", __func__); + return count; + } + aw86214->cont_wait_num = val; + reg_val = aw86214->cont_wait_num; + aw86214_i2c_write(aw86214, AW86214_REG_CONTCFG4, ®_val, + AW_I2C_BYTE_ONE); + return count; +} + +static ssize_t aw86214_cont_drv_lvl_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "cont_drv1_lvl = 0x%02X, cont_drv2_lvl = 0x%02X\n", + aw86214->cont_drv1_lvl, aw86214->cont_drv2_lvl); + return len; +} + +static ssize_t aw86214_cont_drv_lvl_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + unsigned char reg_val = 0; + unsigned int databuf[2] = { 0, 0 }; + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + aw86214->cont_drv1_lvl = databuf[0]; + aw86214->cont_drv2_lvl = databuf[1]; + aw86214_i2c_write_bits(aw86214, AW86214_REG_CONTCFG6, + AW86214_BIT_CONTCFG6_DRV1_LVL_MASK, + aw86214->cont_drv1_lvl); + reg_val = (unsigned char)aw86214->cont_drv2_lvl; + aw86214_i2c_write(aw86214, AW86214_REG_CONTCFG7, ®_val, + AW_I2C_BYTE_ONE); + } + return count; +} + +static ssize_t aw86214_cont_drv_time_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "cont_drv1_time = 0x%02X, cont_drv2_time = 0x%02X\n", + aw86214->cont_drv1_time, aw86214->cont_drv2_time); + return len; +} + +static ssize_t aw86214_cont_drv_time_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + unsigned char reg_val[2] = {0}; + unsigned int databuf[2] = { 0, 0 }; + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + aw86214->cont_drv1_time = databuf[0]; + aw86214->cont_drv2_time = databuf[1]; + reg_val[0] = (unsigned char)aw86214->cont_drv1_time; + reg_val[1] = (unsigned char)aw86214->cont_drv2_time; + aw86214_i2c_write(aw86214, AW86214_REG_CONTCFG8, reg_val, + AW_I2C_BYTE_TWO); + } + return count; +} + +static ssize_t aw86214_vbat_monitor_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + ssize_t len = 0; + + mutex_lock(&aw86214->lock); + aw86214_haptic_get_vbat(aw86214); + len += snprintf(buf + len, PAGE_SIZE - len, "vbat_monitor = %d\n", + aw86214->vbat); + mutex_unlock(&aw86214->lock); + + return len; +} + +static ssize_t aw86214_vbat_monitor_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return count; +} + +static ssize_t aw86214_lra_resistance_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + ssize_t len = 0; + + aw86214_haptic_get_lra_resistance(aw86214); + len += snprintf(buf + len, PAGE_SIZE - len, "lra_resistance = %d\n", + aw86214->lra); + return len; +} + +static ssize_t aw86214_lra_resistance_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return count; +} + +static ssize_t aw86214_prctmode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + ssize_t len = 0; + unsigned char reg_val = 0; + + aw86214_i2c_read(aw86214, AW86214_REG_DETCFG1, ®_val, + AW_I2C_BYTE_ONE); + + len += snprintf(buf + len, PAGE_SIZE - len, "prctmode = %d\n", + reg_val & 0x08); + return len; +} + +static ssize_t aw86214_prctmode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + unsigned int databuf[2] = { 0, 0 }; + unsigned int addr = 0; + unsigned int val = 0; + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + addr = databuf[0]; + val = databuf[1]; + mutex_lock(&aw86214->lock); + aw86214_haptic_swicth_motor_protect_config(aw86214, addr, val); + mutex_unlock(&aw86214->lock); + } + return count; +} + +static ssize_t aw86214_gun_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + + return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw86214->gun_type); + +} + +static ssize_t aw86214_gun_type_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + aw_dev_info("%s: value=%d\n", __func__, val); + mutex_lock(&aw86214->lock); + aw86214->gun_type = val; + mutex_unlock(&aw86214->lock); + return count; +} + +static ssize_t aw86214_bullet_nr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + + return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw86214->bullet_nr); +} + +static ssize_t aw86214_bullet_nr_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + aw_dev_info("%s: value=%d\n", __func__, val); + mutex_lock(&aw86214->lock); + aw86214->bullet_nr = val; + mutex_unlock(&aw86214->lock); + return count; +} + +static ssize_t aw86214_haptic_audio_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, + "%d\n", aw86214->haptic_audio.ctr.cnt); + return len; +} + +static int aw86214_haptic_audio_config(struct aw86214 *aw86214, + unsigned int databuf[]) +{ + struct haptic_ctr *hap_ctr = NULL; + + hap_ctr = kzalloc(sizeof(struct haptic_ctr), GFP_KERNEL); + if (hap_ctr == NULL) + return -ENOMEM; + mutex_lock(&aw86214->haptic_audio.lock); + hap_ctr->cnt = (unsigned char)databuf[0]; + hap_ctr->cmd = (unsigned char)databuf[1]; + hap_ctr->play = (unsigned char)databuf[2]; + hap_ctr->wavseq = (unsigned char)databuf[3]; + hap_ctr->loop = (unsigned char)databuf[4]; + hap_ctr->gain = (unsigned char)databuf[5]; + aw86214_haptic_audio_ctr_list_insert(&aw86214->haptic_audio, + hap_ctr, aw86214->dev); + if (hap_ctr->cmd == 0xff) { + aw_dev_info("%s: haptic_audio stop\n", __func__); + if (hrtimer_active(&aw86214->haptic_audio.timer)) { + aw_dev_info("%s: cancel haptic_audio_timer\n", + __func__); + hrtimer_cancel(&aw86214->haptic_audio.timer); + aw86214->haptic_audio.ctr.cnt = 0; + aw86214_haptic_audio_off(aw86214); + } + } else { + if (hrtimer_active(&aw86214->haptic_audio.timer)) { + } else { + aw_dev_info("%s: start haptic_audio_timer\n", + __func__); + aw86214_haptic_audio_init(aw86214); + hrtimer_start(&aw86214->haptic_audio.timer, + ktime_set(aw86214->haptic_audio.delay_val/1000000, + (aw86214->haptic_audio.delay_val%1000000)*1000), + HRTIMER_MODE_REL); + } + } + mutex_unlock(&aw86214->haptic_audio.lock); + kfree(hap_ctr); + return 0; +} + +static ssize_t aw86214_haptic_audio_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + unsigned int databuf[6] = {0}; + + if (!aw86214->ram_init) + return count; + + if (sscanf(buf, "%d %d %d %d %d %d", + &databuf[0], &databuf[1], &databuf[2], + &databuf[3], &databuf[4], &databuf[5]) == 6) { + if (databuf[2]) { + aw_dev_dbg("%s: cnt=%d, cmd=%d, play=%d\n", __func__, + databuf[0], databuf[1], databuf[2]); + aw_dev_dbg("%s: wavseq=%d, loop=%d, gain=%d\n", + __func__, databuf[3], databuf[4], + databuf[5]); + aw86214_haptic_audio_config(aw86214, databuf); + } + + } + return count; +} + +static ssize_t aw86214_ram_num_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + ssize_t len = 0; + + aw86214_haptic_get_ram_number(aw86214); + len += snprintf(buf+len, PAGE_SIZE-len, + "ram_num = %d\n", aw86214->ram.ram_num); + return len; +} + +static ssize_t aw86214_awrw_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + unsigned char i = 0; + unsigned char reg_num = aw86214->aw_i2c_package.reg_num; + unsigned char flag = aw86214->aw_i2c_package.flag; + unsigned char *reg_data = aw86214->aw_i2c_package.reg_data; + ssize_t len = 0; + + if (!reg_num) { + aw_dev_err("%s: awrw parameter error\n", __func__); + return len; + } + if (flag == AW86214_READ) { + for (i = 0; i < reg_num; i++) { + len += snprintf(buf + len, PAGE_SIZE - len, + "0x%02x,", reg_data[i]); + } + + len += snprintf(buf + len - 1, PAGE_SIZE - len, "\n"); + } + + return len; +} + +static ssize_t aw86214_awrw_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int datatype[3] = { 0 }; + int ret = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw86214 *aw86214 = container_of(cdev, struct aw86214, vib_dev); + + if (sscanf(buf, "%x %x %x", &datatype[0], &datatype[1], + &datatype[2]) == 3) { + if (!datatype[1]) { + aw_dev_err("%s: awrw parameter error\n", __func__); + return count; + } + aw86214->aw_i2c_package.flag = (unsigned char)datatype[0]; + aw86214->aw_i2c_package.reg_num = (unsigned char)datatype[1]; + aw86214->aw_i2c_package.first_addr = (unsigned char)datatype[2]; + + if (aw86214->aw_i2c_package.flag == AW86214_WRITE) { + ret = aw86214_parse_data(aw86214, buf); + if (ret < 0) + return count; + aw86214_i2c_write(aw86214, + aw86214->aw_i2c_package.first_addr, + aw86214->aw_i2c_package.reg_data, + aw86214->aw_i2c_package.reg_num); + } + if (aw86214->aw_i2c_package.flag == AW86214_READ) + aw86214_i2c_read(aw86214, + aw86214->aw_i2c_package.first_addr, + aw86214->aw_i2c_package.reg_data, + aw86214->aw_i2c_package.reg_num); + } else + aw_dev_err("%s: missing number of parameters\n", __func__); + + return count; +} + +static DEVICE_ATTR(f0, 0644, aw86214_f0_show, aw86214_f0_store); +static DEVICE_ATTR(cont, 0644, aw86214_cont_show, aw86214_cont_store); +static DEVICE_ATTR(reg, 0644, aw86214_reg_show, aw86214_reg_store); +static DEVICE_ATTR(duration, 0644, aw86214_duration_show, + aw86214_duration_store); +static DEVICE_ATTR(index, 0644, aw86214_index_show, aw86214_index_store); +static DEVICE_ATTR(activate, 0644, aw86214_activate_show, + aw86214_activate_store); +static DEVICE_ATTR(activate_mode, 0644, aw86214_activate_mode_show, + aw86214_activate_mode_store); +static DEVICE_ATTR(seq, 0644, aw86214_seq_show, aw86214_seq_store); +static DEVICE_ATTR(loop, 0644, aw86214_loop_show, aw86214_loop_store); +static DEVICE_ATTR(state, 0644, aw86214_state_show, aw86214_state_store); +static DEVICE_ATTR(gain, 0644, aw86214_gain_show, aw86214_gain_store); +static DEVICE_ATTR(ram_update, 0644, aw86214_ram_update_show, + aw86214_ram_update_store); +static DEVICE_ATTR(f0_save, 0644, aw86214_f0_save_show, aw86214_f0_save_store); +static DEVICE_ATTR(ram_vbat_comp, 0644, aw86214_ram_vbat_compensate_show, + aw86214_ram_vbat_compensate_store); +static DEVICE_ATTR(cali, 0644, aw86214_cali_show, aw86214_cali_store); +static DEVICE_ATTR(cont_wait_num, 0644, aw86214_cont_wait_num_show, + aw86214_cont_wait_num_store); +static DEVICE_ATTR(cont_drv_lvl, 0644, aw86214_cont_drv_lvl_show, + aw86214_cont_drv_lvl_store); +static DEVICE_ATTR(cont_drv_time, 0644, aw86214_cont_drv_time_show, + aw86214_cont_drv_time_store); +static DEVICE_ATTR(vbat_monitor, 0644, aw86214_vbat_monitor_show, + aw86214_vbat_monitor_store); +static DEVICE_ATTR(lra_resistance, 0644, aw86214_lra_resistance_show, + aw86214_lra_resistance_store); +static DEVICE_ATTR(prctmode, 0644, aw86214_prctmode_show, + aw86214_prctmode_store); +static DEVICE_ATTR(gun_type, 0644, aw86214_gun_type_show, + aw86214_gun_type_store); +static DEVICE_ATTR(bullet_nr, 0644, aw86214_bullet_nr_show, + aw86214_bullet_nr_store); +static DEVICE_ATTR(haptic_audio, 0644, aw86214_haptic_audio_show, + aw86214_haptic_audio_store); +static DEVICE_ATTR(ram_num, 0644, aw86214_ram_num_show, NULL); +static DEVICE_ATTR(awrw, 0644, aw86214_awrw_show, aw86214_awrw_store); +static struct attribute *aw86214_vibrator_attributes[] = { + &dev_attr_state.attr, + &dev_attr_duration.attr, + &dev_attr_activate.attr, + &dev_attr_activate_mode.attr, + &dev_attr_index.attr, + &dev_attr_gain.attr, + &dev_attr_seq.attr, + &dev_attr_loop.attr, + &dev_attr_reg.attr, + &dev_attr_ram_update.attr, + &dev_attr_f0.attr, + &dev_attr_f0_save.attr, + &dev_attr_cali.attr, + &dev_attr_cont.attr, + &dev_attr_cont_wait_num.attr, + &dev_attr_cont_drv_lvl.attr, + &dev_attr_cont_drv_time.attr, + &dev_attr_vbat_monitor.attr, + &dev_attr_lra_resistance.attr, + &dev_attr_prctmode.attr, + &dev_attr_ram_vbat_comp.attr, + &dev_attr_gun_type.attr, + &dev_attr_bullet_nr.attr, + &dev_attr_haptic_audio.attr, + &dev_attr_ram_num.attr, + &dev_attr_awrw.attr, + NULL +}; + +struct attribute_group aw86214_vibrator_attribute_group = { + .attrs = aw86214_vibrator_attributes +}; + +static void aw86214_haptic_ram_play(struct aw86214 *aw86214, unsigned char type) +{ + aw_dev_info("%s index = %d\n", __func__, aw86214->index); + + mutex_lock(&aw86214->ram_lock); + if (type == AW86214_HAPTIC_RAM_LOOP_MODE) + aw86214_haptic_set_repeat_wav_seq(aw86214, aw86214->index); + + if (type == AW86214_HAPTIC_RAM_MODE) { + aw86214_haptic_set_wav_seq(aw86214, 0x00, aw86214->index); + aw86214_haptic_set_wav_seq(aw86214, 0x01, 0x00); + aw86214_haptic_set_wav_loop(aw86214, 0x00, 0x00); + } + aw86214_haptic_play_mode(aw86214, type); + aw86214_haptic_start(aw86214); + mutex_unlock(&aw86214->ram_lock); +} + +static void aw86214_vibrator_work_routine(struct work_struct *work) +{ + struct aw86214 *aw86214 = container_of(work, struct aw86214, + vibrator_work); + + aw_dev_info("%s enter\n", __func__); + + mutex_lock(&aw86214->lock); + /* Enter standby mode */ + aw86214_haptic_stop(aw86214); + aw86214_haptic_upload_lra(aw86214, AW86214_F0_CALI); + if (aw86214->state) { + if (aw86214->activate_mode == AW86214_HAPTIC_RAM_MODE) { + aw86214_brk_en(aw86214, false); + aw86214_haptic_ram_vbat_comp(aw86214, false); + aw86214_haptic_ram_play(aw86214, + AW86214_HAPTIC_RAM_MODE); + } else if (aw86214->activate_mode == + AW86214_HAPTIC_RAM_LOOP_MODE) { + aw86214_haptic_ram_vbat_comp(aw86214, true); + aw86214_haptic_ram_play(aw86214, + AW86214_HAPTIC_RAM_LOOP_MODE); + /* run ms timer */ + hrtimer_start(&aw86214->timer, + ktime_set(aw86214->duration / 1000, + (aw86214->duration % 1000) * 1000000), + HRTIMER_MODE_REL); + } else if (aw86214->activate_mode == + AW86214_HAPTIC_CONT_MODE) { + aw86214_haptic_cont(aw86214); + /* run ms timer */ + hrtimer_start(&aw86214->timer, + ktime_set(aw86214->duration / 1000, + (aw86214->duration % 1000) * 1000000), + HRTIMER_MODE_REL); + } else { + aw_dev_err("%s: activate_mode error\n", + __func__); + } + } + mutex_unlock(&aw86214->lock); +} + + + +int aw86214_vibrator_init(struct aw86214 *aw86214) +{ + int ret = 0; + + aw_dev_info("%s enter\n", __func__); + +#ifdef TIMED_OUTPUT + aw_dev_info("%s: TIMED_OUT FRAMEWORK!\n", __func__); + aw86214->vib_dev.name = "awinic_vibrator"; + aw86214->vib_dev.get_time = aw86214_vibrator_get_time; + aw86214->vib_dev.enable = aw86214_vibrator_enable; + + ret = timed_output_dev_register(&(aw86214->vib_dev)); + if (ret < 0) { + aw_dev_err("%s: fail to create timed output dev\n", __func__); + return ret; + } + ret = sysfs_create_group(&aw86214->vib_dev.dev->kobj, + &aw86214_vibrator_attribute_group); + if (ret < 0) { + aw_dev_err("%s error creating sysfs attr files\n", + __func__); + return ret; + } +#else + aw_dev_info("%s: loaded in leds_cdev framework!\n", + __func__); + aw86214->vib_dev.name = "awinic_vibrator"; + aw86214->vib_dev.brightness_get = aw86214_haptic_brightness_get; + aw86214->vib_dev.brightness_set = aw86214_haptic_brightness_set; + + ret = devm_led_classdev_register(&aw86214->i2c->dev, &aw86214->vib_dev); + if (ret < 0) { + aw_dev_err("%s: fail to create led dev\n", __func__); + return ret; + } + ret = sysfs_create_group(&aw86214->vib_dev.dev->kobj, + &aw86214_vibrator_attribute_group); + if (ret < 0) { + aw_dev_err("%s error creating sysfs attr files\n", __func__); + return ret; + } +#endif + hrtimer_init(&aw86214->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + aw86214->timer.function = aw86214_vibrator_timer_func; + INIT_WORK(&aw86214->vibrator_work, + aw86214_vibrator_work_routine); + + mutex_init(&aw86214->lock); + mutex_init(&aw86214->ram_lock); + return 0; +} + +int aw86214_haptic_init(struct aw86214 *aw86214) +{ + int ret = 0; + unsigned char reg_val = 0; + unsigned char reg_array[8] = {0}; + + aw_dev_info("%s enter\n", __func__); + /* haptic audio */ + aw86214->haptic_audio.delay_val = 1; + aw86214->haptic_audio.timer_val = 21318; + INIT_LIST_HEAD(&(aw86214->haptic_audio.ctr_list)); + hrtimer_init(&aw86214->haptic_audio.timer, + CLOCK_MONOTONIC, HRTIMER_MODE_REL); + aw86214->haptic_audio.timer.function = aw86214_haptic_audio_timer_func; + INIT_WORK(&aw86214->haptic_audio.work, + aw86214_haptic_audio_work_routine); + mutex_init(&aw86214->haptic_audio.lock); + aw86214->gun_type = AW_GUN_TYPE_DEF_VAL; + aw86214->bullet_nr = AW_BULLET_NR_DEF_VAL; + /* haptic init */ + mutex_lock(&aw86214->lock); + aw86214->activate_mode = aw86214->dts_info.mode; + ret = aw86214_i2c_read(aw86214, AW86214_REG_WAVCFG1, ®_val, + AW_I2C_BYTE_ONE); + aw86214->index = reg_val & 0x7F; + ret = aw86214_i2c_read(aw86214, AW86214_REG_PLAYCFG2, ®_val, + AW_I2C_BYTE_ONE); + aw86214->gain = reg_val & 0xFF; + aw_dev_info("%s aw86214->gain =0x%02X\n", __func__, aw86214->gain); + aw86214_i2c_read(aw86214, AW86214_REG_WAVCFG1, reg_array, + AW86214_SEQUENCER_SIZE); + memcpy(aw86214->seq, reg_array, AW86214_SEQUENCER_SIZE); + aw86214_haptic_play_mode(aw86214, AW86214_HAPTIC_STANDBY_MODE); + aw86214_haptic_set_pwm(aw86214, AW86214_PWM_12K); + /* misc value init */ + aw86214_haptic_misc_para_init(aw86214); + /* set motor protect */ + aw86214_haptic_swicth_motor_protect_config(aw86214, 0x00, 0x00); + aw86214_haptic_offset_calibration(aw86214); + /* vbat compensation */ + aw86214_haptic_vbat_mode_config(aw86214, + AW86214_HAPTIC_CONT_VBAT_HW_ADJUST_MODE); + aw86214->ram_vbat_compensate = AW86214_HAPTIC_RAM_VBAT_COMP_ENABLE; + + /* f0 calibration */ + /*LRA trim source select register*/ + aw86214_i2c_write_bits(aw86214, + AW86214_REG_TRIMCFG1, + AW86214_BIT_TRIMCFG1_RL_TRIM_SRC_MASK, + AW86214_BIT_TRIMCFG1_RL_TRIM_SRC_REG); + if (aw86214->dts_info.lk_f0_cali) { + aw86214->f0_cali_data = aw86214->dts_info.lk_f0_cali; + aw86214_haptic_upload_lra(aw86214, AW86214_F0_CALI); + } else { + aw86214_haptic_upload_lra(aw86214, AW86214_WRITE_ZERO); + aw86214_haptic_f0_calibration(aw86214); + } + mutex_unlock(&aw86214->lock); + return ret; +} + +void aw86214_interrupt_setup(struct aw86214 *aw86214) +{ + unsigned char reg_val = 0; + + aw_dev_info("%s enter\n", __func__); + + aw86214_i2c_read(aw86214, AW86214_REG_SYSINT, ®_val, + AW_I2C_BYTE_ONE); + aw_dev_info("%s: reg SYSINT=0x%02X\n", __func__, reg_val); + + /* edge int mode */ + aw86214_i2c_write_bits(aw86214, AW86214_REG_SYSCTRL7, + (AW86214_BIT_SYSCTRL7_INT_MODE_MASK & + AW86214_BIT_SYSCTRL7_INT_EDGE_MODE_MASK), + (AW86214_BIT_SYSCTRL7_INT_MODE_EDGE | + AW86214_BIT_SYSCTRL7_INT_EDGE_MODE_POS)); + /* int enable */ + aw86214_i2c_write_bits(aw86214, AW86214_REG_SYSINTM, + (AW86214_BIT_SYSINTM_UVLM_MASK & + AW86214_BIT_SYSINTM_OCDM_MASK & + AW86214_BIT_SYSINTM_OTM_MASK), + (AW86214_BIT_SYSINTM_UVLM_ON | + AW86214_BIT_SYSINTM_OCDM_ON | + AW86214_BIT_SYSINTM_OTM_ON)); +} + +char aw86214_check_qualify(struct aw86214 *aw86214) +{ + unsigned char reg = 0; + int ret = 0; + + ret = aw86214_i2c_read(aw86214, AW86214_REG_EFCFG5, ®, + AW_I2C_BYTE_ONE); + if (ret < 0) { + aw_dev_err("%s: failed to read register 0x64: %d\n", + __func__, ret); + return ret; + } + if ((reg & 0x80) == 0x80) + return 1; + + return 0; +} diff --git a/drivers/misc/awinic/aw862x/aw86214.h b/drivers/misc/awinic/aw862x/aw86214.h new file mode 100644 index 000000000000..8fdd50ab504a --- /dev/null +++ b/drivers/misc/awinic/aw862x/aw86214.h @@ -0,0 +1,618 @@ +#ifndef _AW86214_H_ +#define _AW86214_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "haptic_nv.h" + +/********************************************************* + * + * marco + * + ********************************************************/ +#define AW86214_I2C_RETRIES (5) +#define AW86214_I2C_RETRY_DELAY (2) +#define AW86214_VBAT_REFER (4200) +#define AW86214_VBAT_MIN (3000) +#define AW86214_VBAT_MAX (5500) +#define AW86214_SEQUENCER_LOOP_SIZE (4) +#define AW86214_SEQUENCER_SIZE (8) +#define AW86214_VBAT_FORMULA(code) (6100 * (code) / 1024) +#define AW86214_LRA_FORMULA(lra_code) (((lra_code) * 678 * 100) / (1024 * 10)) +#define AW86214_STOP_DELAY_MIN (2000) +#define AW86214_STOP_DELAY_MAX (2500) +#define AW86214_VBAT_DELAY_MIN (20000) +#define AW86214_VBAT_DELAY_MAX (25000) +#define AW86214_F0_DELAY_MIN (10000) +#define AW86214_F0_DELAY_MAX (10500) +#define AW86214_LRA_DELAY_MIN (30000) +#define AW86214_LRA_DELAY_MAX (35000) +/********************************************************* + * + * enum + * + ********************************************************/ +enum aw86214_flags { + AW86214_FLAG_NONR = 0, + AW86214_FLAG_SKIP_INTERRUPTS = 1, +}; + +enum aw86214_haptic_work_mode { + AW86214_HAPTIC_STANDBY_MODE = 0, + AW86214_HAPTIC_RAM_MODE = 1, + AW86214_HAPTIC_RAM_LOOP_MODE = 2, + AW86214_HAPTIC_CONT_MODE = 3, + AW86214_HAPTIC_RTP_MODE = 4, + AW86214_HAPTIC_TRIG_MODE = 5, + AW86214_HAPTIC_NULL = 6, +}; + +enum aw86214_haptic_cont_vbat_comp_mode { + AW86214_HAPTIC_CONT_VBAT_SW_ADJUST_MODE = 0, + AW86214_HAPTIC_CONT_VBAT_HW_ADJUST_MODE = 1, +}; + +enum aw86214_haptic_ram_vbat_compensate_mode { + AW86214_HAPTIC_RAM_VBAT_COMP_DISABLE = 0, + AW86214_HAPTIC_RAM_VBAT_COMP_ENABLE = 1, +}; + +enum aw86214_haptic_f0_flag { + AW86214_HAPTIC_LRA_F0 = 0, + AW86214_HAPTIC_CALI_F0 = 1, +}; + +enum aw86214_sram_size_flag { + AW86214_HAPTIC_SRAM_1K = 0, + AW86214_HAPTIC_SRAM_2K = 1, + AW86214_HAPTIC_SRAM_3K = 2, +}; + +enum aw86214_haptic_pwm_mode { + AW86214_PWM_48K = 0, + AW86214_PWM_24K = 1, + AW86214_PWM_12K = 2, +}; + +enum aw86214_haptic_play { + AW86214_HAPTIC_PLAY_NULL = 0, + AW86214_HAPTIC_PLAY_ENABLE = 1, + AW86214_HAPTIC_PLAY_STOP = 2, + AW86214_HAPTIC_PLAY_GAIN = 8, +}; + +enum aw86214_haptic_cmd { + AW86214_HAPTIC_CMD_NULL = 0, + AW86214_HAPTIC_CMD_ENABLE = 1, + AW86214_HAPTIC_CMD_HAPTIC = 0x0f, + AW86214_HAPTIC_CMD_TP = 0x10, + AW86214_HAPTIC_CMD_SYS = 0xf0, + AW86214_HAPTIC_CMD_STOP = 255, +}; + +enum aw86214_haptic_cali_lra { + AW86214_WRITE_ZERO = 0, + AW86214_F0_CALI = 1, +}; + +enum aw86214_haptic_rtp_mode { + AW86214_RTP_SHORT = 4, + AW86214_RTP_LONG = 5, + AW86214_RTP_SEGMENT = 6, +}; + +enum aw86214_awrw_flag { + AW86214_WRITE = 0, + AW86214_READ = 1, +}; +/********************************************************* + * + * struct + * + ********************************************************/ +struct aw86214_dts_info { + unsigned int lk_f0_cali; + unsigned int mode; + unsigned int f0_ref; + unsigned int f0_cali_percent; + unsigned int cont_drv1_lvl_dt; + unsigned int cont_drv2_lvl_dt; + unsigned int cont_drv1_time_dt; + unsigned int cont_drv2_time_dt; + unsigned int cont_wait_num_dt; + unsigned int cont_brk_time_dt; + unsigned int cont_track_margin; + unsigned int cont_tset; + unsigned int cont_drv_width; + unsigned int cont_bemf_set; + unsigned int cont_bst_brk_gain; + unsigned int d2s_gain; + unsigned int bstcfg[5]; + unsigned int prctmode[3]; + unsigned int duration_time[3]; + unsigned int sine_array[4]; +}; + +struct aw86214 { + cdev_t vib_dev; + + unsigned char seq[AW86214_SEQUENCER_SIZE]; + unsigned char loop[AW86214_SEQUENCER_SIZE]; + unsigned char ram_init; + unsigned char f0_cali_flag; + unsigned char ram_vbat_compensate; + unsigned char hwen_flag; + unsigned char flags; + unsigned char chipid; + unsigned char play_mode; + unsigned char activate_mode; + unsigned char duration_time_size; + + char duration_time_flag; + + int reset_gpio; + int irq_gpio; + int state; + int duration; + int amplitude; + int index; + int vmax; + int gain; + int sysclk; + int rate; + int width; + int pstream; + int cstream; + + unsigned int gun_type; + unsigned int bullet_nr; + unsigned int ram_num; + unsigned int f0; + unsigned int cont_f0; + unsigned int cont_drv1_lvl; + unsigned int cont_drv2_lvl; + unsigned int cont_brk_time; + unsigned int cont_wait_num; + unsigned int cont_drv1_time; + unsigned int cont_drv2_time; + unsigned int vbat; + unsigned int lra; + unsigned int ram_update_flag; + unsigned int f0_cali_data; + unsigned int sys_frequency; + + struct regmap *regmap; + struct i2c_client *i2c; + struct device *dev; + struct mutex lock; + struct mutex ram_lock; + struct hrtimer timer; + struct work_struct vibrator_work; + struct delayed_work ram_work; + struct aw86214_dts_info dts_info; + struct ram ram; + struct haptic_audio haptic_audio; + struct aw_i2c_package aw_i2c_package; +}; + +struct aw86214_container { + int len; + unsigned char data[]; +}; + +/********************************************************* + * + * extern + * + ********************************************************/ +extern char aw86214_check_qualify(struct aw86214 *aw86214); +extern int aw86214_parse_dt(struct aw86214 *aw86214, struct device *dev, + struct device_node *np); +extern void aw86214_interrupt_setup(struct aw86214 *aw86214); +extern int aw86214_vibrator_init(struct aw86214 *aw86214); +extern int aw86214_haptic_init(struct aw86214 *aw86214); +extern int aw86214_ram_work_init(struct aw86214 *aw86214); +extern irqreturn_t aw86214_irq(int irq, void *data); + +extern struct attribute_group aw86214_vibrator_attribute_group; + +/******************************************** + * Register List + *******************************************/ +#define AW86214_REG_ID 0x00 +#define AW86214_REG_SYSST 0x01 +#define AW86214_REG_SYSINT 0x02 +#define AW86214_REG_SYSINTM 0x03 +#define AW86214_REG_SYSST2 0x04 +#define AW86214_REG_PLAYCFG2 0x07 +#define AW86214_REG_PLAYCFG3 0x08 +#define AW86214_REG_PLAYCFG4 0x09 +#define AW86214_REG_WAVCFG1 0x0A +#define AW86214_REG_WAVCFG2 0x0B +#define AW86214_REG_WAVCFG3 0x0C +#define AW86214_REG_WAVCFG4 0x0D +#define AW86214_REG_WAVCFG5 0x0E +#define AW86214_REG_WAVCFG6 0x0F +#define AW86214_REG_WAVCFG7 0x10 +#define AW86214_REG_WAVCFG8 0x11 +#define AW86214_REG_WAVCFG9 0x12 +#define AW86214_REG_WAVCFG10 0x13 +#define AW86214_REG_WAVCFG11 0x14 +#define AW86214_REG_WAVCFG12 0x15 +#define AW86214_REG_WAVCFG13 0x16 +#define AW86214_REG_CONTCFG1 0x18 +#define AW86214_REG_CONTCFG2 0x19 +#define AW86214_REG_CONTCFG3 0x1A +#define AW86214_REG_CONTCFG4 0x1B +#define AW86214_REG_CONTCFG5 0x1C +#define AW86214_REG_CONTCFG6 0x1D +#define AW86214_REG_CONTCFG7 0x1E +#define AW86214_REG_CONTCFG8 0x1F +#define AW86214_REG_CONTCFG9 0x20 +#define AW86214_REG_CONTCFG10 0x21 +#define AW86214_REG_CONTCFG11 0x22 +#define AW86214_REG_CONTCFG13 0x24 +#define AW86214_REG_CONTRD14 0x25 +#define AW86214_REG_CONTRD15 0x26 +#define AW86214_REG_CONTRD16 0x27 +#define AW86214_REG_CONTRD17 0x28 +#define AW86214_REG_RTPCFG1 0x2D +#define AW86214_REG_RTPCFG2 0x2E +#define AW86214_REG_RTPCFG3 0x2F +#define AW86214_REG_RTPCFG4 0x30 +#define AW86214_REG_RTPCFG5 0x31 +#define AW86214_REG_TRGCFG1 0x33 +#define AW86214_REG_TRGCFG4 0x36 +#define AW86214_REG_TRGCFG7 0x39 +#define AW86214_REG_TRGCFG8 0x3A +#define AW86214_REG_GLBCFG4 0x3E +#define AW86214_REG_GLBRD5 0x3F +#define AW86214_REG_RAMADDRH 0x40 +#define AW86214_REG_RAMADDRL 0x41 +#define AW86214_REG_RAMDATA 0x42 +#define AW86214_REG_SYSCTRL1 0x43 +#define AW86214_REG_SYSCTRL2 0x44 +#define AW86214_REG_SYSCTRL3 0x45 +#define AW86214_REG_SYSCTRL4 0x46 +#define AW86214_REG_SYSCTRL5 0x47 +#define AW86214_REG_SYSCTRL6 0x48 +#define AW86214_REG_SYSCTRL7 0x49 +#define AW86214_REG_PWMCFG1 0x4C +#define AW86214_REG_PWMCFG3 0x4E +#define AW86214_REG_PWMCFG4 0x4F +#define AW86214_REG_DETCFG1 0x51 +#define AW86214_REG_DETCFG2 0x52 +#define AW86214_REG_DET_RL 0x53 +#define AW86214_REG_DET_VBAT 0x55 +#define AW86214_REG_DET_LO 0x57 +#define AW86214_REG_TRIMCFG1 0x58 +#define AW86214_REG_TRIMCFG3 0x5A +#define AW86214_REG_EFCFG5 0x60 +#define AW86214_REG_ANACFG8 0x77 +/****************************************************** + * Register Detail + *****************************************************/ +/* SYSST: reg 0x01 RO */ +#define AW86214_BIT_SYSST_BST_SCPS (1<<7) +#define AW86214_BIT_SYSST_BST_OVPS (1<<6) +#define AW86214_BIT_SYSST_UVLS (1<<5) +#define AW86214_BIT_SYSST_FF_AES (1<<4) +#define AW86214_BIT_SYSST_FF_AFS (1<<3) +#define AW86214_BIT_SYSST_OCDS (1<<2) +#define AW86214_BIT_SYSST_OTS (1<<1) +#define AW86214_BIT_SYSST_DONES (1<<0) + +/* SYSINT: reg 0x02 RC */ +#define AW86214_BIT_SYSINT_BST_SCPI (1<<7) +#define AW86214_BIT_SYSINT_BST_OVPI (1<<6) +#define AW86214_BIT_SYSINT_UVLI (1<<5) +#define AW86214_BIT_SYSINT_FF_AEI (1<<4) +#define AW86214_BIT_SYSINT_FF_AFI (1<<3) +#define AW86214_BIT_SYSINT_OCDI (1<<2) +#define AW86214_BIT_SYSINT_OTI (1<<1) +#define AW86214_BIT_SYSINT_DONEI (1<<0) + +/* SYSINTM: reg 0x03 RW */ +#define AW86214_BIT_SYSINTM_BST_SCPM_MASK (~(1<<7)) +#define AW86214_BIT_SYSINTM_BST_SCPM_OFF (1<<7) +#define AW86214_BIT_SYSINTM_BST_SCPM_ON (0<<7) +#define AW86214_BIT_SYSINTM_BST_OVPM_MASK (~(1<<6)) +#define AW86214_BIT_SYSINTM_BST_OVPM_OFF (1<<6) +#define AW86214_BIT_SYSINTM_BST_OVPM_ON (0<<6) +#define AW86214_BIT_SYSINTM_UVLM_MASK (~(1<<5)) +#define AW86214_BIT_SYSINTM_UVLM_OFF (1<<5) +#define AW86214_BIT_SYSINTM_UVLM_ON (0<<5) +#define AW86214_BIT_SYSINTM_FF_AEM_MASK (~(1<<4)) +#define AW86214_BIT_SYSINTM_FF_AEM_OFF (1<<4) +#define AW86214_BIT_SYSINTM_FF_AEM_ON (0<<4) +#define AW86214_BIT_SYSINTM_FF_AFM_MASK (~(1<<3)) +#define AW86214_BIT_SYSINTM_FF_AFM_OFF (1<<3) +#define AW86214_BIT_SYSINTM_FF_AFM_ON (0<<3) +#define AW86214_BIT_SYSINTM_OCDM_MASK (~(1<<2)) +#define AW86214_BIT_SYSINTM_OCDM_OFF (1<<2) +#define AW86214_BIT_SYSINTM_OCDM_ON (0<<2) +#define AW86214_BIT_SYSINTM_OTM_MASK (~(1<<1)) +#define AW86214_BIT_SYSINTM_OTM_OFF (1<<1) +#define AW86214_BIT_SYSINTM_OTM_ON (0<<1) +#define AW86214_BIT_SYSINTM_DONEM_MASK (~(1<<0)) +#define AW86214_BIT_SYSINTM_DONEM_OFF (1<<0) +#define AW86214_BIT_SYSINTM_DONEM_ON (0<<0) + +/* PLAYCFG3: reg 0x08 RW */ +#define AW86214_BIT_PLAYCFG3_AUTO_BST_MASK (~(1<<6)) +#define AW86214_BIT_PLAYCFG3_AUTO_BST_ENABLE (1<<6) +#define AW86214_BIT_PLAYCFG3_AUTO_BST_DISABLE (0<<6) +#define AW86214_BIT_PLAYCFG3_STOP_MODE_MASK (~(1<<5)) +#define AW86214_BIT_PLAYCFG3_STOP_MODE_NOW (1<<5) +#define AW86214_BIT_PLAYCFG3_STOP_MODE_LATER (0<<5) +#define AW86214_BIT_PLAYCFG3_BRK_EN_MASK (~(1<<2)) +#define AW86214_BIT_PLAYCFG3_BRK (1<<2) +#define AW86214_BIT_PLAYCFG3_BRK_ENABLE (1<<2) +#define AW86214_BIT_PLAYCFG3_BRK_DISABLE (0<<2) +#define AW86214_BIT_PLAYCFG3_PLAY_MODE_MASK (~(3<<0)) +#define AW86214_BIT_PLAYCFG3_PLAY_MODE_STOP (3<<0) +#define AW86214_BIT_PLAYCFG3_PLAY_MODE_CONT (2<<0) +#define AW86214_BIT_PLAYCFG3_PLAY_MODE_RTP (1<<0) +#define AW86214_BIT_PLAYCFG3_PLAY_MODE_RAM (0<<0) + +/* PLAYCFG4: reg 0x09 RW */ +#define AW86214_BIT_PLAYCFG4_STOP_MASK (~(1<<1)) +#define AW86214_BIT_PLAYCFG4_STOP_ON (1<<1) +#define AW86214_BIT_PLAYCFG4_STOP_OFF (0<<1) +#define AW86214_BIT_PLAYCFG4_GO_MASK (~(1<<0)) +#define AW86214_BIT_PLAYCFG4_GO_ON (1<<0) +#define AW86214_BIT_PLAYCFG4_GO_OFF (0<<0) + +/* WAVCFG1-8: reg 0x0A - reg 0x11 RW */ +#define AW86214_BIT_WAVCFG_SEQWAIT_MASK (~(1<<7)) +#define AW86214_BIT_WAVCFG_SEQWAIT_TIME (1<<7) +#define AW86214_BIT_WAVCFG_SEQWAIT_NUMBER (0<<7) + +/* WAVCFG9-12: reg 0x12 - reg 0x15 RW */ +#define AW86214_BIT_WAVLOOP_SEQ_ODD_MASK (~(0x0F<<4)) +#define AW86214_BIT_WAVLOOP_SEQ_ODD_INIFINITELY (0x0F<<4) +#define AW86214_BIT_WAVLOOP_SEQ_EVEN_MASK (~(0x0F<<0)) +#define AW86214_BIT_WAVLOOP_SEQ_EVEN_INIFINITELY (0x0F<<0) +#define AW86214_BIT_WAVLOOP_INIFINITELY (0x0F<<0) + +/* WAVCFG9: reg 0x12 RW */ +#define AW86214_BIT_WAVCFG9_SEQ1LOOP_MASK (~(0x0F<<4)) +#define AW86214_BIT_WAVCFG9_SEQ1LOOP_INIFINITELY (0x0F<<4) +#define AW86214_BIT_WAVCFG9_SEQ2LOOP_MASK (~(0x0F<<0)) +#define AW86214_BIT_WAVCFG9_SEQ2LOOP_INIFINITELY (0x0F<<0) + +/* WAVCFG10: reg 0x13 RW */ +#define AW86214_BIT_WAVCFG10_SEQ3LOOP_MASK (~(0x0F<<4)) +#define AW86214_BIT_WAVCFG10_SEQ3LOOP_INIFINITELY (0x0F<<4) +#define AW86214_BIT_WAVCFG10_SEQ4LOOP_MASK (~(0x0F<<0)) +#define AW86214_BIT_WAVCFG10_SEQ4LOOP_INIFINITELY (0x0F<<0) + +/* WAVCFG11: reg 0x14 RW */ +#define AW86214_BIT_WAVCFG11_SEQ5LOOP_MASK (~(0x0F<<4)) +#define AW86214_BIT_WAVCFG11_SEQ5LOOP_INIFINITELY (0x0F<<4) +#define AW86214_BIT_WAVCFG11_SEQ6LOOP_MASK (~(0x0F<<0)) +#define AW86214_BIT_WAVCFG11_SEQ6LOOP_INIFINITELY (0x0F<<0) + +/* WAVCFG12: reg 0x15 RW */ +#define AW86214_BIT_WAVCFG12_SEQ7LOOP_MASK (~(0x0F<<4)) +#define AW86214_BIT_WAVCFG12_SEQ7LOOP_INIFINITELY (0x0F<<4) +#define AW86214_BIT_WAVCFG12_SEQ8LOOP_MASK (~(0x0F<<0)) +#define AW86214_BIT_WAVCFG12_SEQ8LOOP_INIFINITELY (0x0F<<0) + +/***************** CONT *****************/ +/* CONTCFG1: reg 0x18 RW */ +#define AW86214_BIT_CONTCFG1_EDGE_FRE_MASK (~(0x0F<<4)) +#define AW86214_BIT_CONTCFG1_EN_F0_DET_MASK (~(1<<3)) +#define AW86214_BIT_CONTCFG1_F0_DET_ENABLE (1<<3) +#define AW86214_BIT_CONTCFG1_F0_DET_DISABLE (0<<3) +#define AW86214_BIT_CONTCFG1_MBRK_MASK (~(1<<2)) +#define AW86214_BIT_CONTCFG1_MBRK_ENABLE (1<<2) +#define AW86214_BIT_CONTCFG1_MBRK_DISABLE (0<<2) +#define AW86214_BIT_CONTCFG1_BRK_BST_MD_MASK (~(1<<1)) +#define AW86214_BIT_CONTCFG1_BRK_BST_MD_ENABLE (1<<1) +#define AW86214_BIT_CONTCFG1_BRK_BST_MD_DISABLE (0<<1) +#define AW86214_BIT_CONTCFG1_SIN_MODE_MASK (~(1<<0)) +#define AW86214_BIT_CONTCFG1_SIN_MODE_COS (1<<0) +#define AW86214_BIT_CONTCFG1_SIN_MODE_SINE (0<<0) + +/* CONTCFG5: reg 0x1C RW */ +#define AW86214_BIT_CONTCFG5_BST_BRK_GAIN_MASK (~(0x0F<<4)) +#define AW86214_BIT_CONTCFG5_BRK_GAIN_MASK (~(0x0F<<0)) + +/* CONTCFG6: reg 0x1D RW */ +#define AW86214_BIT_CONTCFG6_TRACK_EN_MASK (~(1<<7)) +#define AW86214_BIT_CONTCFG6_TRACK_ENABLE (1<<7) +#define AW86214_BIT_CONTCFG6_TRACK_DISABLE (0<<7) +#define AW86214_BIT_CONTCFG6_DRV1_LVL_MASK (~(0x7F<<0)) + +/* CONTCFG7: reg 0x1E RW */ +#define AW86214_BIT_CONTCFG7_DRV2_LVL_MASK (~(0x7F<<0)) + +/* CONTCFG13: reg 0x24 RW */ +#define AW86214_BIT_CONTCFG13_TSET_MASK (~(0x0F<<4)) +#define AW86214_BIT_CONTCFG13_BEME_SET_MASK (~(0x0F<<0)) + +/***************** RTP *****************/ +/* RTPCFG1: reg 0x2D RW */ +#define AW86214_BIT_RTPCFG1_ADDRH_MASK (~(0x0F<<0)) + +#define AW86214_BIT_RTPCFG1_SRAM_SIZE_2K_MASK (~(1<<5)) +#define AW86214_BIT_RTPCFG1_SRAM_SIZE_2K_EN (1<<5) +#define AW86214_BIT_RTPCFG1_SRAM_SIZE_2K_DIS (0<<5) + +#define AW86214_BIT_RTPCFG1_SRAM_SIZE_1K_MASK (~(1<<4)) +#define AW86214_BIT_RTPCFG1_SRAM_SIZE_1K_EN (1<<4) +#define AW86214_BIT_RTPCFG1_SRAM_SIZE_1K_DIS (0<<4) + +/* GLBRD5: reg 0x3F R0 */ +/* GLB_STATE */ +#define AW86214_BIT_GLBRD5_STATE (15<<0) +#define AW86214_BIT_GLBRD5_STATE_STANDBY (0<<0) +#define AW86214_BIT_GLBRD5_STATE_WAKEUP (1<<0) +#define AW86214_BIT_GLBRD5_STATE_STARTUP (2<<0) +#define AW86214_BIT_GLBRD5_STATE_WAIT (3<<0) +#define AW86214_BIT_GLBRD5_STATE_CONT_GO (6<<0) +#define AW86214_BIT_GLBRD5_STATE_RAM_GO (7<<0) +#define AW86214_BIT_GLBRD5_STATE_RTP_GO (8<<0) +#define AW86214_BIT_GLBRD5_STATE_TRIG_GO (9<<0) +#define AW86214_BIT_GLBRD5_STATE_I2S_GO (10<<0) +#define AW86214_BIT_GLBRD5_STATE_BRAKE (11<<0) +#define AW86214_BIT_GLBRD5_STATE_END (12<<0) +/* RAMADDRH: reg 0x40 RWS */ +#define AW86214_BIT_RAMADDRH_MASK (~(63<<0)) + +/* RAMADDRL: reg 0x41 RWS */ +/* RAMADDRL */ + +/* RAMDATA: reg 0x42 RWS */ +/* RAMDATA */ + +/***************** SYSCTRL *****************/ +/* SYSCTRL1: reg 0x43 RW */ +#define AW86214_BIT_SYSCTRL1_VBAT_MODE_MASK (~(1<<7)) +#define AW86214_BIT_SYSCTRL1_VBAT_MODE_HW (1<<7) +#define AW86214_BIT_SYSCTRL1_VBAT_MODE_SW (0<<7) +#define AW86214_BIT_SYSCTRL1_PERP_MASK (~(1<<6)) +#define AW86214_BIT_SYSCTRL1_PERP_ON (1<<6) +#define AW86214_BIT_SYSCTRL1_PERP_OFF (0<<6) +#define AW86214_BIT_SYSCTRL1_CLK_SEL_MASK (~(3<<4)) +#define AW86214_BIT_SYSCTRL1_CLK_SEL_OSC (1<<4) +#define AW86214_BIT_SYSCTRL1_CLK_SEL_AUTO (0<<4) +#define AW86214_BIT_SYSCTRL1_RAMINIT_MASK (~(1<<3)) +#define AW86214_BIT_SYSCTRL1_RAMINIT_ON (1<<3) +#define AW86214_BIT_SYSCTRL1_RAMINIT_OFF (0<<3) +#define AW86214_BIT_SYSCTRL1_EN_FIR_MASK (~(1<<2)) +#define AW86214_BIT_SYSCTRL1_FIR_ENABLE (0<<2) +#define AW86214_BIT_SYSCTRL1_WAKE_MODE_MASK (~(1<<1)) +#define AW86214_BIT_SYSCTRL1_WAKE_MODE_WAKEUP (1<<1) +#define AW86214_BIT_SYSCTRL1_WAKE_MODE_BST (0<<1) +#define AW86214_BIT_SYSCTRL1_RTP_CLK_MASK (~(1<<0)) +#define AW86214_BIT_SYSCTRL1_RTP_PLL (1<<0) +#define AW86214_BIT_SYSCTRL1_RTP_OSC (0<<0) + +/* SYSCTRL2: reg 0x44 RW */ +#define AW86214_BIT_SYSCTRL2_WAKE_MASK (~(1<<7)) +#define AW86214_BIT_SYSCTRL2_WAKE_ON (1<<7) +#define AW86214_BIT_SYSCTRL2_WAKE_OFF (0<<7) +#define AW86214_BIT_SYSCTRL2_STANDBY_MASK (~(1<<6)) +#define AW86214_BIT_SYSCTRL2_STANDBY_ON (1<<6) +#define AW86214_BIT_SYSCTRL2_STANDBY_OFF (0<<6) +#define AW86214_BIT_SYSCTRL2_RTP_DLY_MASK (~(3<<4)) +#define AW86214_BIT_SYSCTRL2_PLL_PIN_MASK (~(1<<3)) +#define AW86214_BIT_SYSCTRL2_PLL_PIN_TEST (1<<3) +#define AW86214_BIT_SYSCTRL2_I2S_PIN_MASK (~(1<<2)) +#define AW86214_BIT_SYSCTRL2_I2S_PIN_I2S (1<<2) +#define AW86214_BIT_SYSCTRL2_I2S_PIN_TRIG (0<<2) +#define AW86214_BIT_SYSCTRL2_WAVDAT_MODE_MASK (~(3<<0)) +#define AW86214_BIT_SYSCTRL2_RATE_12K (2<<0) +#define AW86214_BIT_SYSCTRL2_RATE_24K (0<<0) +#define AW86214_BIT_SYSCTRL2_RATE_48K (1<<0) + +/* SYSCTRL7: reg 0x49 RW */ +#define AW86214_BIT_SYSCTRL7_GAIN_BYPASS_MASK (~(1<<6)) +#define AW86214_BIT_SYSCTRL7_GAIN_CHANGEABLE (1<<6) +#define AW86214_BIT_SYSCTRL7_GAIN_FIXED (0<<6) + +#define AW86214_BIT_SYSCTRL7_INT_EDGE_MODE_MASK (~(1<<5)) +#define AW86214_BIT_SYSCTRL7_INT_EDGE_MODE_POS (0<<5) +#define AW86214_BIT_SYSCTRL7_INT_EDGE_MODE_BOTH (1<<5) +#define AW86214_BIT_SYSCTRL7_INT_MODE_MASK (~(1<<4)) +#define AW86214_BIT_SYSCTRL7_INT_MODE_EDGE (1<<4) +#define AW86214_BIT_SYSCTRL7_INT_MODE_LEVEL (0<<4) + +#define AW86214_BIT_SYSCTRL7_INTP_MASK (~(1<<3)) +#define AW86214_BIT_SYSCTRL7_INTP_HIGH (1<<3) +#define AW86214_BIT_SYSCTRL7_INTP_LOW (0<<3) +#define AW86214_BIT_SYSCTRL7_D2S_GAIN_MASK (~(7<<0)) +#define AW86214_BIT_SYSCTRL7_D2S_GAIN_1 (0<<0) +#define AW86214_BIT_SYSCTRL7_D2S_GAIN_2 (1<<0) +#define AW86214_BIT_SYSCTRL7_D2S_GAIN_4 (2<<0) +#define AW86214_BIT_SYSCTRL7_D2S_GAIN_8 (3<<0) +#define AW86214_BIT_SYSCTRL7_D2S_GAIN_10 (4<<0) +#define AW86214_BIT_SYSCTRL7_D2S_GAIN_16 (5<<0) +#define AW86214_BIT_SYSCTRL7_D2S_GAIN_20 (6<<0) +#define AW86214_BIT_SYSCTRL7_D2S_GAIN_40 (7<<0) + +/* PWMCFG1: reg 0x4C RW */ +#define AW86214_BIT_PWMCFG1_PRC_EN_MASK (~(1<<7)) +#define AW86214_BIT_PWMCFG1_PRC_ENABLE (1<<7) +#define AW86214_BIT_PWMCFG1_PRC_DISABLE (0<<7) +#define AW86214_BIT_PWMCFG1_PRCTIME_MASK (~(0x7F<<0)) + +/* PWMCFG2: reg 0x4D RW */ +#define AW86214_BIT_PWMCFG2_REF_SEL_MASK (~(1<<5)) +#define AW86214_BIT_PWMCFG2_REF_SEL_TRIANGLE (1<<5) +#define AW86214_BIT_PWMCFG2_REF_SEL_SAWTOOTH (0<<5) +#define AW86214_BIT_PWMCFG2_PD_HWM_MASK (~(1<<4)) +#define AW86214_BIT_PWMCFG2_PD_HWM_ON (1<<4) +#define AW86214_BIT_PWMCFG2_PWMOE_MASK (~(1<<3)) +#define AW86214_BIT_PWMCFG2_PWMOE_ON (1<<3) +#define AW86214_BIT_PWMCFG2_PWMFRC_MASK (~(7<<0)) + +/* PWMCFG3: reg 0x4E RW */ +#define AW86214_BIT_PWMCFG3_PR_EN_MASK (~(1<<7)) +#define AW86214_BIT_PWMCFG3_PR_ENABLE (1<<7) +#define AW86214_BIT_PWMCFG3_PR_DISABLE (0<<7) +#define AW86214_BIT_PWMCFG3_PRLVL_MASK (~(0x7F<<0)) + +/* DETCFG1: reg 0x51 RW */ +#define AW86214_BIT_DETCFG1_FTS_GO_MASK (~(1<<7)) +#define AW86214_BIT_DETCFG1_FTS_GO_ENABLE (1<<7) +#define AW86214_BIT_DETCFG1_TEST_GO_MASK (~(1<<6)) +#define AW86214_BIT_DETCFG1_TEST_GO_ENABLE (1<<6) +#define AW86214_BIT_DETCFG1_ADO_SLOT_MODE_MASK (~(1<<5)) +#define AW86214_BIT_DETCFG1_ADO_SLOT_ADC_32 (1<<5) +#define AW86214_BIT_DETCFG1_ADO_SLOT_ADC_256 (0<<5) +#define AW86214_BIT_DETCFG1_RL_OS_MASK (~(1<<4)) +#define AW86214_BIT_DETCFG1_RL (1<<4) +#define AW86214_BIT_DETCFG1_OS (0<<4) +#define AW86214_BIT_DETCFG1_PRCT_MODE_MASK (~(1<<3)) +#define AW86214_BIT_DETCFG1_PRCT_MODE_INVALID (1<<3) +#define AW86214_BIT_DETCFG1_PRCT_MODE_VALID (0<<3) +#define AW86214_BIT_DETCFG1_CLK_ADC_MASK (~(7<<0)) +#define AW86214_BIT_DETCFG1_CLK_ADC_12M (0<<0) +#define AW86214_BIT_DETCFG1_CLK_ADC_6M (1<<0) +#define AW86214_BIT_DETCFG1_CLK_ADC_3M (2<<0) +#define AW86214_BIT_DETCFG1_CLK_ADC_1M5 (3<<0) +#define AW86214_BIT_DETCFG1_CLK_ADC_M75 (4<<0) +#define AW86214_BIT_DETCFG1_CLK_ADC_M37 (5<<0) +#define AW86214_BIT_DETCFG1_CLK_ADC_M18 (6<<0) +#define AW86214_BIT_DETCFG1_CLK_ADC_M09 (7<<0) + +/* DETCFG2: reg 0x52 RW */ +#define AW86214_BIT_DETCFG2_VBAT_GO_MASK (~(1<<1)) +#define AW86214_BIT_DETCFG2_VABT_GO_ON (1<<1) +#define AW86214_BIT_DETCFG2_DIAG_GO_MASK (~(1<<0)) +#define AW86214_BIT_DETCFG2_DIAG_GO_ON (1<<0) + +/* DET_LO: reg 0x57 RW */ +#define AW86214_BIT_DET_LO_TEST_MASK (~(3<<6)) +#define AW86214_BIT_DET_LO_VBAT_MASK (~(3<<4)) +#define AW86214_BIT_DET_LO_OS_MASK (~(3<<2)) +#define AW86214_BIT_DET_LO_RL_MASK (~(3<<0)) +#define AW86214_BIT_DET_LO_VBAT (3<<4) +#define AW86214_BIT_DET_LO_RL (3<<0) + +/* TRIMCFG1: reg:0x58 RW */ +#define AW86214_BIT_TRIMCFG1_RL_TRIM_SRC_MASK (~(1<<6)) +#define AW86214_BIT_TRIMCFG1_RL_TRIM_SRC_REG (1<<6) +#define AW86214_BIT_TRIMCFG1_RL_TRIM_SRC_EFUSE (0<<6) +#define AW86214_BIT_TRIMCFG1_TRIM_RL_MASK (~(63<<0)) + +/* TRIMCFG3: reg:0x5A RW */ +#define AW86214_BIT_TRIMCFG3_OSC_TRIM_SRC_MASK (~(1<<7)) +#define AW86214_BIT_TRIMCFG3_OSC_TRIM_SRC_REG (1<<7) +#define AW86214_BIT_TRIMCFG3_OSC_TRIM_SRC_EFUSE (0<<7) +#define AW86214_BIT_TRIMCFG3_LRA_TRIM_SRC_MASK (~(1<<6)) +#define AW86214_BIT_TRIMCFG3_LRA_TRIM_SRC_REG (1<<6) +#define AW86214_BIT_TRIMCFG3_LRA_TRIM_SRC_EFUSE (0<<6) +#define AW86214_BIT_TRIMCFG3_TRIM_LRA_MASK (~(63<<0)) + +#endif diff --git a/drivers/misc/awinic/aw862x/aw8622x.c b/drivers/misc/awinic/aw862x/aw8622x.c new file mode 100644 index 000000000000..1370caf318d6 --- /dev/null +++ b/drivers/misc/awinic/aw862x/aw8622x.c @@ -0,0 +1,4120 @@ +/* + * aw8622x.c + * + * Copyright (c) 2021 AWINIC Technology CO., LTD + * + * Author: + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aw8622x.h" +#include "haptic_nv.h" + +/****************************************************** + * + * Register Access + * + ******************************************************/ +const unsigned char aw8622x_reg_list[] = { + AW8622X_REG_ID, + AW8622X_REG_SYSST, + AW8622X_REG_SYSINT, + AW8622X_REG_SYSINTM, + AW8622X_REG_SYSST2, + AW8622X_REG_SYSER, + AW8622X_REG_PLAYCFG2, + AW8622X_REG_PLAYCFG3, + AW8622X_REG_PLAYCFG4, + AW8622X_REG_WAVCFG1, + AW8622X_REG_WAVCFG2, + AW8622X_REG_WAVCFG3, + AW8622X_REG_WAVCFG4, + AW8622X_REG_WAVCFG5, + AW8622X_REG_WAVCFG6, + AW8622X_REG_WAVCFG7, + AW8622X_REG_WAVCFG8, + AW8622X_REG_WAVCFG9, + AW8622X_REG_WAVCFG10, + AW8622X_REG_WAVCFG11, + AW8622X_REG_WAVCFG12, + AW8622X_REG_WAVCFG13, + AW8622X_REG_CONTCFG1, + AW8622X_REG_CONTCFG2, + AW8622X_REG_CONTCFG3, + AW8622X_REG_CONTCFG4, + AW8622X_REG_CONTCFG5, + AW8622X_REG_CONTCFG6, + AW8622X_REG_CONTCFG7, + AW8622X_REG_CONTCFG8, + AW8622X_REG_CONTCFG9, + AW8622X_REG_CONTCFG10, + AW8622X_REG_CONTCFG11, + AW8622X_REG_CONTCFG13, + AW8622X_REG_CONTRD14, + AW8622X_REG_CONTRD15, + AW8622X_REG_CONTRD16, + AW8622X_REG_CONTRD17, + AW8622X_REG_RTPCFG1, + AW8622X_REG_RTPCFG2, + AW8622X_REG_RTPCFG3, + AW8622X_REG_RTPCFG4, + AW8622X_REG_RTPCFG5, + AW8622X_REG_TRGCFG1, + AW8622X_REG_TRGCFG2, + AW8622X_REG_TRGCFG3, + AW8622X_REG_TRGCFG4, + AW8622X_REG_TRGCFG5, + AW8622X_REG_TRGCFG6, + AW8622X_REG_TRGCFG7, + AW8622X_REG_TRGCFG8, + AW8622X_REG_GLBCFG4, + AW8622X_REG_GLBRD5, + AW8622X_REG_RAMADDRH, + AW8622X_REG_RAMADDRL, + AW8622X_REG_SYSCTRL1, + AW8622X_REG_SYSCTRL2, + AW8622X_REG_SYSCTRL3, + AW8622X_REG_SYSCTRL4, + AW8622X_REG_SYSCTRL5, + AW8622X_REG_SYSCTRL6, + AW8622X_REG_SYSCTRL7, + AW8622X_REG_PWMCFG1, + AW8622X_REG_PWMCFG3, + AW8622X_REG_PWMCFG4, + AW8622X_REG_DETCFG1, + AW8622X_REG_DETCFG2, + AW8622X_REG_DET_RL, + AW8622X_REG_DET_VBAT, + AW8622X_REG_DET_LO, + AW8622X_REG_TRIMCFG1, + AW8622X_REG_TRIMCFG3, +}; + +/****************************************************** + * + * value + * + ******************************************************/ +static char *aw8622x_ram_name = "aw8622x_haptic.bin"; +static char aw8622x_rtp_name[][AW8622X_RTP_NAME_MAX] = { + {"aw8622x_osc_rtp_12K_10s.bin"}, + {"aw8622x_rtp.bin"}, + {"aw8622x_rtp_lighthouse.bin"}, + {"aw8622x_rtp_silk.bin"}, +}; + +struct pm_qos_request aw8622x_pm_qos_req_vb; + + /****************************************************** + * + * aw8622x i2c write/read + * + ******************************************************/ +static int aw8622x_i2c_read(struct aw8622x *aw8622x, unsigned char reg_addr, + unsigned char *buf, unsigned int len) +{ + int ret = 0; + + struct i2c_msg msg[2] = { + [0] = { + .addr = aw8622x->i2c->addr, + .flags = 0, + .len = sizeof(uint8_t), + .buf = ®_addr, + }, + [1] = { + .addr = aw8622x->i2c->addr, + .flags = I2C_M_RD, + .len = len, + .buf = buf, + }, + }; + + ret = i2c_transfer(aw8622x->i2c->adapter, msg, ARRAY_SIZE(msg)); + if (ret < 0) { + aw_dev_err("%s: i2c_transfer failed\n", __func__); + return ret; + } else if (ret != AW_I2C_READ_MSG_NUM) { + aw_dev_err("%s: transfer failed(size error)\n", __func__); + return -ENXIO; + } + return ret; +} + +static int aw8622x_i2c_write(struct aw8622x *aw8622x, unsigned char reg_addr, + unsigned char *buf, unsigned int len) +{ + unsigned char *data = NULL; + int ret = -1; + + data = kmalloc(len + 1, GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + data[0] = reg_addr; + memcpy(&data[1], buf, len); + ret = i2c_master_send(aw8622x->i2c, data, len + 1); + if (ret < 0) + aw_dev_err("%s: i2c master send 0x%02x error\n", + __func__, reg_addr); + kfree(data); + return ret; +} + +static int +aw8622x_i2c_write_bits(struct aw8622x *aw8622x, unsigned char reg_addr, + unsigned int mask, + unsigned char reg_data) +{ + unsigned char reg_val = 0; + int ret = -1; + + ret = aw8622x_i2c_read(aw8622x, reg_addr, ®_val, AW_I2C_BYTE_ONE); + if (ret < 0) { + aw_dev_err("%s: i2c read error, ret=%d\n", __func__, ret); + return ret; + } + reg_val &= mask; + reg_val |= reg_data; + ret = aw8622x_i2c_write(aw8622x, reg_addr, ®_val, AW_I2C_BYTE_ONE); + if (ret < 0) { + aw_dev_err("%s: i2c write error, ret=%d\n", __func__, ret); + return ret; + } + return 0; +} + +static int aw8622x_parse_data(struct aw8622x *aw8622x, const char *buf) +{ + unsigned char reg_num = aw8622x->aw_i2c_package.reg_num; + unsigned char i = 0; + const char *temp_buf = NULL; + char data_buf[AWRW_CMD_UNIT] = { 0 }; + unsigned int value = 0; + int ret = 0; + int len = strlen(buf) - (AWRW_CMD_UNIT * 3); + + if (len < 0) { + aw_dev_err("%s: parse data error\n", __func__); + return -ERANGE; + } + temp_buf = &buf[AWRW_CMD_UNIT * 3]; + for (i = 0; i < reg_num; i++) { + if (((i + 1) * AWRW_CMD_UNIT) > len) { + aw_dev_err("%s: parse data error\n", __func__); + return -ERANGE; + } + memcpy(data_buf, &temp_buf[i * AWRW_CMD_UNIT], 4); + data_buf[4] = '\0'; + ret = kstrtouint(data_buf, 0, &value); + if (ret < 0) { + aw_dev_err("%s: kstrtouint error\n", + __func__); + return ret; + } + aw8622x->aw_i2c_package.reg_data[i] = (unsigned char)value; + } + return 0; +} + +static unsigned char aw8622x_haptic_rtp_get_fifo_afs(struct aw8622x *aw8622x) +{ + unsigned char ret = 0; + unsigned char reg_val = 0; + + aw8622x_i2c_read(aw8622x, AW8622X_REG_SYSST, ®_val, AW_I2C_BYTE_ONE); + reg_val &= AW8622X_BIT_SYSST_FF_AFS; + ret = reg_val >> 3; + return ret; +} + +/***************************************************** + * + * rtp + * + *****************************************************/ +static void aw8622x_haptic_set_rtp_aei(struct aw8622x *aw8622x, bool flag) +{ + if (flag) { + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSINTM, + AW8622X_BIT_SYSINTM_FF_AEM_MASK, + AW8622X_BIT_SYSINTM_FF_AEM_ON); + } else { + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSINTM, + AW8622X_BIT_SYSINTM_FF_AEM_MASK, + AW8622X_BIT_SYSINTM_FF_AEM_OFF); + } +} + +static int aw8622x_analyse_duration_range(struct aw8622x *aw8622x) +{ + int i = 0; + int ret = 0; + int len = 0; + int *duration_time = NULL; + + len = ARRAY_SIZE(aw8622x->dts_info.duration_time); + duration_time = aw8622x->dts_info.duration_time; + if (len < 2) { + aw_dev_err("%s: duration time range error\n", __func__); + return -ERANGE; + } + for (i = (len - 1); i > 0; i--) { + if (duration_time[i] > duration_time[i-1]) + continue; + else + break; + + } + if (i > 0) { + aw_dev_err("%s: duration time range error\n", __func__); + ret = -ERANGE; + } + return ret; +} + +static int aw8622x_analyse_duration_array_size(struct aw8622x *aw8622x, + struct device_node *np) +{ + int ret = 0; + + ret = of_property_count_elems_of_size(np, "aw8622x_vib_duration_time", + 4); + if (ret < 0) { + aw8622x->duration_time_flag = -1; + aw_dev_info("%s vib_duration_time not found\n", __func__); + return ret; + } + aw8622x->duration_time_size = ret; + if (aw8622x->duration_time_size > 3) { + aw8622x->duration_time_flag = -1; + aw_dev_info("%s vib_duration_time error, array size = %d\n", + __func__, aw8622x->duration_time_size); + return -ERANGE; + } + return 0; +} + +/***************************************************** + * + * device tree + * + *****************************************************/ +int aw8622x_parse_dt(struct aw8622x *aw8622x, struct device *dev, + struct device_node *np) +{ + unsigned int val = 0; + unsigned int prctmode_temp[3]; + unsigned int sine_array_temp[4]; + unsigned int trig_config_temp[21]; + unsigned int duration_time[3]; + int ret = 0; + + val = of_property_read_u32(np, "aw8622x_vib_lk_f0_cali", + &aw8622x->dts_info.lk_f0_cali); + if (val != 0) + aw_dev_info("aw8622x_vib_mode not found\n"); + aw_dev_info("%s: aw8622x_vib_lk_f0_cali = 0x%02x\n", __func__, + aw8622x->dts_info.lk_f0_cali); + val = of_property_read_u32(np, + "aw8622x_vib_mode", + &aw8622x->dts_info.mode); + if (val != 0) + aw_dev_info("%s aw8622x_vib_mode not found\n", __func__); + val = of_property_read_u32(np, + "aw8622x_vib_f0_pre", + &aw8622x->dts_info.f0_ref); + if (val != 0) + aw_dev_info("%s vib_f0_ref not found\n", __func__); + val = + of_property_read_u32(np, "aw8622x_vib_f0_cali_percen", + &aw8622x->dts_info.f0_cali_percent); + if (val != 0) + aw_dev_info("%s vib_f0_cali_percent not found\n", __func__); + + val = of_property_read_u32(np, "aw8622x_vib_cont_drv1_lvl", + &aw8622x->dts_info.cont_drv1_lvl_dt); + if (val != 0) + aw_dev_info("%s vib_cont_drv1_lvl not found\n", __func__); + val = + of_property_read_u32(np, "aw8622x_vib_cont_drv2_lvl", + &aw8622x->dts_info.cont_drv2_lvl_dt); + if (val != 0) + aw_dev_info("%s vib_cont_drv2_lvl not found\n", __func__); + val = + of_property_read_u32(np, "aw8622x_vib_cont_drv1_time", + &aw8622x->dts_info.cont_drv1_time_dt); + if (val != 0) + aw_dev_info("%s vib_cont_drv1_time not found\n", __func__); + val = + of_property_read_u32(np, "aw8622x_vib_cont_drv2_time", + &aw8622x->dts_info.cont_drv2_time_dt); + if (val != 0) + aw_dev_info("%s vib_cont_drv2_time not found\n", __func__); + val = + of_property_read_u32(np, "aw8622x_vib_cont_drv_width", + &aw8622x->dts_info.cont_drv_width); + if (val != 0) + aw_dev_info("%s vib_cont_drv_width not found\n", __func__); + val = + of_property_read_u32(np, "aw8622x_vib_cont_wait_num", + &aw8622x->dts_info.cont_wait_num_dt); + if (val != 0) + aw_dev_info("%s vib_cont_wait_num not found\n", __func__); + val = + of_property_read_u32(np, "aw8622x_vib_cont_brk_gain", + &aw8622x->dts_info.cont_brk_gain); + if (val != 0) + aw_dev_info("%s vib_cont_brk_gain not found\n", __func__); + val = + of_property_read_u32(np, "aw8622x_vib_cont_tset", + &aw8622x->dts_info.cont_tset); + if (val != 0) + aw_dev_info("%s vib_cont_tset not found\n", __func__); + val = + of_property_read_u32(np, "aw8622x_vib_cont_bemf_set", + &aw8622x->dts_info.cont_bemf_set); + if (val != 0) + aw_dev_info("%s vib_cont_bemf_set not found\n", __func__); + val = + of_property_read_u32(np, "aw8622x_vib_d2s_gain", + &aw8622x->dts_info.d2s_gain); + if (val != 0) + aw_dev_info("%s vib_d2s_gain not found\n", __func__); + val = + of_property_read_u32(np, "aw8622x_vib_cont_brk_time", + &aw8622x->dts_info.cont_brk_time_dt); + if (val != 0) + aw_dev_info("%s vib_cont_brk_time not found\n", __func__); + val = + of_property_read_u32(np, "aw8622x_vib_cont_track_margin", + &aw8622x->dts_info.cont_track_margin); + if (val != 0) + aw_dev_info("%s vib_cont_track_margin not found\n", __func__); + + val = of_property_read_u32_array(np, "aw8622x_vib_prctmode", + prctmode_temp, + ARRAY_SIZE(prctmode_temp)); + if (val != 0) + aw_dev_info("%s vib_prctmode not found\n", __func__); + memcpy(aw8622x->dts_info.prctmode, prctmode_temp, + sizeof(prctmode_temp)); + val = of_property_read_u32_array(np, + "aw8622x_vib_sine_array", + sine_array_temp, + ARRAY_SIZE(sine_array_temp)); + if (val != 0) + aw_dev_info("%s vib_sine_array not found\n", __func__); + memcpy(aw8622x->dts_info.sine_array, sine_array_temp, + sizeof(sine_array_temp)); + val = + of_property_read_u32_array(np, + "aw8622x_vib_trig_config", + trig_config_temp, + ARRAY_SIZE(trig_config_temp)); + if (val != 0) + aw_dev_info("%s vib_trig_config not found\n", __func__); + memcpy(aw8622x->dts_info.trig_config, trig_config_temp, + sizeof(trig_config_temp)); + val = of_property_read_u32_array(np, "aw8622x_vib_duration_time", + duration_time, ARRAY_SIZE(duration_time)); + if (val != 0) + aw_dev_info("%s vib_duration_time not found\n", __func__); + ret = aw8622x_analyse_duration_array_size(aw8622x, np); + if (!ret) + memcpy(aw8622x->dts_info.duration_time, + duration_time, sizeof(duration_time)); + aw8622x->dts_info.is_enabled_auto_brk = + of_property_read_bool(np, + "aw8622x_vib_is_enabled_auto_brk"); + aw_dev_info("%s aw8622x->info.is_enabled_auto_brk = %d\n", __func__, + aw8622x->dts_info.is_enabled_auto_brk); + + return 0; +} + +static void aw8622x_haptic_upload_lra(struct aw8622x *aw8622x, + unsigned int flag) +{ + switch (flag) { + case AW8622X_WRITE_ZERO: + aw_dev_info("%s write zero to trim_lra!\n", __func__); + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_TRIMCFG3, + AW8622X_BIT_TRIMCFG3_TRIM_LRA_MASK, + 0x00); + break; + case AW8622X_F0_CALI: + aw_dev_info("%s write f0_cali_data to trim_lra = 0x%02X\n", + __func__, aw8622x->f0_cali_data); + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_TRIMCFG3, + AW8622X_BIT_TRIMCFG3_TRIM_LRA_MASK, + (char)aw8622x->f0_cali_data); + break; + case AW8622X_OSC_CALI: + aw_dev_info("%s write osc_cali_data to trim_lra = 0x%02X\n", + __func__, aw8622x->osc_cali_data); + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_TRIMCFG3, + AW8622X_BIT_TRIMCFG3_TRIM_LRA_MASK, + (char)aw8622x->osc_cali_data); + break; + default: + break; + } +} + +/***************************************************** + * + * sram size, normally 3k(2k fifo, 1k ram) + * + *****************************************************/ +static int aw8622x_sram_size(struct aw8622x *aw8622x, int size_flag) +{ + if (size_flag == AW8622X_HAPTIC_SRAM_2K) { + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_RTPCFG1, + AW8622X_BIT_RTPCFG1_SRAM_SIZE_2K_MASK, + AW8622X_BIT_RTPCFG1_SRAM_SIZE_2K_EN); + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_RTPCFG1, + AW8622X_BIT_RTPCFG1_SRAM_SIZE_1K_MASK, + AW8622X_BIT_RTPCFG1_SRAM_SIZE_1K_DIS); + } else if (size_flag == AW8622X_HAPTIC_SRAM_1K) { + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_RTPCFG1, + AW8622X_BIT_RTPCFG1_SRAM_SIZE_2K_MASK, + AW8622X_BIT_RTPCFG1_SRAM_SIZE_2K_DIS); + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_RTPCFG1, + AW8622X_BIT_RTPCFG1_SRAM_SIZE_1K_MASK, + AW8622X_BIT_RTPCFG1_SRAM_SIZE_1K_EN); + } else if (size_flag == AW8622X_HAPTIC_SRAM_3K) { + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_RTPCFG1, + AW8622X_BIT_RTPCFG1_SRAM_SIZE_1K_MASK, + AW8622X_BIT_RTPCFG1_SRAM_SIZE_1K_EN); + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_RTPCFG1, + AW8622X_BIT_RTPCFG1_SRAM_SIZE_2K_MASK, + AW8622X_BIT_RTPCFG1_SRAM_SIZE_2K_EN); + } + return 0; +} + +static int aw8622x_haptic_stop(struct aw8622x *aw8622x) +{ + bool force_flag = true; + unsigned char cnt = 40; + unsigned char reg_val = 0; + + aw_dev_info("%s enter\n", __func__); + aw8622x->play_mode = AW8622X_HAPTIC_STANDBY_MODE; + reg_val = AW8622X_BIT_PLAYCFG4_STOP_ON; + aw8622x_i2c_write(aw8622x, AW8622X_REG_PLAYCFG4, ®_val, + AW_I2C_BYTE_ONE); + while (cnt) { + aw8622x_i2c_read(aw8622x, AW8622X_REG_GLBRD5, ®_val, + AW_I2C_BYTE_ONE); + if ((reg_val & AW8622X_BIT_GLBRD5_STATE) == + AW8622X_BIT_GLBRD5_STATE_STANDBY) { + cnt = 0; + force_flag = false; + aw_dev_info("%s entered standby! glb_state=0x%02X\n", + __func__, reg_val); + } else { + cnt--; + aw_dev_dbg("%s wait for standby, glb_state=0x%02X\n", + __func__, reg_val); + } + usleep_range(AW8622X_STOP_DELAY_MIN, AW8622X_STOP_DELAY_MAX); + } + + if (force_flag) { + aw_dev_err("%s force to enter standby mode!\n", __func__); + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSCTRL2, + AW8622X_BIT_SYSCTRL2_STANDBY_MASK, + AW8622X_BIT_SYSCTRL2_STANDBY_ON); + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSCTRL2, + AW8622X_BIT_SYSCTRL2_STANDBY_MASK, + AW8622X_BIT_SYSCTRL2_STANDBY_OFF); + } + return 0; +} + +static void aw8622x_haptic_raminit(struct aw8622x *aw8622x, bool flag) +{ + if (flag) { + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSCTRL1, + AW8622X_BIT_SYSCTRL1_RAMINIT_MASK, + AW8622X_BIT_SYSCTRL1_RAMINIT_ON); + } else { + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSCTRL1, + AW8622X_BIT_SYSCTRL1_RAMINIT_MASK, + AW8622X_BIT_SYSCTRL1_RAMINIT_OFF); + } +} + +static int aw8622x_haptic_get_vbat(struct aw8622x *aw8622x) +{ + unsigned char reg_val = 0; + unsigned int vbat_code = 0; + /*unsigned int cont = 2000;*/ + + aw8622x_haptic_stop(aw8622x); + aw8622x_haptic_raminit(aw8622x, true); + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_DETCFG2, + AW8622X_BIT_DETCFG2_VBAT_GO_MASK, + AW8622X_BIT_DETCFG2_VABT_GO_ON); + usleep_range(AW8622X_VBAT_DELAY_MIN, AW8622X_VBAT_DELAY_MAX); + aw8622x_i2c_read(aw8622x, AW8622X_REG_DET_VBAT, ®_val, + AW_I2C_BYTE_ONE); + vbat_code = (vbat_code | reg_val) << 2; + aw8622x_i2c_read(aw8622x, AW8622X_REG_DET_LO, ®_val, + AW_I2C_BYTE_ONE); + vbat_code = vbat_code | ((reg_val & AW8622X_BIT_DET_LO_VBAT) >> 4); + aw8622x->vbat = AW8622X_VBAT_FORMULA(vbat_code); + if (aw8622x->vbat > AW8622X_VBAT_MAX) { + aw8622x->vbat = AW8622X_VBAT_MAX; + aw_dev_info("%s vbat max limit = %dmV\n", __func__, + aw8622x->vbat); + } + if (aw8622x->vbat < AW8622X_VBAT_MIN) { + aw8622x->vbat = AW8622X_VBAT_MIN; + aw_dev_info("%s vbat min limit = %dmV\n", __func__, + aw8622x->vbat); + } + aw_dev_info("%s aw8622x->vbat=%dmV, vbat_code=0x%02X\n", + __func__, aw8622x->vbat, vbat_code); + aw8622x_haptic_raminit(aw8622x, false); + return 0; +} + +static void aw8622x_interrupt_clear(struct aw8622x *aw8622x) +{ + unsigned char reg_val = 0; + + aw8622x_i2c_read(aw8622x, AW8622X_REG_SYSINT, ®_val, + AW_I2C_BYTE_ONE); + aw_dev_dbg("%s: SYSINT=0x%02X\n", __func__, reg_val); +} + +static void aw8622x_haptic_set_gain(struct aw8622x *aw8622x, unsigned char gain) +{ + aw8622x_i2c_write(aw8622x, AW8622X_REG_PLAYCFG2, &gain, + AW_I2C_BYTE_ONE); +} + +static int aw8622x_haptic_ram_vbat_comp(struct aw8622x *aw8622x, + bool flag) +{ + int temp_gain = 0; + + if (flag) { + if (aw8622x->ram_vbat_compensate == + AW8622X_HAPTIC_RAM_VBAT_COMP_ENABLE) { + aw8622x_haptic_get_vbat(aw8622x); + temp_gain = + aw8622x->gain * AW8622X_VBAT_REFER / aw8622x->vbat; + if (temp_gain > + (128 * AW8622X_VBAT_REFER / AW8622X_VBAT_MIN)) { + temp_gain = + 128 * AW8622X_VBAT_REFER / AW8622X_VBAT_MIN; + aw_dev_dbg("%s gain limit=%d\n", __func__, + temp_gain); + } + aw8622x_haptic_set_gain(aw8622x, temp_gain); + } else { + aw8622x_haptic_set_gain(aw8622x, aw8622x->gain); + } + } else { + aw8622x_haptic_set_gain(aw8622x, aw8622x->gain); + } + return 0; +} + +static int aw8622x_haptic_play_mode(struct aw8622x *aw8622x, + unsigned char play_mode) +{ + aw_dev_info("%s enter\n", __func__); + + switch (play_mode) { + case AW8622X_HAPTIC_STANDBY_MODE: + aw_dev_info("%s: enter standby mode\n", __func__); + aw8622x->play_mode = AW8622X_HAPTIC_STANDBY_MODE; + aw8622x_haptic_stop(aw8622x); + break; + case AW8622X_HAPTIC_RAM_MODE: + aw_dev_info("%s: enter ram mode\n", __func__); + aw8622x->play_mode = AW8622X_HAPTIC_RAM_MODE; + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_PLAYCFG3, + AW8622X_BIT_PLAYCFG3_PLAY_MODE_MASK, + AW8622X_BIT_PLAYCFG3_PLAY_MODE_RAM); + break; + case AW8622X_HAPTIC_RAM_LOOP_MODE: + aw_dev_info("%s: enter ram loop mode\n", + __func__); + aw8622x->play_mode = AW8622X_HAPTIC_RAM_LOOP_MODE; + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_PLAYCFG3, + AW8622X_BIT_PLAYCFG3_PLAY_MODE_MASK, + AW8622X_BIT_PLAYCFG3_PLAY_MODE_RAM); + break; + case AW8622X_HAPTIC_RTP_MODE: + aw_dev_info("%s: enter rtp mode\n", __func__); + aw8622x->play_mode = AW8622X_HAPTIC_RTP_MODE; + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_PLAYCFG3, + AW8622X_BIT_PLAYCFG3_PLAY_MODE_MASK, + AW8622X_BIT_PLAYCFG3_PLAY_MODE_RTP); + break; + case AW8622X_HAPTIC_TRIG_MODE: + aw_dev_info("%s: enter trig mode\n", __func__); + aw8622x->play_mode = AW8622X_HAPTIC_TRIG_MODE; + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_PLAYCFG3, + AW8622X_BIT_PLAYCFG3_PLAY_MODE_MASK, + AW8622X_BIT_PLAYCFG3_PLAY_MODE_RAM); + break; + case AW8622X_HAPTIC_CONT_MODE: + aw_dev_info("%s: enter cont mode\n", __func__); + aw8622x->play_mode = AW8622X_HAPTIC_CONT_MODE; + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_PLAYCFG3, + AW8622X_BIT_PLAYCFG3_PLAY_MODE_MASK, + AW8622X_BIT_PLAYCFG3_PLAY_MODE_CONT); + break; + default: + aw_dev_err("%s: play mode %d error", + __func__, play_mode); + break; + } + return 0; +} + +static int aw8622x_haptic_play_go(struct aw8622x *aw8622x, bool flag) +{ + unsigned char reg_val = 0; + + aw_dev_dbg("%s enter\n", __func__); + if (flag == true) { + reg_val = AW8622X_BIT_PLAYCFG4_GO_ON; + aw8622x_i2c_write(aw8622x, AW8622X_REG_PLAYCFG4, ®_val, + AW_I2C_BYTE_ONE); + mdelay(2); + } else { + reg_val = AW8622X_BIT_PLAYCFG4_STOP_ON; + aw8622x_i2c_write(aw8622x, AW8622X_REG_PLAYCFG4, ®_val, + AW_I2C_BYTE_ONE); + } + return 0; +} + +static void aw8622x_haptic_set_wav_seq(struct aw8622x *aw8622x, + unsigned char wav, unsigned char seq) +{ + aw8622x_i2c_write(aw8622x, AW8622X_REG_WAVCFG1 + wav, &seq, + AW_I2C_BYTE_ONE); +} + +static int aw8622x_haptic_set_wav_loop(struct aw8622x *aw8622x, + unsigned char wav, unsigned char loop) +{ + unsigned char tmp = 0; + + if (wav % 2) { + tmp = loop << 0; + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_WAVCFG9 + (wav / 2), + AW8622X_BIT_WAVLOOP_SEQ_EVEN_MASK, tmp); + } else { + tmp = loop << 4; + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_WAVCFG9 + (wav / 2), + AW8622X_BIT_WAVLOOP_SEQ_ODD_MASK, tmp); + } + return 0; +} + +/***************************************************** + * + * haptic f0 cali + * + *****************************************************/ +static int aw8622x_haptic_read_lra_f0(struct aw8622x *aw8622x) +{ + unsigned char reg_val[2] = {0}; + unsigned int f0_reg = 0; + unsigned long f0_tmp = 0; + + aw_dev_info("%s enter\n", __func__); + /* F_LRA_F0 */ + aw8622x_i2c_read(aw8622x, AW8622X_REG_CONTRD14, reg_val, + AW_I2C_BYTE_TWO); + f0_reg = (f0_reg | reg_val[0]) << 8; + f0_reg |= (reg_val[1] << 0); + + + if (!f0_reg) { + aw_dev_err("%s didn't get lra f0 because f0_reg value is 0!\n", + __func__); + aw8622x->f0 = aw8622x->dts_info.f0_ref; + return -ERANGE; + } + f0_tmp = AW8622X_LRA_F0_FORMULA(f0_reg); + aw8622x->f0 = (unsigned int)f0_tmp; + aw_dev_info("%s lra_f0=%d\n", __func__, aw8622x->f0); + return 0; +} + +static int aw8622x_haptic_read_cont_f0(struct aw8622x *aw8622x) +{ + unsigned char reg_val[2] = {0}; + unsigned int f0_reg = 0; + unsigned long f0_tmp = 0; + + aw_dev_info("%s enter\n", __func__); + aw8622x_i2c_read(aw8622x, AW8622X_REG_CONTRD16, reg_val, + AW_I2C_BYTE_TWO); + f0_reg = (f0_reg | reg_val[0]) << 8; + f0_reg |= (reg_val[1] << 0); + + if (!f0_reg) { + aw_dev_err("%s didn't get cont f0 because f0_reg value is 0!\n", + __func__); + aw8622x->cont_f0 = aw8622x->dts_info.f0_ref; + return -ERANGE; + } + f0_tmp = AW8622X_CONT_F0_FORMULA(f0_reg); + aw8622x->cont_f0 = (unsigned int)f0_tmp; + aw_dev_info("%s cont_f0=%d\n", + __func__, aw8622x->cont_f0); + return 0; +} + +static int aw8622x_haptic_cont_get_f0(struct aw8622x *aw8622x) +{ + bool get_f0_flag = false; + unsigned char reg_val = 0; + unsigned char brk_en_temp = 0; + unsigned char reg_array[3] = {0}; + unsigned int cnt = 200; + int ret = 0; + + aw_dev_info("%s enter\n", __func__); + aw8622x->f0 = aw8622x->dts_info.f0_ref; + /* enter standby mode */ + aw8622x_haptic_stop(aw8622x); + /* f0 calibrate work mode */ + aw8622x_haptic_play_mode(aw8622x, AW8622X_HAPTIC_CONT_MODE); + /* enable f0 detect */ + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_CONTCFG1, + AW8622X_BIT_CONTCFG1_EN_F0_DET_MASK, + AW8622X_BIT_CONTCFG1_F0_DET_ENABLE); + /* cont config */ + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_CONTCFG6, + AW8622X_BIT_CONTCFG6_TRACK_EN_MASK, + AW8622X_BIT_CONTCFG6_TRACK_ENABLE); + /* enable auto brake */ + aw8622x_i2c_read(aw8622x, AW8622X_REG_PLAYCFG3, ®_val, + AW_I2C_BYTE_ONE); + brk_en_temp = AW8622X_BIT_PLAYCFG3_BRK & reg_val; + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_PLAYCFG3, + AW8622X_BIT_PLAYCFG3_BRK_EN_MASK, + AW8622X_BIT_PLAYCFG3_BRK_ENABLE); + /* f0 driver level */ + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_CONTCFG6, + AW8622X_BIT_CONTCFG6_DRV1_LVL_MASK, + aw8622x->dts_info.cont_drv1_lvl_dt); + reg_array[0] = (unsigned char)aw8622x->dts_info.cont_drv2_lvl_dt; + reg_array[1] = (unsigned char)aw8622x->dts_info.cont_drv1_time_dt; + reg_array[2] = (unsigned char)aw8622x->dts_info.cont_drv2_time_dt; + aw8622x_i2c_write(aw8622x, AW8622X_REG_CONTCFG7, reg_array, + AW_I2C_BYTE_THREE); + /* TRACK_MARGIN */ + if (!aw8622x->dts_info.cont_track_margin) { + aw_dev_err("%s aw8622x->dts_info.cont_track_margin = 0!\n", + __func__); + } else { + reg_val = (unsigned char)aw8622x->dts_info.cont_track_margin; + aw8622x_i2c_write(aw8622x, AW8622X_REG_CONTCFG11, ®_val, + AW_I2C_BYTE_ONE); + } + /* cont play go */ + aw8622x_haptic_play_go(aw8622x, true); + /* 300ms */ + while (cnt) { + aw8622x_i2c_read(aw8622x, AW8622X_REG_GLBRD5, ®_val, + AW_I2C_BYTE_ONE); + if ((reg_val & AW8622X_BIT_GLBRD5_STATE) == + AW8622X_BIT_GLBRD5_STATE_STANDBY) { + cnt = 0; + get_f0_flag = true; + aw_dev_info("%s entered standby mode! glb_state=0x%02X\n", + __func__, reg_val); + } else { + cnt--; + aw_dev_dbg("%s waitting for standby, glb_state=0x%02X\n", + __func__, reg_val); + } + usleep_range(AW8622X_F0_DELAY_MIN, AW8622X_F0_DELAY_MAX); + } + if (get_f0_flag) { + aw8622x_haptic_read_lra_f0(aw8622x); + aw8622x_haptic_read_cont_f0(aw8622x); + } else { + aw_dev_err("%s enter standby mode failed, stop reading f0!\n", + __func__); + } + /* restore default config */ + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_CONTCFG1, + AW8622X_BIT_CONTCFG1_EN_F0_DET_MASK, + AW8622X_BIT_CONTCFG1_F0_DET_DISABLE); + /* recover auto break config */ + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_PLAYCFG3, + AW8622X_BIT_PLAYCFG3_BRK_EN_MASK, + brk_en_temp); + return ret; +} + +static int aw8622x_haptic_rtp_init(struct aw8622x *aw8622x) +{ + unsigned int buf_len = 0; + unsigned char glb_state_val = 0; + struct aw8622x_container *rtp_container = aw8622x->rtp_container; + + aw_dev_dbg("%s enter\n", __func__); + pm_qos_add_request(&aw8622x_pm_qos_req_vb, PM_QOS_CPU_DMA_LATENCY, + AW8622X_PM_QOS_VALUE_VB); + aw8622x->rtp_cnt = 0; + mutex_lock(&aw8622x->rtp_lock); + while ((!aw8622x_haptic_rtp_get_fifo_afs(aw8622x)) + && (aw8622x->play_mode == AW8622X_HAPTIC_RTP_MODE)) { +#ifdef AW_ENABLE_RTP_PRINT_LOG + aw_dev_info("%s rtp cnt = %d\n", __func__, aw8622x->rtp_cnt); +#endif + if (!rtp_container) { + aw_dev_info("%s:rtp_container is null, break!\n", + __func__); + break; + } + if (aw8622x->rtp_cnt < (aw8622x->ram.base_addr)) { + if ((rtp_container->len - aw8622x->rtp_cnt) < + (aw8622x->ram.base_addr)) { + buf_len = rtp_container->len - aw8622x->rtp_cnt; + } else { + buf_len = aw8622x->ram.base_addr; + } + } else if ((rtp_container->len - aw8622x->rtp_cnt) < + (aw8622x->ram.base_addr >> 2)) { + buf_len = rtp_container->len - aw8622x->rtp_cnt; + } else { + buf_len = aw8622x->ram.base_addr >> 2; + } +#ifdef AW_ENABLE_RTP_PRINT_LOG + aw_dev_info("%s buf_len = %d\n", __func__, + buf_len); +#endif + aw8622x_i2c_write(aw8622x, AW8622X_REG_RTPDATA, + &rtp_container->data[aw8622x->rtp_cnt], + buf_len); + aw8622x->rtp_cnt += buf_len; + aw8622x_i2c_read(aw8622x, AW8622X_REG_GLBRD5, &glb_state_val, + AW_I2C_BYTE_ONE); + if ((aw8622x->rtp_cnt == rtp_container->len) + || ((glb_state_val & AW8622X_BIT_GLBRD5_STATE) == + AW8622X_BIT_GLBRD5_STATE_STANDBY)) { + if (aw8622x->rtp_cnt == rtp_container->len) + aw_dev_info("%s: rtp load completely! glb_state_val=%02x aw8622x->rtp_cnt=%02x\n", + __func__, glb_state_val, + aw8622x->rtp_cnt); + else + aw_dev_err("%s rtp load failed!! glb_state_val=%02x aw8622x->rtp_cnt=%02x\n", + __func__, glb_state_val, + aw8622x->rtp_cnt); + aw8622x->rtp_cnt = 0; + pm_qos_remove_request(&aw8622x_pm_qos_req_vb); + mutex_unlock(&aw8622x->rtp_lock); + return 0; + } + } + + if (aw8622x->play_mode == AW8622X_HAPTIC_RTP_MODE) + aw8622x_haptic_set_rtp_aei(aw8622x, true); + + aw_dev_dbg("%s exit\n", __func__); + mutex_unlock(&aw8622x->rtp_lock); + pm_qos_remove_request(&aw8622x_pm_qos_req_vb); + return 0; +} + +static int aw8622x_haptic_ram_config(struct aw8622x *aw8622x, int duration) +{ + int ret = 0; + + if (aw8622x->duration_time_flag < 0) { + aw_dev_err("%s: duration time error, array size = %d\n", + __func__, aw8622x->duration_time_size); + return -ERANGE; + } + ret = aw8622x_analyse_duration_range(aw8622x); + if (ret < 0) + return ret; + + if ((duration > 0) && (duration < + aw8622x->dts_info.duration_time[0])) { + aw8622x->index = 3; /*3*/ + aw8622x->activate_mode = AW8622X_HAPTIC_RAM_MODE; + } else if ((duration >= aw8622x->dts_info.duration_time[0]) && + (duration < aw8622x->dts_info.duration_time[1])) { + aw8622x->index = 2; /*2*/ + aw8622x->activate_mode = AW8622X_HAPTIC_RAM_MODE; + } else if ((duration >= aw8622x->dts_info.duration_time[1]) && + (duration < aw8622x->dts_info.duration_time[2])) { + aw8622x->index = 1; /*1*/ + aw8622x->activate_mode = AW8622X_HAPTIC_RAM_MODE; + } else if (duration >= aw8622x->dts_info.duration_time[2]) { + aw8622x->index = 4; /*4*/ + aw8622x->activate_mode = AW8622X_HAPTIC_RAM_LOOP_MODE; + } else { + aw_dev_err("%s: duration time error, duration= %d\n", + __func__, duration); + aw8622x->index = 0; + aw8622x->activate_mode = AW8622X_HAPTIC_NULL; + ret = -ERANGE; + } + + return ret; +} + +static unsigned char aw8622x_haptic_osc_read_status(struct aw8622x *aw8622x) +{ + unsigned char reg_val = 0; + + aw8622x_i2c_read(aw8622x, AW8622X_REG_SYSST2, ®_val, + AW_I2C_BYTE_ONE); + return reg_val; +} + +static int aw8622x_haptic_set_repeat_wav_seq(struct aw8622x *aw8622x, + unsigned char seq) +{ + aw8622x_haptic_set_wav_seq(aw8622x, 0x00, seq); + aw8622x_haptic_set_wav_seq(aw8622x, 0x01, 0x00); + aw8622x_haptic_set_wav_loop(aw8622x, 0x00, + AW8622X_BIT_WAVLOOP_INIFINITELY); + return 0; +} + +static void aw8622x_rtp_work_routine(struct work_struct *work) +{ + bool rtp_work_flag = false; + unsigned char reg_val = 0; + unsigned int cnt = 200; + int ret = -1; + const struct firmware *rtp_file; + struct aw8622x *aw8622x = container_of(work, struct aw8622x, rtp_work); + + aw_dev_info("%s enter\n", __func__); + mutex_lock(&aw8622x->rtp_lock); + /* fw loaded */ + ret = request_firmware(&rtp_file, + aw8622x_rtp_name[aw8622x->rtp_file_num], + aw8622x->dev); + if (ret < 0) { + aw_dev_err("%s: failed to read %s\n", __func__, + aw8622x_rtp_name[aw8622x->rtp_file_num]); + mutex_unlock(&aw8622x->rtp_lock); + return; + } + aw8622x->rtp_init = 0; + vfree(aw8622x->rtp_container); + aw8622x->rtp_container = vmalloc(rtp_file->size + sizeof(int)); + if (!aw8622x->rtp_container) { + release_firmware(rtp_file); + aw_dev_err("%s: error allocating memory\n", __func__); + mutex_unlock(&aw8622x->rtp_lock); + return; + } + aw8622x->rtp_container->len = rtp_file->size; + aw_dev_info("%s: rtp file:[%s] size = %dbytes\n", + __func__, aw8622x_rtp_name[aw8622x->rtp_file_num], + aw8622x->rtp_container->len); + memcpy(aw8622x->rtp_container->data, rtp_file->data, rtp_file->size); + mutex_unlock(&aw8622x->rtp_lock); + release_firmware(rtp_file); + mutex_lock(&aw8622x->lock); + aw8622x->rtp_init = 1; + aw8622x_haptic_upload_lra(aw8622x, AW8622X_OSC_CALI); + /* gain */ + aw8622x_haptic_ram_vbat_comp(aw8622x, false); + /* rtp mode config */ + aw8622x_haptic_play_mode(aw8622x, AW8622X_HAPTIC_RTP_MODE); + /* haptic go */ + aw8622x_haptic_play_go(aw8622x, true); + mutex_unlock(&aw8622x->lock); + usleep_range(AW8622X_STOP_DELAY_MIN, AW8622X_STOP_DELAY_MAX); + while (cnt) { + aw8622x_i2c_read(aw8622x, AW8622X_REG_GLBRD5, ®_val, + AW_I2C_BYTE_ONE); + if ((reg_val & AW8622X_BIT_GLBRD5_STATE) == + AW8622X_BIT_GLBRD5_STATE_RTP_GO) { + cnt = 0; + rtp_work_flag = true; + aw_dev_info("%s RTP_GO! glb_state=0x08\n", __func__); + } else { + cnt--; + aw_dev_dbg("%s wait for RTP_GO, glb_state=0x%02X\n", + __func__, reg_val); + } + usleep_range(AW8622X_STOP_DELAY_MIN, AW8622X_STOP_DELAY_MAX); + } + if (rtp_work_flag) { + aw8622x_haptic_rtp_init(aw8622x); + } else { + /* enter standby mode */ + aw8622x_haptic_stop(aw8622x); + aw_dev_err("%s failed to enter RTP_GO status!\n", __func__); + } +} + +static int aw8622x_osc_calculation_time(struct aw8622x *aw8622x) +{ + unsigned char osc_int_state = 0; + unsigned int base_addr = aw8622x->ram.base_addr; + unsigned int buf_len = 0; + int ret = -1; + struct aw8622x_container *rtp_container = aw8622x->rtp_container; + + if (!aw8622x_haptic_rtp_get_fifo_afs(aw8622x)) { + aw_dev_dbg("%s: haptic_rtp_get_fifo_afi, rtp_cnt= %d\n", + __func__, aw8622x->rtp_cnt); + + mutex_lock(&aw8622x->rtp_lock); + if ((rtp_container->len - aw8622x->rtp_cnt) < (base_addr >> 2)) + buf_len = rtp_container->len - aw8622x->rtp_cnt; + else + buf_len = (base_addr >> 2); + + if (aw8622x->rtp_cnt != rtp_container->len) { + if (aw8622x->timeval_flags == 1) { + aw8622x->kstart = ktime_get(); + aw8622x->timeval_flags = 0; + } + aw8622x_i2c_write(aw8622x, AW8622X_REG_RTPDATA, + &rtp_container->data[aw8622x->rtp_cnt], + buf_len); + aw8622x->rtp_cnt += buf_len; + } + mutex_unlock(&aw8622x->rtp_lock); + } + + osc_int_state = aw8622x_haptic_osc_read_status(aw8622x); + if (osc_int_state & AW8622X_BIT_SYSST2_FF_EMPTY) { + aw8622x->kend = ktime_get(); + aw_dev_info("%s osc trim playback done aw8622x->rtp_cnt= %d\n", + __func__, aw8622x->rtp_cnt); + return ret; + } + aw8622x->kend = ktime_get(); + aw8622x->microsecond = ktime_to_us(ktime_sub(aw8622x->kend, + aw8622x->kstart)); + + if (aw8622x->microsecond > AW8622X_OSC_CALI_MAX_LENGTH) { + aw_dev_info("%s osc trim time out! aw8622x->rtp_cnt %d\n", + __func__, aw8622x->rtp_cnt); + aw_dev_info("%s osc_int_state %02x\n", __func__, osc_int_state); + return ret; + } + return 0; +} + +static int aw8622x_rtp_osc_calibration(struct aw8622x *aw8622x) +{ + int ret = -1; + const struct firmware *rtp_file; + + aw8622x->rtp_cnt = 0; + aw8622x->timeval_flags = 1; + + aw_dev_info("%s enter\n", __func__); + /* fw loaded */ + ret = request_firmware(&rtp_file, aw8622x_rtp_name[0], aw8622x->dev); + if (ret < 0) { + aw_dev_err("%s: failed to read %s\n", __func__, + aw8622x_rtp_name[0]); + return ret; + } + /*awinic add stop,for irq interrupt during calibrate */ + aw8622x_haptic_stop(aw8622x); + aw8622x->rtp_init = 0; + mutex_lock(&aw8622x->rtp_lock); + vfree(aw8622x->rtp_container); + aw8622x->rtp_container = vmalloc(rtp_file->size + sizeof(int)); + if (!aw8622x->rtp_container) { + release_firmware(rtp_file); + mutex_unlock(&aw8622x->rtp_lock); + aw_dev_err("%s: error allocating memory\n", + __func__); + return -ENOMEM; + } + aw8622x->rtp_container->len = rtp_file->size; + aw8622x->rtp_len = rtp_file->size; + aw_dev_info("%s: rtp file:[%s] size = %dbytes\n", + __func__, aw8622x_rtp_name[0], aw8622x->rtp_container->len); + + memcpy(aw8622x->rtp_container->data, rtp_file->data, rtp_file->size); + release_firmware(rtp_file); + mutex_unlock(&aw8622x->rtp_lock); + /* gain */ + aw8622x_haptic_ram_vbat_comp(aw8622x, false); + /* rtp mode config */ + aw8622x_haptic_play_mode(aw8622x, AW8622X_HAPTIC_RTP_MODE); + + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSCTRL7, + AW8622X_BIT_SYSCTRL7_INT_MODE_MASK, + AW8622X_BIT_SYSCTRL7_INT_MODE_EDGE); + disable_irq(gpio_to_irq(aw8622x->irq_gpio)); + /* haptic go */ + aw8622x_haptic_play_go(aw8622x, true); + /* require latency of CPU & DMA not more then PM_QOS_VALUE_VB us */ + pm_qos_add_request(&aw8622x_pm_qos_req_vb, PM_QOS_CPU_DMA_LATENCY, + AW8622X_PM_QOS_VALUE_VB); + while (1) { + ret = aw8622x_osc_calculation_time(aw8622x); + if (ret < 0) + break; + } + pm_qos_remove_request(&aw8622x_pm_qos_req_vb); + enable_irq(gpio_to_irq(aw8622x->irq_gpio)); + aw8622x->microsecond = ktime_to_us(ktime_sub(aw8622x->kend, + aw8622x->kstart)); + /*calibration osc */ + aw_dev_info("%s awinic_microsecond: %ld\n", __func__, + aw8622x->microsecond); + aw_dev_info("%s exit\n", __func__); + return 0; +} + +static int aw8622x_osc_trim_calculation(struct aw8622x *aw8622x, + unsigned long int theory_time) +{ + unsigned int real_code = 0; + unsigned int lra_code = 0; + unsigned int DFT_LRA_TRIM_CODE = 0; + /*0.1 percent below no need to calibrate */ + unsigned int osc_cali_threshold = 10; + unsigned long int real_time = aw8622x->microsecond; + + + aw_dev_info("%s enter\n", __func__); + if (theory_time == real_time) { + aw_dev_info("%s theory_time == real_time: %ld, no need to calibrate!\n", + __func__, real_time); + return 0; + } else if (theory_time < real_time) { + if ((real_time - theory_time) > (theory_time / 50)) { + aw_dev_info("%s (real_time - theory_time) > (theory_time/50), can't calibrate!\n", + __func__); + return DFT_LRA_TRIM_CODE; + } + + if ((real_time - theory_time) < + (osc_cali_threshold * theory_time / 10000)) { + aw_dev_info("%s real_time: %ld, theory_time: %ld, no need to calibrate!\n", + __func__, real_time, theory_time); + return DFT_LRA_TRIM_CODE; + } + + real_code = ((real_time - theory_time) * 4000) / theory_time; + real_code = ((real_code % 10 < 5) ? 0 : 1) + real_code / 10; + real_code = 32 + real_code; + } else if (theory_time > real_time) { + if ((theory_time - real_time) > (theory_time / 50)) { + aw_dev_info("%s (theory_time - real_time) > (theory_time / 50), can't calibrate!\n", + __func__); + return DFT_LRA_TRIM_CODE; + } + if ((theory_time - real_time) < + (osc_cali_threshold * theory_time / 10000)) { + aw_dev_info("%s real_time: %ld, theory_time: %ld, no need to calibrate!\n", + __func__, real_time, theory_time); + return DFT_LRA_TRIM_CODE; + } + real_code = ((theory_time - real_time) * 4000) / theory_time; + real_code = ((real_code % 10 < 5) ? 0 : 1) + real_code / 10; + real_code = 32 - real_code; + } + if (real_code > 31) + lra_code = real_code - 32; + else + lra_code = real_code + 32; + aw_dev_info("%s real_time: %ld, theory_time: %ld\n", __func__, + real_time, theory_time); + aw_dev_info("%s real_code: %02X, trim_lra: 0x%02X\n", __func__, + real_code, lra_code); + return lra_code; +} + +static int aw8622x_haptic_get_lra_resistance(struct aw8622x *aw8622x) +{ + unsigned char reg_val = 0; + unsigned char d2s_gain_temp = 0; + unsigned int lra_code = 0; + unsigned int lra = 0; + + mutex_lock(&aw8622x->lock); + aw8622x_haptic_stop(aw8622x); + aw8622x_i2c_read(aw8622x, AW8622X_REG_SYSCTRL7, ®_val, + AW_I2C_BYTE_ONE); + d2s_gain_temp = AW8622X_BIT_SYSCTRL7_GAIN & reg_val; + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSCTRL7, + AW8622X_BIT_SYSCTRL7_D2S_GAIN_MASK, + aw8622x->dts_info.d2s_gain); + aw8622x_haptic_raminit(aw8622x, true); + /* enter standby mode */ + aw8622x_haptic_stop(aw8622x); + usleep_range(AW8622X_STOP_DELAY_MIN, AW8622X_STOP_DELAY_MAX); + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSCTRL2, + AW8622X_BIT_SYSCTRL2_STANDBY_MASK, + AW8622X_BIT_SYSCTRL2_STANDBY_OFF); + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_DETCFG1, + AW8622X_BIT_DETCFG1_RL_OS_MASK, + AW8622X_BIT_DETCFG1_RL); + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_DETCFG2, + AW8622X_BIT_DETCFG2_DIAG_GO_MASK, + AW8622X_BIT_DETCFG2_DIAG_GO_ON); + usleep_range(AW8622X_LRA_DELAY_MIN, AW8622X_LRA_DELAY_MAX); + aw8622x_i2c_read(aw8622x, AW8622X_REG_DET_RL, ®_val, + AW_I2C_BYTE_ONE); + lra_code = (lra_code | reg_val) << 2; + aw8622x_i2c_read(aw8622x, AW8622X_REG_DET_LO, ®_val, + AW_I2C_BYTE_ONE); + lra_code = lra_code | (reg_val & AW8622X_BIT_DET_LO_RL); + /* 2num */ + lra = AW8622X_LRA_FORMULA(lra_code); + /* Keep up with aw8624 driver */ + aw8622x->lra = lra * 10; + aw8622x_haptic_raminit(aw8622x, false); + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSCTRL7, + AW8622X_BIT_SYSCTRL7_D2S_GAIN_MASK, + d2s_gain_temp); + mutex_unlock(&aw8622x->lock); + return 0; +} + +static int aw8622x_haptic_juge_RTP_is_going_on(struct aw8622x *aw8622x) +{ + unsigned char rtp_state = 0; + unsigned char mode = 0; + unsigned char glb_st = 0; + + aw8622x_i2c_read(aw8622x, AW8622X_REG_PLAYCFG3, &mode, + AW_I2C_BYTE_ONE); + aw8622x_i2c_read(aw8622x, AW8622X_REG_GLBRD5, &glb_st, + AW_I2C_BYTE_ONE); + if ((mode & AW8622X_BIT_PLAYCFG3_PLAY_MODE_RTP) && + (glb_st == AW8622X_BIT_GLBRD5_STATE_RTP_GO)) { + rtp_state = 1; + } + return rtp_state; +} + +static void aw8622x_set_ram_addr(struct aw8622x *aw8622x) +{ + unsigned char ram_addr[2] = {0}; + unsigned int base_addr = aw8622x->ram.base_addr; + + ram_addr[0] = (unsigned char)AW_SET_RAMADDR_H(base_addr); + ram_addr[1] = (unsigned char)AW_SET_RAMADDR_L(base_addr); + aw8622x_i2c_write(aw8622x, AW8622X_REG_RAMADDRH, ram_addr, + AW_I2C_BYTE_TWO); +} + +#ifdef AW_CHECK_RAM_DATA +static int aw8622x_check_ram_data(struct aw8622x *aw8622x, + unsigned char *cont_data, + unsigned char *ram_data, unsigned int len) +{ + int i = 0; + + for (i = 0; i < len; i++) { + if (ram_data[i] != cont_data[i]) { + aw_dev_err("%s: check ramdata error, addr=0x%04x, ram_data=0x%02x, file_data=0x%02x\n", + __func__, i, ram_data[i], cont_data[i]); + return -ERANGE; + } + } + return 0; +} +#endif + +static int aw8622x_container_update(struct aw8622x *aw8622x, + struct aw8622x_container *aw8622x_cont) +{ + unsigned char ae_addr_h = 0; + unsigned char af_addr_h = 0; + unsigned char ae_addr_l = 0; + unsigned char af_addr_l = 0; + unsigned char reg_array[3] = {0}; + unsigned int shift = 0; + unsigned int base_addr = 0; + int i = 0; + int ret = 0; + int len = 0; +#ifdef AW_CHECK_RAM_DATA + unsigned char ram_data[AW_RAMDATA_RD_BUFFER_SIZE] = {0}; +#endif + + aw_dev_info("%s enter\n", __func__); + mutex_lock(&aw8622x->lock); + aw8622x->ram.baseaddr_shift = 2; + aw8622x->ram.ram_shift = 4; + /* RAMINIT Enable */ + aw8622x_haptic_raminit(aw8622x, true); + /* Enter standby mode */ + aw8622x_haptic_stop(aw8622x); + /* default 3k SRAM */ + aw8622x_sram_size(aw8622x, AW8622X_HAPTIC_SRAM_3K); + /* set base addr */ + shift = aw8622x->ram.baseaddr_shift; + aw8622x->ram.base_addr = + (unsigned int)((aw8622x_cont->data[0 + shift] << 8) | + (aw8622x_cont->data[1 + shift])); + base_addr = aw8622x->ram.base_addr; + aw_dev_info("%s: base_addr=%d\n", __func__, base_addr); + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_RTPCFG1, + AW8622X_BIT_RTPCFG1_ADDRH_MASK, + (unsigned char)AW_SET_BASEADDR_H(base_addr)); + reg_array[0] = (unsigned char)AW_SET_BASEADDR_L(base_addr); + aw8622x_i2c_write(aw8622x, AW8622X_REG_RTPCFG2, + ®_array[0], AW_I2C_BYTE_ONE); + /* set FIFO_AE and FIFO_AF addr */ + ae_addr_h = (unsigned char)AW8622X_SET_AEADDR_H(base_addr); + af_addr_h = (unsigned char)AW8622X_SET_AFADDR_H(base_addr); + reg_array[0] = ae_addr_h | af_addr_h; + reg_array[1] = (unsigned char)AW8622X_SET_AEADDR_L(base_addr); + reg_array[2] = (unsigned char)AW8622X_SET_AFADDR_L(base_addr); + aw8622x_i2c_write(aw8622x, AW8622X_REG_RTPCFG3, reg_array, + AW_I2C_BYTE_THREE); + /* get FIFO_AE and FIFO_AF addr */ + aw8622x_i2c_read(aw8622x, AW8622X_REG_RTPCFG3, reg_array, + AW_I2C_BYTE_THREE); + ae_addr_h = ((reg_array[0]) & AW8622X_BIT_RTPCFG3_FIFO_AEH) >> 4; + ae_addr_l = reg_array[1]; + aw_dev_info("%s: almost_empty_threshold = %d\n", __func__, + (unsigned short)((ae_addr_h << 8) | ae_addr_l)); + af_addr_h = ((reg_array[0]) & AW8622X_BIT_RTPCFG3_FIFO_AFH); + af_addr_l = reg_array[2]; + aw_dev_info("%s: almost_full_threshold = %d\n", __func__, + (unsigned short)((af_addr_h << 8) | af_addr_l)); + + /* ram */ + aw8622x_set_ram_addr(aw8622x); + i = aw8622x->ram.ram_shift; + while (i < aw8622x_cont->len) { + if ((aw8622x_cont->len - i) < AW_RAMDATA_WR_BUFFER_SIZE) + len = aw8622x_cont->len - i; + else + len = AW_RAMDATA_WR_BUFFER_SIZE; + + aw8622x_i2c_write(aw8622x, AW8622X_REG_RAMDATA, + &aw8622x_cont->data[i], len); + i += len; + } +#ifdef AW_CHECK_RAM_DATA + aw8622x_set_ram_addr(aw8622x); + i = aw8622x->ram.ram_shift; + while (i < aw8622x_cont->len) { + if ((aw8622x_cont->len - i) < AW_RAMDATA_RD_BUFFER_SIZE) + len = aw8622x_cont->len - i; + else + len = AW_RAMDATA_RD_BUFFER_SIZE; + + aw8622x_i2c_read(aw8622x, AW8622X_REG_RAMDATA, ram_data, len); + ret = aw8622x_check_ram_data(aw8622x, &aw8622x_cont->data[i], + ram_data, len); + if (ret < 0) + break; + i += len; + } + if (ret) + aw_dev_err("%s: ram data check sum error\n", __func__); + else + aw_dev_info("%s: ram data check sum pass\n", __func__); + + +#endif + /* RAMINIT Disable */ + aw8622x_haptic_raminit(aw8622x, false); + mutex_unlock(&aw8622x->lock); + aw_dev_info("%s exit\n", __func__); + return ret; +} + +static int aw8622x_haptic_get_ram_number(struct aw8622x *aw8622x) +{ + unsigned char ram_data[3]; + unsigned int first_wave_addr = 0; + + aw_dev_info("%s enter!\n", __func__); + if (!aw8622x->ram_init) { + aw_dev_err("%s: ram init faild, ram_num = 0!\n", + __func__); + return -EPERM; + } + + mutex_lock(&aw8622x->lock); + /* RAMINIT Enable */ + aw8622x_haptic_raminit(aw8622x, true); + aw8622x_haptic_stop(aw8622x); + aw8622x_set_ram_addr(aw8622x); + aw8622x_i2c_read(aw8622x, AW8622X_REG_RAMDATA, ram_data, + AW_I2C_BYTE_THREE); + first_wave_addr = (ram_data[1] << 8 | ram_data[2]); + aw8622x->ram.ram_num = + (first_wave_addr - aw8622x->ram.base_addr - 1) / 4; + aw_dev_info("%s: ram_version = 0x%02x\n", __func__, ram_data[0]); + aw_dev_info("%s: first waveform addr = 0x%04x\n", __func__, + first_wave_addr); + aw_dev_info("%s: ram_num = %d\n", __func__, aw8622x->ram.ram_num); + /* RAMINIT Disable */ + aw8622x_haptic_raminit(aw8622x, false); + mutex_unlock(&aw8622x->lock); + + return 0; +} + +static void aw8622x_ram_check(const struct firmware *cont, void *context) +{ + unsigned short check_sum = 0; + int i = 0; + int ret = 0; + struct aw8622x *aw8622x = context; + struct aw8622x_container *aw8622x_fw; +#ifdef AW_READ_BIN_FLEXBALLY + static unsigned char load_cont; + int ram_timer_val = 1000; + + load_cont++; +#endif + aw_dev_info("%s enter\n", __func__); + if (!cont) { + aw_dev_err("%s: failed to read %s\n", __func__, + aw8622x_ram_name); + release_firmware(cont); +#ifdef AW_READ_BIN_FLEXBALLY + if (load_cont <= 20) { + schedule_delayed_work(&aw8622x->ram_work, + msecs_to_jiffies(ram_timer_val)); + aw_dev_info("%s:start hrtimer: load_cont=%d\n", + __func__, load_cont); + } +#endif + return; + } + aw_dev_info("%s: loaded %s - size: %zu bytes\n", __func__, + aw8622x_ram_name, cont ? cont->size : 0); +/* +* for(i=0; i < cont->size; i++) { +* aw_dev_info("%s: addr: 0x%04x, data: 0x%02X\n", +* __func__, i, *(cont->data+i)); +* } +*/ + /* check sum */ + for (i = 2; i < cont->size; i++) + check_sum += cont->data[i]; + if (check_sum == (unsigned short)((cont->data[0]<<8)|(cont->data[1]))) { + + aw_dev_info("%s: check sum pass: 0x%04x\n", + __func__, check_sum); + aw8622x->ram.check_sum = check_sum; + } else { + aw_dev_err("%s: check sum err: check_sum=0x%04x\n", __func__, + check_sum); + return; + } + + /* aw8622x ram update less then 128kB */ + aw8622x_fw = kzalloc(cont->size + sizeof(int), GFP_KERNEL); + if (!aw8622x_fw) { + release_firmware(cont); + aw_dev_err("%s: Error allocating memory\n", + __func__); + return; + } + aw8622x_fw->len = cont->size; + memcpy(aw8622x_fw->data, cont->data, cont->size); + release_firmware(cont); + ret = aw8622x_container_update(aw8622x, aw8622x_fw); + if (ret) { + kfree(aw8622x_fw); + aw8622x->ram.len = 0; + aw_dev_err("%s: ram firmware update failed!\n", __func__); + } else { + aw8622x->ram_init = 1; + aw8622x->ram.len = aw8622x_fw->len; + kfree(aw8622x_fw); + aw_dev_info("%s: ram firmware update complete!\n", __func__); + } + aw8622x_haptic_get_ram_number(aw8622x); + +} + +static int aw8622x_ram_update(struct aw8622x *aw8622x) +{ + aw8622x->ram_init = 0; + aw8622x->rtp_init = 0; + + return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + aw8622x_ram_name, aw8622x->dev, + GFP_KERNEL, aw8622x, aw8622x_ram_check); +} + +static int aw8622x_rtp_trim_lra_calibration(struct aw8622x *aw8622x) +{ + unsigned char reg_val = 0; + unsigned int fre_val = 0; + unsigned int theory_time = 0; + unsigned int lra_trim_code = 0; + unsigned int rate = 0; + + aw8622x_i2c_read(aw8622x, AW8622X_REG_SYSCTRL2, ®_val, + AW_I2C_BYTE_ONE); + fre_val = (reg_val & AW8622X_BIT_SYSCTRL2_RATE) >> 0; + + if (fre_val == AW8622X_BIT_SYSCTRL2_RATE_48K) + rate = 48000; + else if (fre_val == AW8622X_BIT_SYSCTRL2_RATE_24K) + rate = 24000; + else + rate = 12000; + + theory_time = (aw8622x->rtp_len / rate) * 1000000; + + aw_dev_info("%s microsecond:%ld theory_time = %d\n", __func__, + aw8622x->microsecond, theory_time); + + lra_trim_code = aw8622x_osc_trim_calculation(aw8622x, theory_time); + if (lra_trim_code >= 0) { + aw8622x->osc_cali_data = lra_trim_code; + aw8622x_haptic_upload_lra(aw8622x, AW8622X_OSC_CALI); + } + return 0; +} + +static enum hrtimer_restart aw8622x_vibrator_timer_func(struct hrtimer *timer) +{ + struct aw8622x *aw8622x = container_of(timer, struct aw8622x, timer); + + aw_dev_info("%s enter\n", __func__); + aw8622x->state = 0; + schedule_work(&aw8622x->vibrator_work); + + return HRTIMER_NORESTART; +} + +static int aw8622x_haptic_trig_param_init(struct aw8622x *aw8622x) +{ + aw_dev_info("%s enter\n", __func__); + + if ((aw8622x->name == AW86224_5) && (aw8622x->isUsedIntn)) + return 0; + /* trig1 date */ + aw8622x->trig[0].trig_level = aw8622x->dts_info.trig_config[0]; + aw8622x->trig[0].trig_polar = aw8622x->dts_info.trig_config[1]; + aw8622x->trig[0].pos_enable = aw8622x->dts_info.trig_config[2]; + aw8622x->trig[0].pos_sequence = aw8622x->dts_info.trig_config[3]; + aw8622x->trig[0].neg_enable = aw8622x->dts_info.trig_config[4]; + aw8622x->trig[0].neg_sequence = aw8622x->dts_info.trig_config[5]; + aw8622x->trig[0].trig_brk = aw8622x->dts_info.trig_config[6]; + aw_dev_info("%s: trig1 date init ok!\n", __func__); + if ((aw8622x->name == AW86224_5) && (!aw8622x->isUsedIntn)) { + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSCTRL2, + AW8622X_BIT_SYSCTRL2_INTN_PIN_MASK, + AW8622X_BIT_SYSCTRL2_TRIG1); + return 0; + } + + /* trig2 date */ + aw8622x->trig[1].trig_level = aw8622x->dts_info.trig_config[7 + 0]; + aw8622x->trig[1].trig_polar = aw8622x->dts_info.trig_config[7 + 1]; + aw8622x->trig[1].pos_enable = aw8622x->dts_info.trig_config[7 + 2]; + aw8622x->trig[1].pos_sequence = aw8622x->dts_info.trig_config[7 + 3]; + aw8622x->trig[1].neg_enable = aw8622x->dts_info.trig_config[7 + 4]; + aw8622x->trig[1].neg_sequence = aw8622x->dts_info.trig_config[7 + 5]; + aw8622x->trig[1].trig_brk = aw8622x->dts_info.trig_config[7 + 6]; + aw_dev_info("%s: trig2 date init ok!\n", __func__); + + /* trig3 date */ + aw8622x->trig[2].trig_level = aw8622x->dts_info.trig_config[14 + 0]; + aw8622x->trig[2].trig_polar = aw8622x->dts_info.trig_config[14 + 1]; + aw8622x->trig[2].pos_enable = aw8622x->dts_info.trig_config[14 + 2]; + aw8622x->trig[2].pos_sequence = aw8622x->dts_info.trig_config[14 + 3]; + aw8622x->trig[2].neg_enable = aw8622x->dts_info.trig_config[14 + 4]; + aw8622x->trig[2].neg_sequence = aw8622x->dts_info.trig_config[14 + 5]; + aw8622x->trig[2].trig_brk = aw8622x->dts_info.trig_config[14 + 6]; + aw_dev_info("%s: trig3 date init ok!\n", __func__); + + return 0; +} + +static int aw8622x_haptic_trig_param_config(struct aw8622x *aw8622x) +{ + unsigned char trig1_polar_lev_brk = 0x00; + unsigned char trig2_polar_lev_brk = 0x00; + unsigned char trig3_polar_lev_brk = 0x00; + unsigned char trig1_pos_seq = 0x00; + unsigned char trig2_pos_seq = 0x00; + unsigned char trig3_pos_seq = 0x00; + unsigned char trig1_neg_seq = 0x00; + unsigned char trig2_neg_seq = 0x00; + unsigned char trig3_neg_seq = 0x00; + + aw_dev_info("%s enter\n", __func__); + + if ((aw8622x->name == AW86224_5) && (aw8622x->isUsedIntn)) + return 0; + /* trig1 config */ + trig1_polar_lev_brk = aw8622x->trig[0].trig_polar << 2 | + aw8622x->trig[0].trig_level << 1 | + aw8622x->trig[0].trig_brk; + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_TRGCFG7, + AW8622X_BIT_TRGCFG7_TRG1_POR_LEV_BRK_MASK, + trig1_polar_lev_brk << 5); + + trig1_pos_seq = aw8622x->trig[0].pos_enable << 7 | + aw8622x->trig[0].pos_sequence; + aw8622x_i2c_write(aw8622x, AW8622X_REG_TRGCFG1, &trig1_pos_seq, + AW_I2C_BYTE_ONE); + + trig1_neg_seq = aw8622x->trig[0].neg_enable << 7 | + aw8622x->trig[0].neg_sequence; + aw8622x_i2c_write(aw8622x, AW8622X_REG_TRGCFG4, &trig1_neg_seq, + AW_I2C_BYTE_ONE); + + aw_dev_info("%s: trig1 date config ok!\n", __func__); + + if ((aw8622x->name == AW86224_5) && (!aw8622x->isUsedIntn)) { + aw_dev_info("%s: intn pin is trig.\n", __func__); + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSCTRL2, + AW8622X_BIT_SYSCTRL2_INTN_PIN_MASK, + AW8622X_BIT_SYSCTRL2_TRIG1); + return 0; + } + /* trig2 config */ + trig2_polar_lev_brk = aw8622x->trig[1].trig_polar << 2 | + aw8622x->trig[1].trig_level << 1 | + aw8622x->trig[1].trig_brk; + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_TRGCFG7, + AW8622X_BIT_TRGCFG7_TRG2_POR_LEV_BRK_MASK, + trig2_polar_lev_brk << 1); + trig2_pos_seq = aw8622x->trig[1].pos_enable << 7 | + aw8622x->trig[1].pos_sequence; + aw8622x_i2c_write(aw8622x, AW8622X_REG_TRGCFG2, &trig2_pos_seq, + AW_I2C_BYTE_ONE); + trig2_neg_seq = aw8622x->trig[1].neg_enable << 7 | + aw8622x->trig[1].neg_sequence; + aw8622x_i2c_write(aw8622x, AW8622X_REG_TRGCFG5, &trig2_neg_seq, + AW_I2C_BYTE_ONE); + aw_dev_info("%s: trig2 date config ok!\n", __func__); + + /* trig3 config */ + trig3_polar_lev_brk = aw8622x->trig[2].trig_polar << 2 | + aw8622x->trig[2].trig_level << 1 | + aw8622x->trig[2].trig_brk; + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_TRGCFG8, + AW8622X_BIT_TRGCFG8_TRG3_POR_LEV_BRK_MASK, + trig3_polar_lev_brk << 5); + trig3_pos_seq = aw8622x->trig[2].pos_enable << 7 | + aw8622x->trig[2].pos_sequence; + aw8622x_i2c_write(aw8622x, AW8622X_REG_TRGCFG3, &trig3_pos_seq, + AW_I2C_BYTE_ONE); + trig3_neg_seq = aw8622x->trig[2].neg_enable << 7 | + aw8622x->trig[2].neg_sequence; + aw8622x_i2c_write(aw8622x, AW8622X_REG_TRGCFG6, &trig3_neg_seq, + AW_I2C_BYTE_ONE); + aw_dev_info("%s: trig3 date config ok!\n", __func__); + + return 0; +} + +/***************************************************** + * + * motor protect + * + *****************************************************/ +static int aw8622x_haptic_swicth_motor_protect_config(struct aw8622x *aw8622x, + unsigned char addr, + unsigned char val) +{ + aw_dev_info("%s enter\n", __func__); + if (addr == 1) { + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_DETCFG1, + AW8622X_BIT_DETCFG1_PRCT_MODE_MASK, + AW8622X_BIT_DETCFG1_PRCT_MODE_VALID); + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_PWMCFG1, + AW8622X_BIT_PWMCFG1_PRC_EN_MASK, + AW8622X_BIT_PWMCFG1_PRC_ENABLE); + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_PWMCFG3, + AW8622X_BIT_PWMCFG3_PR_EN_MASK, + AW8622X_BIT_PWMCFG3_PR_ENABLE); + } else if (addr == 0) { + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_DETCFG1, + AW8622X_BIT_DETCFG1_PRCT_MODE_MASK, + AW8622X_BIT_DETCFG1_PRCT_MODE_INVALID); + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_PWMCFG1, + AW8622X_BIT_PWMCFG1_PRC_EN_MASK, + AW8622X_BIT_PWMCFG1_PRC_DISABLE); + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_PWMCFG3, + AW8622X_BIT_PWMCFG3_PR_EN_MASK, + AW8622X_BIT_PWMCFG3_PR_DISABLE); + } else if (addr == 0x2d) { + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_PWMCFG1, + AW8622X_BIT_PWMCFG1_PRCTIME_MASK, val); + } else if (addr == 0x3e) { + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_PWMCFG3, + AW8622X_BIT_PWMCFG3_PRLVL_MASK, val); + } else if (addr == 0x3f) { + aw8622x_i2c_write(aw8622x, AW8622X_REG_PWMCFG4, &val, + AW_I2C_BYTE_ONE); + } + return 0; +} + +static int aw8622x_haptic_f0_calibration(struct aw8622x *aw8622x) +{ + unsigned char reg_val = 0; + char f0_cali_lra = 0; + unsigned int f0_limit = 0; + unsigned int f0_cali_min = aw8622x->dts_info.f0_ref * + (100 - aw8622x->dts_info.f0_cali_percent) / 100; + unsigned int f0_cali_max = aw8622x->dts_info.f0_ref * + (100 + aw8622x->dts_info.f0_cali_percent) / 100; + int ret = 0; + int f0_cali_step = 0; + + aw_dev_info("%s enter\n", __func__); + /* + * aw8622x_haptic_upload_lra(aw8622x, AW8622X_WRITE_ZERO); + */ + if (aw8622x_haptic_cont_get_f0(aw8622x)) { + aw_dev_err("%s get f0 error, user defafult f0\n", + __func__); + } else { + /* max and min limit */ + f0_limit = aw8622x->f0; + aw_dev_info("%s f0_ref = %d, f0_cali_min = %d, f0_cali_max = %d, f0 = %d\n", + __func__, aw8622x->dts_info.f0_ref, + f0_cali_min, f0_cali_max, aw8622x->f0); + + if ((aw8622x->f0 < f0_cali_min) || aw8622x->f0 > f0_cali_max) { + aw_dev_err("%s f0 calibration out of range = %d!\n", + __func__, aw8622x->f0); + f0_limit = aw8622x->dts_info.f0_ref; + return -ERANGE; + } + aw_dev_info("%s f0_limit = %d\n", __func__, + (int)f0_limit); + /* calculate cali step */ + f0_cali_step = 100000 * ((int)f0_limit - + (int)aw8622x->dts_info.f0_ref) / + ((int)f0_limit * 24); + aw_dev_info("%s f0_cali_step = %d\n", __func__, + f0_cali_step); + if (f0_cali_step >= 0) { /*f0_cali_step >= 0 */ + if (f0_cali_step % 10 >= 5) + f0_cali_step = 32 + (f0_cali_step / 10 + 1); + else + f0_cali_step = 32 + f0_cali_step / 10; + } else { /* f0_cali_step < 0 */ + if (f0_cali_step % 10 <= -5) + f0_cali_step = 32 + (f0_cali_step / 10 - 1); + else + f0_cali_step = 32 + f0_cali_step / 10; + } + if (f0_cali_step > 31) + f0_cali_lra = (char)f0_cali_step - 32; + else + f0_cali_lra = (char)f0_cali_step + 32; + /* update cali step */ + aw8622x->f0_cali_data = (int)f0_cali_lra; + aw8622x_haptic_upload_lra(aw8622x, AW8622X_F0_CALI); + + aw8622x_i2c_read(aw8622x, AW8622X_REG_TRIMCFG3, ®_val, + AW_I2C_BYTE_ONE); + + aw_dev_info("%s final trim_lra=0x%02x\n", + __func__, reg_val); + } + /* restore standby work mode */ + aw8622x_haptic_stop(aw8622x); + return ret; +} + +/***************************************************** + * + * haptic cont + * + *****************************************************/ +static int aw8622x_haptic_cont(struct aw8622x *aw8622x) +{ + unsigned char reg_val = 0; + + aw_dev_info("%s enter\n", __func__); + + /* work mode */ + aw8622x_haptic_play_mode(aw8622x, AW8622X_HAPTIC_CONT_MODE); + /* cont config */ + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_CONTCFG6, + (AW8622X_BIT_CONTCFG6_TRACK_EN_MASK & + AW8622X_BIT_CONTCFG6_DRV1_LVL_MASK), + (AW8622X_BIT_CONTCFG6_TRACK_ENABLE | + (unsigned char)aw8622x->cont_drv1_lvl)); + reg_val = (unsigned char)aw8622x->cont_drv2_lvl; + aw8622x_i2c_write(aw8622x, AW8622X_REG_CONTCFG7, ®_val, + AW_I2C_BYTE_ONE); + /* DRV2_TIME */ + reg_val = 0xFF; + aw8622x_i2c_write(aw8622x, AW8622X_REG_CONTCFG9, ®_val, + AW_I2C_BYTE_ONE); + /* cont play go */ + aw8622x_haptic_play_go(aw8622x, true); + return 0; +} + +static int aw8622x_haptic_play_wav_seq(struct aw8622x *aw8622x, + unsigned char flag) +{ + aw_dev_info("%s enter\n", __func__); + if (flag) { + aw8622x_haptic_play_mode(aw8622x, AW8622X_HAPTIC_RAM_MODE); + aw8622x_haptic_play_go(aw8622x, true); + } + return 0; +} + +#ifdef TIMED_OUTPUT +static int aw8622x_vibrator_get_time(struct timed_output_dev *dev) +{ + struct aw8622x *aw8622x = container_of(dev, struct aw8622x, vib_dev); + + if (hrtimer_active(&aw8622x->timer)) { + ktime_t r = hrtimer_get_remaining(&aw8622x->timer); + + return ktime_to_ms(r); + } + return 0; +} + +static void aw8622x_vibrator_enable(struct timed_output_dev *dev, int value) +{ + struct aw8622x *aw8622x = container_of(dev, struct aw8622x, vib_dev); + + aw_dev_info("%s enter\n", __func__); + if (!aw8622x->ram_init) { + aw_dev_err("%s: ram init failed, not allow to play!\n", + __func__); + return; + } + mutex_lock(&aw8622x->lock); + aw8622x_haptic_stop(aw8622x); + if (value > 0) { + aw8622x_haptic_ram_vbat_comp(aw8622x, false); + aw8622x_haptic_play_wav_seq(aw8622x, value); + } + mutex_unlock(&aw8622x->lock); + aw_dev_info("%s exit\n", __func__); +} +#else +static enum led_brightness aw8622x_haptic_brightness_get(struct led_classdev + *cdev) +{ + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + return aw8622x->amplitude; +} + +static void aw8622x_haptic_brightness_set(struct led_classdev *cdev, + enum led_brightness level) +{ + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + aw_dev_info("%s enter\n", __func__); + if (!aw8622x->ram_init) { + aw_dev_err("%s: ram init failed, not allow to play!\n", + __func__); + return; + } + if (aw8622x->ram_update_flag < 0) + return; + aw8622x->amplitude = level; + mutex_lock(&aw8622x->lock); + aw8622x_haptic_stop(aw8622x); + if (aw8622x->amplitude > 0) { + aw8622x_haptic_upload_lra(aw8622x, AW8622X_F0_CALI); + aw8622x_haptic_ram_vbat_comp(aw8622x, false); + aw8622x_haptic_play_wav_seq(aw8622x, aw8622x->amplitude); + } + mutex_unlock(&aw8622x->lock); +} +#endif + +static int +aw8622x_haptic_audio_ctr_list_insert(struct haptic_audio *haptic_audio, + struct haptic_ctr *haptic_ctr, + struct device *dev) +{ + struct haptic_ctr *p_new = NULL; + + p_new = kzalloc(sizeof(struct haptic_ctr), GFP_KERNEL); + if (p_new == NULL) + return -ENOMEM; + /* update new list info */ + p_new->cnt = haptic_ctr->cnt; + p_new->cmd = haptic_ctr->cmd; + p_new->play = haptic_ctr->play; + p_new->wavseq = haptic_ctr->wavseq; + p_new->loop = haptic_ctr->loop; + p_new->gain = haptic_ctr->gain; + + INIT_LIST_HEAD(&(p_new->list)); + list_add(&(p_new->list), &(haptic_audio->ctr_list)); + return 0; +} + +static int +aw8622x_haptic_audio_ctr_list_clear(struct haptic_audio *haptic_audio) +{ + struct haptic_ctr *p_ctr = NULL; + struct haptic_ctr *p_ctr_bak = NULL; + + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), + list) { + list_del(&p_ctr->list); + kfree(p_ctr); + } + + return 0; +} + +static int aw8622x_haptic_audio_off(struct aw8622x *aw8622x) +{ + aw_dev_dbg("%s: enter\n", __func__); + mutex_lock(&aw8622x->lock); + aw8622x_haptic_set_gain(aw8622x, 0x80); + aw8622x_haptic_stop(aw8622x); + aw8622x->gun_type = AW_GUN_TYPE_DEF_VAL; + aw8622x->bullet_nr = AW_BULLET_NR_DEF_VAL; + aw8622x_haptic_audio_ctr_list_clear(&aw8622x->haptic_audio); + mutex_unlock(&aw8622x->lock); + return 0; +} + +static int aw8622x_haptic_audio_init(struct aw8622x *aw8622x) +{ + + aw_dev_dbg("%s enter\n", __func__); + aw8622x_haptic_set_wav_seq(aw8622x, 0x01, 0x00); + + return 0; +} + +static int aw8622x_haptic_activate(struct aw8622x *aw8622x) +{ + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSCTRL2, + AW8622X_BIT_SYSCTRL2_STANDBY_MASK, + AW8622X_BIT_SYSCTRL2_STANDBY_OFF); + aw8622x_interrupt_clear(aw8622x); + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSINTM, + AW8622X_BIT_SYSINTM_UVLM_MASK, + AW8622X_BIT_SYSINTM_UVLM_ON); + return 0; +} + +static int aw8622x_haptic_start(struct aw8622x *aw8622x) +{ + aw8622x_haptic_activate(aw8622x); + aw8622x_haptic_play_go(aw8622x, true); + return 0; +} + +static void aw8622x_ctr_list_config(struct aw8622x *aw8622x, + struct haptic_ctr *p_ctr, + struct haptic_ctr *p_ctr_bak, + struct haptic_audio *haptic_audio) +{ + unsigned int list_input_cnt = 0; + unsigned int list_output_cnt = 0; + unsigned int list_diff_cnt = 0; + unsigned int list_del_cnt = 0; + + list_for_each_entry_safe(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), list) { + list_input_cnt = p_ctr->cnt; + break; + } + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), list) { + list_output_cnt = p_ctr->cnt; + break; + } + if (list_input_cnt > list_output_cnt) + list_diff_cnt = list_input_cnt - list_output_cnt; + if (list_input_cnt < list_output_cnt) + list_diff_cnt = 32 + list_input_cnt - list_output_cnt; + if (list_diff_cnt > 2) { + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), list) { + if ((p_ctr->play == 0) && + (AW8622X_HAPTIC_CMD_ENABLE == + (AW8622X_HAPTIC_CMD_HAPTIC & p_ctr->cmd))) { + list_del(&p_ctr->list); + kfree(p_ctr); + list_del_cnt++; + } + if (list_del_cnt == list_diff_cnt) + break; + } + } +} + +static void aw8622x_haptic_audio_work_routine(struct work_struct *work) +{ + struct aw8622x *aw8622x = container_of(work, + struct aw8622x, + haptic_audio.work); + struct haptic_audio *haptic_audio = NULL; + struct haptic_ctr *p_ctr = NULL; + struct haptic_ctr *p_ctr_bak = NULL; + unsigned int ctr_list_flag = 0; + int rtp_is_going_on = 0; + + aw_dev_dbg("%s enter\n", __func__); + + haptic_audio = &(aw8622x->haptic_audio); + mutex_lock(&aw8622x->haptic_audio.lock); + memset(&aw8622x->haptic_audio.ctr, 0, sizeof(struct haptic_ctr)); + ctr_list_flag = 0; + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), list) { + ctr_list_flag = 1; + break; + } + if (ctr_list_flag == 0) + aw_dev_info("%s: ctr list empty\n", __func__); + + if (ctr_list_flag == 1) + aw8622x_ctr_list_config(aw8622x, p_ctr, + p_ctr_bak, haptic_audio); + + /* get the last data from list */ + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), list) { + aw8622x->haptic_audio.ctr.cnt = p_ctr->cnt; + aw8622x->haptic_audio.ctr.cmd = p_ctr->cmd; + aw8622x->haptic_audio.ctr.play = p_ctr->play; + aw8622x->haptic_audio.ctr.wavseq = p_ctr->wavseq; + aw8622x->haptic_audio.ctr.loop = p_ctr->loop; + aw8622x->haptic_audio.ctr.gain = p_ctr->gain; + list_del(&p_ctr->list); + kfree(p_ctr); + break; + } + + if (aw8622x->haptic_audio.ctr.play) { + aw_dev_info("%s: cnt=%d, cmd=%d, play=%d, wavseq=%d, loop=%d, gain=%d\n", + __func__, + aw8622x->haptic_audio.ctr.cnt, + aw8622x->haptic_audio.ctr.cmd, + aw8622x->haptic_audio.ctr.play, + aw8622x->haptic_audio.ctr.wavseq, + aw8622x->haptic_audio.ctr.loop, + aw8622x->haptic_audio.ctr.gain); + } + + /* rtp mode jump */ + rtp_is_going_on = aw8622x_haptic_juge_RTP_is_going_on(aw8622x); + if (rtp_is_going_on) { + mutex_unlock(&aw8622x->haptic_audio.lock); + return; + } + mutex_unlock(&aw8622x->haptic_audio.lock); + + /*haptic play control*/ + if (AW8622X_HAPTIC_CMD_ENABLE == + (AW8622X_HAPTIC_CMD_HAPTIC & aw8622x->haptic_audio.ctr.cmd)) { + if (aw8622x->haptic_audio.ctr.play == + AW8622X_HAPTIC_PLAY_ENABLE) { + aw_dev_info("%s: haptic_audio_play_start\n", __func__); + aw_dev_info("%s: normal haptic start\n", __func__); + mutex_lock(&aw8622x->lock); + aw8622x_haptic_stop(aw8622x); + aw8622x_haptic_play_mode(aw8622x, + AW8622X_HAPTIC_RAM_MODE); + aw8622x_haptic_set_wav_seq(aw8622x, 0x00, + aw8622x->haptic_audio.ctr.wavseq); + aw8622x_haptic_set_wav_loop(aw8622x, 0x00, + aw8622x->haptic_audio.ctr.loop); + aw8622x_haptic_set_gain(aw8622x, + aw8622x->haptic_audio.ctr.gain); + aw8622x_haptic_start(aw8622x); + mutex_unlock(&aw8622x->lock); + } else if (AW8622X_HAPTIC_PLAY_STOP == + aw8622x->haptic_audio.ctr.play) { + mutex_lock(&aw8622x->lock); + aw8622x_haptic_stop(aw8622x); + mutex_unlock(&aw8622x->lock); + } else if (AW8622X_HAPTIC_PLAY_GAIN == + aw8622x->haptic_audio.ctr.play) { + mutex_lock(&aw8622x->lock); + aw8622x_haptic_set_gain(aw8622x, + aw8622x->haptic_audio.ctr.gain); + mutex_unlock(&aw8622x->lock); + } + } +} + +static ssize_t aw8622x_cont_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + aw8622x_haptic_read_cont_f0(aw8622x); + len += snprintf(buf + len, PAGE_SIZE - len, + "%d\n", aw8622x->cont_f0); + return len; +} + +static ssize_t aw8622x_cont_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + + aw8622x_haptic_stop(aw8622x); + if (val) + aw8622x_haptic_cont(aw8622x); + return count; +} + +static ssize_t aw8622x_f0_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char reg = 0; + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + mutex_lock(&aw8622x->lock); + + /* set d2s_gain to max to get better performance when cat f0 .*/ + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSCTRL7, + AW8622X_BIT_SYSCTRL7_D2S_GAIN_MASK, + AW8622X_BIT_SYSCTRL7_D2S_GAIN_40); + aw8622x_i2c_read(aw8622x, AW8622X_REG_TRIMCFG3, ®, AW_I2C_BYTE_ONE); + aw8622x_haptic_upload_lra(aw8622x, AW8622X_WRITE_ZERO); + aw8622x_haptic_cont_get_f0(aw8622x); + aw8622x_i2c_write(aw8622x, AW8622X_REG_TRIMCFG3, ®, AW_I2C_BYTE_ONE); + /* set d2s_gain to default when cat f0 is finished.*/ + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSCTRL7, + AW8622X_BIT_SYSCTRL7_D2S_GAIN_MASK, + aw8622x->dts_info.d2s_gain); + mutex_unlock(&aw8622x->lock); + len += snprintf(buf + len, PAGE_SIZE - len, + "%d\n", aw8622x->f0); + return len; +} + +static ssize_t aw8622x_f0_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + + return count; +} + +static ssize_t aw8622x_reg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char i = 0; + unsigned char size = 0; + unsigned char cnt = 0; + unsigned char reg_array[AW_REG_MAX] = {0}; + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + aw_dev_dbg("%s: enter!\n", __func__); + + for (i = 0; i <= (AW8622X_REG_TRIMCFG3 + 1); i++) { + + if (i == aw8622x_reg_list[cnt] && + (cnt < sizeof(aw8622x_reg_list))) { + size++; + cnt++; + continue; + } else { + if (size != 0) { + aw8622x_i2c_read(aw8622x, + aw8622x_reg_list[cnt-size], + ®_array[cnt-size], size); + size = 0; + + } + } + } + + for (i = 0; i < sizeof(aw8622x_reg_list); i++) { + len += snprintf(buf + len, PAGE_SIZE - len, + "reg:0x%02X=0x%02X\n", aw8622x_reg_list[i], + reg_array[i]); + } + return len; +} + +static ssize_t aw8622x_reg_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + unsigned char reg_val = 0; + unsigned int databuf[2] = { 0, 0 }; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + reg_val = (unsigned char)databuf[1]; + aw8622x_i2c_write(aw8622x, (unsigned char)databuf[0], + ®_val, AW_I2C_BYTE_ONE); + } + + return count; +} + +static ssize_t aw8622x_duration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + ktime_t time_rem; + s64 time_ms = 0; + + if (hrtimer_active(&aw8622x->timer)) { + time_rem = hrtimer_get_remaining(&aw8622x->timer); + time_ms = ktime_to_ms(time_rem); + } + return snprintf(buf, PAGE_SIZE, "%lld\n", time_ms); +} + +static ssize_t aw8622x_duration_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + /* setting 0 on duration is NOP for now */ + if (val <= 0) + return count; + rc = aw8622x_haptic_ram_config(aw8622x, val); + if (rc < 0) { + aw_dev_info("%s: ram config failed!\n", __func__); + return count; + } + aw8622x->duration = val; + return count; +} + +static ssize_t aw8622x_activate_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + /* For now nothing to show */ + return snprintf(buf, PAGE_SIZE, "activate = %d\n", aw8622x->state); +} + +static ssize_t aw8622x_activate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + if (!aw8622x->ram_init) { + aw_dev_err("%s: ram init failed, not allow to play!\n", + __func__); + return count; + } + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + if (val != 0 && val != 1) + return count; + aw_dev_info("%s: value=%d\n", __func__, val); + mutex_lock(&aw8622x->lock); + hrtimer_cancel(&aw8622x->timer); + aw8622x->state = val; + mutex_unlock(&aw8622x->lock); + schedule_work(&aw8622x->vibrator_work); + return count; +} + +static ssize_t aw8622x_seq_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char i = 0; + unsigned char reg_val[AW8622X_SEQUENCER_SIZE] = {0}; + size_t count = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + aw8622x_i2c_read(aw8622x, AW8622X_REG_WAVCFG1, reg_val, + AW8622X_SEQUENCER_SIZE); + for (i = 0; i < AW8622X_SEQUENCER_SIZE; i++) { + count += snprintf(buf+count, PAGE_SIZE-count, + "seq%d: 0x%02x\n", i+1, reg_val[i]); + aw8622x->seq[i] = reg_val[i]; + } + return count; +} + +static ssize_t aw8622x_seq_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + unsigned int databuf[2] = { 0, 0 }; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + if (databuf[0] > AW8622X_SEQUENCER_SIZE || + databuf[1] > aw8622x->ram.ram_num) { + aw_dev_err("%s input value out of range\n", + __func__); + return count; + } + aw_dev_info("%s: seq%d=0x%02X\n", __func__, + databuf[0], databuf[1]); + mutex_lock(&aw8622x->lock); + aw8622x->seq[databuf[0]] = (unsigned char)databuf[1]; + aw8622x_haptic_set_wav_seq(aw8622x, (unsigned char)databuf[0], + aw8622x->seq[databuf[0]]); + mutex_unlock(&aw8622x->lock); + } + return count; +} + +static ssize_t aw8622x_loop_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char i = 0; + unsigned char reg_val[AW8622X_SEQUENCER_LOOP_SIZE] = {0}; + size_t count = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + aw8622x_i2c_read(aw8622x, AW8622X_REG_WAVCFG9, reg_val, + AW8622X_SEQUENCER_LOOP_SIZE); + + for (i = 0; i < AW8622X_SEQUENCER_LOOP_SIZE; i++) { + aw8622x->loop[i*2+0] = (reg_val[i] >> 4) & 0x0F; + aw8622x->loop[i*2+1] = (reg_val[i] >> 0) & 0x0F; + + count += snprintf(buf+count, PAGE_SIZE-count, + "seq%d_loop: 0x%02x\n", i*2+1, aw8622x->loop[i*2+0]); + count += snprintf(buf+count, PAGE_SIZE-count, + "seq%d_loop: 0x%02x\n", i*2+2, aw8622x->loop[i*2+1]); + } + return count; +} + +static ssize_t aw8622x_loop_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int databuf[2] = { 0, 0 }; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + aw_dev_info("%s: seq%d loop=0x%02X\n", __func__, + databuf[0], databuf[1]); + mutex_lock(&aw8622x->lock); + aw8622x->loop[databuf[0]] = (unsigned char)databuf[1]; + aw8622x_haptic_set_wav_loop(aw8622x, (unsigned char)databuf[0], + aw8622x->loop[databuf[0]]); + mutex_unlock(&aw8622x->lock); + } + return count; +} + +static ssize_t aw8622x_rtp_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + len += snprintf(buf + len, PAGE_SIZE - len, + "rtp_cnt = %d\n", + aw8622x->rtp_cnt); + return len; +} + +static ssize_t aw8622x_rtp_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, + struct aw8622x, vib_dev); + + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) { + aw_dev_info("%s: kstrtouint fail\n", __func__); + return count; + } + mutex_lock(&aw8622x->lock); + aw8622x_haptic_stop(aw8622x); + aw8622x_haptic_set_rtp_aei(aw8622x, false); + aw8622x_interrupt_clear(aw8622x); + if (val < (sizeof(aw8622x_rtp_name) / AW8622X_RTP_NAME_MAX)) { + aw8622x->rtp_file_num = val; + if (val) { + aw_dev_info("%s: aw8622x_rtp_name[%d]: %s\n", __func__, + val, aw8622x_rtp_name[val]); + + schedule_work(&aw8622x->rtp_work); + } else { + aw_dev_err("%s: rtp_file_num 0x%02X over max value\n", + __func__, aw8622x->rtp_file_num); + } + } + mutex_unlock(&aw8622x->lock); + return count; +} + +static ssize_t aw8622x_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", aw8622x->state); +} + +static ssize_t aw8622x_state_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return count; +} + +static ssize_t aw8622x_activate_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", + aw8622x->activate_mode); +} + +static ssize_t aw8622x_activate_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + mutex_lock(&aw8622x->lock); + aw8622x->activate_mode = val; + mutex_unlock(&aw8622x->lock); + return count; +} + +static ssize_t aw8622x_index_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char reg_val = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + aw8622x_i2c_read(aw8622x, AW8622X_REG_WAVCFG1, ®_val, + AW_I2C_BYTE_ONE); + aw8622x->index = reg_val; + return snprintf(buf, PAGE_SIZE, "index = %d\n", aw8622x->index); +} + +static ssize_t aw8622x_index_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + if (val > aw8622x->ram.ram_num) { + aw_dev_err("%s: input value out of range!\n", __func__); + return count; + } + aw_dev_info("%s: value=%d\n", __func__, val); + mutex_lock(&aw8622x->lock); + aw8622x->index = val; + aw8622x_haptic_set_repeat_wav_seq(aw8622x, aw8622x->index); + mutex_unlock(&aw8622x->lock); + return count; +} + +static ssize_t aw8622x_sram_size_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char reg_val = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + aw8622x_i2c_read(aw8622x, AW8622X_REG_RTPCFG1, ®_val, + AW_I2C_BYTE_ONE); + if ((reg_val & 0x30) == 0x20) + return snprintf(buf, PAGE_SIZE, "sram_size = 2K\n"); + else if ((reg_val & 0x30) == 0x10) + return snprintf(buf, PAGE_SIZE, "sram_size = 1K\n"); + else if ((reg_val & 0x30) == 0x30) + return snprintf(buf, PAGE_SIZE, "sram_size = 3K\n"); + return snprintf(buf, PAGE_SIZE, + "sram_size = 0x%02x error, plz check reg.\n", + reg_val & 0x30); +} + +static ssize_t aw8622x_sram_size_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + aw_dev_info("%s: value=%d\n", __func__, val); + mutex_lock(&aw8622x->lock); + if (val == AW8622X_HAPTIC_SRAM_2K) + aw8622x_sram_size(aw8622x, AW8622X_HAPTIC_SRAM_2K); + else if (val == AW8622X_HAPTIC_SRAM_1K) + aw8622x_sram_size(aw8622x, AW8622X_HAPTIC_SRAM_1K); + else if (val == AW8622X_HAPTIC_SRAM_3K) + aw8622x_sram_size(aw8622x, AW8622X_HAPTIC_SRAM_3K); + mutex_unlock(&aw8622x->lock); + return count; +} + +static ssize_t aw8622x_osc_cali_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + len += snprintf(buf + len, PAGE_SIZE - len, "osc_cali_data = 0x%02X\n", + aw8622x->osc_cali_data); + + return len; +} + +static ssize_t aw8622x_osc_cali_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + mutex_lock(&aw8622x->lock); + if (val == 1) { + aw8622x_haptic_upload_lra(aw8622x, AW8622X_WRITE_ZERO); + aw8622x_rtp_osc_calibration(aw8622x); + aw8622x_rtp_trim_lra_calibration(aw8622x); + } else if (val == 2) { + aw8622x_haptic_upload_lra(aw8622x, AW8622X_OSC_CALI); + aw8622x_rtp_osc_calibration(aw8622x); + } else { + aw_dev_err("%s input value out of range\n", __func__); + } + /* osc calibration flag end, other behaviors are permitted */ + mutex_unlock(&aw8622x->lock); + + return count; +} + +static ssize_t aw8622x_gain_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char reg = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + aw8622x_i2c_read(aw8622x, AW8622X_REG_PLAYCFG2, ®, AW_I2C_BYTE_ONE); + + return snprintf(buf, PAGE_SIZE, "0x%02X\n", reg); +} + +static ssize_t aw8622x_gain_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + + aw_dev_info("%s: value=%d\n", __func__, val); + if (val >= AW8622X_GAIN_MAX) + val = AW8622X_GAIN_MAX; + mutex_lock(&aw8622x->lock); + aw8622x->gain = val; + aw8622x_haptic_set_gain(aw8622x, aw8622x->gain); + mutex_unlock(&aw8622x->lock); + return count; +} + +static ssize_t aw8622x_ram_update_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int cnt = 0; + int i = 0; + int size = 0; + ssize_t len = 0; + unsigned char ram_data[AW_RAMDATA_RD_BUFFER_SIZE] = {0}; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + /* RAMINIT Enable */ + aw8622x_haptic_raminit(aw8622x, true); + aw8622x_haptic_stop(aw8622x); + aw8622x_set_ram_addr(aw8622x); + len += snprintf(buf + len, PAGE_SIZE - len, + "haptic_ram len = %d\n", aw8622x->ram.len); + while (cnt < aw8622x->ram.len) { + if ((aw8622x->ram.len - cnt) < AW_RAMDATA_RD_BUFFER_SIZE) + size = aw8622x->ram.len - cnt; + else + size = AW_RAMDATA_RD_BUFFER_SIZE; + + aw8622x_i2c_read(aw8622x, AW8622X_REG_RAMDATA, + ram_data, size); + for (i = 0; i < size; i++) { + len += snprintf(buf + len, PAGE_SIZE - len, + "0x%02X,", ram_data[i]); + } + cnt += size; + } + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + /* RAMINIT Disable */ + aw8622x_haptic_raminit(aw8622x, false); + return len; +} + +static ssize_t aw8622x_ram_update_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + if (val) + aw8622x_ram_update(aw8622x); + return count; +} + +static ssize_t aw8622x_f0_save_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + len += snprintf(buf + len, PAGE_SIZE - len, "f0_cali_data = 0x%02X\n", + aw8622x->f0_cali_data); + + return len; +} + +static ssize_t aw8622x_f0_save_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + aw8622x->f0_cali_data = val; + return count; +} + +static ssize_t aw8622x_osc_save_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + len += snprintf(buf + len, PAGE_SIZE - len, "osc_cali_data = 0x%02X\n", + aw8622x->osc_cali_data); + + return len; +} + +static ssize_t aw8622x_osc_save_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + aw8622x->osc_cali_data = val; + return count; +} + +static ssize_t aw8622x_trig_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + unsigned char i = 0; + unsigned char trig_num = 3; + + if (aw8622x->name == AW86224_5) + trig_num = 1; + + for (i = 0; i < trig_num; i++) { + len += snprintf(buf + len, PAGE_SIZE - len, + "trig%d: trig_level=%d, trig_polar=%d", + i + 1, + aw8622x->trig[i].trig_level, + aw8622x->trig[i].trig_polar); + len += snprintf(buf + len, PAGE_SIZE - len, + "pos_enable=%d, pos_sequence=%d,", + aw8622x->trig[i].pos_enable, + aw8622x->trig[i].pos_sequence); + len += snprintf(buf + len, PAGE_SIZE - len, + "neg_enable=%d, neg_sequence=%d trig_brk=%d\n", + aw8622x->trig[i].neg_enable, + aw8622x->trig[i].neg_sequence, + aw8622x->trig[i].trig_brk); + } + + return len; +} + + + +static ssize_t aw8622x_trig_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + unsigned int databuf[9] = { 0 }; + + if (sscanf(buf, "%d %d %d %d %d %d %d %d", + &databuf[0], &databuf[1], &databuf[2], + &databuf[3], &databuf[4], &databuf[5], + &databuf[6], &databuf[7]) == 8) { + aw_dev_info("%s: %d, %d, %d, %d, %d, %d, %d, %d\n", + __func__, databuf[0], databuf[1], databuf[2], + databuf[3], databuf[4], databuf[5], databuf[6], + databuf[7]); + if ((aw8622x->name == AW86224_5) && (databuf[0])) { + aw_dev_err("%s: input seq value out of range!\n", + __func__); + return count; + } + if (databuf[0] < 0 || databuf[0] > 2) { + aw_dev_err("%s: input seq value out of range!\n", + __func__); + return count; + } + if (!aw8622x->ram_init) { + aw_dev_err("%s: ram init failed, not allow to play!\n", + __func__); + return count; + } + if (databuf[4] > aw8622x->ram.ram_num || + databuf[6] > aw8622x->ram.ram_num) { + aw_dev_err("%s: input seq value out of range!\n", + __func__); + return count; + } + aw8622x->trig[databuf[0]].trig_level = databuf[1]; + aw8622x->trig[databuf[0]].trig_polar = databuf[2]; + aw8622x->trig[databuf[0]].pos_enable = databuf[3]; + aw8622x->trig[databuf[0]].pos_sequence = databuf[4]; + aw8622x->trig[databuf[0]].neg_enable = databuf[5]; + aw8622x->trig[databuf[0]].neg_sequence = databuf[6]; + aw8622x->trig[databuf[0]].trig_brk = databuf[7]; + mutex_lock(&aw8622x->lock); + aw8622x_haptic_trig_param_config(aw8622x); + mutex_unlock(&aw8622x->lock); + } else + aw_dev_err("%s: please input eight parameters\n", __func__); + return count; +} + +static ssize_t aw8622x_ram_vbat_compensate_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + len += + snprintf(buf + len, PAGE_SIZE - len, "ram_vbat_comp = %d\n", + aw8622x->ram_vbat_compensate); + + return len; +} + +static ssize_t aw8622x_ram_vbat_compensate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + + mutex_lock(&aw8622x->lock); + if (val) + aw8622x->ram_vbat_compensate = + AW8622X_HAPTIC_RAM_VBAT_COMP_ENABLE; + else + aw8622x->ram_vbat_compensate = + AW8622X_HAPTIC_RAM_VBAT_COMP_DISABLE; + mutex_unlock(&aw8622x->lock); + + return count; +} + +static ssize_t aw8622x_cali_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + unsigned char reg = 0; + + mutex_lock(&aw8622x->lock); + aw8622x_i2c_read(aw8622x, AW8622X_REG_TRIMCFG3, ®, + AW_I2C_BYTE_ONE); + aw8622x_haptic_upload_lra(aw8622x, AW8622X_F0_CALI); + aw8622x_haptic_cont_get_f0(aw8622x); + aw8622x_i2c_write(aw8622x, AW8622X_REG_TRIMCFG3, ®, + AW_I2C_BYTE_ONE); + mutex_unlock(&aw8622x->lock); + len += snprintf(buf + len, PAGE_SIZE - len, "%d\n", aw8622x->f0); + return len; +} + +static ssize_t aw8622x_cali_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + if (val) { + mutex_lock(&aw8622x->lock); + aw8622x_haptic_upload_lra(aw8622x, AW8622X_WRITE_ZERO); + aw8622x_haptic_f0_calibration(aw8622x); + mutex_unlock(&aw8622x->lock); + } + return count; +} + +static ssize_t aw8622x_cont_wait_num_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + len += snprintf(buf + len, PAGE_SIZE - len, + "cont_wait_num = 0x%02X\n", aw8622x->cont_wait_num); + return len; +} + +static ssize_t aw8622x_cont_wait_num_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned char reg_val = 0; + int err, val; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + err = kstrtoint(buf, 16, &val); + if (err != 0) { + aw_dev_err("%s format not match!", __func__); + return count; + } + aw8622x->cont_wait_num = val; + reg_val = aw8622x->cont_wait_num; + aw8622x_i2c_write(aw8622x, AW8622X_REG_CONTCFG4, ®_val, + AW_I2C_BYTE_ONE); + return count; +} + +static ssize_t aw8622x_cont_drv_lvl_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + len += snprintf(buf + len, PAGE_SIZE - len, + "cont_drv1_lvl = 0x%02X\n", + aw8622x->cont_drv1_lvl); + len += snprintf(buf + len, PAGE_SIZE - len, + "cont_drv2_lvl = 0x%02X\n", + aw8622x->cont_drv2_lvl); + return len; +} + +static ssize_t aw8622x_cont_drv_lvl_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned char reg_val = 0; + unsigned int databuf[2] = { 0, 0 }; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + aw8622x->cont_drv1_lvl = databuf[0]; + aw8622x->cont_drv2_lvl = databuf[1]; + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_CONTCFG6, + AW8622X_BIT_CONTCFG6_DRV1_LVL_MASK, + aw8622x->cont_drv1_lvl); + reg_val = (unsigned char)aw8622x->cont_drv2_lvl; + aw8622x_i2c_write(aw8622x, AW8622X_REG_CONTCFG7, ®_val, + AW_I2C_BYTE_ONE); + } + return count; +} + +static ssize_t aw8622x_cont_drv_time_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + len += snprintf(buf + len, PAGE_SIZE - len, + "cont_drv1_time = 0x%02X\n", + aw8622x->cont_drv1_time); + len += snprintf(buf + len, PAGE_SIZE - len, + "cont_drv2_time = 0x%02X\n", + aw8622x->cont_drv2_time); + return len; +} + +static ssize_t aw8622x_cont_drv_time_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned char reg_val[2] = {0}; + unsigned int databuf[2] = { 0, 0 }; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + aw8622x->cont_drv1_time = databuf[0]; + aw8622x->cont_drv2_time = databuf[1]; + reg_val[0] = (unsigned char)aw8622x->cont_drv1_time; + reg_val[1] = (unsigned char)aw8622x->cont_drv2_time; + aw8622x_i2c_write(aw8622x, AW8622X_REG_CONTCFG8, reg_val, + AW_I2C_BYTE_TWO); + } + return count; +} + +static ssize_t aw8622x_cont_brk_time_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + len += snprintf(buf + len, PAGE_SIZE - len, "cont_brk_time = 0x%02X\n", + aw8622x->cont_brk_time); + return len; +} + +static ssize_t aw8622x_cont_brk_time_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned char reg_val = 0; + int err, val; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + err = kstrtoint(buf, 16, &val); + if (err != 0) { + aw_dev_err("%s format not match!", __func__); + return count; + } + aw8622x->cont_brk_time = val; + reg_val = aw8622x->cont_brk_time; + aw8622x_i2c_write(aw8622x, AW8622X_REG_CONTCFG10, ®_val, + AW_I2C_BYTE_ONE); + return count; +} + +static ssize_t aw8622x_vbat_monitor_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + mutex_lock(&aw8622x->lock); + aw8622x_haptic_get_vbat(aw8622x); + len += snprintf(buf + len, PAGE_SIZE - len, "vbat_monitor = %d\n", + aw8622x->vbat); + mutex_unlock(&aw8622x->lock); + + return len; +} + +static ssize_t aw8622x_vbat_monitor_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return count; +} + +static ssize_t aw8622x_lra_resistance_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + aw8622x_haptic_get_lra_resistance(aw8622x); + len += snprintf(buf + len, PAGE_SIZE - len, "lra_resistance = %d\n", + aw8622x->lra); + return len; +} + +static ssize_t aw8622x_lra_resistance_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return count; +} + +static ssize_t aw8622x_prctmode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + unsigned char reg_val = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + aw8622x_i2c_read(aw8622x, AW8622X_REG_DETCFG1, ®_val, + AW_I2C_BYTE_ONE); + + len += snprintf(buf + len, PAGE_SIZE - len, "prctmode = %d\n", + reg_val & 0x08); + return len; +} + +static ssize_t aw8622x_prctmode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int databuf[2] = { 0, 0 }; + unsigned int addr = 0; + unsigned int val = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + addr = databuf[0]; + val = databuf[1]; + mutex_lock(&aw8622x->lock); + aw8622x_haptic_swicth_motor_protect_config(aw8622x, addr, val); + mutex_unlock(&aw8622x->lock); + } + return count; +} + +static ssize_t aw8622x_gun_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw8622x->gun_type); + +} + +static ssize_t aw8622x_gun_type_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + aw_dev_info("%s: value=%d\n", __func__, val); + mutex_lock(&aw8622x->lock); + aw8622x->gun_type = val; + mutex_unlock(&aw8622x->lock); + return count; +} + +static ssize_t aw8622x_bullet_nr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw8622x->bullet_nr); +} + +static ssize_t aw8622x_bullet_nr_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + aw_dev_info("%s: value=%d\n", __func__, val); + mutex_lock(&aw8622x->lock); + aw8622x->bullet_nr = val; + mutex_unlock(&aw8622x->lock); + return count; +} + +static ssize_t aw8622x_haptic_audio_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + len += snprintf(buf+len, PAGE_SIZE-len, + "%d\n", aw8622x->haptic_audio.ctr.cnt); + return len; +} + +static int aw8622x_audio_config(struct aw8622x *aw8622x, + unsigned int databuf[]) +{ + struct haptic_ctr *hap_ctr = NULL; + + hap_ctr = kzalloc(sizeof(struct haptic_ctr), GFP_KERNEL); + if (hap_ctr == NULL) + return -ENOMEM; + mutex_lock(&aw8622x->haptic_audio.lock); + hap_ctr->cnt = (unsigned char)databuf[0]; + hap_ctr->cmd = (unsigned char)databuf[1]; + hap_ctr->play = (unsigned char)databuf[2]; + hap_ctr->wavseq = (unsigned char)databuf[3]; + hap_ctr->loop = (unsigned char)databuf[4]; + hap_ctr->gain = (unsigned char)databuf[5]; + aw8622x_haptic_audio_ctr_list_insert(&aw8622x->haptic_audio, + hap_ctr, aw8622x->dev); + if (hap_ctr->cmd == 0xff) { + aw_dev_info("%s: haptic_audio stop\n", __func__); + if (hrtimer_active(&aw8622x->haptic_audio.timer)) { + aw_dev_info( "%s: cancel haptic_audio_timer\n", + __func__); + hrtimer_cancel(&aw8622x->haptic_audio.timer); + aw8622x->haptic_audio.ctr.cnt = 0; + aw8622x_haptic_audio_off(aw8622x); + } + } else { + if (hrtimer_active(&aw8622x->haptic_audio.timer)) { + } else { + aw_dev_info( "%s: start haptic_audio_timer\n", + __func__); + aw8622x_haptic_audio_init(aw8622x); + hrtimer_start(&aw8622x->haptic_audio.timer, + ktime_set(aw8622x->haptic_audio.delay_val/1000000, + (aw8622x->haptic_audio.delay_val%1000000)*1000), + HRTIMER_MODE_REL); + } + } + kfree(hap_ctr); + mutex_unlock(&aw8622x->haptic_audio.lock); + return 0; +} + +static ssize_t aw8622x_haptic_audio_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int databuf[6] = {0}; + int rtp_is_going_on = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + + rtp_is_going_on = aw8622x_haptic_juge_RTP_is_going_on(aw8622x); + if (rtp_is_going_on) { + aw_dev_info("%s: RTP is runing, stop audio haptic\n", __func__); + return count; + } + if (!aw8622x->ram_init) + return count; + + if (sscanf(buf, "%d %d %d %d %d %d", + &databuf[0], &databuf[1], &databuf[2], + &databuf[3], &databuf[4], &databuf[5]) == 6) { + if (databuf[2]) { + aw_dev_info("%s: cnt=%d, cmd=%d, play=%d\n", + __func__, databuf[0], databuf[1], databuf[2]); + aw_dev_info("%s: wavseq=%d, loop=%d, gain=%d\n", + __func__, databuf[3], databuf[4], databuf[5]); + aw8622x_audio_config(aw8622x, databuf); + + } + } + return count; +} + +static ssize_t aw8622x_ram_num_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + aw8622x_haptic_get_ram_number(aw8622x); + len += snprintf(buf+len, PAGE_SIZE-len, + "ram_num = %d\n", aw8622x->ram.ram_num); + return len; +} + +static ssize_t aw8622x_awrw_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + unsigned char i = 0; + unsigned char reg_num = aw8622x->aw_i2c_package.reg_num; + unsigned char flag = aw8622x->aw_i2c_package.flag; + unsigned char *reg_data = aw8622x->aw_i2c_package.reg_data; + ssize_t len = 0; + + if (!reg_num) { + aw_dev_err("%s: awrw parameter error\n", + __func__); + return len; + } + if (flag == AW8622X_READ) { + for (i = 0; i < reg_num; i++) { + len += snprintf(buf + len, PAGE_SIZE - len, + "0x%02x,", reg_data[i]); + } + + len += snprintf(buf + len - 1, PAGE_SIZE - len, "\n"); + } + + return len; +} + +static ssize_t aw8622x_awrw_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int datatype[3] = { 0 }; + int ret = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8622x *aw8622x = container_of(cdev, struct aw8622x, vib_dev); + + if (sscanf(buf, "%x %x %x", &datatype[0], &datatype[1], + &datatype[2]) == 3) { + if (!datatype[1]) { + aw_dev_err("%s: awrw parameter error\n", + __func__); + return count; + } + aw8622x->aw_i2c_package.flag = (unsigned char)datatype[0]; + aw8622x->aw_i2c_package.reg_num = (unsigned char)datatype[1]; + aw8622x->aw_i2c_package.first_addr = (unsigned char)datatype[2]; + if (aw8622x->aw_i2c_package.flag == AW8622X_WRITE) { + ret = aw8622x_parse_data(aw8622x, buf); + if (ret < 0) + return count; + aw8622x_i2c_write(aw8622x, + aw8622x->aw_i2c_package.first_addr, + aw8622x->aw_i2c_package.reg_data, + aw8622x->aw_i2c_package.reg_num); + } + if (aw8622x->aw_i2c_package.flag == AW8622X_READ) + aw8622x_i2c_read(aw8622x, + aw8622x->aw_i2c_package.first_addr, + aw8622x->aw_i2c_package.reg_data, + aw8622x->aw_i2c_package.reg_num); + } else + aw_dev_err("%s: missing number of parameters\n", + __func__); + + return count; +} + +static DEVICE_ATTR(f0, 0644, aw8622x_f0_show, aw8622x_f0_store); +static DEVICE_ATTR(cont, 0644, aw8622x_cont_show, aw8622x_cont_store); +static DEVICE_ATTR(register, 0644, aw8622x_reg_show, aw8622x_reg_store); +static DEVICE_ATTR(duration, 0644, aw8622x_duration_show, + aw8622x_duration_store); +static DEVICE_ATTR(index, 0644, aw8622x_index_show, aw8622x_index_store); +static DEVICE_ATTR(activate, 0644, aw8622x_activate_show, + aw8622x_activate_store); +static DEVICE_ATTR(activate_mode, 0644, aw8622x_activate_mode_show, + aw8622x_activate_mode_store); +static DEVICE_ATTR(seq, 0644, aw8622x_seq_show, aw8622x_seq_store); +static DEVICE_ATTR(loop, 0644, aw8622x_loop_show, aw8622x_loop_store); +static DEVICE_ATTR(rtp, 0644, aw8622x_rtp_show, aw8622x_rtp_store); +static DEVICE_ATTR(state, 0644, aw8622x_state_show, aw8622x_state_store); +static DEVICE_ATTR(sram_size, 0644, aw8622x_sram_size_show, + aw8622x_sram_size_store); +static DEVICE_ATTR(osc_cali, 0644, aw8622x_osc_cali_show, + aw8622x_osc_cali_store); +static DEVICE_ATTR(gain, 0644, aw8622x_gain_show, aw8622x_gain_store); +static DEVICE_ATTR(ram_update, 0644, aw8622x_ram_update_show, + aw8622x_ram_update_store); +static DEVICE_ATTR(f0_save, 0644, aw8622x_f0_save_show, aw8622x_f0_save_store); +static DEVICE_ATTR(osc_save, 0644, aw8622x_osc_save_show, + aw8622x_osc_save_store); +static DEVICE_ATTR(trig, 0644, aw8622x_trig_show, aw8622x_trig_store); +static DEVICE_ATTR(ram_vbat_comp, 0644, aw8622x_ram_vbat_compensate_show, + aw8622x_ram_vbat_compensate_store); +static DEVICE_ATTR(cali, 0644, aw8622x_cali_show, aw8622x_cali_store); +static DEVICE_ATTR(cont_wait_num, 0644, aw8622x_cont_wait_num_show, + aw8622x_cont_wait_num_store); +static DEVICE_ATTR(cont_drv_lvl, 0644, aw8622x_cont_drv_lvl_show, + aw8622x_cont_drv_lvl_store); +static DEVICE_ATTR(cont_drv_time, 0644, aw8622x_cont_drv_time_show, + aw8622x_cont_drv_time_store); +static DEVICE_ATTR(cont_brk_time, 0644, aw8622x_cont_brk_time_show, + aw8622x_cont_brk_time_store); +static DEVICE_ATTR(vbat_monitor, 0644, aw8622x_vbat_monitor_show, + aw8622x_vbat_monitor_store); +static DEVICE_ATTR(lra_resistance, 0644, aw8622x_lra_resistance_show, + aw8622x_lra_resistance_store); +static DEVICE_ATTR(prctmode, 0644, aw8622x_prctmode_show, + aw8622x_prctmode_store); +static DEVICE_ATTR(gun_type, 0644, aw8622x_gun_type_show, + aw8622x_gun_type_store); +static DEVICE_ATTR(bullet_nr, 0644, aw8622x_bullet_nr_show, + aw8622x_bullet_nr_store); +static DEVICE_ATTR(haptic_audio, 0644, aw8622x_haptic_audio_show, + aw8622x_haptic_audio_store); +static DEVICE_ATTR(ram_num, 0644, aw8622x_ram_num_show, NULL); +static DEVICE_ATTR(awrw, 0644, aw8622x_awrw_show, aw8622x_awrw_store); +static struct attribute *aw8622x_vibrator_attributes[] = { + &dev_attr_state.attr, + &dev_attr_duration.attr, + &dev_attr_activate.attr, + &dev_attr_activate_mode.attr, + &dev_attr_index.attr, + &dev_attr_gain.attr, + &dev_attr_seq.attr, + &dev_attr_loop.attr, + &dev_attr_register.attr, + &dev_attr_rtp.attr, + &dev_attr_ram_update.attr, + &dev_attr_f0.attr, + &dev_attr_cali.attr, + &dev_attr_f0_save.attr, + &dev_attr_osc_save.attr, + &dev_attr_cont.attr, + &dev_attr_cont_wait_num.attr, + &dev_attr_cont_drv_lvl.attr, + &dev_attr_cont_drv_time.attr, + &dev_attr_cont_brk_time.attr, + &dev_attr_vbat_monitor.attr, + &dev_attr_lra_resistance.attr, + &dev_attr_prctmode.attr, + &dev_attr_sram_size.attr, + &dev_attr_ram_vbat_comp.attr, + &dev_attr_osc_cali.attr, + &dev_attr_gun_type.attr, + &dev_attr_bullet_nr.attr, + &dev_attr_haptic_audio.attr, + &dev_attr_trig.attr, + &dev_attr_ram_num.attr, + &dev_attr_awrw.attr, + NULL +}; + +struct attribute_group aw8622x_vibrator_attribute_group = { + .attrs = aw8622x_vibrator_attributes +}; + +static void aw8622x_haptic_ram_play(struct aw8622x *aw8622x, unsigned char type) +{ + aw_dev_info("%s index = %d\n", __func__, aw8622x->index); + + mutex_lock(&aw8622x->ram_lock); + if (type == AW8622X_HAPTIC_RAM_LOOP_MODE) + aw8622x_haptic_set_repeat_wav_seq(aw8622x, aw8622x->index); + + if (type == AW8622X_HAPTIC_RAM_MODE) { + aw8622x_haptic_set_wav_seq(aw8622x, 0x00, aw8622x->index); + aw8622x_haptic_set_wav_seq(aw8622x, 0x01, 0x00); + aw8622x_haptic_set_wav_loop(aw8622x, 0x00, 0x00); + } + aw8622x_haptic_play_mode(aw8622x, type); + aw8622x_haptic_start(aw8622x); + mutex_unlock(&aw8622x->ram_lock); +} + +static void aw8622x_vibrator_work_routine(struct work_struct *work) +{ + struct aw8622x *aw8622x = container_of(work, struct aw8622x, + vibrator_work); + + aw_dev_info("%s enter\n", __func__); + + mutex_lock(&aw8622x->lock); + /* Enter standby mode */ + aw8622x_haptic_stop(aw8622x); + aw8622x_haptic_upload_lra(aw8622x, AW8622X_F0_CALI); + if (aw8622x->state) { + if (aw8622x->activate_mode == AW8622X_HAPTIC_RAM_MODE) { + aw8622x_haptic_ram_vbat_comp(aw8622x, false); + aw8622x_haptic_ram_play(aw8622x, + AW8622X_HAPTIC_RAM_MODE); + } else if (aw8622x->activate_mode == + AW8622X_HAPTIC_RAM_LOOP_MODE) { + aw8622x_haptic_ram_vbat_comp(aw8622x, true); + aw8622x_haptic_ram_play(aw8622x, + AW8622X_HAPTIC_RAM_LOOP_MODE); + /* run ms timer */ + hrtimer_start(&aw8622x->timer, + ktime_set(aw8622x->duration / 1000, + (aw8622x->duration % 1000) * 1000000), + HRTIMER_MODE_REL); + } else if (aw8622x->activate_mode == + AW8622X_HAPTIC_CONT_MODE) { + aw8622x_haptic_cont(aw8622x); + /* run ms timer */ + hrtimer_start(&aw8622x->timer, + ktime_set(aw8622x->duration / 1000, + (aw8622x->duration % 1000) * 1000000), + HRTIMER_MODE_REL); + } else { + aw_dev_err("%s: activate_mode error\n", + __func__); + } + } + mutex_unlock(&aw8622x->lock); +} + +int aw8622x_vibrator_init(struct aw8622x *aw8622x) +{ + int ret = 0; + + aw_dev_info("%s enter\n", __func__); + +#ifdef TIMED_OUTPUT + aw_dev_info("%s: TIMED_OUT FRAMEWORK!\n", __func__); + aw8622x->vib_dev.name = "awinic_vibrator"; + aw8622x->vib_dev.get_time = aw8622x_vibrator_get_time; + aw8622x->vib_dev.enable = aw8622x_vibrator_enable; + + ret = timed_output_dev_register(&(aw8622x->vib_dev)); + if (ret < 0) { + aw_dev_err("%s: fail to create timed output dev\n", __func__); + return ret; + } + ret = sysfs_create_group(&aw8622x->vib_dev.dev->kobj, + &aw8622x_vibrator_attribute_group); + if (ret < 0) { + aw_dev_err("%s error creating sysfs attr files\n", __func__); + return ret; + } +#else + aw_dev_info("%s: loaded in leds_cdev framework!\n", + __func__); + aw8622x->vib_dev.name = "awinic_vibrator"; + aw8622x->vib_dev.brightness_get = aw8622x_haptic_brightness_get; + aw8622x->vib_dev.brightness_set = aw8622x_haptic_brightness_set; + + ret = devm_led_classdev_register(&aw8622x->i2c->dev, &aw8622x->vib_dev); + if (ret < 0) { + aw_dev_err("%s: fail to create led dev\n", __func__); + return ret; + } + ret = sysfs_create_group(&aw8622x->vib_dev.dev->kobj, + &aw8622x_vibrator_attribute_group); + if (ret < 0) { + aw_dev_err("%s error creating sysfs attr files\n", + __func__); + return ret; + } +#endif + hrtimer_init(&aw8622x->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + aw8622x->timer.function = aw8622x_vibrator_timer_func; + INIT_WORK(&aw8622x->vibrator_work, + aw8622x_vibrator_work_routine); + INIT_WORK(&aw8622x->rtp_work, aw8622x_rtp_work_routine); + mutex_init(&aw8622x->lock); + mutex_init(&aw8622x->rtp_lock); + mutex_init(&aw8622x->ram_lock); + + return 0; +} + +static int aw8622x_haptic_set_pwm(struct aw8622x *aw8622x, unsigned char mode) +{ + switch (mode) { + case AW8622X_PWM_48K: + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSCTRL2, + AW8622X_BIT_SYSCTRL2_WAVDAT_MODE_MASK, + AW8622X_BIT_SYSCTRL2_RATE_48K); + break; + case AW8622X_PWM_24K: + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSCTRL2, + AW8622X_BIT_SYSCTRL2_WAVDAT_MODE_MASK, + AW8622X_BIT_SYSCTRL2_RATE_24K); + break; + case AW8622X_PWM_12K: + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSCTRL2, + AW8622X_BIT_SYSCTRL2_WAVDAT_MODE_MASK, + AW8622X_BIT_SYSCTRL2_RATE_12K); + break; + default: + break; + } + return 0; +} + +static void aw8622x_haptic_misc_para_init(struct aw8622x *aw8622x) +{ + unsigned char reg_array[4] = {0}; + unsigned char reg_val = 0; + + aw_dev_info("%s enter\n", __func__); + aw8622x->cont_drv1_lvl = aw8622x->dts_info.cont_drv1_lvl_dt; + aw8622x->cont_drv2_lvl = aw8622x->dts_info.cont_drv2_lvl_dt; + aw8622x->cont_drv1_time = aw8622x->dts_info.cont_drv1_time_dt; + aw8622x->cont_drv2_time = aw8622x->dts_info.cont_drv2_time_dt; + aw8622x->cont_brk_time = aw8622x->dts_info.cont_brk_time_dt; + aw8622x->cont_wait_num = aw8622x->dts_info.cont_wait_num_dt; + + /* SIN_H */ + reg_array[0] = (unsigned char)aw8622x->dts_info.sine_array[0]; + /* SIN_L */ + reg_array[1] = (unsigned char)aw8622x->dts_info.sine_array[1]; + /* COS_H */ + reg_array[2] = (unsigned char)aw8622x->dts_info.sine_array[2]; + /* COS_L */ + reg_array[3] = (unsigned char)aw8622x->dts_info.sine_array[3]; + + aw8622x_i2c_write(aw8622x, AW8622X_REG_SYSCTRL3, reg_array, + AW_I2C_BYTE_FOUR); + + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_TRGCFG8, + AW8622X_BIT_TRGCFG8_TRG_TRIG1_MODE_MASK, + AW8622X_BIT_TRGCFG8_TRIG1); + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_ANACFG8, + AW8622X_BIT_ANACFG8_TRTF_CTRL_HDRV_MASK, + AW8622X_BIT_ANACFG8_TRTF_CTRL_HDRV); + + /* d2s_gain */ + if (!aw8622x->dts_info.d2s_gain) { + aw_dev_err("%s aw8622x->dts_info.d2s_gain = 0!\n", + __func__); + } else { + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSCTRL7, + AW8622X_BIT_SYSCTRL7_D2S_GAIN_MASK, + aw8622x->dts_info.d2s_gain); + } + + if (aw8622x->dts_info.cont_tset && aw8622x->dts_info.cont_bemf_set) { + reg_array[0] = (unsigned char)aw8622x->dts_info.cont_tset; + reg_array[1] = (unsigned char)aw8622x->dts_info.cont_bemf_set; + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_CONTCFG13, + (AW8622X_BIT_CONTCFG13_TSET_MASK & + AW8622X_BIT_CONTCFG13_BEME_SET_MASK), + ((reg_array[0] << 4)| + reg_array[1])); + } + + /* cont_brk_time */ + if (!aw8622x->cont_brk_time) { + aw_dev_err("%s aw8622x->cont_brk_time = 0!\n", + __func__); + } else { + reg_val = (unsigned char)aw8622x->cont_brk_time; + aw8622x_i2c_write(aw8622x, AW8622X_REG_CONTCFG10, ®_val, + AW_I2C_BYTE_ONE); + } + + /* cont_bst_brk_gain */ + /* + ** if (!aw8622x->dts_info.cont_bst_brk_gain) { + ** aw_dev_err("%s aw8622x->dts_info.cont_bst_brk_gain = 0!\n", + ** __func__); + ** } else { + ** aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_CONTCFG5, + ** AW8622X_BIT_CONTCFG5_BST_BRK_GAIN_MASK, + ** aw8622x->dts_info.cont_bst_brk_gain); + ** } + */ + + /* cont_brk_gain */ + if (!aw8622x->dts_info.cont_brk_gain) { + aw_dev_err("%s aw8622x->dts_info.cont_brk_gain = 0!\n", + __func__); + } else { + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_CONTCFG5, + AW8622X_BIT_CONTCFG5_BRK_GAIN_MASK, + aw8622x->dts_info.cont_brk_gain); + } +} + +/***************************************************** + * + * offset calibration + * + *****************************************************/ +static int aw8622x_haptic_offset_calibration(struct aw8622x *aw8622x) +{ + unsigned int cont = 2000; + unsigned char reg_val = 0; + + aw_dev_info("%s enter\n", __func__); + + aw8622x_haptic_raminit(aw8622x, true); + + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_DETCFG2, + AW8622X_BIT_DETCFG2_DIAG_GO_MASK, + AW8622X_BIT_DETCFG2_DIAG_GO_ON); + while (1) { + aw8622x_i2c_read(aw8622x, AW8622X_REG_DETCFG2, ®_val, + AW_I2C_BYTE_ONE); + if ((reg_val & 0x01) == 0 || cont == 0) + break; + cont--; + } + if (cont == 0) + aw_dev_err("%s calibration offset failed!\n", + __func__); + aw8622x_haptic_raminit(aw8622x, false); + return 0; +} + +/***************************************************** + * + * vbat mode + * + *****************************************************/ +static int aw8622x_haptic_vbat_mode_config(struct aw8622x *aw8622x, + unsigned char flag) +{ + if (flag == AW8622X_HAPTIC_CONT_VBAT_HW_ADJUST_MODE) { + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSCTRL1, + AW8622X_BIT_SYSCTRL1_VBAT_MODE_MASK, + AW8622X_BIT_SYSCTRL1_VBAT_MODE_HW); + } else { + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSCTRL1, + AW8622X_BIT_SYSCTRL1_VBAT_MODE_MASK, + AW8622X_BIT_SYSCTRL1_VBAT_MODE_SW); + } + return 0; +} + +static void aw8622x_ram_work_routine(struct work_struct *work) +{ + struct aw8622x *aw8622x = container_of(work, struct aw8622x, + ram_work.work); + + aw_dev_info("%s enter\n", __func__); + aw8622x_ram_update(aw8622x); +} + +int aw8622x_ram_work_init(struct aw8622x *aw8622x) +{ + int ram_timer_val = 8000; + + aw_dev_info("%s enter\n", __func__); + INIT_DELAYED_WORK(&aw8622x->ram_work, aw8622x_ram_work_routine); + schedule_delayed_work(&aw8622x->ram_work, + msecs_to_jiffies(ram_timer_val)); + return 0; +} +static enum hrtimer_restart +aw8622x_haptic_audio_timer_func(struct hrtimer *timer) +{ + struct aw8622x *aw8622x = container_of(timer, + struct aw8622x, haptic_audio.timer); + + aw_dev_dbg("%s enter\n", __func__); + schedule_work(&aw8622x->haptic_audio.work); + + hrtimer_start(&aw8622x->haptic_audio.timer, + ktime_set(aw8622x->haptic_audio.timer_val/1000000, + (aw8622x->haptic_audio.timer_val%1000000)*1000), + HRTIMER_MODE_REL); + return HRTIMER_NORESTART; +} + +static void +aw8622x_haptic_auto_brk_enable(struct aw8622x *aw8622x, unsigned char flag) +{ + if (flag) { + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_PLAYCFG3, + AW8622X_BIT_PLAYCFG3_BRK_EN_MASK, + AW8622X_BIT_PLAYCFG3_BRK_ENABLE); + } else { + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_PLAYCFG3, + AW8622X_BIT_PLAYCFG3_BRK_EN_MASK, + AW8622X_BIT_PLAYCFG3_BRK_DISABLE); + } +} +int aw8622x_haptic_init(struct aw8622x *aw8622x) +{ + unsigned char reg_val = 0; + unsigned char reg_array[8] = {0}; + int ret = 0; + + aw_dev_info("%s enter\n", __func__); + /* haptic audio */ + aw8622x->haptic_audio.delay_val = 1; + aw8622x->haptic_audio.timer_val = 21318; + INIT_LIST_HEAD(&(aw8622x->haptic_audio.ctr_list)); + hrtimer_init(&aw8622x->haptic_audio.timer, + CLOCK_MONOTONIC, HRTIMER_MODE_REL); + aw8622x->haptic_audio.timer.function = aw8622x_haptic_audio_timer_func; + INIT_WORK(&aw8622x->haptic_audio.work, + aw8622x_haptic_audio_work_routine); + mutex_init(&aw8622x->haptic_audio.lock); + aw8622x->gun_type = AW_GUN_TYPE_DEF_VAL; + aw8622x->bullet_nr = AW_BULLET_NR_DEF_VAL; + + mutex_lock(&aw8622x->lock); + /* haptic init */ + aw8622x->ram_state = 0; + aw8622x->activate_mode = aw8622x->dts_info.mode; + ret = aw8622x_i2c_read(aw8622x, AW8622X_REG_WAVCFG1, ®_val, + AW_I2C_BYTE_ONE); + aw8622x->index = reg_val & AW8622X_BIT_WAVCFG_SEQ; + ret = aw8622x_i2c_read(aw8622x, AW8622X_REG_PLAYCFG2, ®_val, + AW_I2C_BYTE_ONE); + aw8622x->gain = reg_val; + aw_dev_info("%s aw8622x->gain =0x%02X\n", __func__, aw8622x->gain); + aw8622x_i2c_read(aw8622x, AW8622X_REG_WAVCFG1, reg_array, + AW8622X_SEQUENCER_SIZE); + memcpy(aw8622x->seq, reg_array, AW8622X_SEQUENCER_SIZE); + + aw8622x_haptic_play_mode(aw8622x, AW8622X_HAPTIC_STANDBY_MODE); + aw8622x_haptic_set_pwm(aw8622x, AW8622X_PWM_12K); + /* misc value init */ + aw8622x_haptic_misc_para_init(aw8622x); + /* set motor protect */ + aw8622x_haptic_swicth_motor_protect_config(aw8622x, 0x00, 0x00); + aw8622x_haptic_trig_param_init(aw8622x); + aw8622x_haptic_trig_param_config(aw8622x); + aw8622x_haptic_offset_calibration(aw8622x); + /*config auto_brake*/ + aw8622x_haptic_auto_brk_enable(aw8622x, + aw8622x->dts_info.is_enabled_auto_brk); + /* vbat compensation */ + aw8622x_haptic_vbat_mode_config(aw8622x, + AW8622X_HAPTIC_CONT_VBAT_HW_ADJUST_MODE); + aw8622x->ram_vbat_compensate = AW8622X_HAPTIC_RAM_VBAT_COMP_ENABLE; + + /* f0 calibration */ + /*LRA trim source select register*/ + aw8622x_i2c_write_bits(aw8622x, + AW8622X_REG_TRIMCFG1, + AW8622X_BIT_TRIMCFG1_RL_TRIM_SRC_MASK, + AW8622X_BIT_TRIMCFG1_RL_TRIM_SRC_REG); + if (aw8622x->dts_info.lk_f0_cali) { + aw8622x->f0_cali_data = aw8622x->dts_info.lk_f0_cali; + aw8622x_haptic_upload_lra(aw8622x, AW8622X_F0_CALI); + } else { + aw8622x_haptic_upload_lra(aw8622x, AW8622X_WRITE_ZERO); + aw8622x_haptic_f0_calibration(aw8622x); + } + mutex_unlock(&aw8622x->lock); + return ret; +} + +void aw8622x_interrupt_setup(struct aw8622x *aw8622x) +{ + unsigned char reg_val = 0; + + aw_dev_info("%s enter\n", __func__); + + aw8622x_i2c_read(aw8622x, AW8622X_REG_SYSINT, ®_val, + AW_I2C_BYTE_ONE); + + aw_dev_info("%s: reg SYSINT=0x%02X\n", __func__, reg_val); + + /* edge int mode */ + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSCTRL7, + (AW8622X_BIT_SYSCTRL7_INT_MODE_MASK & + AW8622X_BIT_SYSCTRL7_INT_EDGE_MODE_MASK), + (AW8622X_BIT_SYSCTRL7_INT_MODE_EDGE | + AW8622X_BIT_SYSCTRL7_INT_EDGE_MODE_POS)); + /* int enable */ + /* + *aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSINTM, + * AW8622X_BIT_SYSINTM_BST_SCPM_MASK, + * AW8622X_BIT_SYSINTM_BST_SCPM_OFF); + *aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSINTM, + * AW8622X_BIT_SYSINTM_BST_OVPM_MASK, + * AW8622X_BIT_SYSINTM_BST_OVPM_ON); + */ + aw8622x_i2c_write_bits(aw8622x, AW8622X_REG_SYSINTM, + (AW8622X_BIT_SYSINTM_UVLM_MASK & + AW8622X_BIT_SYSINTM_OCDM_MASK & + AW8622X_BIT_SYSINTM_OTM_MASK), + (AW8622X_BIT_SYSINTM_UVLM_ON | + AW8622X_BIT_SYSINTM_OCDM_ON | + AW8622X_BIT_SYSINTM_OTM_ON)); +} +static int aw8622x_is_rtp_load_end(struct aw8622x *aw8622x) +{ + unsigned char glb_st = 0; + int ret = -1; + + aw8622x_i2c_read(aw8622x, AW8622X_REG_GLBRD5, + &glb_st, AW_I2C_BYTE_ONE); + if ((aw8622x->rtp_cnt == aw8622x->rtp_container->len) + || ((glb_st & 0x0f) == 0)) { + if (aw8622x->rtp_cnt == + aw8622x->rtp_container->len) + aw_dev_info("%s: rtp load completely!\n", + __func__); + else + aw_dev_err("%s rtp load failed!!\n", + __func__); + aw8622x_haptic_set_rtp_aei(aw8622x, + false); + aw8622x->rtp_cnt = 0; + aw8622x->rtp_init = 0; + ret = 0; + } + return ret; + +} + +static int aw8622x_write_rtp_data(struct aw8622x *aw8622x) +{ + unsigned int buf_len = 0; + int ret = -1; + + if (!aw8622x->rtp_cnt) { + aw_dev_info("%s:aw8622x->rtp_cnt is 0!\n", + __func__); + return ret; + } + if (!aw8622x->rtp_container) { + aw_dev_info("%s:aw8622x->rtp_container is null, break!\n", + __func__); + return ret; + } + if ((aw8622x->rtp_container->len - aw8622x->rtp_cnt) < + (aw8622x->ram.base_addr >> 1)) { + buf_len = + aw8622x->rtp_container->len - aw8622x->rtp_cnt; + } else { + buf_len = (aw8622x->ram.base_addr >> 2); + } + aw8622x_i2c_write(aw8622x, AW8622X_REG_RTPDATA, + &aw8622x->rtp_container->data[aw8622x->rtp_cnt], + buf_len); + aw8622x->rtp_cnt += buf_len; + return 0; +} + +irqreturn_t aw8622x_irq(int irq, void *data) +{ + struct aw8622x *aw8622x = data; + unsigned char reg_val = 0; + int ret = 0; + + aw_dev_dbg("%s enter\n", __func__); + aw8622x_i2c_read(aw8622x, AW8622X_REG_SYSINT, ®_val, + AW_I2C_BYTE_ONE); + aw_dev_dbg("%s: reg SYSINT=0x%02X\n", __func__, reg_val); + if (reg_val & AW8622X_BIT_SYSINT_UVLI) + aw_dev_err("%s chip uvlo int error\n", __func__); + if (reg_val & AW8622X_BIT_SYSINT_OCDI) + aw_dev_err("%s chip over current int error\n", __func__); + if (reg_val & AW8622X_BIT_SYSINT_OTI) + aw_dev_err("%s chip over temperature int error\n", __func__); + if (reg_val & AW8622X_BIT_SYSINT_DONEI) + aw_dev_info("%s chip playback done\n", __func__); + + if (reg_val & AW8622X_BIT_SYSINT_FF_AEI) { + aw_dev_dbg("%s: aw8622x rtp fifo almost empty\n", __func__); + if (aw8622x->rtp_init) { + while ((!aw8622x_haptic_rtp_get_fifo_afs(aw8622x)) && + (aw8622x->play_mode == + AW8622X_HAPTIC_RTP_MODE)) { + mutex_lock(&aw8622x->rtp_lock); +#ifdef AW_ENABLE_RTP_PRINT_LOG + aw_dev_info( "%s: aw8622x rtp mode fifo update, cnt=%d\n", + __func__, aw8622x->rtp_cnt); +#endif + ret = aw8622x_write_rtp_data(aw8622x); + if (ret < 0) { + mutex_unlock(&aw8622x->rtp_lock); + break; + } + ret = aw8622x_is_rtp_load_end(aw8622x); + if (!ret) { + mutex_unlock(&aw8622x->rtp_lock); + break; + } + mutex_unlock(&aw8622x->rtp_lock); + } + } else { + aw_dev_info("%s: aw8622x rtp init = %d, init error\n", + __func__, aw8622x->rtp_init); + } + } + + if (reg_val & AW8622X_BIT_SYSINT_FF_AFI) + aw_dev_dbg("%s: aw8622x rtp mode fifo almost full!\n", + __func__); + + if (aw8622x->play_mode != AW8622X_HAPTIC_RTP_MODE) + aw8622x_haptic_set_rtp_aei(aw8622x, false); + + aw_dev_dbg("%s exit\n", __func__); + + return IRQ_HANDLED; +} + +char aw8622x_check_qualify(struct aw8622x *aw8622x) +{ + unsigned char reg = 0; + int ret = 0; + + ret = aw8622x_i2c_read(aw8622x, AW8622X_REG_EFRD9, ®, + AW_I2C_BYTE_ONE); + if (ret < 0) { + aw_dev_err("%s: failed to read register 0x64: %d\n", + __func__, ret); + return ret; + } + if ((reg & 0x80) == 0x80) + return 1; + aw_dev_err("%s: register 0x64 error: 0x%02x\n", + __func__, reg); + return 0; +} diff --git a/drivers/misc/awinic/aw862x/aw8622x.h b/drivers/misc/awinic/aw862x/aw8622x.h new file mode 100644 index 000000000000..f2abc1846bdb --- /dev/null +++ b/drivers/misc/awinic/aw862x/aw8622x.h @@ -0,0 +1,774 @@ +#ifndef _AW8622X_H_ +#define _AW8622X_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "haptic_nv.h" + +/********************************************************* + * + * marco + * + ********************************************************/ +#define AW8622X_I2C_RETRIES (5) +#define AW8622X_RTP_NAME_MAX (64) +#define AW8622X_SEQUENCER_SIZE (8) +#define AW8622X_SEQUENCER_LOOP_SIZE (4) +#define AW8622X_OSC_CALI_MAX_LENGTH (11000000) +#define AW8622X_PM_QOS_VALUE_VB (400) +#define AW8622X_VBAT_REFER (4200) +#define AW8622X_VBAT_MIN (3000) +#define AW8622X_VBAT_MAX (5500) +#define AW8622X_TRIG_NUM (3) +#define AW8622X_I2C_RETRY_DELAY (2) +#define AW8622X_GAIN_MAX (0x80) +#define AW8622X_VBAT_FORMULA(code) (6100 * (code) / 1024) +#define AW8622X_LRA_F0_FORMULA(f0_reg) (384000 * 10 / (f0_reg)) +#define AW8622X_CONT_F0_FORMULA(f0_reg) (384000 * 10 / (f0_reg)) +#define AW8622X_LRA_FORMULA(lra_code) (((lra_code) * 678 * 100) / (1024 * 10)) +#define AW8622X_SET_AEADDR_H(addr) ((((addr) >> 1) >> 4) & 0xF0) +#define AW8622X_SET_AEADDR_L(addr) (((addr) >> 1) & 0x00FF) +#define AW8622X_SET_AFADDR_H(addr) ((((addr) - ((addr) >> 2)) >> 8) & 0x0F) +#define AW8622X_SET_AFADDR_L(addr) (((addr) - ((addr) >> 2)) & 0x00FF) +#define AW8622X_STOP_DELAY_MIN (2000) +#define AW8622X_STOP_DELAY_MAX (2500) +#define AW8622X_VBAT_DELAY_MIN (20000) +#define AW8622X_VBAT_DELAY_MAX (25000) +#define AW8622X_F0_DELAY_MIN (10000) +#define AW8622X_F0_DELAY_MAX (10500) +#define AW8622X_LRA_DELAY_MIN (30000) +#define AW8622X_LRA_DELAY_MAX (35000) +/********************************************************* + * + * enum + * + ********************************************************/ +enum aw8622x_flags { + AW8622X_FLAG_NONR = 0, + AW8622X_FLAG_SKIP_INTERRUPTS = 1, +}; + +enum aw8622x_haptic_work_mode { + AW8622X_HAPTIC_STANDBY_MODE = 0, + AW8622X_HAPTIC_RAM_MODE = 1, + AW8622X_HAPTIC_RAM_LOOP_MODE = 2, + AW8622X_HAPTIC_CONT_MODE = 3, + AW8622X_HAPTIC_RTP_MODE = 4, + AW8622X_HAPTIC_TRIG_MODE = 5, + AW8622X_HAPTIC_NULL = 6, +}; + +enum aw8622x_haptic_cont_vbat_comp_mode { + AW8622X_HAPTIC_CONT_VBAT_SW_ADJUST_MODE = 0, + AW8622X_HAPTIC_CONT_VBAT_HW_ADJUST_MODE = 1, +}; + +enum aw8622x_haptic_ram_vbat_compensate_mode { + AW8622X_HAPTIC_RAM_VBAT_COMP_DISABLE = 0, + AW8622X_HAPTIC_RAM_VBAT_COMP_ENABLE = 1, +}; + +enum aw8622x_haptic_f0_flag { + AW8622X_HAPTIC_LRA_F0 = 0, + AW8622X_HAPTIC_CALI_F0 = 1, +}; + +enum aw8622x_sram_size_flag { + AW8622X_HAPTIC_SRAM_1K = 0, + AW8622X_HAPTIC_SRAM_2K = 1, + AW8622X_HAPTIC_SRAM_3K = 2, +}; + +enum aw8622x_haptic_pwm_mode { + AW8622X_PWM_48K = 0, + AW8622X_PWM_24K = 1, + AW8622X_PWM_12K = 2, +}; + +enum aw8622x_haptic_play { + AW8622X_HAPTIC_PLAY_NULL = 0, + AW8622X_HAPTIC_PLAY_ENABLE = 1, + AW8622X_HAPTIC_PLAY_STOP = 2, + AW8622X_HAPTIC_PLAY_GAIN = 8, +}; + +enum aw8622x_haptic_cmd { + AW8622X_HAPTIC_CMD_NULL = 0, + AW8622X_HAPTIC_CMD_ENABLE = 1, + AW8622X_HAPTIC_CMD_HAPTIC = 0x0f, + AW8622X_HAPTIC_CMD_TP = 0x10, + AW8622X_HAPTIC_CMD_SYS = 0xf0, + AW8622X_HAPTIC_CMD_STOP = 255, +}; + +enum aw8622x_haptic_cali_lra { + AW8622X_WRITE_ZERO = 0, + AW8622X_F0_CALI = 1, + AW8622X_OSC_CALI = 2, +}; + +enum aw8622x_haptic_rtp_mode { + AW8622X_RTP_SHORT = 4, + AW8622X_RTP_LONG = 5, + AW8622X_RTP_SEGMENT = 6, +}; + +enum aw8622X_awrw_flag { + AW8622X_WRITE = 0, + AW8622X_READ = 1, +}; + +/********************************************************* + * + * struct + * + ********************************************************/ +struct aw862xx_trig { + unsigned char trig_level; + unsigned char trig_polar; + unsigned char pos_enable; + unsigned char pos_sequence; + unsigned char neg_enable; + unsigned char neg_sequence; + unsigned char trig_brk; +}; + +struct aw8622x_dts_info { + unsigned int lk_f0_cali; + unsigned int mode; + unsigned int f0_ref; + unsigned int f0_cali_percent; + unsigned int cont_drv1_lvl_dt; + unsigned int cont_drv2_lvl_dt; + unsigned int cont_drv1_time_dt; + unsigned int cont_drv2_time_dt; + unsigned int cont_wait_num_dt; + unsigned int cont_brk_time_dt; + unsigned int cont_track_margin; + unsigned int cont_tset; + unsigned int cont_drv_width; + unsigned int cont_bemf_set; + unsigned int cont_brk_gain; + unsigned int d2s_gain; + unsigned int prctmode[3]; + unsigned int sine_array[4]; + unsigned int trig_config[24]; + unsigned int duration_time[3]; + bool is_enabled_powerup_f0_cali; + bool is_enabled_auto_brk; +}; + +struct aw8622x { + unsigned char rtp_init; + unsigned char ram_init; + unsigned char rtp_routine_on; + unsigned char max_pos_beme; + unsigned char max_neg_beme; + unsigned char f0_cali_flag; + unsigned char ram_vbat_compensate; + unsigned char hwen_flag; + unsigned char flags; + unsigned char chipid; + unsigned char play_mode; + unsigned char activate_mode; + unsigned char ram_state; + unsigned char duration_time_size; + unsigned char seq[AW8622X_SEQUENCER_SIZE]; + unsigned char loop[AW8622X_SEQUENCER_SIZE]; + + char duration_time_flag; + + bool isUsedIntn; + bool haptic_ready; + + int name; + int reset_gpio; + int irq_gpio; + int state; + int duration; + int amplitude; + int index; + int vmax; + int gain; + int sysclk; + int rate; + int width; + int pstream; + int cstream; + + unsigned int gun_type; + unsigned int bullet_nr; + unsigned int rtp_cnt; + unsigned int rtp_file_num; + unsigned int f0; + unsigned int cont_f0; + unsigned int cont_drv1_lvl; + unsigned int cont_drv2_lvl; + unsigned int cont_brk_time; + unsigned int cont_wait_num; + unsigned int cont_drv1_time; + unsigned int cont_drv2_time; + unsigned int theory_time; + unsigned int vbat; + unsigned int lra; + unsigned int ram_update_flag; + unsigned int rtp_update_flag; + unsigned int osc_cali_data; + unsigned int f0_cali_data; + unsigned int timeval_flags; + unsigned int osc_cali_flag; + unsigned int sys_frequency; + unsigned int rtp_len; + unsigned long int microsecond; + + struct haptic_audio haptic_audio; + struct regmap *regmap; + struct i2c_client *i2c; + struct device *dev; + struct input_dev *input; + struct mutex lock; + struct mutex rtp_lock; + struct mutex ram_lock; + struct hrtimer timer; + struct work_struct vibrator_work; + struct work_struct rtp_work; + struct delayed_work ram_work; + struct aw862xx_trig trig[AW8622X_TRIG_NUM]; + struct aw8622x_dts_info dts_info; + struct aw_i2c_package aw_i2c_package; + struct ram ram; + struct aw8622x_container *rtp_container; + ktime_t kstart, kend; + + cdev_t vib_dev; +}; + +struct aw8622x_container { + int len; + unsigned char data[]; +}; +/********************************************************* + * + * extern + * + ********************************************************/ +extern char aw8622x_check_qualify(struct aw8622x *aw8622x); +extern int aw8622x_parse_dt(struct aw8622x *aw8622x, struct device *dev, + struct device_node *np); +extern void aw8622x_interrupt_setup(struct aw8622x *aw8622x); +extern int aw8622x_vibrator_init(struct aw8622x *aw8622x); +extern int aw8622x_haptic_init(struct aw8622x *aw8622x); +extern int aw8622x_ram_work_init(struct aw8622x *aw8622x); +extern irqreturn_t aw8622x_irq(int irq, void *data); +extern struct attribute_group aw8622x_vibrator_attribute_group; + +/******************************************** + * Register List + *******************************************/ +#define AW8622X_REG_ID (0x00) +#define AW8622X_REG_SYSST (0x01) +#define AW8622X_REG_SYSINT (0x02) +#define AW8622X_REG_SYSINTM (0x03) +#define AW8622X_REG_SYSST2 (0x04) +#define AW8622X_REG_SYSER (0x05) +#define AW8622X_REG_PLAYCFG2 (0x07) +#define AW8622X_REG_PLAYCFG3 (0x08) +#define AW8622X_REG_PLAYCFG4 (0x09) +#define AW8622X_REG_WAVCFG1 (0x0A) +#define AW8622X_REG_WAVCFG2 (0x0B) +#define AW8622X_REG_WAVCFG3 (0x0C) +#define AW8622X_REG_WAVCFG4 (0x0D) +#define AW8622X_REG_WAVCFG5 (0x0E) +#define AW8622X_REG_WAVCFG6 (0x0F) +#define AW8622X_REG_WAVCFG7 (0x10) +#define AW8622X_REG_WAVCFG8 (0x11) +#define AW8622X_REG_WAVCFG9 (0x12) +#define AW8622X_REG_WAVCFG10 (0x13) +#define AW8622X_REG_WAVCFG11 (0x14) +#define AW8622X_REG_WAVCFG12 (0x15) +#define AW8622X_REG_WAVCFG13 (0x16) +#define AW8622X_REG_CONTCFG1 (0x18) +#define AW8622X_REG_CONTCFG2 (0x19) +#define AW8622X_REG_CONTCFG3 (0x1A) +#define AW8622X_REG_CONTCFG4 (0x1B) +#define AW8622X_REG_CONTCFG5 (0x1C) +#define AW8622X_REG_CONTCFG6 (0x1D) +#define AW8622X_REG_CONTCFG7 (0x1E) +#define AW8622X_REG_CONTCFG8 (0x1F) +#define AW8622X_REG_CONTCFG9 (0x20) +#define AW8622X_REG_CONTCFG10 (0x21) +#define AW8622X_REG_CONTCFG11 (0x22) +#define AW8622X_REG_CONTCFG12 (0x23) +#define AW8622X_REG_CONTCFG13 (0x24) +#define AW8622X_REG_CONTRD14 (0x25) +#define AW8622X_REG_CONTRD15 (0x26) +#define AW8622X_REG_CONTRD16 (0x27) +#define AW8622X_REG_CONTRD17 (0x28) +#define AW8622X_REG_CONTRD18 (0x29) +#define AW8622X_REG_CONTRD19 (0x2A) +#define AW8622X_REG_CONTRD20 (0x2B) +#define AW8622X_REG_CONTRD21 (0x2C) +#define AW8622X_REG_RTPCFG1 (0x2D) +#define AW8622X_REG_RTPCFG2 (0x2E) +#define AW8622X_REG_RTPCFG3 (0x2F) +#define AW8622X_REG_RTPCFG4 (0x30) +#define AW8622X_REG_RTPCFG5 (0x31) +#define AW8622X_REG_RTPDATA (0x32) +#define AW8622X_REG_TRGCFG1 (0x33) +#define AW8622X_REG_TRGCFG2 (0x34) +#define AW8622X_REG_TRGCFG3 (0x35) +#define AW8622X_REG_TRGCFG4 (0x36) +#define AW8622X_REG_TRGCFG5 (0x37) +#define AW8622X_REG_TRGCFG6 (0x38) +#define AW8622X_REG_TRGCFG7 (0x39) +#define AW8622X_REG_TRGCFG8 (0x3A) +#define AW8622X_REG_GLBCFG4 (0x3E) +#define AW8622X_REG_GLBRD5 (0x3F) +#define AW8622X_REG_RAMADDRH (0x40) +#define AW8622X_REG_RAMADDRL (0x41) +#define AW8622X_REG_RAMDATA (0x42) +#define AW8622X_REG_SYSCTRL1 (0x43) +#define AW8622X_REG_SYSCTRL2 (0x44) +#define AW8622X_REG_SYSCTRL3 (0x45) +#define AW8622X_REG_SYSCTRL4 (0x46) +#define AW8622X_REG_SYSCTRL5 (0x47) +#define AW8622X_REG_SYSCTRL6 (0x48) +#define AW8622X_REG_SYSCTRL7 (0x49) +#define AW8622X_REG_PWMCFG1 (0x4C) +#define AW8622X_REG_PWMCFG3 (0x4E) +#define AW8622X_REG_PWMCFG4 (0x4F) +#define AW8622X_REG_DETCFG1 (0x51) +#define AW8622X_REG_DETCFG2 (0x52) +#define AW8622X_REG_DET_RL (0x53) +#define AW8622X_REG_DET_VBAT (0x55) +#define AW8622X_REG_DET_LO (0x57) +#define AW8622X_REG_TRIMCFG1 (0x58) +#define AW8622X_REG_TRIMCFG3 (0x5A) +#define AW8622X_REG_EFRD9 (0x64) +#define AW8622X_REG_ANACFG8 (0x77) +/****************************************************** + * Register Detail + *****************************************************/ +/* SYSST: reg 0x01 RO */ +#define AW8622X_BIT_SYSST_UVLS (1<<5) +#define AW8622X_BIT_SYSST_FF_AES (1<<4) +#define AW8622X_BIT_SYSST_FF_AFS (1<<3) +#define AW8622X_BIT_SYSST_OCDS (1<<2) +#define AW8622X_BIT_SYSST_OTS (1<<1) +#define AW8622X_BIT_SYSST_DONES (1<<0) + +/* SYSINT: reg 0x02 RC */ +#define AW8622X_BIT_SYSINT_UVLI (1<<5) +#define AW8622X_BIT_SYSINT_FF_AEI (1<<4) +#define AW8622X_BIT_SYSINT_FF_AFI (1<<3) +#define AW8622X_BIT_SYSINT_OCDI (1<<2) +#define AW8622X_BIT_SYSINT_OTI (1<<1) +#define AW8622X_BIT_SYSINT_DONEI (1<<0) + +/* SYSINTM: reg 0x03 RW */ +#define AW8622X_BIT_SYSINTM_UVLM_MASK (~(1<<5)) +#define AW8622X_BIT_SYSINTM_UVLM_OFF (1<<5) +#define AW8622X_BIT_SYSINTM_UVLM_ON (0<<5) +#define AW8622X_BIT_SYSINTM_FF_AEM_MASK (~(1<<4)) +#define AW8622X_BIT_SYSINTM_FF_AEM_OFF (1<<4) +#define AW8622X_BIT_SYSINTM_FF_AEM_ON (0<<4) +#define AW8622X_BIT_SYSINTM_FF_AFM_MASK (~(1<<3)) +#define AW8622X_BIT_SYSINTM_FF_AFM_OFF (1<<3) +#define AW8622X_BIT_SYSINTM_FF_AFM_ON (0<<3) +#define AW8622X_BIT_SYSINTM_OCDM_MASK (~(1<<2)) +#define AW8622X_BIT_SYSINTM_OCDM_OFF (1<<2) +#define AW8622X_BIT_SYSINTM_OCDM_ON (0<<2) +#define AW8622X_BIT_SYSINTM_OTM_MASK (~(1<<1)) +#define AW8622X_BIT_SYSINTM_OTM_OFF (1<<1) +#define AW8622X_BIT_SYSINTM_OTM_ON (0<<1) +#define AW8622X_BIT_SYSINTM_DONEM_MASK (~(1<<0)) +#define AW8622X_BIT_SYSINTM_DONEM_OFF (1<<0) +#define AW8622X_BIT_SYSINTM_DONEM_ON (0<<0) + +/* SYSST2: reg 0x04 RO */ +#define AW8622X_BIT_SYSST2_RAM_ADDR_ER (1<<7) +#define AW8622X_BIT_SYSST2_TRG_ADDR_ER (1<<6) +#define AW8622X_BIT_SYSST2_VBG_OK (1<<3) +#define AW8622X_BIT_SYSST2_LDO_OK (1<<2) +#define AW8622X_BIT_SYSST2_FF_FULL (1<<1) +#define AW8622X_BIT_SYSST2_FF_EMPTY (1<<0) + +/* SYSER: reg 0x05 RC */ +#define AW8622X_BIT_SYSER_I2S_ERR (1<<7) +#define AW8622X_BIT_SYSER_TRIG1_EVENT (1<<6) +#define AW8622X_BIT_SYSER_TRIG2_EVENT (1<<5) +#define AW8622X_BIT_SYSER_TRIG3_EVENT (1<<4) +#define AW8622X_BIT_SYSER_OV (1<<3) +#define AW8622X_BIT_SYSER_ADDR_ER (1<<2) +#define AW8622X_BIT_SYSER_FF_ER (1<<1) +#define AW8622X_BIT_SYSER_PLL_REF_ER (1<<0) + +/* PLAYCFG3: reg 0x08 RW */ +#define AW8622X_BIT_PLAYCFG3_STOP_MODE_MASK (~(1<<5)) +#define AW8622X_BIT_PLAYCFG3_STOP_MODE_NOW (1<<5) +#define AW8622X_BIT_PLAYCFG3_STOP_MODE_LATER (0<<5) +#define AW8622X_BIT_PLAYCFG3_BRK_EN_MASK (~(1<<2)) +#define AW8622X_BIT_PLAYCFG3_BRK (1<<2) +#define AW8622X_BIT_PLAYCFG3_BRK_ENABLE (1<<2) +#define AW8622X_BIT_PLAYCFG3_BRK_DISABLE (0<<2) +#define AW8622X_BIT_PLAYCFG3_PLAY_MODE_MASK (~(3<<0)) +#define AW8622X_BIT_PLAYCFG3_PLAY_MODE_STOP (3<<0) +#define AW8622X_BIT_PLAYCFG3_PLAY_MODE_CONT (2<<0) +#define AW8622X_BIT_PLAYCFG3_PLAY_MODE_RTP (1<<0) +#define AW8622X_BIT_PLAYCFG3_PLAY_MODE_RAM (0<<0) + +/* PLAYCFG4: reg 0x09 RW */ +#define AW8622X_BIT_PLAYCFG4_STOP_MASK (~(1<<1)) +#define AW8622X_BIT_PLAYCFG4_STOP_ON (1<<1) +#define AW8622X_BIT_PLAYCFG4_STOP_OFF (0<<1) +#define AW8622X_BIT_PLAYCFG4_GO_MASK (~(1<<0)) +#define AW8622X_BIT_PLAYCFG4_GO_ON (1<<0) +#define AW8622X_BIT_PLAYCFG4_GO_OFF (0<<0) + +/* WAVCFG1-8: reg 0x0A - reg 0x11 RW */ +#define AW8622X_BIT_WAVCFG_SEQWAIT_MASK (~(1<<7)) +#define AW8622X_BIT_WAVCFG_SEQWAIT_TIME (1<<7) +#define AW8622X_BIT_WAVCFG_SEQWAIT_NUMBER (0<<7) +#define AW8622X_BIT_WAVCFG_SEQ (0x7F) + +/* WAVCFG9-12: reg 0x12 - reg 0x15 RW */ +#define AW8622X_BIT_WAVLOOP_SEQ_ODD_MASK (~(0x0F<<4)) +#define AW8622X_BIT_WAVLOOP_SEQ_ODD_INIFINITELY (0x0F<<4) +#define AW8622X_BIT_WAVLOOP_SEQ_EVEN_MASK (~(0x0F<<0)) +#define AW8622X_BIT_WAVLOOP_SEQ_EVEN_INIFINITELY (0x0F<<0) +#define AW8622X_BIT_WAVLOOP_INIFINITELY (0x0F<<0) + +/* WAVCFG9: reg 0x12 RW */ +#define AW8622X_BIT_WAVCFG9_SEQ1LOOP_MASK (~(0x0F<<4)) +#define AW8622X_BIT_WAVCFG9_SEQ1LOOP_INIFINITELY (0x0F<<4) +#define AW8622X_BIT_WAVCFG9_SEQ2LOOP_MASK (~(0x0F<<0)) +#define AW8622X_BIT_WAVCFG9_SEQ2LOOP_INIFINITELY (0x0F<<0) + +/* WAVCFG10: reg 0x13 RW */ +#define AW8622X_BIT_WAVCFG10_SEQ3LOOP_MASK (~(0x0F<<4)) +#define AW8622X_BIT_WAVCFG10_SEQ3LOOP_INIFINITELY (0x0F<<4) +#define AW8622X_BIT_WAVCFG10_SEQ4LOOP_MASK (~(0x0F<<0)) +#define AW8622X_BIT_WAVCFG10_SEQ4LOOP_INIFINITELY (0x0F<<0) + +/* WAVCFG11: reg 0x14 RW */ +#define AW8622X_BIT_WAVCFG11_SEQ5LOOP_MASK (~(0x0F<<4)) +#define AW8622X_BIT_WAVCFG11_SEQ5LOOP_INIFINITELY (0x0F<<4) +#define AW8622X_BIT_WAVCFG11_SEQ6LOOP_MASK (~(0x0F<<0)) +#define AW8622X_BIT_WAVCFG11_SEQ6LOOP_INIFINITELY (0x0F<<0) + +/* WAVCFG12: reg 0x15 RW */ +#define AW8622X_BIT_WAVCFG12_SEQ7LOOP_MASK (~(0x0F<<4)) +#define AW8622X_BIT_WAVCFG12_SEQ7LOOP_INIFINITELY (0x0F<<4) +#define AW8622X_BIT_WAVCFG12_SEQ8LOOP_MASK (~(0x0F<<0)) +#define AW8622X_BIT_WAVCFG12_SEQ8LOOP_INIFINITELY (0x0F<<0) + +/***************** CONT *****************/ +/* CONTCFG1: reg 0x18 RW */ +#define AW8622X_BIT_CONTCFG1_EDGE_FRE_MASK (~(0x0F<<4)) +#define AW8622X_BIT_CONTCFG1_EN_F0_DET_MASK (~(1<<3)) +#define AW8622X_BIT_CONTCFG1_F0_DET_ENABLE (1<<3) +#define AW8622X_BIT_CONTCFG1_F0_DET_DISABLE (0<<3) +#define AW8622X_BIT_CONTCFG1_SIN_MODE_MASK (~(1<<0)) +#define AW8622X_BIT_CONTCFG1_SIN_MODE_COS (1<<0) +#define AW8622X_BIT_CONTCFG1_SIN_MODE_SINE (0<<0) + +/* CONTCFG5: reg 0x1C RW */ +#define AW8622X_BIT_CONTCFG5_BRK_GAIN_MASK (~(0x0F<<0)) + +/* CONTCFG6: reg 0x1D RW */ +#define AW8622X_BIT_CONTCFG6_TRACK_EN_MASK (~(1<<7)) +#define AW8622X_BIT_CONTCFG6_TRACK_ENABLE (1<<7) +#define AW8622X_BIT_CONTCFG6_TRACK_DISABLE (0<<7) +#define AW8622X_BIT_CONTCFG6_DRV1_LVL_MASK (~(0x7F<<0)) + +/* CONTCFG7: reg 0x1E RW */ +#define AW8622X_BIT_CONTCFG7_DRV2_LVL_MASK (~(0x7F<<0)) + +/* CONTCFG13: reg 0x24 RW */ +#define AW8622X_BIT_CONTCFG13_TSET_MASK (~(0x0F<<4)) +#define AW8622X_BIT_CONTCFG13_BEME_SET_MASK (~(0x0F<<0)) + +/***************** RTP *****************/ +/* RTPCFG1: reg 0x2D RW */ +#define AW8622X_BIT_RTPCFG1_ADDRH_MASK (~(0x0F<<0)) + +#define AW8622X_BIT_RTPCFG1_SRAM_SIZE_2K_MASK (~(1<<5)) +#define AW8622X_BIT_RTPCFG1_SRAM_SIZE_2K_EN (1<<5) +#define AW8622X_BIT_RTPCFG1_SRAM_SIZE_2K_DIS (0<<5) + +#define AW8622X_BIT_RTPCFG1_SRAM_SIZE_1K_MASK (~(1<<4)) +#define AW8622X_BIT_RTPCFG1_SRAM_SIZE_1K_EN (1<<4) +#define AW8622X_BIT_RTPCFG1_SRAM_SIZE_1K_DIS (0<<4) + +/* RTPCFG3: reg 0x2F RW */ +#define AW8622X_BIT_RTPCFG3_FIFO_AEH_MASK (~(0x0F<<4)) +#define AW8622X_BIT_RTPCFG3_FIFO_AFH_MASK (~(0x0F<<0)) +#define AW8622X_BIT_RTPCFG3_FIFO_AEH (0x0F<<4) +#define AW8622X_BIT_RTPCFG3_FIFO_AFH (0x0F<<0) + +/***************** TRIGGER *****************/ +#define AW8622X_BIT_TRG_ENABLE_MASK (~(1<<7)) +#define AW8622X_BIT_TRG_ENABLE (1<<7) +#define AW8622X_BIT_TRG_DISABLE (0<<7) +#define AW8622X_BIT_TRG_SEQ_MASK (~(0x7F<<0)) + +/* TRGCFG1: reg 0x33 RW */ +#define AW8622X_BIT_TRGCFG1_TRG1_POS_MASK (~(1<<7)) +#define AW8622X_BIT_TRGCFG1_TRG1_POS_ENABLE (1<<7) +#define AW8622X_BIT_TRGCFG1_TRG1_POS_DISABLE (0<<7) +#define AW8622X_BIT_TRGCFG1_TRG1SEQ_P_MASK (~(0x7F<<0)) + +/* TRGCFG2: reg 0x34 RW */ +#define AW8622X_BIT_TRGCFG2_TRG2_POS_MASK (~(1<<7)) +#define AW8622X_BIT_TRGCFG2_TRG2_POS_ENABLE (1<<7) +#define AW8622X_BIT_TRGCFG2_TRG2_POS_DISABLE (0<<7) +#define AW8622X_BIT_TRGCFG2_TRG2SEQ_P_MASK (~(0x7F<<0)) + +/* TRGCFG3: reg 0x35 RW */ +#define AW8622X_BIT_TRGCFG3_TRG3_POS_MASK (~(1<<7)) +#define AW8622X_BIT_TRGCFG3_TRG3_POS_ENABLE (1<<7) +#define AW8622X_BIT_TRGCFG3_TRG3_POS_DISABLE (0<<7) +#define AW8622X_BIT_TRGCFG3_TRG3SEQ_P_MASK (~(0x7F<<0)) + +/* TRGCFG4: reg 0x36 RW */ +#define AW8622X_BIT_TRGCFG4_TRG1_NEG_MASK (~(1<<7)) +#define AW8622X_BIT_TRGCFG4_TRG1_NEG_ENABLE (1<<7) +#define AW8622X_BIT_TRGCFG4_TRG1_NEG_DISABLE (0<<7) +#define AW8622X_BIT_TRGCFG4_TRG1SEQ_N_MASK (~(0x7F<<0)) + +/* TRGCFG5: reg 0x37 RW */ +#define AW8622X_BIT_TRGCFG5_TRG2_NEG_MASK (~(1<<7)) +#define AW8622X_BIT_TRGCFG5_TRG2_NEG_ENABLE (1<<7) +#define AW8622X_BIT_TRGCFG5_TRG2_NEG_DISABLE (0<<7) +#define AW8622X_BIT_TRGCFG5_TRG2SEQ_N_MASK (~(0x7F<<0)) + +/* TRGCFG6: reg 0x38 RW */ +#define AW8622X_BIT_TRGCFG6_TRG3_NEG_MASK (~(1<<7)) +#define AW8622X_BIT_TRGCFG6_TRG3_NEG_ENABLE (1<<7) +#define AW8622X_BIT_TRGCFG6_TRG3_NEG_DISABLE (0<<7) +#define AW8622X_BIT_TRGCFG6_TRG3SEQ_N_MASK (~(0x7F<<0)) + +/* TRGCFG7: reg 0x39 RW */ +#define AW8622X_BIT_TRGCFG7_TRG1_POR_LEV_BRK_MASK (~(7<<5)) +#define AW8622X_BIT_TRGCFG7_TRG2_POR_LEV_BRK_MASK (~(7<<1)) +#define AW8622X_BIT_TRGCFG7_TRG1_POLAR_MASK (~(1<<7)) +#define AW8622X_BIT_TRGCFG7_TRG1_POLAR_NEG (1<<7) +#define AW8622X_BIT_TRGCFG7_TRG1_POLAR_POS (0<<7) +#define AW8622X_BIT_TRGCFG7_TRG1_MODE_MASK (~(1<<6)) +#define AW8622X_BIT_TRGCFG7_TRG1_MODE_LEVEL (1<<6) +#define AW8622X_BIT_TRGCFG7_TRG1_MODE_EDGE (0<<6) +#define AW8622X_BIT_TRGCFG7_TRG1_AUTO_BRK_MASK (~(1<<5)) +#define AW8622X_BIT_TRGCFG7_TRG1_AUTO_BRK_ENABLE (1<<5) +#define AW8622X_BIT_TRGCFG7_TRG1_AUTO_BRK_DISABLE (0<<5) +#define AW8622X_BIT_TRGCFG7_TRG2_POLAR_MASK (~(1<<3)) +#define AW8622X_BIT_TRGCFG7_TRG2_POLAR_NEG (1<<3) +#define AW8622X_BIT_TRGCFG7_TRG2_POLAR_POS (0<<3) +#define AW8622X_BIT_TRGCFG7_TRG2_MODE_MASK (~(1<<2)) +#define AW8622X_BIT_TRGCFG7_TRG2_MODE_LEVEL (1<<2) +#define AW8622X_BIT_TRGCFG7_TRG2_MODE_EDGE (0<<2) +#define AW8622X_BIT_TRGCFG7_TRG2_AUTO_BRK_MASK (~(1<<1)) +#define AW8622X_BIT_TRGCFG7_TRG2_AUTO_BRK_ENABLE (1<<1) +#define AW8622X_BIT_TRGCFG7_TRG2_AUTO_BRK_DISABLE (0<<1) + +/* TRGCFG8: reg 0x3A RW */ +#define AW8622X_BIT_TRGCFG8_TRG3_POR_LEV_BRK_MASK (~(7<<5)) +#define AW8622X_BIT_TRGCFG8_TRG3_POLAR_MASK (~(1<<7)) +#define AW8622X_BIT_TRGCFG8_TRG3_POLAR_NEG (1<<7) +#define AW8622X_BIT_TRGCFG8_TRG3_POLAR_POS (0<<7) +#define AW8622X_BIT_TRGCFG8_TRG3_MODE_MASK (~(1<<6)) +#define AW8622X_BIT_TRGCFG8_TRG3_MODE_LEVEL (1<<6) +#define AW8622X_BIT_TRGCFG8_TRG3_MODE_EDGE (0<<6) +#define AW8622X_BIT_TRGCFG8_TRG3_AUTO_BRK_MASK (~(1<<5)) +#define AW8622X_BIT_TRGCFG8_TRG3_AUTO_BRK_ENABLE (1<<5) +#define AW8622X_BIT_TRGCFG8_TRG3_AUTO_BRK_DISABLE (0<<5) +#define AW8622X_BIT_TRGCFG8_TRG_TRIG1_MODE_MASK (~(3<<3)) +#define AW8622X_BIT_TRGCFG8_PWM_LRA (0<<3) +#define AW8622X_BIT_TRGCFG8_PWM_ERA (1<<3) +#define AW8622X_BIT_TRGCFG8_TRIG1 (2<<3) +#define AW8622X_BIT_TRGCFG8_DISABLE (3<<3) +#define AW8622X_BIT_TRGCFG8_TRG1_STOP_MASK (~(1<<2)) +#define AW8622X_BIT_TRGCFG8_TRG1_STOP (1<<2) +#define AW8622X_BIT_TRGCFG8_TRG2_STOP_MASK (~(1<<1)) +#define AW8622X_BIT_TRGCFG8_TRG2_STOP (1<<1) +#define AW8622X_BIT_TRGCFG8_TRG3_STOP_MASK (~(1<<0)) +#define AW8622X_BIT_TRGCFG8_TRG3_STOP (1<<0) + +/* GLBCFG4: reg 0x3E RW */ +#define AW8622X_BIT_GLBCFG4_GO_PRIO_MASK (~(3<<6)) +#define AW8622X_BIT_GLBCFG4_TRG3_PRIO_MASK (~(3<<4)) +#define AW8622X_BIT_GLBCFG4_TRG2_PRIO_MASK (~(3<<2)) +#define AW8622X_BIT_GLBCFG4_TRG1_PRIO_MASK (~(3<<0)) + +/* GLBRD5: reg 0x3F R0 */ +/* GLB_STATE */ +#define AW8622X_BIT_GLBRD5_STATE (15<<0) +#define AW8622X_BIT_GLBRD5_STATE_STANDBY (0<<0) +#define AW8622X_BIT_GLBRD5_STATE_WAKEUP (1<<0) +#define AW8622X_BIT_GLBRD5_STATE_STARTUP (2<<0) +#define AW8622X_BIT_GLBRD5_STATE_WAIT (3<<0) +#define AW8622X_BIT_GLBRD5_STATE_CONT_GO (6<<0) +#define AW8622X_BIT_GLBRD5_STATE_RAM_GO (7<<0) +#define AW8622X_BIT_GLBRD5_STATE_RTP_GO (8<<0) +#define AW8622X_BIT_GLBRD5_STATE_TRIG_GO (9<<0) +#define AW8622X_BIT_GLBRD5_STATE_I2S_GO (10<<0) +#define AW8622X_BIT_GLBRD5_STATE_BRAKE (11<<0) +#define AW8622X_BIT_GLBRD5_STATE_END (12<<0) +/* RAMADDRH: reg 0x40 RWS */ +#define AW8622X_BIT_RAMADDRH_MASK (~(63<<0)) + +/***************** SYSCTRL *****************/ +/* SYSCTRL1: reg 0x43 RW */ +#define AW8622X_BIT_SYSCTRL1_VBAT_MODE_MASK (~(1<<7)) +#define AW8622X_BIT_SYSCTRL1_VBAT_MODE_HW (1<<7) +#define AW8622X_BIT_SYSCTRL1_VBAT_MODE_SW (0<<7) +#define AW8622X_BIT_SYSCTRL1_PERP_MASK (~(1<<6)) +#define AW8622X_BIT_SYSCTRL1_PERP_ON (1<<6) +#define AW8622X_BIT_SYSCTRL1_PERP_OFF (0<<6) +#define AW8622X_BIT_SYSCTRL1_CLK_SEL_MASK (~(3<<4)) +#define AW8622X_BIT_SYSCTRL1_CLK_SEL_OSC (1<<4) +#define AW8622X_BIT_SYSCTRL1_CLK_SEL_AUTO (0<<4) +#define AW8622X_BIT_SYSCTRL1_RAMINIT_MASK (~(1<<3)) +#define AW8622X_BIT_SYSCTRL1_RAMINIT_ON (1<<3) +#define AW8622X_BIT_SYSCTRL1_RAMINIT_OFF (0<<3) +#define AW8622X_BIT_SYSCTRL1_EN_FIR_MASK (~(1<<2)) +#define AW8622X_BIT_SYSCTRL1_FIR_ENABLE (0<<2) +#define AW8622X_BIT_SYSCTRL1_WAKE_MODE_MASK (~(1<<1)) +#define AW8622X_BIT_SYSCTRL1_WAKE_MODE_WAKEUP (1<<1) +#define AW8622X_BIT_SYSCTRL1_WAKE_MODE_BST (0<<1) +#define AW8622X_BIT_SYSCTRL1_RTP_CLK_MASK (~(1<<0)) +#define AW8622X_BIT_SYSCTRL1_RTP_PLL (1<<0) +#define AW8622X_BIT_SYSCTRL1_RTP_OSC (0<<0) + +/* SYSCTRL2: reg 0x44 RW */ +#define AW8622X_BIT_SYSCTRL2_WAKE_MASK (~(1<<7)) +#define AW8622X_BIT_SYSCTRL2_WAKE_ON (1<<7) +#define AW8622X_BIT_SYSCTRL2_WAKE_OFF (0<<7) +#define AW8622X_BIT_SYSCTRL2_STANDBY_MASK (~(1<<6)) +#define AW8622X_BIT_SYSCTRL2_STANDBY_ON (1<<6) +#define AW8622X_BIT_SYSCTRL2_STANDBY_OFF (0<<6) +#define AW8622X_BIT_SYSCTRL2_RTP_DLY_MASK (~(3<<4)) +#define AW8622X_BIT_SYSCTRL2_INTN_PIN_MASK (~(1<<3)) +#define AW8622X_BIT_SYSCTRL2_INTN (1<<3) +#define AW8622X_BIT_SYSCTRL2_TRIG1 (0<<3) +#define AW8622X_BIT_SYSCTRL2_WCK_PIN_MASK (~(1<<2)) +#define AW8622X_BIT_SYSCTRL2_ENABLE_TRIG2 (1<<2) +#define AW8622X_BIT_SYSCTRL2_DISENABLE_TRIG2 (0<<2) +#define AW8622X_BIT_SYSCTRL2_WAVDAT_MODE_MASK (~(3<<0)) +#define AW8622X_BIT_SYSCTRL2_RATE (3<<0) +#define AW8622X_BIT_SYSCTRL2_RATE_12K (2<<0) +#define AW8622X_BIT_SYSCTRL2_RATE_24K (0<<0) +#define AW8622X_BIT_SYSCTRL2_RATE_48K (1<<0) + +/* SYSCTRL7: reg 0x49 RW */ +#define AW8622X_BIT_SYSCTRL7_GAIN_BYPASS_MASK (~(1<<6)) +#define AW8622X_BIT_SYSCTRL7_GAIN_CHANGEABLE (1<<6) +#define AW8622X_BIT_SYSCTRL7_GAIN_FIXED (0<<6) +#define AW8622X_BIT_SYSCTRL7_GAIN (0x07) + +#define AW8622X_BIT_SYSCTRL7_INT_EDGE_MODE_MASK (~(1<<5)) +#define AW8622X_BIT_SYSCTRL7_INT_EDGE_MODE_POS (0<<5) +#define AW8622X_BIT_SYSCTRL7_INT_EDGE_MODE_BOTH (1<<5) +#define AW8622X_BIT_SYSCTRL7_INT_MODE_MASK (~(1<<4)) +#define AW8622X_BIT_SYSCTRL7_INT_MODE_EDGE (1<<4) +#define AW8622X_BIT_SYSCTRL7_INT_MODE_LEVEL (0<<4) + +#define AW8622X_BIT_SYSCTRL7_INTP_MASK (~(1<<3)) +#define AW8622X_BIT_SYSCTRL7_INTP_HIGH (1<<3) +#define AW8622X_BIT_SYSCTRL7_INTP_LOW (0<<3) +#define AW8622X_BIT_SYSCTRL7_D2S_GAIN_MASK (~(7<<0)) +#define AW8622X_BIT_SYSCTRL7_D2S_GAIN_1 (0<<0) +#define AW8622X_BIT_SYSCTRL7_D2S_GAIN_2 (1<<0) +#define AW8622X_BIT_SYSCTRL7_D2S_GAIN_4 (2<<0) +#define AW8622X_BIT_SYSCTRL7_D2S_GAIN_5 (3<<0) +#define AW8622X_BIT_SYSCTRL7_D2S_GAIN_8 (4<<0) +#define AW8622X_BIT_SYSCTRL7_D2S_GAIN_10 (5<<0) +#define AW8622X_BIT_SYSCTRL7_D2S_GAIN_20 (6<<0) +#define AW8622X_BIT_SYSCTRL7_D2S_GAIN_40 (7<<0) + +/* PWMCFG1: reg 0x4C RW */ +#define AW8622X_BIT_PWMCFG1_PRC_EN_MASK (~(1<<7)) +#define AW8622X_BIT_PWMCFG1_PRC_ENABLE (1<<7) +#define AW8622X_BIT_PWMCFG1_PRC_DISABLE (0<<7) +#define AW8622X_BIT_PWMCFG1_PRCTIME_MASK (~(0x7F<<0)) + +/* PWMCFG2: reg 0x4D RW */ +#define AW8622X_BIT_PWMCFG2_REF_SEL_MASK (~(1<<5)) +#define AW8622X_BIT_PWMCFG2_REF_SEL_TRIANGLE (1<<5) +#define AW8622X_BIT_PWMCFG2_REF_SEL_SAWTOOTH (0<<5) +#define AW8622X_BIT_PWMCFG2_PD_HWM_MASK (~(1<<4)) +#define AW8622X_BIT_PWMCFG2_PD_HWM_ON (1<<4) +#define AW8622X_BIT_PWMCFG2_PWMOE_MASK (~(1<<3)) +#define AW8622X_BIT_PWMCFG2_PWMOE_ON (1<<3) +#define AW8622X_BIT_PWMCFG2_PWMFRC_MASK (~(7<<0)) + +/* PWMCFG3: reg 0x4E RW */ +#define AW8622X_BIT_PWMCFG3_PR_EN_MASK (~(1<<7)) +#define AW8622X_BIT_PWMCFG3_PR_ENABLE (1<<7) +#define AW8622X_BIT_PWMCFG3_PR_DISABLE (0<<7) +#define AW8622X_BIT_PWMCFG3_PRLVL_MASK (~(0x7F<<0)) + +/* DETCFG1: reg 0x51 RW */ +#define AW8622X_BIT_DETCFG1_FTS_GO_MASK (~(1<<7)) +#define AW8622X_BIT_DETCFG1_FTS_GO_ENABLE (1<<7) +#define AW8622X_BIT_DETCFG1_TEST_GO_MASK (~(1<<6)) +#define AW8622X_BIT_DETCFG1_TEST_GO_ENABLE (1<<6) +#define AW8622X_BIT_DETCFG1_ADO_SLOT_MODE_MASK (~(1<<5)) +#define AW8622X_BIT_DETCFG1_ADO_SLOT_ADC_32 (1<<5) +#define AW8622X_BIT_DETCFG1_ADO_SLOT_ADC_256 (0<<5) +#define AW8622X_BIT_DETCFG1_RL_OS_MASK (~(1<<4)) +#define AW8622X_BIT_DETCFG1_RL (1<<4) +#define AW8622X_BIT_DETCFG1_OS (0<<4) +#define AW8622X_BIT_DETCFG1_PRCT_MODE_MASK (~(1<<3)) +#define AW8622X_BIT_DETCFG1_PRCT_MODE_INVALID (1<<3) +#define AW8622X_BIT_DETCFG1_PRCT_MODE_VALID (0<<3) +#define AW8622X_BIT_DETCFG1_CLK_ADC_MASK (~(7<<0)) +#define AW8622X_BIT_DETCFG1_CLK_ADC_12M (0<<0) +#define AW8622X_BIT_DETCFG1_CLK_ADC_6M (1<<0) +#define AW8622X_BIT_DETCFG1_CLK_ADC_3M (2<<0) +#define AW8622X_BIT_DETCFG1_CLK_ADC_1M5 (3<<0) +#define AW8622X_BIT_DETCFG1_CLK_ADC_M75 (4<<0) +#define AW8622X_BIT_DETCFG1_CLK_ADC_M37 (5<<0) +#define AW8622X_BIT_DETCFG1_CLK_ADC_M18 (6<<0) +#define AW8622X_BIT_DETCFG1_CLK_ADC_M09 (7<<0) + +/* DETCFG2: reg 0x52 RW */ +#define AW8622X_BIT_DETCFG2_VBAT_GO_MASK (~(1<<1)) +#define AW8622X_BIT_DETCFG2_VABT_GO_ON (1<<1) +#define AW8622X_BIT_DETCFG2_DIAG_GO_MASK (~(1<<0)) +#define AW8622X_BIT_DETCFG2_DIAG_GO_ON (1<<0) + +/* DET_LO: reg 0x57 RW */ +#define AW8622X_BIT_DET_LO_TEST_MASK (~(3<<6)) +#define AW8622X_BIT_DET_LO_VBAT_MASK (~(3<<4)) +#define AW8622X_BIT_DET_LO_VBAT (3<<4) +#define AW8622X_BIT_DET_LO_OS_MASK (~(3<<2)) +#define AW8622X_BIT_DET_LO_RL_MASK (~(3<<0)) +#define AW8622X_BIT_DET_LO_RL (3<<0) + +/* TRIMCFG1: reg:0x58 RW */ +#define AW8622X_BIT_TRIMCFG1_RL_TRIM_SRC_MASK (~(1<<6)) +#define AW8622X_BIT_TRIMCFG1_RL_TRIM_SRC_REG (1<<6) +#define AW8622X_BIT_TRIMCFG1_RL_TRIM_SRC_EFUSE (0<<6) +#define AW8622X_BIT_TRIMCFG1_TRIM_RL_MASK (~(63<<0)) + +/* TRIMCFG3: reg:0x5A RW */ +#define AW8622X_BIT_TRIMCFG3_OSC_TRIM_SRC_MASK (~(1<<7)) +#define AW8622X_BIT_TRIMCFG3_OSC_TRIM_SRC_REG (1<<7) +#define AW8622X_BIT_TRIMCFG3_OSC_TRIM_SRC_EFUSE (0<<7) +#define AW8622X_BIT_TRIMCFG3_TRIM_LRA_MASK (~(63<<0)) + +/* TRIMCFG4: reg:0x5B RW */ +/* TRIM_OSC */ + +/* ANACFG8: reg:0x77 RW */ +#define AW8622X_BIT_ANACFG8_TRTF_CTRL_HDRV_MASK (~(1<<6)) +#define AW8622X_BIT_ANACFG8_TRTF_CTRL_HDRV (3<<6) + +#endif diff --git a/drivers/misc/awinic/aw862x/aw8624.c b/drivers/misc/awinic/aw862x/aw8624.c new file mode 100644 index 000000000000..11a453f3bad9 --- /dev/null +++ b/drivers/misc/awinic/aw862x/aw8624.c @@ -0,0 +1,4081 @@ +/* + * aw8624.c + * + * Copyright (c) 2021 AWINIC Technology CO., LTD + * + * Author: + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aw8624.h" +#include "haptic_nv.h" + +/****************************************************** + * + * Register Access + * + ******************************************************/ +const unsigned char aw8624_reg_list[] = { + AW8624_REG_ID, + AW8624_REG_SYSST, + AW8624_REG_SYSINT, + AW8624_REG_SYSINTM, + AW8624_REG_SYSCTRL, + AW8624_REG_GO, + AW8624_REG_WAVSEQ1, + AW8624_REG_WAVSEQ2, + AW8624_REG_WAVSEQ3, + AW8624_REG_WAVSEQ4, + AW8624_REG_WAVSEQ5, + AW8624_REG_WAVSEQ6, + AW8624_REG_WAVSEQ7, + AW8624_REG_WAVSEQ8, + AW8624_REG_WAVLOOP1, + AW8624_REG_WAVLOOP2, + AW8624_REG_WAVLOOP3, + AW8624_REG_WAVLOOP4, + AW8624_REG_MANLOOP, + AW8624_REG_TRG1_SEQP, + AW8624_REG_TRG1_SEQN, + AW8624_REG_TRG_CFG1, + AW8624_REG_TRG_CFG2, + AW8624_REG_DBGCTRL, + AW8624_REG_BASE_ADDRH, + AW8624_REG_BASE_ADDRL, + AW8624_REG_FIFO_AEH, + AW8624_REG_FIFO_AEL, + AW8624_REG_FIFO_AFH, + AW8624_REG_FIFO_AFL, + AW8624_REG_DATCTRL, + AW8624_REG_PWMPRC, + AW8624_REG_PWMDBG, + AW8624_REG_DBGSTAT, + AW8624_REG_WAVECTRL, + AW8624_REG_BRAKE0_CTRL, + AW8624_REG_BRAKE1_CTRL, + AW8624_REG_BRAKE2_CTRL, + AW8624_REG_BRAKE_NUM, + AW8624_REG_ANACTRL, + AW8624_REG_SW_BRAKE, + AW8624_REG_DATDBG, + AW8624_REG_PRLVL, + AW8624_REG_PRTIME, + AW8624_REG_RAMADDRH, + AW8624_REG_RAMADDRL, + AW8624_REG_BRA_MAX_NUM, + AW8624_REG_GLB_STATE, + AW8624_REG_CONT_CTRL, + AW8624_REG_F_PRE_H, + AW8624_REG_F_PRE_L, + AW8624_REG_TD_H, + AW8624_REG_TD_L, + AW8624_REG_TSET, + AW8624_REG_THRS_BRA_END, + AW8624_REG_EF_RDATAH, + AW8624_REG_TRIM_LRA, + AW8624_REG_R_SPARE, + AW8624_REG_D2SCFG, + AW8624_REG_DETCTRL, + AW8624_REG_RLDET, + AW8624_REG_OSDET, + AW8624_REG_VBATDET, + AW8624_REG_ADCTEST, + AW8624_REG_F_LRA_F0_H, + AW8624_REG_F_LRA_F0_L, + AW8624_REG_F_LRA_CONT_H, + AW8624_REG_F_LRA_CONT_L, + AW8624_REG_WAIT_VOL_MP, + AW8624_REG_WAIT_VOL_MN, + AW8624_REG_ZC_THRSH_H, + AW8624_REG_ZC_THRSH_L, + AW8624_REG_BEMF_VTHH_H, + AW8624_REG_BEMF_VTHH_L, + AW8624_REG_BEMF_VTHL_H, + AW8624_REG_BEMF_VTHL_L, + AW8624_REG_BEMF_NUM, + AW8624_REG_DRV_TIME, + AW8624_REG_TIME_NZC, + AW8624_REG_DRV_LVL, + AW8624_REG_DRV_LVL_OV, + AW8624_REG_NUM_F0_1, + AW8624_REG_NUM_F0_2, + AW8624_REG_NUM_F0_3, +}; + +/****************************************************** + * + * value + * + ******************************************************/ +static char *aw8624_ram_name = "aw8624_haptic.bin"; +static char aw8624_rtp_name[][AW8624_RTP_NAME_MAX] = { + {"aw8624_osc_rtp_24K_5s.bin"}, + {"aw8624_rtp.bin"}, + {"aw8624_rtp_lighthouse.bin"}, + {"aw8624_rtp_silk.bin"}, +}; +struct aw8624_dts_info aw8624_dts_data; +struct pm_qos_request aw8624_pm_qos_req_vb; + +/****************************************************** + * + * function declaration + * + ******************************************************/ +static void aw8624_interrupt_clear(struct aw8624 *aw8624); +static void aw8624_haptic_upload_lra(struct aw8624 *aw8624, unsigned int flag); +static int aw8624_haptic_stop(struct aw8624 *aw8624); +static int aw8624_analyse_duration_range(struct aw8624 *aw8624); + +/****************************************************** + * + * aw8624 i2c write/read + * + ******************************************************/ +static int aw8624_i2c_read(struct aw8624 *aw8624, unsigned char reg_addr, + unsigned char *buf, unsigned int len) +{ + int ret = 0; + + struct i2c_msg msg[2] = { + [0] = { + .addr = aw8624->i2c->addr, + .flags = 0, + .len = sizeof(uint8_t), + .buf = ®_addr, + }, + [1] = { + .addr = aw8624->i2c->addr, + .flags = I2C_M_RD, + .len = len, + .buf = buf, + }, + }; + + ret = i2c_transfer(aw8624->i2c->adapter, msg, ARRAY_SIZE(msg)); + if (ret < 0) { + aw_dev_err("%s: i2c_transfer failed\n", __func__); + return ret; + } else if (ret != AW_I2C_READ_MSG_NUM) { + aw_dev_err("%s: transfer failed(size error)\n", __func__); + return -ENXIO; + } + return ret; +} + +static int aw8624_i2c_write(struct aw8624 *aw8624, unsigned char reg_addr, + unsigned char *buf, unsigned int len) +{ + unsigned char *data = NULL; + int ret = -1; + + data = kmalloc(len + 1, GFP_KERNEL); + data[0] = reg_addr; + memcpy(&data[1], buf, len); + ret = i2c_master_send(aw8624->i2c, data, len + 1); + if (ret < 0) + aw_dev_err("%s: i2c master send 0x%02x error\n", + __func__, reg_addr); + kfree(data); + return ret; +} + +static int aw8624_i2c_write_bits(struct aw8624 *aw8624, unsigned char reg_addr, + unsigned int mask, + unsigned char reg_data) +{ + unsigned char reg_val = 0; + int ret = -1; + + ret = aw8624_i2c_read(aw8624, reg_addr, ®_val, AW_I2C_BYTE_ONE); + if (ret < 0) { + aw_dev_err("%s: i2c read error, ret=%d\n", __func__, ret); + return ret; + } + reg_val &= mask; + reg_val |= reg_data; + ret = aw8624_i2c_write(aw8624, reg_addr, ®_val, AW_I2C_BYTE_ONE); + if (ret < 0) { + aw_dev_err("%s: i2c write error, ret=%d\n", __func__, ret); + return ret; + } + return 0; +} + +static int aw8624_parse_data(struct aw8624 *aw8624, const char *buf) +{ + unsigned char reg_num = aw8624->aw_i2c_package.reg_num; + unsigned char i = 0; + const char *temp_buf = NULL; + char data_buf[AWRW_CMD_UNIT] = { 0 }; + unsigned int value = 0; + int ret = 0; + int len = strlen(buf) - (AWRW_CMD_UNIT * 3); + + if (len < 0) { + aw_dev_err("%s: parse data error\n", __func__); + return -ERANGE; + } + temp_buf = &buf[AWRW_CMD_UNIT * 3]; + for (i = 0; i < reg_num; i++) { + if (((i + 1) * AWRW_CMD_UNIT) > len) { + aw_dev_err("%s: parse data error\n", __func__); + return -ERANGE; + } + memcpy(data_buf, &temp_buf[i * AWRW_CMD_UNIT], 4); + data_buf[4] = '\0'; + ret = kstrtouint(data_buf, 0, &value); + if (ret < 0) { + aw_dev_err("%s: kstrtouint error\n", __func__); + return ret; + } + aw8624->aw_i2c_package.reg_data[i] = (unsigned char)value; + } + return 0; +} + +static void aw8624_interrupt_clear(struct aw8624 *aw8624) +{ + unsigned char reg_val = 0; + + aw8624_i2c_read(aw8624, AW8624_REG_SYSINT, ®_val, AW_I2C_BYTE_ONE); + aw_dev_info("%s: reg SYSINT=0x%x\n", __func__, reg_val); +} + +/***************************************************** + * + * ram update + * + *****************************************************/ +static int aw8624_haptic_juge_RTP_is_going_on(struct aw8624 *aw8624) +{ + unsigned char rtp_state = 0; + unsigned char mode = 0; + unsigned char glb_st = 0; + + aw8624_i2c_read(aw8624, AW8624_REG_SYSCTRL, &mode, AW_I2C_BYTE_ONE); + aw8624_i2c_read(aw8624, AW8624_REG_GLB_STATE, &glb_st, AW_I2C_BYTE_ONE); + if ((mode & AW8624_BIT_SYSCTRL_PLAY_MODE_RTP) && + (glb_st == AW8624_BIT_GLBRD5_STATE_RTP_GO)) { + rtp_state = 1; + } + return rtp_state; +} + +static void aw8624_haptic_raminit(struct aw8624 *aw8624, bool flag) +{ + if (flag) { + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_RAMINIT_MASK, + AW8624_BIT_SYSCTRL_RAMINIT_EN); + } else { + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_RAMINIT_MASK, + AW8624_BIT_SYSCTRL_RAMINIT_OFF); + } +} + +#ifdef AW_CHECK_RAM_DATA +static int aw8624_check_ram_data(struct aw8624 *aw8624, + unsigned char *cont_data, + unsigned char *ram_data, unsigned int len) +{ + int i = 0; + + for (i = 0; i < len; i++) { + if (ram_data[i] != cont_data[i]) { + aw_dev_err("%s: check ramdata error, addr=0x%04x, ram_data=0x%02x, file_data=0x%02x\n", + __func__, i, ram_data[i], cont_data[i]); + return -ERANGE; + } + } + return 0; +} +#endif + +static void aw8624_set_ram_addr(struct aw8624 *aw8624) +{ + unsigned char ram_addr[2] = {0}; + unsigned int base_addr = aw8624->ram.base_addr; + + ram_addr[0] = (unsigned char)AW_SET_RAMADDR_H(base_addr); + ram_addr[1] = (unsigned char)AW_SET_RAMADDR_L(base_addr); + + aw8624_i2c_write(aw8624, AW8624_REG_RAMADDRH, ram_addr, + AW_I2C_BYTE_TWO); +} + +static int aw8624_container_update(struct aw8624 *aw8624, + struct aw8624_container *aw8624_cont) +{ + unsigned char reg_array[4] = {0}; + unsigned int shift = 0; + unsigned int base_addr = 0; + int i = 0; + int ret = 0; + int len = 0; +#ifdef AW_CHECK_RAM_DATA + unsigned char ram_data[AW_RAMDATA_RD_BUFFER_SIZE] = {0}; +#endif + mutex_lock(&aw8624->lock); + + aw8624->ram.baseaddr_shift = 2; + aw8624->ram.ram_shift = 4; + + /* RAMINIT Enable */ + aw8624_haptic_raminit(aw8624, true); + + /* set base addr */ + shift = aw8624->ram.baseaddr_shift; + aw8624->ram.base_addr = (unsigned int)((aw8624_cont->data[0+shift]<<8) | + (aw8624_cont->data[1+shift])); + base_addr = aw8624->ram.base_addr; + reg_array[0] = (unsigned char)AW_SET_BASEADDR_H(base_addr); + reg_array[1] = (unsigned char)AW_SET_BASEADDR_L(base_addr); + aw8624_i2c_write(aw8624, AW8624_REG_BASE_ADDRH, reg_array, + AW_I2C_BYTE_TWO); + aw_dev_info("%s: base_addr=0x%04x\n", __func__, + aw8624->ram.base_addr); + + /* set FIFO_AE and FIFO_AF addr */ + reg_array[0] = (unsigned char)AW8624_SET_AEADDR_H(base_addr); + reg_array[1] = (unsigned char)AW8624_SET_AEADDR_L(base_addr); + reg_array[2] = (unsigned char)AW8624_SET_AFADDR_H(base_addr); + reg_array[3] = (unsigned char)AW8624_SET_AFADDR_L(base_addr); + aw8624_i2c_write(aw8624, AW8624_REG_FIFO_AEH, reg_array, + AW_I2C_BYTE_FOUR); + /* get FIFO_AE and FIFO_AF addr */ + aw8624_i2c_read(aw8624, AW8624_REG_FIFO_AEH, reg_array, + AW_I2C_BYTE_FOUR); + aw_dev_info("%s: almost_empty_threshold = %d\n", __func__, + (unsigned short)((reg_array[0] << 8) | reg_array[1])); + aw_dev_info("%s: almost_empty_threshold = %d\n", __func__, + (unsigned short)((reg_array[2] << 8) | reg_array[3])); + + /* write ram data */ + aw8624_set_ram_addr(aw8624); + i = aw8624->ram.ram_shift; + while (i < aw8624_cont->len) { + if ((aw8624_cont->len - i) < AW_RAMDATA_WR_BUFFER_SIZE) + len = aw8624_cont->len - i; + else + len = AW_RAMDATA_WR_BUFFER_SIZE; + + aw8624_i2c_write(aw8624, AW8624_REG_RAMDATA, + &aw8624_cont->data[i], len); + i += len; + } + + +#ifdef AW_CHECK_RAM_DATA + aw8624_set_ram_addr(aw8624); + i = aw8624->ram.ram_shift; + while (i < aw8624_cont->len) { + if ((aw8624_cont->len - i) < AW_RAMDATA_RD_BUFFER_SIZE) + len = aw8624_cont->len - i; + else + len = AW_RAMDATA_RD_BUFFER_SIZE; + + aw8624_i2c_read(aw8624, AW8624_REG_RAMDATA, ram_data, len); + ret = aw8624_check_ram_data(aw8624, &aw8624_cont->data[i], + ram_data, len); + if (ret < 0) + break; + i += len; + } + if (ret) + aw_dev_err("%s: ram data check sum error\n", __func__); + else + aw_dev_info("%s: ram data check sum pass\n", __func__); + + +#endif + /* RAMINIT Disable */ + aw8624_haptic_raminit(aw8624, false); + + mutex_unlock(&aw8624->lock); + aw_dev_info("%s exit\n", __func__); + return ret; +} + +static int aw8624_haptic_get_ram_number(struct aw8624 *aw8624) +{ + unsigned char ram_data[3]; + unsigned int first_wave_addr = 0; + + aw_dev_info("%s enter!\n", __func__); + if (!aw8624->ram_init) { + aw_dev_err("%s: ram init faild, ram_num = 0!\n", __func__); + return -EPERM; + } + + mutex_lock(&aw8624->lock); + /* RAMINIT Enable */ + aw8624_haptic_raminit(aw8624, true); + aw8624_haptic_stop(aw8624); + aw8624_set_ram_addr(aw8624); + + aw8624_i2c_read(aw8624, AW8624_REG_RAMDATA, ram_data, + AW_I2C_BYTE_THREE); + first_wave_addr = (ram_data[1] << 8 | ram_data[2]); + aw8624->ram.ram_num = + (first_wave_addr - aw8624->ram.base_addr - 1) / 4; + aw_dev_info("%s: ram_version = 0x%02x\n", __func__, ram_data[0]); + aw_dev_info("%s: first waveform addr = 0x%04x\n", __func__, + first_wave_addr); + aw_dev_info("%s: ram_num = %d\n", __func__, aw8624->ram.ram_num); + /* RAMINIT Disable */ + aw8624_haptic_raminit(aw8624, false); + mutex_unlock(&aw8624->lock); + + return 0; +} + +static void aw8624_ram_check(const struct firmware *cont, void *context) +{ + struct aw8624 *aw8624 = context; + struct aw8624_container *aw8624_fw; + unsigned short check_sum = 0; + int i = 0; + int ret = 0; +#ifdef AW_READ_BIN_FLEXBALLY + static unsigned char load_cont; + int ram_timer_val = 1000; + + load_cont++; +#endif + aw_dev_dbg("%s enter\n", __func__); + if (!cont) { + aw_dev_err("%s: failed to read %s\n", __func__, + aw8624_ram_name); + release_firmware(cont); +#ifdef AW_READ_BIN_FLEXBALLY + if (load_cont <= 20) { + schedule_delayed_work(&aw8624->ram_work, + msecs_to_jiffies(ram_timer_val)); + aw_dev_info("%s:start hrtimer: load_cont=%d\n", + __func__, load_cont); + } +#endif + return; + } + + aw_dev_info("%s: loaded %s - size: %zu\n", __func__, aw8624_ram_name, + cont ? cont->size : 0); + + /* check sum */ + for (i = 2; i < cont->size; i++) + check_sum += cont->data[i]; + + if (check_sum == (unsigned short)((cont->data[0]<<8)|(cont->data[1]))) { + aw_dev_info("%s: check sum pass : 0x%04x\n", + __func__, check_sum); + aw8624->ram.check_sum = check_sum; + } else { + aw_dev_err("%s: check sum err: check_sum=0x%04x\n", + __func__, check_sum); + return; + } + + /* aw8624 ram update */ + aw8624_fw = kzalloc(cont->size+sizeof(int), GFP_KERNEL); + if (!aw8624_fw) { + release_firmware(cont); + aw_dev_err("%s: Error allocating memory\n", __func__); + return; + } + aw8624_fw->len = cont->size; + memcpy(aw8624_fw->data, cont->data, cont->size); + release_firmware(cont); + + ret = aw8624_container_update(aw8624, aw8624_fw); + if (ret) { + kfree(aw8624_fw); + aw8624->ram.len = 0; + aw_dev_err("%s: ram firmware update failed!\n", __func__); + } else { + aw8624->ram_init = 1; + aw8624->ram.len = aw8624_fw->len; + kfree(aw8624_fw); + aw_dev_info("%s: ram firmware update complete\n", __func__); + } + aw8624_haptic_get_ram_number(aw8624); + +} + +static int aw8624_ram_update(struct aw8624 *aw8624) +{ + aw8624->ram_init = 0; + aw8624->rtp_init = 0; + return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + aw8624_ram_name, aw8624->dev, GFP_KERNEL, + aw8624, aw8624_ram_check); +} + +static void aw8624_ram_work_routine(struct work_struct *work) +{ + struct aw8624 *aw8624 = + container_of(work, struct aw8624, ram_work.work); + + aw8624_ram_update(aw8624); + +} + +int aw8624_ram_init(struct aw8624 *aw8624) +{ + int ram_timer_val = 8000; + + aw_dev_dbg("%s enter\n", __func__); + INIT_DELAYED_WORK(&aw8624->ram_work, aw8624_ram_work_routine); + schedule_delayed_work(&aw8624->ram_work, + msecs_to_jiffies(ram_timer_val)); + + return 0; +} + +/***************************************************** + * + * haptic control + * + *****************************************************/ + +static int aw8624_haptic_play_init(struct aw8624 *aw8624) +{ + unsigned char reg_val = 0; + + if (aw8624->play_mode == AW8624_HAPTIC_CONT_MODE) + reg_val = (unsigned char)(aw8624_dts_data.aw8624_sw_brake[0]); + else + reg_val = (unsigned char)(aw8624_dts_data.aw8624_sw_brake[1]); + + aw8624_i2c_write(aw8624, + AW8624_REG_SW_BRAKE, ®_val, AW_I2C_BYTE_ONE); + return 0; +} + +static int aw8624_haptic_active(struct aw8624 *aw8624) +{ + aw8624_haptic_play_init(aw8624); + aw8624_i2c_write_bits(aw8624, + AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_WORK_MODE_MASK, + AW8624_BIT_SYSCTRL_ACTIVE); + aw8624_interrupt_clear(aw8624); + aw8624_i2c_write_bits(aw8624, + AW8624_REG_SYSINTM, + AW8624_BIT_SYSINTM_UVLO_MASK, + AW8624_BIT_SYSINTM_UVLO_EN); + return 0; +} + +static int aw8624_haptic_play_mode(struct aw8624 *aw8624, + unsigned char play_mode) +{ + switch (play_mode) { + case AW8624_HAPTIC_STANDBY_MODE: + aw_dev_info("%s: enter standby mode\n", __func__); + aw8624->play_mode = AW8624_HAPTIC_STANDBY_MODE; + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSINTM, + AW8624_BIT_SYSINTM_UVLO_MASK, + AW8624_BIT_SYSINTM_UVLO_OFF); + aw8624_i2c_write_bits(aw8624, + AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_WORK_MODE_MASK, + AW8624_BIT_SYSCTRL_STANDBY); + break; + case AW8624_HAPTIC_RAM_MODE: + aw_dev_info("%s: enter ram mode\n", __func__); + aw8624->play_mode = AW8624_HAPTIC_RAM_MODE; + aw8624_i2c_write_bits(aw8624, + AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_PLAY_MODE_MASK, + AW8624_BIT_SYSCTRL_PLAY_MODE_RAM); + aw8624_haptic_active(aw8624); + break; + case AW8624_HAPTIC_RAM_LOOP_MODE: + aw_dev_info("%s: enter ram loop mode\n", __func__); + aw8624->play_mode = AW8624_HAPTIC_RAM_LOOP_MODE; + aw8624_i2c_write_bits(aw8624, + AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_PLAY_MODE_MASK, + AW8624_BIT_SYSCTRL_PLAY_MODE_RAM); + aw8624_haptic_active(aw8624); + break; + case AW8624_HAPTIC_RTP_MODE: + aw_dev_info("%s: enter rtp mode\n", __func__); + aw8624->play_mode = AW8624_HAPTIC_RTP_MODE; + aw8624_i2c_write_bits(aw8624, + AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_PLAY_MODE_MASK, + AW8624_BIT_SYSCTRL_PLAY_MODE_RTP); + aw8624_haptic_active(aw8624); + break; + case AW8624_HAPTIC_TRIG_MODE: + aw_dev_info("%s: enter trig mode\n", __func__); + aw8624->play_mode = AW8624_HAPTIC_TRIG_MODE; + aw8624_i2c_write_bits(aw8624, + AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_PLAY_MODE_MASK, + AW8624_BIT_SYSCTRL_PLAY_MODE_RAM); + aw8624_haptic_active(aw8624); + break; + case AW8624_HAPTIC_CONT_MODE: + aw_dev_info("%s: enter cont mode\n", __func__); + aw8624->play_mode = AW8624_HAPTIC_CONT_MODE; + aw8624_i2c_write_bits(aw8624, + AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_PLAY_MODE_MASK, + AW8624_BIT_SYSCTRL_PLAY_MODE_CONT); + aw8624_haptic_active(aw8624); + break; + default: + aw_dev_err("%s: play mode %d err", __func__, play_mode); + break; + } + return 0; +} + +static int aw8624_haptic_play_go(struct aw8624 *aw8624, bool flag) +{ + aw_dev_dbg("%s enter, flag = %d\n", __func__, flag); + if (!flag) { + aw8624->current_t = ktime_get(); + aw8624->interval_us = ktime_to_us(ktime_sub(aw8624->current_t, + aw8624->pre_enter_t)); + if (aw8624->interval_us < 2000) { + aw_dev_info("%s:aw8624->interval_us=%d\n", + __func__, aw8624->interval_us); + mdelay(2); + } + } + if (flag == true) { + aw8624_i2c_write_bits(aw8624, AW8624_REG_GO, + AW8624_BIT_GO_MASK, AW8624_BIT_GO_ENABLE); + aw8624->pre_enter_t = ktime_get(); + } else { + aw8624_i2c_write_bits(aw8624, AW8624_REG_GO, + AW8624_BIT_GO_MASK, AW8624_BIT_GO_DISABLE); + } + return 0; +} + +static int aw8624_haptic_stop_delay(struct aw8624 *aw8624) +{ + unsigned char reg_val = 0; + unsigned int cnt = 100; + + while (cnt--) { + aw8624_i2c_read(aw8624, AW8624_REG_GLB_STATE, ®_val, + AW_I2C_BYTE_ONE); + if ((reg_val&0x0f) == AW8624_BIT_GLBRD5_STATE_STANDBY) { + aw_dev_info("%s enter standby, reg glb_state=0x%02x\n", + __func__, reg_val); + return 0; + } + mdelay(2); + + aw_dev_dbg("%s wait for standby, reg glb_state=0x%02x\n", + __func__, reg_val); + } + aw_dev_err("%s do not enter standby automatically\n", __func__); + return 0; +} + +static int aw8624_haptic_stop(struct aw8624 *aw8624) +{ + aw_dev_dbg("%s enter\n", __func__); + aw8624_haptic_play_go(aw8624, false); + aw8624_haptic_stop_delay(aw8624); + aw8624_haptic_play_mode(aw8624, AW8624_HAPTIC_STANDBY_MODE); + + return 0; +} + +static int aw8624_haptic_start(struct aw8624 *aw8624) +{ + aw8624_haptic_active(aw8624); + aw8624_haptic_play_go(aw8624, true); + + return 0; +} + +static int aw8624_haptic_set_wav_seq(struct aw8624 *aw8624, + unsigned char wav, unsigned char seq) +{ + aw8624_i2c_write(aw8624, AW8624_REG_WAVSEQ1+wav, &seq, AW_I2C_BYTE_ONE); + return 0; +} + +static int aw8624_haptic_set_wav_loop(struct aw8624 *aw8624, + unsigned char wav, unsigned char loop) +{ + unsigned char tmp = 0; + + if (wav%2) { + tmp = loop<<0; + aw8624_i2c_write_bits(aw8624, AW8624_REG_WAVLOOP1+(wav/2), + AW8624_BIT_WAVLOOP_SEQNP1_MASK, tmp); + } else { + tmp = loop<<4; + aw8624_i2c_write_bits(aw8624, AW8624_REG_WAVLOOP1+(wav/2), + AW8624_BIT_WAVLOOP_SEQN_MASK, tmp); + } + + return 0; +} + +static int +aw8624_haptic_set_repeat_wav_seq(struct aw8624 *aw8624, unsigned char seq) +{ + aw8624_haptic_set_wav_seq(aw8624, 0x00, seq); + aw8624_haptic_set_wav_seq(aw8624, 0x01, 0x00); + aw8624_haptic_set_wav_loop(aw8624, 0x00, + AW8624_BIT_WAVLOOP_INIFINITELY); + + return 0; +} + +static int aw8624_haptic_set_gain(struct aw8624 *aw8624, unsigned char gain) +{ + aw8624_i2c_write(aw8624, AW8624_REG_DATDBG, &gain, AW_I2C_BYTE_ONE); + return 0; +} + +static int aw8624_haptic_set_pwm(struct aw8624 *aw8624, unsigned char mode) +{ + switch (mode) { + case AW8624_PWM_48K: + aw8624_i2c_write_bits(aw8624, + AW8624_REG_PWMDBG, + AW8624_BIT_PWMDBG_PWM_MODE_MASK, + AW8624_BIT_PWMDBG_PWM_48K); + break; + case AW8624_PWM_24K: + aw8624_i2c_write_bits(aw8624, + AW8624_REG_PWMDBG, + AW8624_BIT_PWMDBG_PWM_MODE_MASK, + AW8624_BIT_PWMDBG_PWM_24K); + break; + case AW8624_PWM_12K: + aw8624_i2c_write_bits(aw8624, + AW8624_REG_PWMDBG, + AW8624_BIT_PWMDBG_PWM_MODE_MASK, + AW8624_BIT_PWMDBG_PWM_12K); + break; + default: + break; + } + return 0; +} + +static int aw8624_haptic_play_wav_seq(struct aw8624 *aw8624, + unsigned char flag) +{ + aw_dev_dbg("%s enter\n", __func__); + if (flag) { + aw8624_haptic_play_mode(aw8624, AW8624_HAPTIC_RAM_MODE); + aw8624_haptic_start(aw8624); + } + return 0; +} + + +static int aw8624_haptic_swicth_motorprotect_config(struct aw8624 *aw8624, + unsigned char addr, unsigned char val) +{ + if (addr == 1) { + aw8624_i2c_write_bits(aw8624, + AW8624_REG_DETCTRL, + AW8624_BIT_DETCTRL_PROTECT_MASK, + AW8624_BIT_DETCTRL_PROTECT_SHUTDOWN); + aw8624_i2c_write_bits(aw8624, + AW8624_REG_PWMPRC, + AW8624_BIT_PWMPRC_PRC_EN_MASK, + AW8624_BIT_PWMPRC_PRC_ENABLE); + aw8624_i2c_write_bits(aw8624, + AW8624_REG_PRLVL, + AW8624_BIT_PRLVL_PR_EN_MASK, + AW8624_BIT_PRLVL_PR_ENABLE); + } else if (addr == 0) { + aw8624_i2c_write_bits(aw8624, + AW8624_REG_DETCTRL, + AW8624_BIT_DETCTRL_PROTECT_MASK, + AW8624_BIT_DETCTRL_PROTECT_NO_ACTION); + aw8624_i2c_write_bits(aw8624, + AW8624_REG_PWMPRC, + AW8624_BIT_PWMPRC_PRC_EN_MASK, + AW8624_BIT_PWMPRC_PRC_DISABLE); + aw8624_i2c_write_bits(aw8624, + AW8624_REG_PRLVL, + AW8624_BIT_PRLVL_PR_EN_MASK, + AW8624_BIT_PRLVL_PR_DISABLE); + } else if (addr == 0x2d) { + aw8624_i2c_write_bits(aw8624, AW8624_REG_PWMPRC, + AW8624_BIT_PWMPRC_PRCTIME_MASK, val); + } else if (addr == 0x3e) { + aw8624_i2c_write_bits(aw8624, AW8624_REG_PRLVL, + AW8624_BIT_PRLVL_PRLVL_MASK, val); + } else if (addr == 0x3f) { + aw8624_i2c_write_bits(aw8624, AW8624_REG_PRTIME, + AW8624_BIT_PRTIME_PRTIME_MASK, val); + } else { + /*nothing to do;*/ + } + + return 0; +} + +static int aw8624_haptic_ram_config(struct aw8624 *aw8624, int duration) +{ + int ret = 0; + + if (aw8624->duration_time_flag < 0) { + aw_dev_err("%s: duration time error, array size = %d\n", + __func__, aw8624->duration_time_size); + return -ERANGE; + } + ret = aw8624_analyse_duration_range(aw8624); + if (ret < 0) + return ret; + if ((duration > 0) && (duration < + aw8624_dts_data.aw8624_duration_time[0])) { + aw8624->index = 3; /*3*/ + aw8624->activate_mode = AW8624_HAPTIC_RAM_MODE; + } else if ((duration >= aw8624_dts_data.aw8624_duration_time[0]) && + (duration < aw8624_dts_data.aw8624_duration_time[1])) { + aw8624->index = 2; /*2*/ + aw8624->activate_mode = AW8624_HAPTIC_RAM_MODE; + } else if ((duration >= aw8624_dts_data.aw8624_duration_time[1]) && + (duration < aw8624_dts_data.aw8624_duration_time[2])) { + aw8624->index = 1; /*1*/ + aw8624->activate_mode = AW8624_HAPTIC_RAM_MODE; + } else if (duration >= aw8624_dts_data.aw8624_duration_time[2]) { + aw8624->index = 4; /*4*/ + aw8624->activate_mode = AW8624_HAPTIC_RAM_LOOP_MODE; + } else { + aw_dev_err("%s: duration time error, duration= %d\n", + __func__, duration); + aw8624->index = 0; + aw8624->activate_mode = AW8624_HAPTIC_NULL; + ret = -ERANGE; + } + + return ret; +} + +static int aw8624_haptic_select_pin(struct aw8624 *aw8624, unsigned char pin) +{ + if (pin == AW8624_TRIG1) { + aw8624_i2c_write_bits(aw8624, + AW8624_REG_DBGCTRL, + AW8624_BIT_DBGCTRL_INTN_TRG_SEL_MASK, + AW8624_BIT_DBGCTRL_TRG_SEL_ENABLE); + aw8624_i2c_write_bits(aw8624, + AW8624_REG_TRG_CFG2, + AW8624_BIT_TRGCFG2_TRG1_ENABLE_MASK, + AW8624_BIT_TRGCFG2_TRG1_ENABLE); + aw_dev_info("%s: select TRIG1 pin\n", __func__); + } else if (pin == AW8624_IRQ) { + aw8624_i2c_write_bits(aw8624, + AW8624_REG_DBGCTRL, + AW8624_BIT_DBGCTRL_INTN_TRG_SEL_MASK, + AW8624_BIT_DBGCTRL_INTN_SEL_ENABLE); + aw8624_i2c_write_bits(aw8624, + AW8624_REG_TRG_CFG2, + AW8624_BIT_TRGCFG2_TRG1_ENABLE_MASK, + AW8624_BIT_TRGCFG2_TRG1_DISABLE); + aw_dev_info("%s: select INIT pin\n", __func__); + } else + aw_dev_err("%s: There is no such option\n", __func__); + return 0; +} +static int aw8624_haptic_trig1_param_init(struct aw8624 *aw8624) +{ + if (aw8624->IsUsedIRQ) { + aw8624_haptic_select_pin(aw8624, AW8624_IRQ); + return 0; + } + aw8624->trig.trig_enable = aw8624_dts_data.trig_config[0]; + aw8624->trig.trig_edge = aw8624_dts_data.trig_config[1]; + aw8624->trig.trig_polar = aw8624_dts_data.trig_config[2]; + aw8624->trig.pos_sequence = aw8624_dts_data.trig_config[3]; + aw8624->trig.neg_sequence = aw8624_dts_data.trig_config[4]; + aw_dev_info("%s: trig1 date init ok!\n", __func__); + return 0; +} +static int aw8624_haptic_tirg1_param_config(struct aw8624 *aw8624) +{ + if (aw8624->IsUsedIRQ) { + aw8624_haptic_select_pin(aw8624, AW8624_IRQ); + return 0; + } + if (aw8624->trig.trig_enable) + aw8624_haptic_select_pin(aw8624, AW8624_TRIG1); + else + aw8624_haptic_select_pin(aw8624, AW8624_IRQ); + + aw8624_i2c_write_bits(aw8624, AW8624_REG_TRG_CFG1, + AW8624_BIT_TRGCFG1_TRG1_EDGE_MASK, + aw8624->trig.trig_edge); + aw8624_i2c_write_bits(aw8624, AW8624_REG_TRG_CFG1, + AW8624_BIT_TRGCFG1_TRG1_POLAR_MASK, + aw8624->trig.trig_polar << 1); + aw8624_i2c_write(aw8624, AW8624_REG_TRG1_SEQP, + &aw8624->trig.pos_sequence, AW_I2C_BYTE_ONE); + aw8624_i2c_write(aw8624, AW8624_REG_TRG1_SEQN, + &aw8624->trig.neg_sequence, AW_I2C_BYTE_ONE); + return 0; +} +static int aw8624_haptic_vbat_mode(struct aw8624 *aw8624, unsigned char flag) +{ + if (flag == AW8624_HAPTIC_VBAT_HW_COMP_MODE) { + aw8624_i2c_write_bits(aw8624, + AW8624_REG_ADCTEST, + AW8624_BIT_DETCTRL_VBAT_MODE_MASK, + AW8624_BIT_DETCTRL_VBAT_HW_COMP); + } else { + aw8624_i2c_write_bits(aw8624, + AW8624_REG_ADCTEST, + AW8624_BIT_DETCTRL_VBAT_MODE_MASK, + AW8624_BIT_DETCTRL_VBAT_SW_COMP); + } + return 0; +} + +static int aw8624_haptic_set_f0_preset(struct aw8624 *aw8624, unsigned int f0_pre) +{ + unsigned int f0_reg = 0; + unsigned char reg_array[2] = {0}; + + f0_reg = 1000000000 / (f0_pre * aw8624_dts_data.aw8624_f0_coeff); + reg_array[0] = (unsigned char)((f0_reg >> 8) & 0xff); + reg_array[1] = (unsigned char)((f0_reg >> 0) & 0xff); + + aw8624_i2c_write(aw8624, AW8624_REG_F_PRE_H, reg_array, + AW_I2C_BYTE_TWO); + return 0; +} + +static int aw8624_haptic_read_f0(struct aw8624 *aw8624) +{ + unsigned char reg_val[2] = {0}; + unsigned int f0_reg = 0; + unsigned long f0_tmp = 0; + + aw8624_i2c_read(aw8624, AW8624_REG_F_LRA_F0_H, reg_val, + AW_I2C_BYTE_TWO); + f0_reg = (reg_val[0] << 8) | reg_val[1]; + + if (!f0_reg || !aw8624_dts_data.aw8624_f0_coeff) { + aw8624->f0 = 0; + aw_dev_info("%s : get f0 failed with the value becoming 0!\n", + __func__); + return -EPERM; + } + + f0_tmp = AW8624_F0_FORMULA(f0_reg, aw8624_dts_data.aw8624_f0_coeff); + aw8624->f0 = (unsigned int)f0_tmp; + aw_dev_info("%s f0=%d\n", __func__, aw8624->f0); + return 0; +} + +static int aw8624_haptic_read_cont_f0(struct aw8624 *aw8624) +{ + unsigned char reg_val[2] = {0}; + unsigned int f0_reg = 0; + unsigned long f0_tmp = 0; + + aw8624_i2c_read(aw8624, AW8624_REG_F_LRA_CONT_H, reg_val, + AW_I2C_BYTE_TWO); + f0_reg = (reg_val[0] << 8) | reg_val[1]; + + if (!f0_reg) { + aw8624->cont_f0 = 0; + aw_dev_info("%s: failed to reading cont f0 with 0\n", __func__); + return 0; + } + + f0_tmp = AW8624_F0_FORMULA(f0_reg, aw8624_dts_data.aw8624_f0_coeff); + aw8624->cont_f0 = (unsigned int)f0_tmp; + aw_dev_info("%s cont_f0=%d\n", __func__, aw8624->cont_f0); + return 0; +} + +static int aw8624_haptic_read_beme(struct aw8624 *aw8624) +{ + unsigned char reg_val[2] = {0}; + + aw8624_i2c_read(aw8624, AW8624_REG_WAIT_VOL_MP, reg_val, + AW_I2C_BYTE_TWO); + aw8624->max_pos_beme = reg_val[0]; + aw8624->max_neg_beme = reg_val[1]; + + aw_dev_info("%s max_pos_beme=%d\n", __func__, aw8624->max_pos_beme); + aw_dev_info("%s max_neg_beme=%d\n", __func__, aw8624->max_neg_beme); + + return 0; +} + +static int aw8624_vbat_monitor_detector(struct aw8624 *aw8624) +{ + unsigned char reg_val = 0; + unsigned int vbat = 0; + + aw8624_haptic_stop(aw8624); + /*step 1:EN_RAMINIT*/ + aw8624_haptic_raminit(aw8624, true); + + /*step 2 :launch power supply testing */ + aw8624_i2c_write_bits(aw8624, + AW8624_REG_DETCTRL, + AW8624_BIT_DETCTRL_VBAT_GO_MASK, + AW8624_BIT_DETCTRL_VABT_GO_ENABLE); + usleep_range(AW8624_VBAT_DELAY_MIN, AW8624_VBAT_DELAY_MAX); + + aw8624_i2c_read(aw8624, AW8624_REG_VBATDET, ®_val, + AW_I2C_BYTE_ONE); + vbat = AW8624_VBAT_FORMULA(reg_val); + aw_dev_info("%s get_vbat=%dmV\n", __func__, vbat); + /*step 3: return val*/ + aw8624_haptic_raminit(aw8624, false); + + return vbat; +} + +static int aw8624_lra_resistance_detector(struct aw8624 *aw8624) +{ + unsigned char reg_val = 0; + unsigned char reg_val_anactrl = 0; + unsigned char reg_val_d2scfg = 0; + unsigned int r_lra = 0; + + mutex_lock(&aw8624->lock); + aw8624_i2c_read(aw8624, AW8624_REG_ANACTRL, ®_val_anactrl, + AW_I2C_BYTE_ONE); + aw8624_i2c_read(aw8624, AW8624_REG_D2SCFG, ®_val_d2scfg, + AW_I2C_BYTE_ONE); + aw8624_haptic_stop(aw8624); + aw8624_haptic_raminit(aw8624, true); + + + aw8624_i2c_write_bits(aw8624, + AW8624_REG_ANACTRL, + AW8624_BIT_ANACTRL_EN_IO_PD1_MASK, + AW8624_BIT_ANACTRL_EN_IO_PD1_HIGH); + + aw8624_i2c_write_bits(aw8624, + AW8624_REG_D2SCFG, + AW8624_BIT_D2SCFG_CLK_ADC_MASK, + AW8624_BIT_D2SCFG_CLK_ASC_1P5MHZ); + + aw8624_i2c_write_bits(aw8624, + AW8624_REG_DETCTRL, + (AW8624_BIT_DETCTRL_RL_OS_MASK & + AW8624_BIT_DETCTRL_DIAG_GO_MASK), + (AW8624_BIT_DETCTRL_RL_DETECT | + AW8624_BIT_DETCTRL_DIAG_GO_ENABLE)); + usleep_range(AW8624_LRA_DELAY_MIN, AW8624_LRA_DELAY_MAX); + aw8624_i2c_read(aw8624, AW8624_REG_RLDET, ®_val, + AW_I2C_BYTE_ONE); + r_lra = AW8624_LRA_FORMULA(reg_val); + + aw8624_i2c_write(aw8624, AW8624_REG_D2SCFG, ®_val_d2scfg, + AW_I2C_BYTE_ONE); + aw8624_i2c_write(aw8624, AW8624_REG_ANACTRL, ®_val_anactrl, + AW_I2C_BYTE_ONE); + aw8624_haptic_raminit(aw8624, false); + mutex_unlock(&aw8624->lock); + + return r_lra; +} + +static int aw8624_haptic_ram_vbat_comp(struct aw8624 *aw8624, bool flag) +{ + int temp_gain = 0; + int vbat = 0; + + if (flag) { + if (aw8624->ram_vbat_comp == + AW8624_HAPTIC_RAM_VBAT_COMP_ENABLE) { + vbat = aw8624_vbat_monitor_detector(aw8624); + temp_gain = aw8624->gain * AW8624_VBAT_REFER / vbat; + if + (temp_gain > (128*AW8624_VBAT_REFER/AW8624_VBAT_MIN)) { + temp_gain = + 128*AW8624_VBAT_REFER/AW8624_VBAT_MIN; + aw_dev_dbg("%s gain limit=%d\n", __func__, + temp_gain); + } + aw8624_haptic_set_gain(aw8624, temp_gain); + } else { + aw8624_haptic_set_gain(aw8624, aw8624->gain); + } + } else { + aw8624_haptic_set_gain(aw8624, aw8624->gain); + } + + return 0; +} + +void aw8624_haptic_set_rtp_aei(struct aw8624 *aw8624, bool flag) +{ + if (flag) { + aw8624_i2c_write_bits(aw8624, + AW8624_REG_SYSINTM, + AW8624_BIT_SYSINTM_FF_AE_MASK, + AW8624_BIT_SYSINTM_FF_AE_EN); + } else { + aw8624_i2c_write_bits(aw8624, + AW8624_REG_SYSINTM, + AW8624_BIT_SYSINTM_FF_AE_MASK, + AW8624_BIT_SYSINTM_FF_AE_OFF); + } +} + +static unsigned char aw8624_haptic_rtp_get_fifo_afi(struct aw8624 *aw8624) +{ + unsigned char ret = 0; + unsigned char reg_val = 0; + + if (aw8624->osc_cali_flag == 1) { + aw8624_i2c_read(aw8624, AW8624_REG_SYSST, ®_val, + AW_I2C_BYTE_ONE); + reg_val &= AW8624_BIT_SYSST_FF_AFS; + ret = reg_val >> 3; + } else { + aw8624_i2c_read(aw8624, AW8624_REG_SYSINT, ®_val, + AW_I2C_BYTE_ONE); + reg_val &= AW8624_BIT_SYSINT_FF_AFI; + ret = reg_val >> 3; + } + return ret; +} + +unsigned char aw8624_haptic_rtp_get_fifo_afs(struct aw8624 *aw8624) +{ + unsigned char ret = 0; + unsigned char reg_val = 0; + + aw8624_i2c_read(aw8624, AW8624_REG_SYSST, ®_val, + AW_I2C_BYTE_ONE); + reg_val &= AW8624_BIT_SYSST_FF_AFS; + ret = reg_val >> 3; + + return ret; +} + +static int aw8624_haptic_rtp_init(struct aw8624 *aw8624) +{ + unsigned int buf_len = 0; + unsigned char glb_st = 0; + struct aw8624_container *rtp_container = aw8624->rtp_container; + + aw_dev_dbg("%s enter\n", __func__); + aw8624->rtp_cnt = 0; + mutex_lock(&aw8624->rtp_lock); + while ((!aw8624_haptic_rtp_get_fifo_afs(aw8624)) && + (aw8624->play_mode == AW8624_HAPTIC_RTP_MODE)) { +#ifdef AW_ENABLE_RTP_PRINT_LOG + aw_dev_info("%s rtp cnt = %d\n", __func__, aw8624->rtp_cnt); +#endif + if (!rtp_container) { + aw_dev_info("%s:aw8624_rtp is null break\n", __func__); + break; + } + + if (aw8624->rtp_cnt < aw8624->ram.base_addr) { + if ((rtp_container->len-aw8624->rtp_cnt) < + (aw8624->ram.base_addr)) { + buf_len = rtp_container->len - aw8624->rtp_cnt; + } else { + buf_len = (aw8624->ram.base_addr); + } + } else if ((rtp_container->len - aw8624->rtp_cnt) < + (aw8624->ram.base_addr >> 2)) { + buf_len = rtp_container->len - aw8624->rtp_cnt; + } else { + buf_len = (aw8624->ram.base_addr >> 2); + } +#ifdef AW_ENABLE_RTP_PRINT_LOG + aw_dev_info("%s buf_len = %d\n", __func__, buf_len); +#endif + aw8624_i2c_write(aw8624, AW8624_REG_RTP_DATA, + &rtp_container->data[aw8624->rtp_cnt], + buf_len); + + aw8624->rtp_cnt += buf_len; + aw8624_i2c_read(aw8624, AW8624_REG_GLB_STATE, &glb_st, + AW_I2C_BYTE_ONE); + if (aw8624->rtp_cnt == rtp_container->len || + (glb_st == AW8624_BIT_GLBRD5_STATE_STANDBY)) { + if (aw8624->rtp_cnt == rtp_container->len) + aw_dev_info("%s: rtp load completely!\n", + __func__); + else + aw_dev_err("%s rtp load failed!!\n", __func__); + aw8624->rtp_cnt = 0; + mutex_unlock(&aw8624->rtp_lock); + return 0; + } + } + + if (aw8624->play_mode == AW8624_HAPTIC_RTP_MODE) + aw8624_haptic_set_rtp_aei(aw8624, true); + + aw_dev_dbg("%s exit\n", __func__); + mutex_unlock(&aw8624->rtp_lock); + return 0; +} + +static void aw8624_rtp_work_routine(struct work_struct *work) +{ + const struct firmware *rtp_file; + int ret = -1; + unsigned char reg_val = 0; + bool rtp_work_flag = false; + unsigned int cnt = 200; + + struct aw8624 *aw8624 = container_of(work, struct aw8624, rtp_work); + + /* fw loaded */ + aw_dev_dbg("%s enter\n", __func__); + mutex_lock(&aw8624->rtp_lock); + ret = request_firmware(&rtp_file, + aw8624_rtp_name[aw8624->rtp_file_num], aw8624->dev); + if (ret < 0) { + aw_dev_err("%s: failed to read %s\n", __func__, + aw8624_rtp_name[aw8624->rtp_file_num]); + mutex_unlock(&aw8624->rtp_lock); + return; + } + aw8624->rtp_init = 0; + vfree(aw8624->rtp_container); + aw8624->rtp_container = vmalloc(rtp_file->size+sizeof(int)); + if (!aw8624->rtp_container) { + release_firmware(rtp_file); + aw_dev_err("%s: error allocating memory\n", __func__); + mutex_unlock(&aw8624->rtp_lock); + return; + } + aw8624->rtp_container->len = rtp_file->size; + aw_dev_info("%s: rtp file [%s] size = %d\n", __func__, + aw8624_rtp_name[aw8624->rtp_file_num], + aw8624->rtp_container->len); + memcpy(aw8624->rtp_container->data, rtp_file->data, rtp_file->size); + mutex_unlock(&aw8624->rtp_lock); + release_firmware(rtp_file); + mutex_lock(&aw8624->lock); + aw8624->rtp_init = 1; + if (aw8624->IsUsedIRQ) + aw8624_haptic_select_pin(aw8624, AW8624_IRQ); + aw8624_haptic_upload_lra(aw8624, AW8624_HAPTIC_RTP_CALI_LRA); + /* rtp mode config */ + aw8624_haptic_play_mode(aw8624, AW8624_HAPTIC_RTP_MODE); + + /* haptic start */ + aw8624_haptic_start(aw8624); + mutex_unlock(&aw8624->lock); + usleep_range(AW8624_STOP_DELAY_MIN, AW8624_STOP_DELAY_MAX); + while (cnt) { + aw8624_i2c_read(aw8624, AW8624_REG_GLB_STATE, ®_val, + AW_I2C_BYTE_ONE); + if (reg_val == AW8624_BIT_GLBRD5_STATE_RTP_GO) { + cnt = 0; + rtp_work_flag = true; + aw_dev_info("%s RTP_GO! glb_state=0x08\n", __func__); + } else { + cnt--; + aw_dev_dbg("%s wait for RTP_GO, glb_state=0x%02X\n", + __func__, reg_val); + } + usleep_range(AW8624_STOP_DELAY_MIN, AW8624_STOP_DELAY_MAX); + } + if (rtp_work_flag) { + aw8624_haptic_rtp_init(aw8624); + } else { + /* enter standby mode */ + aw8624_haptic_stop(aw8624); + aw_dev_err("%s failed to enter RTP_GO status!\n", + __func__); + } + +} + +/***************************************************** + * + * haptic - audio + * + *****************************************************/ +static enum hrtimer_restart +aw8624_haptic_audio_timer_func(struct hrtimer *timer) +{ + struct aw8624 *aw8624 = + container_of(timer, struct aw8624, haptic_audio.timer); + + schedule_work(&aw8624->haptic_audio.work); + hrtimer_start(&aw8624->haptic_audio.timer, + ktime_set(aw8624->haptic_audio.timer_val/1000, + (aw8624->haptic_audio.timer_val%1000)*1000000), + HRTIMER_MODE_REL); + return HRTIMER_NORESTART; +} + +static void aw8624_ctr_list_config(struct aw8624 *aw8624, + struct haptic_ctr *p_ctr, + struct haptic_ctr *p_ctr_bak, + struct haptic_audio *haptic_audio) +{ + unsigned int list_input_cnt = 0; + unsigned int list_output_cnt = 0; + unsigned int list_diff_cnt = 0; + unsigned int list_del_cnt = 0; + + list_for_each_entry_safe(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), list) { + list_input_cnt = p_ctr->cnt; + break; + } + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), list) { + list_output_cnt = p_ctr->cnt; + break; + } + if (list_input_cnt > list_output_cnt) + list_diff_cnt = list_input_cnt - list_output_cnt; + + if (list_input_cnt < list_output_cnt) + list_diff_cnt = 32 + list_input_cnt - list_output_cnt; + + if (list_diff_cnt > 2) { + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), list) { + if ((p_ctr->play == 0) && + (AW8624_HAPTIC_CMD_ENABLE == + (AW8624_HAPTIC_CMD_HAPTIC & p_ctr->cmd))) { + list_del(&p_ctr->list); + kfree(p_ctr); + list_del_cnt++; + } + if (list_del_cnt == list_diff_cnt) + break; + } + } +} + +static void aw8624_haptic_audio_work_routine(struct work_struct *work) +{ + struct aw8624 *aw8624 = + container_of(work, struct aw8624, haptic_audio.work); + struct haptic_audio *haptic_audio = NULL; + struct haptic_ctr *p_ctr = NULL; + struct haptic_ctr *p_ctr_bak = NULL; + unsigned int ctr_list_flag = 0; + + int rtp_is_going_on = 0; + + aw_dev_dbg("%s enter\n", __func__); + haptic_audio = &(aw8624->haptic_audio); + mutex_lock(&aw8624->haptic_audio.lock); + memset(&aw8624->haptic_audio.ctr, 0, sizeof(struct haptic_ctr)); + ctr_list_flag = 0; + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), list) { + ctr_list_flag = 1; + break; + } + if (ctr_list_flag == 0) + aw_dev_info("%s: ctr list empty\n", __func__); + if (ctr_list_flag == 1) + aw8624_ctr_list_config(aw8624, p_ctr, p_ctr_bak, haptic_audio); + + /* get the last data from list */ + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), list) { + aw8624->haptic_audio.ctr.cnt = p_ctr->cnt; + aw8624->haptic_audio.ctr.cmd = p_ctr->cmd; + aw8624->haptic_audio.ctr.play = p_ctr->play; + aw8624->haptic_audio.ctr.wavseq = p_ctr->wavseq; + aw8624->haptic_audio.ctr.loop = p_ctr->loop; + aw8624->haptic_audio.ctr.gain = p_ctr->gain; + list_del(&p_ctr->list); + kfree(p_ctr); + break; + } + + if (aw8624->haptic_audio.ctr.play) { + aw_dev_info("%s: cnt=%d, cmd=%d, play=%d, wavseq=%d, loop=%d, gain=%d\n", + __func__, + aw8624->haptic_audio.ctr.cnt, + aw8624->haptic_audio.ctr.cmd, + aw8624->haptic_audio.ctr.play, + aw8624->haptic_audio.ctr.wavseq, + aw8624->haptic_audio.ctr.loop, + aw8624->haptic_audio.ctr.gain); + } + + /* rtp mode jump */ + rtp_is_going_on = aw8624_haptic_juge_RTP_is_going_on(aw8624); + if (rtp_is_going_on) { + mutex_unlock(&aw8624->haptic_audio.lock); + return; + } + mutex_unlock(&aw8624->haptic_audio.lock); + + if ((AW8624_HAPTIC_CMD_HAPTIC & aw8624->haptic_audio.ctr.cmd) == + AW8624_HAPTIC_CMD_ENABLE) { + if (aw8624->haptic_audio.ctr.play == + AW8624_HAPTIC_PLAY_ENABLE) { + aw_dev_info("%s: haptic audio play start\n", __func__); + mutex_lock(&aw8624->lock); + aw8624_haptic_stop(aw8624); + + aw8624_haptic_play_mode(aw8624, AW8624_HAPTIC_RAM_MODE); + + aw8624_haptic_set_wav_seq(aw8624, 0x00, + aw8624->haptic_audio.ctr.wavseq); + + aw8624_haptic_set_wav_loop(aw8624, 0x00, + aw8624->haptic_audio.ctr.loop); + + aw8624_haptic_set_gain(aw8624, + aw8624->haptic_audio.ctr.gain); + + aw8624_haptic_start(aw8624); + mutex_unlock(&aw8624->lock); + } else if (AW8624_HAPTIC_PLAY_STOP == + aw8624->haptic_audio.ctr.play) { + mutex_lock(&aw8624->lock); + aw8624_haptic_stop(aw8624); + mutex_unlock(&aw8624->lock); + + } else if (AW8624_HAPTIC_PLAY_GAIN == + aw8624->haptic_audio.ctr.play) { + mutex_lock(&aw8624->lock); + aw8624_haptic_set_gain(aw8624, + aw8624->haptic_audio.ctr.gain); + mutex_unlock(&aw8624->lock); + } + } +} + +/***************************************************** + * + * haptic cont + * + *****************************************************/ +static int aw8624_haptic_cont(struct aw8624 *aw8624) +{ + unsigned char brake0_level = 0; + unsigned char time_nzc = 0; + unsigned char en_brake1 = 0; + unsigned char brake1_level = 0; + unsigned char en_brake2 = 0; + unsigned char brake2_level = 0; + unsigned char brake2_p_num = 0; + unsigned char brake1_p_num = 0; + unsigned char brake0_p_num = 0; + unsigned char reg_array[4] = {0}; + + aw_dev_dbg("%s enter\n", __func__); + /* work mode */ + aw8624_haptic_active(aw8624); + aw8624_haptic_play_mode(aw8624, AW8624_HAPTIC_CONT_MODE); + + /* preset f0 */ + if (aw8624->f0 <= 0) + aw8624_haptic_set_f0_preset(aw8624, aw8624_dts_data.aw8624_f0_pre); + else + aw8624_haptic_set_f0_preset(aw8624, aw8624->f0); + + /* lpf */ + aw8624_i2c_write_bits(aw8624, AW8624_REG_DATCTRL, + (AW8624_BIT_DATCTRL_FC_MASK & + AW8624_BIT_DATCTRL_LPF_ENABLE_MASK), + (AW8624_BIT_DATCTRL_FC_1000HZ | + AW8624_BIT_DATCTRL_LPF_ENABLE)); + + /* brake */ + en_brake1 = aw8624_dts_data.aw8624_cont_brake[0][0]; + en_brake2 = aw8624_dts_data.aw8624_cont_brake[0][1]; + brake0_level = aw8624_dts_data.aw8624_cont_brake[0][2]; + brake1_level = aw8624_dts_data.aw8624_cont_brake[0][3]; + brake2_level = aw8624_dts_data.aw8624_cont_brake[0][4]; + brake0_p_num = aw8624_dts_data.aw8624_cont_brake[0][5]; + brake1_p_num = aw8624_dts_data.aw8624_cont_brake[0][6]; + brake2_p_num = aw8624_dts_data.aw8624_cont_brake[0][7]; + + reg_array[0] = brake0_level << 0; + reg_array[1] = (en_brake1 << 7)|(brake1_level << 0); + reg_array[2] = (en_brake2 << 7)|(brake2_level << 0); + reg_array[3] = (brake2_p_num << 6) | (brake1_p_num << 3) | + (brake0_p_num << 0); + aw8624_i2c_write(aw8624, AW8624_REG_BRAKE0_CTRL, reg_array, + AW_I2C_BYTE_FOUR); + + /* cont config */ + reg_array[0] = AW8624_BIT_CONT_CTRL_ZC_DETEC_ENABLE | + AW8624_BIT_CONT_CTRL_WAIT_1PERIOD | + AW8624_BIT_CONT_CTRL_BY_GO_SIGNAL | + AW8624_BIT_CONT_CTRL_CLOSE_PLAYBACK | + AW8624_BIT_CONT_CTRL_F0_DETECT_DISABLE | + AW8624_BIT_CONT_CTRL_O2C_DISABLE; + aw8624_i2c_write(aw8624, AW8624_REG_CONT_CTRL, reg_array, + AW_I2C_BYTE_ONE); + /* TD time */ + reg_array[0] = (unsigned char)(aw8624->cont_td>>8); + reg_array[1] = (unsigned char)(aw8624->cont_td>>0); + aw8624_i2c_write(aw8624, AW8624_REG_TD_H, reg_array, AW_I2C_BYTE_TWO); + + + aw8624_i2c_write_bits(aw8624, AW8624_REG_BEMF_NUM, + AW8624_BIT_BEMF_NUM_BRK_MASK, + aw8624->cont_num_brk); + time_nzc = AW8624_BIT_TIME_NZC_DEF_VAL; + aw8624_i2c_write(aw8624, AW8624_REG_TIME_NZC, &time_nzc, + AW_I2C_BYTE_ONE); + + /* f0 driver level */ + reg_array[0] = aw8624->cont_drv_lvl; + reg_array[1] = aw8624->cont_drv_lvl_ov; + aw8624_i2c_write(aw8624, AW8624_REG_DRV_LVL, reg_array, + AW_I2C_BYTE_TWO); + /* cont play go */ + aw8624_haptic_play_go(aw8624, true); + + return 0; +} + +/***************************************************** + * + * haptic f0 cali + * + *****************************************************/ +static void aw8624_haptic_upload_lra(struct aw8624 *aw8624, unsigned int flag) +{ + unsigned char reg_val = 0x00; + + switch (flag) { + case AW8624_HAPTIC_ZERO: + aw_dev_info("%s write zero to trim_lra!\n", __func__); + reg_val = 0x00; + break; + case AW8624_HAPTIC_F0_CALI_LRA: + aw_dev_info("%s f0_cali_lra=%d\n", __func__, + aw8624->f0_calib_data); + reg_val = (unsigned char)aw8624->f0_calib_data; + break; + case AW8624_HAPTIC_RTP_CALI_LRA: + aw_dev_info("%s rtp_cali_lra=%d\n", __func__, + aw8624->lra_calib_data); + reg_val = (unsigned char)aw8624->lra_calib_data; + break; + default: + break; + } + aw8624_i2c_write(aw8624, AW8624_REG_TRIM_LRA, ®_val, + AW_I2C_BYTE_ONE); +} + +static int aw8624_haptic_get_f0(struct aw8624 *aw8624) +{ + int ret = 0; + unsigned char reg_val = 0; + unsigned char reg_array[3] = {0}; + unsigned char f0_pre_num = 0; + unsigned char f0_wait_num = 0; + unsigned char f0_repeat_num = 0; + unsigned char f0_trace_num = 0; + unsigned int t_f0_ms = 0; + unsigned int t_f0_trace_ms = 0; + unsigned char i = 0; + unsigned int f0_cali_cnt = 50; + + + aw_dev_dbg("%s enter\n", __func__); + + /* f0 calibrate work mode */ + aw8624_haptic_stop(aw8624); + aw8624_haptic_play_mode(aw8624, AW8624_HAPTIC_CONT_MODE); + + + aw8624_i2c_write_bits(aw8624, + AW8624_REG_CONT_CTRL, + (AW8624_BIT_CONT_CTRL_EN_CLOSE_MASK & + AW8624_BIT_CONT_CTRL_F0_DETECT_MASK), + (AW8624_BIT_CONT_CTRL_OPEN_PLAYBACK | + AW8624_BIT_CONT_CTRL_F0_DETECT_ENABLE)); + + /* LPF */ + aw8624_i2c_write_bits(aw8624, + AW8624_REG_DATCTRL, + (AW8624_BIT_DATCTRL_FC_MASK & + AW8624_BIT_DATCTRL_LPF_ENABLE_MASK), + (AW8624_BIT_DATCTRL_FC_1000HZ | + AW8624_BIT_DATCTRL_LPF_ENABLE)); + + /* preset f0 */ + aw8624_haptic_set_f0_preset(aw8624, aw8624->f0_pre); + /* f0 driver level */ + aw8624_i2c_write(aw8624, AW8624_REG_DRV_LVL, &aw8624->cont_drv_lvl, + AW_I2C_BYTE_ONE); + /* f0 trace parameter */ + if (!aw8624->f0_pre) { + aw_dev_info("%s:fail to get t_f0_ms\n", __func__); + return 0; + } + + f0_pre_num = aw8624_dts_data.aw8624_f0_trace_parameter[0]; + f0_wait_num = aw8624_dts_data.aw8624_f0_trace_parameter[1]; + f0_repeat_num = aw8624_dts_data.aw8624_f0_trace_parameter[2]; + f0_trace_num = aw8624_dts_data.aw8624_f0_trace_parameter[3]; + reg_array[0] = (f0_pre_num << 4)|(f0_wait_num << 0); + reg_array[1] = f0_repeat_num << 0; + reg_array[2] = f0_trace_num << 0; + + aw8624_i2c_write(aw8624, AW8624_REG_NUM_F0_1, reg_array, + AW_I2C_BYTE_THREE); + + /* clear aw8624 interrupt */ + ret = aw8624_i2c_read(aw8624, AW8624_REG_SYSINT, ®_val, + AW_I2C_BYTE_ONE); + + /* play go and start f0 calibration */ + aw8624_haptic_play_go(aw8624, true); + + /* f0 trace time */ + t_f0_ms = 1000*10 / aw8624->f0_pre; + t_f0_trace_ms = + t_f0_ms * (f0_pre_num + f0_wait_num + + (f0_trace_num + f0_wait_num) * (f0_repeat_num - 1)); + aw_dev_info("%s: t_f0_trace_ms = %dms\n", __func__, t_f0_trace_ms); + usleep_range(t_f0_trace_ms * 1000, t_f0_trace_ms * 1000 + 500); + + for (i = 0; i < f0_cali_cnt; i++) { + ret = aw8624_i2c_read(aw8624, AW8624_REG_GLB_STATE, ®_val, + AW_I2C_BYTE_ONE); + /* f0 calibrate done */ + if (reg_val == AW8624_BIT_GLBRD5_STATE_STANDBY) { + aw8624_haptic_read_f0(aw8624); + aw8624_haptic_read_beme(aw8624); + break; + } + usleep_range(AW8624_F0_DELAY_MIN, AW8624_F0_DELAY_MAX); + aw_dev_info("%s f0 cali sleep 10ms,glb_state=0x%x\n", + __func__, reg_val); + } + + if (i == f0_cali_cnt) + ret = -ERANGE; + else + ret = 0; + + aw8624_i2c_write_bits(aw8624, AW8624_REG_CONT_CTRL, + (AW8624_BIT_CONT_CTRL_EN_CLOSE_MASK & + AW8624_BIT_CONT_CTRL_F0_DETECT_MASK), + (AW8624_BIT_CONT_CTRL_CLOSE_PLAYBACK | + AW8624_BIT_CONT_CTRL_F0_DETECT_DISABLE)); + + return ret; +} + +#ifdef AW8624_MUL_GET_F0 +static int aw8624_multiple_get_f0(struct aw8624 *aw8624) +{ + int f0_max = aw8624_dts_data.aw8624_f0_pre + AW8624_MUL_GET_F0_RANGE; + int f0_min = aw8624_dts_data.aw8624_f0_pre - AW8624_MUL_GET_F0_RANGE; + int i = 0; + int ret = 0; + + aw8624->f0_pre = aw8624_dts_data.aw8624_f0_pre; + for (i = 0; i < AW8624_MUL_GET_F0_NUM; i++) { + aw_dev_info("%s aw8624->f0_pre=%d", __func__, aw8624->f0_pre); + ret = aw8624_haptic_get_f0(aw8624); + if (ret) + return ret; + if (aw8624->f0 >= f0_max || aw8624->f0 <= f0_min) + break; + aw8624->f0_pre = aw8624->f0; + usleep_range(4000, 4500); + } + return 0; +} +#endif + +static int aw8624_haptic_f0_calibration(struct aw8624 *aw8624) +{ + int ret = 0; + unsigned char reg_val = 0; + unsigned int f0_limit = 0; + char f0_cali_lra = 0; + int f0_cali_step = 0; +#ifdef AW8624_MUL_GET_F0 + ret = aw8624_multiple_get_f0(aw8624); +#else + ret = aw8624_haptic_get_f0(aw8624); +#endif + + if (ret) { + aw_dev_err("%s get f0 error, user defafult f0\n", __func__); + } else { + /* max and min limit */ + f0_limit = aw8624->f0; + if (aw8624->f0*100 < aw8624_dts_data.aw8624_f0_pre * + (100-aw8624_dts_data.aw8624_f0_cali_percen)) { + f0_limit = aw8624_dts_data.aw8624_f0_pre; + } + if (aw8624->f0*100 > aw8624_dts_data.aw8624_f0_pre * + (100+aw8624_dts_data.aw8624_f0_cali_percen)) { + f0_limit = aw8624_dts_data.aw8624_f0_pre; + } + /* calculate cali step */ + f0_cali_step = 100000*((int)f0_limit-aw8624_dts_data.aw8624_f0_pre)/((int)f0_limit*25); + + if (f0_cali_step >= 0) { /*f0_cali_step >= 0*/ + if (f0_cali_step % 10 >= 5) { + f0_cali_step = f0_cali_step/10 + 1 + + (aw8624->chipid_flag == 1 ? 32 : 16); + } else { + f0_cali_step = f0_cali_step/10 + + (aw8624->chipid_flag == 1 ? 32 : 16); + } + } else { /*f0_cali_step < 0*/ + if (f0_cali_step % 10 <= -5) { + f0_cali_step = + (aw8624->chipid_flag == 1 ? 32 : 16) + + (f0_cali_step/10 - 1); + } else { + f0_cali_step = + (aw8624->chipid_flag == 1 ? 32 : 16) + + f0_cali_step/10; + } + } + + if (aw8624->chipid_flag == 1) { + if (f0_cali_step > 31) + f0_cali_lra = (char)f0_cali_step - 32; + else + f0_cali_lra = (char)f0_cali_step + 32; + } else { + if (f0_cali_step < 16 || + (f0_cali_step > 31 && f0_cali_step < 48)) { + f0_cali_lra = (char)f0_cali_step + 16; + } else { + f0_cali_lra = (char)f0_cali_step - 16; + } + } + + aw8624->f0_calib_data = (int)f0_cali_lra; + /* update cali step */ + aw8624_haptic_upload_lra(aw8624, + AW8624_HAPTIC_F0_CALI_LRA); + aw8624_i2c_read(aw8624, + AW8624_REG_TRIM_LRA, + ®_val, AW_I2C_BYTE_ONE); + aw_dev_info("%s final trim_lra=0x%02x\n", __func__, reg_val); + } + + aw8624_haptic_play_mode(aw8624, AW8624_HAPTIC_STANDBY_MODE); + aw8624_haptic_stop(aw8624); + + return ret; +} + +static int +aw8624_haptic_audio_ctr_list_insert(struct haptic_audio *haptic_audio, + struct haptic_ctr *haptic_ctr, + struct device *dev) +{ + struct haptic_ctr *p_new = NULL; + + p_new = kzalloc(sizeof(struct haptic_ctr), GFP_KERNEL); + if (p_new == NULL) + return -ERANGE; + /* update new list info */ + p_new->cnt = haptic_ctr->cnt; + p_new->cmd = haptic_ctr->cmd; + p_new->play = haptic_ctr->play; + p_new->wavseq = haptic_ctr->wavseq; + p_new->loop = haptic_ctr->loop; + p_new->gain = haptic_ctr->gain; + + INIT_LIST_HEAD(&(p_new->list)); + list_add(&(p_new->list), &(haptic_audio->ctr_list)); + return 0; +} + +static int aw8624_haptic_audio_ctr_list_clear(struct haptic_audio *haptic_audio) +{ + struct haptic_ctr *p_ctr = NULL; + struct haptic_ctr *p_ctr_bak = NULL; + + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), list) { + list_del(&p_ctr->list); + kfree(p_ctr); + } + + return 0; +} + +static int aw8624_haptic_audio_off(struct aw8624 *aw8624) +{ + aw_dev_info("%s: enter\n", __func__); + mutex_lock(&aw8624->lock); + aw8624_haptic_set_gain(aw8624, 0x80); + aw8624_haptic_stop(aw8624); + aw8624->gun_type = AW_GUN_TYPE_DEF_VAL; + aw8624->bullet_nr =AW_BULLET_NR_DEF_VAL; + aw8624_haptic_audio_ctr_list_clear(&aw8624->haptic_audio); + mutex_unlock(&aw8624->lock); + return 0; +} + +static int aw8624_haptic_audio_init(struct aw8624 *aw8624) +{ + + aw_dev_info("%s: enter\n", __func__); + aw8624_haptic_set_wav_seq(aw8624, 0x01, 0x00); + + return 0; +} + +static int aw8624_haptic_offset_calibration(struct aw8624 *aw8624) +{ + unsigned int cont = 2000; + unsigned char reg_val = 0; + unsigned char reg_val_sysctrl = 0; + + aw_dev_dbg("%s enter\n", __func__); + aw8624_i2c_read(aw8624, AW8624_REG_SYSCTRL, ®_val_sysctrl, + AW_I2C_BYTE_ONE); + aw8624_i2c_write_bits(aw8624, + AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_RAMINIT_MASK, + AW8624_BIT_SYSCTRL_RAMINIT_EN); + aw8624_i2c_write_bits(aw8624, + AW8624_REG_DETCTRL, + AW8624_BIT_DETCTRL_DIAG_GO_MASK, + AW8624_BIT_DETCTRL_DIAG_GO_ENABLE); + while (1) { + aw8624_i2c_read(aw8624, AW8624_REG_DETCTRL, ®_val, + AW_I2C_BYTE_ONE); + if ((reg_val & 0x01) == 0 || cont == 0) + break; + cont--; + } + if (cont == 0) + aw_dev_err("%s calibration offset failed!\n", + __func__); + + aw8624_i2c_write(aw8624, AW8624_REG_SYSCTRL, ®_val_sysctrl, + AW_I2C_BYTE_ONE); + return 0; + +} + +int aw8624_haptic_init(struct aw8624 *aw8624) +{ + int ret = 0; + unsigned char reg_val = 0, reg_flag = 0; + unsigned char reg_array[8] = {0}; + /* haptic audio */ + aw8624->haptic_audio.delay_val = 23; + aw8624->haptic_audio.timer_val = 23; + INIT_LIST_HEAD(&(aw8624->haptic_audio.ctr_list)); + hrtimer_init(&aw8624->haptic_audio.timer, + CLOCK_MONOTONIC, HRTIMER_MODE_REL); + aw8624->haptic_audio.timer.function = aw8624_haptic_audio_timer_func; + INIT_WORK(&aw8624->haptic_audio.work, aw8624_haptic_audio_work_routine); + aw8624->gun_type = AW_GUN_TYPE_DEF_VAL; + aw8624->bullet_nr = AW_BULLET_NR_DEF_VAL; + mutex_init(&aw8624->haptic_audio.lock); + /* haptic init */ + mutex_lock(&aw8624->lock); + ret = aw8624_i2c_read(aw8624, AW8624_REG_EF_RDATAH, ®_flag, + AW_I2C_BYTE_ONE); + if ((ret >= 0) && ((reg_flag & 0x1) == 1)) { + aw8624->chipid_flag = 1; + } else { + aw_dev_err("%s: to read register AW8624_REG_EF_RDATAH: %d\n", + __func__, ret); + } + + aw8624->activate_mode = aw8624_dts_data.aw8624_mode; + ret = aw8624_i2c_read(aw8624, AW8624_REG_WAVSEQ1, ®_val, + AW_I2C_BYTE_ONE); + aw8624->index = reg_val & 0x7F; + ret = aw8624_i2c_read(aw8624, AW8624_REG_DATDBG, ®_val, + AW_I2C_BYTE_ONE); + aw8624->gain = reg_val & 0xFF; + aw8624_i2c_read(aw8624, AW8624_REG_WAVSEQ1, reg_array, + AW8624_SEQUENCER_SIZE); + memcpy(aw8624->seq, reg_array, AW8624_SEQUENCER_SIZE); + + aw8624_haptic_play_mode(aw8624, AW8624_HAPTIC_STANDBY_MODE); + aw8624_haptic_set_pwm(aw8624, AW8624_PWM_24K); + + aw8624_haptic_swicth_motorprotect_config(aw8624, 0x0, 0x0); + /*trig config*/ + aw8624_haptic_trig1_param_init(aw8624); + aw8624_haptic_tirg1_param_config(aw8624); + aw8624_haptic_offset_calibration(aw8624); + aw8624_haptic_vbat_mode(aw8624, AW8624_HAPTIC_VBAT_HW_COMP_MODE); + mutex_unlock(&aw8624->lock); + + /* f0 calibration */ + aw8624->f0_pre = aw8624_dts_data.aw8624_f0_pre; + aw8624->cont_drv_lvl = aw8624_dts_data.aw8624_cont_drv_lvl; + aw8624->cont_drv_lvl_ov = aw8624_dts_data.aw8624_cont_drv_lvl_ov; + aw8624->cont_td = aw8624_dts_data.aw8624_cont_td; + aw8624->cont_zc_thr = aw8624_dts_data.aw8624_cont_zc_thr; + aw8624->cont_num_brk = aw8624_dts_data.aw8624_cont_num_brk; + aw8624->ram_vbat_comp = AW8624_HAPTIC_RAM_VBAT_COMP_ENABLE; + mutex_lock(&aw8624->lock); + aw8624_i2c_write_bits(aw8624, AW8624_REG_R_SPARE, + AW8624_BIT_R_SPARE_MASK, AW8624_BIT_R_SPARE_ENABLE); + /*LRA trim source select register*/ + aw8624_i2c_write_bits(aw8624, + AW8624_REG_ANACTRL, + AW8624_BIT_ANACTRL_LRA_SRC_MASK, + AW8624_BIT_ANACTRL_LRA_SRC_REG); + if (aw8624_dts_data.aw8624_lk_f0_cali) { + aw8624->f0_calib_data = aw8624_dts_data.aw8624_lk_f0_cali; + aw8624_haptic_upload_lra(aw8624, AW8624_HAPTIC_F0_CALI_LRA); + } else { + aw8624_haptic_upload_lra(aw8624, AW8624_HAPTIC_ZERO); + aw8624_haptic_f0_calibration(aw8624); + } + mutex_unlock(&aw8624->lock); + + /*brake*/ + mutex_lock(&aw8624->lock); + reg_val = (unsigned char)(aw8624_dts_data.aw8624_sw_brake[0]); + aw8624_i2c_write(aw8624, AW8624_REG_SW_BRAKE, ®_val, + AW_I2C_BYTE_ONE); + reg_val = 0x00; + aw8624_i2c_write(aw8624, AW8624_REG_THRS_BRA_END, ®_val, + AW_I2C_BYTE_ONE); + aw8624_i2c_write_bits(aw8624, + AW8624_REG_WAVECTRL, + AW8624_BIT_WAVECTRL_NUM_OV_DRIVER_MASK, + AW8624_BIT_WAVECTRL_NUM_OV_DRIVER); + /* zero cross */ + reg_array[0] = (unsigned char)(aw8624->cont_zc_thr>>8); + reg_array[1] = (unsigned char)(aw8624->cont_zc_thr>>0); + aw8624_i2c_write(aw8624, + AW8624_REG_ZC_THRSH_H, reg_array, + AW_I2C_BYTE_TWO); + reg_val = (unsigned char)aw8624_dts_data.aw8624_tset; + aw8624_i2c_write(aw8624, AW8624_REG_TSET, + ®_val, AW_I2C_BYTE_ONE); + + /* bemf */ + reg_array[0] = (unsigned char)aw8624_dts_data.aw8624_bemf_config[0]; + reg_array[1] = (unsigned char)aw8624_dts_data.aw8624_bemf_config[1]; + reg_array[2] = (unsigned char)aw8624_dts_data.aw8624_bemf_config[2]; + reg_array[3] = (unsigned char)aw8624_dts_data.aw8624_bemf_config[3]; + aw8624_i2c_write(aw8624, AW8624_REG_BEMF_VTHH_H, reg_array, + AW_I2C_BYTE_FOUR); + mutex_unlock(&aw8624->lock); + + return ret; +} + +/***************************************************** + * + * vibrator + * + *****************************************************/ +#ifdef TIMED_OUTPUT +static int aw8624_vibrator_get_time(struct timed_output_dev *vib_dev) +{ + struct aw8624 *aw8624 = container_of(vib_dev, struct aw8624, vib_dev); + + if (hrtimer_active(&aw8624->timer)) { + ktime_t r = hrtimer_get_remaining(&aw8624->timer); + + return ktime_to_ms(r); + } + + return 0; +} + +static void aw8624_vibrator_enable(struct timed_output_dev *vib_dev, int value) +{ + struct aw8624 *aw8624 = container_of(vib_dev, struct aw8624, vib_dev); + + aw_dev_dbg("%s enter\n", __func__); + if (!aw8624->ram_init) { + aw_dev_err("%s: ram init failed, not allow to play!\n", + __func__); + return; + } + mutex_lock(&aw8624->lock); + aw8624_haptic_stop(aw8624); + if (value > 0) { + aw8624_haptic_upload_lra(aw8624, AW8624_HAPTIC_F0_CALI_LRA); + aw8624_haptic_ram_vbat_comp(aw8624, false); + aw8624_haptic_play_wav_seq(aw8624, value); + } + + mutex_unlock(&aw8624->lock); +} + +#else +static void +aw8624_vibrator_enable(struct led_classdev *dev, enum led_brightness value) +{ + struct aw8624 *aw8624 = container_of(dev, struct aw8624, vib_dev); + + aw_dev_dbg("%s enter\n", __func__); + if (!aw8624->ram_init) { + aw_dev_err("%s: ram init failed, not allow to play!\n", + __func__); + return; + } + mutex_lock(&aw8624->lock); + aw8624_haptic_stop(aw8624); + if (value > 0) { + aw8624_haptic_upload_lra(aw8624, AW8624_HAPTIC_F0_CALI_LRA); + aw8624_haptic_ram_vbat_comp(aw8624, false); + aw8624_haptic_play_wav_seq(aw8624, value); + } + + mutex_unlock(&aw8624->lock); + + +} + +#endif + +static ssize_t aw8624_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + + return snprintf(buf, PAGE_SIZE, "%d\n", aw8624->state); +} + +static ssize_t aw8624_state_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return count; +} + +static ssize_t aw8624_duration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + ktime_t time_rem; + s64 time_ms = 0; + + if (hrtimer_active(&aw8624->timer)) { + time_rem = hrtimer_get_remaining(&aw8624->timer); + time_ms = ktime_to_ms(time_rem); + } + + return snprintf(buf, PAGE_SIZE, "%lld\n", time_ms); +} + +static ssize_t aw8624_duration_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + + /* setting 0 on duration is NOP for now */ + if (val <= 0) + return count; + rc = aw8624_haptic_ram_config(aw8624, val); + if (rc < 0) + return count; + aw8624->duration = val; + return count; +} + +static ssize_t aw8624_activate_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + /* For now nothing to show */ + return snprintf(buf, PAGE_SIZE, "%d\n", aw8624->state); +} + +static ssize_t aw8624_activate_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + unsigned int val = 0; + int rc = 0; + + if (!aw8624->ram_init) { + aw_dev_err("%s: ram init failed, not allow to play!\n", + __func__); + return count; + } + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + + if (val != 0 && val != 1) + return count; + + aw_dev_info("%s: value=%d\n", __func__, val); + + mutex_lock(&aw8624->lock); + hrtimer_cancel(&aw8624->timer); + + aw8624->state = val; + + /*aw8624_haptic_stop(aw8624);*/ + + mutex_unlock(&aw8624->lock); + schedule_work(&aw8624->vibrator_work); + + return count; +} + +static ssize_t aw8624_activate_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", + aw8624->activate_mode); +} + +static ssize_t aw8624_activate_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + + mutex_lock(&aw8624->lock); + aw8624->activate_mode = val; + mutex_unlock(&aw8624->lock); + return count; +} + + +static ssize_t aw8624_index_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + unsigned char reg_val = 0; + + aw8624_i2c_read(aw8624, AW8624_REG_WAVSEQ1, ®_val, + AW_I2C_BYTE_ONE); + aw8624->index = reg_val; + + return snprintf(buf, PAGE_SIZE, "%d\n", aw8624->index); +} + +static ssize_t aw8624_index_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + if (val > aw8624->ram.ram_num) { + aw_dev_err("%s: input value out of range!\n", __func__); + return count; + } + aw_dev_info("%s: value=%d\n", __func__, val); + + mutex_lock(&aw8624->lock); + aw8624->index = val; + aw8624_haptic_set_repeat_wav_seq(aw8624, aw8624->index); + mutex_unlock(&aw8624->lock); + return count; +} + +static ssize_t aw8624_gain_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw8624->gain); +} + +static ssize_t aw8624_gain_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + + aw_dev_info("%s: value=%d\n", __func__, val); + + mutex_lock(&aw8624->lock); + aw8624->gain = val; + aw8624_haptic_set_gain(aw8624, aw8624->gain); + mutex_unlock(&aw8624->lock); + return count; +} + +static ssize_t aw8624_seq_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + size_t count = 0; + unsigned char i = 0; + unsigned char reg_val[AW8624_SEQUENCER_SIZE] = {0}; + + aw8624_i2c_read(aw8624, AW8624_REG_WAVSEQ1, reg_val, + AW8624_SEQUENCER_SIZE); + + for (i = 0; i < AW8624_SEQUENCER_SIZE; i++) { + count += snprintf(buf+count, PAGE_SIZE-count, + "seq%d: 0x%02x\n", i+1, reg_val[i]); + aw8624->seq[i] = reg_val[i]; + } + return count; +} + +static ssize_t aw8624_seq_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + unsigned int databuf[2] = {0, 0}; + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + if (databuf[0] > AW8624_SEQUENCER_SIZE || + databuf[1] > aw8624->ram.ram_num) { + aw_dev_err("%s input value out of range\n", + __func__); + return count; + } + aw_dev_info("%s: seq%d=0x%x\n", __func__, + databuf[0], databuf[1]); + mutex_lock(&aw8624->lock); + aw8624->seq[databuf[0]] = (unsigned char)databuf[1]; + aw8624_haptic_set_wav_seq(aw8624, (unsigned char)databuf[0], + aw8624->seq[databuf[0]]); + mutex_unlock(&aw8624->lock); + } + return count; +} + +static ssize_t aw8624_loop_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + size_t count = 0; + unsigned char i = 0; + unsigned char reg_val[AW8624_SEQUENCER_LOOP_SIZE] = {0}; + + aw8624_i2c_read(aw8624, AW8624_REG_WAVLOOP1, reg_val, + AW8624_SEQUENCER_LOOP_SIZE); + + for (i = 0; i < AW8624_SEQUENCER_LOOP_SIZE; i++) { + aw8624->loop[i*2+0] = (reg_val[i] >> 4) & 0x0F; + aw8624->loop[i*2+1] = (reg_val[i] >> 0) & 0x0F; + + count += snprintf(buf+count, PAGE_SIZE-count, + "seq%d_loop: 0x%02x\n", i*2+1, aw8624->loop[i*2+0]); + count += snprintf(buf+count, PAGE_SIZE-count, + "seq%d_loop: 0x%02x\n", i*2+2, aw8624->loop[i*2+1]); + } + return count; +} + +static ssize_t aw8624_loop_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + unsigned int databuf[2] = {0, 0}; + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + aw_dev_info("%s: seq%d loop=0x%x\n", __func__, + databuf[0], databuf[1]); + mutex_lock(&aw8624->lock); + aw8624->loop[databuf[0]] = (unsigned char)databuf[1]; + aw8624_haptic_set_wav_loop(aw8624, (unsigned char)databuf[0], + aw8624->loop[databuf[0]]); + mutex_unlock(&aw8624->lock); + } + + return count; +} + +static ssize_t aw8624_reg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char i = 0; + unsigned char size = 0; + unsigned char cnt = 0; + unsigned char reg_array[AW_REG_MAX] = {0}; + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + aw_dev_dbg("%s: enter!\n", __func__); + for (i = 0; i <= (AW8624_REG_NUM_F0_3 + 1); i++) { + + if (i == aw8624_reg_list[cnt] && + (cnt < sizeof(aw8624_reg_list))) { + size++; + cnt++; + continue; + } else { + if (size != 0) { + aw8624_i2c_read(aw8624, + aw8624_reg_list[cnt-size], + ®_array[cnt-size], size); + size = 0; + + } + } + } + + for (i = 0; i < sizeof(aw8624_reg_list); i++) { + len += snprintf(buf + len, PAGE_SIZE - len, + "reg:0x%02X=0x%02X\n", aw8624_reg_list[i], + reg_array[i]); + } + + return len; +} + +static ssize_t aw8624_reg_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned char val = 0; + unsigned int databuf[2] = {0, 0}; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + val = (unsigned char)databuf[1]; + aw8624_i2c_write(aw8624, (unsigned char)databuf[0], &val, + AW_I2C_BYTE_ONE); + } + + return count; +} + +static ssize_t aw8624_rtp_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + len += snprintf(buf+len, PAGE_SIZE-len, "rtp_cnt = %d\n", + aw8624->rtp_cnt); + + return len; +} + +static ssize_t aw8624_rtp_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + if (!(aw8624->IsUsedIRQ)) + return count; + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + mutex_lock(&aw8624->lock); + aw8624_haptic_stop(aw8624); + aw8624_haptic_set_rtp_aei(aw8624, false); + aw8624_interrupt_clear(aw8624); + if (val < (sizeof(aw8624_rtp_name)/AW8624_RTP_NAME_MAX)) { + aw8624->rtp_file_num = val; + if (val) { + aw_dev_info("%s: aw8624_rtp_name[%d]: %s\n", __func__, + val, aw8624_rtp_name[val]); + schedule_work(&aw8624->rtp_work); + } else + aw_dev_err("%s: rtp_file_num 0x%02X over max value\n", + __func__, aw8624->rtp_file_num); + } else { + aw_dev_err("%s: rtp_file_num 0x%02x over max value\n", + __func__, aw8624->rtp_file_num); + } + mutex_unlock(&aw8624->lock); + return count; +} + + +static ssize_t aw8624_ram_update_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char reg_val_sysctrl = 0; + int cnt = 0; + int i = 0; + int size = 0; + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + unsigned char ram_data[AW_RAMDATA_RD_BUFFER_SIZE] = {0}; + + aw8624_i2c_read(aw8624, AW8624_REG_SYSCTRL, ®_val_sysctrl, + AW_I2C_BYTE_ONE); + /* RAMINIT Enable */ + aw8624_i2c_write_bits(aw8624, + AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_RAMINIT_MASK, + AW8624_BIT_SYSCTRL_RAMINIT_EN); + aw8624_set_ram_addr(aw8624); + len += snprintf(buf + len, PAGE_SIZE - len, + "haptic_ram len = %d\n", aw8624->ram.len); + while (cnt < aw8624->ram.len) { + if ((aw8624->ram.len - cnt) < AW_RAMDATA_RD_BUFFER_SIZE) + size = aw8624->ram.len - cnt; + else + size = AW_RAMDATA_RD_BUFFER_SIZE; + + aw8624_i2c_read(aw8624, AW8624_REG_RAMDATA, + ram_data, size); + for (i = 0; i < size; i++) { + len += snprintf(buf + len, PAGE_SIZE - len, + "0x%02X,", ram_data[i]); + } + cnt += size; + } + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + + /* RAMINIT Disable */ + aw8624_i2c_write(aw8624, AW8624_REG_SYSCTRL, ®_val_sysctrl, + AW_I2C_BYTE_ONE); + return len; +} + +static ssize_t aw8624_ram_update_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + + if (val) + aw8624_ram_update(aw8624); + + return count; +} + +static ssize_t aw8624_f0_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + unsigned char temp = 0; + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + mutex_lock(&aw8624->lock); + aw8624_i2c_read(aw8624, AW8624_REG_TRIM_LRA, &temp, + AW_I2C_BYTE_ONE); + aw8624_haptic_upload_lra(aw8624, AW8624_HAPTIC_ZERO); +#ifdef AW8624_MUL_GET_F0 + aw8624_multiple_get_f0(aw8624); +#else + aw8624_haptic_get_f0(aw8624); +#endif + aw8624_i2c_write(aw8624, AW8624_REG_TRIM_LRA, &temp, AW_I2C_BYTE_ONE); + mutex_unlock(&aw8624->lock); + len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw8624->f0); + aw_dev_info("len = %zd, buf=%s", len, buf); + return len; +} + +static ssize_t aw8624_f0_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + + return count; +} + + +static ssize_t aw8624_cali_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + unsigned char temp = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + mutex_lock(&aw8624->lock); + aw8624_i2c_read(aw8624, AW8624_REG_TRIM_LRA, &temp, + AW_I2C_BYTE_ONE); + aw8624_haptic_upload_lra(aw8624, AW8624_HAPTIC_F0_CALI_LRA); + aw8624_haptic_get_f0(aw8624); + aw8624_i2c_write(aw8624, AW8624_REG_TRIM_LRA, &temp, AW_I2C_BYTE_ONE); + mutex_unlock(&aw8624->lock); + + len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw8624->f0); + return len; +} + +static ssize_t +aw8624_cali_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + + if (val) { + mutex_lock(&aw8624->lock); + aw8624_haptic_upload_lra(aw8624, AW8624_HAPTIC_ZERO); + aw8624_haptic_f0_calibration(aw8624); + mutex_unlock(&aw8624->lock); + } + return count; +} + +static ssize_t +aw8624_cont_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + aw8624_haptic_read_cont_f0(aw8624); + len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw8624->cont_f0); + return len; +} + +static ssize_t +aw8624_cont_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + + aw8624_haptic_stop(aw8624); + + if (val) + aw8624_haptic_cont(aw8624); + return count; +} + + +static ssize_t +aw8624_cont_td_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + len += snprintf(buf+len, PAGE_SIZE-len, + "cont_delay_time = 0x%04x\n", + aw8624->cont_td); + return len; +} + +static ssize_t +aw8624_cont_td_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + int err, val; + unsigned char reg_array[2] = {0}; + + err = kstrtoint(buf, 16, &val); + if (err != 0) { + aw_dev_err("%s format not match!", __func__); + return count; + } + + aw8624->cont_td = val; + reg_array[0] = (unsigned char)(val >> 8); + reg_array[1] = (unsigned char)(val >> 0); + aw8624_i2c_write(aw8624, AW8624_REG_TD_H, reg_array, AW_I2C_BYTE_TWO); + + return count; +} + +static ssize_t +aw8624_cont_drv_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + len += snprintf(buf+len, PAGE_SIZE-len, + "cont drv level = 0x%02x\n", + aw8624->cont_drv_lvl); + len += snprintf(buf+len, PAGE_SIZE-len, + "cont drv level overdrive= 0x%02x\n", + aw8624->cont_drv_lvl_ov); + return len; +} + +static ssize_t +aw8624_cont_drv_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned char reg_array[2] = {0}; + unsigned int databuf[2] = {0}; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + aw8624->cont_drv_lvl = databuf[0]; + aw8624->cont_drv_lvl_ov = databuf[1]; + reg_array[0] = aw8624->cont_drv_lvl; + reg_array[1] = aw8624->cont_drv_lvl_ov; + aw8624_i2c_write(aw8624, AW8624_REG_DRV_LVL, reg_array, + AW_I2C_BYTE_TWO); + } + return count; +} + +static ssize_t +aw8624_cont_num_brk_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + len += snprintf(buf+len, PAGE_SIZE-len, + "cont_brk_num = 0x%02x\n", + aw8624->cont_num_brk); + return len; +} + +static ssize_t +aw8624_cont_num_brk_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int err, val; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + err = kstrtoint(buf, 16, &val); + if (err != 0) { + aw_dev_err("%s format not match!", __func__); + return count; + } + + aw8624->cont_num_brk = val; + if (aw8624->cont_num_brk > 7) + aw8624->cont_num_brk = 7; + + aw8624_i2c_write_bits(aw8624, AW8624_REG_BEMF_NUM, + AW8624_BIT_BEMF_NUM_BRK_MASK, aw8624->cont_num_brk); + + return count; +} + +static ssize_t +aw8624_cont_zc_thr_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, + "cont_zero_cross_thr = 0x%04x\n", + aw8624->cont_zc_thr); + return len; +} + +static ssize_t +aw8624_cont_zc_thr_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned char reg_array[2] = {0}; + int err, val; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + err = kstrtoint(buf, 0, &val); + if (err != 0) { + aw_dev_err("%s format not match!", __func__); + return count; + } + aw8624->cont_num_brk = val; + aw_dev_info("%s: val=%d\n", __func__, val); + if (val > 0) { + reg_array[0] = (unsigned char)(val >> 8); + reg_array[1] = (unsigned char)(val >> 0); + aw8624_i2c_write(aw8624, AW8624_REG_ZC_THRSH_H, reg_array, + AW_I2C_BYTE_TWO); + } + return count; +} + +static ssize_t +aw8624_vbat_monitor_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + unsigned int vbat = 0; + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + mutex_lock(&aw8624->lock); + vbat = aw8624_vbat_monitor_detector(aw8624); + mutex_unlock(&aw8624->lock); + len += snprintf(buf+len, PAGE_SIZE-len, "vbat_monitor = %d\n", vbat); + + return len; +} + +static ssize_t +aw8624_vbat_monitor_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + return count; +} + +static ssize_t +aw8624_lra_resistance_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + ssize_t len = 0; + unsigned int r_lra = 0; + + r_lra = aw8624_lra_resistance_detector(aw8624); + + len += snprintf(buf+len, PAGE_SIZE-len, "lra_resistance = %d\n", r_lra); + return len; +} + + +static ssize_t +aw8624_lra_resistance_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + return count; +} + + + +static ssize_t +aw8624_prctmode_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + unsigned char reg_val = 0; + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + + aw8624_i2c_read(aw8624, AW8624_REG_RLDET, ®_val, + AW_I2C_BYTE_ONE); + + len += snprintf(buf+len, PAGE_SIZE-len, + "prctmode = %d\n", reg_val&0x20); + return len; +} + + +static ssize_t +aw8624_prctmode_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int databuf[2] = {0, 0}; + unsigned int addr = 0; + unsigned int val = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + addr = databuf[0]; + val = databuf[1]; + mutex_lock(&aw8624->lock); + aw8624_haptic_swicth_motorprotect_config(aw8624, addr, val); + mutex_unlock(&aw8624->lock); + } + return count; +} + +static ssize_t +aw8624_ram_vbat_comp_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + len += snprintf(buf+len, PAGE_SIZE-len, + "ram_vbat_comp = %d\n", + aw8624->ram_vbat_comp); + + return len; +} + + +static ssize_t +aw8624_ram_vbat_comp_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + + mutex_lock(&aw8624->lock); + if (val) + aw8624->ram_vbat_comp = AW8624_HAPTIC_RAM_VBAT_COMP_ENABLE; + else + aw8624->ram_vbat_comp = AW8624_HAPTIC_RAM_VBAT_COMP_DISABLE; + + mutex_unlock(&aw8624->lock); + + return count; +} + +static ssize_t +aw8624_haptic_audio_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", + aw8624->haptic_audio.ctr.cnt); + return len; +} + +static int aw8624_haptic_audio_config(struct aw8624 *aw8624, + unsigned int databuf[]) +{ + struct haptic_ctr *hap_ctr = NULL; + + hap_ctr = kzalloc(sizeof(struct haptic_ctr), GFP_KERNEL); + if (hap_ctr == NULL) + return -ENOMEM; + mutex_lock(&aw8624->haptic_audio.lock); + hap_ctr->cnt = (unsigned char)databuf[0]; + hap_ctr->cmd = (unsigned char)databuf[1]; + hap_ctr->play = (unsigned char)databuf[2]; + hap_ctr->wavseq = (unsigned char)databuf[3]; + hap_ctr->loop = (unsigned char)databuf[4]; + hap_ctr->gain = (unsigned char)databuf[5]; + aw8624_haptic_audio_ctr_list_insert(&aw8624->haptic_audio, hap_ctr, + aw8624->dev); + if (hap_ctr->cmd == AW8624_HAPTIC_CMD_STOP) { + aw_dev_info("%s: haptic_audio stop\n", __func__); + if (hrtimer_active(&aw8624->haptic_audio.timer)) { + aw_dev_info("%s:cancel haptic_audio_timer\n", __func__); + hrtimer_cancel(&aw8624->haptic_audio.timer); + aw8624->haptic_audio.ctr.cnt = 0; + aw8624_haptic_audio_off(aw8624); + } + } else { + if (hrtimer_active(&aw8624->haptic_audio.timer)) { + } else { + aw_dev_info("%s:start haptic_audio_timer\n", __func__); + aw8624_haptic_audio_init(aw8624); + hrtimer_start(&aw8624->haptic_audio.timer, + ktime_set(aw8624->haptic_audio.delay_val/1000, + (aw8624->haptic_audio.delay_val%1000)*1000000), + HRTIMER_MODE_REL); + } + } + kfree(hap_ctr); + mutex_unlock(&aw8624->haptic_audio.lock); + return 0; +} +static ssize_t +aw8624_haptic_audio_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int databuf[6] = {0}; + int rtp_is_going_on = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + rtp_is_going_on = aw8624_haptic_juge_RTP_is_going_on(aw8624); + if (rtp_is_going_on) { + aw_dev_info("%s: RTP is runing, stop audio haptic\n", __func__); + return count; + } + if (!aw8624->ram_init) { + aw_dev_err("%s: ram init failed, not allow to play!\n", + __func__); + return count; + } + + if (sscanf(buf, "%d %d %d %d %d %d", + &databuf[0], &databuf[1], &databuf[2], + &databuf[3], &databuf[4], &databuf[5]) == 6) { + if (databuf[2]) { + aw_dev_dbg("%s: cnt=%d, cmd=%d, play=%d\n", __func__, + databuf[0], databuf[1], databuf[2]); + aw_dev_dbg("%s: wavseq=%d, loop=%d, gain=%d\n", + __func__, + databuf[3], databuf[4], databuf[5]); + aw8624_haptic_audio_config(aw8624, databuf); + } + + } + return count; +} + +static ssize_t +aw8624_haptic_audio_time_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + len += snprintf(buf+len, PAGE_SIZE-len, + "haptic_audio.delay_val=%dus\n", + aw8624->haptic_audio.delay_val); + len += snprintf(buf+len, PAGE_SIZE-len, + "haptic_audio.timer_val=%dus\n", + aw8624->haptic_audio.timer_val); + return len; +} + +static ssize_t +aw8624_haptic_audio_time_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int databuf[2] = {0}; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + if (sscanf(buf, "%d %d", &databuf[0], &databuf[1]) == 2) { + aw8624->haptic_audio.delay_val = databuf[0]; + aw8624->haptic_audio.timer_val = databuf[1]; + } + return count; +} + +static int aw8624_clock_OSC_trim_calibration(struct aw8624 *aw8624, + unsigned long int theory_time) +{ + unsigned int real_code = 0; + unsigned int LRA_TRIM_CODE = 0; + unsigned int DFT_LRA_TRIM_CODE = 0; + unsigned int Not_need_cali_threshold = 10;/*0.1 percent not need cali*/ + unsigned long int real_time = aw8624->microsecond; + + aw_dev_dbg("%s enter\n", __func__); + if (theory_time == real_time) { + aw_dev_info("aw_osctheory_time == real_time:%ld,", real_time); + aw_dev_info("theory_time = %ld not need to cali\n", + theory_time); + return 0; + } else if (theory_time < real_time) { + if ((real_time - theory_time) > (theory_time / 25)) { + aw_dev_info("%s: failed not to cali\n", __func__); + return DFT_LRA_TRIM_CODE; + } + + if ((real_time - theory_time) < + (Not_need_cali_threshold*theory_time/10000)) { + aw_dev_info("aw_oscmicrosecond:%ld,theory_time = %ld\n", + real_time, theory_time); + return DFT_LRA_TRIM_CODE; + } + + real_code = ((real_time - theory_time) * 4) / (theory_time / 1000); + real_code = ((real_code%10 < 5) ? 0 : 1) + real_code/10; + real_code = 32 + real_code; + } else if (theory_time > real_time) { + if ((theory_time - real_time) > (theory_time / 25)) { + aw_dev_info("failed not to cali\n"); + return DFT_LRA_TRIM_CODE; + } + if ((theory_time - real_time) < + (Not_need_cali_threshold * theory_time/10000)) { + aw_dev_info("aw_oscmicrosecond:%ld,theory_time = %ld\n", + real_time, theory_time); + return DFT_LRA_TRIM_CODE; + } + real_code = ((theory_time - real_time) * 4) / (theory_time / 1000); + real_code = ((real_code%10 < 5) ? 0 : 1) + real_code/10; + real_code = 32 - real_code; + } + if (real_code > 31) + LRA_TRIM_CODE = real_code - 32; + else + LRA_TRIM_CODE = real_code + 32; + + aw_dev_info("aw_oscmicrosecond:%ld,theory_time = %ld,real_code =0X%02X,", + real_time, theory_time, real_code); + aw_dev_info("LRA_TRIM_CODE 0X%02X\n", LRA_TRIM_CODE); + + return LRA_TRIM_CODE; +} + +static int aw8624_rtp_trim_lra_calibration(struct aw8624 *aw8624) +{ + unsigned char reg_val = 0; + unsigned int fre_val = 0; + unsigned int theory_time = 0; + unsigned int lra_rtim_code = 0; + unsigned int rate = 0; + + aw_dev_dbg("%s enter\n", __func__); + aw8624_i2c_read(aw8624, AW8624_REG_PWMDBG, ®_val, + AW_I2C_BYTE_ONE); + fre_val = (reg_val & 0x006f) >> 5; + + if (fre_val == AW8624_CLK_12K) + rate = 12000; + else if (fre_val == AW8624_CLK_24K) + rate = 24000; + else + rate = 48000; + theory_time = (aw8624->rtp_len / rate) * 1000000; + aw_dev_info("microsecond:%ld theory_time = %d\n", + aw8624->microsecond, theory_time); + + lra_rtim_code = aw8624_clock_OSC_trim_calibration(aw8624, theory_time); + if (lra_rtim_code >= 0) { + aw8624->lra_calib_data = lra_rtim_code; + reg_val = (unsigned char)lra_rtim_code; + aw8624_i2c_write(aw8624, AW8624_REG_TRIM_LRA, + ®_val, AW_I2C_BYTE_ONE); + } + return 0; +} + +static unsigned char aw8624_haptic_osc_read_int(struct aw8624 *aw8624) +{ + unsigned char reg_val = 0; + + aw8624_i2c_read(aw8624, AW8624_REG_DBGSTAT, ®_val, + AW_I2C_BYTE_ONE); + return reg_val; +} + +static int aw8624_osc_calculation_time(struct aw8624 *aw8624) +{ + unsigned char osc_int_state = 0; + unsigned int base_addr = aw8624->ram.base_addr; + unsigned int buf_len = 0; + int ret = -1; + struct aw8624_container *rtp_container = aw8624->rtp_container; + + if (!aw8624_haptic_rtp_get_fifo_afi(aw8624)) { + aw_dev_dbg("%s: haptic_rtp_get_fifo_afi, rtp_cnt= %d\n", + __func__, aw8624->rtp_cnt); + + mutex_lock(&aw8624->rtp_lock); + if ((rtp_container->len - aw8624->rtp_cnt) < (base_addr >> 2)) + buf_len = rtp_container->len - aw8624->rtp_cnt; + else + buf_len = (base_addr >> 2); + + if (aw8624->rtp_cnt != rtp_container->len) { + if (aw8624->timeval_flags == 1) { + aw8624->kstart = ktime_get(); + aw8624->timeval_flags = 0; + } + aw8624_i2c_write(aw8624, + AW8624_REG_RTP_DATA, + &rtp_container->data[aw8624->rtp_cnt], + buf_len); + aw8624->rtp_cnt += buf_len; + } + mutex_unlock(&aw8624->rtp_lock); + } + + osc_int_state = aw8624_haptic_osc_read_int(aw8624); + if (osc_int_state&AW8624_BIT_SYSINT_DONEI) { + aw8624->kend = ktime_get(); + aw_dev_info("%s vincent playback aw8624->rtp_cnt= %d\n", + __func__, aw8624->rtp_cnt); + return ret; + } + + aw8624->kend = ktime_get(); + aw8624->microsecond = ktime_to_us(ktime_sub(aw8624->kend, + aw8624->kstart)); + if (aw8624->microsecond > AW8624_OSC_CALIBRATION_T_LENGTH) { + aw_dev_info("%s:vincent time out aw8624->rtp_cnt %d,", + __func__, aw8624->rtp_cnt); + aw_dev_info("%s: osc_int_state %02x\n", __func__, osc_int_state); + return ret; + } + return 0; +} + +static int aw8624_rtp_osc_calibration(struct aw8624 *aw8624) +{ + int ret = -1; + const struct firmware *rtp_file; + + aw8624->rtp_cnt = 0; + aw8624->timeval_flags = 1; + aw8624->osc_cali_flag = 1; + + aw_dev_dbg("%s enter\n", __func__); + /* fw loaded */ + ret = request_firmware(&rtp_file, + aw8624_rtp_name[0],/*aw8624->rtp_file_num */ + aw8624->dev); + if (ret < 0) { + /*aw8624->rtp_file_num */ + aw_dev_err("%s: failed to read %s\n", __func__, + aw8624_rtp_name[0]); + return ret; + } + + /*awinic add stop,for irq interrupt during calibrate*/ + aw8624_haptic_stop(aw8624); + aw8624->rtp_init = 0; + mutex_lock(&aw8624->rtp_lock); + vfree(aw8624->rtp_container); + aw8624->rtp_container = vmalloc(rtp_file->size + sizeof(int)); + if (!aw8624->rtp_container) { + release_firmware(rtp_file); + mutex_unlock(&aw8624->rtp_lock); + aw_dev_err("%s: error allocating memory\n", __func__); + return -ENOMEM; + } + aw8624->rtp_container->len = rtp_file->size; + aw8624->rtp_len = rtp_file->size; + /*aw8624->rtp_file_num */ + aw_dev_info("%s: rtp file [%s] size = %d\n", __func__, + aw8624_rtp_name[0], aw8624->rtp_container->len); + memcpy(aw8624->rtp_container->data, rtp_file->data, rtp_file->size); + release_firmware(rtp_file); + mutex_unlock(&aw8624->rtp_lock); + + /* gain */ + aw8624_haptic_ram_vbat_comp(aw8624, false); + + /* rtp mode config */ + aw8624_haptic_play_mode(aw8624, AW8624_HAPTIC_RTP_MODE); + + aw8624_i2c_write_bits(aw8624, AW8624_REG_DBGCTRL, + AW8624_BIT_DBGCTRL_INT_MODE_MASK, + AW8624_BIT_DBGCTRL_INT_MODE_EDGE); + disable_irq(gpio_to_irq(aw8624->irq_gpio)); + /* haptic start */ + aw8624_haptic_start(aw8624); + pm_qos_add_request(&aw8624_pm_qos_req_vb, PM_QOS_CPU_DMA_LATENCY, + AW8624_PM_QOS_VALUE_VB); + while (1) { + ret = aw8624_osc_calculation_time(aw8624); + if (ret < 0) + break; + } + pm_qos_remove_request(&aw8624_pm_qos_req_vb); + enable_irq(gpio_to_irq(aw8624->irq_gpio)); + + aw8624->osc_cali_flag = 0; + aw8624->microsecond = ktime_to_us(ktime_sub(aw8624->kend, + aw8624->kstart)); + /*calibration osc*/ + aw_dev_info("%s awinic_microsecond:%ld\n", __func__, + aw8624->microsecond); + aw_dev_info("%s exit\n", __func__); + return 0; +} + +static ssize_t aw8624_osc_cali_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + len += + snprintf(buf + len, PAGE_SIZE - len, "lra_calib_data=%d\n", + aw8624->lra_calib_data); + + return len; +} + +static ssize_t aw8624_osc_cali_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + mutex_lock(&aw8624->lock); + /* osc calibration flag start,Other behaviors are forbidden */ + aw8624->osc_cali_run = 1; + if (val == 1) { + aw8624_haptic_upload_lra(aw8624, AW8624_HAPTIC_ZERO); + aw8624_rtp_osc_calibration(aw8624); + aw8624_rtp_trim_lra_calibration(aw8624); + } else if (val == 2) { + aw8624_haptic_upload_lra(aw8624, AW8624_HAPTIC_RTP_CALI_LRA); + aw8624_rtp_osc_calibration(aw8624); + } else { + aw_dev_err("%s input value out of range\n", __func__); + } + aw8624->osc_cali_run = 0; + /* osc calibration flag end,Other behaviors are permitted */ + mutex_unlock(&aw8624->lock); + + return count; +} + + + + +static enum hrtimer_restart aw8624_vibrator_timer_func(struct hrtimer *timer) +{ + struct aw8624 *aw8624 = container_of(timer, struct aw8624, timer); + + aw_dev_dbg("%s enter\n", __func__); + aw8624->state = 0; + schedule_work(&aw8624->vibrator_work); + + return HRTIMER_NORESTART; +} + + +static void aw8624_haptic_ram_play(struct aw8624 *aw8624, unsigned char type) +{ + aw_dev_info("%s index = %d\n", __func__, aw8624->index); + + mutex_lock(&aw8624->ram_lock); + if (type == AW8624_HAPTIC_RAM_LOOP_MODE) + aw8624_haptic_set_repeat_wav_seq(aw8624, aw8624->index); + + if (type == AW8624_HAPTIC_RAM_MODE) { + aw8624_haptic_set_wav_seq(aw8624, 0x00, aw8624->index); + aw8624_haptic_set_wav_seq(aw8624, 0x01, 0x00); + aw8624_haptic_set_wav_loop(aw8624, 0x00, 0x00); + } + aw8624_haptic_play_mode(aw8624, type); + aw8624_haptic_start(aw8624); + mutex_unlock(&aw8624->ram_lock); +} +static void aw8624_vibrator_work_routine(struct work_struct *work) +{ + struct aw8624 *aw8624 = container_of(work, struct aw8624, + vibrator_work); + + aw_dev_dbg("%s enter\n", __func__); + + mutex_lock(&aw8624->lock); + aw8624_haptic_stop(aw8624); + aw8624_haptic_upload_lra(aw8624, AW8624_HAPTIC_F0_CALI_LRA); + if (aw8624->state) { + if (aw8624->activate_mode == AW8624_HAPTIC_RAM_MODE) { + aw8624_haptic_ram_vbat_comp(aw8624, true); + aw8624_haptic_ram_play(aw8624, AW8624_HAPTIC_RAM_MODE); + } else if (aw8624->activate_mode == + AW8624_HAPTIC_RAM_LOOP_MODE) { + aw8624_haptic_ram_vbat_comp(aw8624, true); + aw8624_haptic_ram_play(aw8624, + AW8624_HAPTIC_RAM_LOOP_MODE); + /* run ms timer */ + hrtimer_start(&aw8624->timer, + ktime_set(aw8624->duration / 1000, + (aw8624->duration % 1000) * 1000000), + HRTIMER_MODE_REL); + } else if (aw8624->activate_mode == + AW8624_HAPTIC_CONT_MODE) { + aw8624_haptic_cont(aw8624); + /* run ms timer */ + hrtimer_start(&aw8624->timer, + ktime_set(aw8624->duration / 1000, + (aw8624->duration % 1000) * 1000000), + HRTIMER_MODE_REL); + } else { + aw_dev_err("%s: activate_mode error\n", + __func__); + } + } + mutex_unlock(&aw8624->lock); +} + + + +/****************************************************** + * + * irq + * + ******************************************************/ +void aw8624_interrupt_setup(struct aw8624 *aw8624) +{ + unsigned char reg_val = 0; + + aw8624_i2c_read(aw8624, AW8624_REG_SYSINT, ®_val, + AW_I2C_BYTE_ONE); + aw_dev_info("%s: reg SYSINT=0x%x\n", __func__, reg_val); + + aw8624_i2c_write_bits(aw8624, AW8624_REG_DBGCTRL, + AW8624_BIT_DBGCTRL_INT_MODE_MASK, + AW8624_BIT_DBGCTRL_INT_MODE_EDGE); + + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSINTM, + (AW8624_BIT_SYSINTM_UVLO_MASK & + AW8624_BIT_SYSINTM_OCD_MASK & + AW8624_BIT_SYSINTM_OT_MASK), + (AW8624_BIT_SYSINTM_UVLO_EN | + AW8624_BIT_SYSINTM_OCD_EN | + AW8624_BIT_SYSINTM_OT_EN)); +} + +static ssize_t aw8624_gun_type_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw8624->gun_type); +} + +static ssize_t aw8624_gun_type_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + + aw_dev_dbg("%s: value=%d\n", __func__, val); + + mutex_lock(&aw8624->lock); + aw8624->gun_type = val; + mutex_unlock(&aw8624->lock); + return count; +} + +static ssize_t aw8624_bullet_nr_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw8624->bullet_nr); +} + +static ssize_t aw8624_bullet_nr_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return count; + + aw_dev_dbg("%s: value=%d\n", __func__, val); + + mutex_lock(&aw8624->lock); + aw8624->bullet_nr = val; + mutex_unlock(&aw8624->lock); + return count; +} + +static ssize_t aw8624_trig_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + len += snprintf(buf + len, PAGE_SIZE - len, + "trig: trig_enable=%d, trig_edge=%d", + aw8624->trig.trig_enable, aw8624->trig.trig_edge); + len += snprintf(buf + len, PAGE_SIZE - len, + "trig_polar=%d, pos_sequence=%d, neg_sequence=%d\n", + aw8624->trig.trig_polar, aw8624->trig.pos_sequence, + aw8624->trig.neg_sequence); + return len; + +} + +static ssize_t aw8624_trig_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int databuf[5] = { 0 }; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + if (!aw8624->ram_init) { + aw_dev_err("%s: ram init failed, not allow to play!\n", + __func__); + return count; + } + if (sscanf(buf, "%d %d %d %d %d", + &databuf[0], &databuf[1], + &databuf[2], &databuf[3], &databuf[4]) == 5) { + if (databuf[0] > 1) + databuf[0] = 1; + if (databuf[0] < 0) + databuf[0] = 0; + if (databuf[1] > 1) + databuf[0] = 1; + if (databuf[1] < 0) + databuf[0] = 0; + if (databuf[2] > 1) + databuf[0] = 1; + if (databuf[2] < 0) + databuf[0] = 0; + if (databuf[3] > aw8624->ram.ram_num || + databuf[4] > aw8624->ram.ram_num) { + aw_dev_err("%s: input seq value out of range!\n", + __func__); + return count; + } + aw8624->trig.trig_enable = databuf[0]; + aw8624->trig.trig_edge = databuf[1]; + aw8624->trig.trig_polar = databuf[2]; + aw8624->trig.pos_sequence = databuf[3]; + aw8624->trig.neg_sequence = databuf[4]; + mutex_lock(&aw8624->lock); + aw8624_haptic_tirg1_param_config(aw8624); + mutex_unlock(&aw8624->lock); + } else + aw_dev_err("%s: please input five parameters\n", + __func__); + return count; +} + +static ssize_t aw8624_ram_num_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + ssize_t len = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + aw8624_haptic_get_ram_number(aw8624); + + len += snprintf(buf + len, PAGE_SIZE - len, + "ram_num = %d\n", aw8624->ram.ram_num); + return len; + +} + +static ssize_t aw8624_awrw_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + unsigned char reg_num = aw8624->aw_i2c_package.reg_num; + unsigned char flag = aw8624->aw_i2c_package.flag; + unsigned char *reg_data = aw8624->aw_i2c_package.reg_data; + unsigned char i = 0; + ssize_t len = 0; + + + if (!reg_num) { + aw_dev_err("%s: awrw parameter error\n", + __func__); + return len; + } + if (flag == AW8624_READ) { + for (i = 0; i < reg_num; i++) { + len += snprintf(buf + len, PAGE_SIZE - len, + "0x%02x,", reg_data[i]); + } + + len += snprintf(buf + len - 1, PAGE_SIZE - len, "\n"); + } + + return len; +} + +static ssize_t aw8624_awrw_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int datatype[3] = { 0 }; + int ret = 0; + cdev_t *cdev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(cdev, struct aw8624, vib_dev); + + if (sscanf(buf, "%x %x %x", &datatype[0], &datatype[1], + &datatype[2]) == 3) { + if (!datatype[1]) { + aw_dev_err("%s: awrw parameter error\n", + __func__); + return count; + } + aw8624->aw_i2c_package.flag = (unsigned char)datatype[0]; + aw8624->aw_i2c_package.reg_num = (unsigned char)datatype[1]; + aw8624->aw_i2c_package.first_addr = (unsigned char)datatype[2]; + + if (aw8624->aw_i2c_package.flag == AW8624_WRITE) { + ret = aw8624_parse_data(aw8624, buf); + if (ret < 0) + return count; + aw8624_i2c_write(aw8624, + aw8624->aw_i2c_package.first_addr, + aw8624->aw_i2c_package.reg_data, + aw8624->aw_i2c_package.reg_num); + } + if (aw8624->aw_i2c_package.flag == AW8624_READ) + aw8624_i2c_read(aw8624, + aw8624->aw_i2c_package.first_addr, + aw8624->aw_i2c_package.reg_data, + aw8624->aw_i2c_package.reg_num); + } else + aw_dev_err("%s: missing number of parameters\n", + __func__); + + return count; +} + +#if 0 +/* +* schedule_work is low priority. +* aw8624 rtp mode can`t be interrupted. +*/ +static irqreturn_t aw8624_irq(int irq, void *data) +{ + struct aw8624 *aw8624 = (struct aw8624 *)data; + + schedule_work(&aw8624->irq_work); + return IRQ_HANDLED; +} + +#endif +/***************************************************** + * + * device tree + * + *****************************************************/ +static DEVICE_ATTR(state, 0664, aw8624_state_show, aw8624_state_store); +static DEVICE_ATTR(duration, 0664, aw8624_duration_show, aw8624_duration_store); +static DEVICE_ATTR(activate, 0664, aw8624_activate_show, aw8624_activate_store); +static DEVICE_ATTR(activate_mode, 0664, + aw8624_activate_mode_show, aw8624_activate_mode_store); +static DEVICE_ATTR(index, 0664, aw8624_index_show, aw8624_index_store); +static DEVICE_ATTR(gain, 0664, aw8624_gain_show, aw8624_gain_store); +static DEVICE_ATTR(seq, 0664, aw8624_seq_show, aw8624_seq_store); +static DEVICE_ATTR(loop, 0664, aw8624_loop_show, aw8624_loop_store); +static DEVICE_ATTR(register, 0664, aw8624_reg_show, aw8624_reg_store); +static DEVICE_ATTR(ram_update, 0664, + aw8624_ram_update_show, aw8624_ram_update_store); +static DEVICE_ATTR(f0, 0664, aw8624_f0_show, aw8624_f0_store); +static DEVICE_ATTR(cali, 0664, aw8624_cali_show, aw8624_cali_store); +static DEVICE_ATTR(cont, 0664, aw8624_cont_show, aw8624_cont_store); +static DEVICE_ATTR(cont_td, 0664, aw8624_cont_td_show, aw8624_cont_td_store); +static DEVICE_ATTR(cont_drv, 0664, aw8624_cont_drv_show, aw8624_cont_drv_store); +static DEVICE_ATTR(cont_num_brk, 0664, + aw8624_cont_num_brk_show, aw8624_cont_num_brk_store); +static DEVICE_ATTR(cont_zc_thr, 0664, + aw8624_cont_zc_thr_show, aw8624_cont_zc_thr_store); +static DEVICE_ATTR(vbat_monitor, 0664, + aw8624_vbat_monitor_show, aw8624_vbat_monitor_store); +static DEVICE_ATTR(lra_resistance, 0664, + aw8624_lra_resistance_show, aw8624_lra_resistance_store); +static DEVICE_ATTR(prctmode, 0664, aw8624_prctmode_show, aw8624_prctmode_store); +static DEVICE_ATTR(haptic_audio, 0664, + aw8624_haptic_audio_show, aw8624_haptic_audio_store); +static DEVICE_ATTR(haptic_audio_time, 0664, + aw8624_haptic_audio_time_show, aw8624_haptic_audio_time_store); +static DEVICE_ATTR(ram_vbat_comp, 0664, + aw8624_ram_vbat_comp_show, aw8624_ram_vbat_comp_store); +static DEVICE_ATTR(rtp, 0664, aw8624_rtp_show, aw8624_rtp_store); +static DEVICE_ATTR(osc_cali, 0664, aw8624_osc_cali_show, aw8624_osc_cali_store); +static DEVICE_ATTR(gun_type, 0664, aw8624_gun_type_show, aw8624_gun_type_store); +static DEVICE_ATTR(bullet_nr, 0664, + aw8624_bullet_nr_show, aw8624_bullet_nr_store); +static DEVICE_ATTR(trig, 0664, + aw8624_trig_show, aw8624_trig_store); +static DEVICE_ATTR(ram_num, 0664, aw8624_ram_num_show, NULL); +static DEVICE_ATTR(awrw, 0644, aw8624_awrw_show, aw8624_awrw_store); +static struct attribute *aw8624_vibrator_attributes[] = { + &dev_attr_state.attr, + &dev_attr_duration.attr, + &dev_attr_activate.attr, + &dev_attr_activate_mode.attr, + &dev_attr_index.attr, + &dev_attr_gain.attr, + &dev_attr_seq.attr, + &dev_attr_loop.attr, + &dev_attr_register.attr, + &dev_attr_ram_update.attr, + &dev_attr_f0.attr, + &dev_attr_cali.attr, + &dev_attr_cont.attr, + &dev_attr_cont_td.attr, + &dev_attr_cont_drv.attr, + &dev_attr_cont_num_brk.attr, + &dev_attr_cont_zc_thr.attr, + &dev_attr_vbat_monitor.attr, + &dev_attr_lra_resistance.attr, + &dev_attr_prctmode.attr, + &dev_attr_haptic_audio.attr, + &dev_attr_ram_vbat_comp.attr, + &dev_attr_haptic_audio_time.attr, + &dev_attr_rtp.attr, + &dev_attr_osc_cali.attr, + &dev_attr_gun_type.attr, + &dev_attr_bullet_nr.attr, + &dev_attr_trig.attr, + &dev_attr_ram_num.attr, + &dev_attr_awrw.attr, + NULL +}; + +struct attribute_group aw8624_vibrator_attribute_group = { + .attrs = aw8624_vibrator_attributes +}; +int aw8624_vibrator_init(struct aw8624 *aw8624) +{ + int ret = 0; + + aw_dev_dbg("%s enter\n", __func__); + +#ifdef TIMED_OUTPUT + aw8624->vib_dev.name = "awinic_vibrator"; + aw8624->vib_dev.get_time = aw8624_vibrator_get_time; + aw8624->vib_dev.enable = aw8624_vibrator_enable; + + ret = timed_output_dev_register(&(aw8624->vib_dev)); + if (ret < 0) { + dev_err(aw8624->dev, "%s: fail to create timed output dev\n", + __func__); + return ret; + } + ret = sysfs_create_group(&aw8624->vib_dev.dev->kobj, + &aw8624_vibrator_attribute_group); + if (ret < 0) { + dev_err(aw8624->dev, + "%s error creating sysfs attr files\n", + __func__); + return ret; + } +#else + aw8624->vib_dev.name = "awinic_vibrator"; + aw8624->vib_dev.brightness_set = aw8624_vibrator_enable; + + + ret = devm_led_classdev_register(&aw8624->i2c->dev, &(aw8624->vib_dev)); + if (ret < 0) { + dev_err(aw8624->dev, "%s: fail to create leds dev\n", + __func__); + return ret; + } + + ret = sysfs_create_group(&aw8624->vib_dev.dev->kobj, + &aw8624_vibrator_attribute_group); + if (ret < 0) { + dev_err(aw8624->dev, "%s error creating sysfs attr files\n", + __func__); + return ret; + } +#endif + hrtimer_init(&aw8624->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + aw8624->timer.function = aw8624_vibrator_timer_func; + INIT_WORK(&aw8624->vibrator_work, aw8624_vibrator_work_routine); + + if (aw8624->IsUsedIRQ) + INIT_WORK(&aw8624->rtp_work, aw8624_rtp_work_routine); + + mutex_init(&aw8624->lock); + mutex_init(&aw8624->rtp_lock); + mutex_init(&aw8624->ram_lock); + + + return 0; +} + + +static int aw8624_is_rtp_load_end(struct aw8624 *aw8624) +{ + unsigned char glb_st = 0; + int ret = -1; + + aw8624_i2c_read(aw8624, AW8624_REG_GLB_STATE, &glb_st, + AW_I2C_BYTE_ONE); + if ((aw8624->rtp_cnt == aw8624->rtp_container->len) || + ((glb_st & 0x0f) == 0x00)) { + if (aw8624->rtp_cnt == + aw8624->rtp_container->len) + aw_dev_info("%s:rtp load completely.", + __func__); + else + aw_dev_err("%s rtp load failed!!\n", + __func__); + aw8624_haptic_set_rtp_aei(aw8624, + false); + aw8624->rtp_cnt = 0; + aw8624->rtp_init = 0; + ret = 0; + } + return ret; +} + +static int aw8624_write_rtp_data(struct aw8624 *aw8624) +{ + unsigned int buf_len = 0; + int ret = -1; + + if (!aw8624->rtp_cnt) { + aw_dev_info("%s:aw8624->rtp_cnt is 0!\n", + __func__); + return ret; + } + if (!aw8624->rtp_container) { + aw_dev_info("%s:aw8624->rtp_container is null, break!\n", + __func__); + return ret; + } + if ((aw8624->rtp_container->len - aw8624->rtp_cnt) < + (aw8624->ram.base_addr >> 2)) { + buf_len = + aw8624->rtp_container->len - aw8624->rtp_cnt; + } else { + buf_len = (aw8624->ram.base_addr >> 2); + } + aw8624_i2c_write(aw8624, AW8624_REG_RTP_DATA, + &aw8624->rtp_container->data[aw8624->rtp_cnt], + buf_len); + aw8624->rtp_cnt += buf_len; + + return 0; +} + + +irqreturn_t aw8624_irq(int irq, void *data) +{ + unsigned char reg_val = 0; + unsigned char glb_st = 0; + int ret = 0; + struct aw8624 *aw8624 = data; + + aw8624_i2c_read(aw8624, AW8624_REG_SYSINT, ®_val, + AW_I2C_BYTE_ONE); + if (reg_val & AW8624_BIT_SYSINT_UVLI) + aw_dev_err("%s chip uvlo int error\n", __func__); + if (reg_val & AW8624_BIT_SYSINT_OCDI) + aw_dev_err("%s chip over current int error\n", + __func__); + if (reg_val & AW8624_BIT_SYSINT_OTI) + aw_dev_err("%s chip over temperature int error\n", + __func__); + if (reg_val & AW8624_BIT_SYSINT_DONEI) + aw_dev_info("%s chip playback done\n", __func__); + + + if (reg_val & AW8624_BIT_SYSINT_UVLI) { + aw8624_i2c_read(aw8624, AW8624_REG_GLB_STATE, &glb_st, + AW_I2C_BYTE_ONE); + if (glb_st == AW8624_BIT_GLBRD5_STATE_STANDBY) { + aw8624_i2c_write_bits(aw8624, + AW8624_REG_SYSINTM, + AW8624_BIT_SYSINTM_UVLO_MASK, + AW8624_BIT_SYSINTM_UVLO_OFF); + } + } + + if (reg_val & AW8624_BIT_SYSINT_FF_AEI) { + aw_dev_dbg("%s: aw8624 rtp fifo almost empty\n", + __func__); + if (aw8624->rtp_init) { + while ((!aw8624_haptic_rtp_get_fifo_afs(aw8624)) && + (aw8624->play_mode == AW8624_HAPTIC_RTP_MODE)) { + mutex_lock(&aw8624->rtp_lock); +#ifdef AW_ENABLE_RTP_PRINT_LOG + aw_dev_info("%s: aw8624 rtp mode fifo update, cnt=%d\n", + __func__, aw8624->rtp_cnt); +#endif + ret = aw8624_write_rtp_data(aw8624); + if (ret < 0) { + mutex_unlock(&aw8624->rtp_lock); + break; + } + ret = aw8624_is_rtp_load_end(aw8624); + if (!ret) { + mutex_unlock(&aw8624->rtp_lock); + break; + } + mutex_unlock(&aw8624->rtp_lock); + } + } else { + aw_dev_err( "%s: aw8624 rtp init = %d, init error\n", + __func__, aw8624->rtp_init); + } + } + + if (reg_val & AW8624_BIT_SYSINT_FF_AFI) + aw_dev_dbg("%s: aw8624 rtp mode fifo full\n", __func__); + + if (aw8624->play_mode != AW8624_HAPTIC_RTP_MODE) + aw8624_haptic_set_rtp_aei(aw8624, false); + + return IRQ_HANDLED; +} + +static int aw8624_analyse_duration_range(struct aw8624 *aw8624) +{ + int i = 0; + int ret = 0; + int len = 0; + int *duration_time = NULL; + + len = ARRAY_SIZE(aw8624_dts_data.aw8624_duration_time); + duration_time = aw8624_dts_data.aw8624_duration_time; + if (len < 2) { + aw_dev_err("%s: duration time range error\n", __func__); + return -ERANGE; + } + for (i = (len - 1); i > 0; i--) { + if (duration_time[i] > duration_time[i-1]) + continue; + else + break; + + } + if (i > 0) { + aw_dev_err("%s: duration time range error\n", __func__); + ret = -ERANGE; + } + return ret; +} + +static int +aw8624_analyse_duration_array_size(struct aw8624 *aw8624, + struct device_node *np) +{ + int ret = 0; + + ret = of_property_count_elems_of_size(np, "aw8624_vib_duration_time", + 4); + if (ret < 0) { + aw8624->duration_time_flag = -1; + aw_dev_info("%s vib_duration_time not found\n", __func__); + return ret; + } + aw8624->duration_time_size = ret; + if (aw8624->duration_time_size > 3) { + aw8624->duration_time_flag = -1; + aw_dev_info("%s vib_duration_time error, array size = %d\n", + __func__, aw8624->duration_time_size); + return -ERANGE; + } + return 0; +} + +int aw8624_parse_dt(struct aw8624 *aw8624, struct device *dev, + struct device_node *np) { + unsigned int val = 0; + /*unsigned int brake_ram_config[24];*/ + unsigned int brake_cont_config[24]; + unsigned int f0_trace_parameter[4]; + unsigned int bemf_config[4]; + unsigned int duration_time[3]; + unsigned int sw_brake[2]; + unsigned int trig_config_temp[5]; + int ret = 0; + + val = + of_property_read_u32(np, "aw8624_vib_lk_f0_cali", + &aw8624_dts_data.aw8624_lk_f0_cali); + if (val != 0) + aw_dev_info("aw8624_vib_mode not found\n"); + aw_dev_info("%s: aw8624_vib_lk_f0_cali = 0x%02x\n", + __func__, aw8624_dts_data.aw8624_lk_f0_cali); + val = + of_property_read_u32(np, "aw8624_vib_mode", + &aw8624_dts_data.aw8624_mode); + if (val != 0) + aw_dev_info("aw8624_vib_mode not found\n"); + val = + of_property_read_u32(np, "aw8624_vib_f0_pre", + &aw8624_dts_data.aw8624_f0_pre); + if (val != 0) + aw_dev_info("aw8624_vib_f0_pre not found\n"); + val = + of_property_read_u32(np, "aw8624_vib_f0_cali_percen", + &aw8624_dts_data.aw8624_f0_cali_percen); + if (val != 0) + aw_dev_info("aw8624_vib_f0_cali_percen not found\n"); + val = + of_property_read_u32(np, "aw8624_vib_cont_drv_lev", + &aw8624_dts_data.aw8624_cont_drv_lvl); + if (val != 0) + aw_dev_info("aw8624_vib_cont_drv_lev not found\n"); + val = + of_property_read_u32(np, "aw8624_vib_cont_drv_lvl_ov", + &aw8624_dts_data.aw8624_cont_drv_lvl_ov); + if (val != 0) + aw_dev_info("aw8624_vib_cont_drv_lvl_ov not found\n"); + val = + of_property_read_u32(np, "aw8624_vib_cont_td", + &aw8624_dts_data.aw8624_cont_td); + if (val != 0) + aw_dev_info("aw8624_vib_cont_td not found\n"); + val = + of_property_read_u32(np, "aw8624_vib_cont_zc_thr", + &aw8624_dts_data.aw8624_cont_zc_thr); + if (val != 0) + aw_dev_info("aw8624_vib_cont_zc_thr not found\n"); + val = + of_property_read_u32(np, "aw8624_vib_cont_num_brk", + &aw8624_dts_data.aw8624_cont_num_brk); + if (val != 0) + aw_dev_info("aw8624_vib_cont_num_brk not found\n"); + val = + of_property_read_u32(np, "aw8624_vib_f0_coeff", + &aw8624_dts_data.aw8624_f0_coeff); + if (val != 0) + aw_dev_info("aw8624_vib_f0_coeff not found\n"); + val = of_property_read_u32_array(np, "aw8624_vib_brake_cont_config", + brake_cont_config, ARRAY_SIZE(brake_cont_config)); + if (val != 0) + aw_dev_info("%s vib_brake_cont_config not found\n", __func__); + memcpy(aw8624_dts_data.aw8624_cont_brake, + brake_cont_config, sizeof(brake_cont_config)); + + val = of_property_read_u32_array(np, "aw8624_vib_f0_trace_parameter", + f0_trace_parameter, ARRAY_SIZE(f0_trace_parameter)); + if (val != 0) + aw_dev_info("%s vib_f0_trace_parameter not found\n", __func__); + memcpy(aw8624_dts_data.aw8624_f0_trace_parameter, + f0_trace_parameter, sizeof(f0_trace_parameter)); + + val = of_property_read_u32_array(np, "aw8624_vib_bemf_config", + bemf_config, ARRAY_SIZE(bemf_config)); + if (val != 0) + aw_dev_info("%s vib_bemf_config not found\n", __func__); + memcpy(aw8624_dts_data.aw8624_bemf_config, + bemf_config, sizeof(bemf_config)); + + val = + of_property_read_u32_array(np, "aw8624_vib_sw_brake", + sw_brake, ARRAY_SIZE(sw_brake)); + if (val != 0) + aw_dev_info("%s vib_wavseq not found\n", __func__); + memcpy(aw8624_dts_data.aw8624_sw_brake, + sw_brake, sizeof(sw_brake)); + + val = of_property_read_u32(np, "aw8624_vib_tset", + &aw8624_dts_data.aw8624_tset); + if (val != 0) + aw_dev_info("%s vib_tset not found\n", __func__); + val = of_property_read_u32_array(np, "aw8624_vib_duration_time", + duration_time, ARRAY_SIZE(duration_time)); + if (val != 0) + aw_dev_info("%s vib_duration_time not found\n", __func__); + ret = aw8624_analyse_duration_array_size(aw8624, np); + if (!ret) + memcpy(aw8624_dts_data.aw8624_duration_time, + duration_time, sizeof(duration_time)); + val = + of_property_read_u32_array(np, + "aw8624_vib_trig_config", + trig_config_temp, + ARRAY_SIZE(trig_config_temp)); + if (val != 0) + aw_dev_info("%s vib_trig_config not found\n", + __func__); + memcpy(aw8624_dts_data.trig_config, trig_config_temp, + sizeof(trig_config_temp)); + return 0; +} diff --git a/drivers/misc/awinic/aw862x/aw8624.h b/drivers/misc/awinic/aw862x/aw8624.h new file mode 100644 index 000000000000..ba7cd5fec37c --- /dev/null +++ b/drivers/misc/awinic/aw862x/aw8624.h @@ -0,0 +1,652 @@ +#ifndef _AW8624_H_ +#define _AW8624_H_ + +#include +#include +#include +#include +#include +#include +#include "haptic_nv.h" + +/********************************************************* + * + * marco + * + ********************************************************/ +#define AW8624_I2C_RETRIES (2) +#define AW8624_RTP_NAME_MAX (64) +#define AW8624_SEQUENCER_SIZE (8) +#define AW8624_SEQUENCER_LOOP_SIZE (4) +#define AW8624_OSC_CALIBRATION_T_LENGTH (5100000) +#define AW8624_PM_QOS_VALUE_VB (400) +#define AW8624_VBAT_REFER (4200) +#define AW8624_VBAT_MIN (3000) +#define AW8624_VBAT_MAX (4500) +#define AW8624_HAPTIC_NAME ("aw8624_haptic") +#define AW8624_SET_AEADDR_H(addr) ((((addr) >> 1) >> 8)) +#define AW8624_SET_AEADDR_L(addr) (((addr) >> 1) & 0x00FF) +#define AW8624_SET_AFADDR_H(addr) (((addr) - ((addr) >> 2)) >> 8) +#define AW8624_SET_AFADDR_L(addr) (((addr) - ((addr) >> 2)) & 0x00FF) +#define AW8624_F0_FORMULA(f0_reg, f0_coeff) (1000000000 / ((f0_reg) * (f0_coeff))) +#define AW8624_VBAT_FORMULA(reg_val) (6100 * (reg_val) / 256) +#define AW8624_LRA_FORMULA(reg_val) (298 * (reg_val)) +#define AW8624_VBAT_DELAY_MIN (2000) +#define AW8624_VBAT_DELAY_MAX (2500) +#define AW8624_LRA_DELAY_MIN (3000) +#define AW8624_LRA_DELAY_MAX (3500) +#define AW8624_STOP_DELAY_MIN (2000) +#define AW8624_STOP_DELAY_MAX (2500) +#define AW8624_F0_DELAY_MIN (10000) +#define AW8624_F0_DELAY_MAX (10500) +#define AW8624_MUL_GET_F0_RANGE (150) +#define AW8624_MUL_GET_F0_NUM (3) +/********************************************************* + * + * enum + * + ********************************************************/ +enum aw8624_flags { + AW8624_FLAG_NONR = 0, + AW8624_FLAG_SKIP_INTERRUPTS = 1, +}; + +enum aw8624_chipids { + AW8624_ID = 1, +}; + +enum aw8624_haptic_read_write { + AW8624_HAPTIC_CMD_READ_REG = 0, + AW8624_HAPTIC_CMD_WRITE_REG = 1, +}; + +enum aw8624_haptic_play { + AW8624_HAPTIC_PLAY_NULL = 0, + AW8624_HAPTIC_PLAY_ENABLE = 1, + AW8624_HAPTIC_PLAY_STOP = 2, + AW8624_HAPTIC_PLAY_GAIN = 8, +}; + +enum aw8624_haptic_cmd { + AW8624_HAPTIC_CMD_NULL = 0, + AW8624_HAPTIC_CMD_ENABLE = 1, + AW8624_HAPTIC_CMD_HAPTIC = 0x0f, + AW8624_HAPTIC_CMD_TP = 0x10, + AW8624_HAPTIC_CMD_SYS = 0xf0, + AW8624_HAPTIC_CMD_STOP = 255, +}; +enum aw8624_haptic_work_mode { + AW8624_HAPTIC_STANDBY_MODE = 0, + AW8624_HAPTIC_RAM_MODE = 1, + AW8624_HAPTIC_RAM_LOOP_MODE = 2, + AW8624_HAPTIC_CONT_MODE = 3, + AW8624_HAPTIC_RTP_MODE = 4, + AW8624_HAPTIC_TRIG_MODE = 5, + AW8624_HAPTIC_NULL = 6, +}; + +enum aw8624_haptic_bst_mode { + AW8624_HAPTIC_BYPASS_MODE = 0, + AW8624_HAPTIC_BOOST_MODE = 1, +}; + +enum aw8624_haptic_vbat_comp_mode { + AW8624_HAPTIC_VBAT_SW_COMP_MODE = 0, + AW8624_HAPTIC_VBAT_HW_COMP_MODE = 1, +}; + +enum aw8624_haptic_ram_vbat_comp_mode { + AW8624_HAPTIC_RAM_VBAT_COMP_DISABLE = 0, + AW8624_HAPTIC_RAM_VBAT_COMP_ENABLE = 1, +}; + +enum aw8624_haptic_f0_flag { + AW8624_HAPTIC_LRA_F0 = 0, + AW8624_HAPTIC_CALI_F0 = 1, +}; + +enum aw8624_haptic_pwm_mode { + AW8624_PWM_48K = 0, + AW8624_PWM_24K = 1, + AW8624_PWM_12K = 2, +}; + +enum aw8624_haptic_cali_lra { + AW8624_HAPTIC_ZERO = 0, + AW8624_HAPTIC_F0_CALI_LRA = 1, + AW8624_HAPTIC_RTP_CALI_LRA = 2, +}; + +enum aw8624_haptic_pin { + AW8624_TRIG1 = 0, + AW8624_IRQ = 1, +}; + +enum aw8624_awrw_flag { + AW8624_WRITE = 0, + AW8624_READ = 1, +}; + +enum aw8624_pwm_clk { + AW8624_CLK_24K = 2, + AW8624_CLK_12K = 3, +}; + +/********************************************************* + * + * struct + * + ********************************************************/ +struct fileops { + unsigned char cmd; + unsigned char reg; + unsigned char ram_addrh; + unsigned char ram_addrl; +}; + +struct aw8624_trig { + unsigned char trig_enable; + unsigned char trig_edge; + unsigned char trig_polar; + unsigned char pos_sequence; + unsigned char neg_sequence; +}; + +struct aw8624_dts_info { + int aw8624_lk_f0_cali; + int aw8624_mode; + int aw8624_f0_pre; + int aw8624_f0_cali_percen; + int aw8624_cont_drv_lvl; + int aw8624_cont_drv_lvl_ov; + int aw8624_cont_td; + int aw8624_cont_zc_thr; + int aw8624_cont_num_brk; + int aw8624_f0_coeff; + int aw8624_duration_time[3]; + int aw8624_cont_brake[3][8]; + int aw8624_bemf_config[4]; + int aw8624_sw_brake[2]; + int aw8624_wavseq[16]; + int aw8624_wavloop[10]; + int aw8624_td_brake[3]; + int aw8624_tset; + unsigned int aw8624_f0_trace_parameter[4]; + unsigned int trig_config[5]; +}; + +struct aw8624 { + bool haptic_ready; + bool audio_ready; + bool IsUsedIRQ; + bool ram_update_delay; + + ktime_t current_t; + ktime_t pre_enter_t; + ktime_t kstart, kend; + + cdev_t vib_dev; + + unsigned char hwen_flag; + unsigned char flags; + unsigned char chipid; + unsigned char chipid_flag; + unsigned char singlecycle; + unsigned char play_mode; + unsigned char activate_mode; + unsigned char auto_boost; + unsigned char duration_time_size; + unsigned char cont_drv_lvl; + unsigned char cont_drv_lvl_ov; + unsigned char cont_num_brk; + unsigned char max_pos_beme; + unsigned char max_neg_beme; + unsigned char f0_cali_flag; + unsigned char ram_vbat_comp; + unsigned char rtp_init; + unsigned char ram_init; + unsigned char rtp_routine_on; + unsigned char seq[AW8624_SEQUENCER_SIZE]; + unsigned char loop[AW8624_SEQUENCER_SIZE]; + + char duration_time_flag; + + int state; + int duration; + int amplitude; + int index; + int vmax; + int gain; + int f0_value; + int pre_haptic_number; + int reset_gpio; + int irq_gpio; + int reset_gpio_ret; + int irq_gpio_ret; + + unsigned int f0; + unsigned int f0_pre; + unsigned int cont_td; + unsigned int cont_f0; + unsigned int cont_zc_thr; + unsigned int timeval_flags; + unsigned int osc_cali_flag; + unsigned int theory_time; + unsigned int rtp_len; + unsigned int gun_type; + unsigned int bullet_nr; + unsigned int rtp_cnt; + unsigned int rtp_file_num; + unsigned int vbat; + unsigned int lra; + unsigned int interval_us; + unsigned int ramupdate_flag; + unsigned int rtpupdate_flag; + unsigned int osc_cali_run; + unsigned int lra_calib_data; + unsigned int f0_calib_data; + unsigned long int microsecond; + + struct haptic_audio haptic_audio; + struct regmap *regmap; + struct i2c_client *i2c; + struct device *dev; + struct input_dev *input; + struct aw8624_container *rtp_container; + struct mutex lock; + struct mutex rtp_lock; + struct mutex ram_lock; + struct hrtimer timer; + struct work_struct vibrator_work; + struct work_struct irq_work; + struct work_struct rtp_work; + struct delayed_work ram_work; + struct delayed_work stop_work; + struct fileops fileops; + struct ram ram; + struct aw8624_trig trig; + struct aw_i2c_package aw_i2c_package; +}; + +struct aw8624_container { + int len; + unsigned char data[]; +}; + +/********************************************************* + * + * ioctl + * + ********************************************************/ +struct aw8624_seq_loop { + unsigned char loop[AW8624_SEQUENCER_SIZE]; +}; + +struct aw8624_que_seq { + unsigned char index[AW8624_SEQUENCER_SIZE]; +}; + +/********************************************************* + * + * extern + * + ********************************************************/ +extern int aw8624_parse_dt(struct aw8624 *aw8624, struct device *dev, + struct device_node *np); +extern void aw8624_interrupt_setup(struct aw8624 *aw8624); +extern int aw8624_vibrator_init(struct aw8624 *aw8624); +extern int aw8624_haptic_init(struct aw8624 *aw8624); +extern int aw8624_ram_init(struct aw8624 *aw8624); +extern irqreturn_t aw8624_irq(int irq, void *data); +extern struct attribute_group aw8624_vibrator_attribute_group; + +/******************************************** + * Register List + *******************************************/ +#define AW8624_REG_ID (0x00) +#define AW8624_REG_SYSST (0x01) +#define AW8624_REG_SYSINT (0x02) +#define AW8624_REG_SYSINTM (0x03) +#define AW8624_REG_SYSCTRL (0x04) +#define AW8624_REG_GO (0x05) +#define AW8624_REG_RTP_DATA (0x06) +#define AW8624_REG_WAVSEQ1 (0x07) +#define AW8624_REG_WAVSEQ2 (0x08) +#define AW8624_REG_WAVSEQ3 (0x09) +#define AW8624_REG_WAVSEQ4 (0x0a) +#define AW8624_REG_WAVSEQ5 (0x0b) +#define AW8624_REG_WAVSEQ6 (0x0c) +#define AW8624_REG_WAVSEQ7 (0x0d) +#define AW8624_REG_WAVSEQ8 (0x0e) +#define AW8624_REG_WAVLOOP1 (0x0f) +#define AW8624_REG_WAVLOOP2 (0x10) +#define AW8624_REG_WAVLOOP3 (0x11) +#define AW8624_REG_WAVLOOP4 (0x12) +#define AW8624_REG_MANLOOP (0x13) +#define AW8624_REG_TRG1_SEQP (0x14) +#define AW8624_REG_TRG1_SEQN (0x17) +#define AW8624_REG_TRG_CFG1 (0x1b) +#define AW8624_REG_TRG_CFG2 (0x1c) +#define AW8624_REG_DBGCTRL (0x20) +#define AW8624_REG_BASE_ADDRH (0x21) +#define AW8624_REG_BASE_ADDRL (0x22) +#define AW8624_REG_FIFO_AEH (0x23) +#define AW8624_REG_FIFO_AEL (0x24) +#define AW8624_REG_FIFO_AFH (0x25) +#define AW8624_REG_FIFO_AFL (0x26) +#define AW8624_REG_DATCTRL (0x2b) +#define AW8624_REG_PWMPRC (0x2d) +#define AW8624_REG_PWMDBG (0x2e) +#define AW8624_REG_DBGSTAT (0x30) +#define AW8624_REG_WAVECTRL (0x31) +#define AW8624_REG_BRAKE0_CTRL (0x32) +#define AW8624_REG_BRAKE1_CTRL (0x33) +#define AW8624_REG_BRAKE2_CTRL (0x34) +#define AW8624_REG_BRAKE_NUM (0x35) +#define AW8624_REG_ANACTRL (0x38) +#define AW8624_REG_SW_BRAKE (0x39) +#define AW8624_REG_DATDBG (0x3b) +#define AW8624_REG_PRLVL (0x3e) +#define AW8624_REG_PRTIME (0x3f) +#define AW8624_REG_RAMADDRH (0x40) +#define AW8624_REG_RAMADDRL (0x41) +#define AW8624_REG_RAMDATA (0x42) +#define AW8624_REG_BRA_MAX_NUM (0x44) +#define AW8624_REG_GLB_STATE (0x47) +#define AW8624_REG_CONT_CTRL (0x48) +#define AW8624_REG_F_PRE_H (0x49) +#define AW8624_REG_F_PRE_L (0x4a) +#define AW8624_REG_TD_H (0x4b) +#define AW8624_REG_TD_L (0x4c) +#define AW8624_REG_TSET (0x4d) +#define AW8624_REG_THRS_BRA_END (0x4f) +#define AW8624_REG_EF_RDATAH (0x55) +#define AW8624_REG_TRIM_LRA (0x5b) +#define AW8624_REG_R_SPARE (0x5d) +#define AW8624_REG_D2SCFG (0x5e) +#define AW8624_REG_DETCTRL (0x5f) +#define AW8624_REG_RLDET (0x60) +#define AW8624_REG_OSDET (0x61) +#define AW8624_REG_VBATDET (0x62) +#define AW8624_REG_ADCTEST (0x66) +#define AW8624_REG_F_LRA_F0_H (0x68) +#define AW8624_REG_F_LRA_F0_L (0x69) +#define AW8624_REG_F_LRA_CONT_H (0x6a) +#define AW8624_REG_F_LRA_CONT_L (0x6b) +#define AW8624_REG_WAIT_VOL_MP (0x6e) +#define AW8624_REG_WAIT_VOL_MN (0x6f) +#define AW8624_REG_ZC_THRSH_H (0x72) +#define AW8624_REG_ZC_THRSH_L (0x73) +#define AW8624_REG_BEMF_VTHH_H (0x74) +#define AW8624_REG_BEMF_VTHH_L (0x75) +#define AW8624_REG_BEMF_VTHL_H (0x76) +#define AW8624_REG_BEMF_VTHL_L (0x77) +#define AW8624_REG_BEMF_NUM (0x78) +#define AW8624_REG_DRV_TIME (0x79) +#define AW8624_REG_TIME_NZC (0x7a) +#define AW8624_REG_DRV_LVL (0x7b) +#define AW8624_REG_DRV_LVL_OV (0x7c) +#define AW8624_REG_NUM_F0_1 (0x7d) +#define AW8624_REG_NUM_F0_2 (0x7e) +#define AW8624_REG_NUM_F0_3 (0x7f) +/****************************************************** + * Register Detail + *****************************************************/ + /* SYSST 0x01 */ +#define AW8624_BIT_SYSST_OVS (1<<6) +#define AW8624_BIT_SYSST_UVLS (1<<5) +#define AW8624_BIT_SYSST_FF_AES (1<<4) +#define AW8624_BIT_SYSST_FF_AFS (1<<3) +#define AW8624_BIT_SYSST_OCDS (1<<2) +#define AW8624_BIT_SYSST_OTS (1<<1) +#define AW8624_BIT_SYSST_DONES (1<<0) + + /* SYSINT 0x02 */ +#define AW8624_BIT_SYSINT_OVI (1<<6) +#define AW8624_BIT_SYSINT_UVLI (1<<5) +#define AW8624_BIT_SYSINT_FF_AEI (1<<4) +#define AW8624_BIT_SYSINT_FF_AFI (1<<3) +#define AW8624_BIT_SYSINT_OCDI (1<<2) +#define AW8624_BIT_SYSINT_OTI (1<<1) +#define AW8624_BIT_SYSINT_DONEI (1<<0) + + /* SYSINTM 0x03 */ +#define AW8624_BIT_SYSINTM_OV_MASK (~(1<<6)) +#define AW8624_BIT_SYSINTM_OV_OFF (1<<6) +#define AW8624_BIT_SYSINTM_OV_EN (0<<6) +#define AW8624_BIT_SYSINTM_UVLO_MASK (~(1<<5)) +#define AW8624_BIT_SYSINTM_UVLO_OFF (1<<5) +#define AW8624_BIT_SYSINTM_UVLO_EN (0<<5) +#define AW8624_BIT_SYSINTM_FF_AE_MASK (~(1<<4)) +#define AW8624_BIT_SYSINTM_FF_AE_OFF (1<<4) +#define AW8624_BIT_SYSINTM_FF_AE_EN (0<<4) +#define AW8624_BIT_SYSINTM_FF_AF_MASK (~(1<<3)) +#define AW8624_BIT_SYSINTM_FF_AF_OFF (1<<3) +#define AW8624_BIT_SYSINTM_FF_AF_EN (0<<3) +#define AW8624_BIT_SYSINTM_OCD_MASK (~(1<<2)) +#define AW8624_BIT_SYSINTM_OCD_OFF (1<<2) +#define AW8624_BIT_SYSINTM_OCD_EN (0<<2) +#define AW8624_BIT_SYSINTM_OT_MASK (~(1<<1)) +#define AW8624_BIT_SYSINTM_OT_OFF (1<<1) +#define AW8624_BIT_SYSINTM_OT_EN (0<<1) +#define AW8624_BIT_SYSINTM_DONE_MASK (~(1<<0)) +#define AW8624_BIT_SYSINTM_DONE_OFF (1<<0) +#define AW8624_BIT_SYSINTM_DONE_EN (0<<0) + + /* SYSCTRL 0x04 */ +#define AW8624_BIT_SYSCTRL_WAVDAT_MODE_MASK (~(3<<6)) +#define AW8624_BIT_SYSCTRL_WAVDAT_MODE_4X (3<<6) +#define AW8624_BIT_SYSCTRL_WAVDAT_MODE_2X (0<<6) +#define AW8624_BIT_SYSCTRL_WAVDAT_MODE_1X (1<<6) +#define AW8624_BIT_SYSCTRL_RAMINIT_MASK (~(1<<5)) +#define AW8624_BIT_SYSCTRL_RAMINIT_EN (1<<5) +#define AW8624_BIT_SYSCTRL_RAMINIT_OFF (0<<5) +#define AW8624_BIT_SYSCTRL_PLAY_MODE_MASK (~(3<<2)) +#define AW8624_BIT_SYSCTRL_PLAY_MODE_CONT (2<<2) +#define AW8624_BIT_SYSCTRL_PLAY_MODE_RTP (1<<2) +#define AW8624_BIT_SYSCTRL_PLAY_MODE_RAM (0<<2) +#define AW8624_BIT_SYSCTRL_WORK_MODE_MASK (~(1<<0)) +#define AW8624_BIT_SYSCTRL_STANDBY (1<<0) +#define AW8624_BIT_SYSCTRL_ACTIVE (0<<0) + + /* GO 0x05 */ +#define AW8624_BIT_GO_MASK (~(1<<0)) +#define AW8624_BIT_GO_ENABLE (1<<0) +#define AW8624_BIT_GO_DISABLE (0<<0) + + /* WAVSEQ1 0x07 */ +#define AW8624_BIT_WAVSEQ1_WAIT (1<<7) +#define AW8624_BIT_WAVSEQ1_WAV_FRM_SEQ1_MASK (~(127<<0)) + + /* WAVSEQ2 0x08 */ +#define AW8624_BIT_WAVSEQ2_WAIT (1<<7) +#define AW8624_BIT_WAVSEQ2_WAV_FRM_SEQ2_MASK (~(127<<0)) + + /* WAVSEQ3 0x09 */ +#define AW8624_BIT_WAVSEQ3_WAIT (1<<7) +#define AW8624_BIT_WAVSEQ3_WAV_FRM_SEQ3_MASK (~(127<<0)) + + /* WAVSEQ4 0x0A */ +#define AW8624_BIT_WAVSEQ4_WAIT (1<<7) +#define AW8624_BIT_WAVSEQ4_WAV_FRM_SEQ4_MASK (~(127<<0)) + + /* WAVSEQ5 0X0B */ +#define AW8624_BIT_WAVSEQ5_WAIT (1<<7) +#define AW8624_BIT_WAVSEQ5_WAV_FRM_SEQ5_MASK (~(127<<0)) + + /* WAVSEQ6 0X0C */ +#define AW8624_BIT_WAVSEQ6_WAIT (1<<7) +#define AW8624_BIT_WAVSEQ6_WAV_FRM_SEQ6_MASK (~(127<<0)) + + /* WAVSEQ7 */ +#define AW8624_BIT_WAVSEQ7_WAIT (1<<7) +#define AW8624_BIT_WAVSEQ7_WAV_FRM_SEQ7_MASK (~(127<<0)) + + /* WAVSEQ8 */ +#define AW8624_BIT_WAVSEQ8_WAIT (1<<7) +#define AW8624_BIT_WAVSEQ8_WAV_FRM_SEQ8_MASK (~(127<<0)) + + /* WAVLOOP */ +#define AW8624_BIT_WAVLOOP_SEQN_MASK (~(15<<4)) +#define AW8624_BIT_WAVLOOP_SEQNP1_MASK (~(15<<0)) +#define AW8624_BIT_WAVLOOP_INIFINITELY (15<<0) + + /* WAVLOOP1 */ +#define AW8624_BIT_WAVLOOP1_SEQ1_MASK (~(15<<4)) +#define AW8624_BIT_WAVLOOP1_SEQ2_MASK (~(15<<0)) + + /* WAVLOOP2 */ +#define AW8624_BIT_WAVLOOP2_SEQ3_MASK (~(15<<4)) +#define AW8624_BIT_WAVLOOP2_SEQ4_MASK (~(15<<0)) + + /* WAVLOOP3 */ +#define AW8624_BIT_WAVLOOP3_SEQ5_MASK (~(15<<4)) +#define AW8624_BIT_WAVLOOP3_SEQ6_MASK (~(15<<0)) + + /* WAVLOOP4 */ +#define AW8624_BIT_WAVLOOP4_SEQ7_MASK (~(15<<4)) +#define AW8624_BIT_WAVLOOP4_SEQ8_MASK (~(15<<0)) + + /* TRGCFG1 */ +#define AW8624_BIT_TRGCFG1_TRG1_POLAR_MASK (~(1<<1)) +#define AW8624_BIT_TRGCFG1_TRG1_POLAR_NEG (1<<1) +#define AW8624_BIT_TRGCFG1_TRG1_POLAR_POS (0<<1) +#define AW8624_BIT_TRGCFG1_TRG1_EDGE_MASK (~(1<<0)) +#define AW8624_BIT_TRGCFG1_TRG1_EDGE_POS (1<<0) +#define AW8624_BIT_TRGCFG1_TRG1_EDGE_POS_NEG (0<<0) + + /* TRGCFG2 */ +#define AW8624_BIT_TRGCFG2_TRG1_ENABLE_MASK (~(1<<0)) +#define AW8624_BIT_TRGCFG2_TRG1_ENABLE (1<<0) +#define AW8624_BIT_TRGCFG2_TRG1_DISABLE (0<<0) + + /*DBGCTRL 0X20 */ +#define AW8624_BIT_DBGCTRL_INTN_TRG_SEL_MASK (~(1<<5)) +#define AW8624_BIT_DBGCTRL_INTN_SEL_ENABLE (1<<5) +#define AW8624_BIT_DBGCTRL_TRG_SEL_ENABLE (0<<5) +#define AW8624_BIT_DBGCTRL_INT_MODE_MASK (~(3<<2)) +#define AW8624_BIT_DBGCTRL_INTN_LEVEL_MODE (0<<2) +#define AW8624_BIT_DBGCTRL_INT_MODE_EDGE (1<<2) +#define AW8624_BIT_DBGCTRL_INTN_POSEDGE_MODE (2<<2) +#define AW8624_BIT_DBGCTRL_INTN_BOTH_EDGE_MODE (3<<2) + + /* DATCTRL */ +#define AW8624_BIT_DATCTRL_FC_MASK (~(1<<6)) +#define AW8624_BIT_DATCTRL_FC_1000HZ (3<<6) +#define AW8624_BIT_DATCTRL_FC_800HZ (3<<6) +#define AW8624_BIT_DATCTRL_FC_600HZ (1<<6) +#define AW8624_BIT_DATCTRL_FC_400HZ (0<<6) +#define AW8624_BIT_DATCTRL_LPF_ENABLE_MASK (~(1<<5)) +#define AW8624_BIT_DATCTRL_LPF_ENABLE (1<<5) +#define AW8624_BIT_DATCTRL_LPF_DISABLE (0<<5) + + /*PWMPRC 0X2D */ +#define AW8624_BIT_PWMPRC_PRC_EN_MASK (~(1<<7)) +#define AW8624_BIT_PWMPRC_PRC_ENABLE (1<<7) +#define AW8624_BIT_PWMPRC_PRC_DISABLE (0<<7) +#define AW8624_BIT_PWMPRC_PRCTIME_MASK (~(0x7f<<0)) + + /* PWMDBG */ +#define AW8624_BIT_PWMDBG_PWM_MODE_MASK (~(3<<5)) +#define AW8624_BIT_PWMDBG_PWM_12K (3<<5) +#define AW8624_BIT_PWMDBG_PWM_24K (2<<5) +#define AW8624_BIT_PWMDBG_PWM_48K (0<<5) + +/* GLB_STATE 0x47*/ +#define AW8624_BIT_GLBRD5_STATE_MASK (~(15<<0)) +#define AW8624_BIT_GLBRD5_STATE_STANDBY (0<<0) +#define AW8624_BIT_GLBRD5_STATE_WAKEUP (1<<0) +#define AW8624_BIT_GLBRD5_STATE_STARTUP (2<<0) +#define AW8624_BIT_GLBRD5_STATE_WAIT (3<<0) +#define AW8624_BIT_GLBRD5_STATE_CONT_GO (6<<0) +#define AW8624_BIT_GLBRD5_STATE_RAM_GO (7<<0) +#define AW8624_BIT_GLBRD5_STATE_RTP_GO (8<<0) +#define AW8624_BIT_GLBRD5_STATE_TRIG_GO (9<<0) +#define AW8624_BIT_GLBRD5_STATE_I2S_GO (10<<0) +#define AW8624_BIT_GLBRD5_STATE_BRAKE (11<<0) +#define AW8624_BIT_GLBRD5_STATE_END (12<<0) + + /* WAVECTRL */ +#define AW8624_BIT_WAVECTRL_NUM_OV_DRIVER_MASK (~(0xF<<4)) +#define AW8624_BIT_WAVECTRL_NUM_OV_DRIVER (0<<4) + + /* CONT_CTRL */ +#define AW8624_BIT_CONT_CTRL_ZC_DETEC_MASK (~(1<<7)) +#define AW8624_BIT_CONT_CTRL_ZC_DETEC_ENABLE (1<<7) +#define AW8624_BIT_CONT_CTRL_ZC_DETEC_DISABLE (0<<7) +#define AW8624_BIT_CONT_CTRL_WAIT_PERIOD_MASK (~(3<<5)) +#define AW8624_BIT_CONT_CTRL_WAIT_8PERIOD (3<<5) +#define AW8624_BIT_CONT_CTRL_WAIT_4PERIOD (2<<5) +#define AW8624_BIT_CONT_CTRL_WAIT_2PERIOD (1<<5) +#define AW8624_BIT_CONT_CTRL_WAIT_1PERIOD (0<<5) +#define AW8624_BIT_CONT_CTRL_MODE_MASK (~(1<<4)) +#define AW8624_BIT_CONT_CTRL_BY_DRV_TIME (1<<4) +#define AW8624_BIT_CONT_CTRL_BY_GO_SIGNAL (0<<4) +#define AW8624_BIT_CONT_CTRL_EN_CLOSE_MASK (~(1<<3)) +#define AW8624_BIT_CONT_CTRL_CLOSE_PLAYBACK (1<<3) +#define AW8624_BIT_CONT_CTRL_OPEN_PLAYBACK (0<<3) +#define AW8624_BIT_CONT_CTRL_F0_DETECT_MASK (~(1<<2)) +#define AW8624_BIT_CONT_CTRL_F0_DETECT_ENABLE (1<<2) +#define AW8624_BIT_CONT_CTRL_F0_DETECT_DISABLE (0<<2) +#define AW8624_BIT_CONT_CTRL_O2C_MASK (~(1<<1)) +#define AW8624_BIT_CONT_CTRL_O2C_ENABLE (1<<1) +#define AW8624_BIT_CONT_CTRL_O2C_DISABLE (0<<1) +#define AW8624_BIT_CONT_CTRL_AUTO_BRK_MASK (~(1<<0)) +#define AW8624_BIT_CONT_CTRL_AUTO_BRK_ENABLE (1<<0) +#define AW8624_BIT_CONT_CTRL_AUTO_BRK_DISABLE (0<<0) + +#define AW8624_BIT_D2SCFG_CLK_ADC_MASK (~(7<<5)) +#define AW8624_BIT_D2SCFG_CLK_ASC_1P5MHZ (3<<5) + +#define AW8624_BIT_D2SCFG_GAIN_MASK (~(7<<0)) +#define AW8624_BIT_D2SCFG_GAIN_40 (7<<0) + /* DETCTRL */ +#define AW8624_BIT_DETCTRL_RL_OS_MASK (~(1<<6)) +#define AW8624_BIT_DETCTRL_RL_DETECT (1<<6) +#define AW8624_BIT_DETCTRL_OS_DETECT (0<<6) +#define AW8624_BIT_DETCTRL_PROTECT_MASK (~(1<<5)) +#define AW8624_BIT_DETCTRL_PROTECT_NO_ACTION (1<<5) +#define AW8624_BIT_DETCTRL_PROTECT_SHUTDOWN (0<<5) +#define AW8624_BIT_DETCTRL_VBAT_GO_MASK (~(1<<1)) +#define AW8624_BIT_DETCTRL_VABT_GO_ENABLE (1<<1) +#define AW8624_BIT_DETCTRL_VBAT_GO_DISBALE (0<<1) +#define AW8624_BIT_DETCTRL_DIAG_GO_MASK (~(1<<0)) +#define AW8624_BIT_DETCTRL_DIAG_GO_ENABLE (1<<0) +#define AW8624_BIT_DETCTRL_DIAG_GO_DISABLE (0<<0) + + +#define AW8624_BIT_RAMADDRH_MASK (~(63<<0)) + + /* VBAT MODE */ +#define AW8624_BIT_DETCTRL_VBAT_MODE_MASK (~(1<<6)) +#define AW8624_BIT_DETCTRL_VBAT_HW_COMP (1<<6) +#define AW8624_BIT_DETCTRL_VBAT_SW_COMP (0<<6) + + + /* ANACTRL */ +#define AW8624_BIT_ANACTRL_LRA_SRC_MASK (~(1<<5)) +#define AW8624_BIT_ANACTRL_LRA_SRC_REG (1<<5) +#define AW8624_BIT_ANACTRL_LRA_SRC_EFUSE (0<<5) +#define AW8624_BIT_ANACTRL_EN_IO_PD1_MASK (~(1<<0)) +#define AW8624_BIT_ANACTRL_EN_IO_PD1_HIGH (1<<0) +#define AW8624_BIT_ANACTRL_EN_IO_PD1_LOW (0<<0) + +/* PRLVL */ +#define AW8624_BIT_PRLVL_PR_EN_MASK (~(1<<7)) +#define AW8624_BIT_PRLVL_PR_ENABLE (1<<7) +#define AW8624_BIT_PRLVL_PR_DISABLE (0<<7) +#define AW8624_BIT_PRLVL_PRLVL_MASK (~(0x7f<<0)) + +/* PRTIME */ +#define AW8624_BIT_PRTIME_PRTIME_MASK (~(0xff<<0)) + +#define AW8624_BIT_BEMF_NUM_BRK_MASK (~(0xf<<0)) + +/* TD_H 0x4b TD_brake */ +#define AW8624_BIT_R_SPARE_MASK (~(1<<7)) +#define AW8624_BIT_R_SPARE_ENABLE (1<<7) + +/* TIME_NZC */ +#define AW8624_BIT_TIME_NZC_DEF_VAL (0x1F) + +#endif diff --git a/drivers/misc/awinic/aw862x/haptic_nv.c b/drivers/misc/awinic/aw862x/haptic_nv.c new file mode 100644 index 000000000000..2629bc474dfd --- /dev/null +++ b/drivers/misc/awinic/aw862x/haptic_nv.c @@ -0,0 +1,617 @@ +/* + * haptic_nv.c + * + * Copyright (c) 2021 AWINIC Technology CO., LTD + * + * Author: + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "haptic_nv.h" +#include "aw8624.h" +#include "aw8622x.h" +#include "aw86214.h" + +#define HAPTIC_NV_DRIVER_VERSION ("v1.5.1") + +/****************************************************** + * + * i2c read/write + * + ******************************************************/ +static int haptic_nv_i2c_read(struct awinic *awinic, + unsigned char reg_addr, unsigned char *reg_data) +{ + unsigned char cnt = 0; + int ret = -1; + + while (cnt < HAPTIC_NV_I2C_RETRIES) { + ret = i2c_smbus_read_byte_data(awinic->i2c, reg_addr); + if (ret < 0) { + aw_dev_err("%s: i2c_read cnt=%d error=%d\n", + __func__, cnt, ret); + } else { + *reg_data = ret; + break; + } + cnt++; + usleep_range(2000, 3000); + } + + return ret; +} + +static int haptic_nv_i2c_write(struct awinic *awinic, + unsigned char reg_addr, unsigned char reg_data) +{ + unsigned char cnt = 0; + int ret = -1; + + while (cnt < HAPTIC_NV_I2C_RETRIES) { + ret = + i2c_smbus_write_byte_data(awinic->i2c, reg_addr, reg_data); + if (ret < 0) { + aw_dev_err("%s: i2c_write cnt=%d error=%d\n", + __func__, cnt, ret); + } else { + break; + } + cnt++; + usleep_range(2000, 3000); + } + + return ret; +} + +static int haptic_nv_hw_reset(struct awinic *awinic) +{ + aw_dev_info("%s enter\n", __func__); + + if (awinic && gpio_is_valid(awinic->reset_gpio)) { + gpio_set_value_cansleep(awinic->reset_gpio, 0); + usleep_range(1000, 2000); + gpio_set_value_cansleep(awinic->reset_gpio, 1); + usleep_range(3500, 4000); + } else { + aw_dev_err("%s: failed\n", __func__); + } + return 0; +} + +static int haptic_nv_haptic_softreset(struct awinic *awinic) +{ + aw_dev_info("%s enter\n", __func__); + haptic_nv_i2c_write(awinic, HAPTIC_NV_REG_ID, 0xAA); + usleep_range(2000, 2500); + return 0; +} + +static int haptic_nv_read_chipid(struct awinic *awinic, + unsigned char *reg, unsigned char type) +{ + unsigned char cnt = 0; + int ret = -1; + + while (cnt < HAPTIC_NV_I2C_RETRIES) { + ret = i2c_smbus_read_byte_data(awinic->i2c, HAPTIC_NV_REG_ID); + if (ret < 0) { + if (type == HAPTIC_NV_FIRST_TRY) { + aw_dev_info("%s: reading chip id\n", __func__); + } else if (type == HAPTIC_NV_LAST_TRY) { + aw_dev_err("%s: i2c_read cnt=%d error=%d\n", + __func__, cnt, ret); + } else { + aw_dev_err("%s: type is error\n", __func__); + } + } else { + *reg = ret; + break; + } + cnt++; + usleep_range(2000, 3000); + } + + return ret; +} + +static int haptic_nv_parse_chipid(struct awinic *awinic) +{ + unsigned char cnt = 0; + unsigned char reg = 0; + unsigned char ef_id = 0xff; + int ret = -1; + + while (cnt < HAPTIC_NV_CHIPID_RETRIES) { + /* hardware reset */ + haptic_nv_hw_reset(awinic); + + ret = haptic_nv_read_chipid(awinic, ®, HAPTIC_NV_FIRST_TRY); + if (ret < 0) { + awinic->i2c->addr = (u16)awinic->aw862xx_i2c_addr; + aw_dev_info("%s: try to replace i2c addr [(0x%02X)] to read chip id again\n", + __func__, awinic->i2c->addr); + ret = haptic_nv_read_chipid(awinic, ®, + HAPTIC_NV_LAST_TRY); + if (ret < 0) + break; + } + switch (reg) { + case AW8624_CHIP_ID: + aw_dev_info("%s aw8624 detected\n", __func__); + awinic->name = AW8624; + haptic_nv_haptic_softreset(awinic); + return 0; + case AW8622X_CHIP_ID: + /* Distinguish products by AW862XX_REG_EFRD9. */ + haptic_nv_i2c_read(awinic, AW862XX_REG_EFRD9, &ef_id); + if ((ef_id & 0x41) == AW86224_5_EF_ID) { + awinic->name = AW86224_5; + aw_dev_info("%s aw86224_5 detected\n", + __func__); + haptic_nv_haptic_softreset(awinic); + return 0; + } + if ((ef_id & 0x41) == AW86223_EF_ID) { + awinic->name = AW86223; + aw_dev_info("%s aw86223 detected\n", + __func__); + haptic_nv_haptic_softreset(awinic); + return 0; + } + aw_dev_info("%s unsupported ef_id = (0x%02X)\n", + __func__, ef_id); + break; + case AW86214_CHIP_ID: + if ((ef_id & 0x41) == AW86214_EF_ID) { + awinic->name = AW86214; + aw_dev_info("%s aw86214 detected\n", __func__); + haptic_nv_haptic_softreset(awinic); + return 0; + } + aw_dev_info("%s unsupported ef_id = (0x%02X)\n", + __func__, ef_id); + break; + default: + aw_dev_info("%s unsupported device revision (0x%x)\n", + __func__, reg); + break; + } + cnt++; + + usleep_range(2000, 3000); + } + + return -EINVAL; +} +static int haptic_nv_parse_dt(struct awinic *awinic, struct device *dev, + struct device_node *np) +{ + unsigned int val = 0; + + awinic->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); + if (awinic->reset_gpio >= 0) { + aw_dev_info("%s: reset gpio provided ok\n", __func__); + } else { + awinic->reset_gpio = -1; + aw_dev_err("%s: no reset gpio provided, will not HW reset device\n", + __func__); + return -ERANGE; + } + + awinic->irq_gpio = of_get_named_gpio(np, "irq-gpio", 0); + if (awinic->irq_gpio < 0) { + aw_dev_err("%s: no irq gpio provided.\n", __func__); + awinic->IsUsedIRQ = false; + } else { + aw_dev_info("%s: irq gpio provided ok.\n", __func__); + awinic->IsUsedIRQ = true; + } + + val = of_property_read_u32(np, + "aw862xx_i2c_addr", &awinic->aw862xx_i2c_addr); + if (val) + aw_dev_err("%s:configure aw862xx_i2c_addr error\n", __func__); + else + aw_dev_info("%s: configure aw862xx_i2c_addr ok\n", __func__); + return 0; +} + +static int +haptic_nv_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +{ + int ret = -1; + int irq_flags = 0; + struct awinic *awinic; + struct device_node *np = i2c->dev.of_node; + + aw_dev_info("%s enter\n", __func__); + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) { + aw_dev_err("check_functionality failed\n"); + return -EIO; + } + + awinic = devm_kzalloc(&i2c->dev, sizeof(struct awinic), GFP_KERNEL); + if (awinic == NULL) + return -ENOMEM; + + awinic->dev = &i2c->dev; + awinic->i2c = i2c; + + i2c_set_clientdata(i2c, awinic); + /* aw862xx rst & int */ + if (np) { + ret = haptic_nv_parse_dt(awinic, &i2c->dev, np); + if (ret) { + aw_dev_err("%s: failed to parse device tree node\n", + __func__); + goto err_parse_dt; + } + } + if (gpio_is_valid(awinic->reset_gpio)) { + ret = devm_gpio_request_one(&i2c->dev, awinic->reset_gpio, + GPIOF_OUT_INIT_LOW, "haptic_nv_rst"); + if (ret) { + aw_dev_err("%s: rst request failed\n", __func__); + goto err_reset_gpio_request; + } + } + + if (gpio_is_valid(awinic->irq_gpio)) { + ret = devm_gpio_request_one(&i2c->dev, awinic->irq_gpio, + GPIOF_DIR_IN, "haptic_nv_int"); + if (ret) { + aw_dev_err("%s: int request failed\n", __func__); + goto err_irq_gpio_request; + } + } + /* parse chip id */ + ret = haptic_nv_parse_chipid(awinic); + if (ret < 0) { + aw_dev_err("%s: haptic_nv_read_chipid failed\n", __func__); + goto err_id; + } + /*aw8624*/ + if (awinic->name == AW8624) { + awinic->aw8624 = devm_kzalloc(&i2c->dev, + sizeof(struct aw8624), GFP_KERNEL); + if (awinic->aw8624 == NULL) { + if (gpio_is_valid(awinic->irq_gpio)) + devm_gpio_free(&i2c->dev, awinic->irq_gpio); + if (gpio_is_valid(awinic->reset_gpio)) + devm_gpio_free(&i2c->dev, awinic->reset_gpio); + devm_kfree(&i2c->dev, awinic); + awinic = NULL; + return -ENOMEM; + } + awinic->aw8624->dev = awinic->dev; + awinic->aw8624->i2c = awinic->i2c; + awinic->aw8624->reset_gpio = awinic->reset_gpio; + awinic->aw8624->irq_gpio = awinic->irq_gpio; + awinic->aw8624->IsUsedIRQ = awinic->IsUsedIRQ; + if (np) { + ret = aw8624_parse_dt(awinic->aw8624, &i2c->dev, np); + if (ret) { + aw_dev_err("%s: failed to parse device tree node\n", + __func__); + goto err_aw8624_parse_dt; + } + } + + /* aw8624 irq */ + if (gpio_is_valid(awinic->aw8624->irq_gpio) && + !(awinic->aw8624->flags & AW8624_FLAG_SKIP_INTERRUPTS)) { + /* register irq handler */ + aw8624_interrupt_setup(awinic->aw8624); + irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; + ret = devm_request_threaded_irq(&i2c->dev, + gpio_to_irq(awinic->aw8624->irq_gpio), + NULL, aw8624_irq, irq_flags, + "aw8624", awinic->aw8624); + if (ret != 0) { + aw_dev_err("%s: failed to request IRQ %d: %d\n", + __func__, + gpio_to_irq(awinic->aw8624->irq_gpio), + ret); + goto err_aw8624_irq; + } + } + aw8624_vibrator_init(awinic->aw8624); + aw8624_haptic_init(awinic->aw8624); + aw8624_ram_init(awinic->aw8624); + + } + /* aw8622x */ + if (awinic->name == AW86223 || awinic->name == AW86224_5) { + awinic->aw8622x = devm_kzalloc(&i2c->dev, + sizeof(struct aw8622x), GFP_KERNEL); + if (awinic->aw8622x == NULL) { + if (gpio_is_valid(awinic->irq_gpio)) + devm_gpio_free(&i2c->dev, awinic->irq_gpio); + if (gpio_is_valid(awinic->reset_gpio)) + devm_gpio_free(&i2c->dev, awinic->reset_gpio); + devm_kfree(&i2c->dev, awinic); + awinic = NULL; + return -ENOMEM; + } + awinic->aw8622x->dev = awinic->dev; + awinic->aw8622x->i2c = awinic->i2c; + awinic->aw8622x->reset_gpio = awinic->reset_gpio; + awinic->aw8622x->irq_gpio = awinic->irq_gpio; + awinic->aw8622x->isUsedIntn = awinic->IsUsedIRQ; + awinic->aw8622x->name = awinic->name; + /* chip qualify */ + if (!aw8622x_check_qualify(awinic->aw8622x)) { + aw_dev_err("%s:unqualified chip!\n", __func__); + goto err_aw8622x_check_qualify; + } + if (np) { + ret = aw8622x_parse_dt(awinic->aw8622x, &i2c->dev, np); + if (ret) { + aw_dev_err("%s: failed to parse device tree node\n", + __func__); + goto err_aw8622x_parse_dt; + } + } + /* aw8622x irq */ + if (gpio_is_valid(awinic->aw8622x->irq_gpio) && + !(awinic->aw8622x->flags & AW8622X_FLAG_SKIP_INTERRUPTS)) { + /* register irq handler */ + aw8622x_interrupt_setup(awinic->aw8622x); + irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; + ret = devm_request_threaded_irq(&i2c->dev, + gpio_to_irq(awinic->aw8622x->irq_gpio), + NULL, aw8622x_irq, irq_flags, + "aw8622x", awinic->aw8622x); + if (ret != 0) { + aw_dev_err("%s: failed to request IRQ %d: %d\n", + __func__, + gpio_to_irq(awinic->aw8622x->irq_gpio), + ret); + goto err_aw8622x_irq; + } + } else { + aw_dev_info("%s skipping IRQ registration\n", __func__); + /* disable feature support if gpio was invalid */ + awinic->aw8622x->flags |= AW8622X_FLAG_SKIP_INTERRUPTS; + } + aw8622x_vibrator_init(awinic->aw8622x); + aw8622x_haptic_init(awinic->aw8622x); + aw8622x_ram_work_init(awinic->aw8622x); + } + /* aw86214 */ + if (awinic->name == AW86214) { + awinic->aw86214 = devm_kzalloc(&i2c->dev, + sizeof(struct aw86214), GFP_KERNEL); + if (awinic->aw86214 == NULL) { + if (gpio_is_valid(awinic->reset_gpio)) + devm_gpio_free(&i2c->dev, awinic->reset_gpio); + devm_kfree(&i2c->dev, awinic); + awinic = NULL; + return -ENOMEM; + } + awinic->aw86214->dev = awinic->dev; + awinic->aw86214->i2c = awinic->i2c; + awinic->aw86214->reset_gpio = awinic->reset_gpio; + awinic->aw86214->irq_gpio = awinic->irq_gpio; + /* chip qualify */ + if (!aw86214_check_qualify(awinic->aw86214)) { + aw_dev_err("%s:unqualified chip!\n", __func__); + goto err_aw86214_check_qualify; + } + if (np) { + ret = aw86214_parse_dt(awinic->aw86214, &i2c->dev, np); + if (ret) { + aw_dev_err("%s: failed to parse device tree node\n", + __func__); + goto err_aw86214_parse_dt; + } + } + /* aw86214 irq */ + if (gpio_is_valid(awinic->aw86214->irq_gpio) && + !(awinic->aw86214->flags & AW8622X_FLAG_SKIP_INTERRUPTS)) { + /* register irq handler */ + aw86214_interrupt_setup(awinic->aw86214); + irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; + ret = devm_request_threaded_irq(&i2c->dev, + gpio_to_irq(awinic->aw86214->irq_gpio), + NULL, aw86214_irq, irq_flags, + "aw86214", awinic->aw86214); + if (ret != 0) { + aw_dev_err("%s: failed to request IRQ %d: %d\n", + __func__, + gpio_to_irq(awinic->aw86214->irq_gpio), + ret); + goto err_aw86214_irq; + } + } else { + aw_dev_info("%s skipping IRQ registration\n", __func__); + /* disable feature support if gpio was invalid */ + awinic->aw86214->flags |= AW8622X_FLAG_SKIP_INTERRUPTS; + } + aw86214_vibrator_init(awinic->aw86214); + aw86214_haptic_init(awinic->aw86214); + aw86214_ram_work_init(awinic->aw86214); + } + dev_set_drvdata(&i2c->dev, awinic); + aw_dev_info("%s probe completed successfully!\n", __func__); + + return 0; + +err_aw86214_irq: +err_aw86214_parse_dt: +err_aw86214_check_qualify: + if (awinic->name == AW86214) { + devm_kfree(&i2c->dev, awinic->aw86214); + awinic->aw8622x = NULL; + } +err_aw8622x_irq: +err_aw8622x_parse_dt: +err_aw8622x_check_qualify: + if (awinic->name == AW86223 || awinic->name == AW86224_5) { + devm_kfree(&i2c->dev, awinic->aw8622x); + awinic->aw8622x = NULL; + } +err_aw8624_irq: +err_aw8624_parse_dt: + if (awinic->name == AW8624) { + devm_kfree(&i2c->dev, awinic->aw8624); + awinic->aw8624 = NULL; + } + +err_id: + if (gpio_is_valid(awinic->irq_gpio)) + devm_gpio_free(&i2c->dev, awinic->irq_gpio); +err_irq_gpio_request: + if (gpio_is_valid(awinic->reset_gpio)) + devm_gpio_free(&i2c->dev, awinic->reset_gpio); +err_reset_gpio_request: +err_parse_dt: + devm_kfree(&i2c->dev, awinic); + awinic = NULL; + return ret; + +} + +static int haptic_nv_i2c_remove(struct i2c_client *i2c) +{ + struct awinic *awinic = i2c_get_clientdata(i2c); + + aw_dev_info("%s enter\n", __func__); + + if (awinic->name == AW8624) { + aw_dev_info("%s remove aw86214\n", __func__); + cancel_delayed_work_sync(&awinic->aw8624->ram_work); + cancel_work_sync(&awinic->aw8624->haptic_audio.work); + hrtimer_cancel(&awinic->aw8624->haptic_audio.timer); + if (awinic->aw8624->IsUsedIRQ) + cancel_work_sync(&awinic->aw8624->rtp_work); + cancel_work_sync(&awinic->aw8624->vibrator_work); + hrtimer_cancel(&awinic->aw8624->timer); + mutex_destroy(&awinic->aw8624->lock); + mutex_destroy(&awinic->aw8624->rtp_lock); + mutex_destroy(&awinic->aw8624->haptic_audio.lock); + sysfs_remove_group(&awinic->aw8624->i2c->dev.kobj, + &aw8624_vibrator_attribute_group); +#ifdef TIMED_OUTPUT + timed_output_dev_unregister(&awinic->aw8624->vib_dev); +#endif + devm_free_irq(&awinic->aw8624->i2c->dev, + gpio_to_irq(awinic->aw8624->irq_gpio), awinic->aw8624); + + } else if (awinic->name == AW86223 || awinic->name == AW86224_5) { + aw_dev_info("%s remove aw8622x\n", __func__); + cancel_delayed_work_sync(&awinic->aw8622x->ram_work); + cancel_work_sync(&awinic->aw8622x->haptic_audio.work); + hrtimer_cancel(&awinic->aw8622x->haptic_audio.timer); + if (awinic->aw8622x->isUsedIntn) + cancel_work_sync(&awinic->aw8622x->rtp_work); + cancel_work_sync(&awinic->aw8622x->vibrator_work); + + hrtimer_cancel(&awinic->aw8622x->timer); + mutex_destroy(&awinic->aw8622x->lock); + mutex_destroy(&awinic->aw8622x->rtp_lock); + mutex_destroy(&awinic->aw8622x->haptic_audio.lock); + sysfs_remove_group(&awinic->aw8622x->i2c->dev.kobj, + &aw8622x_vibrator_attribute_group); +#ifdef TIMED_OUTPUT + timed_output_dev_unregister(&awinic->aw8622x->vib_dev); +#endif + devm_free_irq(&awinic->aw8622x->i2c->dev, + gpio_to_irq(awinic->aw8622x->irq_gpio), + awinic->aw8622x); + + } else if (awinic->name == AW86214) { + aw_dev_info("%s remove aw86214\n", __func__); + cancel_delayed_work_sync(&awinic->aw86214->ram_work); + cancel_work_sync(&awinic->aw86214->haptic_audio.work); + hrtimer_cancel(&awinic->aw86214->haptic_audio.timer); + cancel_work_sync(&awinic->aw86214->vibrator_work); + + hrtimer_cancel(&awinic->aw86214->timer); + mutex_destroy(&awinic->aw86214->lock); + mutex_destroy(&awinic->aw86214->haptic_audio.lock); + sysfs_remove_group(&awinic->aw86214->i2c->dev.kobj, + &aw86214_vibrator_attribute_group); +#ifdef TIMED_OUTPUT + timed_output_dev_unregister(&awinic->aw86214->vib_dev); +#endif + devm_free_irq(&awinic->aw86214->i2c->dev, + gpio_to_irq(awinic->aw86214->irq_gpio), + awinic->aw86214); + + } else { + aw_dev_err("%s no chip\n", __func__); + return -ERANGE; + } + aw_dev_info("%s exit\n", __func__); + return 0; +} + +static const struct i2c_device_id haptic_nv_i2c_id[] = { + { HAPTIC_NV_I2C_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, haptic_nv_i2c_id); + +static const struct of_device_id haptic_nv_dt_match[] = { + { .compatible = "awinic,haptic_nv" }, + { }, +}; + +static struct i2c_driver haptic_nv_i2c_driver = { + .driver = { + .name = HAPTIC_NV_I2C_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(haptic_nv_dt_match), + }, + .probe = haptic_nv_i2c_probe, + .remove = haptic_nv_i2c_remove, + .id_table = haptic_nv_i2c_id, +}; + +static int __init haptic_nv_i2c_init(void) +{ + int ret = 0; + + aw_dev_info("awinic driver version %s\n", HAPTIC_NV_DRIVER_VERSION); + + ret = i2c_add_driver(&haptic_nv_i2c_driver); + if (ret) { + aw_dev_err("fail to add awinic device into i2c\n"); + return ret; + } + + return 0; +} + +late_initcall(haptic_nv_i2c_init); + +static void __exit haptic_nv_i2c_exit(void) +{ + i2c_del_driver(&haptic_nv_i2c_driver); +} +module_exit(haptic_nv_i2c_exit); + +MODULE_DESCRIPTION("Awinic Haptic Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/misc/awinic/aw862x/haptic_nv.h b/drivers/misc/awinic/aw862x/haptic_nv.h new file mode 100644 index 000000000000..b61e85d6fda7 --- /dev/null +++ b/drivers/misc/awinic/aw862x/haptic_nv.h @@ -0,0 +1,164 @@ +#ifndef _HAPTIC_NV_H_ +#define _HAPTIC_NV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************* + * + * kernel marco + * + ********************************************************/ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(4, 4, 1) +#define TIMED_OUTPUT +#endif + +#ifdef TIMED_OUTPUT +#include <../../../drivers/staging/android/timed_output.h> +typedef struct timed_output_dev cdev_t; +#else +typedef struct led_classdev cdev_t; +#endif + +/********************************************************* + * + * normal marco + * + ********************************************************/ +#define HAPTIC_NV_I2C_NAME ("awinic_haptic") +#define HAPTIC_NV_AWRW_SIZE (220) +#define HAPTIC_NV_CHIPID_RETRIES (5) +#define HAPTIC_NV_I2C_RETRIES (2) +#define HAPTIC_NV_REG_ID (0x00) +#define AW8624_CHIP_ID (0x24) +#define AW8622X_CHIP_ID (0x00) +#define AW86214_CHIP_ID (0x01) +#define AW862XX_REG_EFRD9 (0x64) +#define REG_NONE_ACCESS (0) +#define REG_RD_ACCESS (1 << 0) +#define REG_WR_ACCESS (1 << 1) +#define AW_REG_MAX (0xFF) +#define AW_RAMDATA_RD_BUFFER_SIZE (1024) +#define AW_RAMDATA_WR_BUFFER_SIZE (2048) +#define AW_GUN_TYPE_DEF_VAL (0xFF) +#define AW_BULLET_NR_DEF_VAL (0) +#define AW_I2C_READ_MSG_NUM (2) +#define AW_I2C_BYTE_ONE (1) +#define AW_I2C_BYTE_TWO (2) +#define AW_I2C_BYTE_THREE (3) +#define AW_I2C_BYTE_FOUR (4) +#define AW_I2C_BYTE_FIVE (5) +#define AW_I2C_BYTE_SIX (6) +#define AW_I2C_BYTE_SEVEN (7) +#define AW_I2C_BYTE_EIGHT (8) +#define AWRW_CMD_UNIT (5) +#define AW_SET_RAMADDR_H(addr) ((addr) >> 8) +#define AW_SET_RAMADDR_L(addr) ((addr) & 0x00FF) +#define AW_SET_BASEADDR_H(addr) ((addr) >> 8) +#define AW_SET_BASEADDR_L(addr) ((addr) & 0x00FF) +/********************************************************* + * + * macro control + * + ********************************************************/ +#define AW_CHECK_RAM_DATA +#define AW_READ_BIN_FLEXBALLY +#define AW_ENABLE_RTP_PRINT_LOG +/* #define AW8624_MUL_GET_F0 */ + +#define aw_dev_err(format, ...) \ + pr_err("[haptic_nv]" format, ##__VA_ARGS__) + +#define aw_dev_info(format, ...) \ + pr_info("[haptic_nv]" format, ##__VA_ARGS__) + +#define aw_dev_dbg(format, ...) \ + pr_debug("[haptic_nv]" format, ##__VA_ARGS__) +/********************************************************* + * + * enum + * + ********************************************************/ +enum haptic_nv_chip_name { + AW_CHIP_NULL = 0, + AW86223 = 1, + AW86224_5 = 2, + AW86214 = 3, + AW8624 = 4, +}; + +enum haptic_nv_read_chip_type { + HAPTIC_NV_FIRST_TRY = 0, + HAPTIC_NV_LAST_TRY = 1, +}; + +enum aw862xx_ef_id { + AW86223_EF_ID = 0x01, + AW86224_5_EF_ID = 0x00, + AW86214_EF_ID = 0x41, +}; +/********************************************************* + * + * struct + * + ********************************************************/ +struct awinic { + bool IsUsedIRQ; + unsigned char name; + + unsigned int aw862xx_i2c_addr; + int reset_gpio; + int irq_gpio; + int reset_gpio_ret; + int irq_gpio_ret; + + struct i2c_client *i2c; + struct device *dev; + struct aw8624 *aw8624; + struct aw8622x *aw8622x; + struct aw86214 *aw86214; +}; + +struct ram { + unsigned int len; + unsigned int check_sum; + unsigned int base_addr; + unsigned char version; + unsigned char ram_shift; + unsigned char baseaddr_shift; + unsigned char ram_num; +}; + +struct haptic_ctr { + unsigned char cnt; + unsigned char cmd; + unsigned char play; + unsigned char wavseq; + unsigned char loop; + unsigned char gain; + struct list_head list; +}; + +struct haptic_audio { + struct mutex lock; + struct hrtimer timer; + struct work_struct work; + int delay_val; + int timer_val; + struct haptic_ctr ctr; + struct list_head ctr_list; +}; + +struct aw_i2c_package { + unsigned char flag; + unsigned char reg_num; + unsigned char first_addr; + unsigned char reg_data[HAPTIC_NV_AWRW_SIZE]; +}; +#endif