From b5d7f015638eff7f57c6c178c669c2203b10be29 Mon Sep 17 00:00:00 2001 From: Weilong Wu Date: Fri, 28 Dec 2018 15:41:54 +0800 Subject: [PATCH] dlkm: haptic: add aw8624 haptic driver Add new awinic haptic driver IC aw8624 driver. It can be compatible with TI drv2624. Change-Id: Ic58e3bd2891cb1d7c8e6f2025ea8e58f0586dcf6 Signed-off-by: Weilong Wu Reviewed-on: https://gerrit.mot.com/1287918 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Reviewed-by: Jialei Hao Reviewed-by: Hujun Liao Submit-Approved: Jira Key --- drivers/misc/awinic/aw8624/Android.mk | 12 + drivers/misc/awinic/aw8624/Kbuild | 5 + drivers/misc/awinic/aw8624/Makefile | 11 + drivers/misc/awinic/aw8624/aw8624.c | 2792 +++++++++++++++++++++++ drivers/misc/awinic/aw8624/aw8624.h | 230 ++ drivers/misc/awinic/aw8624/aw8624_reg.h | 594 +++++ 6 files changed, 3644 insertions(+) create mode 100644 drivers/misc/awinic/aw8624/Android.mk create mode 100644 drivers/misc/awinic/aw8624/Kbuild create mode 100644 drivers/misc/awinic/aw8624/Makefile create mode 100644 drivers/misc/awinic/aw8624/aw8624.c create mode 100644 drivers/misc/awinic/aw8624/aw8624.h create mode 100644 drivers/misc/awinic/aw8624/aw8624_reg.h diff --git a/drivers/misc/awinic/aw8624/Android.mk b/drivers/misc/awinic/aw8624/Android.mk new file mode 100644 index 000000000000..cbe49f2f90d5 --- /dev/null +++ b/drivers/misc/awinic/aw8624/Android.mk @@ -0,0 +1,12 @@ +DLKM_DIR := motorola/kernel/modules +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := aw8624.ko +LOCAL_MODULE_TAGS := optional +ifeq ($(DLKM_INSTALL_TO_VENDOR_OUT),true) +LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/modules/ +else +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +endif +include $(DLKM_DIR)/AndroidKernelModule.mk diff --git a/drivers/misc/awinic/aw8624/Kbuild b/drivers/misc/awinic/aw8624/Kbuild new file mode 100644 index 000000000000..8cf9a56f32f5 --- /dev/null +++ b/drivers/misc/awinic/aw8624/Kbuild @@ -0,0 +1,5 @@ +# add -Wall to try to catch everything we can. +EXTRA_CFLAGS += -Wall +EXTRA_CFLAGS += -I$(TOP)/motorola/kernel/modules/include + +obj-m += aw8624.o diff --git a/drivers/misc/awinic/aw8624/Makefile b/drivers/misc/awinic/aw8624/Makefile new file mode 100644 index 000000000000..62a13fd28500 --- /dev/null +++ b/drivers/misc/awinic/aw8624/Makefile @@ -0,0 +1,11 @@ +KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build + +all: + $(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS) + +modules_install: + $(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install + +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean + diff --git a/drivers/misc/awinic/aw8624/aw8624.c b/drivers/misc/awinic/aw8624/aw8624.c new file mode 100644 index 000000000000..0931727e8617 --- /dev/null +++ b/drivers/misc/awinic/aw8624/aw8624.c @@ -0,0 +1,2792 @@ +/* + * aw8624.c aw8624 haptic module + * + * Version: v1.0.0 + * + * Copyright (c) 2018 AWINIC Technology CO., LTD + * + * Author: Joseph + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "aw8624.h" +#include "aw8624_reg.h" + +/****************************************************** + * + * Marco + * + ******************************************************/ +#define AW8624_I2C_NAME "aw8624_haptic" +#define AW8624_HAPTIC_NAME "aw8624_haptic" +#define AW8624_VERSION "v1.0.0" +#define AWINIC_RAM_UPDATE_DELAY +#define AW_I2C_RETRIES 2 +#define AW_I2C_RETRY_DELAY 2 +#define AW_READ_CHIPID_RETRIES 3 +#define AW_READ_CHIPID_RETRY_DELAY 2 +#define AW8624_MAX_DSP_START_TRY_COUNT 10 +#define AW8624_MAX_FIRMWARE_LOAD_CNT 20 + +/****************************************************** + * + * variable + * + ******************************************************/ +static char *aw8624_ram_name = "aw8624_haptic.bin"; + +#define AW8624_RTP_NAME_MAX 64 +static char aw8624_rtp_name[][AW8624_RTP_NAME_MAX] = { + {"aw8624_rtp.bin"}, + {"aw8624_rtp_lighthouse.bin"}, + {"aw8624_rtp_silk.bin"}, +}; +struct aw8624_container *aw8624_rtp; +struct aw8624 *g_aw8624; + +/****************************************************** + * + * functions + * + ******************************************************/ +static void aw8624_interrupt_clear(struct aw8624 *aw8624); + +/****************************************************** +* +* aw8624 i2c write/read +* +******************************************************/ +static int aw8624_i2c_write(struct aw8624 *aw8624, + 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(aw8624->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 aw8624_i2c_read(struct aw8624 *aw8624, + 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(aw8624->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 aw8624_i2c_write_bits(struct aw8624 *aw8624, + unsigned char reg_addr, unsigned int mask, unsigned char reg_data) +{ + unsigned char reg_val = 0; + + aw8624_i2c_read(aw8624, reg_addr, ®_val); + reg_val &= mask; + reg_val |= reg_data; + aw8624_i2c_write(aw8624, reg_addr, reg_val); + + return 0; +} + + +static int aw8624_i2c_writes(struct aw8624 *aw8624, + 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(aw8624->i2c, data, len + 1); + if (ret < 0) { + pr_err("%s: i2c master send error\n", __func__); + } + + kfree(data); + + return ret; +} + + +static void aw8624_interrupt_clear(struct aw8624 *aw8624) +{ + unsigned char reg_val = 0; + aw8624_i2c_read(aw8624, AW8624_REG_SYSINT, ®_val); + pr_info("%s: reg SYSINT=0x%x\n", __func__, reg_val); +} +/***************************************************** + * + * ram update + * + *****************************************************/ + +static void aw8624_rtp_loaded(const struct firmware *cont, void *context) +{ + struct aw8624 *aw8624 = context; + + if (!cont) { + pr_err("%s: failed to read %s\n", __func__, aw8624_rtp_name[aw8624->rtp_file_num]); + release_firmware(cont); + return; + } + + pr_info("%s: loaded %s - size: %zu\n", __func__, aw8624_rtp_name[aw8624->rtp_file_num], + cont ? cont->size : 0); + + /* aw8624 rtp update */ + aw8624_rtp = kzalloc(cont->size + sizeof(int), GFP_KERNEL); + if (!aw8624_rtp) { + release_firmware(cont); + pr_err("%s: Error allocating memory\n", __func__); + return; + } + aw8624_rtp->len = cont->size; + pr_info("%s: rtp size = %d\n", __func__, aw8624_rtp->len); + memcpy(aw8624_rtp->data, cont->data, cont->size); + release_firmware(cont); + + aw8624->rtp_init = 1; + pr_info("%s: rtp update complete\n", __func__); +} + +static int aw8624_rtp_update(struct aw8624 *aw8624) +{ + pr_info("%s enter\n", __func__); + + return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + aw8624_rtp_name[aw8624->rtp_file_num], aw8624->dev, GFP_KERNEL, + aw8624, aw8624_rtp_loaded); +} + + +static void aw8624_container_update(struct aw8624 *aw8624, + struct aw8624_container *aw8624_cont) +{ + int i = 0; + unsigned int shift = 0; + + mutex_lock(&aw8624->lock); + + aw8624->ram.baseaddr_shift = 2; + aw8624->ram.ram_shift = 4; + + /* RAMINIT Enable */ + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_RAMINIT_MASK, AW8624_BIT_SYSCTRL_RAMINIT_EN); + + /* base addr */ + shift = aw8624->ram.baseaddr_shift; + aw8624->ram.base_addr = (unsigned int)((aw8624_cont->data[0 + shift] << 8) | + (aw8624_cont->data[1 + shift])); + pr_info("%s: base_addr=0x%4x\n", __func__, aw8624->ram.base_addr); + + aw8624_i2c_write(aw8624, AW8624_REG_BASE_ADDRH, aw8624_cont->data[0 + shift]); + aw8624_i2c_write(aw8624, AW8624_REG_BASE_ADDRL, aw8624_cont->data[1 + shift]); + + aw8624_i2c_write(aw8624, AW8624_REG_FIFO_AEH, + (unsigned char)((aw8624->ram.base_addr >> 2) >> 8)); + aw8624_i2c_write(aw8624, AW8624_REG_FIFO_AEL, + (unsigned char)((aw8624->ram.base_addr >> 2) & 0x00FF)); + aw8624_i2c_write(aw8624, AW8624_REG_FIFO_AFH, + (unsigned char)((aw8624->ram.base_addr - (aw8624->ram.base_addr >> 2)) >> 8)); + aw8624_i2c_write(aw8624, AW8624_REG_FIFO_AFL, + (unsigned char)((aw8624->ram.base_addr - (aw8624->ram.base_addr >> 2)) & 0x00FF)); + + /* ram */ + shift = aw8624->ram.baseaddr_shift; + aw8624_i2c_write(aw8624, AW8624_REG_RAMADDRH, aw8624_cont->data[0 + shift]); + aw8624_i2c_write(aw8624, AW8624_REG_RAMADDRL, aw8624_cont->data[1 + shift]); + shift = aw8624->ram.ram_shift; + for (i = shift; i < aw8624_cont->len; i++) { + aw8624_i2c_write(aw8624, AW8624_REG_RAMDATA, aw8624_cont->data[i]); + } + + /* RAMINIT Disable */ + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_RAMINIT_MASK, AW8624_BIT_SYSCTRL_RAMINIT_OFF); + + mutex_unlock(&aw8624->lock); + + pr_info("%s exit\n", __func__); +} + + +static void aw8624_ram_loaded(const struct firmware *cont, void *context) +{ + struct aw8624 *aw8624 = context; + struct aw8624_container *aw8624_fw; + int i = 0; + unsigned short check_sum = 0; + + if (!cont) { + pr_err("%s: failed to read %s\n", __func__, aw8624_ram_name); + release_firmware(cont); + return; + } + + pr_info("%s: loaded %s - size: %zu\n", __func__, aw8624_ram_name, + cont ? cont->size : 0); + + /* check sum */ + for (i = 2; i < cont->size; i++) { + check_sum += cont->data[i]; + } + if (check_sum != (unsigned short)((cont->data[0] << 8) | (cont->data[1]))) { + 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); + aw8624->ram.check_sum = check_sum; + } + + /* aw8624 ram update */ + aw8624_fw = kzalloc(cont->size + sizeof(int), GFP_KERNEL); + if (!aw8624_fw) { + release_firmware(cont); + pr_err("%s: Error allocating memory\n", __func__); + return; + } + aw8624_fw->len = cont->size; + memcpy(aw8624_fw->data, cont->data, cont->size); + release_firmware(cont); + + aw8624_container_update(aw8624, aw8624_fw); + + aw8624->ram.len = aw8624_fw->len; + + kfree(aw8624_fw); + + aw8624->ram_init = 1; + pr_info("%s: fw update complete\n", __func__); + + if (aw8624->IsUsedIRQ) + aw8624_rtp_update(aw8624); + +} + +static int aw8624_ram_update(struct aw8624 *aw8624) +{ + aw8624->ram_init = 0; + aw8624->rtp_init = 0; + return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + aw8624_ram_name, aw8624->dev, GFP_KERNEL, + aw8624, aw8624_ram_loaded); +} + +static void aw8624_ram_work_routine(struct work_struct *work) +{ + struct aw8624 *aw8624 = container_of(work, struct aw8624, ram_work.work); + pr_err("%s \n", __func__); + aw8624_ram_update(aw8624); +} + +static int aw8624_ram_init(struct aw8624 *aw8624) +{ + if (aw8624->ram_update_delay) { + INIT_DELAYED_WORK(&aw8624->ram_work, aw8624_ram_work_routine); + schedule_delayed_work(&aw8624->ram_work, msecs_to_jiffies(5000)); + } else { + aw8624_ram_update(aw8624); + } + return 0; +} + +/***************************************************** + * + * haptic control + * + *****************************************************/ +static int aw8624_haptic_softreset(struct aw8624 *aw8624) +{ + aw8624_i2c_write(aw8624, AW8624_REG_ID, 0xAA); + msleep(1); + return 0; +} + +static int aw8624_haptic_active(struct aw8624 *aw8624) +{ + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_WORK_MODE_MASK, AW8624_BIT_SYSCTRL_ACTIVE); + aw8624_interrupt_clear(aw8624); + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSINTM, + AW8624_BIT_SYSINTM_UVLO_MASK, AW8624_BIT_SYSINTM_UVLO_EN); + return 0; +} + +static int aw8624_haptic_play_mode(struct aw8624 *aw8624, unsigned char play_mode) +{ + switch (play_mode) { + case AW8624_HAPTIC_STANDBY_MODE: + aw8624->play_mode = AW8624_HAPTIC_STANDBY_MODE; + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_WORK_MODE_MASK, AW8624_BIT_SYSCTRL_STANDBY); + break; + case AW8624_HAPTIC_RAM_MODE: + aw8624->play_mode = AW8624_HAPTIC_RAM_MODE; + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_PLAY_MODE_MASK, AW8624_BIT_SYSCTRL_PLAY_MODE_RAM); + break; + case AW8624_HAPTIC_RAM_LOOP_MODE: + aw8624->play_mode = AW8624_HAPTIC_RAM_LOOP_MODE; + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_PLAY_MODE_MASK, AW8624_BIT_SYSCTRL_PLAY_MODE_RAM); + break; + case AW8624_HAPTIC_RTP_MODE: + aw8624->play_mode = AW8624_HAPTIC_RTP_MODE; + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_PLAY_MODE_MASK, AW8624_BIT_SYSCTRL_PLAY_MODE_RTP); + break; + case AW8624_HAPTIC_TRIG_MODE: + aw8624->play_mode = AW8624_HAPTIC_TRIG_MODE; + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_PLAY_MODE_MASK, AW8624_BIT_SYSCTRL_PLAY_MODE_RAM); + break; + case AW8624_HAPTIC_CONT_MODE: + aw8624->play_mode = AW8624_HAPTIC_CONT_MODE; + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_PLAY_MODE_MASK, AW8624_BIT_SYSCTRL_PLAY_MODE_CONT); + break; + default: + dev_err(aw8624->dev, "%s: play mode %d err", + __func__, play_mode); + break; + } + return 0; +} + + + +static int aw8624_haptic_play_go(struct aw8624 *aw8624, bool flag) +{ + if (flag == true) { + aw8624_i2c_write_bits(aw8624, AW8624_REG_GO, + AW8624_BIT_GO_MASK, AW8624_BIT_GO_ENABLE); + } else { + aw8624_i2c_write_bits(aw8624, AW8624_REG_GO, + AW8624_BIT_GO_MASK, AW8624_BIT_GO_DISABLE); + } + return 0; +} + +static int aw8624_haptic_stop_delay(struct aw8624 *aw8624) +{ + unsigned char reg_val = 0; + unsigned int cnt = 100; + + while (cnt--) { + aw8624_i2c_read(aw8624, AW8624_REG_GLB_STATE, ®_val); + 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 aw8624_haptic_stop(struct aw8624 *aw8624) +{ + aw8624_haptic_play_go(aw8624, false); + aw8624_haptic_stop_delay(aw8624); + aw8624_haptic_play_mode(aw8624, AW8624_HAPTIC_STANDBY_MODE); + + return 0; +} + +static int aw8624_haptic_start(struct aw8624 *aw8624) +{ + aw8624_haptic_active(aw8624); + aw8624_haptic_play_go(aw8624, true); + + return 0; +} + +static int aw8624_haptic_set_wav_seq(struct aw8624 *aw8624, + unsigned char wav, unsigned char seq) +{ + aw8624_i2c_write(aw8624, AW8624_REG_WAVSEQ1 + wav, seq); + return 0; +} + +static int aw8624_haptic_set_wav_loop(struct aw8624 *aw8624, + unsigned char wav, unsigned char loop) +{ + unsigned char tmp = 0; + + if (wav % 2) { + tmp = loop << 0; + aw8624_i2c_write_bits(aw8624, AW8624_REG_WAVLOOP1 + (wav / 2), + AW8624_BIT_WAVLOOP_SEQNP1_MASK, tmp); + } else { + tmp = loop << 4; + aw8624_i2c_write_bits(aw8624, AW8624_REG_WAVLOOP1 + (wav / 2), + AW8624_BIT_WAVLOOP_SEQN_MASK, tmp); + } + + return 0; +} + +static int aw8624_haptic_set_repeat_wav_seq(struct aw8624 *aw8624, unsigned char seq) +{ + aw8624_haptic_set_wav_seq(aw8624, 0x00, seq); + aw8624_haptic_set_wav_loop(aw8624, 0x00, AW8624_BIT_WAVLOOP_INIFINITELY); + + return 0; +} + +static int aw8624_haptic_set_gain(struct aw8624 *aw8624, unsigned char gain) +{ + aw8624_i2c_write(aw8624, AW8624_REG_DATDBG, gain); + return 0; +} + +static int aw8624_haptic_set_pwm(struct aw8624 *aw8624, unsigned char mode) +{ + switch (mode) { + case AW8624_PWM_48K: + aw8624_i2c_write_bits(aw8624, AW8624_REG_PWMDBG, + AW8624_BIT_PWMDBG_PWM_MODE_MASK, AW8624_BIT_PWMDBG_PWM_48K); + break; + case AW8624_PWM_24K: + aw8624_i2c_write_bits(aw8624, AW8624_REG_PWMDBG, + AW8624_BIT_PWMDBG_PWM_MODE_MASK, AW8624_BIT_PWMDBG_PWM_24K); + break; + case AW8624_PWM_12K: + aw8624_i2c_write_bits(aw8624, AW8624_REG_PWMDBG, + AW8624_BIT_PWMDBG_PWM_MODE_MASK, AW8624_BIT_PWMDBG_PWM_12K); + break; + default: + break; + } + return 0; +} + +static int aw8624_haptic_play_repeat_seq(struct aw8624 *aw8624, unsigned char flag) +{ + if (flag) { + aw8624_haptic_play_mode(aw8624, AW8624_HAPTIC_RAM_LOOP_MODE); + aw8624_haptic_start(aw8624); + } + + return 0; +} + +static int aw8624_haptic_swicth_motorprotect_config(struct aw8624 *aw8624, unsigned char addr , unsigned char val) +{ + if (addr == 1) { + aw8624_i2c_write_bits(aw8624, AW8624_REG_DETCTRL, + AW8624_BIT_DETCTRL_PROTECT_MASK, AW8624_BIT_DETCTRL_PROTECT_SHUTDOWN); + aw8624_i2c_write_bits(aw8624, AW8624_REG_PWMPRC, + AW8624_BIT_PWMPRC_PRC_EN_MASK, AW8624_BIT_PWMPRC_PRC_ENABLE); + aw8624_i2c_write_bits(aw8624, AW8624_REG_PRLVL, + AW8624_BIT_PRLVL_PR_EN_MASK, AW8624_BIT_PRLVL_PR_ENABLE); + } else if (addr == 0) { + aw8624_i2c_write_bits(aw8624, AW8624_REG_DETCTRL, + AW8624_BIT_DETCTRL_PROTECT_MASK, AW8624_BIT_DETCTRL_PROTECT_NO_ACTION); + aw8624_i2c_write_bits(aw8624, AW8624_REG_PWMPRC, + AW8624_BIT_PWMPRC_PRC_EN_MASK, AW8624_BIT_PWMPRC_PRC_DISABLE); + aw8624_i2c_write_bits(aw8624, AW8624_REG_PRLVL, + AW8624_BIT_PRLVL_PR_EN_MASK, AW8624_BIT_PRLVL_PR_DISABLE); + } else if (addr == 0x2d) { + aw8624_i2c_write_bits(aw8624, AW8624_REG_PWMPRC, + AW8624_BIT_PWMPRC_PRCTIME_MASK, val); + } else if (addr == 0x3e) { + aw8624_i2c_write_bits(aw8624, AW8624_REG_PRLVL, + AW8624_BIT_PRLVL_PRLVL_MASK, val); + } else if (addr == 0x3f) { + aw8624_i2c_write_bits(aw8624, AW8624_REG_PRTIME, + AW8624_BIT_PRTIME_PRTIME_MASK, val); + } else { + /*nothing to do;*/ + } + + return 0; +} + +static int aw8624_haptic_trig1_config(struct aw8624 *aw8624, unsigned char flag) +{ + if (flag) { + aw8624_i2c_write_bits(aw8624, AW8624_REG_DBGCTRL, + AW8624_BIT_DBGCTRL_INTN_TRG_SEL_MASK , AW8624_BIT_DBGCTRL_TRG_SEL_ENABLE); + aw8624_i2c_write_bits(aw8624, AW8624_REG_TRG_CFG2, + AW8624_BIT_TRGCFG2_TRG1_ENABLE_MASK, AW8624_BIT_TRGCFG2_TRG1_ENABLE); + } else { + aw8624_i2c_write_bits(aw8624, AW8624_REG_DBGCTRL, + AW8624_BIT_DBGCTRL_INTN_TRG_SEL_MASK , AW8624_BIT_DBGCTRL_TRG_SEL_ENABLE); + aw8624_i2c_write_bits(aw8624, AW8624_REG_TRG_CFG2, + AW8624_BIT_TRGCFG2_TRG1_ENABLE_MASK, AW8624_BIT_TRGCFG2_TRG1_DISABLE); + } + return 0; +} + +static int aw8624_haptic_vbat_mode(struct aw8624 *aw8624, unsigned char flag) +{ + if (flag == AW8624_HAPTIC_VBAT_HW_COMP_MODE) { + aw8624_i2c_write_bits(aw8624, AW8624_REG_ADCTEST, + AW8624_BIT_DETCTRL_VBAT_MODE_MASK, AW8624_BIT_DETCTRL_VBAT_HW_COMP); + } else { + aw8624_i2c_write_bits(aw8624, AW8624_REG_ADCTEST, + AW8624_BIT_DETCTRL_VBAT_MODE_MASK, AW8624_BIT_DETCTRL_VBAT_SW_COMP); + } + return 0; +} + +static int aw8624_haptic_set_f0_preset(struct aw8624 *aw8624) +{ + unsigned int f0_reg = 0; + + f0_reg = 1000000000 / (aw8624->f0_pre * AW8624_HAPTIC_F0_COEFF); + aw8624_i2c_write(aw8624, AW8624_REG_F_PRE_H, (unsigned char)((f0_reg >> 8) & 0xff)); + aw8624_i2c_write(aw8624, AW8624_REG_F_PRE_L, (unsigned char)((f0_reg >> 0) & 0xff)); + + return 0; +} + +static int aw8624_haptic_read_f0(struct aw8624 *aw8624) +{ + int ret = 0; + unsigned char reg_val = 0; + unsigned int f0_reg = 0; + unsigned long f0_tmp = 0; + + ret = aw8624_i2c_read(aw8624, AW8624_REG_F_LRA_F0_H, ®_val); + f0_reg = (reg_val << 8); + ret = aw8624_i2c_read(aw8624, AW8624_REG_F_LRA_F0_L, ®_val); + f0_reg |= (reg_val << 0); + f0_tmp = 1000000000 / (f0_reg * AW8624_HAPTIC_F0_COEFF); + aw8624->f0 = (unsigned int)f0_tmp; + pr_info("%s f0=%d\n", __func__, aw8624->f0); + return 0; +} + +static int aw8624_haptic_read_cont_f0(struct aw8624 *aw8624) +{ + int ret = 0; + unsigned char reg_val = 0; + unsigned int f0_reg = 0; + unsigned long f0_tmp = 0; + + ret = aw8624_i2c_read(aw8624, AW8624_REG_F_LRA_CONT_H, ®_val); + f0_reg = (reg_val << 8); + ret = aw8624_i2c_read(aw8624, AW8624_REG_F_LRA_CONT_L, ®_val); + f0_reg |= (reg_val << 0); + f0_tmp = 1000000000 / (f0_reg * AW8624_HAPTIC_F0_COEFF); + aw8624->cont_f0 = (unsigned int)f0_tmp; + pr_info("%s cont_f0=%d\n", __func__, aw8624->cont_f0); + return 0; +} + +static int aw8624_haptic_read_beme(struct aw8624 *aw8624) +{ + int ret = 0; + unsigned char reg_val = 0; + + ret = aw8624_i2c_read(aw8624, AW8624_REG_WAIT_VOL_MP, ®_val); + aw8624->max_pos_beme = (reg_val << 0); + ret = aw8624_i2c_read(aw8624, AW8624_REG_WAIT_VOL_MN, ®_val); + aw8624->max_neg_beme = (reg_val << 0); + + pr_info("%s max_pos_beme=%d\n", __func__, aw8624->max_pos_beme); + pr_info("%s max_neg_beme=%d\n", __func__, aw8624->max_neg_beme); + + return 0; +} + +static int aw8624_haptic_brake_config(struct aw8624 *aw8624) +{ + unsigned char brake0_level = 0; + unsigned char en_brake1 = 0; + unsigned char brake1_level = 0; + unsigned char en_brake2 = 0; + unsigned char brake2_level = 0; + unsigned char brake2_p_num = 0; + unsigned char brake1_p_num = 0; + unsigned char brake0_p_num = 0; + + if (aw8624->duration < 30) { + brake0_level = 80; + en_brake1 = 1; + brake1_level = 60; + en_brake2 = 1; + brake2_level = 30; + brake0_p_num = 5; + brake1_p_num = 1; + brake2_p_num = 1; + } else { + brake0_level = 90; + en_brake1 = 1; + brake1_level = 60; + en_brake2 = 1; + brake2_level = 30; + brake0_p_num = 5; + brake1_p_num = 5; + brake2_p_num = 3; + } + + aw8624_i2c_write(aw8624, AW8624_REG_BRAKE0_CTRL, (brake0_level << 0)); + aw8624_i2c_write(aw8624, AW8624_REG_BRAKE1_CTRL, (en_brake1 << 7) | (brake1_level << 0)); + aw8624_i2c_write(aw8624, AW8624_REG_BRAKE2_CTRL, (en_brake2 << 7) | (brake2_level << 0)); + aw8624_i2c_write(aw8624, AW8624_REG_BRAKE_NUM, ((brake2_p_num << 6) | (brake1_p_num << 3) | (brake0_p_num << 0))); + + return 0; +} +static void aw8624_haptic_set_rtp_aei(struct aw8624 *aw8624, bool flag) +{ + if (flag) { + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSINTM, + AW8624_BIT_SYSINTM_FF_AE_MASK, AW8624_BIT_SYSINTM_FF_AE_EN); + } else { + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSINTM, + AW8624_BIT_SYSINTM_FF_AE_MASK, AW8624_BIT_SYSINTM_FF_AE_OFF); + } +} + +static unsigned char aw8624_haptic_rtp_get_fifo_afi(struct aw8624 *aw8624) +{ + unsigned char ret = 0; + unsigned char reg_val = 0; + + aw8624_i2c_read(aw8624, AW8624_REG_SYSINT, ®_val); + reg_val &= AW8624_BIT_SYSINT_FF_AFI; + ret = reg_val >> 3; + + return ret; +} + +static int aw8624_haptic_rtp_init(struct aw8624 *aw8624) +{ + unsigned int buf_len = 0; + + aw8624->rtp_cnt = 0; + + while ((!aw8624_haptic_rtp_get_fifo_afi(aw8624)) && + (aw8624->play_mode == AW8624_HAPTIC_RTP_MODE)) { + pr_info("%s rtp cnt = %d\n", __func__, aw8624->rtp_cnt); + if ((aw8624_rtp->len - aw8624->rtp_cnt) < (aw8624->ram.base_addr >> 3)) { + buf_len = aw8624_rtp->len - aw8624->rtp_cnt; + } else { + buf_len = (aw8624->ram.base_addr >> 3); + } + aw8624_i2c_writes(aw8624, AW8624_REG_RTP_DATA, + &aw8624_rtp->data[aw8624->rtp_cnt], buf_len); + aw8624->rtp_cnt += buf_len; + if (aw8624->rtp_cnt == aw8624_rtp->len) { + pr_info("%s: rtp update complete\n", __func__); + aw8624->rtp_cnt = 0; + return 0; + } + } + + if (aw8624->play_mode == AW8624_HAPTIC_RTP_MODE) { + aw8624_haptic_set_rtp_aei(aw8624, true); + } + + pr_info("%s exit\n", __func__); + + return 0; +} + +static void aw8624_rtp_work_routine(struct work_struct *work) +{ + const struct firmware *rtp_file; + int ret = -1; + struct aw8624 *aw8624 = container_of(work, struct aw8624, rtp_work); + + /* fw loaded */ + ret = request_firmware(&rtp_file, + aw8624_rtp_name[aw8624->rtp_file_num], aw8624->dev); + if (ret < 0) { + pr_err("%s: failed to read %s\n", __func__, + aw8624_rtp_name[aw8624->rtp_file_num]); + return ; + } + aw8624->rtp_init = 0; + kfree(aw8624_rtp); + aw8624_rtp = kzalloc(rtp_file->size + sizeof(int), GFP_KERNEL); + if (!aw8624_rtp) { + release_firmware(rtp_file); + pr_err("%s: error allocating memory\n", __func__); + return; + } + aw8624_rtp->len = rtp_file->size; + pr_info("%s: rtp file [%s] size = %d\n", __func__, + aw8624_rtp_name[aw8624->rtp_file_num], aw8624_rtp->len); + memcpy(aw8624_rtp->data, rtp_file->data, rtp_file->size); + release_firmware(rtp_file); + + aw8624->rtp_init = 1; + + aw8624_i2c_write_bits(aw8624, AW8624_REG_DBGCTRL, + AW8624_BIT_DBGCTRL_INTN_TRG_SEL_MASK, AW8624_BIT_DBGCTRL_INTN_SEL_ENABLE); + + /* rtp mode config */ + aw8624_haptic_play_mode(aw8624, AW8624_HAPTIC_RTP_MODE); + + /* haptic start */ + aw8624_haptic_start(aw8624); + aw8624_haptic_rtp_init(aw8624); +} + +/***************************************************** + * + * haptic - audio + * + *****************************************************/ +static enum hrtimer_restart aw8624_haptic_audio_timer_func(struct hrtimer *timer) +{ + struct aw8624 *aw8624 = container_of(timer, struct aw8624, haptic_audio.timer); + schedule_work(&aw8624->haptic_audio.work); + + hrtimer_start(&aw8624->haptic_audio.timer, + ktime_set(aw8624->haptic_audio.timer_val / 1000, + (aw8624->haptic_audio.timer_val % 1000) * 1000000), + HRTIMER_MODE_REL); + return HRTIMER_NORESTART; +} + +static void aw8624_haptic_audio_work_routine(struct work_struct *work) +{ + struct aw8624 *aw8624 = container_of(work, struct aw8624, haptic_audio.work); + + mutex_lock(&aw8624->haptic_audio.lock); + if (aw8624->haptic_audio.ctr[aw8624->haptic_audio.cnt].cmd == 0x01) { + if (aw8624->haptic_audio.ctr[aw8624->haptic_audio.cnt].play == 0x01) { + pr_info("%s: haptic audio play start\n", __func__); + mutex_lock(&aw8624->lock); + aw8624_haptic_stop(aw8624); + + aw8624_haptic_play_mode(aw8624, AW8624_HAPTIC_RAM_MODE); + + aw8624_haptic_set_wav_seq(aw8624, 0x00, + aw8624->haptic_audio.ctr[aw8624->haptic_audio.cnt].wavseq); + aw8624_haptic_set_wav_seq(aw8624, 0x01, 0x00); + + aw8624_haptic_set_wav_loop(aw8624, 0x00, + aw8624->haptic_audio.ctr[aw8624->haptic_audio.cnt].loop); + + aw8624_haptic_set_gain(aw8624, + aw8624->haptic_audio.ctr[aw8624->haptic_audio.cnt].gain); + + aw8624_haptic_start(aw8624); + mutex_unlock(&aw8624->lock); + } + aw8624->haptic_audio.ctr[aw8624->haptic_audio.cnt].cmd = 0; + } + + aw8624->haptic_audio.cnt ++; + if (aw8624->haptic_audio.ctr[aw8624->haptic_audio.cnt].cmd == 0) { + aw8624->haptic_audio.cnt = 0; + pr_debug("%s: haptic play buffer restart\n", __func__); + } + mutex_unlock(&aw8624->haptic_audio.lock); + +} + + + +/***************************************************** + * + * haptic cont + * + *****************************************************/ +static int aw8624_haptic_cont(struct aw8624 *aw8624) +{ + unsigned char brake0_level = 0; + unsigned char en_brake1 = 0; + unsigned char brake1_level = 0; + unsigned char en_brake2 = 0; + unsigned char brake2_level = 0; + unsigned char brake2_p_num = 0; + unsigned char brake1_p_num = 0; + unsigned char brake0_p_num = 0; + + /* work mode */ + aw8624_haptic_active(aw8624); + aw8624_haptic_play_mode(aw8624, AW8624_HAPTIC_CONT_MODE); + + /* preset f0 */ + aw8624->f0_pre = aw8624->f0; + aw8624_haptic_set_f0_preset(aw8624); + + /* lpf */ + aw8624_i2c_write_bits(aw8624, AW8624_REG_DATCTRL, + AW8624_BIT_DATCTRL_FC_MASK, AW8624_BIT_DATCTRL_FC_1000HZ); + aw8624_i2c_write_bits(aw8624, AW8624_REG_DATCTRL, + AW8624_BIT_DATCTRL_LPF_ENABLE_MASK, AW8624_BIT_DATCTRL_LPF_ENABLE); + + /*brake*/ + brake0_level = 0x5A; + en_brake1 = 1; + brake1_level = 0x2A; + en_brake2 = 1; + brake2_level = 0x14; + brake2_p_num = 0x03; + brake1_p_num = 0x03; + brake0_p_num = 0x06; + aw8624_i2c_write(aw8624, AW8624_REG_BRAKE0_CTRL, (brake0_level << 0)); + aw8624_i2c_write(aw8624, AW8624_REG_BRAKE1_CTRL, (en_brake1 << 7) | (brake1_level << 0)); + aw8624_i2c_write(aw8624, AW8624_REG_BRAKE2_CTRL, (en_brake2 << 7) | (brake2_level << 0)); + aw8624_i2c_write(aw8624, AW8624_REG_BRAKE_NUM, ((brake2_p_num << 6) | (brake1_p_num << 3) | (brake0_p_num << 0))); + + /* cont config */ + aw8624_i2c_write_bits(aw8624, AW8624_REG_CONT_CTRL, + AW8624_BIT_CONT_CTRL_ZC_DETEC_MASK, AW8624_BIT_CONT_CTRL_ZC_DETEC_ENABLE); + aw8624_i2c_write_bits(aw8624, AW8624_REG_CONT_CTRL, + AW8624_BIT_CONT_CTRL_WAIT_PERIOD_MASK, AW8624_BIT_CONT_CTRL_WAIT_1PERIOD); + + aw8624_i2c_write_bits(aw8624, AW8624_REG_CONT_CTRL, + AW8624_BIT_CONT_CTRL_MODE_MASK, AW8624_BIT_CONT_CTRL_BY_GO_SIGNAL); + + aw8624_i2c_write_bits(aw8624, AW8624_REG_CONT_CTRL, + AW8624_BIT_CONT_CTRL_EN_CLOSE_MASK, AW8624_BIT_CONT_CTRL_CLOSE_PLAYBACK); + aw8624_i2c_write_bits(aw8624, AW8624_REG_CONT_CTRL, + AW8624_BIT_CONT_CTRL_F0_DETECT_MASK, AW8624_BIT_CONT_CTRL_F0_DETECT_DISABLE); + aw8624_i2c_write_bits(aw8624, AW8624_REG_CONT_CTRL, + AW8624_BIT_CONT_CTRL_O2C_MASK, AW8624_BIT_CONT_CTRL_O2C_DISABLE); + + /* TD time */ + aw8624_i2c_write(aw8624, AW8624_REG_TD_H, (unsigned char)(aw8624->cont_td >> 8)); + aw8624_i2c_write(aw8624, AW8624_REG_TD_L, (unsigned char)(aw8624->cont_td >> 0)); + aw8624_i2c_write(aw8624, AW8624_REG_TSET, 0x12); + + /* zero cross */ + aw8624_i2c_write(aw8624, AW8624_REG_ZC_THRSH_H, (unsigned char)(aw8624->cont_zc_thr >> 8)); + aw8624_i2c_write(aw8624, AW8624_REG_ZC_THRSH_L, (unsigned char)(aw8624->cont_zc_thr >> 0)); + + /* bemf */ + aw8624_i2c_write(aw8624, AW8624_REG_BEMF_VTHH_H, 0x10); + aw8624_i2c_write(aw8624, AW8624_REG_BEMF_VTHH_L, 0x08); + aw8624_i2c_write(aw8624, AW8624_REG_BEMF_VTHL_H, 0x13); + aw8624_i2c_write(aw8624, AW8624_REG_BEMF_VTHL_L, 0xF8); + aw8624_i2c_write_bits(aw8624, AW8624_REG_BEMF_NUM, AW8624_BIT_BEMF_NUM_BRK_MASK, aw8624->cont_num_brk); + aw8624_i2c_write(aw8624, AW8624_REG_TIME_NZC, 0x1f); + + /* f0 driver level */ + aw8624_i2c_write(aw8624, AW8624_REG_DRV_LVL, aw8624->cont_drv_lvl); + aw8624_i2c_write(aw8624, AW8624_REG_DRV_LVL_OV, aw8624->cont_drv_lvl_ov); + + /* cont play go */ + aw8624_haptic_play_go(aw8624, true); + + return 0; +} + +/***************************************************** + * + * haptic f0 cali + * + *****************************************************/ +static int aw8624_haptic_get_f0(struct aw8624 *aw8624) +{ + 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__); + + aw8624->f0 = aw8624->f0_pre; + /* f0 calibrate work mode */ + aw8624_haptic_stop(aw8624); + aw8624_haptic_play_mode(aw8624, AW8624_HAPTIC_CONT_MODE); + + + aw8624_i2c_write_bits(aw8624, AW8624_REG_CONT_CTRL, + AW8624_BIT_CONT_CTRL_EN_CLOSE_MASK, AW8624_BIT_CONT_CTRL_OPEN_PLAYBACK); + aw8624_i2c_write_bits(aw8624, AW8624_REG_CONT_CTRL, + AW8624_BIT_CONT_CTRL_F0_DETECT_MASK, AW8624_BIT_CONT_CTRL_F0_DETECT_ENABLE); + + /* LPF */ + aw8624_i2c_write_bits(aw8624, AW8624_REG_DATCTRL, + AW8624_BIT_DATCTRL_FC_MASK, AW8624_BIT_DATCTRL_FC_1000HZ); + aw8624_i2c_write_bits(aw8624, AW8624_REG_DATCTRL, + AW8624_BIT_DATCTRL_LPF_ENABLE_MASK, AW8624_BIT_DATCTRL_LPF_ENABLE); + + /* LRA OSC Source */ + if (aw8624->f0_cali_flag == AW8624_HAPTIC_CALI_F0) { + aw8624_i2c_write_bits(aw8624, AW8624_REG_ANACTRL, + AW8624_BIT_ANACTRL_LRA_SRC_MASK, AW8624_BIT_ANACTRL_LRA_SRC_REG); + } else { + aw8624_i2c_write_bits(aw8624, AW8624_REG_ANACTRL, + AW8624_BIT_ANACTRL_LRA_SRC_MASK, AW8624_BIT_ANACTRL_LRA_SRC_EFUSE); + } + + /* preset f0 */ + aw8624_haptic_set_f0_preset(aw8624); + /* beme config */ + aw8624_i2c_write(aw8624, AW8624_REG_BEMF_VTHH_H, 0x10); + aw8624_i2c_write(aw8624, AW8624_REG_BEMF_VTHH_L, 0x08); + aw8624_i2c_write(aw8624, AW8624_REG_BEMF_VTHL_H, 0x03); + aw8624_i2c_write(aw8624, AW8624_REG_BEMF_VTHL_L, 0xf8); + /* f0 driver level */ + aw8624_i2c_write(aw8624, AW8624_REG_DRV_LVL, aw8624->cont_drv_lvl); + /* f0 trace parameter */ + f0_pre_num = 0x05; + f0_wait_num = 0x03; + f0_repeat_num = 0x01; + f0_trace_num = 0x0f; + aw8624_i2c_write(aw8624, AW8624_REG_NUM_F0_1, (f0_pre_num << 4) | (f0_wait_num << 0)); + aw8624_i2c_write(aw8624, AW8624_REG_NUM_F0_2, (f0_repeat_num << 0)); + aw8624_i2c_write(aw8624, AW8624_REG_NUM_F0_3, (f0_trace_num << 0)); + + /* clear aw8624 interrupt */ + ret = aw8624_i2c_read(aw8624, AW8624_REG_SYSINT, ®_val); + + /* play go and start f0 calibration */ + aw8624_haptic_play_go(aw8624, true); + + /* f0 trace time */ + t_f0_ms = 1000 * 10 / aw8624->f0_pre; + t_f0_trace_ms = t_f0_ms * (f0_pre_num + f0_wait_num + (f0_trace_num + f0_wait_num) * f0_repeat_num); + msleep(t_f0_trace_ms); + + for (i = 0; i < f0_cali_cnt; i++) { + ret = aw8624_i2c_read(aw8624, AW8624_REG_SYSINT, ®_val); + /* f0 calibrate done */ + if (reg_val & 0x01) { + aw8624_haptic_read_f0(aw8624); + aw8624_haptic_read_beme(aw8624); + break; + } + msleep(10); + pr_info("%s f0 cali sleep 10ms\n", __func__); + } + + if (i == f0_cali_cnt) { + ret = -1; + } else { + ret = 0; + } + /* restore default work mode */ + aw8624_i2c_write_bits(aw8624, AW8624_REG_CONT_CTRL, + AW8624_BIT_CONT_CTRL_EN_CLOSE_MASK, AW8624_BIT_CONT_CTRL_CLOSE_PLAYBACK); + aw8624_i2c_write_bits(aw8624, AW8624_REG_CONT_CTRL, + AW8624_BIT_CONT_CTRL_F0_DETECT_MASK, AW8624_BIT_CONT_CTRL_F0_DETECT_DISABLE); + + return ret; +} + +static int aw8624_haptic_f0_calibration(struct aw8624 *aw8624) +{ + int ret = 0; + unsigned char reg_val = 0; + unsigned int f0_limit = 0; + char f0_cali_lra = 0; + int f0_cali_step = 0; + int f0_dft_step = 0; + + aw8624->f0_cali_flag = AW8624_HAPTIC_CALI_F0; + + if (aw8624_haptic_get_f0(aw8624)) { + pr_err("%s get f0 error, user defafult f0\n", __func__); + } else { + /* max and min limit */ + f0_limit = aw8624->f0; + if (aw8624->f0 * 100 < AW8624_HAPTIC_F0_PRE * (100 - AW8624_HAPTIC_F0_CALI_PERCEN)) { + f0_limit = AW8624_HAPTIC_F0_PRE * (100 - AW8624_HAPTIC_F0_CALI_PERCEN) / 100; + } + if (aw8624->f0 * 100 > AW8624_HAPTIC_F0_PRE * (100 + AW8624_HAPTIC_F0_CALI_PERCEN)) { + f0_limit = AW8624_HAPTIC_F0_PRE * (100 + AW8624_HAPTIC_F0_CALI_PERCEN) / 100; + } + /* calculate cali step */ + f0_cali_step = 10000 * ((int)f0_limit - (int)aw8624->f0_pre) / ((int)aw8624->f0_pre * 24); + pr_info("%s f0_cali_step=%d\n", __func__, f0_cali_step); + + /* get default cali step */ + aw8624_i2c_read(aw8624, AW8624_REG_TRIM_LRA, ®_val); + if (reg_val & 0x10) { + reg_val &= 0xef; + } else { + reg_val |= 0x10;; + } + f0_dft_step = reg_val; + pr_info("%s f0_dft_step=%d\n", __func__, f0_dft_step); + + /* get new cali step */ + f0_cali_step += f0_dft_step; + pr_info("%s f0_cali_step=%d\n", __func__, f0_cali_step); + + if (f0_cali_step > 63) { + f0_cali_step = 63; + } else if (f0_cali_step < 0) { + f0_cali_step = 0; + } + f0_cali_lra = (char)f0_cali_step; + pr_info("%s f0_cali_lra=%d\n", __func__, f0_cali_lra); + + /* get cali step code*/ + if (f0_cali_lra & 0x10) { + f0_cali_lra &= 0xef; + } else { + f0_cali_lra |= 0x10; + } + pr_info("%s reg f0_cali_lra=%d\n", __func__, f0_cali_lra); + + /* update cali step */ + aw8624_i2c_write(aw8624, AW8624_REG_TRIM_LRA, (char)f0_cali_lra); + aw8624_i2c_read(aw8624, AW8624_REG_TRIM_LRA, ®_val); + pr_info("%s final trim_lra=0x%02x\n", __func__, reg_val); + } + + aw8624_haptic_play_mode(aw8624, AW8624_HAPTIC_STANDBY_MODE); + aw8624_haptic_play_mode(aw8624, AW8624_HAPTIC_RAM_MODE); + aw8624_haptic_stop(aw8624); + + return ret; +} + +/***************************************************** + * + * haptic fops + * + *****************************************************/ +static int aw8624_file_open(struct inode *inode, struct file *file) +{ + if (!try_module_get(THIS_MODULE)) + return -ENODEV; + + file->private_data = (void *)g_aw8624; + + return 0; +} + +static int aw8624_file_release(struct inode *inode, struct file *file) +{ + file->private_data = (void *)NULL; + + module_put(THIS_MODULE); + + return 0; +} + +static long aw8624_file_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct aw8624 *aw8624 = (struct aw8624 *)file->private_data; + + int ret = 0; + + dev_info(aw8624->dev, "%s: cmd=0x%x, arg=0x%lx\n", + __func__, cmd, arg); + + mutex_lock(&aw8624->lock); + + if (_IOC_TYPE(cmd) != AW8624_HAPTIC_IOCTL_MAGIC) { + dev_err(aw8624->dev, "%s: cmd magic err\n", + __func__); + return -EINVAL; + } + + switch (cmd) { + default: + dev_err(aw8624->dev, "%s, unknown cmd\n", __func__); + break; + } + + mutex_unlock(&aw8624->lock); + + return ret; +} + +static ssize_t aw8624_file_read(struct file *filp, char *buff, size_t len, loff_t *offset) +{ + struct aw8624 *aw8624 = (struct aw8624 *)filp->private_data; + int ret = 0; + int i = 0; + unsigned char reg_val = 0; + unsigned char *pbuff = NULL; + + mutex_lock(&aw8624->lock); + + dev_info(aw8624->dev, "%s: len=%zu\n", __func__, len); + + switch (aw8624->fileops.cmd) { + case AW8624_HAPTIC_CMD_READ_REG: + pbuff = (unsigned char *)kzalloc(len, GFP_KERNEL); + if (pbuff != NULL) { + for (i = 0; i < len; i++) { + aw8624_i2c_read(aw8624, aw8624->fileops.reg + i, ®_val); + pbuff[i] = reg_val; + } + ret = copy_to_user(buff, pbuff, len); + if (ret) { + dev_err(aw8624->dev, "%s: copy to user fail\n", __func__); + } + kfree(pbuff); + } else { + dev_err(aw8624->dev, "%s: alloc memory fail\n", __func__); + } + break; + default: + dev_err(aw8624->dev, "%s, unknown cmd %d \n", __func__, aw8624->fileops.cmd); + break; + } + + mutex_unlock(&aw8624->lock); + + for (i = 0; i < len; i++) { + dev_info(aw8624->dev, "%s: buff[%d]=0x%02x\n", + __func__, i, buff[i]); + } + + return len; +} + +static ssize_t aw8624_file_write(struct file *filp, const char *buff, size_t len, loff_t *off) +{ + struct aw8624 *aw8624 = (struct aw8624 *)filp->private_data; + int i = 0; + int ret = 0; + unsigned char *pbuff = NULL; + + + mutex_lock(&aw8624->lock); + + aw8624->fileops.cmd = buff[0]; + + switch (aw8624->fileops.cmd) { + case AW8624_HAPTIC_CMD_READ_REG: + if (len == 2) { + aw8624->fileops.reg = buff[1]; + } else { + dev_err(aw8624->dev, "%s: read cmd len %zu err\n", __func__, len); + } + break; + case AW8624_HAPTIC_CMD_WRITE_REG: + if (len > 2) { + pbuff = (unsigned char *)kzalloc(len, GFP_KERNEL); + if (pbuff != NULL) { + ret = copy_from_user(pbuff, buff, len); + if (ret) { + dev_err(aw8624->dev, "%s: copy from user fail\n", __func__); + } else { + for (i = 0; i < len - 2; i++) { + dev_info(aw8624->dev, "%s: write reg0x%02x=0x%02x\n", + __func__, pbuff[1] + i, pbuff[i + 2]); + aw8624_i2c_write(aw8624, pbuff[1] + i, pbuff[2 + i]); + } + } + kfree(pbuff); + } else { + dev_err(aw8624->dev, "%s: alloc memory fail\n", __func__); + } + } else { + dev_err(aw8624->dev, "%s: write cmd len %zu err\n", __func__, len); + } + break; + default: + dev_err(aw8624->dev, "%s, unknown cmd %d \n", __func__, aw8624->fileops.cmd); + break; + } + + mutex_unlock(&aw8624->lock); + + return len; +} + +static struct file_operations fops = { + .owner = THIS_MODULE, + .read = aw8624_file_read, + .write = aw8624_file_write, + .unlocked_ioctl = aw8624_file_unlocked_ioctl, + .open = aw8624_file_open, + .release = aw8624_file_release, +}; + +static struct miscdevice aw8624_haptic_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = AW8624_HAPTIC_NAME, + .fops = &fops, +}; + +static int aw8624_haptic_init(struct aw8624 *aw8624) +{ + int ret = 0; + unsigned char i = 0; + unsigned char reg_val = 0; + unsigned char brake0_level = 0; + unsigned char en_brake1 = 0; + unsigned char brake1_level = 0; + unsigned char en_brake2 = 0; + unsigned char brake2_level = 0; + unsigned char brake2_p_num = 0; + unsigned char brake1_p_num = 0; + unsigned char brake0_p_num = 0; + + ret = misc_register(&aw8624_haptic_misc); + if (ret) { + dev_err(aw8624->dev, "%s: misc fail: %d\n", __func__, ret); + return ret; + } + + /* haptic audio */ + aw8624->haptic_audio.delay_val = 23; + aw8624->haptic_audio.timer_val = 23; + + hrtimer_init(&aw8624->haptic_audio.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + aw8624->haptic_audio.timer.function = aw8624_haptic_audio_timer_func; + INIT_WORK(&aw8624->haptic_audio.work, aw8624_haptic_audio_work_routine); + + mutex_init(&aw8624->haptic_audio.lock); + + /* haptic init */ + mutex_lock(&aw8624->lock); + aw8624->activate_mode = AW8624_HAPTIC_ACTIVATE_RAM_MODE; + ret = aw8624_i2c_read(aw8624, AW8624_REG_WAVSEQ1, ®_val); + aw8624->index = reg_val & 0x7F; + ret = aw8624_i2c_read(aw8624, AW8624_REG_DATDBG, ®_val); + aw8624->gain = reg_val & 0xFF; + for (i = 0; i < AW8624_SEQUENCER_SIZE; i++) { + ret = aw8624_i2c_read(aw8624, AW8624_REG_WAVSEQ1 + i, ®_val); + aw8624->seq[i] = reg_val; + } + + aw8624_haptic_play_mode(aw8624, AW8624_HAPTIC_STANDBY_MODE); + aw8624_haptic_set_pwm(aw8624, AW8624_PWM_24K); + aw8624_haptic_set_wav_seq(aw8624, 0x00, 0x02); + aw8624_haptic_set_wav_seq(aw8624, 0x01, 0x01); + aw8624_haptic_set_wav_loop(aw8624, 0x00, 0x02); + aw8624_haptic_set_wav_loop(aw8624, 0x01, 0x0f); + aw8624_haptic_swicth_motorprotect_config(aw8624, 0x0 , 0x0); + aw8624_haptic_vbat_mode(aw8624, AW8624_HAPTIC_VBAT_HW_COMP_MODE); + mutex_unlock(&aw8624->lock); + + /* f0 calibration */ + aw8624->f0_pre = AW8624_HAPTIC_F0_PRE; + aw8624->cont_drv_lvl = AW8624_HAPTIC_CONT_DRV_LVL; + aw8624->cont_drv_lvl_ov = AW8624_HAPTIC_CONT_DRV_LVL_OV; + aw8624->cont_td = AW8624_HAPTIC_CONT_TD; + aw8624->cont_zc_thr = AW8624_HAPTIC_CONT_ZC_THR; + aw8624->cont_num_brk = AW8624_HAPTIC_CONT_NUM_BRK; + mutex_lock(&aw8624->lock); + aw8624_haptic_f0_calibration(aw8624); + mutex_unlock(&aw8624->lock); + + /*brake*/ + mutex_lock(&aw8624->lock); + aw8624_i2c_write(aw8624, AW8624_REG_SW_BRAKE, 0x0c); + brake0_level = 0x64; + en_brake1 = 1; + brake1_level = 0x46; + en_brake2 = 1; + brake2_level = 0x1e; + brake2_p_num = 0x03; + brake1_p_num = 0x05; + brake0_p_num = 0x07; + aw8624_i2c_write(aw8624, AW8624_REG_BRAKE0_CTRL, (brake0_level << 0)); + aw8624_i2c_write(aw8624, AW8624_REG_BRAKE1_CTRL, (en_brake1 << 7) | (brake1_level << 0)); + aw8624_i2c_write(aw8624, AW8624_REG_BRAKE2_CTRL, (en_brake2 << 7) | (brake2_level << 0)); + aw8624_i2c_write(aw8624, AW8624_REG_BRAKE_NUM, ((brake2_p_num << 6) | (brake1_p_num << 3) | (brake0_p_num << 0))); + aw8624_i2c_write(aw8624, AW8624_REG_THRS_BRA_END, 0x00); + aw8624_i2c_write_bits(aw8624, AW8624_REG_WAVECTRL, + AW8624_BIT_WAVECTRL_NUM_OV_DRIVER_MASK, AW8624_BIT_WAVECTRL_NUM_OV_DRIVER); + mutex_unlock(&aw8624->lock); + + return ret; +} + + + +/***************************************************** + * + * vibrator + * + *****************************************************/ +static void aw8624_vibrator_enable(struct led_classdev *dev, enum led_brightness value) +{ + struct aw8624 *aw8624 = container_of(dev, struct aw8624, to_dev); + + pr_info("%s: time value = %d\n", __FUNCTION__, value); + + mutex_lock(&aw8624->lock); + hrtimer_cancel(&aw8624->timer); + + aw8624->state = value; + aw8624_haptic_stop(aw8624); + if (aw8624->state) { + /* run ms timer */ + hrtimer_start(&aw8624->timer, + ktime_set(value / 1000, (value % 1000) * 1000000), + HRTIMER_MODE_REL); + } + + mutex_unlock(&aw8624->lock); + + schedule_work(&aw8624->vibrator_work); +} + +static ssize_t aw8624_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", aw8624->state); +} + +static ssize_t aw8624_state_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return count; +} + +static ssize_t aw8624_duration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + ktime_t time_rem; + s64 time_ms = 0; + + if (hrtimer_active(&aw8624->timer)) { + time_rem = hrtimer_get_remaining(&aw8624->timer); + time_ms = ktime_to_ms(time_rem); + } + + return snprintf(buf, PAGE_SIZE, "%lld\n", time_ms); +} + +static ssize_t aw8624_duration_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + 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; + + if (val < 20) { + val = 20; + } + aw8624->duration = val; + return count; +} + +static ssize_t aw8624_activate_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + /* For now nothing to show */ + return snprintf(buf, PAGE_SIZE, "%d\n", aw8624->state); +} + +static ssize_t aw8624_activate_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + 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(&aw8624->lock); + hrtimer_cancel(&aw8624->timer); + + aw8624->state = val; + + if (aw8624->state) { + /* clip value to max */ + val = aw8624->duration; + /* run ms timer */ + hrtimer_start(&aw8624->timer, + ktime_set(val / 1000, (val % 1000) * 1000000), + HRTIMER_MODE_REL); + } + mutex_unlock(&aw8624->lock); + schedule_work(&aw8624->vibrator_work); + + return count; +} + +static ssize_t aw8624_activate_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + + return snprintf(buf, PAGE_SIZE, "activate_mode=%d\n", aw8624->activate_mode); +} + +static ssize_t aw8624_activate_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + mutex_lock(&aw8624->lock); + aw8624->activate_mode = val; + mutex_unlock(&aw8624->lock); + return count; +} + + +static ssize_t aw8624_index_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + unsigned char reg_val = 0; + aw8624_i2c_read(aw8624, AW8624_REG_WAVSEQ1, ®_val); + aw8624->index = reg_val; + + return snprintf(buf, PAGE_SIZE, "%d\n", aw8624->index); +} + +static ssize_t aw8624_index_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + pr_info("%s: value=%d\n", __FUNCTION__, val); + + mutex_lock(&aw8624->lock); + aw8624->index = val; + aw8624_haptic_set_repeat_wav_seq(aw8624, aw8624->index); + mutex_unlock(&aw8624->lock); + return count; +} + + +static ssize_t aw8624_gain_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw8624->gain); +} + +static ssize_t aw8624_gain_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + pr_info("%s: value=%d\n", __FUNCTION__, val); + + mutex_lock(&aw8624->lock); + aw8624->gain = val; + aw8624_haptic_set_gain(aw8624, aw8624->gain); + mutex_unlock(&aw8624->lock); + return count; +} + +static ssize_t aw8624_seq_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + size_t count = 0; + unsigned char i = 0; + unsigned char reg_val = 0; + + for (i = 0; i < AW8624_SEQUENCER_SIZE; i++) { + aw8624_i2c_read(aw8624, AW8624_REG_WAVSEQ1 + i, ®_val); + count += snprintf(buf + count, PAGE_SIZE - count, + "seq%d: 0x%02x\n", i + 1, reg_val); + aw8624->seq[i] |= reg_val; + } + return count; +} + +static ssize_t aw8624_seq_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + unsigned int databuf[2] = {0, 0}; + + if (2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) { + printk("%s: seq%d=0x%x\n", __FUNCTION__, databuf[0], databuf[1]); + mutex_lock(&aw8624->lock); + aw8624->seq[databuf[0]] = (unsigned char)databuf[1]; + aw8624_haptic_set_wav_seq(aw8624, (unsigned char)databuf[0], + aw8624->seq[databuf[0]]); + mutex_unlock(&aw8624->lock); + } + return count; +} + +static ssize_t aw8624_loop_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + size_t count = 0; + unsigned char i = 0; + unsigned char reg_val = 0; + + for (i = 0; i < AW8624_SEQUENCER_LOOP_SIZE; i++) { + aw8624_i2c_read(aw8624, AW8624_REG_WAVLOOP1 + i, ®_val); + aw8624->loop[i * 2 + 0] = (reg_val >> 4) & 0x0F; + aw8624->loop[i * 2 + 1] = (reg_val >> 0) & 0x0F; + + count += snprintf(buf + count, PAGE_SIZE - count, + "seq%d loop: 0x%02x\n", i * 2 + 1, aw8624->loop[i * 2 + 0]); + count += snprintf(buf + count, PAGE_SIZE - count, + "seq%d loop: 0x%02x\n", i * 2 + 2, aw8624->loop[i * 2 + 1]); + } + return count; +} + +static ssize_t aw8624_loop_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + unsigned int databuf[2] = {0, 0}; + + if (2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) { + pr_info("%s: seq%d loop=0x%x\n", __FUNCTION__, databuf[0], databuf[1]); + mutex_lock(&aw8624->lock); + aw8624->loop[databuf[0]] = (unsigned char)databuf[1]; + aw8624_haptic_set_wav_loop(aw8624, (unsigned char)databuf[0], + aw8624->loop[databuf[0]]); + mutex_unlock(&aw8624->lock); + } + + return count; +} + +static ssize_t aw8624_reg_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + ssize_t len = 0; + unsigned char i = 0; + unsigned char reg_val = 0; + for (i = 0; i < AW8624_REG_MAX; i ++) { + if (!(aw8624_reg_access[i]®_RD_ACCESS)) + continue; + aw8624_i2c_read(aw8624, i, ®_val); + len += snprintf(buf + len, PAGE_SIZE - len, "reg:0x%02x=0x%02x \n", i, reg_val); + } + return len; +} + +static ssize_t aw8624_reg_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + unsigned int databuf[2] = {0, 0}; + + if (2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) { + aw8624_i2c_write(aw8624, (unsigned char)databuf[0], (unsigned char)databuf[1]); + } + + return count; +} + + +static ssize_t aw8624_rtp_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + ssize_t len = 0; + len += snprintf(buf + len, PAGE_SIZE - len, "rtp play: %d\n", aw8624->rtp_cnt); + + return len; +} + +static ssize_t aw8624_rtp_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + unsigned int val = 0; + int rc = 0; + + if (!(aw8624->IsUsedIRQ)) + return rc; + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + aw8624_haptic_stop(aw8624); + aw8624_haptic_set_rtp_aei(aw8624, false); + aw8624_interrupt_clear(aw8624); + if (val < (sizeof(aw8624_rtp_name) / AW8624_RTP_NAME_MAX)) { + aw8624->rtp_file_num = val; + if (val) { + schedule_work(&aw8624->rtp_work); + } + } else { + pr_err("%s: rtp_file_num 0x%02x over max value \n", __func__, aw8624->rtp_file_num); + } + + return count; +} + + +static ssize_t aw8624_ram_update_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + ssize_t len = 0; + len += snprintf(buf + len, PAGE_SIZE - len, "sram update mode\n"); + return len; +} + +static ssize_t aw8624_ram_update_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + if (val) { + aw8624_ram_update(aw8624); + } + return count; +} + +static ssize_t aw8624_f0_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + ssize_t len = 0; + + mutex_lock(&aw8624->lock); + aw8624->f0_cali_flag = AW8624_HAPTIC_LRA_F0; + aw8624_haptic_get_f0(aw8624); + mutex_unlock(&aw8624->lock); + len += snprintf(buf + len, PAGE_SIZE - len, "aw8624 lra f0 = %d\n", aw8624->f0); + return len; +} + +static ssize_t aw8624_f0_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + return count; +} + + +static ssize_t aw8624_cali_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + ssize_t len = 0; + mutex_lock(&aw8624->lock); + aw8624->f0_cali_flag = AW8624_HAPTIC_CALI_F0; + aw8624_haptic_get_f0(aw8624); + mutex_unlock(&aw8624->lock); + len += snprintf(buf + len, PAGE_SIZE - len, "aw8624 f0 = %d\n", aw8624->f0); + return len; +} + +static ssize_t aw8624_cali_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + if (val) { + mutex_lock(&aw8624->lock); + aw8624_haptic_f0_calibration(aw8624); + mutex_unlock(&aw8624->lock); + } + return count; +} + +static ssize_t aw8624_cont_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + ssize_t len = 0; + aw8624_haptic_read_cont_f0(aw8624); + len += snprintf(buf + len, PAGE_SIZE - len, "aw8624 f0 = %d\n", aw8624->f0); + return len; +} + +static ssize_t aw8624_cont_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + aw8624_haptic_stop(aw8624); + if (val) { + aw8624_haptic_cont(aw8624); + } + return count; +} + + +static ssize_t aw8624_cont_td_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + ssize_t len = 0; + len += snprintf(buf + len, PAGE_SIZE - len, "aw8624 cont delay time = 0x%04x\n", aw8624->cont_td); + return len; +} + +static ssize_t aw8624_cont_td_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + unsigned int databuf[1] = {0}; + if (1 == sscanf(buf, "%x", &databuf[0])) { + aw8624->cont_td = databuf[0]; + aw8624_i2c_write(aw8624, AW8624_REG_TD_H, (unsigned char)(databuf[0] >> 8)); + aw8624_i2c_write(aw8624, AW8624_REG_TD_L, (unsigned char)(databuf[0] >> 0)); + } + return count; +} + +static ssize_t aw8624_cont_drv_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + ssize_t len = 0; + len += snprintf(buf + len, PAGE_SIZE - len, "aw8624 cont drv level = 0x%02x\n", aw8624->cont_drv_lvl); + len += snprintf(buf + len, PAGE_SIZE - len, "aw8624 cont drv level overdrive= 0x%02x\n", aw8624->cont_drv_lvl_ov); + return len; +} + +static ssize_t aw8624_cont_drv_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + unsigned int databuf[2] = {0, 0}; + if (2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) { + aw8624->cont_drv_lvl = databuf[0]; + aw8624_i2c_write(aw8624, AW8624_REG_DRV_LVL, aw8624->cont_drv_lvl); + aw8624->cont_drv_lvl_ov = databuf[1]; + aw8624_i2c_write(aw8624, AW8624_REG_DRV_LVL_OV, aw8624->cont_drv_lvl_ov); + } + return count; +} + +static ssize_t aw8624_cont_num_brk_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + ssize_t len = 0; + len += snprintf(buf + len, PAGE_SIZE - len, "aw8624 cont break num = 0x%02x\n", aw8624->cont_num_brk); + return len; +} + +static ssize_t aw8624_cont_num_brk_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + unsigned int databuf[1] = {0}; + if (1 == sscanf(buf, "%d", &databuf[0])) { + aw8624->cont_num_brk = databuf[0]; + if (aw8624->cont_num_brk > 7) { + aw8624->cont_num_brk = 7; + } + aw8624_i2c_write_bits(aw8624, AW8624_REG_BEMF_NUM, + AW8624_BIT_BEMF_NUM_BRK_MASK, aw8624->cont_num_brk); + } + return count; +} + +static ssize_t aw8624_cont_zc_thr_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + ssize_t len = 0; + len += snprintf(buf + len, PAGE_SIZE - len, "aw8624 cont zero cross thr = 0x%04x\n", aw8624->cont_zc_thr); + return len; +} + +static ssize_t aw8624_cont_zc_thr_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + unsigned int databuf[1] = {0}; + if (1 == sscanf(buf, "%x", &databuf[0])) { + aw8624->cont_zc_thr = databuf[0]; + aw8624_i2c_write(aw8624, AW8624_REG_ZC_THRSH_H, (unsigned char)(databuf[0] >> 8)); + aw8624_i2c_write(aw8624, AW8624_REG_ZC_THRSH_L, (unsigned char)(databuf[0] >> 0)); + } + return count; +} + +static ssize_t aw8624_vbat_monitor_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + ssize_t len = 0; + + unsigned char reg_val = 0; + unsigned char reg_val_sysctrl = 0; + unsigned char reg_val_detctrl = 0; + unsigned int vbat = 0; + + mutex_lock(&aw8624->lock); + aw8624_haptic_stop(aw8624); + aw8624_i2c_read(aw8624, AW8624_REG_SYSCTRL, ®_val_sysctrl); + aw8624_i2c_read(aw8624, AW8624_REG_DETCTRL, ®_val_detctrl); + /*step 1:EN_RAMINIT*/ + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_RAMINIT_MASK, AW8624_BIT_SYSCTRL_RAMINIT_EN); + + /*step 2 :launch offset cali */ + aw8624_i2c_write_bits(aw8624, AW8624_REG_DETCTRL, + AW8624_BIT_DETCTRL_DIAG_GO_MASK, AW8624_BIT_DETCTRL_DIAG_GO_ENABLE); + /*step 3 :delay */ + msleep(2); + + /*step 4 :launch power supply testing */ + aw8624_i2c_write_bits(aw8624, AW8624_REG_DETCTRL, + AW8624_BIT_DETCTRL_VBAT_GO_MASK, AW8624_BIT_DETCTRL_VABT_GO_ENABLE); + msleep(2); + + aw8624_i2c_read(aw8624, AW8624_REG_VBATDET, ®_val); + vbat = 6100 * reg_val / 256; + + len += snprintf(buf + len, PAGE_SIZE - len, "vbat=%dmV\n", vbat); + + /*step 5: return val*/ + aw8624_i2c_write(aw8624, AW8624_REG_SYSCTRL, reg_val_sysctrl); + mutex_unlock(&aw8624->lock); + + return len; +} + +static ssize_t aw8624_vbat_monitor_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + return count; +} + +static ssize_t aw8624_lra_resistance_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + ssize_t len = 0; + unsigned char reg_val = 0; + unsigned char reg_val_sysctrl = 0; + unsigned char reg_val_anactrl = 0; + unsigned char reg_val_d2scfg = 0; + unsigned int r_lra = 0; + + mutex_lock(&aw8624->lock); + aw8624_i2c_read(aw8624, AW8624_REG_SYSCTRL, ®_val_anactrl); + aw8624_i2c_read(aw8624, AW8624_REG_ANACTRL, ®_val_sysctrl); + aw8624_i2c_read(aw8624, AW8624_REG_D2SCFG, ®_val_d2scfg); + aw8624_haptic_stop(aw8624); + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_RAMINIT_MASK, AW8624_BIT_SYSCTRL_RAMINIT_EN); + + + aw8624_i2c_write_bits(aw8624, AW8624_REG_ANACTRL, + AW8624_BIT_ANACTRL_EN_IO_PD1_MASK, AW8624_BIT_ANACTRL_EN_IO_PD1_HIGH); + + aw8624_i2c_write_bits(aw8624, AW8624_REG_D2SCFG, + AW8624_BIT_D2SCFG_CLK_ADC_MASK, AW8624_BIT_D2SCFG_CLK_ASC_1P5MHZ); + + aw8624_i2c_write_bits(aw8624, AW8624_REG_DETCTRL, + AW8624_BIT_DETCTRL_RL_OS_MASK, AW8624_BIT_DETCTRL_RL_DETECT); + aw8624_i2c_write_bits(aw8624, AW8624_REG_DETCTRL, + AW8624_BIT_DETCTRL_DIAG_GO_MASK, AW8624_BIT_DETCTRL_DIAG_GO_ENABLE); + msleep(3); + aw8624_i2c_read(aw8624, AW8624_REG_RLDET, ®_val); + r_lra = 298 * reg_val; + len += snprintf(buf + len, PAGE_SIZE - len, "r_lra=%dmohm\n", r_lra); + + aw8624_i2c_write(aw8624, AW8624_REG_D2SCFG, reg_val_d2scfg); + aw8624_i2c_write(aw8624, AW8624_REG_ANACTRL, reg_val_anactrl); + aw8624_i2c_write(aw8624, AW8624_REG_SYSCTRL, reg_val_sysctrl); + + mutex_unlock(&aw8624->lock); + + return len; +} + + +static ssize_t aw8624_lra_resistance_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + return count; +} + +static ssize_t aw8624_trig_boost_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + ssize_t len = 0; + return len; +} +static ssize_t aw8624_trig_boost_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + unsigned int val = 0; + int rc = 0; + + if (!(aw8624->IsUsedIRQ)) + return rc; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + mutex_lock(&aw8624->lock); + aw8624_haptic_stop(aw8624); + aw8624_haptic_trig1_config(aw8624, val); + mutex_unlock(&aw8624->lock); + + return count; +} + +static ssize_t aw8624_prctmode_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + ssize_t len = 0; + unsigned char reg_val = 0; + + aw8624_i2c_read(aw8624, AW8624_REG_RLDET, ®_val); + + len += snprintf(buf + len, PAGE_SIZE - len, "prctmode=%d\n", reg_val & 0x20); + return len; +} + + +static ssize_t aw8624_prctmode_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + 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(&aw8624->lock); + aw8624_haptic_swicth_motorprotect_config(aw8624, addr, val); + mutex_unlock(&aw8624->lock); + } + return count; +} + + + +static ssize_t aw8624_haptic_audio_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + ssize_t len = 0; + len += snprintf(buf + len, PAGE_SIZE - len, "%d\n", aw8624->haptic_audio.cnt); + return len; +} + +static ssize_t aw8624_haptic_audio_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + 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(&aw8624->haptic_audio.lock); + aw8624->haptic_audio.cnt = (unsigned char)databuf[0]; + aw8624->haptic_audio.ctr[aw8624->haptic_audio.cnt].cmd = (unsigned char)databuf[1]; + aw8624->haptic_audio.ctr[aw8624->haptic_audio.cnt].play = (unsigned char)databuf[2]; + aw8624->haptic_audio.ctr[aw8624->haptic_audio.cnt].wavseq = (unsigned char)databuf[3]; + aw8624->haptic_audio.ctr[aw8624->haptic_audio.cnt].loop = (unsigned char)databuf[4]; + aw8624->haptic_audio.ctr[aw8624->haptic_audio.cnt].gain = (unsigned char)databuf[5]; + mutex_unlock(&aw8624->haptic_audio.lock); + + if (aw8624->haptic_audio.ctr[aw8624->haptic_audio.cnt].cmd == 0xff) { + pr_info("%s: haptic_audio stop\n", __func__); + if (hrtimer_active(&aw8624->haptic_audio.timer)) { + pr_info("%s: cancel haptic_audio_timer\n", __func__); + hrtimer_cancel(&aw8624->haptic_audio.timer); + aw8624->haptic_audio.cnt = 0; + } + } else { + if (hrtimer_active(&aw8624->haptic_audio.timer)) { + } else { + pr_info("%s: start haptic_audio_timer\n", __func__); + hrtimer_start(&aw8624->haptic_audio.timer, + ktime_set(aw8624->haptic_audio.delay_val / 1000, + (aw8624->haptic_audio.delay_val % 1000) * 1000000), + HRTIMER_MODE_REL); + } + } + } + return count; +} + +static ssize_t aw8624_haptic_audio_time_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + ssize_t len = 0; + len += snprintf(buf + len, PAGE_SIZE - len, "haptic_audio.delay_val=%dus\n", aw8624->haptic_audio.delay_val); + len += snprintf(buf + len, PAGE_SIZE - len, "haptic_audio.timer_val=%dus\n", aw8624->haptic_audio.timer_val); + return len; +} + +static ssize_t aw8624_haptic_audio_time_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + + struct led_classdev *to_dev = dev_get_drvdata(dev); + struct aw8624 *aw8624 = container_of(to_dev, struct aw8624, to_dev); + + unsigned int databuf[2] = {0}; + + if (2 == sscanf(buf, "%d %d", &databuf[0], &databuf[1])) { + aw8624->haptic_audio.delay_val = databuf[0]; + aw8624->haptic_audio.timer_val = databuf[1]; + } + return count; +} + +static DEVICE_ATTR(state, S_IWUSR | S_IRUGO, aw8624_state_show, aw8624_state_store); +static DEVICE_ATTR(duration, S_IWUSR | S_IRUGO, aw8624_duration_show, aw8624_duration_store); +static DEVICE_ATTR(activate, S_IWUSR | S_IRUGO, aw8624_activate_show, aw8624_activate_store); +static DEVICE_ATTR(activate_mode, S_IWUSR | S_IRUGO, aw8624_activate_mode_show, aw8624_activate_mode_store); +static DEVICE_ATTR(index, S_IWUSR | S_IRUGO, aw8624_index_show, aw8624_index_store); +static DEVICE_ATTR(gain, S_IWUSR | S_IRUGO, aw8624_gain_show, aw8624_gain_store); +static DEVICE_ATTR(seq, S_IWUSR | S_IRUGO, aw8624_seq_show, aw8624_seq_store); +static DEVICE_ATTR(loop, S_IWUSR | S_IRUGO, aw8624_loop_show, aw8624_loop_store); +static DEVICE_ATTR(register, S_IWUSR | S_IRUGO, aw8624_reg_show, aw8624_reg_store); +static DEVICE_ATTR(ram_update, S_IWUSR | S_IRUGO, aw8624_ram_update_show, aw8624_ram_update_store); +static DEVICE_ATTR(f0, S_IWUSR | S_IRUGO, aw8624_f0_show, aw8624_f0_store); +static DEVICE_ATTR(cali, S_IWUSR | S_IRUGO, aw8624_cali_show, aw8624_cali_store); +static DEVICE_ATTR(cont, S_IWUSR | S_IRUGO, aw8624_cont_show, aw8624_cont_store); +static DEVICE_ATTR(cont_td, S_IWUSR | S_IRUGO, aw8624_cont_td_show, aw8624_cont_td_store); +static DEVICE_ATTR(cont_drv, S_IWUSR | S_IRUGO, aw8624_cont_drv_show, aw8624_cont_drv_store); +static DEVICE_ATTR(cont_num_brk, S_IWUSR | S_IRUGO, aw8624_cont_num_brk_show, aw8624_cont_num_brk_store); +static DEVICE_ATTR(cont_zc_thr, S_IWUSR | S_IRUGO, aw8624_cont_zc_thr_show, aw8624_cont_zc_thr_store); +static DEVICE_ATTR(vbat_monitor, S_IWUSR | S_IRUGO, aw8624_vbat_monitor_show, aw8624_vbat_monitor_store); +static DEVICE_ATTR(lra_resistance, S_IWUSR | S_IRUGO, aw8624_lra_resistance_show, aw8624_lra_resistance_store); +static DEVICE_ATTR(prctmode, S_IWUSR | S_IRUGO, aw8624_prctmode_show, aw8624_prctmode_store); +static DEVICE_ATTR(haptic_audio, S_IWUSR | S_IRUGO, aw8624_haptic_audio_show, aw8624_haptic_audio_store); +static DEVICE_ATTR(haptic_audio_time, S_IWUSR | S_IRUGO, aw8624_haptic_audio_time_show, aw8624_haptic_audio_time_store); +static DEVICE_ATTR(trig_boost, S_IWUSR | S_IRUGO, aw8624_trig_boost_show, aw8624_trig_boost_store); +static DEVICE_ATTR(rtp, S_IWUSR | S_IRUGO, aw8624_rtp_show, aw8624_rtp_store); +static struct attribute *aw8624_vibrator_attributes[] = { + &dev_attr_state.attr, + &dev_attr_duration.attr, + &dev_attr_activate.attr, + &dev_attr_activate_mode.attr, + &dev_attr_index.attr, + &dev_attr_gain.attr, + &dev_attr_seq.attr, + &dev_attr_loop.attr, + &dev_attr_register.attr, + &dev_attr_ram_update.attr, + &dev_attr_f0.attr, + &dev_attr_cali.attr, + &dev_attr_cont.attr, + &dev_attr_cont_td.attr, + &dev_attr_cont_drv.attr, + &dev_attr_cont_num_brk.attr, + &dev_attr_cont_zc_thr.attr, + &dev_attr_vbat_monitor.attr, + &dev_attr_lra_resistance.attr, + &dev_attr_prctmode.attr, + &dev_attr_haptic_audio.attr, + &dev_attr_haptic_audio_time.attr, + &dev_attr_trig_boost.attr, + &dev_attr_rtp.attr, + NULL +}; + +static struct attribute_group aw8624_vibrator_attribute_group = { + .attrs = aw8624_vibrator_attributes +}; + +static enum hrtimer_restart aw8624_vibrator_timer_func(struct hrtimer *timer) +{ + struct aw8624 *aw8624 = container_of(timer, struct aw8624, timer); + + pr_info("%s enter\n", __func__); + aw8624->state = 0; + schedule_work(&aw8624->vibrator_work); + + return HRTIMER_NORESTART; +} + +static void aw8624_irq_work_routine(struct work_struct *work) +{ + struct aw8624 *aw8624 = container_of(work, struct aw8624, irq_work); + unsigned char reg_val = 0; + unsigned int buf_len = 0; + + aw8624_i2c_read(aw8624, AW8624_REG_SYSINT, ®_val); + + if (reg_val & AW8624_BIT_SYSINT_FF_AEI) { + if (aw8624->rtp_init) { + while ((!aw8624_haptic_rtp_get_fifo_afi(aw8624)) && + (aw8624->play_mode == AW8624_HAPTIC_RTP_MODE)) { + if ((aw8624_rtp->len - aw8624->rtp_cnt) < (aw8624->ram.base_addr >> 3)) { + buf_len = aw8624_rtp->len - aw8624->rtp_cnt; + } else { + buf_len = (aw8624->ram.base_addr >> 3); + } + aw8624_i2c_writes(aw8624, AW8624_REG_RTP_DATA, + &aw8624_rtp->data[aw8624->rtp_cnt], buf_len); + aw8624->rtp_cnt += buf_len; + if (aw8624->rtp_cnt == aw8624_rtp->len) { + aw8624_haptic_set_rtp_aei(aw8624, false); + aw8624->rtp_cnt = 0; + aw8624->rtp_init = 0; + break; + } + } + } + } + + if (aw8624->play_mode != AW8624_HAPTIC_RTP_MODE) { + aw8624_haptic_set_rtp_aei(aw8624, false); + } + + aw8624_i2c_read(aw8624, AW8624_REG_SYSINT, ®_val); + aw8624_i2c_read(aw8624, AW8624_REG_SYSST, ®_val); + +} + +static void aw8624_vibrator_work_routine(struct work_struct *work) +{ + struct aw8624 *aw8624 = container_of(work, struct aw8624, vibrator_work); + + pr_debug("%s enter\n", __func__); + + mutex_lock(&aw8624->lock); + aw8624_haptic_stop(aw8624); + if (aw8624->state) { + aw8624_haptic_brake_config(aw8624); + if (aw8624->activate_mode == AW8624_HAPTIC_ACTIVATE_RAM_MODE) { + aw8624_haptic_play_repeat_seq(aw8624, true); + } else if (aw8624->activate_mode == AW8624_HAPTIC_ACTIVATE_CONT_MODE) { + aw8624_haptic_cont(aw8624); + } else { + } + } + mutex_unlock(&aw8624->lock); +} + +static int aw8624_vibrator_init(struct aw8624 *aw8624) +{ + int ret = 0; + + printk("%s enter\n", __func__); + + aw8624->to_dev.name = "vibrator"; + + aw8624->to_dev.brightness_set = aw8624_vibrator_enable; + + ret = devm_led_classdev_register(&aw8624->i2c->dev, &(aw8624->to_dev)); + if (ret < 0) { + dev_err(aw8624->dev, "%s: fail to create leds dev\n", + __func__); + return ret; + } + ret = sysfs_create_group(&aw8624->to_dev.dev->kobj, &aw8624_vibrator_attribute_group); + if (ret < 0) { + dev_err(aw8624->dev, "%s error creating sysfs attr files\n", __func__); + return ret; + } + + hrtimer_init(&aw8624->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + aw8624->timer.function = aw8624_vibrator_timer_func; + INIT_WORK(&aw8624->vibrator_work, aw8624_vibrator_work_routine); + + if (aw8624->IsUsedIRQ) { + INIT_WORK(&aw8624->rtp_work, aw8624_rtp_work_routine); + INIT_WORK(&aw8624->irq_work, aw8624_irq_work_routine); + } + + mutex_init(&aw8624->lock); + + return 0; +} + + + + +/****************************************************** + * + * irq + * + ******************************************************/ + + +static void aw8624_interrupt_setup(struct aw8624 *aw8624) +{ + unsigned char reg_val = 0; + + aw8624_i2c_read(aw8624, AW8624_REG_SYSINT, ®_val); + pr_info("%s: reg SYSINT=0x%x\n", __func__, reg_val); + + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSINTM, + AW8624_BIT_SYSINTM_UVLO_MASK, AW8624_BIT_SYSINTM_UVLO_EN); + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSINTM, + AW8624_BIT_SYSINTM_OCD_MASK, AW8624_BIT_SYSINTM_OCD_EN); + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSINTM, + AW8624_BIT_SYSINTM_OT_MASK, AW8624_BIT_SYSINTM_OT_EN); +} + +static irqreturn_t aw8624_irq(int irq, void *data) +{ + struct aw8624 *aw8624 = (struct aw8624 *)data; + schedule_work(&aw8624->irq_work); + return IRQ_HANDLED; +} + +/***************************************************** + * + * device tree + * + *****************************************************/ +static int aw8624_parse_dt(struct device *dev, struct aw8624 *aw8624, + struct device_node *np) +{ + unsigned int val = 0; + aw8624->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); + if (aw8624->reset_gpio < 0) { + aw8624->reset_gpio = -1; + 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__); + } + + aw8624->irq_gpio = of_get_named_gpio(np, "irq-gpio", 0); + if (aw8624->irq_gpio < 0) { + dev_err(dev, "%s: no irq gpio provided.\n", __func__); + aw8624->IsUsedIRQ = false; + } else { + dev_info(dev, "%s: irq gpio provided ok.\n", __func__); + aw8624->IsUsedIRQ = true; + aw8624->irq_gpio = -1; + } + + aw8624->ram_update_delay = of_property_read_bool(np, "ram-update-delay"); + + val = of_property_read_u32(np, "real-i2c-addr", &aw8624->real_i2c_addr); + if (val) { + aw8624->dts_addr_real = false; + } else { + dev_info(dev, "find real-i2c-addr option in dts\n"); + aw8624->dts_addr_real = true; + } + return 0; +} + +static int aw8624_hw_reset(struct aw8624 *aw8624) +{ + pr_info("%s enter\n", __func__); + + if (aw8624 && gpio_is_valid(aw8624->reset_gpio)) { + gpio_set_value_cansleep(aw8624->reset_gpio, 0); + msleep(1); + gpio_set_value_cansleep(aw8624->reset_gpio, 1); + msleep(1); + } else { + dev_err(aw8624->dev, "%s: failed\n", __func__); + } + return 0; +} + + +/***************************************************** + * + * check chip id + * + *****************************************************/ +static int aw8624_read_chipid(struct aw8624 *aw8624) +{ + int ret = -1; + unsigned char cnt = 0; + unsigned char reg = 0; + + while (cnt < AW_READ_CHIPID_RETRIES) { + /* hardware reset */ + aw8624_hw_reset(aw8624); + + ret = aw8624_i2c_read(aw8624, AW8624_REG_ID, ®); + if (ret < 0) { + dev_err(aw8624->dev, "%s: failed to read register AW8624_REG_ID: %d\n", __func__, ret); + } + switch (reg) { + case 0x24: + pr_info("%s aw8624 detected\n", __func__); + aw8624->chipid = AW8624_ID; + aw8624_haptic_softreset(aw8624); + 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 aw8624_i2c_reg_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct aw8624 *aw8624 = dev_get_drvdata(dev); + + unsigned int databuf[2] = {0, 0}; + + if (2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) { + aw8624_i2c_write(aw8624, (unsigned char)databuf[0], (unsigned char)databuf[1]); + } + + return count; +} + +static ssize_t aw8624_i2c_reg_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct aw8624 *aw8624 = dev_get_drvdata(dev); + ssize_t len = 0; + unsigned char i = 0; + unsigned char reg_val = 0; + for (i = 0; i < AW8624_REG_MAX; i ++) { + if (!(aw8624_reg_access[i]®_RD_ACCESS)) + continue; + aw8624_i2c_read(aw8624, i, ®_val); + len += snprintf(buf + len, PAGE_SIZE - len, "reg:0x%02x=0x%02x \n", i, reg_val); + } + return len; +} +static ssize_t aw8624_i2c_ram_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct aw8624 *aw8624 = dev_get_drvdata(dev); + + unsigned int databuf[1] = {0}; + + if (1 == sscanf(buf, "%x", &databuf[0])) { + if (1 == databuf[0]) { + aw8624_ram_update(aw8624); + } + } + + return count; +} + +static ssize_t aw8624_i2c_ram_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct aw8624 *aw8624 = dev_get_drvdata(dev); + ssize_t len = 0; + unsigned int i = 0; + unsigned char reg_val = 0; + + aw8624_haptic_stop(aw8624); + /* RAMINIT Enable */ + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_RAMINIT_MASK, AW8624_BIT_SYSCTRL_RAMINIT_EN); + + aw8624_i2c_write(aw8624, AW8624_REG_RAMADDRH, (unsigned char)(aw8624->ram.base_addr >> 8)); + aw8624_i2c_write(aw8624, AW8624_REG_RAMADDRL, (unsigned char)(aw8624->ram.base_addr & 0x00ff)); + len += snprintf(buf + len, PAGE_SIZE - len, "aw8624_haptic_ram:\n"); + for (i = 0; i < aw8624->ram.len; i++) { + aw8624_i2c_read(aw8624, AW8624_REG_RAMDATA, ®_val); + len += snprintf(buf + len, PAGE_SIZE - len, "0x%02x,", reg_val); + } + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + /* RAMINIT Disable */ + aw8624_i2c_write_bits(aw8624, AW8624_REG_SYSCTRL, + AW8624_BIT_SYSCTRL_RAMINIT_MASK, AW8624_BIT_SYSCTRL_RAMINIT_OFF); + + return len; +} + +static DEVICE_ATTR(reg, S_IWUSR | S_IRUGO, aw8624_i2c_reg_show, aw8624_i2c_reg_store); +static DEVICE_ATTR(ram, S_IWUSR | S_IRUGO, aw8624_i2c_ram_show, aw8624_i2c_ram_store); + +static struct attribute *aw8624_attributes[] = { + &dev_attr_reg.attr, + &dev_attr_ram.attr, + NULL +}; + +static struct attribute_group aw8624_attribute_group = { + .attrs = aw8624_attributes +}; + + +/****************************************************** + * + * i2c driver + * + ******************************************************/ +static int aw8624_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +{ + struct aw8624 *aw8624; + struct device_node *np = i2c->dev.of_node; + int ret = -1; + + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) { + dev_err(&i2c->dev, "check_functionality failed\n"); + return -EIO; + } + + aw8624 = devm_kzalloc(&i2c->dev, sizeof(struct aw8624), GFP_KERNEL); + if (aw8624 == NULL) + return -ENOMEM; + + aw8624->dev = &i2c->dev; + aw8624->i2c = i2c; + + i2c_set_clientdata(i2c, aw8624); + + /* aw8624 rst & int */ + if (np) { + ret = aw8624_parse_dt(&i2c->dev, aw8624, np); + if (ret) { + dev_err(&i2c->dev, "%s: failed to parse device tree node\n", __func__); + goto err_parse_dt; + } + } + + if (aw8624->dts_addr_real) + i2c->addr = (u16)aw8624->real_i2c_addr; + + if (gpio_is_valid(aw8624->reset_gpio)) { + ret = devm_gpio_request_one(&i2c->dev, aw8624->reset_gpio, + GPIOF_OUT_INIT_LOW, "aw8624_rst"); + if (ret) { + dev_err(&i2c->dev, "%s: rst request failed\n", __func__); + goto err_parse_dt; + } + } + + if (gpio_is_valid(aw8624->irq_gpio)) { + ret = devm_gpio_request_one(&i2c->dev, aw8624->irq_gpio, + GPIOF_DIR_IN, "aw8624_int"); + if (ret) { + dev_err(&i2c->dev, "%s: int request failed\n", __func__); + goto err_parse_dt; + } + } + + /* aw8624 chip id */ + ret = aw8624_read_chipid(aw8624); + if (ret < 0) { + dev_err(&i2c->dev, "%s: aw8624_read_chipid failed ret=%d\n", __func__, ret); + goto err_id; + } + + /* aw8624 irq */ + if (gpio_is_valid(aw8624->irq_gpio)) { + /* register irq handler */ + aw8624_interrupt_setup(aw8624); + ret = devm_request_threaded_irq(&i2c->dev, + gpio_to_irq(aw8624->irq_gpio), + NULL, aw8624_irq, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "aw8624", aw8624); + if (ret != 0) { + dev_err(&i2c->dev, "%s: failed to request IRQ %d: %d\n", + __func__, gpio_to_irq(aw8624->irq_gpio), ret); + goto err_irq; + } + } + + dev_set_drvdata(&i2c->dev, aw8624); + + ret = sysfs_create_group(&i2c->dev.kobj, &aw8624_attribute_group); + if (ret < 0) { + dev_info(&i2c->dev, "%s error creating sysfs attr files\n", __func__); + goto err_sysfs; + } + + g_aw8624 = aw8624; + + aw8624_vibrator_init(aw8624); + aw8624_haptic_init(aw8624); + aw8624_ram_init(aw8624); + msleep(100); + + if (aw8624->IsUsedIRQ) + aw8624_haptic_trig1_config(aw8624, true); + pr_info("%s probe completed successfully!\n", __func__); + + return 0; + +err_sysfs: + sysfs_remove_group(&i2c->dev.kobj, &aw8624_attribute_group); +err_irq: +err_id: +err_parse_dt: + return ret; +} + +static int aw8624_i2c_remove(struct i2c_client *i2c) +{ + struct aw8624 *aw8624 = i2c_get_clientdata(i2c); + + cancel_delayed_work_sync(&aw8624->ram_work); + misc_deregister(&aw8624_haptic_misc); + + cancel_work_sync(&aw8624->haptic_audio.work); + hrtimer_cancel(&aw8624->haptic_audio.timer); + + if (aw8624->IsUsedIRQ) { + cancel_work_sync(&aw8624->irq_work); + cancel_work_sync(&aw8624->rtp_work); + } + cancel_work_sync(&aw8624->vibrator_work); + hrtimer_cancel(&aw8624->timer); + + mutex_destroy(&aw8624->lock); + mutex_destroy(&aw8624->haptic_audio.lock); + + sysfs_remove_group(&i2c->dev.kobj, &aw8624_attribute_group); + sysfs_remove_group(&i2c->dev.kobj, &aw8624_vibrator_attribute_group); + + devm_free_irq(&i2c->dev, gpio_to_irq(aw8624->irq_gpio), aw8624); + + return 0; +} + +static const struct i2c_device_id aw8624_i2c_id[] = { + { AW8624_I2C_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, aw8624_i2c_id); + +static struct of_device_id aw8624_dt_match[] = { + { .compatible = "awinic,aw8624_haptic" }, + { }, +}; + +static struct i2c_driver aw8624_i2c_driver = { + .driver = { + .name = AW8624_I2C_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(aw8624_dt_match), + }, + .probe = aw8624_i2c_probe, + .remove = aw8624_i2c_remove, + .id_table = aw8624_i2c_id, +}; + +static int __init aw8624_i2c_init(void) +{ + int ret = 0; + + pr_info("aw8624 driver version %s\n", AW8624_VERSION); + + ret = i2c_add_driver(&aw8624_i2c_driver); + if (ret) { + pr_err("fail to add aw8624 device into i2c\n"); + return ret; + } + + return 0; +} + +module_init(aw8624_i2c_init); + +static void __exit aw8624_i2c_exit(void) +{ + i2c_del_driver(&aw8624_i2c_driver); +} +module_exit(aw8624_i2c_exit); + +MODULE_DESCRIPTION("AW8624 Haptic Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/misc/awinic/aw8624/aw8624.h b/drivers/misc/awinic/aw8624/aw8624.h new file mode 100644 index 000000000000..45c9a8890caf --- /dev/null +++ b/drivers/misc/awinic/aw8624/aw8624.h @@ -0,0 +1,230 @@ +#ifndef _AW8624_H_ +#define _AW8624_H_ + +/********************************************************* + * + * kernel version + * + ********************************************************/ + +/********************************************************* + * + * aw8624.h + * + ********************************************************/ +#include +#include +#include +#include +#include +#include +#include +/********************************************************* + * + * marco + * + ********************************************************/ +#define MAX_I2C_BUFFER_SIZE 65536 + +#define AW8624_REG_MAX 0xff + +#define AW8624_SEQUENCER_SIZE 8 +#define AW8624_SEQUENCER_LOOP_SIZE 4 + +#define AW8624_RTP_I2C_SINGLE_MAX_NUM 512 + +#define HAPTIC_MAX_TIMEOUT 10000 + +#define AW8624_HAPTIC_F0_PRE 2600 +#define AW8624_HAPTIC_F0_CALI_PERCEN 7 /*-7%~7% */ +#define AW8624_HAPTIC_CONT_DRV_LVL 125 /*80 //125=2.98v */ +#define AW8624_HAPTIC_CONT_DRV_LVL_OV 155 /* 127 //155=3.69v */ +#define AW8624_HAPTIC_CONT_TD 0xf06c /*0x005d */ +#define AW8624_HAPTIC_CONT_ZC_THR 0x0ff1 /* 0x009a */ +#define AW8624_HAPTIC_CONT_NUM_BRK 3 +#define AW8624_HAPTIC_F0_COEFF 260 /*2.604167 */ + + +enum aw8624_flags { + AW8624_FLAG_NONR = 0, + AW8624_FLAG_SKIP_INTERRUPTS = 1, +}; + +enum aw8624_chipids { + AW8624_ID = 1, +}; + +enum aw8624_haptic_read_write { + AW8624_HAPTIC_CMD_READ_REG = 0, + AW8624_HAPTIC_CMD_WRITE_REG = 1, +}; + + +enum aw8624_haptic_work_mode { + AW8624_HAPTIC_STANDBY_MODE = 0, + AW8624_HAPTIC_RAM_MODE = 1, + AW8624_HAPTIC_RTP_MODE = 2, + AW8624_HAPTIC_TRIG_MODE = 3, + AW8624_HAPTIC_CONT_MODE = 4, + AW8624_HAPTIC_RAM_LOOP_MODE = 5, +}; + +enum aw8624_haptic_bst_mode { + AW8624_HAPTIC_BYPASS_MODE = 0, + AW8624_HAPTIC_BOOST_MODE = 1, +}; + +enum aw8624_haptic_activate_mode { + AW8624_HAPTIC_ACTIVATE_RAM_MODE = 0, + AW8624_HAPTIC_ACTIVATE_CONT_MODE = 1, +}; + +enum aw8624_haptic_vbat_comp_mode { + AW8624_HAPTIC_VBAT_SW_COMP_MODE = 0, + AW8624_HAPTIC_VBAT_HW_COMP_MODE = 1, +}; + +enum aw8624_haptic_f0_flag { + AW8624_HAPTIC_LRA_F0 = 0, + AW8624_HAPTIC_CALI_F0 = 1, +}; + +enum aw8624_haptic_pwm_mode { + AW8624_PWM_48K = 0, + AW8624_PWM_24K = 1, + AW8624_PWM_12K = 2, +}; + +/********************************************************* + * + * struct + * + ********************************************************/ +struct fileops { + unsigned char cmd; + unsigned char reg; + unsigned char ram_addrh; + unsigned char ram_addrl; +}; + +struct ram { + unsigned int len; + unsigned int check_sum; + unsigned int base_addr; + unsigned char version; + unsigned char ram_shift; + unsigned char baseaddr_shift; +}; + +struct haptic_ctr { + unsigned char cmd; + unsigned char play; + unsigned char wavseq; + unsigned char loop; + unsigned char gain; +}; + +struct haptic_audio { + struct mutex lock; + struct hrtimer timer; + struct work_struct work; + int delay_val; + int timer_val; + unsigned char cnt; + struct haptic_ctr ctr[256]; +}; + +struct aw8624 { + struct i2c_client *i2c; + struct device *dev; + + struct mutex lock; + struct hrtimer timer; + struct work_struct vibrator_work; + struct work_struct irq_work; + struct work_struct rtp_work; + struct delayed_work ram_work; + + struct led_classdev to_dev; + + struct fileops fileops; + struct ram ram; + + int reset_gpio; + int irq_gpio; + int reset_gpio_ret; + int irq_gpio_ret; + + unsigned char hwen_flag; + unsigned char flags; + unsigned char chipid; + + unsigned char play_mode; + unsigned char activate_mode; + + int state; + int duration; + int amplitude; + int index; + int vmax; + int gain; + + unsigned char seq[AW8624_SEQUENCER_SIZE]; + unsigned char loop[AW8624_SEQUENCER_SIZE]; + + unsigned int rtp_cnt; + unsigned int rtp_file_num; + + unsigned char rtp_init; + unsigned char ram_init; + + unsigned int f0; + unsigned int f0_pre; + unsigned int cont_td; + unsigned int cont_f0; + unsigned int cont_zc_thr; + unsigned char cont_drv_lvl; + unsigned char cont_drv_lvl_ov; + unsigned char cont_num_brk; + unsigned char max_pos_beme; + unsigned char max_neg_beme; + unsigned char f0_cali_flag; + bool IsUsedIRQ; + bool ram_update_delay; + bool dts_addr_real; + unsigned int real_i2c_addr; + struct haptic_audio haptic_audio; +}; + +struct aw8624_container { + int len; + unsigned char data[]; +}; + + +/********************************************************* + * + * ioctl + * + ********************************************************/ +struct aw8624_seq_loop { + unsigned char loop[AW8624_SEQUENCER_SIZE]; +}; + +struct aw8624_que_seq { + unsigned char index[AW8624_SEQUENCER_SIZE]; +}; + + +#define AW8624_HAPTIC_IOCTL_MAGIC 'h' + +#define AW8624_HAPTIC_SET_QUE_SEQ _IOWR(AW8624_HAPTIC_IOCTL_MAGIC, 1, struct aw8624_que_seq*) +#define AW8624_HAPTIC_SET_SEQ_LOOP _IOWR(AW8624_HAPTIC_IOCTL_MAGIC, 2, struct aw8624_seq_loop*) +#define AW8624_HAPTIC_PLAY_QUE_SEQ _IOWR(AW8624_HAPTIC_IOCTL_MAGIC, 3, unsigned int) +#define AW8624_HAPTIC_SET_BST_VOL _IOWR(AW8624_HAPTIC_IOCTL_MAGIC, 4, unsigned int) +#define AW8624_HAPTIC_SET_BST_PEAK_CUR _IOWR(AW8624_HAPTIC_IOCTL_MAGIC, 5, unsigned int) +#define AW8624_HAPTIC_SET_GAIN _IOWR(AW8624_HAPTIC_IOCTL_MAGIC, 6, unsigned int) +#define AW8624_HAPTIC_PLAY_REPEAT_SEQ _IOWR(AW8624_HAPTIC_IOCTL_MAGIC, 7, unsigned int) + +#endif + diff --git a/drivers/misc/awinic/aw8624/aw8624_reg.h b/drivers/misc/awinic/aw8624/aw8624_reg.h new file mode 100644 index 000000000000..96b5c4504b7e --- /dev/null +++ b/drivers/misc/awinic/aw8624/aw8624_reg.h @@ -0,0 +1,594 @@ +#ifndef _AW8624_REG_H_ +#define _AW8624_REG_H_ + +/******************************************** + * Register List + *******************************************/ +#define AW8624_REG_ID 0x00 +#define AW8624_REG_SYSST 0x01 +#define AW8624_REG_SYSINT 0x02 +#define AW8624_REG_SYSINTM 0x03 +#define AW8624_REG_SYSCTRL 0x04 +#define AW8624_REG_GO 0x05 +#define AW8624_REG_RTP_DATA 0x06 +#define AW8624_REG_WAVSEQ1 0x07 +#define AW8624_REG_WAVSEQ2 0x08 +#define AW8624_REG_WAVSEQ3 0x09 +#define AW8624_REG_WAVSEQ4 0x0a +#define AW8624_REG_WAVSEQ5 0x0b +#define AW8624_REG_WAVSEQ6 0x0c +#define AW8624_REG_WAVSEQ7 0x0d +#define AW8624_REG_WAVSEQ8 0x0e +#define AW8624_REG_WAVLOOP1 0x0f +#define AW8624_REG_WAVLOOP2 0x10 +#define AW8624_REG_WAVLOOP3 0x11 +#define AW8624_REG_WAVLOOP4 0x12 +#define AW8624_REG_MAIN_LOOP 0x13 +#define AW8624_REG_TRG1_SEQP 0x14 +#define AW8624_REG_TRG1_SEQN 0x17 +#define AW8624_REG_PLAY_PRIO 0x1a +#define AW8624_REG_TRG_CFG1 0x1b +#define AW8624_REG_TRG_CFG2 0x1c +#define AW8624_REG_DBGCTRL 0x20 +#define AW8624_REG_BASE_ADDRH 0x21 +#define AW8624_REG_BASE_ADDRL 0x22 +#define AW8624_REG_FIFO_AEH 0x23 +#define AW8624_REG_FIFO_AEL 0x24 +#define AW8624_REG_FIFO_AFH 0x25 +#define AW8624_REG_FIFO_AFL 0x26 +#define AW8624_REG_WAKE_DLY 0x27 +#define AW8624_REG_START_DLY 0x28 +#define AW8624_REG_END_DLY_H 0x29 +#define AW8624_REG_END_DLY_L 0x2a +#define AW8624_REG_DATCTRL 0x2b +#define AW8624_REG_PWMDEL 0x2c +#define AW8624_REG_PWMPRC 0x2d +#define AW8624_REG_PWMDBG 0x2e +#define AW8624_REG_LDOCTRL 0x2f +#define AW8624_REG_DBGSTAT 0x30 +#define AW8624_REG_WAVECTRL 0x31 +#define AW8624_REG_BRAKE0_CTRL 0x32 +#define AW8624_REG_BRAKE1_CTRL 0x33 +#define AW8624_REG_BRAKE2_CTRL 0x34 +#define AW8624_REG_BRAKE_NUM 0x35 +#define AW8624_REG_ANADBG1 0x36 +#define AW8624_REG_ANADBG2 0x37 +#define AW8624_REG_ANACTRL 0x38 +#define AW8624_REG_SW_BRAKE 0x39 +#define AW8624_REG_GLBDBG 0x3a +#define AW8624_REG_DATDBG 0x3b +#define AW8624_REG_WDCTRL 0x3c +#define AW8624_REG_HDRVDBG 0x3d +#define AW8624_REG_PRLVL 0x3e +#define AW8624_REG_PRTIME 0x3f +#define AW8624_REG_RAMADDRH 0x40 +#define AW8624_REG_RAMADDRL 0x41 +#define AW8624_REG_RAMDATA 0x42 +#define AW8624_REG_TM 0x43 +#define AW8624_REG_BRA_MAX_NUM 0x44 +#define AW8624_REG_BEMF_ERM_FAC 0x45 +#define AW8624_REG_BEMF_BRA_FAC 0x46 +#define AW8624_REG_GLB_STATE 0x47 +#define AW8624_REG_CONT_CTRL 0x48 +#define AW8624_REG_F_PRE_H 0x49 +#define AW8624_REG_F_PRE_L 0x4a +#define AW8624_REG_TD_H 0x4b +#define AW8624_REG_TD_L 0x4c +#define AW8624_REG_TSET 0x4d +#define AW8624_REG_THRS_BRA_RAP 0x4e +#define AW8624_REG_THRS_BRA_END 0x4f +#define AW8624_REG_EF_CTRL 0x50 +#define AW8624_REG_EF_WDATAH 0x53 +#define AW8624_REG_EF_WDATAL 0x54 +#define AW8624_REG_EF_RDATAH 0x55 +#define AW8624_REG_EF_RDATAL 0x56 +#define AW8624_REG_DLY 0x57 +#define AW8624_REG_EF_WR_WIDTH 0x58 +#define AW8624_REG_EF_RD_WIDTH 0x59 +#define AW8624_REG_TRIM_LRA 0x5b +#define AW8624_REG_TRIM_OSC 0x5c +#define AW8624_REG_R_SPARE 0x5d +#define AW8624_REG_D2SCFG 0x5e +#define AW8624_REG_DETCTRL 0x5f +#define AW8624_REG_RLDET 0x60 +#define AW8624_REG_OSDET 0x61 +#define AW8624_REG_VBATDET 0x62 +#define AW8624_REG_TESTDET 0x63 +#define AW8624_REG_DETLO 0x64 +#define AW8624_REG_BEMFDBG 0x65 +#define AW8624_REG_ADCTEST 0x66 +#define AW8624_REG_BEMFTEST 0x67 +#define AW8624_REG_F_LRA_F0_H 0x68 +#define AW8624_REG_F_LRA_F0_L 0x69 +#define AW8624_REG_F_LRA_CONT_H 0x6a +#define AW8624_REG_F_LRA_CONT_L 0x6b +#define AW8624_REG_WAIT_VOL_MP 0x6e +#define AW8624_REG_WAIT_VOL_MN 0x6f +#define AW8624_REG_BEMF_VOL_H 0x70 +#define AW8624_REG_BEMF_VOL_L 0x71 +#define AW8624_REG_ZC_THRSH_H 0x72 +#define AW8624_REG_ZC_THRSH_L 0x73 +#define AW8624_REG_BEMF_VTHH_H 0x74 +#define AW8624_REG_BEMF_VTHH_L 0x75 +#define AW8624_REG_BEMF_VTHL_H 0x76 +#define AW8624_REG_BEMF_VTHL_L 0x77 +#define AW8624_REG_BEMF_NUM 0x78 +#define AW8624_REG_DRV_TIME 0x79 +#define AW8624_REG_TIME_NZC 0x7a +#define AW8624_REG_DRV_LVL 0x7b +#define AW8624_REG_DRV_LVL_OV 0x7c +#define AW8624_REG_NUM_F0_1 0x7d +#define AW8624_REG_NUM_F0_2 0x7e +#define AW8624_REG_NUM_F0_3 0x7f + + + +/******************************************** + * Register Access + *******************************************/ +#define REG_NONE_ACCESS 0 +#define REG_RD_ACCESS 1 << 0 +#define REG_WR_ACCESS 1 << 1 + + +const unsigned char aw8624_reg_access[AW8624_REG_MAX] = { + [AW8624_REG_ID ] = REG_RD_ACCESS, + [AW8624_REG_SYSST ] = REG_RD_ACCESS, + [AW8624_REG_SYSINT ] = REG_RD_ACCESS, + [AW8624_REG_SYSINTM ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_SYSCTRL ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_GO ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_RTP_DATA ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_WAVSEQ1 ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_WAVSEQ2 ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_WAVSEQ3 ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_WAVSEQ4 ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_WAVSEQ5 ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_WAVSEQ6 ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_WAVSEQ7 ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_WAVSEQ8 ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_WAVLOOP1 ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_WAVLOOP2 ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_WAVLOOP3 ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_WAVLOOP4 ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_MAIN_LOOP ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_TRG1_SEQP ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_TRG1_SEQN ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_PLAY_PRIO ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_TRG_CFG1 ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_TRG_CFG2 ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_DBGCTRL ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_BASE_ADDRH ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_BASE_ADDRL ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_FIFO_AEH ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_FIFO_AEL ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_FIFO_AFH ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_FIFO_AFL ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_WAKE_DLY ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_START_DLY ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_END_DLY_H ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_END_DLY_L ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_DATCTRL ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_PWMDEL ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_PWMPRC ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_PWMDBG ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_LDOCTRL ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_DBGSTAT ] = REG_RD_ACCESS, + [AW8624_REG_WAVECTRL ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_BRAKE0_CTRL ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_BRAKE1_CTRL ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_BRAKE2_CTRL ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_BRAKE_NUM ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_ANADBG1 ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_ANADBG2 ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_ANACTRL ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_SW_BRAKE ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_GLBDBG ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_DATDBG ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_WDCTRL ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_HDRVDBG ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_PRLVL ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_PRTIME ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_RAMADDRH ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_RAMADDRL ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_RAMDATA ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_TM ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_BRA_MAX_NUM ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_BEMF_ERM_FAC ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_BEMF_BRA_FAC ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_GLB_STATE ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_CONT_CTRL ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_F_PRE_H ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_F_PRE_L ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_TD_H ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_TD_L ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_TSET ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_THRS_BRA_RAP ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_THRS_BRA_END ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_EF_CTRL ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_EF_WDATAH ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_EF_WDATAL ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_EF_RDATAH ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_EF_RDATAL ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_DLY ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_EF_WR_WIDTH ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_EF_RD_WIDTH ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_TRIM_LRA ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_TRIM_OSC ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_R_SPARE ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_D2SCFG ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_DETCTRL ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_RLDET ] = REG_RD_ACCESS, + [AW8624_REG_OSDET ] = REG_RD_ACCESS, + [AW8624_REG_VBATDET ] = REG_RD_ACCESS, + [AW8624_REG_TESTDET ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_DETLO ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_BEMFDBG ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_ADCTEST ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_BEMFTEST ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_F_LRA_F0_H ] = REG_RD_ACCESS, + [AW8624_REG_F_LRA_F0_L ] = REG_RD_ACCESS, + [AW8624_REG_F_LRA_CONT_H ] = REG_RD_ACCESS, + [AW8624_REG_F_LRA_CONT_L ] = REG_RD_ACCESS, + [AW8624_REG_WAIT_VOL_MP ] = REG_RD_ACCESS, + [AW8624_REG_WAIT_VOL_MN ] = REG_RD_ACCESS, + [AW8624_REG_BEMF_VOL_H ] = REG_RD_ACCESS, + [AW8624_REG_BEMF_VOL_L ] = REG_RD_ACCESS, + [AW8624_REG_ZC_THRSH_H ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_ZC_THRSH_L ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_BEMF_VTHH_H ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_BEMF_VTHH_L ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_BEMF_VTHL_H ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_BEMF_VTHL_L ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_BEMF_NUM ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_DRV_TIME ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_TIME_NZC ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_DRV_LVL ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_DRV_LVL_OV ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_NUM_F0_1 ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_NUM_F0_2 ] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8624_REG_NUM_F0_3 ] = REG_RD_ACCESS | REG_WR_ACCESS, +}; + + + + +/****************************************************** + * Register Detail + *****************************************************/ +/* + * SYSST 0x01 + */ +#define AW8624_BIT_SYSST_OVS (1<<6) +#define AW8624_BIT_SYSST_UVLS (1<<5) +#define AW8624_BIT_SYSST_FF_AES (1<<4) +#define AW8624_BIT_SYSST_FF_AFS (1<<3) +#define AW8624_BIT_SYSST_OCDS (1<<2) +#define AW8624_BIT_SYSST_OTS (1<<1) +#define AW8624_BIT_SYSST_DONES (1<<0) + +/* + * SYSINT 0x02 + */ +#define AW8624_BIT_SYSINT_OVI (1<<6) +#define AW8624_BIT_SYSINT_UVLI (1<<5) +#define AW8624_BIT_SYSINT_FF_AEI (1<<4) +#define AW8624_BIT_SYSINT_FF_AFI (1<<3) +#define AW8624_BIT_SYSINT_OCDI (1<<2) +#define AW8624_BIT_SYSINT_OTI (1<<1) +#define AW8624_BIT_SYSINT_DONEI (1<<0) + +/* + * SYSINTM 0x03 + */ +#define AW8624_BIT_SYSINTM_OV_MASK (~(1<<6)) +#define AW8624_BIT_SYSINTM_OV_OFF (1<<6) +#define AW8624_BIT_SYSINTM_OV_EN (0<<6) +#define AW8624_BIT_SYSINTM_UVLO_MASK (~(1<<5)) +#define AW8624_BIT_SYSINTM_UVLO_OFF (1<<5) +#define AW8624_BIT_SYSINTM_UVLO_EN (0<<5) +#define AW8624_BIT_SYSINTM_FF_AE_MASK (~(1<<4)) +#define AW8624_BIT_SYSINTM_FF_AE_OFF (1<<4) +#define AW8624_BIT_SYSINTM_FF_AE_EN (0<<4) +#define AW8624_BIT_SYSINTM_FF_AF_MASK (~(1<<3)) +#define AW8624_BIT_SYSINTM_FF_AF_OFF (1<<3) +#define AW8624_BIT_SYSINTM_FF_AF_EN (0<<3) +#define AW8624_BIT_SYSINTM_OCD_MASK (~(1<<2)) +#define AW8624_BIT_SYSINTM_OCD_OFF (1<<2) +#define AW8624_BIT_SYSINTM_OCD_EN (0<<2) +#define AW8624_BIT_SYSINTM_OT_MASK (~(1<<1)) +#define AW8624_BIT_SYSINTM_OT_OFF (1<<1) +#define AW8624_BIT_SYSINTM_OT_EN (0<<1) +#define AW8624_BIT_SYSINTM_DONE_MASK (~(1<<0)) +#define AW8624_BIT_SYSINTM_DONE_OFF (1<<0) +#define AW8624_BIT_SYSINTM_DONE_EN (0<<0) + +/* + * SYSCTRL 0x04 + */ +#define AW8624_BIT_SYSCTRL_WAVDAT_MODE_MASK (~(3<<6)) +#define AW8624_BIT_SYSCTRL_WAVDAT_MODE_4X (3<<6) +#define AW8624_BIT_SYSCTRL_WAVDAT_MODE_2X (0<<6) +#define AW8624_BIT_SYSCTRL_WAVDAT_MODE_1X (1<<6) +#define AW8624_BIT_SYSCTRL_RAMINIT_MASK (~(1<<5)) +#define AW8624_BIT_SYSCTRL_RAMINIT_EN (1<<5) +#define AW8624_BIT_SYSCTRL_RAMINIT_OFF (0<<5) +#define AW8624_BIT_SYSCTRL_PLAY_MODE_MASK (~(3<<2)) +#define AW8624_BIT_SYSCTRL_PLAY_MODE_CONT (2<<2) +#define AW8624_BIT_SYSCTRL_PLAY_MODE_RTP (1<<2) +#define AW8624_BIT_SYSCTRL_PLAY_MODE_RAM (0<<2) +#define AW8624_BIT_SYSCTRL_WORK_MODE_MASK (~(1<<0)) +#define AW8624_BIT_SYSCTRL_STANDBY (1<<0) +#define AW8624_BIT_SYSCTRL_ACTIVE (0<<0) + +/* + * GO 0x05 + */ +#define AW8624_BIT_GO_MASK (~(1<<0)) +#define AW8624_BIT_GO_ENABLE (1<<0) +#define AW8624_BIT_GO_DISABLE (0<<0) + +/* + * WAVSEQ1 0x07 + */ +#define AW8624_BIT_WAVSEQ1_WAIT (1<<7) +#define AW8624_BIT_WAVSEQ1_WAV_FRM_SEQ1_MASK (~(127<<0)) + +/* + * WAVSEQ2 0x08 + */ +#define AW8624_BIT_WAVSEQ2_WAIT (1<<7) +#define AW8624_BIT_WAVSEQ2_WAV_FRM_SEQ2_MASK (~(127<<0)) + +/* + * WAVSEQ3 0x09 + */ +#define AW8624_BIT_WAVSEQ3_WAIT (1<<7) +#define AW8624_BIT_WAVSEQ3_WAV_FRM_SEQ3_MASK (~(127<<0)) + +/* + * WAVSEQ4 0x0A + */ +#define AW8624_BIT_WAVSEQ4_WAIT (1<<7) +#define AW8624_BIT_WAVSEQ4_WAV_FRM_SEQ4_MASK (~(127<<0)) + +/* + * WAVSEQ5 0X0B + */ +#define AW8624_BIT_WAVSEQ5_WAIT (1<<7) +#define AW8624_BIT_WAVSEQ5_WAV_FRM_SEQ5_MASK (~(127<<0)) + +/* + * WAVSEQ6 0X0C + */ +#define AW8624_BIT_WAVSEQ6_WAIT (1<<7) +#define AW8624_BIT_WAVSEQ6_WAV_FRM_SEQ6_MASK (~(127<<0)) + +/* + * WAVSEQ7 + */ +#define AW8624_BIT_WAVSEQ7_WAIT (1<<7) +#define AW8624_BIT_WAVSEQ7_WAV_FRM_SEQ7_MASK (~(127<<0)) + +/* + * WAVSEQ8 + */ +#define AW8624_BIT_WAVSEQ8_WAIT (1<<7) +#define AW8624_BIT_WAVSEQ8_WAV_FRM_SEQ8_MASK (~(127<<0)) + +/* + * WAVLOOP + */ +#define AW8624_BIT_WAVLOOP_SEQN_MASK (~(15<<4)) +#define AW8624_BIT_WAVLOOP_SEQNP1_MASK (~(15<<0)) +#define AW8624_BIT_WAVLOOP_INIFINITELY (15<<0) + +/* + * WAVLOOP1 + */ +#define AW8624_BIT_WAVLOOP1_SEQ1_MASK (~(15<<4)) +#define AW8624_BIT_WAVLOOP1_SEQ2_MASK (~(15<<0)) + +/* + * WAVLOOP2 + */ +#define AW8624_BIT_WAVLOOP2_SEQ3_MASK (~(15<<4)) +#define AW8624_BIT_WAVLOOP2_SEQ4_MASK (~(15<<0)) + +/* + * WAVLOOP3 + */ +#define AW8624_BIT_WAVLOOP3_SEQ5_MASK (~(15<<4)) +#define AW8624_BIT_WAVLOOP3_SEQ6_MASK (~(15<<0)) + +/* + * WAVLOOP4 + */ +#define AW8624_BIT_WAVLOOP4_SEQ7_MASK (~(15<<4)) +#define AW8624_BIT_WAVLOOP4_SEQ8_MASK (~(15<<0)) + + +/* + * PLAYPRIO + */ +#define AW8624_BIT_PLAYPRIO_GO_MASK (~(3<<6)) +#define AW8624_BIT_PLAYPRIO_TRIG3_MASK (~(3<<4)) +#define AW8624_BIT_PLAYPRIO_TRIG2_MASK (~(3<<2)) +#define AW8624_BIT_PLAYPRIO_TRIG1_MASK (~(3<<0)) + +/* + * TRGCFG1 + */ +#define AW8624_BIT_TRGCFG1_TRG3_POLAR_MASK (~(1<<5)) +#define AW8624_BIT_TRGCFG1_TRG3_POLAR_NEG (1<<5) +#define AW8624_BIT_TRGCFG1_TRG3_POLAR_POS (0<<5) +#define AW8624_BIT_TRGCFG1_TRG3_EDGE_MASK (~(1<<4)) +#define AW8624_BIT_TRGCFG1_TRG3_EDGE_POS (1<<4) +#define AW8624_BIT_TRGCFG1_TRG3_EDGE_POS_NEG (0<<4) +#define AW8624_BIT_TRGCFG1_TRG2_POLAR_MASK (~(1<<3)) +#define AW8624_BIT_TRGCFG1_TRG2_POLAR_NEG (1<<3) +#define AW8624_BIT_TRGCFG1_TRG2_POLAR_POS (0<<3) +#define AW8624_BIT_TRGCFG1_TRG2_EDGE_MASK (~(1<<2)) +#define AW8624_BIT_TRGCFG1_TRG2_EDGE_POS (1<<2) +#define AW8624_BIT_TRGCFG1_TRG2_EDGE_POS_NEG (0<<2) +#define AW8624_BIT_TRGCFG1_TRG1_POLAR_MASK (~(1<<1)) +#define AW8624_BIT_TRGCFG1_TRG1_POLAR_NEG (1<<1) +#define AW8624_BIT_TRGCFG1_TRG1_POLAR_POS (0<<1) +#define AW8624_BIT_TRGCFG1_TRG1_EDGE_MASK (~(1<<0)) +#define AW8624_BIT_TRGCFG1_TRG1_EDGE_POS (1<<0) +#define AW8624_BIT_TRGCFG1_TRG1_EDGE_POS_NEG (0<<0) + +/* + * TRGCFG2 + */ +#define AW8624_BIT_TRGCFG2_TRG3_ENABLE_MASK (~(1<<2)) +#define AW8624_BIT_TRGCFG2_TRG3_ENABLE (1<<2) +#define AW8624_BIT_TRGCFG2_TRG3_DISABLE (0<<2) +#define AW8624_BIT_TRGCFG2_TRG2_ENABLE_MASK (~(1<<1)) +#define AW8624_BIT_TRGCFG2_TRG2_ENABLE (1<<1) +#define AW8624_BIT_TRGCFG2_TRG2_DISABLE (0<<1) +#define AW8624_BIT_TRGCFG2_TRG1_ENABLE_MASK (~(1<<0)) +#define AW8624_BIT_TRGCFG2_TRG1_ENABLE (1<<0) +#define AW8624_BIT_TRGCFG2_TRG1_DISABLE (0<<0) + +/*DBGCTRL //0X20 */ +#define AW8624_BIT_DBGCTRL_INTN_TRG_SEL_MASK (~(1<<5)) +#define AW8624_BIT_DBGCTRL_INTN_SEL_ENABLE (1<<5) +#define AW8624_BIT_DBGCTRL_TRG_SEL_ENABLE (0<<5) + +/* + * DATCTRL + */ +#define AW8624_BIT_DATCTRL_FC_MASK (~(1<<6)) +#define AW8624_BIT_DATCTRL_FC_1000HZ (3<<6) +#define AW8624_BIT_DATCTRL_FC_800HZ (3<<6) +#define AW8624_BIT_DATCTRL_FC_600HZ (1<<6) +#define AW8624_BIT_DATCTRL_FC_400HZ (0<<6) +#define AW8624_BIT_DATCTRL_LPF_ENABLE_MASK (~(1<<5)) +#define AW8624_BIT_DATCTRL_LPF_ENABLE (1<<5) +#define AW8624_BIT_DATCTRL_LPF_DISABLE (0<<5) + +/*PWMPRC //0X2D */ +#define AW8624_BIT_PWMPRC_PRC_EN_MASK (~(1<<7)) +#define AW8624_BIT_PWMPRC_PRC_ENABLE (1<<7) +#define AW8624_BIT_PWMPRC_PRC_DISABLE (0<<7) +#define AW8624_BIT_PWMPRC_PRCTIME_MASK (~(0x7f<<0)) + +/* + * PWMDBG + */ +#define AW8624_BIT_PWMDBG_PWM_MODE_MASK (~(3<<5)) +#define AW8624_BIT_PWMDBG_PWM_12K (3<<5) +#define AW8624_BIT_PWMDBG_PWM_24K (2<<5) +#define AW8624_BIT_PWMDBG_PWM_48K (0<<5) + +/* + * WAVECTRL + */ +#define AW8624_BIT_WAVECTRL_NUM_OV_DRIVER_MASK (~(0xF<<4)) +#define AW8624_BIT_WAVECTRL_NUM_OV_DRIVER (0<<4) + +/* + * BST_AUTO + */ +#define AW8624_BIT_BST_AUTO_BST_AUTOSW_MASK (~(1<<2)) +#define AW8624_BIT_BST_AUTO_BST_AUTOMATIC_BOOST (1<<2) +#define AW8624_BIT_BST_AUTO_BST_MANUAL_BOOST (0<<2) + +/* + * CONT_CTRL + */ +#define AW8624_BIT_CONT_CTRL_ZC_DETEC_MASK (~(1<<7)) +#define AW8624_BIT_CONT_CTRL_ZC_DETEC_ENABLE (1<<7) +#define AW8624_BIT_CONT_CTRL_ZC_DETEC_DISABLE (0<<7) +#define AW8624_BIT_CONT_CTRL_WAIT_PERIOD_MASK (~(3<<5)) +#define AW8624_BIT_CONT_CTRL_WAIT_8PERIOD (3<<5) +#define AW8624_BIT_CONT_CTRL_WAIT_4PERIOD (2<<5) +#define AW8624_BIT_CONT_CTRL_WAIT_2PERIOD (1<<5) +#define AW8624_BIT_CONT_CTRL_WAIT_1PERIOD (0<<5) +#define AW8624_BIT_CONT_CTRL_MODE_MASK (~(1<<4)) +#define AW8624_BIT_CONT_CTRL_BY_DRV_TIME (1<<4) +#define AW8624_BIT_CONT_CTRL_BY_GO_SIGNAL (0<<4) +#define AW8624_BIT_CONT_CTRL_EN_CLOSE_MASK (~(1<<3)) +#define AW8624_BIT_CONT_CTRL_CLOSE_PLAYBACK (1<<3) +#define AW8624_BIT_CONT_CTRL_OPEN_PLAYBACK (0<<3) +#define AW8624_BIT_CONT_CTRL_F0_DETECT_MASK (~(1<<2)) +#define AW8624_BIT_CONT_CTRL_F0_DETECT_ENABLE (1<<2) +#define AW8624_BIT_CONT_CTRL_F0_DETECT_DISABLE (0<<2) +#define AW8624_BIT_CONT_CTRL_O2C_MASK (~(1<<1)) +#define AW8624_BIT_CONT_CTRL_O2C_ENABLE (1<<1) +#define AW8624_BIT_CONT_CTRL_O2C_DISABLE (0<<1) +#define AW8624_BIT_CONT_CTRL_AUTO_BRK_MASK (~(1<<0)) +#define AW8624_BIT_CONT_CTRL_AUTO_BRK_ENABLE (1<<0) +#define AW8624_BIT_CONT_CTRL_AUTO_BRK_DISABLE (0<<0) + +#define AW8624_BIT_D2SCFG_CLK_ADC_MASK (~(7<<4)) +#define AW8624_BIT_D2SCFG_CLK_ASC_1P5MHZ (3<<4) + +/* + * DETCTRL + */ +#define AW8624_BIT_DETCTRL_RL_OS_MASK (~(1<<6)) +#define AW8624_BIT_DETCTRL_RL_DETECT (1<<6) +#define AW8624_BIT_DETCTRL_OS_DETECT (0<<6) +#define AW8624_BIT_DETCTRL_PROTECT_MASK (~(1<<5)) +#define AW8624_BIT_DETCTRL_PROTECT_NO_ACTION (1<<5) +#define AW8624_BIT_DETCTRL_PROTECT_SHUTDOWN (0<<5) +#define AW8624_BIT_DETCTRL_VBAT_GO_MASK (~(1<<1)) +#define AW8624_BIT_DETCTRL_VABT_GO_ENABLE (1<<1) +#define AW8624_BIT_DETCTRL_VBAT_GO_DISBALE (0<<1) +#define AW8624_BIT_DETCTRL_DIAG_GO_MASK (~(1<<0)) +#define AW8624_BIT_DETCTRL_DIAG_GO_ENABLE (1<<0) +#define AW8624_BIT_DETCTRL_DIAG_GO_DISABLE (0<<0) + + +/* + * VBAT MODE + */ +#define AW8624_BIT_DETCTRL_VBAT_MODE_MASK (~(1<<6)) +#define AW8624_BIT_DETCTRL_VBAT_HW_COMP (1<<6) +#define AW8624_BIT_DETCTRL_VBAT_SW_COMP (0<<6) + + +/* + * ANACTRL + */ +#define AW8624_BIT_ANACTRL_LRA_SRC_MASK (~(1<<5)) +#define AW8624_BIT_ANACTRL_LRA_SRC_REG (1<<5) +#define AW8624_BIT_ANACTRL_LRA_SRC_EFUSE (0<<5) +#define AW8624_BIT_ANACTRL_EN_IO_PD1_MASK (~(1<<0)) +#define AW8624_BIT_ANACTRL_EN_IO_PD1_HIGH (1<<0) +#define AW8624_BIT_ANACTRL_EN_IO_PD1_LOW (0<<0) + +/* + *SW_BRAKE + */ +#define AW8624_BIT_EN_BRAKE_CONT_MASK (~(1<<3)) +#define AW8624_BIT_EN_BRAKE_CONT_ENABLE (1<<3) +#define AW8624_BIT_EN_BRAKE_CONT_DISABLE (0<<3) +#define AW8624_BIT_EN_BRAKE_RAM_MASK (~(1<<2)) +#define AW8624_BIT_EN_BRAKE_RAM_ENABLE (1<<2) +#define AW8624_BIT_EN_BRAKE_RAM_DISABLE (0<<2) +#define AW8624_BIT_EN_BRAKE_RTP_MASK (~(1<<1)) +#define AW8624_BIT_EN_BRAKE_RTP_ENABLE (1<<1) +#define AW8624_BIT_EN_BRAKE_RTP_DISABLE (0<<1) +#define AW8624_BIT_EN_BRAKE_TRIG_MASK (~(1<<0)) +#define AW8624_BIT_EN_BRAKE_TRIG_ENABLE (1<<0) +#define AW8624_BIT_EN_BRAKE_TRIG_DISABLE (0<<0) + +/* + *PRLVL + */ +#define AW8624_BIT_PRLVL_PR_EN_MASK (~(1<<7)) +#define AW8624_BIT_PRLVL_PR_ENABLE (1<<7) +#define AW8624_BIT_PRLVL_PR_DISABLE (0<<7) +#define AW8624_BIT_PRLVL_PRLVL_MASK (~(0x7f<<0)) + +/* + *PRTIME + */ +#define AW8624_BIT_PRTIME_PRTIME_MASK (~(0xff<<0)) + +#define AW8624_BIT_BEMF_NUM_BRK_MASK (~(0xf<<0)) +#endif +