-/*\r
- * aw8695.c aw8695 haptic module\r
- *\r
- * Version: v1.2.4\r
- *\r
- * Copyright (c) 2018 AWINIC Technology CO., LTD\r
- *\r
- * Author: Nick Li <liweilei@awinic.com.cn>\r
- *\r
- * This program is free software; you can redistribute it and/or modify it\r
- * under the terms of the GNU General Public License as published by the\r
- * Free Software Foundation; either version 2 of the License, or (at your\r
- * option) any later version.\r
- */\r
-\r
-#include <linux/module.h>\r
-#include <linux/kernel.h>\r
-#include <linux/i2c.h>\r
-#include <linux/of_gpio.h>\r
-#include <linux/delay.h>\r
-#include <linux/device.h>\r
-#include <linux/firmware.h>\r
-#include <linux/slab.h>\r
-#include <linux/version.h>\r
-#include <linux/input.h>\r
-#include <linux/interrupt.h>\r
-#include <linux/debugfs.h>\r
-#include <linux/miscdevice.h>\r
-#include <asm/uaccess.h>\r
-#include <linux/syscalls.h>\r
-#include <linux/power_supply.h>\r
-#include "aw8695.h"\r
-#include "aw8695_reg.h"\r
-#include "aw8695_config.h"\r
-\r
-/******************************************************\r
- *\r
- * Marco\r
- *\r
- ******************************************************/\r
-#define AW8695_I2C_NAME "aw8695_haptic"\r
-#define AW8695_HAPTIC_NAME "aw8695_haptic"\r
-\r
-#define AW8695_VERSION "v1.2.4"\r
-\r
-\r
-#define AWINIC_RAM_UPDATE_DELAY\r
-\r
-#define AW_I2C_RETRIES 2\r
-#define AW_I2C_RETRY_DELAY 2\r
-#define AW_READ_CHIPID_RETRIES 5\r
-#define AW_READ_CHIPID_RETRY_DELAY 2\r
-\r
-#define AW8695_MAX_DSP_START_TRY_COUNT 10\r
-\r
-\r
-\r
-#define AW8695_MAX_FIRMWARE_LOAD_CNT 20\r
-\r
-/******************************************************\r
- *\r
- * variable\r
- *\r
- ******************************************************/\r
-#define AW8695_RTP_NAME_MAX 64\r
-static char *aw8695_ram_name = "aw8695_haptic.bin";\r
-static char aw8695_rtp_name[][AW8695_RTP_NAME_MAX] = {\r
- {"aw8695_rtp.bin"},\r
- {"aw8695_rtp_lighthouse.bin"},\r
- {"aw8695_rtp_silk.bin"},\r
-};\r
-\r
-struct aw8695_container *aw8695_rtp;\r
-struct aw8695 *g_aw8695;\r
-\r
-/******************************************************\r
- *\r
- * functions\r
- *\r
- ******************************************************/\r
-static void aw8695_interrupt_clear(struct aw8695 *aw8695);\r
-static int aw8695_haptic_trig_enable_config(struct aw8695 *aw8695);\r
-\r
-\r
- /******************************************************\r
- *\r
- * aw8695 i2c write/read\r
- *\r
- ******************************************************/\r
-static int aw8695_i2c_write(struct aw8695 *aw8695,\r
- unsigned char reg_addr, unsigned char reg_data)\r
-{\r
- int ret = -1;\r
- unsigned char cnt = 0;\r
-\r
- while(cnt < AW_I2C_RETRIES) {\r
- ret = i2c_smbus_write_byte_data(aw8695->i2c, reg_addr, reg_data);\r
- if(ret < 0) {\r
- pr_err("%s: i2c_write cnt=%d error=%d\n", __func__, cnt, ret);\r
- } else {\r
- break;\r
- }\r
- cnt ++;\r
- msleep(AW_I2C_RETRY_DELAY);\r
- }\r
-\r
- return ret;\r
-}\r
-\r
-static int aw8695_i2c_read(struct aw8695 *aw8695,\r
- unsigned char reg_addr, unsigned char *reg_data)\r
-{\r
- int ret = -1;\r
- unsigned char cnt = 0;\r
-\r
- while(cnt < AW_I2C_RETRIES) {\r
- ret = i2c_smbus_read_byte_data(aw8695->i2c, reg_addr);\r
- if(ret < 0) {\r
- pr_err("%s: i2c_read cnt=%d error=%d\n", __func__, cnt, ret);\r
- } else {\r
- *reg_data = ret;\r
- break;\r
- }\r
- cnt ++;\r
- msleep(AW_I2C_RETRY_DELAY);\r
- }\r
-\r
- return ret;\r
-}\r
-\r
-static int aw8695_i2c_write_bits(struct aw8695 *aw8695,\r
- unsigned char reg_addr, unsigned int mask, unsigned char reg_data)\r
-{\r
- unsigned char reg_val = 0;\r
-\r
- aw8695_i2c_read(aw8695, reg_addr, ®_val);\r
- reg_val &= mask;\r
- reg_val |= reg_data;\r
- aw8695_i2c_write(aw8695, reg_addr, reg_val);\r
-\r
- return 0;\r
-}\r
-\r
-static int aw8695_i2c_writes(struct aw8695 *aw8695,\r
- unsigned char reg_addr, unsigned char *buf, unsigned int len)\r
-{\r
- int ret = -1;\r
- unsigned char *data;\r
-\r
- data = kmalloc(len+1, GFP_KERNEL);\r
- if (data == NULL) {\r
- pr_err("%s: can not allocate memory\n", __func__);\r
- return -ENOMEM;\r
- }\r
-\r
- data[0] = reg_addr;\r
- memcpy(&data[1], buf, len);\r
-\r
- ret = i2c_master_send(aw8695->i2c, data, len+1);\r
- if (ret < 0) {\r
- pr_err("%s: i2c master send error\n", __func__);\r
- }\r
-\r
- kfree(data);\r
-\r
- return ret;\r
-}\r
-\r
-/*****************************************************\r
- *\r
- * ram update\r
- *\r
- *****************************************************/\r
-static void aw8695_rtp_loaded(const struct firmware *cont, void *context)\r
-{\r
- struct aw8695 *aw8695 = context;\r
- pr_info("%s enter\n", __func__);\r
-\r
- if (!cont) {\r
- pr_err("%s: failed to read %s\n", __func__, aw8695_rtp_name[aw8695->rtp_file_num]);\r
- release_firmware(cont);\r
- return;\r
- }\r
-\r
- pr_info("%s: loaded %s - size: %zu\n", __func__, aw8695_rtp_name[aw8695->rtp_file_num],\r
- cont ? cont->size : 0);\r
-\r
- /* aw8695 rtp update */\r
- aw8695_rtp = kzalloc(cont->size+sizeof(int), GFP_KERNEL);\r
- if (!aw8695_rtp) {\r
- release_firmware(cont);\r
- pr_err("%s: Error allocating memory\n", __func__);\r
- return;\r
- }\r
- aw8695_rtp->len = cont->size;\r
- pr_info("%s: rtp size = %d\n", __func__, aw8695_rtp->len);\r
- memcpy(aw8695_rtp->data, cont->data, cont->size);\r
- release_firmware(cont);\r
-\r
- aw8695->rtp_init = 1;\r
- pr_info("%s: rtp update complete\n", __func__);\r
-}\r
-\r
-static int aw8695_rtp_update(struct aw8695 *aw8695)\r
-{\r
- pr_info("%s enter\n", __func__);\r
-\r
- return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,\r
- aw8695_rtp_name[aw8695->rtp_file_num], aw8695->dev, GFP_KERNEL,\r
- aw8695, aw8695_rtp_loaded);\r
-}\r
-\r
-\r
- static void aw8695_container_update(struct aw8695 *aw8695,\r
- struct aw8695_container *aw8695_cont)\r
-{\r
- int i = 0;\r
- unsigned int shift = 0;\r
-\r
- pr_info("%s enter\n", __func__);\r
-\r
- mutex_lock(&aw8695->lock);\r
-\r
- aw8695->ram.baseaddr_shift = 2;\r
- aw8695->ram.ram_shift = 4;\r
-\r
- /* RAMINIT Enable */\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_RAMINIT_MASK, AW8695_BIT_SYSCTRL_RAMINIT_EN);\r
-\r
- /* base addr */\r
- shift = aw8695->ram.baseaddr_shift;\r
- aw8695->ram.base_addr = (unsigned int)((aw8695_cont->data[0+shift]<<8) |\r
- (aw8695_cont->data[1+shift]));\r
- pr_info("%s: base_addr=0x%4x\n", __func__, aw8695->ram.base_addr);\r
-\r
- aw8695_i2c_write(aw8695, AW8695_REG_BASE_ADDRH, aw8695_cont->data[0+shift]);\r
- aw8695_i2c_write(aw8695, AW8695_REG_BASE_ADDRL, aw8695_cont->data[1+shift]);\r
-\r
- aw8695_i2c_write(aw8695, AW8695_REG_FIFO_AEH,\r
- (unsigned char)((aw8695->ram.base_addr>>2)>>8));\r
- aw8695_i2c_write(aw8695, AW8695_REG_FIFO_AEL,\r
- (unsigned char)((aw8695->ram.base_addr>>2)&0x00FF));\r
- aw8695_i2c_write(aw8695, AW8695_REG_FIFO_AFH,\r
- (unsigned char)((aw8695->ram.base_addr-(aw8695->ram.base_addr>>2))>>8));\r
- aw8695_i2c_write(aw8695, AW8695_REG_FIFO_AFL,\r
- (unsigned char)((aw8695->ram.base_addr-(aw8695->ram.base_addr>>2))&0x00FF));\r
-\r
- /* ram */\r
- shift = aw8695->ram.baseaddr_shift;\r
- aw8695_i2c_write(aw8695, AW8695_REG_RAMADDRH, aw8695_cont->data[0+shift]);\r
- aw8695_i2c_write(aw8695, AW8695_REG_RAMADDRL, aw8695_cont->data[1+shift]);\r
- shift = aw8695->ram.ram_shift;\r
- for(i=shift; i<aw8695_cont->len; i++) {\r
- aw8695_i2c_write(aw8695, AW8695_REG_RAMDATA, aw8695_cont->data[i]);\r
- }\r
-\r
-#if 0\r
- /* ram check */\r
- shift = aw8695->ram.baseaddr_shift;\r
- aw8695_i2c_write(aw8695, AW8695_REG_RAMADDRH, aw8695_cont->data[0+shift]);\r
- aw8695_i2c_write(aw8695, AW8695_REG_RAMADDRL, aw8695_cont->data[1+shift]);\r
- shift = aw8695->ram.ram_shift;\r
- for(i=shift; i<aw8695_cont->len; i++) {\r
- aw8695_i2c_read(aw8695, AW8695_REG_RAMDATA, ®_val);\r
- if(reg_val != aw8695_cont->data[i]) {\r
- pr_err("%s: ram check error addr=0x%04x, file_data=0x%02x, ram_data=0x%02x\n",\r
- __func__, i, aw8695_cont->data[i], reg_val);\r
- return;\r
- }\r
- }\r
-#endif\r
-\r
- /* RAMINIT Disable */\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_RAMINIT_MASK, AW8695_BIT_SYSCTRL_RAMINIT_OFF);\r
-\r
- mutex_unlock(&aw8695->lock);\r
-\r
- pr_info("%s exit\n", __func__);\r
-}\r
-\r
-\r
-static void aw8695_ram_loaded(const struct firmware *cont, void *context)\r
-{\r
- struct aw8695 *aw8695 = context;\r
- struct aw8695_container *aw8695_fw;\r
- int i = 0;\r
- unsigned short check_sum = 0;\r
-\r
- pr_info("%s enter\n", __func__);\r
-\r
- if (!cont) {\r
- pr_err("%s: failed to read %s\n", __func__, aw8695_ram_name);\r
- release_firmware(cont);\r
- return;\r
- }\r
-\r
- pr_info("%s: loaded %s - size: %zu\n", __func__, aw8695_ram_name,\r
- cont ? cont->size : 0);\r
-/*\r
- for(i=0; i<cont->size; i++) {\r
- pr_info("%s: addr:0x%04x, data:0x%02x\n", __func__, i, *(cont->data+i));\r
- }\r
-*/\r
-\r
- /* check sum */\r
- for(i=2; i<cont->size; i++) {\r
- check_sum += cont->data[i];\r
- }\r
- if(check_sum != (unsigned short)((cont->data[0]<<8)|(cont->data[1]))) {\r
- pr_err("%s: check sum err: check_sum=0x%04x\n", __func__, check_sum);\r
- return;\r
- } else {\r
- pr_info("%s: check sum pass : 0x%04x\n", __func__, check_sum);\r
- aw8695->ram.check_sum = check_sum;\r
- }\r
-\r
- /* aw8695 ram update */\r
- aw8695_fw = kzalloc(cont->size+sizeof(int), GFP_KERNEL);\r
- if (!aw8695_fw) {\r
- release_firmware(cont);\r
- pr_err("%s: Error allocating memory\n", __func__);\r
- return;\r
- }\r
- aw8695_fw->len = cont->size;\r
- memcpy(aw8695_fw->data, cont->data, cont->size);\r
- release_firmware(cont);\r
-\r
- aw8695_container_update(aw8695, aw8695_fw);\r
-\r
- aw8695->ram.len = aw8695_fw->len;\r
-\r
- kfree(aw8695_fw);\r
-\r
- aw8695->ram_init = 1;\r
- pr_info("%s: fw update complete\n", __func__);\r
-\r
- aw8695_haptic_trig_enable_config(aw8695);\r
-\r
- aw8695_rtp_update(aw8695);\r
-}\r
-\r
-static int aw8695_ram_update(struct aw8695 *aw8695)\r
-{\r
- aw8695->ram_init = 0;\r
- aw8695->rtp_init = 0;\r
- return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,\r
- aw8695_ram_name, aw8695->dev, GFP_KERNEL,\r
- aw8695, aw8695_ram_loaded);\r
-}\r
-\r
-#ifdef AWINIC_RAM_UPDATE_DELAY\r
-static void aw8695_ram_work_routine(struct work_struct *work)\r
-{\r
- struct aw8695 *aw8695 = container_of(work, struct aw8695, ram_work.work);\r
-\r
- pr_info("%s enter\n", __func__);\r
-\r
- aw8695_ram_update(aw8695);\r
-\r
-}\r
-#endif\r
-\r
-static int aw8695_ram_init(struct aw8695 *aw8695)\r
-{\r
-#ifdef AWINIC_RAM_UPDATE_DELAY\r
- int ram_timer_val = 5000;\r
- INIT_DELAYED_WORK(&aw8695->ram_work, aw8695_ram_work_routine);\r
- schedule_delayed_work(&aw8695->ram_work, msecs_to_jiffies(ram_timer_val));\r
-#else\r
- aw8695_ram_update(aw8695);\r
-#endif\r
- return 0;\r
-}\r
-\r
-\r
-\r
-/*****************************************************\r
- *\r
- * haptic control\r
- *\r
- *****************************************************/\r
-static int aw8695_haptic_softreset(struct aw8695 *aw8695)\r
-{\r
- pr_debug("%s enter\n", __func__);\r
-\r
- aw8695_i2c_write(aw8695, AW8695_REG_ID, 0xAA);\r
- msleep(1);\r
- return 0;\r
-}\r
-\r
-static int aw8695_haptic_active(struct aw8695 *aw8695)\r
-{\r
- pr_debug("%s enter\n", __func__);\r
-\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_WORK_MODE_MASK, AW8695_BIT_SYSCTRL_ACTIVE);\r
- aw8695_interrupt_clear(aw8695);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM,\r
- AW8695_BIT_SYSINTM_UVLO_MASK, AW8695_BIT_SYSINTM_UVLO_EN);\r
- return 0;\r
-}\r
-\r
-static int aw8695_haptic_play_mode(struct aw8695 *aw8695, unsigned char play_mode)\r
-{\r
- pr_debug("%s enter\n", __func__);\r
-\r
- switch(play_mode) {\r
- case AW8695_HAPTIC_STANDBY_MODE:\r
- aw8695->play_mode = AW8695_HAPTIC_STANDBY_MODE;\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM,\r
- AW8695_BIT_SYSINTM_UVLO_MASK, AW8695_BIT_SYSINTM_UVLO_OFF);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_WORK_MODE_MASK, AW8695_BIT_SYSCTRL_STANDBY);\r
- break;\r
- case AW8695_HAPTIC_RAM_MODE:\r
- aw8695->play_mode = AW8695_HAPTIC_RAM_MODE;\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_PLAY_MODE_MASK, AW8695_BIT_SYSCTRL_PLAY_MODE_RAM);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BOOST);\r
- if(aw8695->auto_boost) {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,\r
- AW8695_BIT_BST_AUTO_BST_RAM_MASK, AW8695_BIT_BST_AUTO_BST_RAM_ENABLE);\r
- }\r
- aw8695_haptic_active(aw8695);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BYPASS);\r
- if(aw8695->auto_boost) {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,\r
- AW8695_BIT_BST_AUTO_BST_RAM_MASK, AW8695_BIT_BST_AUTO_BST_RAM_DISABLE);\r
- }\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BOOST);\r
- if(aw8695->auto_boost) {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,\r
- AW8695_BIT_BST_AUTO_BST_RAM_MASK, AW8695_BIT_BST_AUTO_BST_RAM_ENABLE);\r
- }\r
- msleep(3);\r
- break;\r
- case AW8695_HAPTIC_RAM_LOOP_MODE:\r
- aw8695->play_mode = AW8695_HAPTIC_RAM_LOOP_MODE;\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_PLAY_MODE_MASK, AW8695_BIT_SYSCTRL_PLAY_MODE_RAM);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BOOST);\r
- if(aw8695->auto_boost) {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,\r
- AW8695_BIT_BST_AUTO_BST_RAM_MASK, AW8695_BIT_BST_AUTO_BST_RAM_ENABLE);\r
- }\r
- aw8695_haptic_active(aw8695);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BYPASS);\r
- if(aw8695->auto_boost) {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,\r
- AW8695_BIT_BST_AUTO_BST_RAM_MASK, AW8695_BIT_BST_AUTO_BST_RAM_DISABLE);\r
- }\r
- msleep(3);\r
- break;\r
- case AW8695_HAPTIC_RTP_MODE:\r
- aw8695->play_mode = AW8695_HAPTIC_RTP_MODE;\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_PLAY_MODE_MASK, AW8695_BIT_SYSCTRL_PLAY_MODE_RTP);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BOOST);\r
- if(aw8695->auto_boost) {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,\r
- AW8695_BIT_BST_AUTO_BST_RAM_MASK, AW8695_BIT_BST_AUTO_BST_RAM_ENABLE);\r
- }\r
- aw8695_haptic_active(aw8695);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BYPASS);\r
- if(aw8695->auto_boost) {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,\r
- AW8695_BIT_BST_AUTO_BST_RAM_MASK, AW8695_BIT_BST_AUTO_BST_RAM_DISABLE);\r
- }\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BOOST);\r
- if(aw8695->auto_boost) {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,\r
- AW8695_BIT_BST_AUTO_BST_RAM_MASK, AW8695_BIT_BST_AUTO_BST_RAM_ENABLE);\r
- }\r
- msleep(3);\r
- break;\r
- case AW8695_HAPTIC_TRIG_MODE:\r
- aw8695->play_mode = AW8695_HAPTIC_TRIG_MODE;\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_PLAY_MODE_MASK, AW8695_BIT_SYSCTRL_PLAY_MODE_RAM);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BOOST);\r
- if(aw8695->auto_boost) {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,\r
- AW8695_BIT_BST_AUTO_BST_RAM_MASK, AW8695_BIT_BST_AUTO_BST_RAM_ENABLE);\r
- }\r
- aw8695_haptic_active(aw8695);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BYPASS);\r
- if(aw8695->auto_boost) {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,\r
- AW8695_BIT_BST_AUTO_BST_RAM_MASK, AW8695_BIT_BST_AUTO_BST_RAM_DISABLE);\r
- }\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BOOST);\r
- if(aw8695->auto_boost) {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,\r
- AW8695_BIT_BST_AUTO_BST_RAM_MASK, AW8695_BIT_BST_AUTO_BST_RAM_ENABLE);\r
- }\r
- msleep(3);\r
- break;\r
- case AW8695_HAPTIC_CONT_MODE:\r
- aw8695->play_mode = AW8695_HAPTIC_CONT_MODE;\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_PLAY_MODE_MASK, AW8695_BIT_SYSCTRL_PLAY_MODE_CONT);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BOOST);\r
- if(aw8695->auto_boost) {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,\r
- AW8695_BIT_BST_AUTO_BST_RAM_MASK, AW8695_BIT_BST_AUTO_BST_RAM_ENABLE);\r
- }\r
- aw8695_haptic_active(aw8695);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BYPASS);\r
- if(aw8695->auto_boost) {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,\r
- AW8695_BIT_BST_AUTO_BST_RAM_MASK, AW8695_BIT_BST_AUTO_BST_RAM_DISABLE);\r
- }\r
- msleep(3);\r
- break;\r
- default:\r
- dev_err(aw8695->dev, "%s: play mode %d err",\r
- __func__, play_mode);\r
- break;\r
- }\r
- return 0;\r
-}\r
-\r
-static int aw8695_haptic_play_go(struct aw8695 *aw8695, bool flag)\r
-{\r
- pr_debug("%s enter\n", __func__);\r
-\r
- if(flag == true) {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_GO,\r
- AW8695_BIT_GO_MASK, AW8695_BIT_GO_ENABLE);\r
- } else {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_GO,\r
- AW8695_BIT_GO_MASK, AW8695_BIT_GO_DISABLE);\r
- }\r
- return 0;\r
-}\r
-\r
-static int aw8695_haptic_stop_delay(struct aw8695 *aw8695)\r
-{\r
- unsigned char reg_val = 0;\r
- unsigned int cnt = 100;\r
-\r
- while(cnt--) {\r
- aw8695_i2c_read(aw8695, AW8695_REG_GLB_STATE, ®_val);\r
- if((reg_val&0x0f) == 0x00) {\r
- return 0;\r
- }\r
- msleep(2);\r
- pr_info("%s wait for standby, reg glb_state=0x%02x\n",\r
- __func__, reg_val);\r
- }\r
- pr_err("%s do not enter standby automatically\n", __func__);\r
-\r
- return 0;\r
-}\r
-\r
-static int aw8695_haptic_stop(struct aw8695 *aw8695)\r
-{\r
- pr_debug("%s enter\n", __func__);\r
-\r
- aw8695_haptic_play_go(aw8695, false);\r
- aw8695_haptic_stop_delay(aw8695);\r
- aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_STANDBY_MODE);\r
-\r
- return 0;\r
-}\r
-\r
-static int aw8695_haptic_start(struct aw8695 *aw8695)\r
-{\r
- pr_debug("%s enter\n", __func__);\r
-\r
- aw8695_haptic_play_go(aw8695, true);\r
-\r
- return 0;\r
-}\r
-\r
-static int aw8695_haptic_set_wav_seq(struct aw8695 *aw8695,\r
- unsigned char wav, unsigned char seq)\r
-{\r
- aw8695_i2c_write(aw8695, AW8695_REG_WAVSEQ1+wav,\r
- seq);\r
- return 0;\r
-}\r
-\r
-static int aw8695_haptic_set_wav_loop(struct aw8695 *aw8695,\r
- unsigned char wav, unsigned char loop)\r
-{\r
- unsigned char tmp = 0;\r
-\r
- if(wav%2) {\r
- tmp = loop<<0;\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_WAVLOOP1+(wav/2),\r
- AW8695_BIT_WAVLOOP_SEQNP1_MASK, tmp);\r
- } else {\r
- tmp = loop<<4;\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_WAVLOOP1+(wav/2),\r
- AW8695_BIT_WAVLOOP_SEQN_MASK, tmp);\r
- }\r
-\r
- return 0;\r
-}\r
-/*\r
-static int aw8695_haptic_set_main_loop(struct aw8695 *aw8695,\r
- unsigned char loop)\r
-{\r
- aw8695_i2c_write(aw8695, AW8695_REG_MAIN_LOOP, loop);\r
- return 0;\r
-}\r
-*/\r
-\r
-static int aw8695_haptic_set_repeat_wav_seq(struct aw8695 *aw8695, unsigned char seq)\r
-{\r
- aw8695_haptic_set_wav_seq(aw8695, 0x00, seq);\r
- aw8695_haptic_set_wav_loop(aw8695, 0x00, AW8695_BIT_WAVLOOP_INIFINITELY);\r
-\r
- return 0;\r
-}\r
-\r
-\r
-static int aw8695_haptic_set_bst_vol(struct aw8695 *aw8695, unsigned char bst_vol)\r
-{\r
- if(bst_vol & 0xe0) {\r
- bst_vol = 0x1f;\r
- }\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_BSTDBG4,\r
- AW8695_BIT_BSTDBG4_BSTVOL_MASK, (bst_vol<<1));\r
- return 0;\r
-}\r
-\r
-static int aw8695_haptic_set_bst_peak_cur(struct aw8695 *aw8695, unsigned char peak_cur)\r
-{\r
- peak_cur &= AW8695_BSTCFG_PEAKCUR_LIMIT;\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_BSTCFG,\r
- AW8695_BIT_BSTCFG_PEAKCUR_MASK, peak_cur);\r
- return 0;\r
-}\r
-\r
-static int aw8695_haptic_set_gain(struct aw8695 *aw8695, unsigned char gain)\r
-{\r
- aw8695_i2c_write(aw8695, AW8695_REG_DATDBG, gain);\r
- return 0;\r
-}\r
-\r
-static int aw8695_haptic_set_pwm(struct aw8695 *aw8695, unsigned char mode)\r
-{\r
- switch(mode) {\r
- case AW8695_PWM_48K:\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_PWMDBG,\r
- AW8695_BIT_PWMDBG_PWM_MODE_MASK, AW8695_BIT_PWMDBG_PWM_48K);\r
- break;\r
- case AW8695_PWM_24K:\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_PWMDBG,\r
- AW8695_BIT_PWMDBG_PWM_MODE_MASK, AW8695_BIT_PWMDBG_PWM_24K);\r
- break;\r
- case AW8695_PWM_12K:\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_PWMDBG,\r
- AW8695_BIT_PWMDBG_PWM_MODE_MASK, AW8695_BIT_PWMDBG_PWM_12K);\r
- break;\r
- default:\r
- break;\r
- }\r
- return 0;\r
-}\r
-\r
-static int aw8695_haptic_play_wav_seq(struct aw8695 *aw8695, unsigned char flag)\r
-{\r
- pr_debug("%s enter\n", __func__);\r
-\r
- //aw8695_haptic_stop(aw8695);\r
- if(flag) {\r
- aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_RAM_MODE);\r
- aw8695_haptic_start(aw8695);\r
- }\r
- return 0;\r
-}\r
-\r
-static int aw8695_haptic_play_repeat_seq(struct aw8695 *aw8695, unsigned char flag)\r
-{\r
- pr_debug("%s enter\n", __func__);\r
- //aw8695_haptic_stop(aw8695);\r
- if(flag) {\r
- aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_RAM_LOOP_MODE);\r
- aw8695_haptic_start(aw8695);\r
- }\r
-\r
- return 0;\r
-}\r
-\r
-static int aw8695_haptic_swicth_motorprotect_config(struct aw8695 *aw8695, unsigned char addr, unsigned char val)\r
-{\r
- pr_debug("%s enter\n", __func__);\r
- if(addr == 1) {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_DETCTRL,\r
- AW8695_BIT_DETCTRL_PROTECT_MASK, AW8695_BIT_DETCTRL_PROTECT_SHUTDOWN);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_PWMPRC,\r
- AW8695_BIT_PWMPRC_PRC_MASK, AW8695_BIT_PWMPRC_PRC_ENABLE);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_PRLVL,\r
- AW8695_BIT_PRLVL_PR_MASK, AW8695_BIT_PRLVL_PR_ENABLE);\r
- } else if (addr == 0) {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_DETCTRL,\r
- AW8695_BIT_DETCTRL_PROTECT_MASK, AW8695_BIT_DETCTRL_PROTECT_NO_ACTION);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_PWMPRC,\r
- AW8695_BIT_PWMPRC_PRC_MASK, AW8695_BIT_PWMPRC_PRC_DISABLE);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_PRLVL,\r
- AW8695_BIT_PRLVL_PR_MASK, AW8695_BIT_PRLVL_PR_DISABLE);\r
- } else if (addr == 0x2d){\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_PWMPRC,\r
- AW8695_BIT_PWMPRC_PRCTIME_MASK, val);\r
- }else if (addr == 0x3e){\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_PRLVL,\r
- AW8695_BIT_PRLVL_PRLVL_MASK, val);\r
- }else if (addr == 0x3f){\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_PRTIME,\r
- AW8695_BIT_PRTIME_PRTIME_MASK, val);\r
- } else{\r
- /*nothing to do;*/\r
- }\r
- return 0;\r
-}\r
-\r
-static int aw8695_haptic_trig_default_level(struct aw8695 *aw8695)\r
-{\r
- pr_debug("%s enter\n", __func__);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1,\r
- AW8695_BIT_TRGCFG1_TRG1_POLAR_MASK, AW8695_TRG1_DEFAULT_POLAR);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1,\r
- AW8695_BIT_TRGCFG1_TRG2_POLAR_MASK, AW8695_TRG2_DEFAULT_POLAR);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1,\r
- AW8695_BIT_TRGCFG1_TRG3_POLAR_MASK, AW8695_TRG3_DEFAULT_POLAR);\r
-\r
- return 0;\r
-}\r
-\r
-static int aw8695_haptic_trig_enable_config(struct aw8695 *aw8695)\r
-{\r
- pr_debug("%s enter\n", __func__);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG2,\r
- AW8695_BIT_TRGCFG2_TRG1_ENABLE_MASK, AW8695_TRG1_DEFAULT_ENABLE);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG2,\r
- AW8695_BIT_TRGCFG2_TRG2_ENABLE_MASK, AW8695_TRG2_DEFAULT_ENABLE);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG2,\r
- AW8695_BIT_TRGCFG2_TRG3_ENABLE_MASK, AW8695_TRG3_DEFAULT_ENABLE);\r
-\r
- return 0;\r
-}\r
-\r
-\r
-static int aw8695_haptic_auto_boost_config(struct aw8695 *aw8695, unsigned char flag)\r
-{\r
- aw8695->auto_boost = flag;\r
- if(flag) {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,\r
- AW8695_BIT_BST_AUTO_BST_AUTOSW_MASK, AW8695_BIT_BST_AUTO_BST_AUTOMATIC_BOOST);\r
- } else {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,\r
- AW8695_BIT_BST_AUTO_BST_AUTOSW_MASK, AW8695_BIT_BST_AUTO_BST_MANUAL_BOOST);\r
- }\r
- return 0;\r
-}\r
-\r
-static int aw8695_haptic_vbat_mode(struct aw8695 *aw8695, unsigned char flag)\r
-{\r
- if(flag == AW8695_HAPTIC_VBAT_HW_COMP_MODE) {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_ADCTEST,\r
- AW8695_BIT_ADCTEST_VBAT_MODE_MASK, AW8695_BIT_ADCTEST_VBAT_HW_COMP);\r
- } else {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_ADCTEST,\r
- AW8695_BIT_ADCTEST_VBAT_MODE_MASK, AW8695_BIT_ADCTEST_VBAT_SW_COMP);\r
- }\r
- return 0;\r
-}\r
-\r
-\r
-static int aw8695_haptic_set_f0_preset(struct aw8695 *aw8695)\r
-{\r
- unsigned int f0_reg = 0;\r
-\r
- pr_debug("%s enter\n", __func__);\r
-\r
- f0_reg = 1000000000/(aw8695->f0_pre*AW8695_HAPTIC_F0_COEFF);\r
- aw8695_i2c_write(aw8695, AW8695_REG_F_PRE_H, (unsigned char)((f0_reg>>8)&0xff));\r
- aw8695_i2c_write(aw8695, AW8695_REG_F_PRE_L, (unsigned char)((f0_reg>>0)&0xff));\r
-\r
- return 0;\r
-}\r
-\r
-static int aw8695_haptic_read_f0(struct aw8695 *aw8695)\r
-{\r
- int ret = 0;\r
- unsigned char reg_val = 0;\r
- unsigned int f0_reg = 0;\r
- unsigned long f0_tmp = 0;\r
-\r
- pr_debug("%s enter\n", __func__);\r
-\r
- ret = aw8695_i2c_read(aw8695, AW8695_REG_F_LRA_F0_H, ®_val);\r
- f0_reg = (reg_val<<8);\r
- ret = aw8695_i2c_read(aw8695, AW8695_REG_F_LRA_F0_L, ®_val);\r
- f0_reg |= (reg_val<<0);\r
- f0_tmp = 1000000000/(f0_reg*AW8695_HAPTIC_F0_COEFF);\r
- aw8695->f0 = (unsigned int)f0_tmp;\r
- pr_info("%s f0=%d\n", __func__, aw8695->f0);\r
-\r
- return 0;\r
-}\r
-\r
-static int aw8695_haptic_read_cont_f0(struct aw8695 *aw8695)\r
-{\r
- int ret = 0;\r
- unsigned char reg_val = 0;\r
- unsigned int f0_reg = 0;\r
- unsigned long f0_tmp = 0;\r
-\r
- pr_debug("%s enter\n", __func__);\r
-\r
- ret = aw8695_i2c_read(aw8695, AW8695_REG_F_LRA_CONT_H, ®_val);\r
- f0_reg = (reg_val<<8);\r
- ret = aw8695_i2c_read(aw8695, AW8695_REG_F_LRA_CONT_L, ®_val);\r
- f0_reg |= (reg_val<<0);\r
- f0_tmp = 1000000000/(f0_reg*AW8695_HAPTIC_F0_COEFF);\r
- aw8695->cont_f0 = (unsigned int)f0_tmp;\r
- pr_info("%s f0=%d\n", __func__, aw8695->cont_f0);\r
-\r
- return 0;\r
-}\r
-\r
-static int aw8695_haptic_read_beme(struct aw8695 *aw8695)\r
-{\r
- int ret = 0;\r
- unsigned char reg_val = 0;\r
-\r
- ret = aw8695_i2c_read(aw8695, AW8695_REG_WAIT_VOL_MP, ®_val);\r
- aw8695->max_pos_beme = (reg_val<<0);\r
- ret = aw8695_i2c_read(aw8695, AW8695_REG_WAIT_VOL_MN, ®_val);\r
- aw8695->max_neg_beme = (reg_val<<0);\r
-\r
- pr_info("%s max_pos_beme=%d\n", __func__, aw8695->max_pos_beme);\r
- pr_info("%s max_neg_beme=%d\n", __func__, aw8695->max_neg_beme);\r
-\r
- return 0;\r
-}\r
-\r
-\r
-\r
-static void aw8695_haptic_set_rtp_aei(struct aw8695 *aw8695, bool flag)\r
-{\r
- if(flag) {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM,\r
- AW8695_BIT_SYSINTM_FF_AE_MASK, AW8695_BIT_SYSINTM_FF_AE_EN);\r
- } else {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM,\r
- AW8695_BIT_SYSINTM_FF_AE_MASK, AW8695_BIT_SYSINTM_FF_AE_OFF);\r
- }\r
-}\r
-/*\r
-static void aw8695_haptic_set_rtp_afi(struct aw8695 *aw8695, bool flag)\r
-{\r
- if(flag) {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM,\r
- AW8695_BIT_SYSINTM_FF_AF_MASK, AW8695_BIT_SYSINTM_FF_AF_EN);\r
- } else {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM,\r
- AW8695_BIT_SYSINTM_FF_AF_MASK, AW8695_BIT_SYSINTM_FF_AF_OFF);\r
- }\r
-}\r
-*/\r
-/*\r
-static unsigned char aw8695_haptic_rtp_get_fifo_aei(struct aw8695 *aw8695)\r
-{\r
- unsigned char ret;\r
- unsigned char reg_val;\r
-\r
- aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val);\r
- reg_val &= AW8695_BIT_SYSINT_FF_AEI;\r
- ret = reg_val>>4;\r
-\r
- return ret;\r
-}\r
-*/\r
-\r
-static unsigned char aw8695_haptic_rtp_get_fifo_afi(struct aw8695 *aw8695)\r
-{\r
- unsigned char ret = 0;\r
- unsigned char reg_val = 0;\r
-\r
- aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val);\r
- reg_val &= AW8695_BIT_SYSINT_FF_AFI;\r
- ret = reg_val>>3;\r
-\r
- return ret;\r
-}\r
-\r
-static int aw8695_haptic_rtp_init(struct aw8695 *aw8695)\r
-{\r
- unsigned int buf_len = 0;\r
-\r
- pr_info("%s enter\n", __func__);\r
-\r
- aw8695->rtp_cnt = 0;\r
-\r
- while((!aw8695_haptic_rtp_get_fifo_afi(aw8695)) &&\r
- (aw8695->play_mode == AW8695_HAPTIC_RTP_MODE)) {\r
- pr_info("%s rtp cnt = %d\n", __func__, aw8695->rtp_cnt);\r
- if((aw8695_rtp->len-aw8695->rtp_cnt) < (aw8695->ram.base_addr>>2)) {\r
- buf_len = aw8695_rtp->len-aw8695->rtp_cnt;\r
- } else {\r
- buf_len = (aw8695->ram.base_addr>>2);\r
- }\r
- aw8695_i2c_writes(aw8695, AW8695_REG_RTP_DATA,\r
- &aw8695_rtp->data[aw8695->rtp_cnt], buf_len);\r
- aw8695->rtp_cnt += buf_len;\r
- if(aw8695->rtp_cnt == aw8695_rtp->len) {\r
- pr_info("%s: rtp update complete\n", __func__);\r
- aw8695->rtp_cnt = 0;\r
- return 0;\r
- }\r
- }\r
-\r
- if(aw8695->play_mode == AW8695_HAPTIC_RTP_MODE) {\r
- aw8695_haptic_set_rtp_aei(aw8695, true);\r
- }\r
-\r
- pr_info("%s exit\n", __func__);\r
-\r
- return 0;\r
-}\r
-\r
-static void aw8695_rtp_work_routine(struct work_struct *work)\r
-{\r
- const struct firmware *rtp_file;\r
- int ret = -1;\r
- struct aw8695 *aw8695 = container_of(work, struct aw8695, rtp_work);\r
-\r
- pr_info("%s enter\n", __func__);\r
-\r
- /* fw loaded */\r
- ret = request_firmware(&rtp_file,\r
- aw8695_rtp_name[aw8695->rtp_file_num],\r
- aw8695->dev);\r
- if(ret < 0)\r
- {\r
- pr_err("%s: failed to read %s\n", __func__,\r
- aw8695_rtp_name[aw8695->rtp_file_num]);\r
- return ;\r
- }\r
- aw8695->rtp_init = 0;\r
- kfree(aw8695_rtp);\r
- aw8695_rtp = kzalloc(rtp_file->size+sizeof(int), GFP_KERNEL);\r
- if (!aw8695_rtp) {\r
- release_firmware(rtp_file);\r
- pr_err("%s: error allocating memory\n", __func__);\r
- return;\r
- }\r
- aw8695_rtp->len = rtp_file->size;\r
- pr_info("%s: rtp file [%s] size = %d\n", __func__,\r
- aw8695_rtp_name[aw8695->rtp_file_num], aw8695_rtp->len);\r
- memcpy(aw8695_rtp->data, rtp_file->data, rtp_file->size);\r
- release_firmware(rtp_file);\r
-\r
- aw8695->rtp_init = 1;\r
-\r
- /* rtp mode config */\r
- aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_RTP_MODE);\r
-\r
- /* haptic start */\r
- aw8695_haptic_start(aw8695);\r
-\r
- aw8695_haptic_rtp_init(aw8695);\r
-}\r
-\r
-\r
-/*****************************************************\r
- *\r
- * haptic - audio\r
- *\r
- *****************************************************/\r
-static enum hrtimer_restart aw8695_haptic_audio_timer_func(struct hrtimer *timer)\r
-{\r
- struct aw8695 *aw8695 = container_of(timer, struct aw8695, haptic_audio.timer);\r
-\r
- pr_debug("%s enter\n", __func__);\r
- schedule_work(&aw8695->haptic_audio.work);\r
-\r
- hrtimer_start(&aw8695->haptic_audio.timer,\r
- ktime_set(aw8695->haptic_audio.timer_val/1000000,\r
- (aw8695->haptic_audio.timer_val%1000000)*1000),\r
- HRTIMER_MODE_REL);\r
- return HRTIMER_NORESTART;\r
-}\r
-\r
-static void aw8695_haptic_audio_work_routine(struct work_struct *work)\r
-{\r
- struct aw8695 *aw8695 = container_of(work, struct aw8695, haptic_audio.work);\r
-\r
- pr_debug("%s enter\n", __func__);\r
-\r
- mutex_lock(&aw8695->haptic_audio.lock);\r
- memcpy(&aw8695->haptic_audio.ctr,\r
- &aw8695->haptic_audio.data[aw8695->haptic_audio.cnt],\r
- sizeof(struct haptic_ctr));\r
- pr_debug("%s: cnt=%d, cmd=%d, play=%d, wavseq=%d, loop=%d, gain=%d\n",\r
- __func__,\r
- aw8695->haptic_audio.cnt,\r
- aw8695->haptic_audio.ctr.cmd,\r
- aw8695->haptic_audio.ctr.play,\r
- aw8695->haptic_audio.ctr.wavseq,\r
- aw8695->haptic_audio.ctr.loop,\r
- aw8695->haptic_audio.ctr.gain);\r
- mutex_unlock(&aw8695->haptic_audio.lock);\r
- if(aw8695->haptic_audio.ctr.cmd == 0x01) {\r
- if(aw8695->haptic_audio.ctr.play == 0x01) {\r
- pr_info("%s: haptic_audio_play_start\n", __func__);\r
- mutex_lock(&aw8695->lock);\r
- aw8695_haptic_stop(aw8695);\r
-\r
- aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_RAM_MODE);\r
-\r
- aw8695_haptic_set_wav_seq(aw8695, 0x00,\r
- aw8695->haptic_audio.ctr.wavseq);\r
- aw8695_haptic_set_wav_seq(aw8695, 0x01, 0x00);\r
-\r
- aw8695_haptic_set_wav_loop(aw8695, 0x00,\r
- aw8695->haptic_audio.ctr.loop);\r
-\r
- aw8695_haptic_set_gain(aw8695,\r
- aw8695->haptic_audio.ctr.gain);\r
-\r
- aw8695_haptic_start(aw8695);\r
- mutex_unlock(&aw8695->lock);\r
- }\r
- mutex_lock(&aw8695->haptic_audio.lock);\r
- memset(&aw8695->haptic_audio.data[aw8695->haptic_audio.cnt],\r
- 0, sizeof(struct haptic_ctr));\r
- mutex_unlock(&aw8695->haptic_audio.lock);\r
- }\r
-\r
- mutex_lock(&aw8695->haptic_audio.lock);\r
- aw8695->haptic_audio.cnt ++;\r
- if(aw8695->haptic_audio.data[aw8695->haptic_audio.cnt].cmd == 0) {\r
- aw8695->haptic_audio.cnt = 0;\r
- pr_debug("%s: haptic play buffer restart\n", __func__);\r
- }\r
- mutex_unlock(&aw8695->haptic_audio.lock);\r
-\r
-}\r
-\r
-\r
-/*****************************************************\r
- *\r
- * haptic cont\r
- *\r
- *****************************************************/\r
-static int aw8695_haptic_cont(struct aw8695 *aw8695)\r
-{\r
- pr_info("%s enter\n", __func__);\r
-\r
- /* work mode */\r
- aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_CONT_MODE);\r
-\r
- /* preset f0 */\r
- aw8695->f0_pre = aw8695->f0;\r
- aw8695_haptic_set_f0_preset(aw8695);\r
-\r
- /* lpf */\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_DATCTRL,\r
- AW8695_BIT_DATCTRL_FC_MASK, AW8695_BIT_DATCTRL_FC_1000HZ);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_DATCTRL,\r
- AW8695_BIT_DATCTRL_LPF_ENABLE_MASK, AW8695_BIT_DATCTRL_LPF_ENABLE);\r
-\r
- /* cont config */\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL,\r
- AW8695_BIT_CONT_CTRL_ZC_DETEC_MASK, AW8695_BIT_CONT_CTRL_ZC_DETEC_ENABLE);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL,\r
- AW8695_BIT_CONT_CTRL_WAIT_PERIOD_MASK, AW8695_BIT_CONT_CTRL_WAIT_1PERIOD);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL,\r
- AW8695_BIT_CONT_CTRL_MODE_MASK, AW8695_BIT_CONT_CTRL_BY_GO_SIGNAL);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL,\r
- AW8695_BIT_CONT_CTRL_EN_CLOSE_MASK, AW8695_CONT_PLAYBACK_MODE);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL,\r
- AW8695_BIT_CONT_CTRL_F0_DETECT_MASK, AW8695_BIT_CONT_CTRL_F0_DETECT_DISABLE);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL,\r
- AW8695_BIT_CONT_CTRL_O2C_MASK, AW8695_BIT_CONT_CTRL_O2C_DISABLE);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL,\r
- AW8695_BIT_CONT_CTRL_AUTO_BRK_MASK, AW8695_BIT_CONT_CTRL_AUTO_BRK_ENABLE);\r
-\r
- /* TD time */\r
- aw8695_i2c_write(aw8695, AW8695_REG_TD_H, (unsigned char)(aw8695->cont_td>>8));\r
- aw8695_i2c_write(aw8695, AW8695_REG_TD_L, (unsigned char)(aw8695->cont_td>>0));\r
- aw8695_i2c_write(aw8695, AW8695_REG_TSET, 0x12);\r
-\r
- /* zero cross */\r
- aw8695_i2c_write(aw8695, AW8695_REG_ZC_THRSH_H, (unsigned char)(aw8695->cont_zc_thr>>8));\r
- aw8695_i2c_write(aw8695, AW8695_REG_ZC_THRSH_L, (unsigned char)(aw8695->cont_zc_thr>>0));\r
-\r
- /* bemf */\r
- aw8695_i2c_write(aw8695, AW8695_REG_BEMF_VTHH_H, 0x10);\r
- aw8695_i2c_write(aw8695, AW8695_REG_BEMF_VTHH_L, 0x08);\r
- aw8695_i2c_write(aw8695, AW8695_REG_BEMF_VTHL_H, 0x03);\r
- aw8695_i2c_write(aw8695, AW8695_REG_BEMF_VTHL_L, 0xf8);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_BEMF_NUM,\r
- AW8695_BIT_BEMF_NUM_BRK_MASK, aw8695->cont_num_brk);\r
- aw8695_i2c_write(aw8695, AW8695_REG_TIME_NZC, 0x23); // 35*171us=5.985ms\r
-\r
- /* f0 driver level */\r
- aw8695_i2c_write(aw8695, AW8695_REG_DRV_LVL, aw8695->cont_drv_lvl);\r
- aw8695_i2c_write(aw8695, AW8695_REG_DRV_LVL_OV, aw8695->cont_drv_lvl_ov);\r
-\r
- /* cont play go */\r
- aw8695_haptic_play_go(aw8695, true);\r
-\r
- return 0;\r
-}\r
-\r
-/*****************************************************\r
- *\r
- * haptic f0 cali\r
- *\r
- *****************************************************/\r
-static int aw8695_haptic_get_f0(struct aw8695 *aw8695)\r
-{\r
- int ret = 0;\r
- unsigned char i = 0;\r
- unsigned char reg_val = 0;\r
- unsigned char f0_pre_num = 0;\r
- unsigned char f0_wait_num = 0;\r
- unsigned char f0_repeat_num = 0;\r
- unsigned char f0_trace_num = 0;\r
- unsigned int t_f0_ms = 0;\r
- unsigned int t_f0_trace_ms = 0;\r
- unsigned int f0_cali_cnt = 50;\r
-\r
- pr_info("%s enter\n", __func__);\r
-\r
- aw8695->f0 = aw8695->f0_pre;\r
-\r
- /* f0 calibrate work mode */\r
- aw8695_haptic_stop(aw8695);\r
- aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_CONT_MODE);\r
-\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL,\r
- AW8695_BIT_CONT_CTRL_EN_CLOSE_MASK, AW8695_BIT_CONT_CTRL_OPEN_PLAYBACK);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL,\r
- AW8695_BIT_CONT_CTRL_F0_DETECT_MASK, AW8695_BIT_CONT_CTRL_F0_DETECT_ENABLE);\r
-\r
- /* LPF */\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_DATCTRL,\r
- AW8695_BIT_DATCTRL_FC_MASK, AW8695_BIT_DATCTRL_FC_1000HZ);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_DATCTRL,\r
- AW8695_BIT_DATCTRL_LPF_ENABLE_MASK, AW8695_BIT_DATCTRL_LPF_ENABLE);\r
-\r
- /* LRA OSC Source */\r
- if(aw8695->f0_cali_flag == AW8695_HAPTIC_CALI_F0) {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_ANACTRL,\r
- AW8695_BIT_ANACTRL_LRA_SRC_MASK, AW8695_BIT_ANACTRL_LRA_SRC_REG);\r
- } else {\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_ANACTRL,\r
- AW8695_BIT_ANACTRL_LRA_SRC_MASK, AW8695_BIT_ANACTRL_LRA_SRC_EFUSE);\r
- }\r
-\r
- /* preset f0 */\r
- aw8695_haptic_set_f0_preset(aw8695);\r
-\r
- /* beme config */\r
- aw8695_i2c_write(aw8695, AW8695_REG_BEMF_VTHH_H, 0x10);\r
- aw8695_i2c_write(aw8695, AW8695_REG_BEMF_VTHH_L, 0x08);\r
- aw8695_i2c_write(aw8695, AW8695_REG_BEMF_VTHL_H, 0x03);\r
- aw8695_i2c_write(aw8695, AW8695_REG_BEMF_VTHL_L, 0xf8);\r
-\r
- /* f0 driver level */\r
- aw8695_i2c_write(aw8695, AW8695_REG_DRV_LVL, aw8695->cont_drv_lvl);\r
-\r
- /* f0 trace parameter */\r
- f0_pre_num = 0x05;\r
- f0_wait_num = 0x03;\r
- f0_repeat_num = 0x02;\r
- f0_trace_num = 0x0f;\r
- aw8695_i2c_write(aw8695, AW8695_REG_NUM_F0_1, (f0_pre_num<<4)|(f0_wait_num<<0));\r
- aw8695_i2c_write(aw8695, AW8695_REG_NUM_F0_2, (f0_repeat_num<<0));\r
- aw8695_i2c_write(aw8695, AW8695_REG_NUM_F0_3, (f0_trace_num<<0));\r
-\r
- /* clear aw8695 interrupt */\r
- ret = aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val);\r
-\r
- /* play go and start f0 calibration */\r
- aw8695_haptic_play_go(aw8695, true);\r
-\r
- /* f0 trace time */\r
- t_f0_ms = 1000*10/aw8695->f0_pre;\r
- t_f0_trace_ms = t_f0_ms * (f0_pre_num + f0_wait_num + (f0_trace_num+f0_wait_num)*(f0_repeat_num-1));\r
- msleep(t_f0_trace_ms);\r
-\r
- for(i=0; i<f0_cali_cnt; i++) {\r
- ret = aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val);\r
- /* f0 calibrate done */\r
- if(reg_val & 0x01) {\r
- aw8695_haptic_read_f0(aw8695);\r
- aw8695_haptic_read_beme(aw8695);\r
- break;\r
- }\r
- msleep(10);\r
- pr_info("%s f0 cali sleep 10ms\n", __func__);\r
- }\r
-\r
- if(i == f0_cali_cnt) {\r
- ret = -1;\r
- } else {\r
- ret = 0;\r
- }\r
-\r
- /* restore default config */\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL,\r
- AW8695_BIT_CONT_CTRL_EN_CLOSE_MASK, AW8695_CONT_PLAYBACK_MODE);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL,\r
- AW8695_BIT_CONT_CTRL_F0_DETECT_MASK, AW8695_BIT_CONT_CTRL_F0_DETECT_DISABLE);\r
-\r
- return ret;\r
-}\r
-\r
-static int aw8695_haptic_f0_calibration(struct aw8695 *aw8695)\r
-{\r
- int ret = 0;\r
- unsigned char reg_val = 0;\r
- unsigned int f0_limit = 0;\r
- char f0_cali_lra = 0;\r
- int f0_cali_step = 0;\r
- int f0_dft_step = 0;\r
-\r
- pr_info("%s enter\n", __func__);\r
-\r
- aw8695->f0_cali_flag = AW8695_HAPTIC_CALI_F0;\r
-\r
- if(aw8695_haptic_get_f0(aw8695)) {\r
- pr_err("%s get f0 error, user defafult f0\n", __func__);\r
- } else {\r
- /* max and min limit */\r
- f0_limit = aw8695->f0;\r
- if(aw8695->f0*100 < AW8695_HAPTIC_F0_PRE*(100-AW8695_HAPTIC_F0_CALI_PERCEN)) {\r
- f0_limit = AW8695_HAPTIC_F0_PRE*(100-AW8695_HAPTIC_F0_CALI_PERCEN)/100;\r
- }\r
- if(aw8695->f0*100 > AW8695_HAPTIC_F0_PRE*(100+AW8695_HAPTIC_F0_CALI_PERCEN)) {\r
- f0_limit = AW8695_HAPTIC_F0_PRE*(100+AW8695_HAPTIC_F0_CALI_PERCEN)/100;\r
- }\r
-\r
- /* calculate cali step */\r
- f0_cali_step = 10000*((int)f0_limit-(int)aw8695->f0_pre)/((int)f0_limit*25);\r
- pr_debug("%s f0_cali_step=%d\n", __func__, f0_cali_step);\r
-\r
- /* get default cali step */\r
- aw8695_i2c_read(aw8695, AW8695_REG_TRIM_LRA, ®_val);\r
- if(reg_val & 0x20) {\r
- f0_dft_step = reg_val - 0x40;\r
- } else {\r
- f0_dft_step = reg_val;\r
- }\r
- pr_debug("%s f0_dft_step=%d\n", __func__, f0_dft_step);\r
-\r
- /* get new cali step */\r
- f0_cali_step += f0_dft_step;\r
- pr_debug("%s f0_cali_step=%d\n", __func__, f0_cali_step);\r
-\r
- if(f0_cali_step > 31) {\r
- f0_cali_step = 31;\r
- } else if(f0_cali_step < -32) {\r
- f0_cali_step = -32;\r
- }\r
- f0_cali_lra = (char)f0_cali_step;\r
- pr_debug("%s f0_cali_lra=%d\n", __func__, f0_cali_lra);\r
-\r
- /* get cali step complement code*/\r
- if(f0_cali_lra < 0) {\r
- f0_cali_lra += 0x40;\r
- }\r
- pr_debug("%s reg f0_cali_lra=%d\n", __func__, f0_cali_lra);\r
-\r
- /* update cali step */\r
- aw8695_i2c_write(aw8695, AW8695_REG_TRIM_LRA, (char)f0_cali_lra);\r
- aw8695_i2c_read(aw8695, AW8695_REG_TRIM_LRA, ®_val);\r
- pr_info("%s final trim_lra=0x%02x\n", __func__, reg_val);\r
- }\r
-\r
- /* restore default work mode */\r
- aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_STANDBY_MODE);\r
- aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_RAM_MODE);\r
- aw8695_haptic_stop(aw8695);\r
-\r
- return ret;\r
-}\r
-\r
-/*****************************************************\r
- *\r
- * haptic fops\r
- *\r
- *****************************************************/\r
-static int aw8695_file_open(struct inode *inode, struct file *file)\r
-{\r
- if (!try_module_get(THIS_MODULE))\r
- return -ENODEV;\r
-\r
- file->private_data = (void*)g_aw8695;\r
-\r
- return 0;\r
-}\r
-\r
-static int aw8695_file_release(struct inode *inode, struct file *file)\r
-{\r
- file->private_data = (void*)NULL;\r
-\r
- module_put(THIS_MODULE);\r
-\r
- return 0;\r
-}\r
-\r
-static long aw8695_file_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)\r
-{\r
- struct aw8695 *aw8695 = (struct aw8695 *)file->private_data;\r
-\r
- int ret = 0;\r
-\r
- dev_info(aw8695->dev, "%s: cmd=0x%x, arg=0x%lx\n",\r
- __func__, cmd, arg);\r
-\r
- mutex_lock(&aw8695->lock);\r
-\r
- if(_IOC_TYPE(cmd) != AW8695_HAPTIC_IOCTL_MAGIC) {\r
- dev_err(aw8695->dev, "%s: cmd magic err\n",\r
- __func__);\r
- return -EINVAL;\r
- }\r
-\r
- switch (cmd) {\r
- default:\r
- dev_err(aw8695->dev, "%s, unknown cmd\n", __func__);\r
- break;\r
- }\r
-\r
- mutex_unlock(&aw8695->lock);\r
-\r
- return ret;\r
-}\r
-\r
-static ssize_t aw8695_file_read(struct file* filp, char* buff, size_t len, loff_t* offset)\r
-{\r
- struct aw8695 *aw8695 = (struct aw8695 *)filp->private_data;\r
- int ret = 0;\r
- int i = 0;\r
- unsigned char reg_val = 0;\r
- unsigned char *pbuff = NULL;\r
-\r
- mutex_lock(&aw8695->lock);\r
-\r
- dev_info(aw8695->dev, "%s: len=%zu\n", __func__, len);\r
-\r
- switch(aw8695->fileops.cmd)\r
- {\r
- case AW8695_HAPTIC_CMD_READ_REG:\r
- pbuff = (unsigned char *)kzalloc(len, GFP_KERNEL);\r
- if(pbuff != NULL) {\r
- for(i=0; i<len; i++) {\r
- aw8695_i2c_read(aw8695, aw8695->fileops.reg+i, ®_val);\r
- pbuff[i] = reg_val;\r
- }\r
- for(i=0; i<len; i++) {\r
- dev_info(aw8695->dev, "%s: pbuff[%d]=0x%02x\n",\r
- __func__, i, pbuff[i]);\r
- }\r
- ret = copy_to_user(buff, pbuff, len);\r
- if(ret) {\r
- dev_err(aw8695->dev, "%s: copy to user fail\n", __func__);\r
- }\r
- kfree(pbuff);\r
- } else {\r
- dev_err(aw8695->dev, "%s: alloc memory fail\n", __func__);\r
- }\r
- break;\r
- default:\r
- dev_err(aw8695->dev, "%s, unknown cmd %d \n", __func__, aw8695->fileops.cmd);\r
- break;\r
- }\r
-\r
- mutex_unlock(&aw8695->lock);\r
-\r
-\r
- return len;\r
-}\r
-\r
-static ssize_t aw8695_file_write(struct file* filp, const char* buff, size_t len, loff_t* off)\r
-{\r
- struct aw8695 *aw8695 = (struct aw8695 *)filp->private_data;\r
- int i = 0;\r
- int ret = 0;\r
- unsigned char *pbuff = NULL;\r
-\r
- pbuff = (unsigned char *)kzalloc(len, GFP_KERNEL);\r
- if(pbuff == NULL) {\r
- dev_err(aw8695->dev, "%s: alloc memory fail\n", __func__);\r
- return len;\r
- }\r
- ret = copy_from_user(pbuff, buff, len);\r
- if(ret) {\r
- dev_err(aw8695->dev, "%s: copy from user fail\n", __func__);\r
- return len;\r
- }\r
-\r
- for(i=0; i<len; i++) {\r
- dev_info(aw8695->dev, "%s: pbuff[%d]=0x%02x\n",\r
- __func__, i, pbuff[i]);\r
- }\r
-\r
- mutex_lock(&aw8695->lock);\r
-\r
- aw8695->fileops.cmd = pbuff[0];\r
-\r
- switch(aw8695->fileops.cmd)\r
- {\r
- case AW8695_HAPTIC_CMD_READ_REG:\r
- if(len == 2) {\r
- aw8695->fileops.reg = pbuff[1];\r
- } else {\r
- dev_err(aw8695->dev, "%s: read cmd len %zu err\n", __func__, len);\r
- }\r
- break;\r
- case AW8695_HAPTIC_CMD_WRITE_REG:\r
- if(len > 2) {\r
- for(i=0; i<len-2; i++) {\r
- dev_info(aw8695->dev, "%s: write reg0x%02x=0x%02x\n",\r
- __func__, pbuff[1]+i, pbuff[i+2]);\r
- aw8695_i2c_write(aw8695, pbuff[1]+i, pbuff[2+i]);\r
- }\r
- } else {\r
- dev_err(aw8695->dev, "%s: write cmd len %zu err\n", __func__, len);\r
- }\r
- break;\r
- default:\r
- dev_err(aw8695->dev, "%s, unknown cmd %d \n", __func__, aw8695->fileops.cmd);\r
- break;\r
- }\r
-\r
- mutex_unlock(&aw8695->lock);\r
-\r
- if(pbuff != NULL) {\r
- kfree(pbuff);\r
- }\r
- return len;\r
-}\r
-\r
-static struct file_operations fops =\r
-{\r
- .owner = THIS_MODULE,\r
- .read = aw8695_file_read,\r
- .write = aw8695_file_write,\r
- .unlocked_ioctl = aw8695_file_unlocked_ioctl,\r
- .open = aw8695_file_open,\r
- .release = aw8695_file_release,\r
-};\r
-\r
-static struct miscdevice aw8695_haptic_misc =\r
-{\r
- .minor = MISC_DYNAMIC_MINOR,\r
- .name = AW8695_HAPTIC_NAME,\r
- .fops = &fops,\r
-};\r
-\r
-static int aw8695_haptic_init(struct aw8695 *aw8695)\r
-{\r
- int ret = 0;\r
- unsigned char i = 0;\r
- unsigned char reg_val = 0;\r
-\r
- pr_info("%s enter\n", __func__);\r
-\r
- ret = misc_register(&aw8695_haptic_misc);\r
- if(ret) {\r
- dev_err(aw8695->dev, "%s: misc fail: %d\n", __func__, ret);\r
- return ret;\r
- }\r
-\r
- /* haptic audio */\r
- aw8695->haptic_audio.delay_val = 20833;\r
- aw8695->haptic_audio.timer_val = 20833;\r
-\r
- hrtimer_init(&aw8695->haptic_audio.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);\r
- aw8695->haptic_audio.timer.function = aw8695_haptic_audio_timer_func;\r
- INIT_WORK(&aw8695->haptic_audio.work, aw8695_haptic_audio_work_routine);\r
-\r
- mutex_init(&aw8695->haptic_audio.lock);\r
-\r
-\r
- /* haptic init */\r
- mutex_lock(&aw8695->lock);\r
-\r
- aw8695->activate_mode = AW8695_HAPTIC_ACTIVATE_CONT_MODE;\r
-\r
- ret = aw8695_i2c_read(aw8695, AW8695_REG_WAVSEQ1, ®_val);\r
- aw8695->index = reg_val & 0x7F;\r
- ret = aw8695_i2c_read(aw8695, AW8695_REG_DATDBG, ®_val);\r
- aw8695->gain = reg_val & 0xFF;\r
- ret = aw8695_i2c_read(aw8695, AW8695_REG_BSTDBG4, ®_val);\r
- aw8695->vmax = (reg_val>>1)&0x1F;\r
- for(i=0; i<AW8695_SEQUENCER_SIZE; i++) {\r
- ret = aw8695_i2c_read(aw8695, AW8695_REG_WAVSEQ1+i, ®_val);\r
- aw8695->seq[i] = reg_val;\r
- }\r
-\r
- aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_STANDBY_MODE);\r
-\r
- aw8695_haptic_set_pwm(aw8695, AW8695_PWM_24K);\r
-\r
- aw8695_i2c_write(aw8695, AW8695_REG_BSTDBG1, 0x30);\r
- aw8695_i2c_write(aw8695, AW8695_REG_BSTDBG2, 0xeb);\r
- aw8695_i2c_write(aw8695, AW8695_REG_BSTDBG3, 0xd4);\r
- aw8695_i2c_write(aw8695, AW8695_REG_TSET, 0x12);\r
- aw8695_i2c_write(aw8695, AW8695_REG_R_SPARE, 0x68);\r
-\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_ANADBG,\r
- AW8695_BIT_ANADBG_IOC_MASK, AW8695_BIT_ANADBG_IOC_4P65A);\r
-\r
- aw8695_haptic_set_bst_peak_cur(aw8695, AW8695_DEFAULT_PEAKCUR);\r
- aw8695_haptic_swicth_motorprotect_config(aw8695, 0x00, 0x00);\r
- aw8695_haptic_auto_boost_config(aw8695, false);\r
- aw8695_haptic_trig_default_level(aw8695);\r
- aw8695_haptic_vbat_mode(aw8695, AW8695_HAPTIC_VBAT_HW_COMP_MODE);\r
-\r
- mutex_unlock(&aw8695->lock);\r
-\r
-\r
- /* f0 calibration */\r
- mutex_lock(&aw8695->lock);\r
- aw8695->f0_pre = AW8695_HAPTIC_F0_PRE;\r
- aw8695->cont_drv_lvl = AW8695_HAPTIC_CONT_DRV_LVL;\r
- aw8695->cont_drv_lvl_ov = AW8695_HAPTIC_CONT_DRV_LVL_OV;\r
- aw8695->cont_td = AW8695_HAPTIC_CONT_TD;\r
- aw8695->cont_zc_thr = AW8695_HAPTIC_CONT_ZC_THR;\r
- aw8695->cont_num_brk = AW8695_HAPTIC_CONT_NUM_BRK;\r
- aw8695_haptic_f0_calibration(aw8695);\r
- mutex_unlock(&aw8695->lock);\r
-\r
- return ret;\r
-}\r
-\r
-\r
-\r
-/*****************************************************\r
- *\r
- * vibrator\r
- *\r
- *****************************************************/\r
-#ifdef TIMED_OUTPUT\r
-static int aw8695_vibrator_get_time(struct timed_output_dev *dev)\r
-{\r
- struct aw8695 *aw8695 = container_of(dev, struct aw8695, to_dev);\r
-\r
- if (hrtimer_active(&aw8695->timer)) {\r
- ktime_t r = hrtimer_get_remaining(&aw8695->timer);\r
- return ktime_to_ms(r);\r
- }\r
-\r
- return 0;\r
-}\r
-\r
-static void aw8695_vibrator_enable( struct timed_output_dev *dev, int value)\r
-{\r
- struct aw8695 *aw8695 = container_of(dev, struct aw8695, to_dev);\r
-\r
- mutex_lock(&aw8695->lock);\r
-\r
- pr_debug("%s enter\n", __func__);\r
-\r
- aw8695_haptic_stop(aw8695);\r
-\r
- if (value > 0) {\r
- aw8695_haptic_play_wav_seq(aw8695, value);\r
- }\r
-\r
- mutex_unlock(&aw8695->lock);\r
-\r
- pr_debug("%s exit\n", __func__);\r
-}\r
-\r
-#else\r
-static enum led_brightness aw8695_haptic_brightness_get(struct led_classdev *cdev)\r
-{\r
- struct aw8695 *aw8695 =\r
- container_of(cdev, struct aw8695, cdev);\r
-\r
- return aw8695->amplitude;\r
-}\r
-\r
-static void aw8695_haptic_brightness_set(struct led_classdev *cdev,\r
- enum led_brightness level)\r
-{\r
- struct aw8695 *aw8695 =\r
- container_of(cdev, struct aw8695, cdev);\r
-\r
- aw8695->amplitude = level;\r
-\r
- mutex_lock(&aw8695->lock);\r
-\r
- aw8695_haptic_stop(aw8695);\r
- if (aw8695->amplitude > 0) {\r
- aw8695_haptic_play_wav_seq(aw8695, aw8695->amplitude);\r
- }\r
-\r
- mutex_unlock(&aw8695->lock);\r
-\r
-}\r
-#endif\r
-\r
-static ssize_t aw8695_state_show(struct device *dev,\r
- struct device_attribute *attr, char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
-\r
- return snprintf(buf, PAGE_SIZE, "%d\n", aw8695->state);\r
-}\r
-\r
-static ssize_t aw8695_state_store(struct device *dev,\r
- struct device_attribute *attr, const char *buf, size_t count)\r
-{\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_duration_show(struct device *dev,\r
- struct device_attribute *attr, char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- ktime_t time_rem;\r
- s64 time_ms = 0;\r
-\r
- if (hrtimer_active(&aw8695->timer)) {\r
- time_rem = hrtimer_get_remaining(&aw8695->timer);\r
- time_ms = ktime_to_ms(time_rem);\r
- }\r
-\r
- return snprintf(buf, PAGE_SIZE, "%lld\n", time_ms);\r
-}\r
-\r
-static ssize_t aw8695_duration_store(struct device *dev,\r
- struct device_attribute *attr, const char *buf, size_t count)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- unsigned int val = 0;\r
- int rc = 0;\r
-\r
- rc = kstrtouint(buf, 0, &val);\r
- if (rc < 0)\r
- return rc;\r
-\r
- /* setting 0 on duration is NOP for now */\r
- if (val <= 0)\r
- return count;\r
-\r
- aw8695->duration = val;\r
-\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_activate_show(struct device *dev,\r
- struct device_attribute *attr, char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
-\r
- /* For now nothing to show */\r
- return snprintf(buf, PAGE_SIZE, "%d\n", aw8695->state);\r
-}\r
-\r
-static ssize_t aw8695_activate_store(struct device *dev,\r
- struct device_attribute *attr, const char *buf, size_t count)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- unsigned int val = 0;\r
- int rc = 0;;\r
-\r
- rc = kstrtouint(buf, 0, &val);\r
- if (rc < 0)\r
- return rc;\r
-\r
- if (val != 0 && val != 1)\r
- return count;\r
-\r
- pr_debug("%s: value=%d\n", __FUNCTION__, val);\r
-\r
- mutex_lock(&aw8695->lock);\r
- hrtimer_cancel(&aw8695->timer);\r
-\r
- aw8695->state = val;\r
- if (aw8695->duration > 100) {\r
- aw8695_haptic_set_repeat_wav_seq(aw8695, AW8695_LONG_RAM);\r
- } else if (aw8695->duration < 100) {\r
- aw8695_haptic_set_wav_seq(aw8695, 0x00, AW8695_SHORT_RAM_100_UP);\r
- }\r
-\r
- if (aw8695->state)\r
- {\r
- /* clip value to max */\r
- val = aw8695->duration;\r
- /* run ms timer */\r
- hrtimer_start(&aw8695->timer,\r
- ktime_set(val / 1000, (val % 1000) * 1000000),\r
- HRTIMER_MODE_REL);\r
- }\r
- mutex_unlock(&aw8695->lock);\r
- schedule_work(&aw8695->vibrator_work);\r
-\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_activate_mode_show(struct device *dev,\r
- struct device_attribute *attr, char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
-\r
- return snprintf(buf, PAGE_SIZE, "activate_mode=%d\n", aw8695->activate_mode);\r
-}\r
-\r
-static ssize_t aw8695_activate_mode_store(struct device *dev,\r
- struct device_attribute *attr, const char *buf, size_t count)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- unsigned int val = 0;\r
- int rc = 0;\r
-\r
- rc = kstrtouint(buf, 0, &val);\r
- if (rc < 0)\r
- return rc;\r
-\r
- mutex_lock(&aw8695->lock);\r
- aw8695->activate_mode = val;\r
- mutex_unlock(&aw8695->lock);\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_index_show(struct device *dev,\r
- struct device_attribute *attr, char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- unsigned char reg_val = 0;\r
- aw8695_i2c_read(aw8695, AW8695_REG_WAVSEQ1, ®_val);\r
- aw8695->index = reg_val;\r
-\r
- return snprintf(buf, PAGE_SIZE, "%d\n", aw8695->index);\r
-}\r
-\r
-static ssize_t aw8695_index_store(struct device *dev,\r
- struct device_attribute *attr, const char *buf, size_t count)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- unsigned int val = 0;\r
- int rc = 0;\r
-\r
- rc = kstrtouint(buf, 0, &val);\r
- if (rc < 0)\r
- return rc;\r
-\r
- pr_debug("%s: value=%d\n", __FUNCTION__, val);\r
-\r
- mutex_lock(&aw8695->lock);\r
- aw8695->index = val;\r
- aw8695_haptic_set_repeat_wav_seq(aw8695, aw8695->index);\r
- mutex_unlock(&aw8695->lock);\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_vmax_show(struct device *dev,\r
- struct device_attribute *attr, char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
-\r
- return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw8695->vmax);\r
-}\r
-\r
-static ssize_t aw8695_vmax_store(struct device *dev,\r
- struct device_attribute *attr, const char *buf, size_t count)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- unsigned int val = 0;\r
- int rc = 0;\r
-\r
- rc = kstrtouint(buf, 0, &val);\r
- if (rc < 0)\r
- return rc;\r
-\r
- pr_debug("%s: value=%d\n", __FUNCTION__, val);\r
-\r
- mutex_lock(&aw8695->lock);\r
- aw8695->vmax = val;\r
- aw8695_haptic_set_bst_vol(aw8695, aw8695->vmax);\r
- mutex_unlock(&aw8695->lock);\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_gain_show(struct device *dev,\r
- struct device_attribute *attr, char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
-\r
- return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw8695->gain);\r
-}\r
-\r
-static ssize_t aw8695_gain_store(struct device *dev,\r
- struct device_attribute *attr, const char *buf, size_t count)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- unsigned int val = 0;\r
- int rc = 0;\r
-\r
- rc = kstrtouint(buf, 0, &val);\r
- if (rc < 0)\r
- return rc;\r
-\r
- pr_debug("%s: value=%d\n", __FUNCTION__, val);\r
-\r
- mutex_lock(&aw8695->lock);\r
- aw8695->gain = val;\r
- aw8695_haptic_set_gain(aw8695, aw8695->gain);\r
- mutex_unlock(&aw8695->lock);\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_seq_show(struct device *dev,\r
- struct device_attribute *attr, char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- size_t count = 0;\r
- unsigned char i = 0;\r
- unsigned char reg_val = 0;\r
-\r
- for(i=0; i<AW8695_SEQUENCER_SIZE; i++) {\r
- aw8695_i2c_read(aw8695, AW8695_REG_WAVSEQ1+i, ®_val);\r
- count += snprintf(buf+count, PAGE_SIZE-count,\r
- "seq%d: 0x%02x\n", i+1, reg_val);\r
- aw8695->seq[i] |= reg_val;\r
- }\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_seq_store(struct device *dev,\r
- struct device_attribute *attr, const char *buf, size_t count)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- unsigned int databuf[2] = {0, 0};\r
-\r
- if(2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) {\r
- pr_debug("%s: seq%d=0x%x\n", __FUNCTION__, databuf[0], databuf[1]);\r
- mutex_lock(&aw8695->lock);\r
- aw8695->seq[databuf[0]] = (unsigned char)databuf[1];\r
- aw8695_haptic_set_wav_seq(aw8695, (unsigned char)databuf[0],\r
- aw8695->seq[databuf[0]]);\r
- mutex_unlock(&aw8695->lock);\r
- }\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_loop_show(struct device *dev,\r
- struct device_attribute *attr, char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- size_t count = 0;\r
- unsigned char i = 0;\r
- unsigned char reg_val = 0;\r
-\r
- for(i=0; i<AW8695_SEQUENCER_LOOP_SIZE; i++) {\r
- aw8695_i2c_read(aw8695, AW8695_REG_WAVLOOP1+i, ®_val);\r
- aw8695->loop[i*2+0] = (reg_val>>4)&0x0F;\r
- aw8695->loop[i*2+1] = (reg_val>>0)&0x0F;\r
-\r
- count += snprintf(buf+count, PAGE_SIZE-count,\r
- "seq%d loop: 0x%02x\n", i*2+1, aw8695->loop[i*2+0]);\r
- count += snprintf(buf+count, PAGE_SIZE-count,\r
- "seq%d loop: 0x%02x\n", i*2+2, aw8695->loop[i*2+1]);\r
- }\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_loop_store(struct device *dev,\r
- struct device_attribute *attr, const char *buf, size_t count)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- unsigned int databuf[2] = {0, 0};\r
-\r
- if(2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) {\r
- pr_debug("%s: seq%d loop=0x%x\n", __FUNCTION__, databuf[0], databuf[1]);\r
- mutex_lock(&aw8695->lock);\r
- aw8695->loop[databuf[0]] = (unsigned char)databuf[1];\r
- aw8695_haptic_set_wav_loop(aw8695, (unsigned char)databuf[0],\r
- aw8695->loop[databuf[0]]);\r
- mutex_unlock(&aw8695->lock);\r
- }\r
-\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_reg_show(struct device *dev, struct device_attribute *attr,\r
- char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- ssize_t len = 0;\r
- unsigned char i = 0;\r
- unsigned char reg_val = 0;\r
- for(i = 0; i < AW8695_REG_MAX; i ++) {\r
- if(!(aw8695_reg_access[i]®_RD_ACCESS))\r
- continue;\r
- aw8695_i2c_read(aw8695, i, ®_val);\r
- len += snprintf(buf+len, PAGE_SIZE-len, "reg:0x%02x=0x%02x \n", i, reg_val);\r
- }\r
- return len;\r
-}\r
-\r
-static ssize_t aw8695_reg_store(struct device *dev, struct device_attribute *attr,\r
- const char *buf, size_t count)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- unsigned int databuf[2] = {0, 0};\r
-\r
- if(2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) {\r
- aw8695_i2c_write(aw8695, (unsigned char)databuf[0], (unsigned char)databuf[1]);\r
- }\r
-\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_rtp_show(struct device *dev, struct device_attribute *attr,\r
- char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- ssize_t len = 0;\r
- len += snprintf(buf+len, PAGE_SIZE-len, "rtp play: %d\n", aw8695->rtp_cnt);\r
-\r
- return len;\r
-}\r
-\r
-static ssize_t aw8695_rtp_store(struct device *dev, struct device_attribute *attr,\r
- const char *buf, size_t count)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- unsigned int val = 0;\r
- int rc = 0;\r
-\r
- rc = kstrtouint(buf, 0, &val);\r
- if (rc < 0)\r
- return rc;\r
-\r
- aw8695_haptic_stop(aw8695);\r
- aw8695_haptic_set_rtp_aei(aw8695, false);\r
- aw8695_interrupt_clear(aw8695);\r
- if(val < (sizeof(aw8695_rtp_name)/AW8695_RTP_NAME_MAX)) {\r
- aw8695->rtp_file_num = val;\r
- if(val) {\r
- schedule_work(&aw8695->rtp_work);\r
- }\r
- } else {\r
- pr_err("%s: rtp_file_num 0x%02x over max value \n", __func__, aw8695->rtp_file_num);\r
- }\r
-\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_ram_update_show(struct device *dev, struct device_attribute *attr,\r
- char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- //struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- //struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- //struct led_classdev *cdev = dev_get_drvdata(dev);\r
- //struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- ssize_t len = 0;\r
- len += snprintf(buf+len, PAGE_SIZE-len, "sram update mode\n");\r
- return len;\r
-}\r
-\r
-static ssize_t aw8695_ram_update_store(struct device *dev, struct device_attribute *attr,\r
- const char *buf, size_t count)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- unsigned int val = 0;\r
- int rc = 0;\r
-\r
- rc = kstrtouint(buf, 0, &val);\r
- if (rc < 0)\r
- return rc;\r
-\r
- if(val) {\r
- aw8695_ram_update(aw8695);\r
- }\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_f0_show(struct device *dev, struct device_attribute *attr,\r
- char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- ssize_t len = 0;\r
-\r
- mutex_lock(&aw8695->lock);\r
- aw8695->f0_cali_flag = AW8695_HAPTIC_LRA_F0;\r
- aw8695_haptic_get_f0(aw8695);\r
- mutex_unlock(&aw8695->lock);\r
- len += snprintf(buf+len, PAGE_SIZE-len, "aw8695 lra f0 = %d\n", aw8695->f0);\r
- return len;\r
-}\r
-\r
-static ssize_t aw8695_f0_store(struct device *dev, struct device_attribute *attr,\r
- const char *buf, size_t count)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- //struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- //struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- //struct led_classdev *cdev = dev_get_drvdata(dev);\r
- //struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- unsigned int val = 0;\r
- int rc = 0;\r
-\r
- rc = kstrtouint(buf, 0, &val);\r
- if (rc < 0)\r
- return rc;\r
-\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_cali_show(struct device *dev, struct device_attribute *attr,\r
- char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- ssize_t len = 0;\r
- mutex_lock(&aw8695->lock);\r
- aw8695->f0_cali_flag = AW8695_HAPTIC_CALI_F0;\r
- aw8695_haptic_get_f0(aw8695);\r
- mutex_unlock(&aw8695->lock);\r
- len += snprintf(buf+len, PAGE_SIZE-len, "aw8695 cali f0 = %d\n", aw8695->f0);\r
- return len;\r
-}\r
-\r
-static ssize_t aw8695_cali_store(struct device *dev, struct device_attribute *attr,\r
- const char *buf, size_t count)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- unsigned int val = 0;\r
- int rc = 0;\r
-\r
- rc = kstrtouint(buf, 0, &val);\r
- if (rc < 0)\r
- return rc;\r
-\r
- if(val) {\r
- mutex_lock(&aw8695->lock);\r
- aw8695_haptic_f0_calibration(aw8695);\r
- mutex_unlock(&aw8695->lock);\r
- }\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_cont_show(struct device *dev, struct device_attribute *attr,\r
- char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- ssize_t len = 0;\r
- aw8695_haptic_read_cont_f0(aw8695);\r
- len += snprintf(buf+len, PAGE_SIZE-len, "aw8695 cont f0 = %d\n", aw8695->cont_f0);\r
- return len;\r
-}\r
-\r
-static ssize_t aw8695_cont_store(struct device *dev, struct device_attribute *attr,\r
- const char *buf, size_t count)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- unsigned int val = 0;\r
- int rc = 0;\r
-\r
- rc = kstrtouint(buf, 0, &val);\r
- if (rc < 0)\r
- return rc;\r
-\r
- aw8695_haptic_stop(aw8695);\r
- if(val) {\r
- aw8695_haptic_cont(aw8695);\r
- }\r
- return count;\r
-}\r
-\r
-\r
-static ssize_t aw8695_cont_td_show(struct device *dev, struct device_attribute *attr,\r
- char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- ssize_t len = 0;\r
- len += snprintf(buf+len, PAGE_SIZE-len, "aw8695 cont delay time = 0x%04x\n", aw8695->cont_td);\r
- return len;\r
-}\r
-\r
-static ssize_t aw8695_cont_td_store(struct device *dev, struct device_attribute *attr,\r
- const char *buf, size_t count)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- unsigned int databuf[1] = {0};\r
- if(1 == sscanf(buf, "%x", &databuf[0])) {\r
- aw8695->cont_td = databuf[0];\r
- aw8695_i2c_write(aw8695, AW8695_REG_TD_H, (unsigned char)(databuf[0]>>8));\r
- aw8695_i2c_write(aw8695, AW8695_REG_TD_L, (unsigned char)(databuf[0]>>0));\r
- }\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_cont_drv_show(struct device *dev, struct device_attribute *attr,\r
- char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- ssize_t len = 0;\r
- len += snprintf(buf+len, PAGE_SIZE-len, "aw8695 cont drv level = %d\n", aw8695->cont_drv_lvl);\r
- len += snprintf(buf+len, PAGE_SIZE-len, "aw8695 cont drv level overdrive= %d\n", aw8695->cont_drv_lvl_ov);\r
- return len;\r
-}\r
-\r
-static ssize_t aw8695_cont_drv_store(struct device *dev, struct device_attribute *attr,\r
- const char *buf, size_t count)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- unsigned int databuf[2] = {0, 0};\r
- if(2 == sscanf(buf, "%d %d", &databuf[0], &databuf[1])) {\r
- aw8695->cont_drv_lvl = databuf[0];\r
- aw8695_i2c_write(aw8695, AW8695_REG_DRV_LVL, aw8695->cont_drv_lvl);\r
- aw8695->cont_drv_lvl_ov = databuf[1];\r
- aw8695_i2c_write(aw8695, AW8695_REG_DRV_LVL_OV, aw8695->cont_drv_lvl_ov);\r
- }\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_cont_num_brk_show(struct device *dev, struct device_attribute *attr,\r
- char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- ssize_t len = 0;\r
- len += snprintf(buf+len, PAGE_SIZE-len, "aw8695 cont break num = %d\n", aw8695->cont_num_brk);\r
- return len;\r
-}\r
-\r
-static ssize_t aw8695_cont_num_brk_store(struct device *dev, struct device_attribute *attr,\r
- const char *buf, size_t count)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- unsigned int databuf[1] = {0};\r
- if(1 == sscanf(buf, "%d", &databuf[0])) {\r
- aw8695->cont_num_brk = databuf[0];\r
- if(aw8695->cont_num_brk > 7) {\r
- aw8695->cont_num_brk = 7;\r
- }\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_BEMF_NUM,\r
- AW8695_BIT_BEMF_NUM_BRK_MASK, aw8695->cont_num_brk);\r
- }\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_cont_zc_thr_show(struct device *dev, struct device_attribute *attr,\r
- char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- ssize_t len = 0;\r
- len += snprintf(buf+len, PAGE_SIZE-len, "aw8695 cont zero cross thr = 0x%04x\n", aw8695->cont_zc_thr);\r
- return len;\r
-}\r
-\r
-static ssize_t aw8695_cont_zc_thr_store(struct device *dev, struct device_attribute *attr,\r
- const char *buf, size_t count)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- unsigned int databuf[1] = {0};\r
- if(1 == sscanf(buf, "%x", &databuf[0])) {\r
- aw8695->cont_zc_thr = databuf[0];\r
- aw8695_i2c_write(aw8695, AW8695_REG_ZC_THRSH_H, (unsigned char)(databuf[0]>>8));\r
- aw8695_i2c_write(aw8695, AW8695_REG_ZC_THRSH_L, (unsigned char)(databuf[0]>>0));\r
- }\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_vbat_monitor_show(struct device *dev, struct device_attribute *attr,\r
- char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- ssize_t len = 0;\r
- unsigned char reg_val = 0;\r
- unsigned int vbat = 0;\r
-\r
- mutex_lock(&aw8695->lock);\r
- aw8695_haptic_stop(aw8695);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_RAMINIT_MASK, AW8695_BIT_SYSCTRL_RAMINIT_EN);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BYPASS);\r
-\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_DETCTRL,\r
- AW8695_BIT_DETCTRL_DIAG_GO_MASK, AW8695_BIT_DETCTRL_DIAG_GO_ENABLE);\r
- msleep(2);\r
-\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_DETCTRL,\r
- AW8695_BIT_DETCTRL_DIAG_GO_MASK, AW8695_BIT_DETCTRL_DIAG_GO_DISABLE);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_DETCTRL,\r
- AW8695_BIT_DETCTRL_VBAT_GO_MASK, AW8695_BIT_DETCTRL_VABT_GO_ENABLE);\r
- msleep(2);\r
-\r
- aw8695_i2c_read(aw8695, AW8695_REG_VBATDET, ®_val);\r
- vbat = 6100 * reg_val / 256;\r
-\r
- len += snprintf(buf+len, PAGE_SIZE-len, "vbat=%dmV\n", vbat);\r
-\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_RAMINIT_MASK, AW8695_BIT_SYSCTRL_RAMINIT_OFF);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BOOST);\r
- mutex_unlock(&aw8695->lock);\r
-\r
- return len;\r
-}\r
-\r
-static ssize_t aw8695_vbat_monitor_store(struct device *dev, struct device_attribute *attr,\r
- const char *buf, size_t count)\r
-{\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_lra_resistance_show(struct device *dev, struct device_attribute *attr,\r
- char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- ssize_t len = 0;\r
- unsigned char reg_val = 0;\r
- unsigned int r_lra = 0;\r
-\r
- mutex_lock(&aw8695->lock);\r
- aw8695_haptic_stop(aw8695);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_RAMINIT_MASK, AW8695_BIT_SYSCTRL_RAMINIT_EN);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BYPASS);\r
-\r
-\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_ANACTRL,\r
- AW8695_BIT_ANACTRL_HD_PD_MASK, AW8695_BIT_ANACTRL_HD_HZ_EN);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_D2SCFG,\r
- AW8695_BIT_D2SCFG_CLK_ADC_MASK, AW8695_BIT_D2SCFG_CLK_ASC_1P5MHZ);\r
-\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_DETCTRL,\r
- AW8695_BIT_DETCTRL_RL_OS_MASK, AW8695_BIT_DETCTRL_RL_DETECT);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_DETCTRL,\r
- AW8695_BIT_DETCTRL_DIAG_GO_MASK, AW8695_BIT_DETCTRL_DIAG_GO_ENABLE);\r
- msleep(3);\r
- aw8695_i2c_read(aw8695, AW8695_REG_RLDET, ®_val);\r
- r_lra = 298 * reg_val;\r
- len += snprintf(buf+len, PAGE_SIZE-len, "r_lra=%dmohm\n", r_lra);\r
-\r
-\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_ANACTRL,\r
- AW8695_BIT_ANACTRL_HD_PD_MASK, AW8695_BIT_ANACTRL_HD_PD_EN);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_D2SCFG,\r
- AW8695_BIT_D2SCFG_CLK_ADC_MASK, AW8695_BIT_D2SCFG_CLK_ASC_6MHZ);\r
-\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_RAMINIT_MASK, AW8695_BIT_SYSCTRL_RAMINIT_OFF);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BOOST);\r
- mutex_unlock(&aw8695->lock);\r
-\r
- return len;\r
-}\r
-\r
-static ssize_t aw8695_lra_resistance_store(struct device *dev, struct device_attribute *attr,\r
- const char *buf, size_t count)\r
-{\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_auto_boost_show(struct device *dev, struct device_attribute *attr,\r
- char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- ssize_t len = 0;\r
-\r
- len += snprintf(buf+len, PAGE_SIZE-len, "auto_boost=%d\n", aw8695->auto_boost);\r
-\r
- return len;\r
-}\r
-\r
-\r
-static ssize_t aw8695_auto_boost_store(struct device *dev, struct device_attribute *attr,\r
- const char *buf, size_t count)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- unsigned int val = 0;\r
- int rc = 0;\r
-\r
- rc = kstrtouint(buf, 0, &val);\r
- if (rc < 0)\r
- return rc;\r
-\r
- mutex_lock(&aw8695->lock);\r
- aw8695_haptic_stop(aw8695);\r
- aw8695_haptic_auto_boost_config(aw8695, val);\r
- mutex_unlock(&aw8695->lock);\r
-\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_prctmode_show(struct device *dev, struct device_attribute *attr,\r
- char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- ssize_t len = 0;\r
- unsigned char reg_val = 0;\r
-\r
- aw8695_i2c_read(aw8695, AW8695_REG_RLDET, ®_val);\r
-\r
- len += snprintf(buf+len, PAGE_SIZE-len, "prctmode=%d\n", reg_val&0x20);\r
- return len;\r
-}\r
-\r
-\r
-static ssize_t aw8695_prctmode_store(struct device *dev, struct device_attribute *attr,\r
- const char *buf, size_t count)\r
-{\r
- #ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
- #else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
- #endif\r
- unsigned int databuf[2] = {0, 0};\r
- unsigned int addr=0;\r
- unsigned int val=0;\r
- if(2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) {\r
- addr = databuf[0];\r
- val=databuf[1];\r
- mutex_lock(&aw8695->lock);\r
- aw8695_haptic_swicth_motorprotect_config(aw8695, addr, val);\r
- mutex_unlock(&aw8695->lock);\r
- }\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_haptic_audio_show(struct device *dev, struct device_attribute *attr,\r
- char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- ssize_t len = 0;\r
- len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw8695->haptic_audio.cnt);\r
- return len;\r
-}\r
-\r
-static ssize_t aw8695_haptic_audio_store(struct device *dev, struct device_attribute *attr,\r
- const char *buf, size_t count)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- unsigned int databuf[6] = {0};\r
-\r
- if(6 == sscanf(buf, "%d %d %d %d %d %d", &databuf[0], &databuf[1], &databuf[2],\r
- &databuf[3], &databuf[4], &databuf[5])) {\r
- pr_debug("%s: cnt=%d, cmd=%d, play=%d, wavseq=%d, loop=%d, gain=%d\n",\r
- __func__, databuf[0], databuf[1], databuf[2], databuf[3],\r
- databuf[4], databuf[5]);\r
- mutex_lock(&aw8695->haptic_audio.lock);\r
- aw8695->haptic_audio.data[(unsigned char)databuf[0]].cmd = (unsigned char)databuf[1];\r
- aw8695->haptic_audio.data[(unsigned char)databuf[0]].play = (unsigned char)databuf[2];\r
- aw8695->haptic_audio.data[(unsigned char)databuf[0]].wavseq = (unsigned char)databuf[3];\r
- aw8695->haptic_audio.data[(unsigned char)databuf[0]].loop = (unsigned char)databuf[4];\r
- aw8695->haptic_audio.data[(unsigned char)databuf[0]].gain = (unsigned char)databuf[5];\r
- mutex_unlock(&aw8695->haptic_audio.lock);\r
-\r
- if(aw8695->haptic_audio.data[aw8695->haptic_audio.cnt].cmd == 0xff) {\r
- pr_info("%s: haptic_audio stop\n", __func__);\r
- if(hrtimer_active(&aw8695->haptic_audio.timer)) {\r
- pr_info("%s: cancel haptic_audio_timer\n", __func__);\r
- hrtimer_cancel(&aw8695->haptic_audio.timer);\r
- aw8695->haptic_audio.cnt = 0;\r
- aw8695_haptic_set_gain(aw8695, 0x80);\r
- }\r
- } else {\r
- if(hrtimer_active(&aw8695->haptic_audio.timer)) {\r
- } else {\r
- pr_info("%s: start haptic_audio_timer\n", __func__);\r
- hrtimer_start(&aw8695->haptic_audio.timer,\r
- ktime_set(aw8695->haptic_audio.delay_val/1000000,\r
- (aw8695->haptic_audio.delay_val%1000000)*1000),\r
- HRTIMER_MODE_REL);\r
- }\r
- }\r
- }\r
- return count;\r
-}\r
-\r
-\r
-static ssize_t aw8695_haptic_audio_time_show(struct device *dev, struct device_attribute *attr,\r
- char *buf)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- ssize_t len = 0;\r
- len += snprintf(buf+len, PAGE_SIZE-len, "haptic_audio.delay_val=%dus\n", aw8695->haptic_audio.delay_val);\r
- len += snprintf(buf+len, PAGE_SIZE-len, "haptic_audio.timer_val=%dus\n", aw8695->haptic_audio.timer_val);\r
- return len;\r
-}\r
-\r
-static ssize_t aw8695_haptic_audio_time_store(struct device *dev, struct device_attribute *attr,\r
- const char *buf, size_t count)\r
-{\r
-#ifdef TIMED_OUTPUT\r
- struct timed_output_dev *to_dev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);\r
-#else\r
- struct led_classdev *cdev = dev_get_drvdata(dev);\r
- struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);\r
-#endif\r
- unsigned int databuf[2] = {0};\r
-\r
- if(2 == sscanf(buf, "%d %d", &databuf[0], &databuf[1])) {\r
- aw8695->haptic_audio.delay_val = databuf[0];\r
- aw8695->haptic_audio.timer_val = databuf[1];\r
- }\r
- return count;\r
-}\r
-\r
-\r
-static DEVICE_ATTR(state, S_IWUSR | S_IRUGO, aw8695_state_show, aw8695_state_store);\r
-static DEVICE_ATTR(duration, S_IWUSR | S_IRUGO, aw8695_duration_show, aw8695_duration_store);\r
-static DEVICE_ATTR(activate, S_IWUSR | S_IRUGO, aw8695_activate_show, aw8695_activate_store);\r
-static DEVICE_ATTR(activate_mode, S_IWUSR | S_IRUGO, aw8695_activate_mode_show, aw8695_activate_mode_store);\r
-static DEVICE_ATTR(index, S_IWUSR | S_IRUGO, aw8695_index_show, aw8695_index_store);\r
-static DEVICE_ATTR(vmax, S_IWUSR | S_IRUGO, aw8695_vmax_show, aw8695_vmax_store);\r
-static DEVICE_ATTR(gain, S_IWUSR | S_IRUGO, aw8695_gain_show, aw8695_gain_store);\r
-static DEVICE_ATTR(seq, S_IWUSR | S_IRUGO, aw8695_seq_show, aw8695_seq_store);\r
-static DEVICE_ATTR(loop, S_IWUSR | S_IRUGO, aw8695_loop_show, aw8695_loop_store);\r
-static DEVICE_ATTR(register, S_IWUSR | S_IRUGO, aw8695_reg_show, aw8695_reg_store);\r
-static DEVICE_ATTR(rtp, S_IWUSR | S_IRUGO, aw8695_rtp_show, aw8695_rtp_store);\r
-static DEVICE_ATTR(ram_update, S_IWUSR | S_IRUGO, aw8695_ram_update_show, aw8695_ram_update_store);\r
-static DEVICE_ATTR(f0, S_IWUSR | S_IRUGO, aw8695_f0_show, aw8695_f0_store);\r
-static DEVICE_ATTR(cali, S_IWUSR | S_IRUGO, aw8695_cali_show, aw8695_cali_store);\r
-static DEVICE_ATTR(cont, S_IWUSR | S_IRUGO, aw8695_cont_show, aw8695_cont_store);\r
-static DEVICE_ATTR(cont_td, S_IWUSR | S_IRUGO, aw8695_cont_td_show, aw8695_cont_td_store);\r
-static DEVICE_ATTR(cont_drv, S_IWUSR | S_IRUGO, aw8695_cont_drv_show, aw8695_cont_drv_store);\r
-static DEVICE_ATTR(cont_num_brk, S_IWUSR | S_IRUGO, aw8695_cont_num_brk_show, aw8695_cont_num_brk_store);\r
-static DEVICE_ATTR(cont_zc_thr, S_IWUSR | S_IRUGO, aw8695_cont_zc_thr_show, aw8695_cont_zc_thr_store);\r
-static DEVICE_ATTR(vbat_monitor, S_IWUSR | S_IRUGO, aw8695_vbat_monitor_show, aw8695_vbat_monitor_store);\r
-static DEVICE_ATTR(lra_resistance, S_IWUSR | S_IRUGO, aw8695_lra_resistance_show, aw8695_lra_resistance_store);\r
-static DEVICE_ATTR(auto_boost, S_IWUSR | S_IRUGO, aw8695_auto_boost_show, aw8695_auto_boost_store);\r
-static DEVICE_ATTR(prctmode, S_IWUSR | S_IRUGO, aw8695_prctmode_show, aw8695_prctmode_store);\r
-static DEVICE_ATTR(haptic_audio, S_IWUSR | S_IRUGO, aw8695_haptic_audio_show, aw8695_haptic_audio_store);\r
-static DEVICE_ATTR(haptic_audio_time, S_IWUSR | S_IRUGO, aw8695_haptic_audio_time_show, aw8695_haptic_audio_time_store);\r
-\r
-\r
-static struct attribute *aw8695_vibrator_attributes[] = {\r
- &dev_attr_state.attr,\r
- &dev_attr_duration.attr,\r
- &dev_attr_activate.attr,\r
- &dev_attr_activate_mode.attr,\r
- &dev_attr_index.attr,\r
- &dev_attr_vmax.attr,\r
- &dev_attr_gain.attr,\r
- &dev_attr_seq.attr,\r
- &dev_attr_loop.attr,\r
- &dev_attr_register.attr,\r
- &dev_attr_rtp.attr,\r
- &dev_attr_ram_update.attr,\r
- &dev_attr_f0.attr,\r
- &dev_attr_cali.attr,\r
- &dev_attr_cont.attr,\r
- &dev_attr_cont_td.attr,\r
- &dev_attr_cont_drv.attr,\r
- &dev_attr_cont_num_brk.attr,\r
- &dev_attr_cont_zc_thr.attr,\r
- &dev_attr_vbat_monitor.attr,\r
- &dev_attr_lra_resistance.attr,\r
- &dev_attr_auto_boost.attr,\r
- &dev_attr_prctmode.attr,\r
- &dev_attr_haptic_audio.attr,\r
- &dev_attr_haptic_audio_time.attr,\r
- NULL\r
-};\r
-\r
-static struct attribute_group aw8695_vibrator_attribute_group = {\r
- .attrs = aw8695_vibrator_attributes\r
-};\r
-\r
-static enum hrtimer_restart aw8695_vibrator_timer_func(struct hrtimer *timer)\r
-{\r
- struct aw8695 *aw8695 = container_of(timer, struct aw8695, timer);\r
-\r
- pr_debug("%s enter\n", __func__);\r
- aw8695->state = 0;\r
- schedule_work(&aw8695->vibrator_work);\r
-\r
- return HRTIMER_NORESTART;\r
-}\r
-\r
-static void aw8695_vibrator_work_routine(struct work_struct *work)\r
-{\r
- struct aw8695 *aw8695 = container_of(work, struct aw8695, vibrator_work);\r
-\r
- pr_debug("%s enter\n", __func__);\r
-\r
- mutex_lock(&aw8695->lock);\r
-\r
- aw8695_haptic_stop(aw8695);\r
- if(aw8695->state) {\r
- if(aw8695->activate_mode == AW8695_HAPTIC_ACTIVATE_RAM_MODE) {\r
- aw8695_haptic_play_repeat_seq(aw8695, true);\r
- } else if(aw8695->activate_mode == AW8695_HAPTIC_ACTIVATE_CONT_MODE) {\r
- aw8695_haptic_cont(aw8695);\r
- } else {\r
- }\r
- }\r
- mutex_unlock(&aw8695->lock);\r
-}\r
-\r
-static int aw8695_vibrator_init(struct aw8695 *aw8695)\r
-{\r
- int ret = 0;\r
-\r
- pr_info("%s enter\n", __func__);\r
-\r
-#ifdef TIMED_OUTPUT\r
- aw8695->to_dev.name = "vibrator";\r
- aw8695->to_dev.get_time = aw8695_vibrator_get_time;\r
- aw8695->to_dev.enable = aw8695_vibrator_enable;\r
-\r
- ret = timed_output_dev_register(&(aw8695->to_dev));\r
- if ( ret < 0){\r
- dev_err(aw8695->dev, "%s: fail to create timed output dev\n",\r
- __func__);\r
- return ret;\r
- }\r
- ret = sysfs_create_group(&aw8695->to_dev.dev->kobj, &aw8695_vibrator_attribute_group);\r
- if (ret < 0) {\r
- dev_err(aw8695->dev, "%s error creating sysfs attr files\n", __func__);\r
- return ret;\r
- }\r
-#else\r
- aw8695->cdev.name = "vibrator";\r
- aw8695->cdev.brightness_get = aw8695_haptic_brightness_get;\r
- aw8695->cdev.brightness_set = aw8695_haptic_brightness_set;\r
-\r
- ret = devm_led_classdev_register(&aw8695->i2c->dev, &aw8695->cdev);\r
- if (ret < 0){\r
- dev_err(aw8695->dev, "%s: fail to create led dev\n",\r
- __func__);\r
- return ret;\r
- }\r
- ret = sysfs_create_group(&aw8695->cdev.dev->kobj, &aw8695_vibrator_attribute_group);\r
- if (ret < 0) {\r
- dev_err(aw8695->dev, "%s error creating sysfs attr files\n", __func__);\r
- return ret;\r
- }\r
-#endif\r
- hrtimer_init(&aw8695->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);\r
- aw8695->timer.function = aw8695_vibrator_timer_func;\r
- INIT_WORK(&aw8695->vibrator_work, aw8695_vibrator_work_routine);\r
-\r
- INIT_WORK(&aw8695->rtp_work, aw8695_rtp_work_routine);\r
-\r
- mutex_init(&aw8695->lock);\r
-\r
- return 0;\r
-}\r
-\r
-\r
-\r
-\r
-/******************************************************\r
- *\r
- * irq\r
- *\r
- ******************************************************/\r
-static void aw8695_interrupt_clear(struct aw8695 *aw8695)\r
-{\r
- unsigned char reg_val = 0;\r
- pr_info("%s enter\n", __func__);\r
- aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val);\r
- pr_info("%s: reg SYSINT=0x%x\n", __func__, reg_val);\r
-}\r
-\r
-static void aw8695_interrupt_setup(struct aw8695 *aw8695)\r
-{\r
- unsigned char reg_val = 0;\r
-\r
- pr_info("%s enter\n", __func__);\r
-\r
- aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val);\r
- pr_info("%s: reg SYSINT=0x%x\n", __func__, reg_val);\r
-\r
- /* edge int mode */\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_DBGCTRL,\r
- AW8695_BIT_DBGCTRL_INT_MODE_MASK, AW8695_BIT_DBGCTRL_INT_MODE_EDGE);\r
-\r
- /* int enable */\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM,\r
- AW8695_BIT_SYSINTM_BSTERR_MASK, AW8695_BIT_SYSINTM_BSTERR_OFF);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM,\r
- AW8695_BIT_SYSINTM_OV_MASK, AW8695_BIT_SYSINTM_OV_EN);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM,\r
- AW8695_BIT_SYSINTM_UVLO_MASK, AW8695_BIT_SYSINTM_UVLO_EN);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM,\r
- AW8695_BIT_SYSINTM_OCD_MASK, AW8695_BIT_SYSINTM_OCD_EN);\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM,\r
- AW8695_BIT_SYSINTM_OT_MASK, AW8695_BIT_SYSINTM_OT_EN);\r
-}\r
-\r
-static irqreturn_t aw8695_irq(int irq, void *data)\r
-{\r
- struct aw8695 *aw8695 = data;\r
- unsigned char reg_val = 0;\r
- unsigned char dbg_val = 0;\r
- unsigned int buf_len = 0;\r
-\r
- pr_debug("%s enter\n", __func__);\r
-\r
- aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val);\r
- pr_info("%s: reg SYSINT=0x%x\n", __func__, reg_val);\r
- aw8695_i2c_read(aw8695, AW8695_REG_DBGSTAT, &dbg_val);\r
- pr_info("%s: reg DBGSTAT=0x%x\n", __func__, dbg_val);\r
-\r
- if(reg_val & AW8695_BIT_SYSINT_OVI) {\r
- pr_err("%s chip ov int error\n", __func__);\r
- }\r
- if(reg_val & AW8695_BIT_SYSINT_UVLI) {\r
- pr_err("%s chip uvlo int error\n", __func__);\r
- }\r
- if(reg_val & AW8695_BIT_SYSINT_OCDI) {\r
- pr_err("%s chip over current int error\n", __func__);\r
- }\r
- if(reg_val & AW8695_BIT_SYSINT_OTI) {\r
- pr_err("%s chip over temperature int error\n", __func__);\r
- }\r
- if(reg_val & AW8695_BIT_SYSINT_DONEI) {\r
- pr_info("%s chip playback done\n", __func__);\r
- }\r
-\r
- if(reg_val & AW8695_BIT_SYSINT_FF_AEI) {\r
- pr_debug("%s: aw8695 rtp fifo almost empty int\n", __func__);\r
- if(aw8695->rtp_init) {\r
- while((!aw8695_haptic_rtp_get_fifo_afi(aw8695)) &&\r
- (aw8695->play_mode == AW8695_HAPTIC_RTP_MODE)) {\r
- pr_info("%s: aw8695 rtp mode fifo update, cnt=%d\n",\r
- __func__, aw8695->rtp_cnt);\r
- if((aw8695_rtp->len-aw8695->rtp_cnt) < (aw8695->ram.base_addr>>2)) {\r
- buf_len = aw8695_rtp->len-aw8695->rtp_cnt;\r
- } else {\r
- buf_len = (aw8695->ram.base_addr>>2);\r
- }\r
- aw8695_i2c_writes(aw8695, AW8695_REG_RTP_DATA,\r
- &aw8695_rtp->data[aw8695->rtp_cnt], buf_len);\r
- aw8695->rtp_cnt += buf_len;\r
- if(aw8695->rtp_cnt == aw8695_rtp->len) {\r
- pr_info("%s: rtp update complete\n", __func__);\r
- aw8695_haptic_set_rtp_aei(aw8695, false);\r
- aw8695->rtp_cnt = 0;\r
- aw8695->rtp_init = 0;\r
- break;\r
- }\r
- }\r
- } else {\r
- pr_err("%s: aw8695 rtp init = %d, init error\n", __func__, aw8695->rtp_init);\r
- }\r
- }\r
-\r
- if(reg_val & AW8695_BIT_SYSINT_FF_AFI) {\r
- pr_debug("%s: aw8695 rtp mode fifo full empty\n", __func__);\r
- }\r
-\r
- if(aw8695->play_mode != AW8695_HAPTIC_RTP_MODE) {\r
- aw8695_haptic_set_rtp_aei(aw8695, false);\r
- }\r
-\r
- aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val);\r
- pr_debug("%s: reg SYSINT=0x%x\n", __func__, reg_val);\r
- aw8695_i2c_read(aw8695, AW8695_REG_SYSST, ®_val);\r
- pr_debug("%s: reg SYSST=0x%x\n", __func__, reg_val);\r
-\r
- pr_debug("%s exit\n", __func__);\r
-\r
- return IRQ_HANDLED;\r
-}\r
-\r
-/*****************************************************\r
- *\r
- * device tree\r
- *\r
- *****************************************************/\r
-static int aw8695_parse_dt(struct device *dev, struct aw8695 *aw8695,\r
- struct device_node *np) {\r
- aw8695->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);\r
- if (aw8695->reset_gpio < 0) {\r
- dev_err(dev, "%s: no reset gpio provided, will not HW reset device\n", __func__);\r
- return -1;\r
- } else {\r
- dev_info(dev, "%s: reset gpio provided ok\n", __func__);\r
- }\r
- aw8695->irq_gpio = of_get_named_gpio(np, "irq-gpio", 0);\r
- if (aw8695->irq_gpio < 0) {\r
- dev_err(dev, "%s: no irq gpio provided.\n", __func__);\r
- } else {\r
- dev_info(dev, "%s: irq gpio provided ok.\n", __func__);\r
- }\r
-\r
- return 0;\r
-}\r
-\r
-static int aw8695_hw_reset(struct aw8695 *aw8695)\r
-{\r
- pr_info("%s enter\n", __func__);\r
-\r
- if (aw8695 && gpio_is_valid(aw8695->reset_gpio)) {\r
- gpio_set_value_cansleep(aw8695->reset_gpio, 0);\r
- msleep(1);\r
- gpio_set_value_cansleep(aw8695->reset_gpio, 1);\r
- msleep(1);\r
- } else {\r
- dev_err(aw8695->dev, "%s: failed\n", __func__);\r
- }\r
- return 0;\r
-}\r
-\r
-\r
-/*****************************************************\r
- *\r
- * check chip id\r
- *\r
- *****************************************************/\r
-static int aw8695_read_chipid(struct aw8695 *aw8695)\r
-{\r
- int ret = -1;\r
- unsigned char cnt = 0;\r
- unsigned char reg = 0;\r
-\r
- while(cnt < AW_READ_CHIPID_RETRIES) {\r
- /* hardware reset */\r
- aw8695_hw_reset(aw8695);\r
-\r
- ret = aw8695_i2c_read(aw8695, AW8695_REG_ID, ®);\r
- if (ret < 0) {\r
- dev_err(aw8695->dev, "%s: failed to read register AW8695_REG_ID: %d\n", __func__, ret);\r
- }\r
- switch (reg) {\r
- case AW8695_CHIPID:\r
- pr_info("%s aw8695 detected\n", __func__);\r
- aw8695->chipid = AW8695_CHIPID;\r
- //aw8695->flags |= AW8695_FLAG_SKIP_INTERRUPTS;\r
- aw8695_haptic_softreset(aw8695);\r
- return 0;\r
- default:\r
- pr_info("%s unsupported device revision (0x%x)\n", __func__, reg );\r
- break;\r
- }\r
- cnt ++;\r
-\r
- msleep(AW_READ_CHIPID_RETRY_DELAY);\r
- }\r
-\r
- return -EINVAL;\r
-}\r
-\r
-/******************************************************\r
- *\r
- * sys group attribute: reg\r
- *\r
- ******************************************************/\r
-static ssize_t aw8695_i2c_reg_store(struct device *dev, struct device_attribute *attr,\r
- const char *buf, size_t count)\r
-{\r
- struct aw8695 *aw8695 = dev_get_drvdata(dev);\r
-\r
- unsigned int databuf[2] = {0, 0};\r
-\r
- if(2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) {\r
- aw8695_i2c_write(aw8695, (unsigned char)databuf[0], (unsigned char)databuf[1]);\r
- }\r
-\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_i2c_reg_show(struct device *dev, struct device_attribute *attr,\r
- char *buf)\r
-{\r
- struct aw8695 *aw8695 = dev_get_drvdata(dev);\r
- ssize_t len = 0;\r
- unsigned char i = 0;\r
- unsigned char reg_val = 0;\r
- for(i = 0; i < AW8695_REG_MAX; i ++) {\r
- if(!(aw8695_reg_access[i]®_RD_ACCESS))\r
- continue;\r
- aw8695_i2c_read(aw8695, i, ®_val);\r
- len += snprintf(buf+len, PAGE_SIZE-len, "reg:0x%02x=0x%02x \n", i, reg_val);\r
- }\r
- return len;\r
-}\r
-static ssize_t aw8695_i2c_ram_store(struct device *dev, struct device_attribute *attr,\r
- const char *buf, size_t count)\r
-{\r
- struct aw8695 *aw8695 = dev_get_drvdata(dev);\r
-\r
- unsigned int databuf[1] = {0};\r
-\r
- if(1 == sscanf(buf, "%x", &databuf[0])) {\r
- if(1 == databuf[0]) {\r
- aw8695_ram_update(aw8695);\r
- }\r
- }\r
-\r
- return count;\r
-}\r
-\r
-static ssize_t aw8695_i2c_ram_show(struct device *dev, struct device_attribute *attr,\r
- char *buf)\r
-{\r
- struct aw8695 *aw8695 = dev_get_drvdata(dev);\r
- ssize_t len = 0;\r
- unsigned int i = 0;\r
- unsigned char reg_val = 0;\r
-\r
- aw8695_haptic_stop(aw8695);\r
- /* RAMINIT Enable */\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_RAMINIT_MASK, AW8695_BIT_SYSCTRL_RAMINIT_EN);\r
-\r
- aw8695_i2c_write(aw8695, AW8695_REG_RAMADDRH, (unsigned char)(aw8695->ram.base_addr>>8));\r
- aw8695_i2c_write(aw8695, AW8695_REG_RAMADDRL, (unsigned char)(aw8695->ram.base_addr&0x00ff));\r
- len += snprintf(buf+len, PAGE_SIZE-len, "aw8695_haptic_ram:\n");\r
- for(i=0; i<aw8695->ram.len; i++) {\r
- aw8695_i2c_read(aw8695, AW8695_REG_RAMDATA, ®_val);\r
- len += snprintf(buf+len, PAGE_SIZE-len, "0x%02x,", reg_val);\r
- }\r
- len += snprintf(buf+len, PAGE_SIZE-len, "\n");\r
- /* RAMINIT Disable */\r
- aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,\r
- AW8695_BIT_SYSCTRL_RAMINIT_MASK, AW8695_BIT_SYSCTRL_RAMINIT_OFF);\r
-\r
- return len;\r
-}\r
-\r
-static DEVICE_ATTR(reg, S_IWUSR | S_IRUGO, aw8695_i2c_reg_show, aw8695_i2c_reg_store);\r
-static DEVICE_ATTR(ram, S_IWUSR | S_IRUGO, aw8695_i2c_ram_show, aw8695_i2c_ram_store);\r
-\r
-static struct attribute *aw8695_attributes[] = {\r
- &dev_attr_reg.attr,\r
- &dev_attr_ram.attr,\r
- NULL\r
-};\r
-\r
-static struct attribute_group aw8695_attribute_group = {\r
- .attrs = aw8695_attributes\r
-};\r
-\r
-\r
-/******************************************************\r
- *\r
- * i2c driver\r
- *\r
- ******************************************************/\r
-static int aw8695_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)\r
-{\r
- struct aw8695 *aw8695;\r
- struct device_node *np = i2c->dev.of_node;\r
- int irq_flags = 0;\r
- int ret = -1;\r
-\r
- pr_info("%s enter\n", __func__);\r
-\r
- if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) {\r
- dev_err(&i2c->dev, "check_functionality failed\n");\r
- return -EIO;\r
- }\r
-\r
- aw8695 = devm_kzalloc(&i2c->dev, sizeof(struct aw8695), GFP_KERNEL);\r
- if (aw8695 == NULL)\r
- return -ENOMEM;\r
-\r
- aw8695->dev = &i2c->dev;\r
- aw8695->i2c = i2c;\r
-\r
- i2c_set_clientdata(i2c, aw8695);\r
-\r
- /* aw8695 rst & int */\r
- if (np) {\r
- ret = aw8695_parse_dt(&i2c->dev, aw8695, np);\r
- if (ret) {\r
- dev_err(&i2c->dev, "%s: failed to parse device tree node\n", __func__);\r
- goto err_parse_dt;\r
- }\r
- } else {\r
- aw8695->reset_gpio = -1;\r
- aw8695->irq_gpio = -1;\r
- }\r
-\r
- if (gpio_is_valid(aw8695->reset_gpio)) {\r
- ret = devm_gpio_request_one(&i2c->dev, aw8695->reset_gpio,\r
- GPIOF_OUT_INIT_LOW, "aw8695_rst");\r
- if (ret){\r
- dev_err(&i2c->dev, "%s: rst request failed\n", __func__);\r
- goto err_gpio_request;\r
- }\r
- }\r
-\r
- if (gpio_is_valid(aw8695->irq_gpio)) {\r
- ret = devm_gpio_request_one(&i2c->dev, aw8695->irq_gpio,\r
- GPIOF_DIR_IN, "aw8695_int");\r
- if (ret){\r
- dev_err(&i2c->dev, "%s: int request failed\n", __func__);\r
- goto err_gpio_request;\r
- }\r
- }\r
-\r
- /* aw8695 chip id */\r
- ret = aw8695_read_chipid(aw8695);\r
- if (ret < 0) {\r
- dev_err(&i2c->dev, "%s: aw8695_read_chipid failed ret=%d\n", __func__, ret);\r
- goto err_id;\r
- }\r
-\r
- /* aw8695 irq */\r
- if (gpio_is_valid(aw8695->irq_gpio) &&\r
- !(aw8695->flags & AW8695_FLAG_SKIP_INTERRUPTS)) {\r
- /* register irq handler */\r
- aw8695_interrupt_setup(aw8695);\r
- irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;\r
- ret = devm_request_threaded_irq(&i2c->dev,\r
- gpio_to_irq(aw8695->irq_gpio),\r
- NULL, aw8695_irq, irq_flags,\r
- "aw8695", aw8695);\r
- if (ret != 0) {\r
- dev_err(&i2c->dev, "%s: failed to request IRQ %d: %d\n",\r
- __func__, gpio_to_irq(aw8695->irq_gpio), ret);\r
- goto err_irq;\r
- }\r
- } else {\r
- dev_info(&i2c->dev, "%s skipping IRQ registration\n", __func__);\r
- /* disable feature support if gpio was invalid */\r
- aw8695->flags |= AW8695_FLAG_SKIP_INTERRUPTS;\r
- }\r
-\r
- dev_set_drvdata(&i2c->dev, aw8695);\r
-\r
- ret = sysfs_create_group(&i2c->dev.kobj, &aw8695_attribute_group);\r
- if (ret < 0) {\r
- dev_info(&i2c->dev, "%s error creating sysfs attr files\n", __func__);\r
- goto err_sysfs;\r
- }\r
-\r
- g_aw8695 = aw8695;\r
-\r
- aw8695_vibrator_init(aw8695);\r
-\r
- aw8695_haptic_init(aw8695);\r
-\r
- aw8695_ram_init(aw8695);\r
-\r
- pr_info("%s probe completed successfully!\n", __func__);\r
-\r
- return 0;\r
-\r
-err_sysfs:\r
- devm_free_irq(&i2c->dev, gpio_to_irq(aw8695->irq_gpio), aw8695);\r
-err_irq:\r
-err_id:\r
- if (gpio_is_valid(aw8695->irq_gpio))\r
- devm_gpio_free(&i2c->dev, aw8695->irq_gpio);\r
- if (gpio_is_valid(aw8695->reset_gpio))\r
- devm_gpio_free(&i2c->dev, aw8695->reset_gpio);\r
-err_gpio_request:\r
-err_parse_dt:\r
- devm_kfree(&i2c->dev, aw8695);\r
- aw8695 = NULL;\r
- return ret;\r
-}\r
-\r
-static int aw8695_i2c_remove(struct i2c_client *i2c)\r
-{\r
- struct aw8695 *aw8695 = i2c_get_clientdata(i2c);\r
-\r
- pr_info("%s enter\n", __func__);\r
-\r
- sysfs_remove_group(&i2c->dev.kobj, &aw8695_attribute_group);\r
-\r
- devm_free_irq(&i2c->dev, gpio_to_irq(aw8695->irq_gpio), aw8695);\r
-\r
- if (gpio_is_valid(aw8695->irq_gpio))\r
- devm_gpio_free(&i2c->dev, aw8695->irq_gpio);\r
- if (gpio_is_valid(aw8695->reset_gpio))\r
- devm_gpio_free(&i2c->dev, aw8695->reset_gpio);\r
-\r
- devm_kfree(&i2c->dev, aw8695);\r
- aw8695 = NULL;\r
-\r
- return 0;\r
-}\r
-\r
-static const struct i2c_device_id aw8695_i2c_id[] = {\r
- { AW8695_I2C_NAME, 0 },\r
- { }\r
-};\r
-MODULE_DEVICE_TABLE(i2c, aw8695_i2c_id);\r
-\r
-static struct of_device_id aw8695_dt_match[] = {\r
- { .compatible = "awinic,aw8695_haptic" },\r
- { },\r
-};\r
-\r
-static struct i2c_driver aw8695_i2c_driver = {\r
- .driver = {\r
- .name = AW8695_I2C_NAME,\r
- .owner = THIS_MODULE,\r
- .of_match_table = of_match_ptr(aw8695_dt_match),\r
- },\r
- .probe = aw8695_i2c_probe,\r
- .remove = aw8695_i2c_remove,\r
- .id_table = aw8695_i2c_id,\r
-};\r
-\r
-\r
-static int __init aw8695_i2c_init(void)\r
-{\r
- int ret = 0;\r
-\r
- pr_info("aw8695 driver version %s\n", AW8695_VERSION);\r
-\r
- ret = i2c_add_driver(&aw8695_i2c_driver);\r
- if(ret){\r
- pr_err("fail to add aw8695 device into i2c\n");\r
- return ret;\r
- }\r
-\r
- return 0;\r
-}\r
-//late_initcall(aw8695_i2c_init);\r
-module_init(aw8695_i2c_init);\r
-\r
-\r
-static void __exit aw8695_i2c_exit(void)\r
-{\r
- i2c_del_driver(&aw8695_i2c_driver);\r
-}\r
-module_exit(aw8695_i2c_exit);\r
-\r
-\r
-MODULE_DESCRIPTION("AW8695 Haptic Driver");\r
-MODULE_LICENSE("GPL v2");\r
+/*
+ * aw8695.c aw8695 haptic module
+ *
+ * Version: v1.2.8
+ *
+ * Copyright (c) 2018 AWINIC Technology CO., LTD
+ *
+ * Author: Nick Li <liweilei@awinic.com.cn>
+ *
+ * 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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/of_gpio.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/debugfs.h>
+#include <linux/miscdevice.h>
+#include <asm/uaccess.h>
+#include <linux/syscalls.h>
+#include <linux/power_supply.h>
+#include "aw8695.h"
+#include "aw8695_reg.h"
+#include "aw8695_config.h"
+
+/******************************************************
+ *
+ * Marco
+ *
+ ******************************************************/
+#define AW8695_I2C_NAME "aw8695_haptic"
+#define AW8695_HAPTIC_NAME "aw8695_haptic"
+
+#define AW8695_VERSION "v1.2.8"
+
+
+#define AWINIC_RAM_UPDATE_DELAY
+
+#define AW_I2C_RETRIES 2
+#define AW_I2C_RETRY_DELAY 2
+#define AW_READ_CHIPID_RETRIES 5
+#define AW_READ_CHIPID_RETRY_DELAY 2
+
+#define AW8695_MAX_DSP_START_TRY_COUNT 10
+
+
+
+#define AW8695_MAX_FIRMWARE_LOAD_CNT 20
+#ifdef MOTO_VIBRATOR_SUPPORT
+#define AW8695_SEQ_NO_RTP_BASE 102
+#endif
+/******************************************************
+ *
+ * variable
+ *
+ ******************************************************/
+#define AW8695_RTP_NAME_MAX 64
+static char *aw8695_ram_name = "aw8695_haptic.bin";
+static char aw8695_rtp_name[][AW8695_RTP_NAME_MAX] = {
+ {"aw8695_rtp.bin"},
+ {"aw8695_rtp_lighthouse.bin"},
+ {"aw8695_rtp_silk.bin"},
+};
+
+struct aw8695_container *aw8695_rtp;
+struct aw8695 *g_aw8695;
+
+/******************************************************
+ *
+ * functions
+ *
+ ******************************************************/
+static void aw8695_interrupt_clear(struct aw8695 *aw8695);
+static int aw8695_haptic_trig_enable_config(struct aw8695 *aw8695);
+#ifdef MOTO_VIBRATOR_SUOOPRT
+static void aw8695_vibrate(struct aw8695 *aw8695, int value);
+#endif
+
+ /******************************************************
+ *
+ * aw8695 i2c write/read
+ *
+ ******************************************************/
+static int aw8695_i2c_write(struct aw8695 *aw8695,
+ unsigned char reg_addr, unsigned char reg_data)
+{
+ int ret = -1;
+ unsigned char cnt = 0;
+
+ while(cnt < AW_I2C_RETRIES) {
+ ret = i2c_smbus_write_byte_data(aw8695->i2c, reg_addr, reg_data);
+ if(ret < 0) {
+ pr_err("%s: i2c_write cnt=%d error=%d\n", __func__, cnt, ret);
+ } else {
+ break;
+ }
+ cnt ++;
+ msleep(AW_I2C_RETRY_DELAY);
+ }
+
+ return ret;
+}
+
+static int aw8695_i2c_read(struct aw8695 *aw8695,
+ unsigned char reg_addr, unsigned char *reg_data)
+{
+ int ret = -1;
+ unsigned char cnt = 0;
+
+ while(cnt < AW_I2C_RETRIES) {
+ ret = i2c_smbus_read_byte_data(aw8695->i2c, reg_addr);
+ if(ret < 0) {
+ pr_err("%s: i2c_read cnt=%d error=%d\n", __func__, cnt, ret);
+ } else {
+ *reg_data = ret;
+ break;
+ }
+ cnt ++;
+ msleep(AW_I2C_RETRY_DELAY);
+ }
+
+ return ret;
+}
+
+static int aw8695_i2c_write_bits(struct aw8695 *aw8695,
+ unsigned char reg_addr, unsigned int mask, unsigned char reg_data)
+{
+ unsigned char reg_val = 0;
+
+ aw8695_i2c_read(aw8695, reg_addr, ®_val);
+ reg_val &= mask;
+ reg_val |= reg_data;
+ aw8695_i2c_write(aw8695, reg_addr, reg_val);
+
+ return 0;
+}
+
+static int aw8695_i2c_writes(struct aw8695 *aw8695,
+ unsigned char reg_addr, unsigned char *buf, unsigned int len)
+{
+ int ret = -1;
+ unsigned char *data;
+
+ data = kmalloc(len+1, GFP_KERNEL);
+ if (data == NULL) {
+ pr_err("%s: can not allocate memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ data[0] = reg_addr;
+ memcpy(&data[1], buf, len);
+
+ ret = i2c_master_send(aw8695->i2c, data, len+1);
+ if (ret < 0) {
+ pr_err("%s: i2c master send error\n", __func__);
+ }
+
+ kfree(data);
+
+ return ret;
+}
+
+/*****************************************************
+ *
+ * ram update
+ *
+ *****************************************************/
+static void aw8695_rtp_loaded(const struct firmware *cont, void *context)
+{
+ struct aw8695 *aw8695 = context;
+ pr_info("%s enter\n", __func__);
+
+ if (!cont) {
+ pr_err("%s: failed to read %s\n", __func__, aw8695_rtp_name[aw8695->rtp_file_num]);
+ release_firmware(cont);
+ return;
+ }
+
+ pr_info("%s: loaded %s - size: %zu\n", __func__, aw8695_rtp_name[aw8695->rtp_file_num],
+ cont ? cont->size : 0);
+
+ /* aw8695 rtp update */
+ aw8695_rtp = kzalloc(cont->size+sizeof(int), GFP_KERNEL);
+ if (!aw8695_rtp) {
+ release_firmware(cont);
+ pr_err("%s: Error allocating memory\n", __func__);
+ return;
+ }
+ aw8695_rtp->len = cont->size;
+ pr_info("%s: rtp size = %d\n", __func__, aw8695_rtp->len);
+ memcpy(aw8695_rtp->data, cont->data, cont->size);
+ release_firmware(cont);
+
+ aw8695->rtp_init = 1;
+ pr_info("%s: rtp update complete\n", __func__);
+}
+
+static int aw8695_rtp_update(struct aw8695 *aw8695)
+{
+ pr_info("%s enter\n", __func__);
+
+ return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+ aw8695_rtp_name[aw8695->rtp_file_num], aw8695->dev, GFP_KERNEL,
+ aw8695, aw8695_rtp_loaded);
+}
+
+
+ static void aw8695_container_update(struct aw8695 *aw8695,
+ struct aw8695_container *aw8695_cont)
+{
+ int i = 0;
+ unsigned int shift = 0;
+
+ pr_info("%s enter\n", __func__);
+
+ mutex_lock(&aw8695->lock);
+
+ aw8695->ram.baseaddr_shift = 2;
+ aw8695->ram.ram_shift = 4;
+
+ /* RAMINIT Enable */
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_RAMINIT_MASK, AW8695_BIT_SYSCTRL_RAMINIT_EN);
+
+ /* base addr */
+ shift = aw8695->ram.baseaddr_shift;
+ aw8695->ram.base_addr = (unsigned int)((aw8695_cont->data[0+shift]<<8) |
+ (aw8695_cont->data[1+shift]));
+ pr_info("%s: base_addr=0x%4x\n", __func__, aw8695->ram.base_addr);
+
+ aw8695_i2c_write(aw8695, AW8695_REG_BASE_ADDRH, aw8695_cont->data[0+shift]);
+ aw8695_i2c_write(aw8695, AW8695_REG_BASE_ADDRL, aw8695_cont->data[1+shift]);
+
+ aw8695_i2c_write(aw8695, AW8695_REG_FIFO_AEH,
+ (unsigned char)((aw8695->ram.base_addr>>2)>>8));
+ aw8695_i2c_write(aw8695, AW8695_REG_FIFO_AEL,
+ (unsigned char)((aw8695->ram.base_addr>>2)&0x00FF));
+ aw8695_i2c_write(aw8695, AW8695_REG_FIFO_AFH,
+ (unsigned char)((aw8695->ram.base_addr-(aw8695->ram.base_addr>>2))>>8));
+ aw8695_i2c_write(aw8695, AW8695_REG_FIFO_AFL,
+ (unsigned char)((aw8695->ram.base_addr-(aw8695->ram.base_addr>>2))&0x00FF));
+
+ /* ram */
+ shift = aw8695->ram.baseaddr_shift;
+ aw8695_i2c_write(aw8695, AW8695_REG_RAMADDRH, aw8695_cont->data[0+shift]);
+ aw8695_i2c_write(aw8695, AW8695_REG_RAMADDRL, aw8695_cont->data[1+shift]);
+ shift = aw8695->ram.ram_shift;
+ for(i=shift; i<aw8695_cont->len; i++) {
+ aw8695_i2c_write(aw8695, AW8695_REG_RAMDATA, aw8695_cont->data[i]);
+ }
+
+#if 0
+ /* ram check */
+ shift = aw8695->ram.baseaddr_shift;
+ aw8695_i2c_write(aw8695, AW8695_REG_RAMADDRH, aw8695_cont->data[0+shift]);
+ aw8695_i2c_write(aw8695, AW8695_REG_RAMADDRL, aw8695_cont->data[1+shift]);
+ shift = aw8695->ram.ram_shift;
+ for(i=shift; i<aw8695_cont->len; i++) {
+ aw8695_i2c_read(aw8695, AW8695_REG_RAMDATA, ®_val);
+ if(reg_val != aw8695_cont->data[i]) {
+ pr_err("%s: ram check error addr=0x%04x, file_data=0x%02x, ram_data=0x%02x\n",
+ __func__, i, aw8695_cont->data[i], reg_val);
+ return;
+ }
+ }
+#endif
+
+ /* RAMINIT Disable */
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_RAMINIT_MASK, AW8695_BIT_SYSCTRL_RAMINIT_OFF);
+
+ mutex_unlock(&aw8695->lock);
+
+ pr_info("%s exit\n", __func__);
+}
+
+
+static void aw8695_ram_loaded(const struct firmware *cont, void *context)
+{
+ struct aw8695 *aw8695 = context;
+ struct aw8695_container *aw8695_fw;
+ int i = 0;
+ unsigned short check_sum = 0;
+
+ pr_info("%s enter\n", __func__);
+
+ if (!cont) {
+ pr_err("%s: failed to read %s\n", __func__, aw8695_ram_name);
+ release_firmware(cont);
+ return;
+ }
+
+ pr_info("%s: loaded %s - size: %zu\n", __func__, aw8695_ram_name,
+ cont ? cont->size : 0);
+/*
+ for(i=0; i<cont->size; i++) {
+ pr_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]))) {
+ pr_err("%s: check sum err: check_sum=0x%04x\n", __func__, check_sum);
+ return;
+ } else {
+ pr_info("%s: check sum pass : 0x%04x\n", __func__, check_sum);
+ aw8695->ram.check_sum = check_sum;
+ }
+
+ /* aw8695 ram update */
+ aw8695_fw = kzalloc(cont->size+sizeof(int), GFP_KERNEL);
+ if (!aw8695_fw) {
+ release_firmware(cont);
+ pr_err("%s: Error allocating memory\n", __func__);
+ return;
+ }
+ aw8695_fw->len = cont->size;
+ memcpy(aw8695_fw->data, cont->data, cont->size);
+ release_firmware(cont);
+
+ aw8695_container_update(aw8695, aw8695_fw);
+
+ aw8695->ram.len = aw8695_fw->len;
+
+ kfree(aw8695_fw);
+
+ aw8695->ram_init = 1;
+ pr_info("%s: fw update complete\n", __func__);
+
+ aw8695_haptic_trig_enable_config(aw8695);
+
+ aw8695_rtp_update(aw8695);
+}
+
+static int aw8695_ram_update(struct aw8695 *aw8695)
+{
+ aw8695->ram_init = 0;
+ aw8695->rtp_init = 0;
+ return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+ aw8695_ram_name, aw8695->dev, GFP_KERNEL,
+ aw8695, aw8695_ram_loaded);
+}
+
+#ifdef AWINIC_RAM_UPDATE_DELAY
+static void aw8695_ram_work_routine(struct work_struct *work)
+{
+ struct aw8695 *aw8695 = container_of(work, struct aw8695, ram_work.work);
+
+ pr_info("%s enter\n", __func__);
+
+ aw8695_ram_update(aw8695);
+
+}
+#endif
+
+static int aw8695_ram_init(struct aw8695 *aw8695)
+{
+#ifdef AWINIC_RAM_UPDATE_DELAY
+ int ram_timer_val = 5000;
+ INIT_DELAYED_WORK(&aw8695->ram_work, aw8695_ram_work_routine);
+ schedule_delayed_work(&aw8695->ram_work, msecs_to_jiffies(ram_timer_val));
+#else
+ aw8695_ram_update(aw8695);
+#endif
+ return 0;
+}
+
+
+
+/*****************************************************
+ *
+ * haptic control
+ *
+ *****************************************************/
+static int aw8695_haptic_softreset(struct aw8695 *aw8695)
+{
+ pr_debug("%s enter\n", __func__);
+
+ aw8695_i2c_write(aw8695, AW8695_REG_ID, 0xAA);
+ msleep(1);
+ return 0;
+}
+
+static int aw8695_haptic_active(struct aw8695 *aw8695)
+{
+ pr_debug("%s enter\n", __func__);
+
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_WORK_MODE_MASK, AW8695_BIT_SYSCTRL_ACTIVE);
+ aw8695_interrupt_clear(aw8695);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM,
+ AW8695_BIT_SYSINTM_UVLO_MASK, AW8695_BIT_SYSINTM_UVLO_EN);
+ return 0;
+}
+
+static int aw8695_haptic_play_mode(struct aw8695 *aw8695, unsigned char play_mode)
+{
+ pr_debug("%s enter\n", __func__);
+
+ switch(play_mode) {
+ case AW8695_HAPTIC_STANDBY_MODE:
+ aw8695->play_mode = AW8695_HAPTIC_STANDBY_MODE;
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM,
+ AW8695_BIT_SYSINTM_UVLO_MASK, AW8695_BIT_SYSINTM_UVLO_OFF);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_WORK_MODE_MASK, AW8695_BIT_SYSCTRL_STANDBY);
+ break;
+ case AW8695_HAPTIC_RAM_MODE:
+ aw8695->play_mode = AW8695_HAPTIC_RAM_MODE;
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_PLAY_MODE_MASK, AW8695_BIT_SYSCTRL_PLAY_MODE_RAM);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BYPASS);
+ if(aw8695->auto_boost) {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,
+ AW8695_BIT_BST_AUTO_BST_RAM_MASK, AW8695_BIT_BST_AUTO_BST_RAM_DISABLE);
+ }
+ aw8695_haptic_active(aw8695);
+ if(aw8695->auto_boost) {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,
+ AW8695_BIT_BST_AUTO_BST_RAM_MASK, AW8695_BIT_BST_AUTO_BST_RAM_ENABLE);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_BST_MODE_MASK&AW8695_BIT_SYSCTRL_WORK_MODE_MASK,
+ AW8695_BIT_SYSCTRL_BST_MODE_BOOST|AW8695_BIT_SYSCTRL_STANDBY);
+ aw8695_haptic_active(aw8695);
+ } else {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BOOST);
+ }
+ msleep(3);
+ break;
+ case AW8695_HAPTIC_RAM_LOOP_MODE:
+ aw8695->play_mode = AW8695_HAPTIC_RAM_LOOP_MODE;
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_PLAY_MODE_MASK, AW8695_BIT_SYSCTRL_PLAY_MODE_RAM);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BYPASS);
+ if(aw8695->auto_boost) {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,
+ AW8695_BIT_BST_AUTO_BST_RAM_MASK, AW8695_BIT_BST_AUTO_BST_RAM_DISABLE);
+ }
+ aw8695_haptic_active(aw8695);
+ break;
+ case AW8695_HAPTIC_RTP_MODE:
+ aw8695->play_mode = AW8695_HAPTIC_RTP_MODE;
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_PLAY_MODE_MASK, AW8695_BIT_SYSCTRL_PLAY_MODE_RTP);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BYPASS);
+ if(aw8695->auto_boost) {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,
+ AW8695_BIT_BST_AUTO_BST_RAM_MASK, AW8695_BIT_BST_AUTO_BST_RTP_DISABLE);
+ }
+ aw8695_haptic_active(aw8695);
+ if(aw8695->auto_boost) {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,
+ AW8695_BIT_BST_AUTO_BST_RAM_MASK, AW8695_BIT_BST_AUTO_BST_RTP_ENABLE);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_BST_MODE_MASK&AW8695_BIT_SYSCTRL_WORK_MODE_MASK,
+ AW8695_BIT_SYSCTRL_BST_MODE_BOOST|AW8695_BIT_SYSCTRL_STANDBY);
+ aw8695_haptic_active(aw8695);
+ } else {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BOOST);
+ }
+ msleep(3);
+ break;
+ case AW8695_HAPTIC_TRIG_MODE:
+ aw8695->play_mode = AW8695_HAPTIC_TRIG_MODE;
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_PLAY_MODE_MASK, AW8695_BIT_SYSCTRL_PLAY_MODE_RAM);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BYPASS);
+ if(aw8695->auto_boost) {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,
+ AW8695_BIT_BST_AUTO_BST_RAM_MASK, AW8695_BIT_BST_AUTO_BST_RAM_DISABLE);
+ }
+ aw8695_haptic_active(aw8695);
+ if(aw8695->auto_boost) {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,
+ AW8695_BIT_BST_AUTO_BST_RAM_MASK, AW8695_BIT_BST_AUTO_BST_RAM_ENABLE);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_BST_MODE_MASK&AW8695_BIT_SYSCTRL_WORK_MODE_MASK,
+ AW8695_BIT_SYSCTRL_BST_MODE_BOOST|AW8695_BIT_SYSCTRL_STANDBY);
+ aw8695_haptic_active(aw8695);
+ } else {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BOOST);
+ }
+ msleep(3);
+ break;
+ case AW8695_HAPTIC_CONT_MODE:
+ aw8695->play_mode = AW8695_HAPTIC_CONT_MODE;
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_PLAY_MODE_MASK, AW8695_BIT_SYSCTRL_PLAY_MODE_CONT);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BYPASS);
+ if(aw8695->auto_boost) {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,
+ AW8695_BIT_BST_AUTO_BST_RAM_MASK, AW8695_BIT_BST_AUTO_BST_RAM_DISABLE);
+ }
+ aw8695_haptic_active(aw8695);
+ break;
+ default:
+ dev_err(aw8695->dev, "%s: play mode %d err",
+ __func__, play_mode);
+ break;
+ }
+ return 0;
+}
+
+static int aw8695_haptic_play_go(struct aw8695 *aw8695, bool flag)
+{
+ pr_debug("%s enter\n", __func__);
+
+ if(flag == true) {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_GO,
+ AW8695_BIT_GO_MASK, AW8695_BIT_GO_ENABLE);
+ } else {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_GO,
+ AW8695_BIT_GO_MASK, AW8695_BIT_GO_DISABLE);
+ }
+ return 0;
+}
+
+static int aw8695_haptic_stop_delay(struct aw8695 *aw8695)
+{
+ unsigned char reg_val = 0;
+ unsigned int cnt = 100;
+
+ while(cnt--) {
+ aw8695_i2c_read(aw8695, AW8695_REG_GLB_STATE, ®_val);
+ if((reg_val&0x0f) == 0x00) {
+ return 0;
+ }
+ msleep(2);
+ pr_debug("%s wait for standby, reg glb_state=0x%02x\n",
+ __func__, reg_val);
+ }
+ pr_err("%s do not enter standby automatically\n", __func__);
+
+ return 0;
+}
+
+static int aw8695_haptic_stop(struct aw8695 *aw8695)
+{
+ pr_debug("%s enter\n", __func__);
+
+ aw8695_haptic_play_go(aw8695, false);
+ aw8695_haptic_stop_delay(aw8695);
+ aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_STANDBY_MODE);
+
+ return 0;
+}
+
+static int aw8695_haptic_start(struct aw8695 *aw8695)
+{
+ pr_debug("%s enter\n", __func__);
+
+ aw8695_haptic_play_go(aw8695, true);
+
+ return 0;
+}
+
+static int aw8695_haptic_set_wav_seq(struct aw8695 *aw8695,
+ unsigned char wav, unsigned char seq)
+{
+ aw8695_i2c_write(aw8695, AW8695_REG_WAVSEQ1+wav,
+ seq);
+ return 0;
+}
+
+static int aw8695_haptic_set_wav_loop(struct aw8695 *aw8695,
+ unsigned char wav, unsigned char loop)
+{
+ unsigned char tmp = 0;
+
+ if(wav%2) {
+ tmp = loop<<0;
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_WAVLOOP1+(wav/2),
+ AW8695_BIT_WAVLOOP_SEQNP1_MASK, tmp);
+ } else {
+ tmp = loop<<4;
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_WAVLOOP1+(wav/2),
+ AW8695_BIT_WAVLOOP_SEQN_MASK, tmp);
+ }
+
+ return 0;
+}
+/*
+static int aw8695_haptic_set_main_loop(struct aw8695 *aw8695,
+ unsigned char loop)
+{
+ aw8695_i2c_write(aw8695, AW8695_REG_MAIN_LOOP, loop);
+ return 0;
+}
+*/
+
+static int aw8695_haptic_set_repeat_wav_seq(struct aw8695 *aw8695, unsigned char seq)
+{
+ aw8695_haptic_set_wav_seq(aw8695, 0x00, seq);
+ aw8695_haptic_set_wav_loop(aw8695, 0x00, AW8695_BIT_WAVLOOP_INIFINITELY);
+
+ return 0;
+}
+
+
+static int aw8695_haptic_set_bst_vol(struct aw8695 *aw8695, unsigned char bst_vol)
+{
+ if(bst_vol & 0xe0) {
+ bst_vol = 0x1f;
+ }
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_BSTDBG4,
+ AW8695_BIT_BSTDBG4_BSTVOL_MASK, (bst_vol<<1));
+ return 0;
+}
+
+static int aw8695_haptic_set_bst_peak_cur(struct aw8695 *aw8695, unsigned char peak_cur)
+{
+ peak_cur &= AW8695_BSTCFG_PEAKCUR_LIMIT;
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_BSTCFG,
+ AW8695_BIT_BSTCFG_PEAKCUR_MASK, peak_cur);
+ return 0;
+}
+
+static int aw8695_haptic_set_gain(struct aw8695 *aw8695, unsigned char gain)
+{
+ aw8695_i2c_write(aw8695, AW8695_REG_DATDBG, gain);
+ return 0;
+}
+
+static int aw8695_haptic_set_pwm(struct aw8695 *aw8695, unsigned char mode)
+{
+ switch(mode) {
+ case AW8695_PWM_48K:
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_PWMDBG,
+ AW8695_BIT_PWMDBG_PWM_MODE_MASK, AW8695_BIT_PWMDBG_PWM_48K);
+ break;
+ case AW8695_PWM_24K:
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_PWMDBG,
+ AW8695_BIT_PWMDBG_PWM_MODE_MASK, AW8695_BIT_PWMDBG_PWM_24K);
+ break;
+ case AW8695_PWM_12K:
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_PWMDBG,
+ AW8695_BIT_PWMDBG_PWM_MODE_MASK, AW8695_BIT_PWMDBG_PWM_12K);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int aw8695_haptic_play_wav_seq(struct aw8695 *aw8695, unsigned char flag)
+{
+ pr_debug("%s enter\n", __func__);
+
+ if(flag) {
+ aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_RAM_MODE);
+ aw8695_haptic_start(aw8695);
+ }
+ return 0;
+}
+
+static int aw8695_haptic_play_repeat_seq(struct aw8695 *aw8695, unsigned char flag)
+{
+ pr_debug("%s enter\n", __func__);
+
+ if(flag) {
+ aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_RAM_LOOP_MODE);
+ aw8695_haptic_start(aw8695);
+ }
+
+ return 0;
+}
+
+/*****************************************************
+ *
+ * motor protect
+ *
+ *****************************************************/
+static int aw8695_haptic_swicth_motorprotect_config(struct aw8695 *aw8695, unsigned char addr, unsigned char val)
+{
+ pr_debug("%s enter\n", __func__);
+ if(addr == 1) {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_DETCTRL,
+ AW8695_BIT_DETCTRL_PROTECT_MASK, AW8695_BIT_DETCTRL_PROTECT_SHUTDOWN);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_PWMPRC,
+ AW8695_BIT_PWMPRC_PRC_MASK, AW8695_BIT_PWMPRC_PRC_ENABLE);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_PRLVL,
+ AW8695_BIT_PRLVL_PR_MASK, AW8695_BIT_PRLVL_PR_ENABLE);
+ } else if (addr == 0) {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_DETCTRL,
+ AW8695_BIT_DETCTRL_PROTECT_MASK, AW8695_BIT_DETCTRL_PROTECT_NO_ACTION);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_PWMPRC,
+ AW8695_BIT_PWMPRC_PRC_MASK, AW8695_BIT_PWMPRC_PRC_DISABLE);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_PRLVL,
+ AW8695_BIT_PRLVL_PR_MASK, AW8695_BIT_PRLVL_PR_DISABLE);
+ } else if (addr == 0x2d){
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_PWMPRC,
+ AW8695_BIT_PWMPRC_PRCTIME_MASK, val);
+ }else if (addr == 0x3e){
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_PRLVL,
+ AW8695_BIT_PRLVL_PRLVL_MASK, val);
+ }else if (addr == 0x3f){
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_PRTIME,
+ AW8695_BIT_PRTIME_PRTIME_MASK, val);
+ } else{
+ /*nothing to do;*/
+ }
+ return 0;
+}
+
+
+/*****************************************************
+ *
+ * trig config
+ *
+ *****************************************************/
+static int aw8695_haptic_trig_param_init(struct aw8695 *aw8695)
+{
+ pr_debug("%s enter\n", __func__);
+
+ aw8695->trig[0].enable = AW8695_TRG1_ENABLE;
+ aw8695->trig[0].default_level = AW8695_TRG1_DEFAULT_LEVEL;
+ aw8695->trig[0].dual_edge = AW8695_TRG1_DUAL_EDGE;
+ aw8695->trig[0].frist_seq = AW8695_TRG1_FIRST_EDGE_SEQ;
+ aw8695->trig[0].second_seq = AW8695_TRG1_SECOND_EDGE_SEQ;
+
+ aw8695->trig[1].enable = AW8695_TRG2_ENABLE;
+ aw8695->trig[1].default_level = AW8695_TRG2_DEFAULT_LEVEL;
+ aw8695->trig[1].dual_edge = AW8695_TRG2_DUAL_EDGE;
+ aw8695->trig[1].frist_seq = AW8695_TRG2_FIRST_EDGE_SEQ;
+ aw8695->trig[1].second_seq = AW8695_TRG2_SECOND_EDGE_SEQ;
+
+ aw8695->trig[2].enable = AW8695_TRG3_ENABLE;
+ aw8695->trig[2].default_level = AW8695_TRG3_DEFAULT_LEVEL;
+ aw8695->trig[2].dual_edge = AW8695_TRG3_DUAL_EDGE;
+ aw8695->trig[2].frist_seq = AW8695_TRG3_FIRST_EDGE_SEQ;
+ aw8695->trig[2].second_seq = AW8695_TRG3_SECOND_EDGE_SEQ;
+
+ return 0;
+}
+
+static int aw8695_haptic_trig_param_config(struct aw8695 *aw8695)
+{
+ pr_debug("%s enter\n", __func__);
+
+ if(aw8695->trig[0].default_level) {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1,
+ AW8695_BIT_TRGCFG1_TRG1_POLAR_MASK, AW8695_BIT_TRGCFG1_TRG1_POLAR_NEG);
+ } else {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1,
+ AW8695_BIT_TRGCFG1_TRG1_POLAR_MASK, AW8695_BIT_TRGCFG1_TRG1_POLAR_POS);
+ }
+ if(aw8695->trig[1].default_level) {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1,
+ AW8695_BIT_TRGCFG1_TRG2_POLAR_MASK, AW8695_BIT_TRGCFG1_TRG2_POLAR_NEG);
+ } else {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1,
+ AW8695_BIT_TRGCFG1_TRG2_POLAR_MASK, AW8695_BIT_TRGCFG1_TRG2_POLAR_POS);
+ }
+ if(aw8695->trig[2].default_level) {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1,
+ AW8695_BIT_TRGCFG1_TRG3_POLAR_MASK, AW8695_BIT_TRGCFG1_TRG3_POLAR_NEG);
+ } else {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1,
+ AW8695_BIT_TRGCFG1_TRG3_POLAR_MASK, AW8695_BIT_TRGCFG1_TRG3_POLAR_POS);
+ }
+
+ if(aw8695->trig[0].dual_edge) {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1,
+ AW8695_BIT_TRGCFG1_TRG1_EDGE_MASK, AW8695_BIT_TRGCFG1_TRG1_EDGE_POS_NEG);
+ } else {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1,
+ AW8695_BIT_TRGCFG1_TRG1_EDGE_MASK, AW8695_BIT_TRGCFG1_TRG1_EDGE_POS);
+ }
+ if(aw8695->trig[1].dual_edge) {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1,
+ AW8695_BIT_TRGCFG1_TRG2_EDGE_MASK, AW8695_BIT_TRGCFG1_TRG2_EDGE_POS_NEG);
+ } else {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1,
+ AW8695_BIT_TRGCFG1_TRG2_EDGE_MASK, AW8695_BIT_TRGCFG1_TRG2_EDGE_POS);
+ }
+ if(aw8695->trig[2].dual_edge) {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1,
+ AW8695_BIT_TRGCFG1_TRG3_EDGE_MASK, AW8695_BIT_TRGCFG1_TRG3_EDGE_POS_NEG);
+ } else {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1,
+ AW8695_BIT_TRGCFG1_TRG3_EDGE_MASK, AW8695_BIT_TRGCFG1_TRG3_EDGE_POS);
+ }
+
+ if(aw8695->trig[0].frist_seq) {
+ aw8695_i2c_write(aw8695, AW8695_REG_TRG1_WAV_P, aw8695->trig[0].frist_seq);
+ }
+ if(aw8695->trig[0].second_seq && aw8695->trig[0].dual_edge) {
+ aw8695_i2c_write(aw8695, AW8695_REG_TRG1_WAV_N, aw8695->trig[0].second_seq);
+ }
+ if(aw8695->trig[1].frist_seq) {
+ aw8695_i2c_write(aw8695, AW8695_REG_TRG2_WAV_P, aw8695->trig[1].frist_seq);
+ }
+ if(aw8695->trig[1].second_seq && aw8695->trig[1].dual_edge) {
+ aw8695_i2c_write(aw8695, AW8695_REG_TRG2_WAV_N, aw8695->trig[1].second_seq);
+ }
+ if(aw8695->trig[2].frist_seq) {
+ aw8695_i2c_write(aw8695, AW8695_REG_TRG3_WAV_P, aw8695->trig[1].frist_seq);
+ }
+ if(aw8695->trig[2].second_seq && aw8695->trig[2].dual_edge) {
+ aw8695_i2c_write(aw8695, AW8695_REG_TRG3_WAV_N, aw8695->trig[1].second_seq);
+ }
+
+ return 0;
+}
+
+static int aw8695_haptic_trig_enable_config(struct aw8695 *aw8695)
+{
+ pr_debug("%s enter\n", __func__);
+
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG2,
+ AW8695_BIT_TRGCFG2_TRG1_ENABLE_MASK, aw8695->trig[0].enable);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG2,
+ AW8695_BIT_TRGCFG2_TRG2_ENABLE_MASK, aw8695->trig[1].enable);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG2,
+ AW8695_BIT_TRGCFG2_TRG3_ENABLE_MASK, aw8695->trig[2].enable);
+
+ return 0;
+}
+
+
+static int aw8695_haptic_auto_boost_config(struct aw8695 *aw8695, unsigned char flag)
+{
+ aw8695->auto_boost = flag;
+ if(flag) {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,
+ AW8695_BIT_BST_AUTO_BST_AUTOSW_MASK, AW8695_BIT_BST_AUTO_BST_AUTOMATIC_BOOST);
+ } else {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO,
+ AW8695_BIT_BST_AUTO_BST_AUTOSW_MASK, AW8695_BIT_BST_AUTO_BST_MANUAL_BOOST);
+ }
+ return 0;
+}
+
+/*****************************************************
+ *
+ * vbat mode
+ *
+ *****************************************************/
+static int aw8695_haptic_cont_vbat_mode(struct aw8695 *aw8695, unsigned char flag)
+{
+ if(flag == AW8695_HAPTIC_CONT_VBAT_HW_COMP_MODE) {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_ADCTEST,
+ AW8695_BIT_ADCTEST_VBAT_MODE_MASK, AW8695_BIT_ADCTEST_VBAT_HW_COMP);
+ } else {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_ADCTEST,
+ AW8695_BIT_ADCTEST_VBAT_MODE_MASK, AW8695_BIT_ADCTEST_VBAT_SW_COMP);
+ }
+ return 0;
+}
+
+static int aw8695_haptic_get_vbat(struct aw8695 *aw8695)
+{
+ unsigned char reg_val = 0;
+
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_RAMINIT_MASK, AW8695_BIT_SYSCTRL_RAMINIT_EN);
+
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_DETCTRL,
+ AW8695_BIT_DETCTRL_DIAG_GO_MASK, AW8695_BIT_DETCTRL_DIAG_GO_ENABLE);
+ msleep(2);
+
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_DETCTRL,
+ AW8695_BIT_DETCTRL_DIAG_GO_MASK, AW8695_BIT_DETCTRL_DIAG_GO_DISABLE);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_DETCTRL,
+ AW8695_BIT_DETCTRL_VBAT_GO_MASK, AW8695_BIT_DETCTRL_VABT_GO_ENABLE);
+ msleep(2);
+
+ aw8695_i2c_read(aw8695, AW8695_REG_VBATDET, ®_val);
+ aw8695->vbat = 6100 * reg_val / 256;
+ if(aw8695->vbat > AW8695_VBAT_MAX) {
+ aw8695->vbat = AW8695_VBAT_MAX;
+ pr_debug("%s vbat max limit = %dmV\n", __func__, aw8695->vbat);
+ }
+ if(aw8695->vbat < AW8695_VBAT_MIN) {
+ aw8695->vbat = AW8695_VBAT_MIN;
+ pr_debug("%s vbat min limit = %dmV\n", __func__, aw8695->vbat);
+ }
+
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_RAMINIT_MASK, AW8695_BIT_SYSCTRL_RAMINIT_OFF);
+
+ return 0;
+}
+
+static int aw8695_haptic_ram_vbat_comp(struct aw8695 *aw8695, bool flag)
+{
+ int temp_gain = 0;
+
+ if(flag) {
+ if(aw8695->ram_vbat_comp == AW8695_HAPTIC_RAM_VBAT_COMP_ENABLE) {
+ aw8695_haptic_get_vbat(aw8695);
+ temp_gain = aw8695->gain * AW8695_VBAT_REFER / aw8695->vbat;
+ if(temp_gain > (128*AW8695_VBAT_REFER/AW8695_VBAT_MIN)) {
+ temp_gain = 128*AW8695_VBAT_REFER/AW8695_VBAT_MIN;
+ pr_debug("%s gain limit=%d\n", __func__, temp_gain);
+ }
+ aw8695_haptic_set_gain(aw8695, temp_gain);
+ } else {
+ aw8695_haptic_set_gain(aw8695, aw8695->gain);
+ }
+ } else {
+ aw8695_haptic_set_gain(aw8695, aw8695->gain);
+ }
+
+ return 0;
+}
+
+/*****************************************************
+ *
+ * f0
+ *
+ *****************************************************/
+static int aw8695_haptic_set_f0_preset(struct aw8695 *aw8695)
+{
+ unsigned int f0_reg = 0;
+
+ pr_debug("%s enter\n", __func__);
+
+ f0_reg = 1000000000/(aw8695->f0_pre*AW8695_HAPTIC_F0_COEFF);
+ aw8695_i2c_write(aw8695, AW8695_REG_F_PRE_H, (unsigned char)((f0_reg>>8)&0xff));
+ aw8695_i2c_write(aw8695, AW8695_REG_F_PRE_L, (unsigned char)((f0_reg>>0)&0xff));
+
+ return 0;
+}
+
+static int aw8695_haptic_read_f0(struct aw8695 *aw8695)
+{
+ int ret = 0;
+ unsigned char reg_val = 0;
+ unsigned int f0_reg = 0;
+ unsigned long f0_tmp = 0;
+
+ pr_debug("%s enter\n", __func__);
+
+ ret = aw8695_i2c_read(aw8695, AW8695_REG_F_LRA_F0_H, ®_val);
+ f0_reg = (reg_val<<8);
+ ret = aw8695_i2c_read(aw8695, AW8695_REG_F_LRA_F0_L, ®_val);
+ f0_reg |= (reg_val<<0);
+ f0_tmp = 1000000000/(f0_reg*AW8695_HAPTIC_F0_COEFF);
+ aw8695->f0 = (unsigned int)f0_tmp;
+ pr_info("%s f0=%d\n", __func__, aw8695->f0);
+
+ return 0;
+}
+
+static int aw8695_haptic_read_cont_f0(struct aw8695 *aw8695)
+{
+ int ret = 0;
+ unsigned char reg_val = 0;
+ unsigned int f0_reg = 0;
+ unsigned long f0_tmp = 0;
+
+ pr_debug("%s enter\n", __func__);
+
+ ret = aw8695_i2c_read(aw8695, AW8695_REG_F_LRA_CONT_H, ®_val);
+ f0_reg = (reg_val<<8);
+ ret = aw8695_i2c_read(aw8695, AW8695_REG_F_LRA_CONT_L, ®_val);
+ f0_reg |= (reg_val<<0);
+ f0_tmp = 1000000000/(f0_reg*AW8695_HAPTIC_F0_COEFF);
+ aw8695->cont_f0 = (unsigned int)f0_tmp;
+ pr_info("%s f0=%d\n", __func__, aw8695->cont_f0);
+
+ return 0;
+}
+
+static int aw8695_haptic_read_beme(struct aw8695 *aw8695)
+{
+ int ret = 0;
+ unsigned char reg_val = 0;
+
+ ret = aw8695_i2c_read(aw8695, AW8695_REG_WAIT_VOL_MP, ®_val);
+ aw8695->max_pos_beme = (reg_val<<0);
+ ret = aw8695_i2c_read(aw8695, AW8695_REG_WAIT_VOL_MN, ®_val);
+ aw8695->max_neg_beme = (reg_val<<0);
+
+ pr_info("%s max_pos_beme=%d\n", __func__, aw8695->max_pos_beme);
+ pr_info("%s max_neg_beme=%d\n", __func__, aw8695->max_neg_beme);
+
+ return 0;
+}
+
+
+
+/*****************************************************
+ *
+ * rtp
+ *
+ *****************************************************/
+static void aw8695_haptic_set_rtp_aei(struct aw8695 *aw8695, bool flag)
+{
+ if(flag) {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM,
+ AW8695_BIT_SYSINTM_FF_AE_MASK, AW8695_BIT_SYSINTM_FF_AE_EN);
+ } else {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM,
+ AW8695_BIT_SYSINTM_FF_AE_MASK, AW8695_BIT_SYSINTM_FF_AE_OFF);
+ }
+}
+/*
+static void aw8695_haptic_set_rtp_afi(struct aw8695 *aw8695, bool flag)
+{
+ if(flag) {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM,
+ AW8695_BIT_SYSINTM_FF_AF_MASK, AW8695_BIT_SYSINTM_FF_AF_EN);
+ } else {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM,
+ AW8695_BIT_SYSINTM_FF_AF_MASK, AW8695_BIT_SYSINTM_FF_AF_OFF);
+ }
+}
+*/
+/*
+static unsigned char aw8695_haptic_rtp_get_fifo_aei(struct aw8695 *aw8695)
+{
+ unsigned char ret;
+ unsigned char reg_val;
+
+ aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val);
+ reg_val &= AW8695_BIT_SYSINT_FF_AEI;
+ ret = reg_val>>4;
+
+ return ret;
+}
+*/
+
+static unsigned char aw8695_haptic_rtp_get_fifo_afi(struct aw8695 *aw8695)
+{
+ unsigned char ret = 0;
+ unsigned char reg_val = 0;
+
+ aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val);
+ reg_val &= AW8695_BIT_SYSINT_FF_AFI;
+ ret = reg_val>>3;
+
+ return ret;
+}
+
+/*****************************************************
+ *
+ * rtp
+ *
+ *****************************************************/
+static int aw8695_haptic_rtp_init(struct aw8695 *aw8695)
+{
+ unsigned int buf_len = 0;
+
+ pr_info("%s enter\n", __func__);
+
+ aw8695->rtp_cnt = 0;
+
+ while((!aw8695_haptic_rtp_get_fifo_afi(aw8695)) &&
+ (aw8695->play_mode == AW8695_HAPTIC_RTP_MODE)) {
+ pr_info("%s rtp cnt = %d\n", __func__, aw8695->rtp_cnt);
+ if((aw8695_rtp->len-aw8695->rtp_cnt) < (aw8695->ram.base_addr>>2)) {
+ buf_len = aw8695_rtp->len-aw8695->rtp_cnt;
+ } else {
+ buf_len = (aw8695->ram.base_addr>>2);
+ }
+ aw8695_i2c_writes(aw8695, AW8695_REG_RTP_DATA,
+ &aw8695_rtp->data[aw8695->rtp_cnt], buf_len);
+ aw8695->rtp_cnt += buf_len;
+ if(aw8695->rtp_cnt == aw8695_rtp->len) {
+ pr_info("%s: rtp update complete\n", __func__);
+ aw8695->rtp_cnt = 0;
+ return 0;
+ }
+ }
+
+ if(aw8695->play_mode == AW8695_HAPTIC_RTP_MODE) {
+ aw8695_haptic_set_rtp_aei(aw8695, true);
+ }
+
+ pr_info("%s exit\n", __func__);
+
+ return 0;
+}
+
+static void aw8695_rtp_work_routine(struct work_struct *work)
+{
+ const struct firmware *rtp_file;
+ int ret = -1;
+ struct aw8695 *aw8695 = container_of(work, struct aw8695, rtp_work);
+
+ pr_info("%s enter\n", __func__);
+
+ /* fw loaded */
+ ret = request_firmware(&rtp_file,
+ aw8695_rtp_name[aw8695->rtp_file_num],
+ aw8695->dev);
+ if(ret < 0)
+ {
+ pr_err("%s: failed to read %s\n", __func__,
+ aw8695_rtp_name[aw8695->rtp_file_num]);
+ return ;
+ }
+ aw8695->rtp_init = 0;
+ kfree(aw8695_rtp);
+ aw8695_rtp = kzalloc(rtp_file->size+sizeof(int), GFP_KERNEL);
+ if (!aw8695_rtp) {
+ release_firmware(rtp_file);
+ pr_err("%s: error allocating memory\n", __func__);
+ return;
+ }
+ aw8695_rtp->len = rtp_file->size;
+ pr_info("%s: rtp file [%s] size = %d\n", __func__,
+ aw8695_rtp_name[aw8695->rtp_file_num], aw8695_rtp->len);
+ memcpy(aw8695_rtp->data, rtp_file->data, rtp_file->size);
+ release_firmware(rtp_file);
+
+ aw8695->rtp_init = 1;
+
+ /* gain */
+ aw8695_haptic_ram_vbat_comp(aw8695, false);
+
+ /* rtp mode config */
+ aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_RTP_MODE);
+
+ /* haptic start */
+ aw8695_haptic_start(aw8695);
+
+ aw8695_haptic_rtp_init(aw8695);
+}
+
+
+/*****************************************************
+ *
+ * haptic - audio
+ *
+ *****************************************************/
+static enum hrtimer_restart aw8695_haptic_audio_timer_func(struct hrtimer *timer)
+{
+ struct aw8695 *aw8695 = container_of(timer, struct aw8695, haptic_audio.timer);
+
+ pr_debug("%s enter\n", __func__);
+ schedule_work(&aw8695->haptic_audio.work);
+
+ hrtimer_start(&aw8695->haptic_audio.timer,
+ ktime_set(aw8695->haptic_audio.timer_val/1000000,
+ (aw8695->haptic_audio.timer_val%1000000)*1000),
+ HRTIMER_MODE_REL);
+ return HRTIMER_NORESTART;
+}
+
+static void aw8695_haptic_audio_work_routine(struct work_struct *work)
+{
+ struct aw8695 *aw8695 = container_of(work, struct aw8695, haptic_audio.work);
+
+ pr_debug("%s enter\n", __func__);
+
+ mutex_lock(&aw8695->haptic_audio.lock);
+ memcpy(&aw8695->haptic_audio.ctr,
+ &aw8695->haptic_audio.data[aw8695->haptic_audio.cnt],
+ sizeof(struct haptic_ctr));
+ pr_debug("%s: cnt=%d, cmd=%d, play=%d, wavseq=%d, loop=%d, gain=%d\n",
+ __func__,
+ aw8695->haptic_audio.cnt,
+ aw8695->haptic_audio.ctr.cmd,
+ aw8695->haptic_audio.ctr.play,
+ aw8695->haptic_audio.ctr.wavseq,
+ aw8695->haptic_audio.ctr.loop,
+ aw8695->haptic_audio.ctr.gain);
+ mutex_unlock(&aw8695->haptic_audio.lock);
+ if(aw8695->haptic_audio.ctr.cmd == 0x01) {
+ if(aw8695->haptic_audio.ctr.play == 0x01) {
+ pr_info("%s: haptic_audio_play_start\n", __func__);
+ mutex_lock(&aw8695->lock);
+ aw8695_haptic_stop(aw8695);
+
+ aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_RAM_MODE);
+
+ aw8695_haptic_set_wav_seq(aw8695, 0x00,
+ aw8695->haptic_audio.ctr.wavseq);
+ aw8695_haptic_set_wav_seq(aw8695, 0x01, 0x00);
+
+ aw8695_haptic_set_wav_loop(aw8695, 0x00,
+ aw8695->haptic_audio.ctr.loop);
+
+ aw8695_haptic_set_gain(aw8695,
+ aw8695->haptic_audio.ctr.gain);
+
+ aw8695_haptic_start(aw8695);
+ mutex_unlock(&aw8695->lock);
+ }
+ mutex_lock(&aw8695->haptic_audio.lock);
+ memset(&aw8695->haptic_audio.data[aw8695->haptic_audio.cnt],
+ 0, sizeof(struct haptic_ctr));
+ mutex_unlock(&aw8695->haptic_audio.lock);
+ }
+
+ mutex_lock(&aw8695->haptic_audio.lock);
+ aw8695->haptic_audio.cnt ++;
+ if(aw8695->haptic_audio.data[aw8695->haptic_audio.cnt].cmd == 0) {
+ aw8695->haptic_audio.cnt = 0;
+ pr_debug("%s: haptic play buffer restart\n", __func__);
+ }
+ mutex_unlock(&aw8695->haptic_audio.lock);
+
+}
+
+
+/*****************************************************
+ *
+ * haptic cont
+ *
+ *****************************************************/
+static int aw8695_haptic_cont(struct aw8695 *aw8695)
+{
+ pr_info("%s enter\n", __func__);
+
+ /* work mode */
+ aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_CONT_MODE);
+
+ /* preset f0 */
+ aw8695->f0_pre = aw8695->f0;
+ aw8695_haptic_set_f0_preset(aw8695);
+
+ /* lpf */
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_DATCTRL,
+ AW8695_BIT_DATCTRL_FC_MASK, AW8695_BIT_DATCTRL_FC_1000HZ);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_DATCTRL,
+ AW8695_BIT_DATCTRL_LPF_ENABLE_MASK, AW8695_BIT_DATCTRL_LPF_ENABLE);
+
+ /* cont config */
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL,
+ AW8695_BIT_CONT_CTRL_ZC_DETEC_MASK, AW8695_BIT_CONT_CTRL_ZC_DETEC_ENABLE);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL,
+ AW8695_BIT_CONT_CTRL_WAIT_PERIOD_MASK, AW8695_BIT_CONT_CTRL_WAIT_1PERIOD);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL,
+ AW8695_BIT_CONT_CTRL_MODE_MASK, AW8695_BIT_CONT_CTRL_BY_GO_SIGNAL);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL,
+ AW8695_BIT_CONT_CTRL_EN_CLOSE_MASK, AW8695_CONT_PLAYBACK_MODE);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL,
+ AW8695_BIT_CONT_CTRL_F0_DETECT_MASK, AW8695_BIT_CONT_CTRL_F0_DETECT_DISABLE);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL,
+ AW8695_BIT_CONT_CTRL_O2C_MASK, AW8695_BIT_CONT_CTRL_O2C_DISABLE);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL,
+ AW8695_BIT_CONT_CTRL_AUTO_BRK_MASK, AW8695_BIT_CONT_CTRL_AUTO_BRK_ENABLE);
+
+ /* TD time */
+ aw8695_i2c_write(aw8695, AW8695_REG_TD_H, (unsigned char)(aw8695->cont_td>>8));
+ aw8695_i2c_write(aw8695, AW8695_REG_TD_L, (unsigned char)(aw8695->cont_td>>0));
+ aw8695_i2c_write(aw8695, AW8695_REG_TSET, 0x12);
+
+ /* zero cross */
+ aw8695_i2c_write(aw8695, AW8695_REG_ZC_THRSH_H, (unsigned char)(aw8695->cont_zc_thr>>8));
+ aw8695_i2c_write(aw8695, AW8695_REG_ZC_THRSH_L, (unsigned char)(aw8695->cont_zc_thr>>0));
+
+ /* bemf */
+ aw8695_i2c_write(aw8695, AW8695_REG_BEMF_VTHH_H, 0x10);
+ aw8695_i2c_write(aw8695, AW8695_REG_BEMF_VTHH_L, 0x08);
+ aw8695_i2c_write(aw8695, AW8695_REG_BEMF_VTHL_H, 0x03);
+ aw8695_i2c_write(aw8695, AW8695_REG_BEMF_VTHL_L, 0xf8);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_BEMF_NUM,
+ AW8695_BIT_BEMF_NUM_BRK_MASK, aw8695->cont_num_brk);
+ aw8695_i2c_write(aw8695, AW8695_REG_TIME_NZC, 0x23); // 35*171us=5.985ms
+
+ /* f0 driver level */
+ aw8695_i2c_write(aw8695, AW8695_REG_DRV_LVL, aw8695->cont_drv_lvl);
+ aw8695_i2c_write(aw8695, AW8695_REG_DRV_LVL_OV, aw8695->cont_drv_lvl_ov);
+
+ /* cont play go */
+ aw8695_haptic_play_go(aw8695, true);
+
+ return 0;
+}
+
+/*****************************************************
+ *
+ * haptic f0 cali
+ *
+ *****************************************************/
+static int aw8695_haptic_get_f0(struct aw8695 *aw8695)
+{
+ int ret = 0;
+ unsigned char i = 0;
+ unsigned char reg_val = 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 int f0_cali_cnt = 50;
+
+ pr_info("%s enter\n", __func__);
+
+ aw8695->f0 = aw8695->f0_pre;
+
+ /* f0 calibrate work mode */
+ aw8695_haptic_stop(aw8695);
+ aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_CONT_MODE);
+
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL,
+ AW8695_BIT_CONT_CTRL_EN_CLOSE_MASK, AW8695_BIT_CONT_CTRL_OPEN_PLAYBACK);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL,
+ AW8695_BIT_CONT_CTRL_F0_DETECT_MASK, AW8695_BIT_CONT_CTRL_F0_DETECT_ENABLE);
+
+ /* LPF */
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_DATCTRL,
+ AW8695_BIT_DATCTRL_FC_MASK, AW8695_BIT_DATCTRL_FC_1000HZ);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_DATCTRL,
+ AW8695_BIT_DATCTRL_LPF_ENABLE_MASK, AW8695_BIT_DATCTRL_LPF_ENABLE);
+
+ /* LRA OSC Source */
+ if(aw8695->f0_cali_flag == AW8695_HAPTIC_CALI_F0) {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_ANACTRL,
+ AW8695_BIT_ANACTRL_LRA_SRC_MASK, AW8695_BIT_ANACTRL_LRA_SRC_REG);
+ } else {
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_ANACTRL,
+ AW8695_BIT_ANACTRL_LRA_SRC_MASK, AW8695_BIT_ANACTRL_LRA_SRC_EFUSE);
+ }
+
+ /* preset f0 */
+ aw8695_haptic_set_f0_preset(aw8695);
+
+ /* beme config */
+ aw8695_i2c_write(aw8695, AW8695_REG_BEMF_VTHH_H, 0x10);
+ aw8695_i2c_write(aw8695, AW8695_REG_BEMF_VTHH_L, 0x08);
+ aw8695_i2c_write(aw8695, AW8695_REG_BEMF_VTHL_H, 0x03);
+ aw8695_i2c_write(aw8695, AW8695_REG_BEMF_VTHL_L, 0xf8);
+
+ /* f0 driver level */
+ aw8695_i2c_write(aw8695, AW8695_REG_DRV_LVL, aw8695->cont_drv_lvl);
+
+ /* f0 trace parameter */
+ f0_pre_num = 0x05;
+ f0_wait_num = 0x03;
+ f0_repeat_num = 0x02;
+ f0_trace_num = 0x0f;
+ aw8695_i2c_write(aw8695, AW8695_REG_NUM_F0_1, (f0_pre_num<<4)|(f0_wait_num<<0));
+ aw8695_i2c_write(aw8695, AW8695_REG_NUM_F0_2, (f0_repeat_num<<0));
+ aw8695_i2c_write(aw8695, AW8695_REG_NUM_F0_3, (f0_trace_num<<0));
+
+ /* clear aw8695 interrupt */
+ ret = aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val);
+
+ /* play go and start f0 calibration */
+ aw8695_haptic_play_go(aw8695, true);
+
+ /* f0 trace time */
+ t_f0_ms = 1000*10/aw8695->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));
+ msleep(t_f0_trace_ms);
+
+ for(i=0; i<f0_cali_cnt; i++) {
+ ret = aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val);
+ /* f0 calibrate done */
+ if(reg_val & 0x01) {
+ aw8695_haptic_read_f0(aw8695);
+ aw8695_haptic_read_beme(aw8695);
+ break;
+ }
+ msleep(10);
+ pr_info("%s f0 cali sleep 10ms\n", __func__);
+ }
+
+ if(i == f0_cali_cnt) {
+ ret = -1;
+ } else {
+ ret = 0;
+ }
+
+ /* restore default config */
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL,
+ AW8695_BIT_CONT_CTRL_EN_CLOSE_MASK, AW8695_CONT_PLAYBACK_MODE);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL,
+ AW8695_BIT_CONT_CTRL_F0_DETECT_MASK, AW8695_BIT_CONT_CTRL_F0_DETECT_DISABLE);
+
+ return ret;
+}
+
+static int aw8695_haptic_f0_calibration(struct aw8695 *aw8695)
+{
+ int ret = 0;
+ unsigned char reg_val = 0;
+ unsigned int f0_limit = 0;
+ char f0_cali_lra = 0;
+ int f0_cali_step = 0;
+ int f0_dft_step = 0;
+
+ pr_info("%s enter\n", __func__);
+
+ aw8695->f0_cali_flag = AW8695_HAPTIC_CALI_F0;
+
+ if(aw8695_haptic_get_f0(aw8695)) {
+ pr_err("%s get f0 error, user defafult f0\n", __func__);
+ } else {
+ /* max and min limit */
+ f0_limit = aw8695->f0;
+ if(aw8695->f0*100 < AW8695_HAPTIC_F0_PRE*(100-AW8695_HAPTIC_F0_CALI_PERCEN)) {
+ f0_limit = AW8695_HAPTIC_F0_PRE*(100-AW8695_HAPTIC_F0_CALI_PERCEN)/100;
+ }
+ if(aw8695->f0*100 > AW8695_HAPTIC_F0_PRE*(100+AW8695_HAPTIC_F0_CALI_PERCEN)) {
+ f0_limit = AW8695_HAPTIC_F0_PRE*(100+AW8695_HAPTIC_F0_CALI_PERCEN)/100;
+ }
+
+ /* calculate cali step */
+ f0_cali_step = 10000*((int)f0_limit-(int)aw8695->f0_pre)/((int)f0_limit*25);
+ pr_debug("%s f0_cali_step=%d\n", __func__, f0_cali_step);
+
+ /* get default cali step */
+ aw8695_i2c_read(aw8695, AW8695_REG_TRIM_LRA, ®_val);
+ if(reg_val & 0x20) {
+ f0_dft_step = reg_val - 0x40;
+ } else {
+ f0_dft_step = reg_val;
+ }
+ pr_debug("%s f0_dft_step=%d\n", __func__, f0_dft_step);
+
+ /* get new cali step */
+ f0_cali_step += f0_dft_step;
+ pr_debug("%s f0_cali_step=%d\n", __func__, f0_cali_step);
+
+ if(f0_cali_step > 31) {
+ f0_cali_step = 31;
+ } else if(f0_cali_step < -32) {
+ f0_cali_step = -32;
+ }
+ f0_cali_lra = (char)f0_cali_step;
+ pr_debug("%s f0_cali_lra=%d\n", __func__, f0_cali_lra);
+
+ /* get cali step complement code*/
+ if(f0_cali_lra < 0) {
+ f0_cali_lra += 0x40;
+ }
+ pr_debug("%s reg f0_cali_lra=%d\n", __func__, f0_cali_lra);
+
+ /* update cali step */
+ aw8695_i2c_write(aw8695, AW8695_REG_TRIM_LRA, (char)f0_cali_lra);
+ aw8695_i2c_read(aw8695, AW8695_REG_TRIM_LRA, ®_val);
+ pr_info("%s final trim_lra=0x%02x\n", __func__, reg_val);
+ }
+
+ /* restore default work mode */
+ aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_STANDBY_MODE);
+ aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_RAM_MODE);
+ aw8695_haptic_stop(aw8695);
+
+ return ret;
+}
+
+/*****************************************************
+ *
+ * haptic fops
+ *
+ *****************************************************/
+static int aw8695_file_open(struct inode *inode, struct file *file)
+{
+ if (!try_module_get(THIS_MODULE))
+ return -ENODEV;
+
+ file->private_data = (void*)g_aw8695;
+
+ return 0;
+}
+
+static int aw8695_file_release(struct inode *inode, struct file *file)
+{
+ file->private_data = (void*)NULL;
+
+ module_put(THIS_MODULE);
+
+ return 0;
+}
+
+static long aw8695_file_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct aw8695 *aw8695 = (struct aw8695 *)file->private_data;
+
+ int ret = 0;
+
+ dev_info(aw8695->dev, "%s: cmd=0x%x, arg=0x%lx\n",
+ __func__, cmd, arg);
+
+ mutex_lock(&aw8695->lock);
+
+ if(_IOC_TYPE(cmd) != AW8695_HAPTIC_IOCTL_MAGIC) {
+ dev_err(aw8695->dev, "%s: cmd magic err\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ switch (cmd) {
+ default:
+ dev_err(aw8695->dev, "%s, unknown cmd\n", __func__);
+ break;
+ }
+
+ mutex_unlock(&aw8695->lock);
+
+ return ret;
+}
+
+static ssize_t aw8695_file_read(struct file* filp, char* buff, size_t len, loff_t* offset)
+{
+ struct aw8695 *aw8695 = (struct aw8695 *)filp->private_data;
+ int ret = 0;
+ int i = 0;
+ unsigned char reg_val = 0;
+ unsigned char *pbuff = NULL;
+
+ mutex_lock(&aw8695->lock);
+
+ dev_info(aw8695->dev, "%s: len=%zu\n", __func__, len);
+
+ switch(aw8695->fileops.cmd)
+ {
+ case AW8695_HAPTIC_CMD_READ_REG:
+ pbuff = (unsigned char *)kzalloc(len, GFP_KERNEL);
+ if(pbuff != NULL) {
+ for(i=0; i<len; i++) {
+ aw8695_i2c_read(aw8695, aw8695->fileops.reg+i, ®_val);
+ pbuff[i] = reg_val;
+ }
+ for(i=0; i<len; i++) {
+ dev_info(aw8695->dev, "%s: pbuff[%d]=0x%02x\n",
+ __func__, i, pbuff[i]);
+ }
+ ret = copy_to_user(buff, pbuff, len);
+ if(ret) {
+ dev_err(aw8695->dev, "%s: copy to user fail\n", __func__);
+ }
+ kfree(pbuff);
+ } else {
+ dev_err(aw8695->dev, "%s: alloc memory fail\n", __func__);
+ }
+ break;
+ default:
+ dev_err(aw8695->dev, "%s, unknown cmd %d \n", __func__, aw8695->fileops.cmd);
+ break;
+ }
+
+ mutex_unlock(&aw8695->lock);
+
+
+ return len;
+}
+
+static ssize_t aw8695_file_write(struct file* filp, const char* buff, size_t len, loff_t* off)
+{
+ struct aw8695 *aw8695 = (struct aw8695 *)filp->private_data;
+ int i = 0;
+ int ret = 0;
+ unsigned char *pbuff = NULL;
+
+ pbuff = (unsigned char *)kzalloc(len, GFP_KERNEL);
+ if(pbuff == NULL) {
+ dev_err(aw8695->dev, "%s: alloc memory fail\n", __func__);
+ return len;
+ }
+ ret = copy_from_user(pbuff, buff, len);
+ if(ret) {
+ dev_err(aw8695->dev, "%s: copy from user fail\n", __func__);
+ return len;
+ }
+
+ for(i=0; i<len; i++) {
+ dev_info(aw8695->dev, "%s: pbuff[%d]=0x%02x\n",
+ __func__, i, pbuff[i]);
+ }
+
+ mutex_lock(&aw8695->lock);
+
+ aw8695->fileops.cmd = pbuff[0];
+
+ switch(aw8695->fileops.cmd)
+ {
+ case AW8695_HAPTIC_CMD_READ_REG:
+ if(len == 2) {
+ aw8695->fileops.reg = pbuff[1];
+ } else {
+ dev_err(aw8695->dev, "%s: read cmd len %zu err\n", __func__, len);
+ }
+ break;
+ case AW8695_HAPTIC_CMD_WRITE_REG:
+ if(len > 2) {
+ for(i=0; i<len-2; i++) {
+ dev_info(aw8695->dev, "%s: write reg0x%02x=0x%02x\n",
+ __func__, pbuff[1]+i, pbuff[i+2]);
+ aw8695_i2c_write(aw8695, pbuff[1]+i, pbuff[2+i]);
+ }
+ } else {
+ dev_err(aw8695->dev, "%s: write cmd len %zu err\n", __func__, len);
+ }
+ break;
+ default:
+ dev_err(aw8695->dev, "%s, unknown cmd %d \n", __func__, aw8695->fileops.cmd);
+ break;
+ }
+
+ mutex_unlock(&aw8695->lock);
+
+ if(pbuff != NULL) {
+ kfree(pbuff);
+ }
+ return len;
+}
+
+static struct file_operations fops =
+{
+ .owner = THIS_MODULE,
+ .read = aw8695_file_read,
+ .write = aw8695_file_write,
+ .unlocked_ioctl = aw8695_file_unlocked_ioctl,
+ .open = aw8695_file_open,
+ .release = aw8695_file_release,
+};
+
+static struct miscdevice aw8695_haptic_misc =
+{
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = AW8695_HAPTIC_NAME,
+ .fops = &fops,
+};
+
+static int aw8695_haptic_init(struct aw8695 *aw8695)
+{
+ int ret = 0;
+ unsigned char i = 0;
+ unsigned char reg_val = 0;
+
+ pr_info("%s enter\n", __func__);
+
+ ret = misc_register(&aw8695_haptic_misc);
+ if(ret) {
+ dev_err(aw8695->dev, "%s: misc fail: %d\n", __func__, ret);
+ return ret;
+ }
+
+ /* haptic audio */
+ aw8695->haptic_audio.delay_val = 20833;
+ aw8695->haptic_audio.timer_val = 20833;
+
+ hrtimer_init(&aw8695->haptic_audio.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ aw8695->haptic_audio.timer.function = aw8695_haptic_audio_timer_func;
+ INIT_WORK(&aw8695->haptic_audio.work, aw8695_haptic_audio_work_routine);
+
+ mutex_init(&aw8695->haptic_audio.lock);
+
+
+ /* haptic init */
+ mutex_lock(&aw8695->lock);
+
+ aw8695->activate_mode = AW8695_HAPTIC_ACTIVATE_CONT_MODE;
+
+ ret = aw8695_i2c_read(aw8695, AW8695_REG_WAVSEQ1, ®_val);
+ aw8695->index = reg_val & 0x7F;
+ ret = aw8695_i2c_read(aw8695, AW8695_REG_DATDBG, ®_val);
+ aw8695->gain = reg_val & 0xFF;
+ ret = aw8695_i2c_read(aw8695, AW8695_REG_BSTDBG4, ®_val);
+ aw8695->vmax = (reg_val>>1)&0x1F;
+ for(i=0; i<AW8695_SEQUENCER_SIZE; i++) {
+ ret = aw8695_i2c_read(aw8695, AW8695_REG_WAVSEQ1+i, ®_val);
+ aw8695->seq[i] = reg_val;
+ }
+
+ aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_STANDBY_MODE);
+
+ aw8695_haptic_set_pwm(aw8695, AW8695_PWM_24K);
+
+ aw8695_i2c_write(aw8695, AW8695_REG_BSTDBG1, 0x30);
+ aw8695_i2c_write(aw8695, AW8695_REG_BSTDBG2, 0xeb);
+ aw8695_i2c_write(aw8695, AW8695_REG_BSTDBG3, 0xd4);
+ aw8695_i2c_write(aw8695, AW8695_REG_TSET, 0x12);
+ aw8695_i2c_write(aw8695, AW8695_REG_R_SPARE, 0x68);
+
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_ANADBG,
+ AW8695_BIT_ANADBG_IOC_MASK, AW8695_BIT_ANADBG_IOC_4P65A);
+
+ aw8695_haptic_set_bst_peak_cur(aw8695, AW8695_DEFAULT_PEAKCUR);
+
+ aw8695_haptic_swicth_motorprotect_config(aw8695, 0x00, 0x00);
+
+ aw8695_haptic_auto_boost_config(aw8695, false);
+
+ aw8695_haptic_trig_param_init(aw8695);
+ aw8695_haptic_trig_param_config(aw8695);
+
+ aw8695_haptic_cont_vbat_mode(aw8695,
+ AW8695_HAPTIC_CONT_VBAT_HW_COMP_MODE);
+ aw8695->ram_vbat_comp = AW8695_HAPTIC_RAM_VBAT_COMP_ENABLE;
+
+ mutex_unlock(&aw8695->lock);
+
+
+ /* f0 calibration */
+ mutex_lock(&aw8695->lock);
+ aw8695->f0_pre = AW8695_HAPTIC_F0_PRE;
+ aw8695->cont_drv_lvl = AW8695_HAPTIC_CONT_DRV_LVL;
+ aw8695->cont_drv_lvl_ov = AW8695_HAPTIC_CONT_DRV_LVL_OV;
+ aw8695->cont_td = AW8695_HAPTIC_CONT_TD;
+ aw8695->cont_zc_thr = AW8695_HAPTIC_CONT_ZC_THR;
+ aw8695->cont_num_brk = AW8695_HAPTIC_CONT_NUM_BRK;
+ aw8695_haptic_f0_calibration(aw8695);
+ mutex_unlock(&aw8695->lock);
+
+ return ret;
+}
+
+
+
+/*****************************************************
+ *
+ * vibrator
+ *
+ *****************************************************/
+#ifdef MOTO_VIBRATOR_SUPPORT
+static void aw8695_rtp_play(struct aw8695 *aw8695, int value)
+{
+ aw8695_haptic_stop(aw8695);
+ aw8695_haptic_set_rtp_aei(aw8695, false);
+ aw8695_interrupt_clear(aw8695);
+ if(value < (sizeof(aw8695_rtp_name)/AW8695_RTP_NAME_MAX)) {
+ aw8695->rtp_file_num = value;
+ if(value) {
+ schedule_work(&aw8695->rtp_work);
+ }
+ } else {
+ pr_err("%s: rtp_file_num 0x%02x over max value \n", __func__, aw8695->rtp_file_num);
+ }
+}
+
+static void aw8695_vibrate(struct aw8695 *aw8695, int value)
+{
+ int seq = 0;
+
+ mutex_lock(&aw8695->lock);
+
+ aw8695_haptic_stop(aw8695);
+ seq = aw8695->seq[0];
+ pr_debug("%s: value=%d, seq=%d\n", __FUNCTION__, value, seq);
+
+ if (value > 0 || seq > 2) {
+ if (seq >= AW8695_SEQ_NO_RTP_BASE) {
+ aw8695->haptic_mode = HAPTIC_RTP;
+ } else if (value < 100 || seq > 2) {
+ aw8695->haptic_mode = HAPTIC_SHORT;
+ } else {
+ aw8695->haptic_mode = HAPTIC_LONG;
+ }
+
+ switch (aw8695->haptic_mode) {
+ case HAPTIC_RTP:
+ aw8695_rtp_play(aw8695, seq - AW8695_SEQ_NO_RTP_BASE);
+ break;
+ case HAPTIC_SHORT:
+ if (aw8695->seq[0] == 0)
+ aw8695->seq[0] = 0x01;
+
+ aw8695_haptic_set_wav_seq(aw8695, 0x00, aw8695->seq[0]);
+ aw8695_haptic_set_wav_loop(aw8695, 0x00, 0x00);
+ aw8695_haptic_ram_vbat_comp(aw8695, false);
+ aw8695_haptic_play_wav_seq(aw8695, 0x01);
+ break;
+ case HAPTIC_LONG:
+ aw8695->duration = value;
+ /* wav index config */
+ aw8695->index = 0x02;
+ aw8695_haptic_set_repeat_wav_seq(aw8695, aw8695->index);
+
+ /* run ms timer */
+ hrtimer_cancel(&aw8695->timer);
+ aw8695->state = 0x01;
+ if (aw8695->state)
+ {
+ hrtimer_start(&aw8695->timer,
+ ktime_set(aw8695->duration / 1000, (value % 1000) * 1000000),
+ HRTIMER_MODE_REL);
+ }
+ schedule_work(&aw8695->vibrator_work);
+ break;
+ default:
+ break;
+ }
+
+ /* Restore to default short waveform */
+ if (seq > 2)
+ aw8695->seq[0] = 0;
+ }
+
+ mutex_unlock(&aw8695->lock);
+}
+#endif
+
+#ifdef TIMED_OUTPUT
+static int aw8695_vibrator_get_time(struct timed_output_dev *dev)
+{
+ struct aw8695 *aw8695 = container_of(dev, struct aw8695, to_dev);
+
+ if (hrtimer_active(&aw8695->timer)) {
+ ktime_t r = hrtimer_get_remaining(&aw8695->timer);
+ return ktime_to_ms(r);
+ }
+
+ return 0;
+}
+
+static void aw8695_vibrator_enable( struct timed_output_dev *dev, int value)
+{
+ struct aw8695 *aw8695 = container_of(dev, struct aw8695, to_dev);
+
+ mutex_lock(&aw8695->lock);
+
+ pr_debug("%s enter\n", __func__);
+
+ aw8695_haptic_stop(aw8695);
+
+ if (value > 0) {
+ aw8695_haptic_ram_vbat_comp(aw8695, false);
+ aw8695_haptic_play_wav_seq(aw8695, value);
+ }
+
+ mutex_unlock(&aw8695->lock);
+
+ pr_debug("%s exit\n", __func__);
+}
+
+#else
+static enum led_brightness aw8695_haptic_brightness_get(struct led_classdev *cdev)
+{
+ struct aw8695 *aw8695 =
+ container_of(cdev, struct aw8695, cdev);
+
+ return aw8695->amplitude;
+}
+
+static void aw8695_haptic_brightness_set(struct led_classdev *cdev,
+ enum led_brightness level)
+{
+ struct aw8695 *aw8695 =
+ container_of(cdev, struct aw8695, cdev);
+
+ aw8695->amplitude = level;
+
+ mutex_lock(&aw8695->lock);
+
+ aw8695_haptic_stop(aw8695);
+ if (aw8695->amplitude > 0) {
+ aw8695_haptic_ram_vbat_comp(aw8695, false);
+ aw8695_haptic_play_wav_seq(aw8695, aw8695->amplitude);
+ }
+
+ mutex_unlock(&aw8695->lock);
+
+}
+#endif
+
+static ssize_t aw8695_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", aw8695->state);
+}
+
+static ssize_t aw8695_state_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ return count;
+}
+
+static ssize_t aw8695_duration_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ ktime_t time_rem;
+ s64 time_ms = 0;
+
+ if (hrtimer_active(&aw8695->timer)) {
+ time_rem = hrtimer_get_remaining(&aw8695->timer);
+ time_ms = ktime_to_ms(time_rem);
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%lld\n", time_ms);
+}
+
+static ssize_t aw8695_duration_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ unsigned int val = 0;
+ int rc = 0;
+
+ rc = kstrtouint(buf, 0, &val);
+ if (rc < 0)
+ return rc;
+
+ /* setting 0 on duration is NOP for now */
+ if (val <= 0)
+ return count;
+
+ aw8695->duration = val;
+
+ return count;
+}
+
+static ssize_t aw8695_activate_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+
+ /* For now nothing to show */
+ return snprintf(buf, PAGE_SIZE, "%d\n", aw8695->state);
+}
+
+static ssize_t aw8695_activate_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+
+#ifdef MOTO_VIBRATOR_SUPPORT
+ unsigned int val = 0;
+ int rc = 0;
+
+ rc = kstrtouint(buf, 0, &val);
+ if (rc < 0)
+ return rc;
+
+ if (val != 0 && val != 1)
+ return count;
+
+ pr_debug("%s: value=%d\n", __FUNCTION__, val);
+
+ aw8695->state = val;
+
+ if (aw8695->state)
+ aw8695_vibrate(aw8695, aw8695->duration);
+ else
+ aw8695_vibrate(aw8695, 0);
+#else
+ unsigned int val = 0;
+ int rc = 0;;
+
+ rc = kstrtouint(buf, 0, &val);
+ if (rc < 0)
+ return rc;
+
+ if (val != 0 && val != 1)
+ return count;
+
+ pr_debug("%s: value=%d\n", __FUNCTION__, val);
+
+ mutex_lock(&aw8695->lock);
+ hrtimer_cancel(&aw8695->timer);
+
+ aw8695->state = val;
+
+ if (aw8695->state)
+ {
+ /* clip value to max */
+ val = aw8695->duration;
+ /* run ms timer */
+ hrtimer_start(&aw8695->timer,
+ ktime_set(val / 1000, (val % 1000) * 1000000),
+ HRTIMER_MODE_REL);
+ }
+ mutex_unlock(&aw8695->lock);
+ schedule_work(&aw8695->vibrator_work);
+#endif
+
+ return count;
+}
+
+static ssize_t aw8695_activate_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+
+ return snprintf(buf, PAGE_SIZE, "activate_mode=%d\n", aw8695->activate_mode);
+}
+
+static ssize_t aw8695_activate_mode_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ unsigned int val = 0;
+ int rc = 0;
+
+ rc = kstrtouint(buf, 0, &val);
+ if (rc < 0)
+ return rc;
+
+ mutex_lock(&aw8695->lock);
+ aw8695->activate_mode = val;
+ mutex_unlock(&aw8695->lock);
+ return count;
+}
+
+static ssize_t aw8695_index_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ unsigned char reg_val = 0;
+ aw8695_i2c_read(aw8695, AW8695_REG_WAVSEQ1, ®_val);
+ aw8695->index = reg_val;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", aw8695->index);
+}
+
+static ssize_t aw8695_index_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ unsigned int val = 0;
+ int rc = 0;
+
+ rc = kstrtouint(buf, 0, &val);
+ if (rc < 0)
+ return rc;
+
+ pr_debug("%s: value=%d\n", __FUNCTION__, val);
+
+ mutex_lock(&aw8695->lock);
+ aw8695->index = val;
+ aw8695_haptic_set_repeat_wav_seq(aw8695, aw8695->index);
+ mutex_unlock(&aw8695->lock);
+ return count;
+}
+
+static ssize_t aw8695_vmax_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+
+ return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw8695->vmax);
+}
+
+static ssize_t aw8695_vmax_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ unsigned int val = 0;
+ int rc = 0;
+
+ rc = kstrtouint(buf, 0, &val);
+ if (rc < 0)
+ return rc;
+
+ pr_debug("%s: value=%d\n", __FUNCTION__, val);
+
+ mutex_lock(&aw8695->lock);
+ aw8695->vmax = val;
+ aw8695_haptic_set_bst_vol(aw8695, aw8695->vmax);
+ mutex_unlock(&aw8695->lock);
+ return count;
+}
+
+static ssize_t aw8695_gain_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw8695->gain);
+}
+
+static ssize_t aw8695_gain_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ unsigned int val = 0;
+ int rc = 0;
+
+ rc = kstrtouint(buf, 0, &val);
+ if (rc < 0)
+ return rc;
+
+ pr_debug("%s: value=%d\n", __FUNCTION__, val);
+
+ mutex_lock(&aw8695->lock);
+ aw8695->gain = val;
+ aw8695_haptic_set_gain(aw8695, aw8695->gain);
+ mutex_unlock(&aw8695->lock);
+ return count;
+}
+
+static ssize_t aw8695_seq_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ size_t count = 0;
+ unsigned char i = 0;
+ unsigned char reg_val = 0;
+
+ for(i=0; i<AW8695_SEQUENCER_SIZE; i++) {
+ aw8695_i2c_read(aw8695, AW8695_REG_WAVSEQ1+i, ®_val);
+ count += snprintf(buf+count, PAGE_SIZE-count,
+ "seq%d: 0x%02x\n", i+1, reg_val);
+ aw8695->seq[i] |= reg_val;
+ }
+ return count;
+}
+
+static ssize_t aw8695_seq_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+
+#ifdef MOTO_VIBRATOR_SUPPORT
+ unsigned int i = 0;
+ unsigned int val = 0;
+ int rc = 0;
+
+ rc = kstrtouint(buf, 0, &val);
+ if (rc < 0)
+ return rc;
+
+ pr_debug("%s: value=%x\n", __FUNCTION__, val);
+
+ mutex_lock(&aw8695->lock);
+ for(i=0; i<4; i++) {
+ aw8695->seq[i] = (val>>((AW8695_WAV_SEQ_SIZE-i-1)*8))&0xFF;
+ aw8695_haptic_set_wav_seq(aw8695, i, aw8695->seq[i]);
+ }
+ mutex_unlock(&aw8695->lock);
+#else
+ unsigned int databuf[2] = {0, 0};
+
+ if(2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) {
+ pr_debug("%s: seq%d=0x%x\n", __FUNCTION__, databuf[0], databuf[1]);
+ mutex_lock(&aw8695->lock);
+ aw8695->seq[databuf[0]] = (unsigned char)databuf[1];
+ aw8695_haptic_set_wav_seq(aw8695, (unsigned char)databuf[0],
+ aw8695->seq[databuf[0]]);
+ mutex_unlock(&aw8695->lock);
+ }
+#endif
+ return count;
+}
+
+static ssize_t aw8695_loop_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ size_t count = 0;
+ unsigned char i = 0;
+ unsigned char reg_val = 0;
+
+ for(i=0; i<AW8695_SEQUENCER_LOOP_SIZE; i++) {
+ aw8695_i2c_read(aw8695, AW8695_REG_WAVLOOP1+i, ®_val);
+ aw8695->loop[i*2+0] = (reg_val>>4)&0x0F;
+ aw8695->loop[i*2+1] = (reg_val>>0)&0x0F;
+
+ count += snprintf(buf+count, PAGE_SIZE-count,
+ "seq%d loop: 0x%02x\n", i*2+1, aw8695->loop[i*2+0]);
+ count += snprintf(buf+count, PAGE_SIZE-count,
+ "seq%d loop: 0x%02x\n", i*2+2, aw8695->loop[i*2+1]);
+ }
+ return count;
+}
+
+static ssize_t aw8695_loop_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ unsigned int databuf[2] = {0, 0};
+
+ if(2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) {
+ pr_debug("%s: seq%d loop=0x%x\n", __FUNCTION__, databuf[0], databuf[1]);
+ mutex_lock(&aw8695->lock);
+ aw8695->loop[databuf[0]] = (unsigned char)databuf[1];
+ aw8695_haptic_set_wav_loop(aw8695, (unsigned char)databuf[0],
+ aw8695->loop[databuf[0]]);
+ mutex_unlock(&aw8695->lock);
+ }
+
+ return count;
+}
+
+static ssize_t aw8695_reg_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ ssize_t len = 0;
+ unsigned char i = 0;
+ unsigned char reg_val = 0;
+ for(i = 0; i < AW8695_REG_MAX; i ++) {
+ if(!(aw8695_reg_access[i]®_RD_ACCESS))
+ continue;
+ aw8695_i2c_read(aw8695, i, ®_val);
+ len += snprintf(buf+len, PAGE_SIZE-len, "reg:0x%02x=0x%02x \n", i, reg_val);
+ }
+ return len;
+}
+
+static ssize_t aw8695_reg_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ unsigned int databuf[2] = {0, 0};
+
+ if(2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) {
+ aw8695_i2c_write(aw8695, (unsigned char)databuf[0], (unsigned char)databuf[1]);
+ }
+
+ return count;
+}
+
+static ssize_t aw8695_rtp_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ ssize_t len = 0;
+ len += snprintf(buf+len, PAGE_SIZE-len, "rtp play: %d\n", aw8695->rtp_cnt);
+
+ return len;
+}
+
+static ssize_t aw8695_rtp_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ unsigned int val = 0;
+ int rc = 0;
+
+ rc = kstrtouint(buf, 0, &val);
+ if (rc < 0)
+ return rc;
+
+ aw8695_haptic_stop(aw8695);
+ aw8695_haptic_set_rtp_aei(aw8695, false);
+ aw8695_interrupt_clear(aw8695);
+ if(val < (sizeof(aw8695_rtp_name)/AW8695_RTP_NAME_MAX)) {
+ aw8695->rtp_file_num = val;
+ if(val) {
+ schedule_work(&aw8695->rtp_work);
+ }
+ } else {
+ pr_err("%s: rtp_file_num 0x%02x over max value \n", __func__, aw8695->rtp_file_num);
+ }
+
+ return count;
+}
+
+static ssize_t aw8695_ram_update_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+#ifdef TIMED_OUTPUT
+ //struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ //struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ //struct led_classdev *cdev = dev_get_drvdata(dev);
+ //struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ ssize_t len = 0;
+ len += snprintf(buf+len, PAGE_SIZE-len, "sram update mode\n");
+ return len;
+}
+
+static ssize_t aw8695_ram_update_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ unsigned int val = 0;
+ int rc = 0;
+
+ rc = kstrtouint(buf, 0, &val);
+ if (rc < 0)
+ return rc;
+
+ if(val) {
+ aw8695_ram_update(aw8695);
+ }
+ return count;
+}
+
+static ssize_t aw8695_f0_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ ssize_t len = 0;
+
+ mutex_lock(&aw8695->lock);
+ aw8695->f0_cali_flag = AW8695_HAPTIC_LRA_F0;
+ aw8695_haptic_get_f0(aw8695);
+ mutex_unlock(&aw8695->lock);
+ len += snprintf(buf+len, PAGE_SIZE-len, "aw8695 lra f0 = %d\n", aw8695->f0);
+ return len;
+}
+
+static ssize_t aw8695_f0_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+#ifdef TIMED_OUTPUT
+ //struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ //struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ //struct led_classdev *cdev = dev_get_drvdata(dev);
+ //struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ unsigned int val = 0;
+ int rc = 0;
+
+ rc = kstrtouint(buf, 0, &val);
+ if (rc < 0)
+ return rc;
+
+ return count;
+}
+
+static ssize_t aw8695_cali_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ ssize_t len = 0;
+ mutex_lock(&aw8695->lock);
+ aw8695->f0_cali_flag = AW8695_HAPTIC_CALI_F0;
+ aw8695_haptic_get_f0(aw8695);
+ mutex_unlock(&aw8695->lock);
+ len += snprintf(buf+len, PAGE_SIZE-len, "aw8695 cali f0 = %d\n", aw8695->f0);
+ return len;
+}
+
+static ssize_t aw8695_cali_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ unsigned int val = 0;
+ int rc = 0;
+
+ rc = kstrtouint(buf, 0, &val);
+ if (rc < 0)
+ return rc;
+
+ if(val) {
+ mutex_lock(&aw8695->lock);
+ aw8695_haptic_f0_calibration(aw8695);
+ mutex_unlock(&aw8695->lock);
+ }
+ return count;
+}
+
+static ssize_t aw8695_cont_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ ssize_t len = 0;
+ aw8695_haptic_read_cont_f0(aw8695);
+ len += snprintf(buf+len, PAGE_SIZE-len, "aw8695 cont f0 = %d\n", aw8695->cont_f0);
+ return len;
+}
+
+static ssize_t aw8695_cont_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ unsigned int val = 0;
+ int rc = 0;
+
+ rc = kstrtouint(buf, 0, &val);
+ if (rc < 0)
+ return rc;
+
+ aw8695_haptic_stop(aw8695);
+ if(val) {
+ aw8695_haptic_cont(aw8695);
+ }
+ return count;
+}
+
+
+static ssize_t aw8695_cont_td_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ ssize_t len = 0;
+ len += snprintf(buf+len, PAGE_SIZE-len, "aw8695 cont delay time = 0x%04x\n", aw8695->cont_td);
+ return len;
+}
+
+static ssize_t aw8695_cont_td_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ unsigned int databuf[1] = {0};
+ if(1 == sscanf(buf, "%x", &databuf[0])) {
+ aw8695->cont_td = databuf[0];
+ aw8695_i2c_write(aw8695, AW8695_REG_TD_H, (unsigned char)(databuf[0]>>8));
+ aw8695_i2c_write(aw8695, AW8695_REG_TD_L, (unsigned char)(databuf[0]>>0));
+ }
+ return count;
+}
+
+static ssize_t aw8695_cont_drv_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ ssize_t len = 0;
+ len += snprintf(buf+len, PAGE_SIZE-len, "aw8695 cont drv level = %d\n", aw8695->cont_drv_lvl);
+ len += snprintf(buf+len, PAGE_SIZE-len, "aw8695 cont drv level overdrive= %d\n", aw8695->cont_drv_lvl_ov);
+ return len;
+}
+
+static ssize_t aw8695_cont_drv_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ unsigned int databuf[2] = {0, 0};
+ if(2 == sscanf(buf, "%d %d", &databuf[0], &databuf[1])) {
+ aw8695->cont_drv_lvl = databuf[0];
+ aw8695_i2c_write(aw8695, AW8695_REG_DRV_LVL, aw8695->cont_drv_lvl);
+ aw8695->cont_drv_lvl_ov = databuf[1];
+ aw8695_i2c_write(aw8695, AW8695_REG_DRV_LVL_OV, aw8695->cont_drv_lvl_ov);
+ }
+ return count;
+}
+
+static ssize_t aw8695_cont_num_brk_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ ssize_t len = 0;
+ len += snprintf(buf+len, PAGE_SIZE-len, "aw8695 cont break num = %d\n", aw8695->cont_num_brk);
+ return len;
+}
+
+static ssize_t aw8695_cont_num_brk_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ unsigned int databuf[1] = {0};
+ if(1 == sscanf(buf, "%d", &databuf[0])) {
+ aw8695->cont_num_brk = databuf[0];
+ if(aw8695->cont_num_brk > 7) {
+ aw8695->cont_num_brk = 7;
+ }
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_BEMF_NUM,
+ AW8695_BIT_BEMF_NUM_BRK_MASK, aw8695->cont_num_brk);
+ }
+ return count;
+}
+
+static ssize_t aw8695_cont_zc_thr_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ ssize_t len = 0;
+ len += snprintf(buf+len, PAGE_SIZE-len, "aw8695 cont zero cross thr = 0x%04x\n", aw8695->cont_zc_thr);
+ return len;
+}
+
+static ssize_t aw8695_cont_zc_thr_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ unsigned int databuf[1] = {0};
+ if(1 == sscanf(buf, "%x", &databuf[0])) {
+ aw8695->cont_zc_thr = databuf[0];
+ aw8695_i2c_write(aw8695, AW8695_REG_ZC_THRSH_H, (unsigned char)(databuf[0]>>8));
+ aw8695_i2c_write(aw8695, AW8695_REG_ZC_THRSH_L, (unsigned char)(databuf[0]>>0));
+ }
+ return count;
+}
+
+static ssize_t aw8695_vbat_monitor_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ ssize_t len = 0;
+
+ mutex_lock(&aw8695->lock);
+ aw8695_haptic_stop(aw8695);
+ aw8695_haptic_get_vbat(aw8695);
+ len += snprintf(buf+len, PAGE_SIZE-len, "vbat=%dmV\n", aw8695->vbat);
+ mutex_unlock(&aw8695->lock);
+
+ return len;
+}
+
+static ssize_t aw8695_vbat_monitor_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return count;
+}
+
+static ssize_t aw8695_lra_resistance_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ ssize_t len = 0;
+ unsigned char reg_val = 0;
+
+ mutex_lock(&aw8695->lock);
+ aw8695_haptic_stop(aw8695);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_RAMINIT_MASK, AW8695_BIT_SYSCTRL_RAMINIT_EN);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BYPASS);
+
+
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_ANACTRL,
+ AW8695_BIT_ANACTRL_HD_PD_MASK, AW8695_BIT_ANACTRL_HD_HZ_EN);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_D2SCFG,
+ AW8695_BIT_D2SCFG_CLK_ADC_MASK, AW8695_BIT_D2SCFG_CLK_ASC_1P5MHZ);
+
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_DETCTRL,
+ AW8695_BIT_DETCTRL_RL_OS_MASK, AW8695_BIT_DETCTRL_RL_DETECT);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_DETCTRL,
+ AW8695_BIT_DETCTRL_DIAG_GO_MASK, AW8695_BIT_DETCTRL_DIAG_GO_ENABLE);
+ msleep(3);
+ aw8695_i2c_read(aw8695, AW8695_REG_RLDET, ®_val);
+ aw8695->lra = 298 * reg_val;
+ len += snprintf(buf+len, PAGE_SIZE-len, "r_lra=%dmohm\n", aw8695->lra);
+
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_ANACTRL,
+ AW8695_BIT_ANACTRL_HD_PD_MASK, AW8695_BIT_ANACTRL_HD_PD_EN);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_D2SCFG,
+ AW8695_BIT_D2SCFG_CLK_ADC_MASK, AW8695_BIT_D2SCFG_CLK_ASC_6MHZ);
+
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_RAMINIT_MASK, AW8695_BIT_SYSCTRL_RAMINIT_OFF);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_BST_MODE_MASK, AW8695_BIT_SYSCTRL_BST_MODE_BOOST);
+ mutex_unlock(&aw8695->lock);
+
+ return len;
+}
+
+static ssize_t aw8695_lra_resistance_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return count;
+}
+
+static ssize_t aw8695_auto_boost_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ ssize_t len = 0;
+
+ len += snprintf(buf+len, PAGE_SIZE-len, "auto_boost=%d\n", aw8695->auto_boost);
+
+ return len;
+}
+
+
+static ssize_t aw8695_auto_boost_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ unsigned int val = 0;
+ int rc = 0;
+
+ rc = kstrtouint(buf, 0, &val);
+ if (rc < 0)
+ return rc;
+
+ mutex_lock(&aw8695->lock);
+ aw8695_haptic_stop(aw8695);
+ aw8695_haptic_auto_boost_config(aw8695, val);
+ mutex_unlock(&aw8695->lock);
+
+ return count;
+}
+
+static ssize_t aw8695_prctmode_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ ssize_t len = 0;
+ unsigned char reg_val = 0;
+
+ aw8695_i2c_read(aw8695, AW8695_REG_RLDET, ®_val);
+
+ len += snprintf(buf+len, PAGE_SIZE-len, "prctmode=%d\n", reg_val&0x20);
+ return len;
+}
+
+
+static ssize_t aw8695_prctmode_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ #ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+ #else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+ #endif
+ unsigned int databuf[2] = {0, 0};
+ unsigned int addr=0;
+ unsigned int val=0;
+ if(2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) {
+ addr = databuf[0];
+ val=databuf[1];
+ mutex_lock(&aw8695->lock);
+ aw8695_haptic_swicth_motorprotect_config(aw8695, addr, val);
+ mutex_unlock(&aw8695->lock);
+ }
+ return count;
+}
+
+static ssize_t aw8695_trig_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ ssize_t len = 0;
+ unsigned char i = 0;
+ for(i=0; i<AW8695_TRIG_NUM; i++) {
+ len += snprintf(buf+len, PAGE_SIZE-len,
+ "trig%d: enable=%d, default_level=%d, dual_edge=%d, frist_seq=%d, second_seq=%d\n",
+ i+1, aw8695->trig[i].enable, aw8695->trig[i].default_level, aw8695->trig[i].dual_edge,
+ aw8695->trig[i].frist_seq, aw8695->trig[i].second_seq);
+ }
+
+ return len;
+}
+
+static ssize_t aw8695_trig_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ #ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+ #else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+ #endif
+ unsigned int databuf[6] = {0};
+ if(sscanf(buf, "%d %d %d %d %d %d",
+ &databuf[0], &databuf[1], &databuf[2], &databuf[3], &databuf[4], &databuf[5])) {
+ pr_debug("%s: %d, %d, %d, %d, %d, %d\n", __func__,
+ databuf[0], databuf[1], databuf[2], databuf[3], databuf[4], databuf[5]);
+ if(databuf[0] > 3) {
+ databuf[0] = 3;
+ }
+ if(databuf[0] > 0) {
+ databuf[0] -= 1;
+ }
+ aw8695->trig[databuf[0]].enable = databuf[1];
+ aw8695->trig[databuf[0]].default_level = databuf[2];
+ aw8695->trig[databuf[0]].dual_edge = databuf[3];
+ aw8695->trig[databuf[0]].frist_seq = databuf[4];
+ aw8695->trig[databuf[0]].second_seq = databuf[5];
+ mutex_lock(&aw8695->lock);
+ aw8695_haptic_trig_param_config(aw8695);
+ aw8695_haptic_trig_enable_config(aw8695);
+ mutex_unlock(&aw8695->lock);
+ }
+ return count;
+}
+
+static ssize_t aw8695_ram_vbat_comp_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ ssize_t len = 0;
+
+ len += snprintf(buf+len, PAGE_SIZE-len, "ram_vbat_comp=%d\n", aw8695->ram_vbat_comp);
+
+ return len;
+}
+
+
+static ssize_t aw8695_ram_vbat_comp_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ unsigned int val = 0;
+ int rc = 0;
+
+ rc = kstrtouint(buf, 0, &val);
+ if (rc < 0)
+ return rc;
+
+ mutex_lock(&aw8695->lock);
+ if(val) {
+ aw8695->ram_vbat_comp = AW8695_HAPTIC_RAM_VBAT_COMP_ENABLE;
+ } else {
+ aw8695->ram_vbat_comp = AW8695_HAPTIC_RAM_VBAT_COMP_DISABLE;
+ }
+ mutex_unlock(&aw8695->lock);
+
+ return count;
+}
+
+static ssize_t aw8695_haptic_audio_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ ssize_t len = 0;
+ len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw8695->haptic_audio.cnt);
+ return len;
+}
+
+static ssize_t aw8695_haptic_audio_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ unsigned int databuf[6] = {0};
+
+ if(6 == sscanf(buf, "%d %d %d %d %d %d", &databuf[0], &databuf[1], &databuf[2],
+ &databuf[3], &databuf[4], &databuf[5])) {
+ pr_debug("%s: cnt=%d, cmd=%d, play=%d, wavseq=%d, loop=%d, gain=%d\n",
+ __func__, databuf[0], databuf[1], databuf[2], databuf[3],
+ databuf[4], databuf[5]);
+ mutex_lock(&aw8695->haptic_audio.lock);
+ aw8695->haptic_audio.data[(unsigned char)databuf[0]].cmd = (unsigned char)databuf[1];
+ aw8695->haptic_audio.data[(unsigned char)databuf[0]].play = (unsigned char)databuf[2];
+ aw8695->haptic_audio.data[(unsigned char)databuf[0]].wavseq = (unsigned char)databuf[3];
+ aw8695->haptic_audio.data[(unsigned char)databuf[0]].loop = (unsigned char)databuf[4];
+ aw8695->haptic_audio.data[(unsigned char)databuf[0]].gain = (unsigned char)databuf[5];
+ mutex_unlock(&aw8695->haptic_audio.lock);
+
+ if(aw8695->haptic_audio.data[aw8695->haptic_audio.cnt].cmd == 0xff) {
+ pr_info("%s: haptic_audio stop\n", __func__);
+ if(hrtimer_active(&aw8695->haptic_audio.timer)) {
+ pr_info("%s: cancel haptic_audio_timer\n", __func__);
+ hrtimer_cancel(&aw8695->haptic_audio.timer);
+ aw8695->haptic_audio.cnt = 0;
+ aw8695_haptic_set_gain(aw8695, 0x80);
+ }
+ } else {
+ if(hrtimer_active(&aw8695->haptic_audio.timer)) {
+ } else {
+ pr_info("%s: start haptic_audio_timer\n", __func__);
+ hrtimer_start(&aw8695->haptic_audio.timer,
+ ktime_set(aw8695->haptic_audio.delay_val/1000000,
+ (aw8695->haptic_audio.delay_val%1000000)*1000),
+ HRTIMER_MODE_REL);
+ }
+ }
+ }
+ return count;
+}
+
+
+static ssize_t aw8695_haptic_audio_time_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ ssize_t len = 0;
+ len += snprintf(buf+len, PAGE_SIZE-len, "haptic_audio.delay_val=%dus\n", aw8695->haptic_audio.delay_val);
+ len += snprintf(buf+len, PAGE_SIZE-len, "haptic_audio.timer_val=%dus\n", aw8695->haptic_audio.timer_val);
+ return len;
+}
+
+static ssize_t aw8695_haptic_audio_time_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+#ifdef TIMED_OUTPUT
+ struct timed_output_dev *to_dev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);
+#else
+ struct led_classdev *cdev = dev_get_drvdata(dev);
+ struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev);
+#endif
+ unsigned int databuf[2] = {0};
+
+ if(2 == sscanf(buf, "%d %d", &databuf[0], &databuf[1])) {
+ aw8695->haptic_audio.delay_val = databuf[0];
+ aw8695->haptic_audio.timer_val = databuf[1];
+ }
+ return count;
+}
+
+
+static DEVICE_ATTR(state, S_IWUSR | S_IRUGO, aw8695_state_show, aw8695_state_store);
+static DEVICE_ATTR(duration, S_IWUSR | S_IRUGO, aw8695_duration_show, aw8695_duration_store);
+static DEVICE_ATTR(activate, S_IWUSR | S_IRUGO, aw8695_activate_show, aw8695_activate_store);
+static DEVICE_ATTR(activate_mode, S_IWUSR | S_IRUGO, aw8695_activate_mode_show, aw8695_activate_mode_store);
+static DEVICE_ATTR(index, S_IWUSR | S_IRUGO, aw8695_index_show, aw8695_index_store);
+static DEVICE_ATTR(vmax, S_IWUSR | S_IRUGO, aw8695_vmax_show, aw8695_vmax_store);
+static DEVICE_ATTR(gain, S_IWUSR | S_IRUGO, aw8695_gain_show, aw8695_gain_store);
+static DEVICE_ATTR(seq, S_IWUSR | S_IRUGO, aw8695_seq_show, aw8695_seq_store);
+static DEVICE_ATTR(loop, S_IWUSR | S_IRUGO, aw8695_loop_show, aw8695_loop_store);
+static DEVICE_ATTR(register, S_IWUSR | S_IRUGO, aw8695_reg_show, aw8695_reg_store);
+static DEVICE_ATTR(rtp, S_IWUSR | S_IRUGO, aw8695_rtp_show, aw8695_rtp_store);
+static DEVICE_ATTR(ram_update, S_IWUSR | S_IRUGO, aw8695_ram_update_show, aw8695_ram_update_store);
+static DEVICE_ATTR(f0, S_IWUSR | S_IRUGO, aw8695_f0_show, aw8695_f0_store);
+static DEVICE_ATTR(cali, S_IWUSR | S_IRUGO, aw8695_cali_show, aw8695_cali_store);
+static DEVICE_ATTR(cont, S_IWUSR | S_IRUGO, aw8695_cont_show, aw8695_cont_store);
+static DEVICE_ATTR(cont_td, S_IWUSR | S_IRUGO, aw8695_cont_td_show, aw8695_cont_td_store);
+static DEVICE_ATTR(cont_drv, S_IWUSR | S_IRUGO, aw8695_cont_drv_show, aw8695_cont_drv_store);
+static DEVICE_ATTR(cont_num_brk, S_IWUSR | S_IRUGO, aw8695_cont_num_brk_show, aw8695_cont_num_brk_store);
+static DEVICE_ATTR(cont_zc_thr, S_IWUSR | S_IRUGO, aw8695_cont_zc_thr_show, aw8695_cont_zc_thr_store);
+static DEVICE_ATTR(vbat_monitor, S_IWUSR | S_IRUGO, aw8695_vbat_monitor_show, aw8695_vbat_monitor_store);
+static DEVICE_ATTR(lra_resistance, S_IWUSR | S_IRUGO, aw8695_lra_resistance_show, aw8695_lra_resistance_store);
+static DEVICE_ATTR(auto_boost, S_IWUSR | S_IRUGO, aw8695_auto_boost_show, aw8695_auto_boost_store);
+static DEVICE_ATTR(prctmode, S_IWUSR | S_IRUGO, aw8695_prctmode_show, aw8695_prctmode_store);
+static DEVICE_ATTR(trig, S_IWUSR | S_IRUGO, aw8695_trig_show, aw8695_trig_store);
+static DEVICE_ATTR(ram_vbat_comp, S_IWUSR | S_IRUGO, aw8695_ram_vbat_comp_show, aw8695_ram_vbat_comp_store);
+static DEVICE_ATTR(haptic_audio, S_IWUSR | S_IRUGO, aw8695_haptic_audio_show, aw8695_haptic_audio_store);
+static DEVICE_ATTR(haptic_audio_time, S_IWUSR | S_IRUGO, aw8695_haptic_audio_time_show, aw8695_haptic_audio_time_store);
+
+
+static struct attribute *aw8695_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_vmax.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_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_auto_boost.attr,
+ &dev_attr_prctmode.attr,
+ &dev_attr_trig.attr,
+ &dev_attr_ram_vbat_comp.attr,
+ &dev_attr_haptic_audio.attr,
+ &dev_attr_haptic_audio_time.attr,
+ NULL
+};
+
+static struct attribute_group aw8695_vibrator_attribute_group = {
+ .attrs = aw8695_vibrator_attributes
+};
+
+static enum hrtimer_restart aw8695_vibrator_timer_func(struct hrtimer *timer)
+{
+ struct aw8695 *aw8695 = container_of(timer, struct aw8695, timer);
+
+ pr_debug("%s enter\n", __func__);
+ aw8695->state = 0;
+ schedule_work(&aw8695->vibrator_work);
+
+ return HRTIMER_NORESTART;
+}
+
+static void aw8695_vibrator_work_routine(struct work_struct *work)
+{
+ struct aw8695 *aw8695 = container_of(work, struct aw8695, vibrator_work);
+
+ pr_debug("%s enter\n", __func__);
+
+ mutex_lock(&aw8695->lock);
+
+ aw8695_haptic_stop(aw8695);
+ if(aw8695->state) {
+ if(aw8695->activate_mode == AW8695_HAPTIC_ACTIVATE_RAM_MODE) {
+ aw8695_haptic_ram_vbat_comp(aw8695, true);
+ aw8695_haptic_play_repeat_seq(aw8695, true);
+ } else if(aw8695->activate_mode == AW8695_HAPTIC_ACTIVATE_CONT_MODE) {
+ aw8695_haptic_cont(aw8695);
+ } else {
+ }
+ }
+ mutex_unlock(&aw8695->lock);
+}
+
+static int aw8695_vibrator_init(struct aw8695 *aw8695)
+{
+ int ret = 0;
+
+ pr_info("%s enter\n", __func__);
+
+#ifdef TIMED_OUTPUT
+ aw8695->to_dev.name = "vibrator";
+ aw8695->to_dev.get_time = aw8695_vibrator_get_time;
+ aw8695->to_dev.enable = aw8695_vibrator_enable;
+
+ ret = timed_output_dev_register(&(aw8695->to_dev));
+ if ( ret < 0){
+ dev_err(aw8695->dev, "%s: fail to create timed output dev\n",
+ __func__);
+ return ret;
+ }
+ ret = sysfs_create_group(&aw8695->to_dev.dev->kobj, &aw8695_vibrator_attribute_group);
+ if (ret < 0) {
+ dev_err(aw8695->dev, "%s error creating sysfs attr files\n", __func__);
+ return ret;
+ }
+#else
+ aw8695->cdev.name = "vibrator";
+ aw8695->cdev.brightness_get = aw8695_haptic_brightness_get;
+ aw8695->cdev.brightness_set = aw8695_haptic_brightness_set;
+
+ ret = devm_led_classdev_register(&aw8695->i2c->dev, &aw8695->cdev);
+ if (ret < 0){
+ dev_err(aw8695->dev, "%s: fail to create led dev\n",
+ __func__);
+ return ret;
+ }
+ ret = sysfs_create_group(&aw8695->cdev.dev->kobj, &aw8695_vibrator_attribute_group);
+ if (ret < 0) {
+ dev_err(aw8695->dev, "%s error creating sysfs attr files\n", __func__);
+ return ret;
+ }
+#endif
+ hrtimer_init(&aw8695->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ aw8695->timer.function = aw8695_vibrator_timer_func;
+ INIT_WORK(&aw8695->vibrator_work, aw8695_vibrator_work_routine);
+
+ INIT_WORK(&aw8695->rtp_work, aw8695_rtp_work_routine);
+
+ mutex_init(&aw8695->lock);
+
+ return 0;
+}
+
+
+
+
+/******************************************************
+ *
+ * irq
+ *
+ ******************************************************/
+static void aw8695_interrupt_clear(struct aw8695 *aw8695)
+{
+ unsigned char reg_val = 0;
+ pr_debug("%s enter\n", __func__);
+ aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val);
+ pr_debug("%s: reg SYSINT=0x%x\n", __func__, reg_val);
+}
+
+static void aw8695_interrupt_setup(struct aw8695 *aw8695)
+{
+ unsigned char reg_val = 0;
+
+ pr_info("%s enter\n", __func__);
+
+ aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val);
+ pr_info("%s: reg SYSINT=0x%x\n", __func__, reg_val);
+
+ /* edge int mode */
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_DBGCTRL,
+ AW8695_BIT_DBGCTRL_INT_MODE_MASK, AW8695_BIT_DBGCTRL_INT_MODE_EDGE);
+
+ /* int enable */
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM,
+ AW8695_BIT_SYSINTM_BSTERR_MASK, AW8695_BIT_SYSINTM_BSTERR_OFF);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM,
+ AW8695_BIT_SYSINTM_OV_MASK, AW8695_BIT_SYSINTM_OV_EN);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM,
+ AW8695_BIT_SYSINTM_UVLO_MASK, AW8695_BIT_SYSINTM_UVLO_EN);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM,
+ AW8695_BIT_SYSINTM_OCD_MASK, AW8695_BIT_SYSINTM_OCD_EN);
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM,
+ AW8695_BIT_SYSINTM_OT_MASK, AW8695_BIT_SYSINTM_OT_EN);
+}
+
+static irqreturn_t aw8695_irq(int irq, void *data)
+{
+ struct aw8695 *aw8695 = data;
+ unsigned char reg_val = 0;
+ unsigned char dbg_val = 0;
+ unsigned int buf_len = 0;
+
+ pr_debug("%s enter\n", __func__);
+
+ aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val);
+ pr_info("%s: reg SYSINT=0x%x\n", __func__, reg_val);
+ aw8695_i2c_read(aw8695, AW8695_REG_DBGSTAT, &dbg_val);
+ pr_info("%s: reg DBGSTAT=0x%x\n", __func__, dbg_val);
+
+ if(reg_val & AW8695_BIT_SYSINT_OVI) {
+ pr_err("%s chip ov int error\n", __func__);
+ }
+ if(reg_val & AW8695_BIT_SYSINT_UVLI) {
+ pr_err("%s chip uvlo int error\n", __func__);
+ }
+ if(reg_val & AW8695_BIT_SYSINT_OCDI) {
+ pr_err("%s chip over current int error\n", __func__);
+ }
+ if(reg_val & AW8695_BIT_SYSINT_OTI) {
+ pr_err("%s chip over temperature int error\n", __func__);
+ }
+ if(reg_val & AW8695_BIT_SYSINT_DONEI) {
+ pr_info("%s chip playback done\n", __func__);
+ }
+
+ if(reg_val & AW8695_BIT_SYSINT_FF_AEI) {
+ pr_debug("%s: aw8695 rtp fifo almost empty int\n", __func__);
+ if(aw8695->rtp_init) {
+ while((!aw8695_haptic_rtp_get_fifo_afi(aw8695)) &&
+ (aw8695->play_mode == AW8695_HAPTIC_RTP_MODE)) {
+ pr_info("%s: aw8695 rtp mode fifo update, cnt=%d\n",
+ __func__, aw8695->rtp_cnt);
+ if((aw8695_rtp->len-aw8695->rtp_cnt) < (aw8695->ram.base_addr>>2)) {
+ buf_len = aw8695_rtp->len-aw8695->rtp_cnt;
+ } else {
+ buf_len = (aw8695->ram.base_addr>>2);
+ }
+ aw8695_i2c_writes(aw8695, AW8695_REG_RTP_DATA,
+ &aw8695_rtp->data[aw8695->rtp_cnt], buf_len);
+ aw8695->rtp_cnt += buf_len;
+ if(aw8695->rtp_cnt == aw8695_rtp->len) {
+ pr_info("%s: rtp update complete\n", __func__);
+ aw8695_haptic_set_rtp_aei(aw8695, false);
+ aw8695->rtp_cnt = 0;
+ aw8695->rtp_init = 0;
+ break;
+ }
+ }
+ } else {
+ pr_err("%s: aw8695 rtp init = %d, init error\n", __func__, aw8695->rtp_init);
+ }
+ }
+
+ if(reg_val & AW8695_BIT_SYSINT_FF_AFI) {
+ pr_debug("%s: aw8695 rtp mode fifo full empty\n", __func__);
+ }
+
+ if(aw8695->play_mode != AW8695_HAPTIC_RTP_MODE) {
+ aw8695_haptic_set_rtp_aei(aw8695, false);
+ }
+
+ aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val);
+ pr_debug("%s: reg SYSINT=0x%x\n", __func__, reg_val);
+ aw8695_i2c_read(aw8695, AW8695_REG_SYSST, ®_val);
+ pr_debug("%s: reg SYSST=0x%x\n", __func__, reg_val);
+
+ pr_debug("%s exit\n", __func__);
+
+ return IRQ_HANDLED;
+}
+
+/*****************************************************
+ *
+ * device tree
+ *
+ *****************************************************/
+static int aw8695_parse_dt(struct device *dev, struct aw8695 *aw8695,
+ struct device_node *np) {
+ aw8695->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
+ if (aw8695->reset_gpio < 0) {
+ dev_err(dev, "%s: no reset gpio provided, will not HW reset device\n", __func__);
+ return -1;
+ } else {
+ dev_info(dev, "%s: reset gpio provided ok\n", __func__);
+ }
+ aw8695->irq_gpio = of_get_named_gpio(np, "irq-gpio", 0);
+ if (aw8695->irq_gpio < 0) {
+ dev_err(dev, "%s: no irq gpio provided.\n", __func__);
+ } else {
+ dev_info(dev, "%s: irq gpio provided ok.\n", __func__);
+ }
+
+ return 0;
+}
+
+static int aw8695_hw_reset(struct aw8695 *aw8695)
+{
+ pr_info("%s enter\n", __func__);
+
+ if (aw8695 && gpio_is_valid(aw8695->reset_gpio)) {
+ gpio_set_value_cansleep(aw8695->reset_gpio, 0);
+ msleep(1);
+ gpio_set_value_cansleep(aw8695->reset_gpio, 1);
+ msleep(1);
+ } else {
+ dev_err(aw8695->dev, "%s: failed\n", __func__);
+ }
+ return 0;
+}
+
+
+/*****************************************************
+ *
+ * check chip id
+ *
+ *****************************************************/
+static int aw8695_read_chipid(struct aw8695 *aw8695)
+{
+ int ret = -1;
+ unsigned char cnt = 0;
+ unsigned char reg = 0;
+
+ while(cnt < AW_READ_CHIPID_RETRIES) {
+ /* hardware reset */
+ aw8695_hw_reset(aw8695);
+
+ ret = aw8695_i2c_read(aw8695, AW8695_REG_ID, ®);
+ if (ret < 0) {
+ dev_err(aw8695->dev, "%s: failed to read register AW8695_REG_ID: %d\n", __func__, ret);
+ }
+ switch (reg) {
+ case AW8695_CHIPID:
+ pr_info("%s aw8695 detected\n", __func__);
+ aw8695->chipid = AW8695_CHIPID;
+ //aw8695->flags |= AW8695_FLAG_SKIP_INTERRUPTS;
+ aw8695_haptic_softreset(aw8695);
+ return 0;
+ default:
+ pr_info("%s unsupported device revision (0x%x)\n", __func__, reg );
+ break;
+ }
+ cnt ++;
+
+ msleep(AW_READ_CHIPID_RETRY_DELAY);
+ }
+
+ return -EINVAL;
+}
+
+/******************************************************
+ *
+ * sys group attribute: reg
+ *
+ ******************************************************/
+static ssize_t aw8695_i2c_reg_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct aw8695 *aw8695 = dev_get_drvdata(dev);
+
+ unsigned int databuf[2] = {0, 0};
+
+ if(2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) {
+ aw8695_i2c_write(aw8695, (unsigned char)databuf[0], (unsigned char)databuf[1]);
+ }
+
+ return count;
+}
+
+static ssize_t aw8695_i2c_reg_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct aw8695 *aw8695 = dev_get_drvdata(dev);
+ ssize_t len = 0;
+ unsigned char i = 0;
+ unsigned char reg_val = 0;
+ for(i = 0; i < AW8695_REG_MAX; i ++) {
+ if(!(aw8695_reg_access[i]®_RD_ACCESS))
+ continue;
+ aw8695_i2c_read(aw8695, i, ®_val);
+ len += snprintf(buf+len, PAGE_SIZE-len, "reg:0x%02x=0x%02x \n", i, reg_val);
+ }
+ return len;
+}
+static ssize_t aw8695_i2c_ram_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct aw8695 *aw8695 = dev_get_drvdata(dev);
+
+ unsigned int databuf[1] = {0};
+
+ if(1 == sscanf(buf, "%x", &databuf[0])) {
+ if(1 == databuf[0]) {
+ aw8695_ram_update(aw8695);
+ }
+ }
+
+ return count;
+}
+
+static ssize_t aw8695_i2c_ram_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct aw8695 *aw8695 = dev_get_drvdata(dev);
+ ssize_t len = 0;
+ unsigned int i = 0;
+ unsigned char reg_val = 0;
+
+ aw8695_haptic_stop(aw8695);
+ /* RAMINIT Enable */
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_RAMINIT_MASK, AW8695_BIT_SYSCTRL_RAMINIT_EN);
+
+ aw8695_i2c_write(aw8695, AW8695_REG_RAMADDRH, (unsigned char)(aw8695->ram.base_addr>>8));
+ aw8695_i2c_write(aw8695, AW8695_REG_RAMADDRL, (unsigned char)(aw8695->ram.base_addr&0x00ff));
+ len += snprintf(buf+len, PAGE_SIZE-len, "aw8695_haptic_ram:\n");
+ for(i=0; i<aw8695->ram.len; i++) {
+ aw8695_i2c_read(aw8695, AW8695_REG_RAMDATA, ®_val);
+ len += snprintf(buf+len, PAGE_SIZE-len, "0x%02x,", reg_val);
+ }
+ len += snprintf(buf+len, PAGE_SIZE-len, "\n");
+ /* RAMINIT Disable */
+ aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL,
+ AW8695_BIT_SYSCTRL_RAMINIT_MASK, AW8695_BIT_SYSCTRL_RAMINIT_OFF);
+
+ return len;
+}
+
+static DEVICE_ATTR(reg, S_IWUSR | S_IRUGO, aw8695_i2c_reg_show, aw8695_i2c_reg_store);
+static DEVICE_ATTR(ram, S_IWUSR | S_IRUGO, aw8695_i2c_ram_show, aw8695_i2c_ram_store);
+
+static struct attribute *aw8695_attributes[] = {
+ &dev_attr_reg.attr,
+ &dev_attr_ram.attr,
+ NULL
+};
+
+static struct attribute_group aw8695_attribute_group = {
+ .attrs = aw8695_attributes
+};
+
+
+/******************************************************
+ *
+ * i2c driver
+ *
+ ******************************************************/
+static int aw8695_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+ struct aw8695 *aw8695;
+ struct device_node *np = i2c->dev.of_node;
+ int irq_flags = 0;
+ int ret = -1;
+
+ pr_info("%s enter\n", __func__);
+
+ if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) {
+ dev_err(&i2c->dev, "check_functionality failed\n");
+ return -EIO;
+ }
+
+ aw8695 = devm_kzalloc(&i2c->dev, sizeof(struct aw8695), GFP_KERNEL);
+ if (aw8695 == NULL)
+ return -ENOMEM;
+
+ aw8695->dev = &i2c->dev;
+ aw8695->i2c = i2c;
+
+ i2c_set_clientdata(i2c, aw8695);
+
+ /* aw8695 rst & int */
+ if (np) {
+ ret = aw8695_parse_dt(&i2c->dev, aw8695, np);
+ if (ret) {
+ dev_err(&i2c->dev, "%s: failed to parse device tree node\n", __func__);
+ goto err_parse_dt;
+ }
+ } else {
+ aw8695->reset_gpio = -1;
+ aw8695->irq_gpio = -1;
+ }
+
+ if (gpio_is_valid(aw8695->reset_gpio)) {
+ ret = devm_gpio_request_one(&i2c->dev, aw8695->reset_gpio,
+ GPIOF_OUT_INIT_LOW, "aw8695_rst");
+ if (ret){
+ dev_err(&i2c->dev, "%s: rst request failed\n", __func__);
+ goto err_reset_gpio_request;
+ }
+ }
+
+ if (gpio_is_valid(aw8695->irq_gpio)) {
+ ret = devm_gpio_request_one(&i2c->dev, aw8695->irq_gpio,
+ GPIOF_DIR_IN, "aw8695_int");
+ if (ret){
+ dev_err(&i2c->dev, "%s: int request failed\n", __func__);
+ goto err_irq_gpio_request;
+ }
+ }
+
+ /* aw8695 chip id */
+ ret = aw8695_read_chipid(aw8695);
+ if (ret < 0) {
+ dev_err(&i2c->dev, "%s: aw8695_read_chipid failed ret=%d\n", __func__, ret);
+ goto err_id;
+ }
+
+ /* aw8695 irq */
+ if (gpio_is_valid(aw8695->irq_gpio) &&
+ !(aw8695->flags & AW8695_FLAG_SKIP_INTERRUPTS)) {
+ /* register irq handler */
+ aw8695_interrupt_setup(aw8695);
+ irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
+ ret = devm_request_threaded_irq(&i2c->dev,
+ gpio_to_irq(aw8695->irq_gpio),
+ NULL, aw8695_irq, irq_flags,
+ "aw8695", aw8695);
+ if (ret != 0) {
+ dev_err(&i2c->dev, "%s: failed to request IRQ %d: %d\n",
+ __func__, gpio_to_irq(aw8695->irq_gpio), ret);
+ goto err_irq;
+ }
+ } else {
+ dev_info(&i2c->dev, "%s skipping IRQ registration\n", __func__);
+ /* disable feature support if gpio was invalid */
+ aw8695->flags |= AW8695_FLAG_SKIP_INTERRUPTS;
+ }
+
+ dev_set_drvdata(&i2c->dev, aw8695);
+
+ ret = sysfs_create_group(&i2c->dev.kobj, &aw8695_attribute_group);
+ if (ret < 0) {
+ dev_info(&i2c->dev, "%s error creating sysfs attr files\n", __func__);
+ goto err_sysfs;
+ }
+
+ g_aw8695 = aw8695;
+
+ aw8695_vibrator_init(aw8695);
+
+ aw8695_haptic_init(aw8695);
+
+ aw8695_ram_init(aw8695);
+
+ pr_info("%s probe completed successfully!\n", __func__);
+
+ return 0;
+
+err_sysfs:
+ devm_free_irq(&i2c->dev, gpio_to_irq(aw8695->irq_gpio), aw8695);
+err_irq:
+err_id:
+ if (gpio_is_valid(aw8695->irq_gpio))
+ devm_gpio_free(&i2c->dev, aw8695->irq_gpio);
+err_irq_gpio_request:
+ if (gpio_is_valid(aw8695->reset_gpio))
+ devm_gpio_free(&i2c->dev, aw8695->reset_gpio);
+err_reset_gpio_request:
+err_parse_dt:
+ devm_kfree(&i2c->dev, aw8695);
+ aw8695 = NULL;
+ return ret;
+}
+
+static int aw8695_i2c_remove(struct i2c_client *i2c)
+{
+ struct aw8695 *aw8695 = i2c_get_clientdata(i2c);
+
+ pr_info("%s enter\n", __func__);
+
+ sysfs_remove_group(&i2c->dev.kobj, &aw8695_attribute_group);
+
+ devm_free_irq(&i2c->dev, gpio_to_irq(aw8695->irq_gpio), aw8695);
+
+ if (gpio_is_valid(aw8695->irq_gpio))
+ devm_gpio_free(&i2c->dev, aw8695->irq_gpio);
+ if (gpio_is_valid(aw8695->reset_gpio))
+ devm_gpio_free(&i2c->dev, aw8695->reset_gpio);
+
+ devm_kfree(&i2c->dev, aw8695);
+ aw8695 = NULL;
+
+ return 0;
+}
+
+static const struct i2c_device_id aw8695_i2c_id[] = {
+ { AW8695_I2C_NAME, 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, aw8695_i2c_id);
+
+static struct of_device_id aw8695_dt_match[] = {
+ { .compatible = "awinic,aw8695_haptic" },
+ { },
+};
+
+static struct i2c_driver aw8695_i2c_driver = {
+ .driver = {
+ .name = AW8695_I2C_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(aw8695_dt_match),
+ },
+ .probe = aw8695_i2c_probe,
+ .remove = aw8695_i2c_remove,
+ .id_table = aw8695_i2c_id,
+};
+
+
+static int __init aw8695_i2c_init(void)
+{
+ int ret = 0;
+
+ pr_info("aw8695 driver version %s\n", AW8695_VERSION);
+
+ ret = i2c_add_driver(&aw8695_i2c_driver);
+ if(ret){
+ pr_err("fail to add aw8695 device into i2c\n");
+ return ret;
+ }
+
+ return 0;
+}
+//late_initcall(aw8695_i2c_init);
+module_init(aw8695_i2c_init);
+
+
+static void __exit aw8695_i2c_exit(void)
+{
+ i2c_del_driver(&aw8695_i2c_driver);
+}
+module_exit(aw8695_i2c_exit);
+
+
+MODULE_DESCRIPTION("AW8695 Haptic Driver");
+MODULE_LICENSE("GPL v2");