Add support for Input framework. The legacy support for timeout framework can be...
authora0393714 <navada@ti.com>
Thu, 26 Dec 2019 13:09:05 +0000 (18:39 +0530)
committera0393714 <navada@ti.com>
Thu, 26 Dec 2019 13:09:05 +0000 (18:39 +0530)
drv2624.c
drv2624.h

index d78aabbc2092e782bd46ced1e789c4c57470cabb..e372932056478dfafb747644a9ee481e1a086d25 100755 (executable)
--- a/drv2624.c
+++ b/drv2624.c
@@ -27,6 +27,7 @@
 #define DEBUG
 
 #include <linux/init.h>
+#include <linux/input.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/miscdevice.h>
+#include <linux/interrupt.h>
 #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<<PINFUNC_SHIFT));
 
        if ((actuator.mnActuatorType == ERM)
@@ -1185,9 +1329,8 @@ static void dev_init_platform_data(struct drv2624_data *pDRV2624)
                value_temp |= (pDrv2624Platdata->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");
index b827e5d9ffbbe940e45873fe6ac97233f58284ac..602f5ae2ce77daa54c3c89db66faa0ab7c6f4226 100755 (executable)
--- a/drv2624.h
+++ b/drv2624.h
 ** =============================================================================
 */
 
+
 #include <linux/regmap.h>
 #include <linux/timer.h>
 #include <linux/workqueue.h>
-#include <../../../drivers/staging/android/timed_output.h>
 #include <linux/hrtimer.h>
-#include <linux/wakelock.h>
 #include <linux/mutex.h>
 #include <linux/cdev.h>
 #include <linux/firmware.h>
+#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
 
 #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
 
 #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
 #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' */