From b32695915a7d967cfeb8b71c2064240356c39829 Mon Sep 17 00:00:00 2001 From: a0393714 Date: Thu, 26 Dec 2019 18:39:05 +0530 Subject: [PATCH] Add support for Input framework. The legacy support for timeout framework can be enabled by using ANDROID_TIMED_OUTPUT configuration --- drv2624.c | 1327 +++++++++++++++++++++++++++++++---------------------- drv2624.h | 175 ++++--- 2 files changed, 895 insertions(+), 607 deletions(-) diff --git a/drv2624.c b/drv2624.c index d78aabb..e372932 100755 --- a/drv2624.c +++ b/drv2624.c @@ -27,6 +27,7 @@ #define DEBUG #include +#include #include #include #include @@ -48,11 +49,24 @@ #include #include #include +#include #include "drv2624.h" - static struct drv2624_data *g_DRV2624data = NULL; -static bool g_logEnable = false; +static struct regmap_config drv2624_i2c_regmap = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_NONE, +}; + +static int dev_run_diagnostics(struct drv2624_data *pDRV2624); +static inline int drv2624_calculate_voltage(unsigned int voltage); + +/** + * RW Functions for DRV2624 registers through I2C + * drv2624_reg_read, drv2624_reg_write, + * drv2624_bulk_read, drv2624_bulk_write + **/ static int drv2624_reg_read(struct drv2624_data *pDRV2624, unsigned char reg) @@ -62,14 +76,13 @@ static int drv2624_reg_read(struct drv2624_data *pDRV2624, mutex_lock(&pDRV2624->dev_lock); nResult = regmap_read(pDRV2624->mpRegmap, reg, &val); - mutex_unlock(&pDRV2624->dev_lock); + mutex_unlock(&pDRV2624->dev_lock); if (nResult < 0) { dev_err(pDRV2624->dev, "%s I2C error %d\n", __func__, nResult); return nResult; } else { - if (g_logEnable) - dev_dbg(pDRV2624->dev, "%s, Reg[0x%x]=0x%x\n", __func__, reg, val); + dev_dbg(pDRV2624->dev, "%s, Reg[0x%x]=0x%x\n", __func__, reg, val); return val; } } @@ -78,15 +91,14 @@ static int drv2624_reg_write(struct drv2624_data *pDRV2624, unsigned char reg, unsigned char val) { int nResult; - + dev_dbg(pDRV2624->dev, "%s, Reg[0x%x]=0x%x\n", __func__, reg, val); mutex_lock(&pDRV2624->dev_lock); nResult = regmap_write(pDRV2624->mpRegmap, reg, val); mutex_unlock(&pDRV2624->dev_lock); if (nResult < 0) dev_err(pDRV2624->dev, "%s reg=0x%x, value=0%x error %d\n", __func__, reg, val, nResult); - else if (g_logEnable) - dev_dbg(pDRV2624->dev, "%s, Reg[0x%x]=0x%x\n", __func__, reg, val); + dev_dbg(pDRV2624->dev, "%s, Reg[0x%x]=0x%x\n", __func__, reg, val); return nResult; } @@ -117,10 +129,9 @@ static int drv2624_bulk_write(struct drv2624_data *pDRV2624, if (nResult < 0) dev_err(pDRV2624->dev, "%s reg=0%x, count=%d error %d\n", __func__, reg, count, nResult); - else if (g_logEnable) - for(i = 0; i < count; i++) - dev_dbg(pDRV2624->dev, "%s, Reg[0x%x]=0x%x\n", - __func__, reg+i, buf[i]); + for(i = 0; i < count; i++) + dev_dbg(pDRV2624->dev, "%s, Reg[0x%x]=0x%x\n", + __func__, reg+i, buf[i]); return nResult; } @@ -136,13 +147,18 @@ static int drv2624_set_bits(struct drv2624_data *pDRV2624, if (nResult < 0) dev_err(pDRV2624->dev, "%s reg=%x, mask=0x%x, value=0x%x error %d\n", __func__, reg, mask, val, nResult); - else if (g_logEnable) - dev_dbg(pDRV2624->dev, "%s, Reg[0x%x]:M=0x%x, V=0x%x\n", - __func__, reg, mask, val); + dev_dbg(pDRV2624->dev, "%s, Reg[0x%x]:M=0x%x, V=0x%x\n", + __func__, reg, mask, val); return nResult; } +/** + * + * bRTP = NO == 0; Enable all interrupt of DRV2624 + * bRTP = 1 == 1; Only Enable critical interrupt, PROCESS_DONE and PRG_ERROR + * + **/ static int drv2624_enableIRQ(struct drv2624_data *pDRV2624, unsigned char bRTP) { int nResult = 0; @@ -168,7 +184,6 @@ static int drv2624_enableIRQ(struct drv2624_data *pDRV2624, unsigned char bRTP) pDRV2624->mbIRQEnabled = true; end: - return nResult; } @@ -185,88 +200,58 @@ static void drv2624_disableIRQ(struct drv2624_data *pDRV2624) static int drv2624_set_go_bit(struct drv2624_data *pDRV2624, unsigned char val) { - int nResult = 0, value =0; - int retry = POLL_GO_BIT_RETRY; + int nResult = 0, value = 0; + int retry = GO_BIT_MAX_RETRY_CNT; - val &= 0x01; + val &= DRV2624_GO_BIT_MASK; + dev_dbg(pDRV2624->dev, "%s, go val = %d\n", __func__, val); nResult = drv2624_reg_write(pDRV2624, DRV2624_REG_GO, val); - if (nResult < 0) + if (nResult < 0) goto end; - mdelay(POLL_GO_BIT_INTERVAL); + mdelay(GO_BIT_CHECK_INTERVAL); value = drv2624_reg_read(pDRV2624, DRV2624_REG_GO); if (value < 0) { nResult = value; goto end; } - if (val) { - if (value != GO) { - nResult = -EIO; - dev_warn(pDRV2624->dev, "%s, GO fail, stop action\n", __func__); - } - } else { - while (retry > 0) { - value = drv2624_reg_read(pDRV2624, DRV2624_REG_GO); - if (value < 0) { - nResult = value; - break; - } - - if(value==0) - break; - - mdelay(POLL_GO_BIT_INTERVAL); - retry--; - } + dev_dbg(pDRV2624->dev, "%s, go value = %d\n", __func__, value); + while (((value & DRV2624_GO_BIT_MASK) != val) && (retry > 0)) { + value = drv2624_reg_read(pDRV2624, DRV2624_REG_GO); - if (retry == 0) - dev_err(pDRV2624->dev, - "%s, ERROR: clear GO fail\n", __func__); - else if (g_logEnable) - dev_dbg(pDRV2624->dev, - "%s, clear GO, remain=%d\n", __func__, retry); + dev_dbg(pDRV2624->dev, "%s, GO bit %d\n", __func__, value); + mdelay(GO_BIT_CHECK_INTERVAL); + retry--; } -end: + dev_dbg(pDRV2624->dev, "%s: pull go bit success!\n", __func__); +end: return nResult; } -static int drv2624_change_mode(struct drv2624_data *pDRV2624, - unsigned char work_mode) +static inline int drv2624_change_mode(struct drv2624_data *pDRV2624, + drv2624_mode_t work_mode) { + pDRV2624->mnWorkMode = work_mode; return drv2624_set_bits(pDRV2624, DRV2624_REG_MODE, WORKMODE_MASK, work_mode); } -static int vibrator_get_time(struct timed_output_dev *dev) -{ - struct drv2624_data *pDRV2624 = container_of(dev, struct drv2624_data, to_dev); - - if (hrtimer_active(&pDRV2624->timer)) { - ktime_t r = hrtimer_get_remaining(&pDRV2624->timer); - return ktime_to_ms(r); - } - - return 0; -} - -static void drv2624_set_stopflag(struct drv2624_data *pDRV2624) +static inline void drv2624_set_stopflag(struct drv2624_data *pDRV2624) { pDRV2624->mnVibratorPlaying = NO; - wake_unlock(&pDRV2624->wklock); - if (g_logEnable) - dev_dbg(pDRV2624->dev, "wklock unlock"); + pDRV2624->mnEffectType = 0; } static int drv2624_get_diag_result(struct drv2624_data *pDRV2624, unsigned char nStatus) { - int nResult = 0; + int Re = 0, nResult = 0; pDRV2624->mDiagResult.mnResult = nStatus; - if((nStatus&DIAG_MASK) != DIAG_SUCCESS) - dev_err(pDRV2624->dev, "Diagnostic fail\n"); + if((nStatus & DIAG_MASK) != DIAG_SUCCESS) + dev_err(pDRV2624->dev, "%s: Diagnostic fail\n", __func__); else { nResult = drv2624_reg_read(pDRV2624, DRV2624_REG_DIAG_Z); if (nResult < 0) @@ -278,68 +263,48 @@ static int drv2624_get_diag_result(struct drv2624_data *pDRV2624, unsigned char goto end; pDRV2624->mDiagResult.mnDiagK = nResult; - dev_dbg(pDRV2624->dev, "Diag : ZResult=0x%x, CurrentK=0x%x\n", + Re = 478.43 * (pDRV2624->mDiagResult.mnDiagZ / (4 * pDRV2624->mDiagResult.mnDiagK + 719)); + + dev_dbg(pDRV2624->dev, + "%s: ZResult=0x%x, CurrentK=0x%x, Re = %d ohm\n", + __func__, pDRV2624->mDiagResult.mnDiagZ, - pDRV2624->mDiagResult.mnDiagK); + pDRV2624->mDiagResult.mnDiagK, + Re); } end: return nResult; } -static int drv2624_get_calibration_result(struct drv2624_data *pDRV2624, unsigned char nStatus) -{ - int nResult = 0; - - pDRV2624->mAutoCalResult.mnResult = nStatus; - if ((nStatus&DIAG_MASK) != DIAG_SUCCESS) - dev_err(pDRV2624->dev, "Calibration fail\n"); - else { - nResult = drv2624_reg_read(pDRV2624, DRV2624_REG_CAL_COMP); - if (nResult < 0) - goto end; - pDRV2624->mAutoCalResult.mnCalComp = nResult; - - nResult = drv2624_reg_read(pDRV2624, DRV2624_REG_CAL_BEMF); - if (nResult < 0) - goto end; - pDRV2624->mAutoCalResult.mnCalBemf = nResult; - - nResult = drv2624_reg_read(pDRV2624, DRV2624_REG_LOOP_CONTROL) & BEMFGAIN_MASK; - if (nResult < 0) - goto end; - pDRV2624->mAutoCalResult.mnCalGain = nResult; - - dev_dbg(pDRV2624->dev, "AutoCal : Comp=0x%x, Bemf=0x%x, Gain=0x%x\n", - pDRV2624->mAutoCalResult.mnCalComp, - pDRV2624->mAutoCalResult.mnCalBemf, - pDRV2624->mAutoCalResult.mnCalGain); - } -end: - return nResult; -} - +/** + * No need to stop in Waveform Sequencer Mode. + * 1. Disable irq + * 2. Cancel hrimer + * 3. Set GO bit as STOP + * 4. Set stop flag in drv2624_data struct + * + **/ static int drv2624_stop(struct drv2624_data *pDRV2624) { int nResult = 0, mode = 0; + dev_dbg(pDRV2624->dev, "%s enter!\n", __func__); nResult = drv2624_reg_read(pDRV2624, DRV2624_REG_MODE); if (nResult < 0) - goto err; + return nResult; mode = nResult & WORKMODE_MASK; - if (mode == MODE_WAVEFORM_SEQUENCER) - { + if (mode == MODE_WAVEFORM_SEQUENCER) { dev_dbg(pDRV2624->dev, "In sequence play, ignore stop\n"); return 0; } if (pDRV2624->mnVibratorPlaying == YES) { - dev_dbg(pDRV2624->dev, "%s\n", __func__); if (pDRV2624->mbIRQUsed) drv2624_disableIRQ(pDRV2624); - if (hrtimer_active(&pDRV2624->timer)) - hrtimer_cancel(&pDRV2624->timer); + if (hrtimer_active(&pDRV2624->haptics_timer)) + hrtimer_cancel(&pDRV2624->haptics_timer); nResult = drv2624_set_go_bit(pDRV2624, STOP); drv2624_set_stopflag(pDRV2624); } @@ -347,37 +312,43 @@ static int drv2624_stop(struct drv2624_data *pDRV2624) return nResult; } +#ifdef ANDROID_TIMED_OUTPUT +static int vibrator_get_time(struct timed_output_dev *dev) + { + struct drv2624_data *pDRV2624 = container_of(dev, struct drv2624_data, to_dev); + + if (hrtimer_active(&pDRV2624->haptics_timer)) { + ktime_t r = hrtimer_get_remaining(&pDRV2624->haptics_timer); + return ktime_to_ms(r); + } + + return 0; +} + static void vibrator_enable( struct timed_output_dev *dev, int value) { int nResult = 0; - struct drv2624_data *pDRV2624 = + struct drv2624_data *pDRV2624 = container_of(dev, struct drv2624_data, to_dev); dev_dbg(pDRV2624->dev, "%s, value=%d\n", __func__, value); mutex_lock(&pDRV2624->lock); - pDRV2624->mnWorkMode = WORK_IDLE; - if (g_logEnable) - dev_dbg(pDRV2624->dev, "%s, afer mnWorkMode=0x%x\n", - __func__, pDRV2624->mnWorkMode); + dev_dbg(pDRV2624->dev, "%s, afer mnWorkMode=0x%x\n", + __func__, pDRV2624->mnWorkMode); drv2624_stop(pDRV2624); if (value > 0) { - wake_lock(&pDRV2624->wklock); - if (g_logEnable) - dev_dbg(pDRV2624->dev, "wklock lock"); - - nResult = drv2624_change_mode(pDRV2624, MODE_RTP); + nResult = drv2624_change_mode(pDRV2624, DRV2624_RTP_MODE); if (nResult < 0) goto end; nResult = drv2624_set_go_bit(pDRV2624, GO); if (nResult >= 0) { value = (value > MAX_TIMEOUT) ? MAX_TIMEOUT : value; - pDRV2624->mnWorkMode |= WORK_VIBRATOR; - hrtimer_start(&pDRV2624->timer, + hrtimer_start(&pDRV2624->haptics_timer, ns_to_ktime((u64)value * NSEC_PER_MSEC), HRTIMER_MODE_REL); pDRV2624->mnVibratorPlaying = YES; @@ -387,46 +358,46 @@ static void vibrator_enable( struct timed_output_dev *dev, int value) } end: - if (nResult < 0) { - wake_unlock(&pDRV2624->wklock); - if (g_logEnable) - dev_dbg(pDRV2624->dev, "wklock unlock"); - } mutex_unlock(&pDRV2624->lock); } +#endif /* ANDROID_TIMED_OUTPUT */ static enum hrtimer_restart vibrator_timer_func(struct hrtimer *timer) { struct drv2624_data *pDRV2624 = - container_of(timer, struct drv2624_data, timer); + container_of(timer, struct drv2624_data, haptics_timer); dev_dbg(pDRV2624->dev, "%s\n", __func__); schedule_work(&pDRV2624->vibrator_work); + return HRTIMER_NORESTART; } +/** + * 1. Do work due to pDRV2624->mnWorkMode set before. + * 2. For WORK_EFFECTSEQUENCER, WORK_CALIBRATION and WORK_DIAGNOSTIC + * check the GO bit until the process in DRV2624 has completed. + * 3. For WORK_VIBRATOR, Stop DRV2624 directly. + **/ static void vibrator_work_routine(struct work_struct *work) { struct drv2624_data *pDRV2624 = container_of(work, struct drv2624_data, vibrator_work); - unsigned char mode = MODE_RTP; - unsigned char status; + unsigned char status; int nResult = 0; mutex_lock(&pDRV2624->lock); - if (g_logEnable) - dev_dbg(pDRV2624->dev, "%s, afer mnWorkMode=0x%x\n", - __func__, pDRV2624->mnWorkMode); + dev_dbg(pDRV2624->dev, "%s, afer mnWorkMode=0x%x\n", + __func__, pDRV2624->mnWorkMode); - if ((pDRV2624->mnWorkMode & WORK_IRQ) && pDRV2624->mbIRQUsed) { - nResult = drv2624_reg_read(pDRV2624,DRV2624_REG_STATUS); - if (nResult >= 0) - pDRV2624->mnIntStatus = nResult; - drv2624_disableIRQ(pDRV2624); + if (pDRV2624->mbIRQUsed) { + pDRV2624->mnIntStatus = drv2624_reg_read(pDRV2624,DRV2624_REG_STATUS); if (nResult < 0) goto err; + drv2624_disableIRQ(pDRV2624); + status = pDRV2624->mnIntStatus; dev_dbg(pDRV2624->dev, "%s, status=0x%x\n", __func__, pDRV2624->mnIntStatus); @@ -442,92 +413,24 @@ static void vibrator_work_routine(struct work_struct *work) if (status & PRG_ERR_MASK) dev_err(pDRV2624->dev, "ERROR, PRG error!!\n"); - - if (status & PROCESS_DONE_MASK) { - nResult = drv2624_reg_read(pDRV2624, DRV2624_REG_MODE); - if (nResult < 0) - goto err; - - mode = nResult & WORKMODE_MASK; - if (mode == MODE_CALIBRATION) - nResult = drv2624_get_calibration_result(pDRV2624, status); - else if (mode == MODE_DIAGNOSTIC) - nResult = drv2624_get_diag_result(pDRV2624, status); - else if (mode == MODE_WAVEFORM_SEQUENCER) - dev_dbg(pDRV2624->dev, - "Waveform Sequencer Playback finished\n"); - else if(mode == MODE_RTP) - dev_dbg(pDRV2624->dev, "RTP IRQ\n"); - } - - if ((mode != MODE_RTP) && (pDRV2624->mnVibratorPlaying == YES)) - drv2624_set_stopflag(pDRV2624); - - pDRV2624->mnWorkMode &= ~WORK_IRQ; } - if (pDRV2624->mnWorkMode & WORK_VIBRATOR) { + if (pDRV2624->mnWorkMode == DRV2624_RTP_MODE) { drv2624_stop(pDRV2624); - pDRV2624->mnWorkMode &= ~WORK_VIBRATOR; - } - - if (pDRV2624->mnWorkMode & WORK_EFFECTSEQUENCER) { - status = drv2624_reg_read(pDRV2624, DRV2624_REG_GO); - if ((status < 0) || (status == STOP) || !pDRV2624->mnVibratorPlaying) { - drv2624_stop(pDRV2624); - pDRV2624->mnWorkMode &= ~WORK_EFFECTSEQUENCER; - } else { - if (!hrtimer_active(&pDRV2624->timer)) { - if (g_logEnable) - dev_dbg(pDRV2624->dev, "will check GO bit after %d ms\n", POLL_GO_BIT_INTERVAL); - hrtimer_start(&pDRV2624->timer, - ns_to_ktime((u64)POLL_GO_BIT_INTERVAL * NSEC_PER_MSEC), HRTIMER_MODE_REL); - } - } - } - - if (pDRV2624->mnWorkMode & WORK_CALIBRATION) { - status = drv2624_reg_read(pDRV2624, DRV2624_REG_GO); - if ((status < 0) || (status == STOP) || !pDRV2624->mnVibratorPlaying) { - drv2624_stop(pDRV2624); - pDRV2624->mnWorkMode &= ~WORK_CALIBRATION; - if (status < 0) - goto err; - nResult = drv2624_reg_read(pDRV2624, DRV2624_REG_STATUS); - if (nResult >= 0) - nResult = drv2624_get_calibration_result(pDRV2624, nResult); - } else { - if (!hrtimer_active(&pDRV2624->timer)) { - if (g_logEnable) - dev_dbg(pDRV2624->dev, "will check GO bit after %d ms\n", POLL_GO_BIT_INTERVAL); - hrtimer_start(&pDRV2624->timer, - ns_to_ktime((u64)POLL_GO_BIT_INTERVAL * NSEC_PER_MSEC), HRTIMER_MODE_REL); - } - } - } - - if (pDRV2624->mnWorkMode & WORK_DIAGNOSTIC) { + } else if (pDRV2624->mnWorkMode == DRV2624_RAM_MODE) { status = drv2624_reg_read(pDRV2624, DRV2624_REG_GO); if ((status < 0) || (status == STOP) || !pDRV2624->mnVibratorPlaying) { drv2624_stop(pDRV2624); - pDRV2624->mnWorkMode &= ~WORK_DIAGNOSTIC; - if (status < 0) - goto err; - nResult = drv2624_reg_read(pDRV2624, DRV2624_REG_STATUS); - if (nResult >= 0) - nResult = drv2624_get_diag_result(pDRV2624, nResult); } else { - if (!hrtimer_active(&pDRV2624->timer)) { - if (g_logEnable) - dev_dbg(pDRV2624->dev, "will check GO bit after %d ms\n", POLL_GO_BIT_INTERVAL); - hrtimer_start(&pDRV2624->timer, - ns_to_ktime((u64)POLL_GO_BIT_INTERVAL * NSEC_PER_MSEC), HRTIMER_MODE_REL); + if (!hrtimer_active(&pDRV2624->haptics_timer)) { + dev_dbg(pDRV2624->dev, "will check GO bit after %d ms\n", GO_BIT_CHECK_INTERVAL); + hrtimer_start(&pDRV2624->haptics_timer, + ns_to_ktime((u64)GO_BIT_CHECK_INTERVAL * NSEC_PER_MSEC), HRTIMER_MODE_REL); } } } err: - mutex_unlock(&pDRV2624->lock); } @@ -535,117 +438,185 @@ static int dev_auto_calibrate(struct drv2624_data *pDRV2624) { int nResult = 0; - dev_info(pDRV2624->dev, "%s\n", __func__); - wake_lock(&pDRV2624->wklock); - if (g_logEnable) - dev_dbg(pDRV2624->dev, "wklock lock"); + dev_info(pDRV2624->dev, "%s enter!\n", __func__); + + /* Set MODE register to Auto Level Calibration Routine + * and choose Trigger Function Internal */ + + + nResult = drv2624_reg_write(pDRV2624, + DRV2624_REG_MODE, + DRV2624_CALIBRATION_MODE_CFG); + if (nResult < 0) + goto end; nResult = drv2624_change_mode(pDRV2624, MODE_CALIBRATION); + + if(nResult < 0) + { + dev_err(pDRV2624->dev, "%s: change mode Done nResult = %d\n", + __func__, nResult); + goto end; + } + + nResult = drv2624_set_bits(pDRV2624, + AUTO_CAL_TIME_REG, + AUTO_CAL_TIME_MASK, + AUTO_CAL_TIME_AUTO_TRIGGER); if (nResult < 0) + { + dev_err(pDRV2624->dev, "%s: set bits Done nResult = %d\n", + __func__, nResult); goto end; + } nResult = drv2624_set_go_bit(pDRV2624, GO); if (nResult < 0) + { + dev_err(pDRV2624->dev, "%s: calibrate go bit Done nResult = %d\n", + __func__, nResult); goto end; - - dev_dbg(pDRV2624->dev, "calibration start\n"); + } + msleep(1000); /* waiting auto calibration finished */ pDRV2624->mnVibratorPlaying = YES; - if (!pDRV2624->mbIRQUsed) { - pDRV2624->mnWorkMode |= WORK_CALIBRATION; - schedule_work(&pDRV2624->vibrator_work); - } + return nResult; +end: + dev_err(pDRV2624->dev, "%s: Calibtion Done nResult = %d\n", + __func__, nResult); + return nResult; +} + +static int drv2624_get_calibration_result(struct drv2624_data *pDRV2624) +{ + int nResult, cal_bemf, cal_comp, cal_gain; + + dev_dbg(pDRV2624->dev, "%s: enter!\n", __func__); + + nResult = drv2624_reg_read(pDRV2624,DRV2624_REG_STATUS); + if (nResult < 0) + goto end; + pDRV2624->mnIntStatus = nResult; + + cal_comp = drv2624_reg_read(pDRV2624, DRV2624_REG_CAL_COMP); + if (cal_comp < 0) + goto end; + pDRV2624->mAutoCalResult.mnCalComp = cal_comp; + + cal_bemf = drv2624_reg_read(pDRV2624, DRV2624_REG_CAL_BEMF); + if (cal_bemf < 0) + goto end; + pDRV2624->mAutoCalResult.mnCalBemf = cal_bemf; + + cal_gain = drv2624_reg_read(pDRV2624, DRV2624_REG_LOOP_CONTROL) & BEMFGAIN_MASK; + if (cal_gain < 0) + goto end; + pDRV2624->mAutoCalResult.mnCalGain = cal_gain; end: - if (nResult < 0) { - wake_unlock(&pDRV2624->wklock); - if (g_logEnable) - dev_dbg(pDRV2624->dev, "wklock unlock"); - } + dev_dbg(pDRV2624->dev, "%s: nResult = %d\n", __func__, nResult); + return nResult; +} + +/*show calibrtion*/ +static ssize_t +drv2624_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int nResult = 0; + struct drv2624_data *pDRV2624 = dev_get_drvdata(dev); + + //return snprintf(buf, 100 ,"Cal_Result: 0x%x, CalComp: 0x%x, CalBemf: 0x%x, CalGain: 0x%x\n" + //, nResult, cal_comp, cal_bemf, cal_gain); + + nResult = drv2624_get_calibration_result(pDRV2624); + if (nResult < 0) + goto end; + + dev_dbg(pDRV2624->dev, + "%s: Cal_Result: 0x%x, CalComp: 0x%x, CalBemf: 0x%x, CalGain: 0x%x\n", + __func__, pDRV2624->mnIntStatus, pDRV2624->mAutoCalResult.mnCalComp, + pDRV2624->mAutoCalResult.mnCalBemf, pDRV2624->mAutoCalResult.mnCalGain); + + return snprintf(buf, 100 ,"Cal_Result: 0x%x, CalComp: 0x%x, CalBemf: 0x%x, CalGain: 0x%x\n", + pDRV2624->mnIntStatus, pDRV2624->mAutoCalResult.mnCalComp, + pDRV2624->mAutoCalResult.mnCalBemf, pDRV2624->mAutoCalResult.mnCalGain); +end: return nResult; } -static int dev_run_diagnostics(struct drv2624_data *pDRV2624) +/* store calibration*/ +static ssize_t drv2624_store( + struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) { int nResult = 0; + struct drv2624_data *tdev = dev_get_drvdata(dev); + + if ((buf[0] == 'C') && (buf[1] == 'A') && + (buf[2] == 'L') && (buf[3] == 'I') && (buf[4] == 'B')) { + nResult = dev_auto_calibrate(tdev); + } else if ((buf[0] == 'D') && (buf[1] == 'I') + && (buf[2] == 'A') && (buf[3] == 'G')) { + nResult = dev_run_diagnostics(tdev); + } + + return size; +} + +static DEVICE_ATTR(cali, 0664, drv2624_show, drv2624_store); + +static int dev_run_diagnostics(struct drv2624_data *pDRV2624) +{ + int nResult = 0, value = 0; dev_info(pDRV2624->dev, "%s\n", __func__); - wake_lock(&pDRV2624->wklock); - if (g_logEnable) - dev_dbg(pDRV2624->dev, "wklock lock"); - nResult = drv2624_change_mode(pDRV2624, MODE_DIAGNOSTIC); - if (nResult < 0) + nResult = drv2624_change_mode(pDRV2624, DRV2624_DIAG_MODE); + if (nResult < 0) goto end; nResult = drv2624_set_go_bit(pDRV2624, GO); if (nResult < 0) goto end; - dev_dbg(pDRV2624->dev, "Diag start\n"); + dev_dbg(pDRV2624->dev, "%s: Diag start\n", __func__); pDRV2624->mnVibratorPlaying = YES; - if (!pDRV2624->mbIRQUsed) { - pDRV2624->mnWorkMode |= WORK_DIAGNOSTIC; - schedule_work(&pDRV2624->vibrator_work); - } - + value = drv2624_reg_read(pDRV2624, DRV2624_REG_STATUS); + if (value < 0) { + return value; + } + drv2624_get_diag_result(pDRV2624, value); end: - if (nResult < 0) { - wake_unlock(&pDRV2624->wklock); - if (g_logEnable) - dev_dbg(pDRV2624->dev, "wklock unlock"); - } return nResult; } +/** + * Play Waveform sequence stored in DRV2624_REG_SEQUENCER_1 + * + **/ static int drv2624_playEffect(struct drv2624_data *pDRV2624) { int nResult = 0; dev_info(pDRV2624->dev, "%s\n", __func__); - wake_lock(&pDRV2624->wklock); - if (g_logEnable) - dev_dbg(pDRV2624->dev, "wklock lock"); - nResult = drv2624_change_mode(pDRV2624, MODE_WAVEFORM_SEQUENCER); - if (nResult < 0) + nResult = drv2624_change_mode(pDRV2624, DRV2624_WAVE_SEQ_MODE); + if (nResult < 0) goto end; nResult = drv2624_set_go_bit(pDRV2624, GO); - if (nResult < 0) + if (nResult < 0) goto end; dev_dbg(pDRV2624->dev, "effects start\n"); pDRV2624->mnVibratorPlaying = YES; if (!pDRV2624->mbIRQUsed) { - pDRV2624->mnWorkMode |= WORK_EFFECTSEQUENCER; schedule_work(&pDRV2624->vibrator_work); } end: - if (nResult < 0) { - wake_unlock(&pDRV2624->wklock); - dev_dbg(pDRV2624->dev, "wklock unlock"); - } - return nResult; -} - -static int drv2624_config_waveform(struct drv2624_data *pDRV2624, - struct drv2624_wave_setting *psetting) -{ - int nResult = 0; - int value = 0; - - nResult = drv2624_reg_write(pDRV2624, - DRV2624_REG_MAIN_LOOP, psetting->mnLoop & 0x07); - if (nResult >= 0) { - value |= ((psetting->mnInterval & 0x01) << INTERVAL_SHIFT); - value |= (psetting->mnScale & 0x03); - nResult = drv2624_set_bits(pDRV2624, DRV2624_REG_CONTROL2, - INTERVAL_MASK | SCALE_MASK, value); - } return nResult; } @@ -661,7 +632,7 @@ static int drv2624_set_waveform(struct drv2624_data *pDRV2624, for (i = 0; i < DRV2624_SEQUENCER_SIZE; i++) { len++; if (pSequencer->msWaveform[i].mnEffect != 0) { - if (i < 4) + if (i < 4) loop[0] |= (pSequencer->msWaveform[i].mnLoop << (2*i)); else loop[1] |= (pSequencer->msWaveform[i].mnLoop << (2*(i-4))); @@ -673,10 +644,10 @@ static int drv2624_set_waveform(struct drv2624_data *pDRV2624, if (len == 1) nResult = drv2624_reg_write(pDRV2624, DRV2624_REG_SEQUENCER_1, 0); - else + else nResult = drv2624_bulk_write(pDRV2624, DRV2624_REG_SEQUENCER_1, effects, len); - if (nResult < 0) { + if (nResult < 0) { dev_err(pDRV2624->dev, "sequence error\n"); goto end; } @@ -689,7 +660,6 @@ static int drv2624_set_waveform(struct drv2624_data *pDRV2624, } end: - return nResult; } @@ -708,6 +678,32 @@ static int fw_chksum(const struct firmware *fw) return sum; } +static int drv2624_get_effect_timems(struct drv2624_data *pDRV2624, unsigned char effect) +{ + unsigned char *fw = &pDRV2624->mnFwRam[0]; + u16 header_address, tmp; + u16 address = 0; + unsigned char effect_repeats = 0; + unsigned int effect_size = 0; + int i = 0; + unsigned int ticks = 0; + unsigned int playback_interval = 0; + + effect++; + header_address = (effect - 1) * 3 + 1; + tmp = fw[header_address]; + address = tmp << 8 | fw[header_address+1]; + effect_repeats = (fw[header_address+2] & 0xe0) >> 5; + effect_size = fw[header_address+2] & 0x1f; + + for (i = 0; i< effect_size/2; i++) { + ticks += fw[address + (i * 2) + 1]; + } + playback_interval = (pDRV2624->msWaveformSetting.mnInterval == INTERVAL_5MS) ? 5 : 1; + + return ticks * (effect_repeats + 1) * playback_interval; +} + /* drv2624_firmware_load: * This function is called by the * request_firmware_nowait function as soon @@ -729,21 +725,23 @@ static void drv2624_firmware_load(const struct firmware *fw, void *context) if (fw != NULL) { pBuf = fw->data; size = fw->size; - if (size > 1024) + if (size > 1024) { dev_err(pDRV2624->dev,"%s, ERROR!! firmware size %d too big\n", __func__, size); - else { + } else { memcpy(&(pDRV2624->fw_header), pBuf, sizeof(struct drv2624_fw_header)); if ((pDRV2624->fw_header.fw_magic != DRV2624_MAGIC) || (pDRV2624->fw_header.fw_size != size) - || (pDRV2624->fw_header.fw_chksum != fw_chksum(fw))) + || (pDRV2624->fw_header.fw_chksum != fw_chksum(fw))) { dev_err(pDRV2624->dev, - "%s, ERROR!! firmware not right:Magic=0x%x, Size=%d, chksum=0x%x\n", + "%s, ERROR!! firmware not right:Magic=0x%x, Size=%d, chksum=0x%x\n", __func__, pDRV2624->fw_header.fw_magic, pDRV2624->fw_header.fw_size, pDRV2624->fw_header.fw_chksum); - else { + } else { dev_info(pDRV2624->dev,"%s, firmware good\n", __func__); + //pDRV2624->play.effect_count = pDRV2624->fw_header.fw_effCount; + pBuf += sizeof(struct drv2624_fw_header); drv2624_reg_write(pDRV2624, DRV2624_REG_RAM_ADDR_UPPER, 0); drv2624_reg_write(pDRV2624, DRV2624_REG_RAM_ADDR_LOWER, 0); @@ -751,6 +749,11 @@ static void drv2624_firmware_load(const struct firmware *fw, void *context) fwsize = size - sizeof(struct drv2624_fw_header); for(i = 0; i < fwsize; i++) drv2624_reg_write(pDRV2624, DRV2624_REG_RAM_DATA, pBuf[i]); + + memset(&pDRV2624->mnFwRam[0], 0, DRV2624_RAM_SIZE); + memcpy(&pDRV2624->mnFwRam[0], pBuf, fwsize); + for (i = 0; i < pDRV2624->fw_header.fw_effCount; i++) + pDRV2624->mnEffectTimems[i] = drv2624_get_effect_timems(pDRV2624, i); } } } else @@ -758,7 +761,7 @@ static void drv2624_firmware_load(const struct firmware *fw, void *context) release_firmware(fw); - mutex_unlock(&pDRV2624->lock); + mutex_unlock(&pDRV2624->lock); } static int drv2624_file_open(struct inode *inode, struct file *file) @@ -873,100 +876,6 @@ static ssize_t drv2624_file_read(struct file* filp, char* buff, size_t length, l } break; - case HAPTIC_CMDID_CONFIG_WAVEFORM: - if (length == sizeof(struct drv2624_wave_setting)) { - struct drv2624_wave_setting wavesetting; - - value = drv2624_reg_read(pDRV2624, DRV2624_REG_CONTROL2); - wavesetting.mnLoop = drv2624_reg_read(pDRV2624, DRV2624_REG_MAIN_LOOP)&0x07; - wavesetting.mnInterval = ((value&INTERVAL_MASK)>>INTERVAL_SHIFT); - wavesetting.mnScale = (value&SCALE_MASK); - nResult = copy_to_user(buff, &wavesetting, length); - if (0 != nResult) { - /* Failed to copy all the data, exit */ - dev_err(pDRV2624->dev, "copy to user fail %d\n", nResult); - } - } - break; - - case HAPTIC_CMDID_SET_SEQUENCER: - if (length == sizeof(struct drv2624_waveform_sequencer)) { - struct drv2624_waveform_sequencer sequencer; - unsigned char effects[DRV2624_SEQUENCER_SIZE] = {0}; - unsigned char loop[2] = {0}; - int i = 0; - - nResult = drv2624_bulk_read(pDRV2624, DRV2624_REG_SEQUENCER_1, - effects, DRV2624_SEQUENCER_SIZE); - if (nResult < 0) - break; - - nResult = drv2624_bulk_read(pDRV2624, DRV2624_REG_SEQ_LOOP_1, loop, 2); - if (nResult < 0) - break; - - for(i = 0; i < DRV2624_SEQUENCER_SIZE; i++){ - sequencer.msWaveform[i].mnEffect = effects[i]; - if(i < 4) - sequencer.msWaveform[i].mnLoop = ((loop[0]>>(2*i))&0x03); - else - sequencer.msWaveform[i].mnLoop = ((loop[1]>>(2*(i-4)))&0x03); - } - - nResult = copy_to_user(buff, &sequencer, length); - if (0 != nResult) { - /* Failed to copy all the data, exit */ - dev_err(pDRV2624->dev, "copy to user fail %d\n", nResult); - } - } - break; - - case HAPTIC_CMDID_READ_FIRMWARE: - if (length > 0) { - int i = 0; - - p_kBuf = (unsigned char *)kzalloc(length, GFP_KERNEL); - if(p_kBuf != NULL){ - nResult = drv2624_reg_write(pDRV2624, DRV2624_REG_RAM_ADDR_UPPER, pDRV2624->mRAMMSB); - if (nResult < 0) - break; - nResult = drv2624_reg_write(pDRV2624, DRV2624_REG_RAM_ADDR_LOWER, pDRV2624->mRAMLSB); - if (nResult < 0) - break; - - for (i = 0; i < length; i++) { - nResult = drv2624_reg_read(pDRV2624,DRV2624_REG_RAM_DATA); - if (nResult < 0) - break; - p_kBuf[i] = nResult; - } - if(0 > nResult) - break; - - nResult = copy_to_user(buff, p_kBuf, length); - if (0 != nResult) { - /* Failed to copy all the data, exit */ - dev_err(pDRV2624->dev, "copy to user fail %d\n", nResult); - } - - kfree(p_kBuf); - } else { - dev_err(pDRV2624->dev, "read no mem\n"); - nResult = -ENOMEM; - } - } - break; - - case HAPTIC_CMDID_REGLOG_ENABLE: - if (length == 1) { - nResult = copy_to_user(buff, &g_logEnable, 1); - if (0 != nResult) { - /* Failed to copy all the data, exit */ - dev_err(pDRV2624->dev, "copy to user fail %d\n", nResult); - } - } - break; - default: pDRV2624->mnFileCmd = 0; break; @@ -1004,7 +913,7 @@ static ssize_t drv2624_file_write(struct file* filp, const char* buff, size_t le if (len == 2) pDRV2624->mnCurrentReg = p_kBuf[1]; else - dev_err(pDRV2624->dev, " read cmd len %d err\n", len); + dev_err(pDRV2624->dev, " read cmd len %lu err\n", (unsigned long)len); break; case HAPTIC_CMDID_REG_WRITE: @@ -1013,14 +922,8 @@ static ssize_t drv2624_file_write(struct file* filp, const char* buff, size_t le else if ((len - 1) > 2) nResult = drv2624_bulk_write(pDRV2624, p_kBuf[1], &p_kBuf[2], len-2); else - dev_err(pDRV2624->dev, "%s, reg_write len %d error\n", __func__, len); - break; - - case HAPTIC_CMDID_REG_SETBIT: - if (len == 4) - nResult = drv2624_set_bits(pDRV2624, p_kBuf[1], p_kBuf[2], p_kBuf[3]); - else - dev_err(pDRV2624->dev, "setbit len %d error\n", len); + dev_err(pDRV2624->dev, "%s, reg_write len %lu error\n", + __func__, (unsigned long)len); break; case HAPTIC_CMDID_RUN_DIAG: @@ -1032,90 +935,319 @@ static ssize_t drv2624_file_write(struct file* filp, const char* buff, size_t le drv2624_enableIRQ(pDRV2624, NO); break; - case HAPTIC_CMDID_UPDATE_FIRMWARE: + case HAPTIC_CMDID_RUN_CALIBRATION: nResult = drv2624_stop(pDRV2624); if (nResult < 0) break; - nResult = request_firmware_nowait(THIS_MODULE, + + nResult = dev_auto_calibrate(pDRV2624); + if ((nResult >= 0) && pDRV2624->mbIRQUsed) + drv2624_enableIRQ(pDRV2624, NO); + break; + + case HAPTIC_SET_CALIBRATION_RESULT: + drv2624_reg_write(pDRV2624, DRV2624_REG_CAL_COMP, p_kBuf[1]); + drv2624_reg_write(pDRV2624, DRV2624_REG_CAL_BEMF, p_kBuf[2]); + drv2624_reg_write(pDRV2624, DRV2624_REG_LOOP_CONTROL, p_kBuf[3]); + break; + + default: + dev_err(pDRV2624->dev, "%s, unknown cmd\n", __func__); + break; + } + +err: + if (p_kBuf != NULL) + kfree(p_kBuf); + + mutex_unlock(&pDRV2624->lock); + + return len; +} + +static void upload_periodic_work_routine(struct work_struct *work) +{ + struct drv2624_data *pDRV2624 = + container_of(work, struct drv2624_data, upload_periodic_work); + int nResult = 0; + + mutex_lock(&pDRV2624->lock); + nResult = drv2624_stop(pDRV2624); + if (nResult < 0) { + return; + } + + nResult = drv2624_set_waveform(pDRV2624, &pDRV2624->msWaveformSequencer); + if (nResult < 0) + dev_err(pDRV2624->dev, "Configurate predefined effect %d failed, nResult=%d\n", + pDRV2624->msWaveformSequencer.msWaveform[0].mnEffect, nResult); + dev_dbg(pDRV2624->dev, "Configurate predefined effect success, effect=%d\n", + pDRV2624->msWaveformSequencer.msWaveform[0].mnEffect); + + mutex_unlock(&pDRV2624->lock); +} + +static int drv2624_haptics_upload_effect(struct input_dev *dev, + struct ff_effect *effect, struct ff_effect *old) +{ + struct drv2624_data *pDRV2624 = input_get_drvdata(dev); + struct drv2624_constant_playinfo *play = &pDRV2624->play; + u16 data[CUSTOM_DATA_LEN]; + int nResult = 0; + ktime_t rem; + s64 time_us; + uint time_ms = 0; + + pr_info("%s enter function \n", __func__); + mutex_lock(&pDRV2624->lock); + + /* waiting last vibration to end */ + if (hrtimer_active(&pDRV2624->haptics_timer)) { + rem = hrtimer_get_remaining(&pDRV2624->haptics_timer); + time_us = ktime_to_us(rem); + dev_info(pDRV2624->dev, + "%s: waiting for playing finished: %lld us\n", + __func__, time_us); + usleep_range(time_us, time_us + 100); + } + + pDRV2624->mnEffectType = effect->type; + dev_info(pDRV2624->dev, "%s: mnEffectType: %d\n", + __func__, pDRV2624->mnEffectType); + + switch (pDRV2624->mnEffectType) { + case FF_CONSTANT: + play->length = effect->replay.length; + play->rtp_input = effect->u.constant.level; + pDRV2624->mnWorkMode = DRV2624_RTP_MODE; + dev_info(pDRV2624->dev, "%s: length(%d), level(%d)\n", + __func__, play->length, play->rtp_input); + break; + + case FF_PERIODIC: +#ifdef NEED_RELOAD_FIRMWARE + if (pDRV2624->fw_header.fw_magic == 0) { + nResult = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, "drv2624.bin", pDRV2624->dev, GFP_KERNEL, pDRV2624, drv2624_firmware_load); - break; + dev_info(pDRV2624->dev,"%s:request_firmware_nowait nResult=%d\n", __func__, nResult); - case HAPTIC_CMDID_READ_FIRMWARE: - if (len == 3) { - pDRV2624->mRAMMSB = buff[1]; - pDRV2624->mRAMLSB = buff[2]; - } else - dev_err(pDRV2624->dev, "%s, read fw len error\n", __func__); - break; + } +#endif - case HAPTIC_CMDID_RUN_CALIBRATION: - nResult = drv2624_stop(pDRV2624); - if (nResult < 0) + if (effect->u.periodic.waveform != FF_CUSTOM) { + dev_err(pDRV2624->dev, "Only accept custom waveforms\n"); + nResult = -EINVAL; break; + } - nResult = dev_auto_calibrate(pDRV2624); - if ((nResult >= 0) && pDRV2624->mbIRQUsed) - drv2624_enableIRQ(pDRV2624, NO); - break; + if (copy_from_user(data, effect->u.periodic.custom_data, + sizeof(u16) * CUSTOM_DATA_LEN)) { + nResult = -EFAULT; + break; + } - case HAPTIC_CMDID_CONFIG_WAVEFORM: - if (len == (1 + sizeof(struct drv2624_wave_setting))) { - struct drv2624_wave_setting wavesetting; + play->effect_id = data[CUSTOM_DATA_EFFECT_IDX]; + play->magnitude = effect->u.periodic.magnitude; + pDRV2624->mnWorkMode = DRV2624_RAM_MODE; + dev_dbg(pDRV2624->dev, "%s: effect_id = %d, magnitude = %d\n", + __func__, play->effect_id, play->magnitude); - memcpy(&wavesetting, &p_kBuf[1], sizeof(struct drv2624_wave_setting)); - nResult = drv2624_config_waveform(pDRV2624, &wavesetting); - } else - dev_dbg(pDRV2624->dev, "pass cmd, prepare for read\n"); - break; + if ((play->effect_id < 0) || + (play->effect_id > pDRV2624->fw_header.fw_effCount)) { + dev_err(pDRV2624->dev, "%s: overflow effect_id = %d, max_effect_id = %d\n", + __func__, play->effect_id, pDRV2624->fw_header.fw_effCount); + nResult = -EINVAL; + break; + } - case HAPTIC_CMDID_SET_SEQUENCER: - if (len == (1 + sizeof(struct drv2624_waveform_sequencer))) { - struct drv2624_waveform_sequencer sequencer; + pr_info("%s next upload to use effect \n", __func__); + memset(&pDRV2624->msWaveformSequencer, 0, sizeof(struct drv2624_waveform_sequencer)); + pDRV2624->msWaveformSequencer.msWaveform[0].mnEffect = data[CUSTOM_DATA_EFFECT_IDX]; + pDRV2624->msWaveformSequencer.msWaveform[0].mnLoop = 0; + pDRV2624->msWaveformSequencer.msWaveform[1].mnEffect = 0; + pDRV2624->msWaveformSequencer.msWaveform[1].mnLoop = 0; + + dev_dbg(pDRV2624->dev, "upload to use effect %d\n", + data[CUSTOM_DATA_EFFECT_IDX]); + + time_ms = pDRV2624->mnEffectTimems[data[CUSTOM_DATA_EFFECT_IDX] - 1]; + dev_dbg(pDRV2624->dev, "effect playing time_ms %d\n", time_ms); + + data[CUSTOM_DATA_TIMEOUT_SEC_IDX] = + time_ms / MSEC_PER_SEC; + data[CUSTOM_DATA_TIMEOUT_MSEC_IDX] = + time_ms % MSEC_PER_SEC; + + /* + * Copy the custom data contains the play length back to + * userspace so that the userspace client can wait and + * send stop playing command after it's done. + */ + if (copy_to_user(effect->u.periodic.custom_data, data, + sizeof(u16) * CUSTOM_DATA_LEN)) { + pr_info("%s copy to user failed \n", __func__); + nResult = -EFAULT; + break; + } - memcpy(&sequencer, &p_kBuf[1], sizeof(struct drv2624_waveform_sequencer)); - nResult = drv2624_set_waveform(pDRV2624, &sequencer); - } else - dev_dbg(pDRV2624->dev, "pass cmd, prepare for read\n"); + schedule_work(&pDRV2624->upload_periodic_work); break; + default: + dev_err(pDRV2624->dev, "Unsupported effect type: %d\n", + effect->type); + break; + } - case HAPTIC_CMDID_PLAY_EFFECT_SEQUENCE: - nResult = drv2624_stop(pDRV2624); - if (nResult < 0) + mutex_unlock(&pDRV2624->lock); + dev_info(pDRV2624->dev, "%s exit \n", __func__); + + return nResult; +} + +static void haptics_playback_work_routine(struct work_struct *work) +{ + int nResult = 0; + struct drv2624_data *pDRV2624 = + container_of(work, struct drv2624_data, haptics_playback_work); + + mutex_lock(&pDRV2624->lock); + + dev_dbg(pDRV2624->dev, "%s enter effect.lenth(%d) \n", + __func__, pDRV2624->play.length); + + nResult = drv2624_stop(pDRV2624); + if (nResult < 0) { + dev_err(pDRV2624->dev, "%s: stop faild!\n", __func__); + goto end; + } + + switch(pDRV2624->mnEffectType) { + case FF_PERIODIC: + nResult = drv2624_stop(pDRV2624); + if (nResult < 0) + break; + nResult = drv2624_playEffect(pDRV2624); + if ((nResult >= 0) && pDRV2624->mbIRQUsed) + drv2624_enableIRQ(pDRV2624, NO); break; - nResult = drv2624_playEffect(pDRV2624); - if ((nResult >= 0) && pDRV2624->mbIRQUsed) - drv2624_enableIRQ(pDRV2624, NO); - break; + case FF_CONSTANT: + drv2624_stop(pDRV2624); + nResult = drv2624_change_mode(pDRV2624, DRV2624_RTP_MODE); + if (nResult < 0){ + dev_dbg(pDRV2624->dev, + "%s: change_mode nResult = %d\n", + __func__, nResult); + break; + } - case HAPTIC_CMDID_STOP: - nResult = drv2624_stop(pDRV2624); - break; + nResult = drv2624_reg_write(pDRV2624, DRV2624_REG_RTP_INPUT, 0x7f); + if (nResult < 0) + break; - case HAPTIC_CMDID_REGLOG_ENABLE: - if (len == 2) - g_logEnable = p_kBuf[1]; - break; + nResult = drv2624_set_go_bit(pDRV2624, GO); + if (nResult < 0) + break; - default: - dev_err(pDRV2624->dev, "%s, unknown cmd\n", __func__); - break; + pDRV2624->mnVibratorPlaying = YES; + + if (pDRV2624->mbIRQUsed) + nResult = drv2624_enableIRQ(pDRV2624, YES); + break; + + default: + dev_info(pDRV2624->dev, "Unsupported effect type: %d\n", + pDRV2624->mnEffectType); + break; } -err: - if (p_kBuf != NULL) - kfree(p_kBuf); + if (pDRV2624->play.length != 0) { + hrtimer_start(&pDRV2624->haptics_timer, + ns_to_ktime(pDRV2624->play.length * NSEC_PER_MSEC), + HRTIMER_MODE_REL); + } - mutex_unlock(&pDRV2624->lock); +end: + mutex_unlock(&pDRV2624->lock); +} - return len; +static int drv2624_haptics_playback(struct input_dev *dev, int effect_id, int val) +{ + struct drv2624_data *pDRV2624 = input_get_drvdata(dev); + int nResult = 0; + + dev_dbg(pDRV2624->dev, "%s: mnEffectType(%d) WorkMode(%d)\n", + __func__, pDRV2624->mnEffectType, pDRV2624->mnWorkMode); + + if ((pDRV2624->mnEffectType == FF_CONSTANT) && + (pDRV2624->mnWorkMode == DRV2624_RTP_MODE)) { + if(hrtimer_active(&pDRV2624->haptics_timer)){ + hrtimer_cancel(&pDRV2624->haptics_timer); + } + schedule_work(&pDRV2624->haptics_playback_work); + } else if ((pDRV2624->mnEffectType == FF_PERIODIC) && + (pDRV2624->mnWorkMode == DRV2624_RAM_MODE)){ + schedule_work(&pDRV2624->haptics_playback_work); + } else { + dev_err(pDRV2624->dev, "%s: effect_type(%d) not supported!\n", + __func__, pDRV2624->mnEffectType); + } + + return nResult; +} + +static int drv2624_haptics_erase(struct input_dev *dev, int effect_id) +{ + struct drv2624_data *pDRV2624 = input_get_drvdata(dev); + int nResult = 0; + + mutex_lock(&pDRV2624->lock); + nResult = drv2624_stop(pDRV2624); + if (nResult < 0) + dev_err(pDRV2624->dev, "failed to stop vibrator: %d\n", nResult); + mutex_unlock(&pDRV2624->lock); + + return nResult; +} +static void haptics_set_gain_work_routine(struct work_struct *work) +{ + int nResult; + struct drv2624_data *pDRV2624 = + container_of(work, struct drv2624_data, haptics_set_gain_work); + struct drv2624_constant_playinfo *play = &pDRV2624->play; + + mutex_lock(&pDRV2624->lock); + nResult = drv2624_reg_write(pDRV2624, DRV2624_REG_RTP_INPUT, play->rtp_input); + if (nResult < 0) + dev_err(pDRV2624->dev, "Configurate RTP_INPUT failed, nResult=%d\n", + nResult); + mutex_unlock(&pDRV2624->lock); +} + +/* NOTE: gain range: 0 ~ 0x7f*/ +static void drv2624_haptics_set_gain(struct input_dev *dev, u16 gain) +{ + struct drv2624_data *pDRV2624 = input_get_drvdata(dev); + struct drv2624_constant_playinfo *play = &pDRV2624->play; + + if (gain == 0) + return; + else if (gain > 0x7f) + gain = 0x7f; + dev_dbg(pDRV2624->dev, "drv2624_haptics_set_gain, gain=%d\n", gain); + play->rtp_input = (gain - LIGHT_MAGNITUDE) * 255 / (STRONG_MAGNITUDE - LIGHT_MAGNITUDE); + //play->rtp_input = gain; + dev_dbg(pDRV2624->dev, "upload constant effect, rtp_input=%d\n", play->rtp_input); + dev_dbg(pDRV2624->dev, "enter drv264_reg_write rtp_input\n"); + schedule_work(&pDRV2624->haptics_set_gain_work); } + static struct file_operations fops = { .owner = THIS_MODULE, @@ -1132,11 +1264,12 @@ static struct miscdevice drv2624_misc = .name = HAPTICS_DEVICE_NAME, .fops = &fops, }; - + static int Haptics_init(struct drv2624_data *pDRV2624) { int nResult = 0; +#ifdef ANDROID_TIMED_OUTPUT pDRV2624->to_dev.name = "vibrator"; pDRV2624->to_dev.get_time = vibrator_get_time; pDRV2624->to_dev.enable = vibrator_enable; @@ -1146,6 +1279,7 @@ static int Haptics_init(struct drv2624_data *pDRV2624) dev_err(pDRV2624->dev, "drv2624: fail to create timed output dev\n"); return nResult; } +#endif /* ANDROID_TIMED_OUTPUT */ nResult = misc_register(&drv2624_misc); if (nResult) { @@ -1153,24 +1287,34 @@ static int Haptics_init(struct drv2624_data *pDRV2624) return nResult; } - hrtimer_init(&pDRV2624->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - pDRV2624->timer.function = vibrator_timer_func; - INIT_WORK(&pDRV2624->vibrator_work, vibrator_work_routine); + nResult = device_create_file(pDRV2624->dev, &dev_attr_cali); + if (nResult < 0) { + dev_info(pDRV2624->dev, "sys file creation failed nResult: %d\n", nResult); + return nResult; + } - wake_lock_init(&pDRV2624->wklock, WAKE_LOCK_SUSPEND, "vibrator"); + hrtimer_init(&pDRV2624->haptics_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + pDRV2624->haptics_timer.function = vibrator_timer_func; + + INIT_WORK(&pDRV2624->vibrator_work, vibrator_work_routine); + INIT_WORK(&pDRV2624->upload_periodic_work, upload_periodic_work_routine); + INIT_WORK(&pDRV2624->haptics_playback_work, haptics_playback_work_routine); + INIT_WORK(&pDRV2624->haptics_set_gain_work, haptics_set_gain_work_routine); mutex_init(&pDRV2624->lock); return 0; } -static void dev_init_platform_data(struct drv2624_data *pDRV2624) +static void drv2624_init(struct drv2624_data *pDRV2624) { struct drv2624_platform_data *pDrv2624Platdata = &pDRV2624->msPlatData; struct actuator_data actuator = pDrv2624Platdata->msActuator; unsigned char value_temp = 0; unsigned char mask_temp = 0; + struct drv2624_wave_setting wavesetting; + unsigned char value = 0; - drv2624_set_bits(pDRV2624, + drv2624_set_bits(pDRV2624, DRV2624_REG_MODE, PINFUNC_MASK, (PINFUNC_INT<mnLoop << LOOP_SHIFT); } - if (value_temp != 0) - drv2624_set_bits(pDRV2624, DRV2624_REG_CONTROL1, - mask_temp|AUTOBRK_OK_MASK, value_temp|AUTOBRK_OK_ENABLE); + drv2624_set_bits(pDRV2624, DRV2624_REG_CONTROL1, + mask_temp|AUTOBRK_OK_MASK, value_temp|AUTOBRK_OK_ENABLE); value_temp = 0; if (actuator.mnActuatorType == ERM) @@ -1211,18 +1354,24 @@ static void dev_init_platform_data(struct drv2624_data *pDRV2624) if (actuator.mnActuatorType == LRA) { unsigned char DriveTime = 5*(1000 - actuator.mnLRAFreq)/actuator.mnLRAFreq; unsigned short openLoopPeriod = - (unsigned short)((unsigned int)1000000000 / (24619 * actuator.mnLRAFreq)); + (unsigned short)((unsigned int)1000000000 / (24619 * actuator.mnLRAFreq)); - if (actuator.mnLRAFreq < 125) + if (actuator.mnLRAFreq < 125) DriveTime |= (MINFREQ_SEL_45HZ << MINFREQ_SEL_SHIFT); drv2624_set_bits(pDRV2624, DRV2624_REG_DRIVE_TIME, DRIVE_TIME_MASK | MINFREQ_SEL_MASK, DriveTime); drv2624_set_bits(pDRV2624, DRV2624_REG_OL_PERIOD_H, 0x03, (openLoopPeriod&0x0300)>>8); drv2624_reg_write(pDRV2624, DRV2624_REG_OL_PERIOD_L, (openLoopPeriod&0x00ff)); - dev_info(pDRV2624->dev, "%s, LRA = %d, DriveTime=0x%x\n", + dev_info(pDRV2624->dev, "%s, LRA = %d, DriveTime=0x%x\n", __func__, actuator.mnLRAFreq, DriveTime); } + + value = drv2624_reg_read(pDRV2624, DRV2624_REG_CONTROL2); + wavesetting.mnLoop = drv2624_reg_read(pDRV2624, DRV2624_REG_MAIN_LOOP)&0x07; + wavesetting.mnInterval = ((value&INTERVAL_MASK)>>INTERVAL_SHIFT); + wavesetting.mnScale = (value&SCALE_MASK); + memcpy(&pDRV2624->msWaveformSetting, &wavesetting, sizeof(struct drv2624_wave_setting)); } static irqreturn_t drv2624_irq_handler(int irq, void *dev_id) @@ -1231,6 +1380,7 @@ static irqreturn_t drv2624_irq_handler(int irq, void *dev_id) pDRV2624->mnWorkMode |= WORK_IRQ; schedule_work(&pDRV2624->vibrator_work); + return IRQ_HANDLED; } @@ -1245,122 +1395,127 @@ static int drv2624_parse_dt(struct device *dev, struct drv2624_data *pDRV2624) if (pPlatData->mnGpioNRST < 0) { dev_err(pDRV2624->dev, "Looking up %s property in node %s failed %d\n", "ti,reset-gpio", np->full_name, pPlatData->mnGpioNRST); - nResult = -EINVAL; + return -EINVAL; } else dev_dbg(pDRV2624->dev, "ti,reset-gpio=%d\n", pPlatData->mnGpioNRST); - if (nResult >=0) { - rc = of_property_read_u32(np, "ti,smart-loop", &value); - if (rc) { - dev_err(pDRV2624->dev, "Looking up %s property in node %s failed %d\n", - "ti,smart-loop", np->full_name, rc); - nResult = -EINVAL; - } else { - pPlatData->mnLoop = value & 0x01; - dev_dbg(pDRV2624->dev, "ti,smart-loop=%d\n", pPlatData->mnLoop); - } + rc = of_property_read_u32(np, "ti,smart-loop", &value); + if (rc) { + dev_err(pDRV2624->dev, "Looking up %s property in node %s failed %d\n", + "ti,smart-loop", np->full_name, rc); + return -EINVAL; + } else { + pPlatData->mnLoop = value & 0x01; + dev_dbg(pDRV2624->dev, "ti,smart-loop=%d\n", pPlatData->mnLoop); } - if (nResult >=0) { - rc = of_property_read_u32(np, "ti,actuator", &value); - if (rc) { - dev_err(pDRV2624->dev, "Looking up %s property in node %s failed %d\n", - "ti,actuator", np->full_name, rc); - nResult = -EINVAL; - } else { - pPlatData->msActuator.mnActuatorType = value & 0x01; - dev_dbg(pDRV2624->dev, "ti,actuator=%d\n", - pPlatData->msActuator.mnActuatorType); - } + rc = of_property_read_u32(np, "ti,actuator", &value); + if (rc) { + dev_err(pDRV2624->dev, "Looking up %s property in node %s failed %d\n", + "ti,actuator", np->full_name, rc); + return -EINVAL; + } else { + pPlatData->msActuator.mnActuatorType = value & 0x01; + dev_dbg(pDRV2624->dev, "ti,actuator=%d\n", + pPlatData->msActuator.mnActuatorType); } - if (nResult >=0) { - rc = of_property_read_u32(np, "ti,rated-voltage", &value); - if (rc) { - dev_err(pDRV2624->dev, "Looking up %s property in node %s failed %d\n", - "ti,rated-voltage", np->full_name, rc); - nResult = -EINVAL; - }else{ - pPlatData->msActuator.mnRatedVoltage = value; - dev_dbg(pDRV2624->dev, "ti,rated-voltage=0x%x\n", - pPlatData->msActuator.mnRatedVoltage); - } + rc = of_property_read_u32(np, "ti,rated-voltage", &value); + if (rc) { + dev_err(pDRV2624->dev, "Looking up %s property in node %s failed %d\n", + "ti,rated-voltage", np->full_name, rc); + return -EINVAL; + }else{ + pPlatData->msActuator.mnRatedVoltage = drv2624_calculate_voltage(value); + dev_dbg(pDRV2624->dev, "ti,rated-voltage=0x%x\n", + pPlatData->msActuator.mnRatedVoltage); } - if (nResult >=0) { - rc = of_property_read_u32(np, "ti,odclamp-voltage", &value); - if (rc) { - dev_err(pDRV2624->dev, "Looking up %s property in node %s failed %d\n", - "ti,odclamp-voltage", np->full_name, rc); - nResult = -EINVAL; - } else { - pPlatData->msActuator.mnOverDriveClampVoltage = value; - dev_dbg(pDRV2624->dev, "ti,odclamp-voltage=0x%x\n", - pPlatData->msActuator.mnOverDriveClampVoltage); - } + rc = of_property_read_u32(np, "ti,odclamp-voltage", &value); + if (rc) { + dev_err(pDRV2624->dev, "Looking up %s property in node %s failed %d\n", + "ti,odclamp-voltage", np->full_name, rc); + return -EINVAL; + } else { + pPlatData->msActuator.mnOverDriveClampVoltage = + drv2624_calculate_voltage(value); + dev_dbg(pDRV2624->dev, "ti,odclamp-voltage=0x%x\n", + pPlatData->msActuator.mnOverDriveClampVoltage); } - if ((nResult >= 0) && (pPlatData->msActuator.mnActuatorType == LRA)) { + if (pPlatData->msActuator.mnActuatorType == LRA) { rc = of_property_read_u32(np, "ti,lra-frequency", &value); if (rc) { dev_err(pDRV2624->dev, "Looking up %s property in node %s failed %d\n", "ti,lra-frequency", np->full_name, rc); - nResult = -EINVAL; + return -EINVAL; } else { if ((value >= 45) && (value <= 300)) { pPlatData->msActuator.mnLRAFreq = value; dev_dbg(pDRV2624->dev, "ti,lra-frequency=%d\n", pPlatData->msActuator.mnLRAFreq); } else { - nResult = -EINVAL; - dev_err(pDRV2624->dev, "ERROR, ti,lra-frequency=%d, out of range\n", + dev_err(pDRV2624->dev, "ERROR, ti,lra-frequency=%d, out of range\n", pPlatData->msActuator.mnLRAFreq); + return -EINVAL; } } } - if (nResult >= 0) { - pPlatData->mnGpioINT = of_get_named_gpio(np, "ti,irq-gpio", 0); - if (pPlatData->mnGpioINT < 0) { - dev_err(pDRV2624->dev, "Looking up %s property in node %s failed %d\n", - "ti,irq-gpio", np->full_name, pPlatData->mnGpioINT); - } else - dev_dbg(pDRV2624->dev, "ti,irq-gpio=%d\n", pPlatData->mnGpioINT); - } + pPlatData->mnGpioINT = of_get_named_gpio(np, "ti,irq-gpio", 0); + if (pPlatData->mnGpioINT < 0) { + dev_err(pDRV2624->dev, "Looking up %s property in node %s failed %d\n", + "ti,irq-gpio", np->full_name, pPlatData->mnGpioINT); + return -EINVAL; + } else + dev_dbg(pDRV2624->dev, "ti,irq-gpio=%d\n", pPlatData->mnGpioINT); return nResult; } -#ifdef CONFIG_PM_SLEEP -static int drv2624_suspend(struct device *dev) +static void drv2624_close(struct input_dev *input) { - struct drv2624_data *pDRV2624 = dev_get_drvdata(dev); + struct drv2624_data *pDRV2624 = input_get_drvdata(input); dev_dbg(pDRV2624->dev, "%s\n", __func__); mutex_lock(&pDRV2624->lock); - if (hrtimer_active(&pDRV2624->timer) || pDRV2624->mnVibratorPlaying) + if (hrtimer_active(&pDRV2624->haptics_timer) || pDRV2624->mnVibratorPlaying) drv2624_stop(pDRV2624); mutex_unlock(&pDRV2624->lock); - return 0; + return; } -static int drv2624_resume(struct device *dev) +/** + * Rated and Overdriver Voltages: + * Calculated using the formula r = voltage(V) * 255 / 5.6 + * where r is what will be written to the register + * and v is the rated or overdriver voltage of the actuator + **/ +static inline int drv2624_calculate_voltage(unsigned int voltage) { - return 0; + return (voltage * 255 / 5600); } -#endif -static struct regmap_config drv2624_i2c_regmap = { - .reg_bits = 8, - .val_bits = 8, - .cache_type = REGCACHE_NONE, -}; +static int drv2624_hw_reset(struct drv2624_data *pDRV2624) +{ + int nResult = 0; + + dev_dbg(pDRV2624->dev, "%s: enter! \n", __func__); + + gpio_direction_output(pDRV2624->msPlatData.mnGpioNRST, 0); + mdelay(5); + gpio_direction_output(pDRV2624->msPlatData.mnGpioNRST, 1); + mdelay(2); + + return nResult; +} static int drv2624_i2c_probe(struct i2c_client* client, const struct i2c_device_id* id) { - struct drv2624_data *pDRV2624; int nResult = 0; + struct drv2624_data *pDRV2624; + struct ff_device *ff; dev_info(&client->dev, "%s enter\n", __func__); @@ -1376,6 +1531,7 @@ static int drv2624_i2c_probe(struct i2c_client* client, const struct i2c_device_ } pDRV2624->dev = &client->dev; + pDRV2624->client = client; i2c_set_clientdata(client,pDRV2624); dev_set_drvdata(&client->dev, pDRV2624); @@ -1384,24 +1540,24 @@ static int drv2624_i2c_probe(struct i2c_client* client, const struct i2c_device_ nResult = PTR_ERR(pDRV2624->mpRegmap); dev_err(pDRV2624->dev, "%s:Failed to allocate register map: %d\n", __func__, nResult); - return nResult; + goto free_mem; } if (client->dev.of_node) { dev_dbg(pDRV2624->dev, "of node parse\n"); nResult = drv2624_parse_dt(&client->dev, pDRV2624); + if (nResult < 0) { + dev_err(pDRV2624->dev, "%s: parse_dt failed %d\n", + __func__, nResult); + goto free_gpio; + } } else if (client->dev.platform_data) { dev_dbg(pDRV2624->dev, "platform data parse\n"); memcpy(&pDRV2624->msPlatData, client->dev.platform_data, sizeof(struct drv2624_platform_data)); } else { dev_err(pDRV2624->dev, "%s: ERROR no platform data\n",__func__); - return -EINVAL; - } - - if ((nResult < 0) || !gpio_is_valid(pDRV2624->msPlatData.mnGpioNRST)) { - dev_err(pDRV2624->dev, "%s: platform data error\n",__func__); - return -EINVAL; + goto free_gpio; } if (gpio_is_valid(pDRV2624->msPlatData.mnGpioNRST)) { @@ -1409,19 +1565,16 @@ static int drv2624_i2c_probe(struct i2c_client* client, const struct i2c_device_ if (nResult < 0) { dev_err(pDRV2624->dev, "%s: GPIO %d request NRST error\n", __func__, pDRV2624->msPlatData.mnGpioNRST); - return nResult; + goto free_gpio; } - - gpio_direction_output(pDRV2624->msPlatData.mnGpioNRST, 0); - mdelay(5); - gpio_direction_output(pDRV2624->msPlatData.mnGpioNRST, 1); - mdelay(2); + drv2624_hw_reset(pDRV2624); } mutex_init(&pDRV2624->dev_lock); + nResult = drv2624_reg_read(pDRV2624, DRV2624_REG_ID); if (nResult < 0) - goto exit_gpio_request_failed1; + goto destroy_mutex; else { dev_info(pDRV2624->dev, "%s, ID status (0x%x)\n", __func__, nResult); pDRV2624->mnDeviceID = nResult; @@ -1430,17 +1583,17 @@ static int drv2624_i2c_probe(struct i2c_client* client, const struct i2c_device_ if ((pDRV2624->mnDeviceID & 0xf0) != DRV2624_ID) { dev_err(pDRV2624->dev, "%s, device_id(0x%x) fail\n", __func__, pDRV2624->mnDeviceID); - goto exit_gpio_request_failed1; + goto destroy_mutex; } - dev_init_platform_data(pDRV2624); + drv2624_init(pDRV2624); if (gpio_is_valid(pDRV2624->msPlatData.mnGpioINT)) { nResult = gpio_request(pDRV2624->msPlatData.mnGpioINT, "DRV2624-IRQ"); if (nResult < 0) { dev_err(pDRV2624->dev, "%s: GPIO %d request INT error\n", __func__, pDRV2624->msPlatData.mnGpioINT); - goto exit_gpio_request_failed1; + goto destroy_mutex; } gpio_direction_input(pDRV2624->msPlatData.mnGpioINT); pDRV2624->mnIRQ = gpio_to_irq(pDRV2624->msPlatData.mnGpioINT); @@ -1450,36 +1603,75 @@ static int drv2624_i2c_probe(struct i2c_client* client, const struct i2c_device_ NULL, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, pDRV2624); if (nResult < 0) { dev_err(pDRV2624->dev, "request_irq failed, %d\n", nResult); - goto exit_gpio_request_failed2; + goto destroy_mutex; } + disable_irq_nosync(pDRV2624->mnIRQ); pDRV2624->mbIRQEnabled = false; pDRV2624->mbIRQUsed = true; } else pDRV2624->mbIRQUsed = false; - g_DRV2624data = pDRV2624; + /* input dev init */ + pDRV2624->input_dev = devm_input_allocate_device(&client->dev); + if (!pDRV2624->input_dev) { + dev_err(&client->dev, "Failed to allocate input device_node\n"); + goto destroy_mutex; + } + + pDRV2624->input_dev->name = "drv2624:haptics"; + pDRV2624->input_dev->close = drv2624_close; + input_set_drvdata(pDRV2624->input_dev, pDRV2624); + input_set_capability(pDRV2624->input_dev, EV_FF, FF_RUMBLE); + + input_set_capability(pDRV2624->input_dev, EV_FF, FF_CONSTANT); + input_set_capability(pDRV2624->input_dev, EV_FF, FF_GAIN); + input_set_capability(pDRV2624->input_dev, EV_FF, FF_PERIODIC); + input_set_capability(pDRV2624->input_dev, EV_FF, FF_CUSTOM); + + nResult = input_ff_create(pDRV2624->input_dev, EFFECT_MAX_NUM); + if (nResult) { + dev_err(&client->dev, "input_ff_create() failed: %d\n", + nResult); + goto destroy_mutex; + } + + ff = pDRV2624->input_dev->ff; + ff->upload = drv2624_haptics_upload_effect; + ff->playback = drv2624_haptics_playback; + ff->erase = drv2624_haptics_erase; + ff->set_gain = drv2624_haptics_set_gain; + + nResult = input_register_device(pDRV2624->input_dev); + if (nResult) { + dev_err(&client->dev, "couldn't register input device: %d\n", + nResult); + goto destory_ff; + } Haptics_init(pDRV2624); + g_DRV2624data = pDRV2624; - request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, "drv2624.bin", + request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, "drv2624.bin", &(client->dev), GFP_KERNEL, pDRV2624, drv2624_firmware_load); dev_info(pDRV2624->dev, "drv2624 probe succeeded\n"); return 0; -exit_gpio_request_failed2: +destory_ff: + input_ff_destroy(pDRV2624->input_dev); +destroy_mutex: + mutex_destroy(&pDRV2624->dev_lock); +free_gpio: if (gpio_is_valid(pDRV2624->msPlatData.mnGpioINT)) gpio_free(pDRV2624->msPlatData.mnGpioINT); - -exit_gpio_request_failed1: if (gpio_is_valid(pDRV2624->msPlatData.mnGpioNRST)) gpio_free(pDRV2624->msPlatData.mnGpioNRST); +free_mem: + if (NULL != pDRV2624) + kfree(pDRV2624); - mutex_destroy(&pDRV2624->dev_lock); - - dev_err(pDRV2624->dev, "%s failed, err=%d\n", __func__, nResult); return nResult; } @@ -1495,6 +1687,7 @@ static int drv2624_i2c_remove(struct i2c_client* client) misc_deregister(&drv2624_misc); + input_ff_destroy(pDRV2624->input_dev); mutex_destroy(&pDRV2624->lock); mutex_destroy(&pDRV2624->dev_lock); @@ -1507,9 +1700,43 @@ static const struct i2c_device_id drv2624_i2c_id[] = { }; #ifdef CONFIG_PM_SLEEP -static const struct dev_pm_ops drv2624_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(drv2624_suspend, drv2624_resume) -}; +static int __maybe_unused drv2624_suspend(struct device *dev) +{ + struct drv2624_data *pDRV2624 = dev_get_drvdata(dev); + + dev_dbg(pDRV2624->dev, "%s enter!\n", __func__); + mutex_lock(&pDRV2624->lock); + if (hrtimer_active(&pDRV2624->haptics_timer) || + pDRV2624->mnVibratorPlaying) { + drv2624_stop(pDRV2624); + } + /* set device to standby mode */ + drv2624_set_bits(pDRV2624, + DRV2624_REG_CONTROL1, + DRV2624_AUTO_BRK_INTO_STBY_MASK, + DRV2624_STBY_MODE_WITH_AUTO_BRAKE); + mutex_unlock(&pDRV2624->lock); + + return 0; +} + +static int __maybe_unused drv2624_resume(struct device *dev) +{ + struct drv2624_data *pDRV2624 = dev_get_drvdata(dev); + + dev_dbg(pDRV2624->dev, "%s enter!\n", __func__); + + mutex_lock(&pDRV2624->lock); + /* set device to active mode */ + drv2624_reg_write(pDRV2624, + DRV2624_REG_CONTROL1, + DRV2624_REMOVE_STBY_MODE); + mutex_unlock(&pDRV2624->lock); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(drv2624_pm_ops, drv2624_suspend, drv2624_resume); #endif MODULE_DEVICE_TABLE(i2c, drv2624_i2c_id); @@ -1543,4 +1770,4 @@ module_i2c_driver(drv2624_i2c_driver); MODULE_AUTHOR("Texas Instruments Inc."); MODULE_DESCRIPTION("DRV2624 I2C Smart Haptics driver"); -MODULE_LICENSE("GPLv2"); \ No newline at end of file +MODULE_LICENSE("GPL"); diff --git a/drv2624.h b/drv2624.h index b827e5d..602f5ae 100755 --- a/drv2624.h +++ b/drv2624.h @@ -27,33 +27,38 @@ ** ============================================================================= */ + #include #include #include -#include <../../../drivers/staging/android/timed_output.h> #include -#include #include #include #include +#ifdef ANDROID +#include <../../../drivers/staging/android/timed_output.h> +#elif defined ANDROID_TIMED_OUTPUT +#include "timed_output.h" +#endif #define HAPTICS_DEVICE_NAME "drv2624" - +#define NEED_RELOAD_FIRMWARE 1 #define DRV2624_REG_ID 0x00 -#define DRV2624_ID (0x02&0xf0) +#define DRV2624_ID_MASK 0xf0 +#define DRV2624_ID (0x02&DRV2624_ID_MASK) #define DRV2624_REG_STATUS 0x01 -#define DIAG_MASK 0x80 +#define DIAG_MASK 0x80 #define DIAG_SUCCESS 0x00 -#define DIAG_SHIFT 0x07 -#define INT_MASK 0x1f +#define DIAG_SHIFT 0x07 +#define INT_MASK 0x1f #define PRG_ERR_MASK 0x10 #define PROCESS_DONE_MASK 0x08 -#define ULVO_MASK 0x04 +#define ULVO_MASK 0x04 #define OVERTEMPRATURE_MASK 0x02 #define OVERCURRENT_MASK 0x01 -#define DRV2624_REG_INT_ENABLE 0x02 +#define DRV2624_REG_INT_ENABLE 0x02 #define INT_MASK_ALL 0x1f #define INT_ENABLE_ALL 0x00 #define INT_ENABLE_CRITICAL 0x08 @@ -62,30 +67,37 @@ #define DRV2624_REG_MODE 0x07 #define WORKMODE_MASK 0x03 -#define MODE_RTP 0x00 -#define MODE_WAVEFORM_SEQUENCER 0x01 +#define MODE_RTP 0x00 +#define MODE_WAVEFORM_SEQUENCER 0x01 #define MODE_DIAGNOSTIC 0x02 #define MODE_CALIBRATION 0x03 #define PINFUNC_MASK 0x0c -#define PINFUNC_INT 0x02 +#define PINFUNC_INT 0x02 #define PINFUNC_SHIFT 0x02 +#define DRV2624_CALIBRATION_MODE_CFG 0x4B + +#define DRV2624_REG_CONTROL1 0x08 +#define DRV2624_AUTO_BRK_INTO_STBY_MASK (0x01 << 3) +#define DRV2624_STBY_MODE_WITH_AUTO_BRAKE (0x01 << 3) +#define DRV2624_STBY_MODE_WITHOUT_AUTO_BRAKE 0x00 +#define DRV2624_REMOVE_STBY_MODE 0x00 -#define DRV2624_REG_CONTROL1 0x08 #define ACTUATOR_MASK 0x80 #define ACTUATOR_SHIFT 7 -#define LOOP_MASK 0x40 -#define LOOP_SHIFT 6 +#define LOOP_MASK 0x40 +#define LOOP_SHIFT 6 #define AUTOBRK_OK_MASK 0x10 #define AUTOBRK_OK_ENABLE 0x10 #define DRV2624_REG_GO 0x0c - -#define DRV2624_REG_CONTROL2 0x0d -#define LIB_LRA 0x00 -#define LIB_ERM 0x01 -#define LIB_MASK 0x80 -#define LIB_SHIFT 0x07 -#define SCALE_MASK 0x03 +#define DRV2624_GO_BIT_MASK 0x01 + +#define DRV2624_REG_CONTROL2 0x0d +#define LIB_LRA 0x00 +#define LIB_ERM 0x01 +#define LIB_MASK 0x80 +#define LIB_SHIFT 0x07 +#define SCALE_MASK 0x03 #define INTERVAL_MASK 0x20 #define INTERVAL_SHIFT 0x05 @@ -99,7 +111,7 @@ #define DRV2624_REG_CAL_COMP 0x21 #define DRV2624_REG_CAL_BEMF 0x22 #define DRV2624_REG_LOOP_CONTROL 0x23 -#define BEMFGAIN_MASK 0x03 +#define BEMFGAIN_MASK 0x03 #define DRV2624_REG_DRIVE_TIME 0x27 #define DRIVE_TIME_MASK 0x1f @@ -107,68 +119,92 @@ #define MINFREQ_SEL_MASK 0x80 #define MINFREQ_SEL_SHIFT 0x07 -#define DRV2624_REG_OL_PERIOD_H 0x2e -#define DRV2624_REG_OL_PERIOD_L 0x2f +#define DRV2624_REG_OL_PERIOD_H 0x2e +#define DRV2624_REG_OL_PERIOD_L 0x2f #define DRV2624_REG_DIAG_K 0x30 -#define GO_BIT_POLL_INTERVAL 15 +#define GO_BIT_POLL_INTERVAL 15 #define STANDBY_WAKE_DELAY 1 #define WAKE_STANDBY_DELAY 3 #define DRV2624_REG_RAM_ADDR_UPPER 0xfd #define DRV2624_REG_RAM_ADDR_LOWER 0xfe -#define DRV2624_REG_RAM_DATA 0xff +#define DRV2624_REG_RAM_DATA 0xff /* Commands */ #define HAPTIC_CMDID_PLAY_SINGLE_EFFECT 0x01 #define HAPTIC_CMDID_PLAY_EFFECT_SEQUENCE 0x02 #define HAPTIC_CMDID_PLAY_TIMED_EFFECT 0x03 -#define HAPTIC_CMDID_GET_DEV_ID 0x04 -#define HAPTIC_CMDID_RUN_DIAG 0x05 +#define HAPTIC_CMDID_GET_DEV_ID 0x04 +#define HAPTIC_CMDID_RUN_DIAG 0x05 #define HAPTIC_CMDID_AUDIOHAPTIC_ENABLE 0x06 #define HAPTIC_CMDID_AUDIOHAPTIC_DISABLE 0x07 #define HAPTIC_CMDID_AUDIOHAPTIC_GETSTATUS 0x08 -#define HAPTIC_CMDID_REG_WRITE 0x09 -#define HAPTIC_CMDID_REG_READ 0x0a -#define HAPTIC_CMDID_REG_SETBIT 0x0b -#define HAPTIC_CMDID_PATTERN_RTP 0x0c -#define HAPTIC_CMDID_RTP_SEQUENCE 0x0d +#define HAPTIC_CMDID_REG_WRITE 0x09 +#define HAPTIC_CMDID_REG_READ 0x0a +#define HAPTIC_CMDID_REG_SETBIT 0x0b +#define HAPTIC_CMDID_PATTERN_RTP 0x0c +#define HAPTIC_CMDID_RTP_SEQUENCE 0x0d #define HAPTIC_CMDID_GET_EFFECT_COUNT 0x10 #define HAPTIC_CMDID_UPDATE_FIRMWARE 0x11 -#define HAPTIC_CMDID_READ_FIRMWARE 0x12 +#define HAPTIC_CMDID_READ_FIRMWARE 0x12 #define HAPTIC_CMDID_RUN_CALIBRATION 0x13 #define HAPTIC_CMDID_CONFIG_WAVEFORM 0x14 -#define HAPTIC_CMDID_SET_SEQUENCER 0x15 -#define HAPTIC_CMDID_REGLOG_ENABLE 0x16 +#define HAPTIC_CMDID_SET_SEQUENCER 0x15 +#define HAPTIC_CMDID_REGLOG_ENABLE 0x16 +#define HAPTIC_SET_CALIBRATION_RESULT 0x17 -#define HAPTIC_CMDID_STOP 0xFF +#define HAPTIC_CMDID_STOP 0xFF -#define MAX_TIMEOUT 10000 /* 10s */ -#define MAX_READ_BYTES 0xff -#define DRV2624_SEQUENCER_SIZE 8 +#define MAX_TIMEOUT 10000 /* 10s */ +#define MAX_READ_BYTES 0xff +#define DRV2624_SEQUENCER_SIZE 8 -#define WORK_IDLE 0 +#define WORK_IDLE 0 #define WORK_VIBRATOR 0x01 -#define WORK_IRQ 0x02 -#define WORK_EFFECTSEQUENCER 0x04 +#define WORK_IRQ 0x02 +#define WORK_EFFECTSEQUENCER 0x04 #define WORK_CALIBRATION 0x08 #define WORK_DIAGNOSTIC 0x10 #define YES 1 #define NO 0 #define GO 1 -#define STOP 0 - -#define POLL_GO_BIT_INTERVAL 5 /* 5 ms */ -#define POLL_GO_BIT_RETRY 20 /* 50 times */ +#define STOP 0 + +#define GO_BIT_CHECK_INTERVAL 5 /* 5 ms */ +#define GO_BIT_MAX_RETRY_CNT 20 /* 50 times */ + +#define DRV2624_MAGIC 0x2624 +#define STRONG_MAGNITUDE 0x7fff +#define MEDIUM_MAGNITUDE 0x5fff +#define LIGHT_MAGNITUDE 0x3fff +#define DRV2624_RAM_SIZE 1024 +#define EFFECT_MAX_NUM 32 + +/* auto calibration */ +#define AUTO_CAL_TIME_REG 0x2A +#define AUTO_CAL_TIME_MASK 0x03 +#define AUTO_CAL_TIME_250MS 0x00 +#define AUTO_CAL_TIME_500MS 0x01 +#define AUTO_CAL_TIME_1000MS 0x10 +#define AUTO_CAL_TIME_AUTO_TRIGGER 0x11 + +typedef enum { + DRV2624_RTP_MODE = 0x00, + DRV2624_RAM_MODE, + DRV2624_WAVE_SEQ_MODE = DRV2624_RAM_MODE, + DRV2624_DIAG_MODE, + DRV2624_CALIBRATION_MODE, +} drv2624_mode_t; enum actuator_type { - ERM, + ERM = 0, LRA }; enum loop_type { - CLOSE_LOOP, + CLOSE_LOOP = 0x00, OPEN_LOOP }; @@ -242,7 +278,7 @@ struct drv2624_diag_result { struct drv2624_platform_data { int mnGpioNRST; int mnGpioINT; - unsigned char mnLoop; + unsigned char mnLoop; struct actuator_data msActuator; }; @@ -254,10 +290,26 @@ struct drv2624_fw_header{ int fw_effCount; }; -#define DRV2624_MAGIC 0x2624 +struct drv2624_constant_playinfo { + int effect_count; + int effect_id; + int length; + int magnitude; + unsigned char rtp_input; +}; + +enum haptics_custom_effect_param { + CUSTOM_DATA_EFFECT_IDX, + CUSTOM_DATA_TIMEOUT_SEC_IDX, + CUSTOM_DATA_TIMEOUT_MSEC_IDX, + CUSTOM_DATA_LEN, +}; struct drv2624_data { + struct input_dev *input_dev; + struct i2c_client *client; struct drv2624_platform_data msPlatData; + struct mutex lock; struct mutex dev_lock; unsigned char mnDeviceID; struct device *dev; @@ -272,11 +324,7 @@ struct drv2624_data { volatile int mnVibratorPlaying; volatile char mnWorkMode; unsigned char mnCurrentReg; - struct wake_lock wklock; - struct hrtimer timer; - struct mutex lock; - struct work_struct vibrator_work; - struct timed_output_dev to_dev; + struct hrtimer haptics_timer; struct drv2624_autocal_result mAutoCalResult; struct drv2624_diag_result mDiagResult; @@ -284,6 +332,19 @@ struct drv2624_data { struct drv2624_fw_header fw_header; unsigned char mRAMLSB; unsigned char mRAMMSB; + + int mnEffectType; + unsigned char mnFwRam[DRV2624_RAM_SIZE]; + unsigned int mnEffectTimems[EFFECT_MAX_NUM]; + struct drv2624_constant_playinfo play; + + struct work_struct vibrator_work; +#ifdef ANDROID_TIMED_OUTPUT + struct timed_output_dev to_dev; +#endif + struct work_struct upload_periodic_work; + struct work_struct haptics_playback_work; + struct work_struct haptics_set_gain_work; }; #define DRV2624_MAGIC_NUMBER 0x32363234 /* '2624' */ -- 2.39.2