EKKANE-15:[kane]:kernel:add cap sensor driver
authoryanfei <yanfei5@huaqin.com>
Sun, 30 Sep 2018 06:21:04 +0000 (14:21 +0800)
committerxiest1 <xiest1@lenovo.com>
Tue, 5 Nov 2019 09:29:45 +0000 (17:29 +0800)
add cap sensor driver

Change-Id: I10e1ba136c833d6b0214cb33463e7aeab90dd874
Signed-off-by: yanfei <yanfei5@huaqin.com>
arch/arm64/boot/dts/exynos/wing-sensor.dtsi
arch/arm64/configs/robusta2_evb_defconfig
arch/arm64/configs/wing_defconfig [changed mode: 0644->0755]
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/sx933x.h [new file with mode: 0755]
drivers/input/misc/sx933x_sar.c [new file with mode: 0755]
drivers/regulator/s2mpu09-regulator.c [changed mode: 0644->0755]

index 1bed4b98ea6295be5b3ee9bfeb45a12c9f248eea..0ca6cf9f0482017c5fccb2cacba09d0ad0a0f753 100755 (executable)
        status = "okay";
        samsung,reset-before-trans;
        clock-frequency = <400000>;
-       sx9325@28 {
-
-               compatible = "semtech,sx9325";
+       sx933x@28 {
+               compatible = "Semtech,sx933x";
                reg = <0x28>;
-               cap_vdd-supply = <&l3_reg>;
-               gpios = <&gpa2 6 0>; /* IRQ */
-               pinctrl-names = "default";
-               pinctrl-0 = <&cap_int_status>;
-               cap,use_channel = <0x0f>;
-               cap,use_channel_top = <0x00>;
-               cap,use_channel_bottom = <0x01>;
-               cap,raw_data_channel = <0x01>;
-               cap,scan_period = <0x02>;
-               reg_array_len = <5>;
-               reg_array_val = <0x36 0x1b 0x37 0x1b 0x4a 0x66 0x4b 0x00 0x4c 0x00>;
-
-
-       };
+               Semtech,nirq-gpio = <&gpa2 6 0>; /* IRQ */
+               pinctrl-names = "default";
+               pinctrl-0 = <&cap_int_status>;
+               Semtech,button-flag = <0x15>;
+               Semtech,reg-num = <23>;
+               Semtech,reg-init = <0x8020 0x1F0000
+                       0x8024 0x300008d7 /*again 6.6pf*/
+                       0x8028 0x24928000
+                       0x802C 0x300010d7
+                       0x8030 0x24960000
+                       0x8034 0x300010d7
+                       0x8038 0x24B20000
+                       0x803C 0x300004D4
+                       0x8040 0x25920000
+                       0x8044 0x300004D4
+                       0x8048 0x2C920000
+                       0x8054 0x02103010 /*ph0*/
+                       0x8058 0x20600C00
+                       0x805c 0x0
+                       0x8064 0x00900000 /*5mm th*/
+                       0x8070 0x0
+                       0x8074 0x02103110 /*ph1*/
+                       0x8084 0x00BB0000 /*5mm th*/
+                       0x8094 0x02103810 /*ph2*/
+                       0x80A4 0x00C60000 /*5mm th*/
+                       0x80B4 0x0010FF00
+                       0x80D4 0x00105A00
+                       0x4004 0x67 >;
+               };
 
 
 };
index f1578a7c3b6c0ad5e1e41a7eaff0bd352e826337..350b0cf056b8f500b15f066035c27aa9f29c0d4e 100755 (executable)
@@ -535,7 +535,8 @@ CONFIG_HARDENED_USERCOPY=y
 CONFIG_SECURITY_SELINUX=y
 CONFIG_CRYPTO_DISKCIPHER=y
 CONFIG_EXYNOS_FMP=y
-CONFIG_SARSENSOR_SX9325=y
+#CONFIG_SARSENSOR_SX9325=y
+CONFIG_SARSENSOR_SX9331=y
 CONFIG_NFC=y
 CONFIG_SEC_NFC=y
 CONFIG_SEC_NFC_PRODUCT_N5=y
old mode 100644 (file)
new mode 100755 (executable)
index b3e5f6a..16747f5
@@ -529,7 +529,8 @@ CONFIG_HARDENED_USERCOPY=y
 CONFIG_SECURITY_SELINUX=y
 CONFIG_CRYPTO_DISKCIPHER=y
 CONFIG_EXYNOS_FMP=y
-CONFIG_SARSENSOR_SX9325=y
+#CONFIG_SARSENSOR_SX9325=y
+CONFIG_SARSENSOR_SX9331=y
 CONFIG_NFC=y
 CONFIG_SEC_NFC=y
 CONFIG_SEC_NFC_PRODUCT_N5=y
index 4846cb3c91b64b2f6a674206f4d58b9e0c9ebe14..29ef0b101dfac8eb649289efe6c7bd683cb1efb5 100755 (executable)
@@ -881,6 +881,13 @@ config INPUT_S2MU106_HAPTIC
         The Haptic Motor driver support both ERM and
         LRA type actuators.
 
+config SARSENSOR_SX9331
+       bool "SARSENSOR SX9331"
+       default n
+       help
+         Say Y here if you have a sar sensor SX9325 connected
+         to your system.If unsure, say N.
+
 config SARSENSOR_SX9325
        bool "SARSENSOR SX9325"
        default n
index b9e8ce9cf087dd5676ddc6db7429c2f1f8d024a7..b6cac4791b9fc27b9a1081cd073b7cff625847a8 100755 (executable)
@@ -84,4 +84,5 @@ obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND)       += xen-kbdfront.o
 obj-$(CONFIG_INPUT_YEALINK)            += yealink.o
 obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR)   += ideapad_slidebar.o
 obj-$(CONFIG_INPUT_S2MU106_HAPTIC)     += s2mu106_haptic.o
+obj-$(CONFIG_SARSENSOR_SX9331) += sx933x_sar.o
 obj-$(CONFIG_SARSENSOR_SX9325) += sx9325_sar.o
diff --git a/drivers/input/misc/sx933x.h b/drivers/input/misc/sx933x.h
new file mode 100755 (executable)
index 0000000..f2877e4
--- /dev/null
@@ -0,0 +1,755 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+#ifndef SX933x_H
+#define SX933x_H
+
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+
+#if 0
+#include <linux/wakelock.h>
+#include <linux/earlysuspend.h>
+#include <linux/suspend.h>
+#endif
+/*
+ *  I2C Registers
+ */
+#define   SX933X_HOSTIRQSRC_REG           0x4000
+#define   SX933X_HOSTIRQMSK_REG           0x4004
+#define   SX933X_HOSTIRQCTRL_REG          0x4008
+#define   SX933X_PAUSESTAT_REG            0x4010
+#define   SX933X_AFECTRL_REG              0x4054
+#define   SX933X_CLKGEN_REG               0x4200
+#define   SX933X_I2CADDR_REG              0x41C4
+#define   SX933X_RESET_REG                0x4240
+#define   SX933X_CMD_REG                  0x4280
+#define   SX933X_TOPSTAT0_REG             0x4284
+#define   SX933X_PINCFG_REG               0x42C0
+#define   SX933X_PINDOUT_REG              0x42C4
+#define   SX933X_PINDIN_REG               0x42C8
+#define   SX933X_INFO_REG                 0x42D8
+#define   SX933X_STAT0_REG                0x8000
+#define   SX933X_STAT1_REG                0x8004
+#define   SX933X_STAT2_REG                0x8008
+#define   SX933X_IRQCFG0_REG              0x800C
+#define   SX933X_IRQCFG1_REG              0x8010
+#define   SX933X_IRQCFG2_REG              0x8014
+#define   SX933X_IRQCFG3_REG              0x8018
+#define   SX933X_SCANPERIOD_REG           0x801C
+#define   SX933X_GNRLCTRL2_REG            0x8020
+#define   SX933X_AFEPARAMSPH0_REG         0x8024
+#define   SX933X_AFEPHPH0_REG             0x8028
+#define   SX933X_AFEPARAMSPH1_REG         0x802C
+#define   SX933X_AFEPHPH1_REG             0x8030
+#define   SX933X_AFEPARAMSPH2_REG         0x8034
+#define   SX933X_AFEPHPH2_REG             0x8038
+#define   SX933X_AFEPARAMSPH3_REG         0x803C
+#define   SX933X_AFEPHPH3_REG             0x8040
+#define   SX933X_AFEPARAMSPH4_REG         0x8044
+#define   SX933X_AFEPHPH4_REG             0x8048
+#define   SX933X_AFEPARAMSPH5_REG         0x804c
+#define   SX933X_AFEPHPH5_REG             0x8050
+
+#define   SX933X_ADCFILTPH0_REG           0x8054
+#define   SX933X_AVGBFILTPH0_REG          0x8058
+#define   SX933X_AVGAFILTPH0_REG          0x805C
+#define   SX933X_ADVDIG0PH0_REG           0x8060
+#define   SX933X_ADVDIG1PH0_REG           0x8064
+#define   SX933X_ADVDIG2PH0_REG           0x8068
+#define   SX933X_ADVDIG3PH0_REG           0x806C
+#define   SX933X_ADVDIG4PH0_REG           0x8070
+#define   SX933X_ADCFILTPH1_REG           0x8074
+#define   SX933X_AVGBFILTPH1_REG          0x8078
+#define   SX933X_AVGAFILTPH1_REG          0x807C
+#define   SX933X_ADVDIG0PH1_REG           0x8080
+#define   SX933X_ADVDIG1PH1_REG           0x8084
+#define   SX933X_ADVDIG2PH1_REG           0x8088
+#define   SX933X_ADVDIG3PH1_REG           0x808C
+#define   SX933X_ADVDIG4PH1_REG           0x8090
+#define   SX933X_ADCFILTPH2_REG           0x8094
+#define   SX933X_AVGBFILTPH2_REG          0x8098
+#define   SX933X_AVGAFILTPH2_REG          0x809C
+#define   SX933X_ADVDIG0PH2_REG           0x80A0
+#define   SX933X_ADVDIG1PH2_REG           0x80A4
+#define   SX933X_ADVDIG2PH2_REG           0x80A8
+#define   SX933X_ADVDIG3PH2_REG           0x80AC
+#define   SX933X_ADVDIG4PH2_REG           0x80B0
+#define   SX933X_ADCFILTPH3_REG           0x80B4
+#define   SX933X_AVGBFILTPH3_REG          0x80B8
+#define   SX933X_AVGAFILTPH3_REG          0x80BC
+#define   SX933X_ADVDIG0PH3_REG           0x80C0
+#define   SX933X_ADVDIG1PH3_REG           0x80C4
+#define   SX933X_ADVDIG2PH3_REG           0x80C8
+#define   SX933X_ADVDIG3PH3_REG           0x80CC
+#define   SX933X_ADVDIG4PH3_REG           0x80D0
+#define   SX933X_ADCFILTPH4_REG           0x80D4
+#define   SX933X_AVGBFILTPH4_REG          0x80D8
+#define   SX933X_AVGAFILTPH4_REG          0x80DC
+#define   SX933X_ADVDIG0PH4_REG           0x80E0
+#define   SX933X_ADVDIG1PH4_REG           0x80E4
+#define   SX933X_ADVDIG2PH4_REG           0x80E8
+#define   SX933X_ADVDIG3PH4_REG           0x80EC
+#define   SX933X_ADVDIG4PH4_REG           0x80F0
+#define   SX933X_ADCFILTPH5_REG           0x80F4
+#define   SX933X_AVGBFILTPH5_REG          0x80F8
+#define   SX933X_AVGAFILTPH5_REG          0x80FC
+#define   SX933X_ADVDIG0PH5_REG           0x8100
+#define   SX933X_ADVDIG1PH5_REG           0x8104
+#define   SX933X_ADVDIG2PH5_REG           0x8108
+#define   SX933X_ADVDIG3PH5_REG           0x810C
+#define   SX933X_ADVDIG4PH5_REG           0x8110
+
+#define   SX933X_REFCORRA_REG             0x8124
+#define   SX933X_REFCORRB_REG             0x8128
+
+#define   SX933X_SMARTSAR0A_REG           0x812C
+#define   SX933X_SMARTSAR1A_REG           0x8130
+#define   SX933X_SMARTSAR2A_REG           0x8134
+
+#define   SX933X_SMARTSAR0B_REG           0x8138
+#define   SX933X_SMARTSAR1B_REG           0x813C
+#define   SX933X_SMARTSAR2B_REG           0x8140
+
+#define   SX933X_SMARTSAR0C_REG           0x8144
+#define   SX933X_SMARTSAR1C_REG           0x8148
+#define   SX933X_SMARTSAR2C_REG           0x814C
+
+
+
+
+#define   SX933X_AUTOFREQ0_REG            0x8154
+#define   SX933X_AUTOFREQ1_REG            0x8158
+
+#define   SX933X_USEPH0_REG               0x815C
+#define   SX933X_USEPH1_REG               0x8160
+#define   SX933X_USEPH2_REG               0x8164
+#define   SX933X_USEPH3_REG               0x8168
+#define   SX933X_USEPH4_REG               0x816C
+#define   SX933X_USEPH5_REG               0x8170
+
+#define   SX933X_AVGPH0_REG               0x8174
+#define   SX933X_AVGPH1_REG               0x8178
+#define   SX933X_AVGPH2_REG               0x817C
+#define   SX933X_AVGPH3_REG               0x8180
+#define   SX933X_AVGPH4_REG               0x8184
+#define   SX933X_AVGPH5_REG               0x8188
+
+#define   SX933X_DIFFPH0_REG              0x818C
+#define   SX933X_DIFFPH1_REG              0x8190
+#define   SX933X_DIFFPH2_REG              0x8194
+#define   SX933X_DIFFPH3_REG              0x8198
+#define   SX933X_DIFFPH4_REG              0x819C
+#define   SX933X_DIFFPH5_REG              0x81A0
+
+#define   SX933X_OFFSETPH0_REG            SX933X_AFEPHPH0_REG//bit14:0
+#define   SX933X_OFFSETPH1_REG            SX933X_AFEPHPH1_REG//bit14:0
+#define   SX933X_OFFSETPH2_REG            SX933X_AFEPHPH2_REG//bit14:0
+#define   SX933X_OFFSETPH3_REG            SX933X_AFEPHPH3_REG//bit14:0
+#define   SX933X_OFFSETPH4_REG            SX933X_AFEPHPH4_REG//bit14:0
+#define   SX933X_OFFSETPH5_REG            SX933X_AFEPHPH5_REG//bit14:0
+
+//i2c register bit mask
+#define   MSK_IRQSTAT_RESET               0x00000080
+#define   MSK_IRQSTAT_TOUCH               0x00000040
+#define   MSK_IRQSTAT_RELEASE             0x00000020
+#define   MSK_IRQSTAT_COMP                0x00000010
+#define   MSK_IRQSTAT_CONV                0x00000008
+#define   MSK_IRQSTAT_PROG2IRQ            0x00000004
+#define   MSK_IRQSTAT_PROG1IRQ            0x00000002
+#define   MSK_IRQSTAT_PROG0IRQ            0x00000001
+
+#define   I2C_SOFTRESET_VALUE             0x000000DE
+
+#define   I2C_REGCMD_PHEN                 0x0000000F
+#define   I2C_REGCMD_COMPEN               0x0000000E
+#define   I2C_REGCMD_EN_SLEEP             0x0000000D
+#define   I2C_REGCMD_EX_SLEEP             0x0000000C
+
+#define   I2C_REGGNRLCTRL2_PHEN_MSK       0x000000FF
+#define   I2C_REGGNRLCTRL2_COMPEN_MSK     0x00ff0000
+
+#define   MSK_REGSTAT0_STEADYSTAT5        0x20
+#define   MSK_REGSTAT0_STEADYSTAT4        0x10
+#define   MSK_REGSTAT0_STEADYSTAT3        0x08
+#define   MSK_REGSTAT0_STEADYSTAT2        0x04
+#define   MSK_REGSTAT0_STEADYSTAT1        0x02
+#define   MSK_REGSTAT0_STEADYSTAT0        0x01
+
+#define   MSK_REGSTAT0_BODYSTAT5          ((long int)0x20<<8)
+#define   MSK_REGSTAT0_BODYSTAT4          ((long int)0x10<<8)
+#define   MSK_REGSTAT0_BODYSTAT3          ((long int)0x08<<8)
+#define   MSK_REGSTAT0_BODYSTAT2          ((long int)0x04<<8)
+#define   MSK_REGSTAT0_BODYSTAT1          ((long int)0x02<<8)
+#define   MSK_REGSTAT0_BODYSTAT0          ((long int)0x01<<8)
+
+#define   MSK_REGSTAT0_TABLESTAT5         ((long int)0x20<<16)
+#define   MSK_REGSTAT0_TABLESTAT4         ((long int)0x10<<16)
+#define   MSK_REGSTAT0_TABLESTAT3         ((long int)0x08<<16)
+#define   MSK_REGSTAT0_TABLESTAT2         ((long int)0x04<<16)
+#define   MSK_REGSTAT0_TABLESTAT1         ((long int)0x02<<16)
+#define   MSK_REGSTAT0_TABLESTAT0         ((long int)0x01<<16)
+
+#define   MSK_REGSTAT0_PROXSTAT5          ((long int)0x20<<24)
+#define   MSK_REGSTAT0_PROXSTAT4          ((long int)0x10<<24)
+#define   MSK_REGSTAT0_PROXSTAT3          ((long int)0x08<<24)
+#define   MSK_REGSTAT0_PROXSTAT2          ((long int)0x04<<24)
+#define   MSK_REGSTAT0_PROXSTAT1          ((long int)0x02<<24)
+#define   MSK_REGSTAT0_PROXSTAT0          ((long int)0x01<<24)
+
+#define   MSK_REGSTAT1_FAILSTAT5          ((long int)0x20<<24)
+#define   MSK_REGSTAT1_FAILSTAT4          ((long int)0x10<<24)
+#define   MSK_REGSTAT1_FAILSTAT3          ((long int)0x08<<24)
+#define   MSK_REGSTAT1_FAILSTAT2          ((long int)0x04<<24)
+#define   MSK_REGSTAT1_FAILSTAT1          ((long int)0x02<<24)
+#define   MSK_REGSTAT1_FAILSTAT0          ((long int)0x01<<24)
+
+#define   MSK_REGSTAT1_COMPSTAT5          ((long int)0x20<<16)
+#define   MSK_REGSTAT1_COMPSTAT4          ((long int)0x10<<16)
+#define   MSK_REGSTAT1_COMPSTAT3          ((long int)0x08<<16)
+#define   MSK_REGSTAT1_COMPSTAT2          ((long int)0x04<<16)
+#define   MSK_REGSTAT1_COMPSTAT1          ((long int)0x02<<16)
+#define   MSK_REGSTAT1_COMPSTAT0          ((long int)0x01<<16)
+#define   MSK_REGSTAT1_SATSTAT5           ((long int)0x20<<8)
+#define   MSK_REGSTAT1_SATSTAT4           ((long int)0x10<<8)
+#define   MSK_REGSTAT1_SATSTAT3           ((long int)0x08<<8)
+#define   MSK_REGSTAT1_SATSTAT2           ((long int)0x04<<8)
+#define   MSK_REGSTAT1_SATSTAT1           ((long int)0x02<<8)
+#define   MSK_REGSTAT1_SATSTAT0           ((long int)0x01<<8)
+
+
+
+#define   MSK_REGSTAT2_STARTUPSTAT5       ((long int)0x20)
+#define   MSK_REGSTAT2_STARTUPSTAT4       ((long int)0x10)
+#define   MSK_REGSTAT2_STARTUPSTAT3       ((long int)0x08)
+#define   MSK_REGSTAT2_STARTUPSTAT2       ((long int)0x04)
+#define   MSK_REGSTAT2_STARTUPSTAT1       ((long int)0x02)
+#define   MSK_REGSTAT2_STARTUPSTAT0       ((long int)0x01)
+
+#define   MSK_REGSTAT1_STEADYSTATALL      0x02
+
+
+#define   SX933X_STAT0_PROXSTAT_PH5_FLAG      0x20000000
+#define   SX933X_STAT0_PROXSTAT_PH4_FLAG      0x10000000
+#define   SX933X_STAT0_PROXSTAT_PH3_FLAG      0x08000000
+#define   SX933X_STAT0_PROXSTAT_PH2_FLAG      0x04000000
+#define   SX933X_STAT0_PROXSTAT_PH1_FLAG      0x02000000
+#define   SX933X_STAT0_PROXSTAT_PH0_FLAG      0x01000000
+
+#define   SX933X_STAT0_BODYSTAT_PH5_FLAG      0x00002000
+#define   SX933X_STAT0_BODYSTAT_PH4_FLAG      0x00001000
+#define   SX933X_STAT0_BODYSTAT_PH3_FLAG      0x00000800
+#define   SX933X_STAT0_BODYSTAT_PH2_FLAG      0x00000400
+#define   SX933X_STAT0_BODYSTAT_PH1_FLAG      0x00000200
+#define   SX933X_STAT0_BODYSTAT_PH0_FLAG      0x00000100
+
+/*      Chip ID        */
+#define SX933X_WHOAMI_VALUE                   0x00003113
+/*command*/
+#define SX933X_PHASE_CONTROL                  0x0000000F
+#define SX933X_COMPENSATION_CONTROL           0x0000000E
+#define SX933X_ENTER_CONTROL                  0x0000000D
+#define SX933X_EXIT_CONTROL                   0x0000000C
+
+
+
+
+/**************************************
+ *   define platform data
+ *
+ **************************************/
+struct smtc_reg_data
+{
+       unsigned int reg;
+       unsigned int val;
+};
+
+typedef struct smtc_reg_data smtc_reg_data_t;
+typedef struct smtc_reg_data *psmtc_reg_data_t;
+
+
+struct _buttonInfo
+{
+       /*! The Key to send to the input */
+       // int keycode; //not use
+       /*! Mask to look for on Prox Touch Status */
+       int ProxMask;
+       /*! Mask to look for on Table Touch Status */
+       int BodyMask;
+       /*! Current state of button. */
+       int state;
+       struct input_dev *input_dev;
+       char *name;
+       struct sensors_classdev sensors_capsensor_cdev;
+       bool enabled;
+       //may different project use different buttons
+       bool used;
+};
+
+struct totalButtonInformation
+{
+       struct _buttonInfo *buttons;
+       int buttonSize;
+       //struct input_dev *input; //not used
+};
+
+typedef struct totalButtonInformation buttonInformation_t;
+typedef struct totalButtonInformation *pbuttonInformation_t;
+
+
+/* Define Registers that need to be initialized to values different than
+ * default
+ */
+/*define the value without Phase enable settings for easy changes in driver*/
+static const struct smtc_reg_data sx933x_i2c_reg_setup[] =
+{
+       //
+       {
+               .reg = SX933X_AFECTRL_REG,
+               .val = 0x00000400,
+       },
+       //
+       {
+               .reg = SX933X_CLKGEN_REG,
+               .val = 0x00000008,
+       },
+       //
+       {
+               .reg = SX933X_PINCFG_REG,
+               .val = 0x08000000,
+       },
+       {
+               .reg = SX933X_PINDOUT_REG,
+               .val = 0x0000003F,
+       },
+       //
+       {
+               .reg = SX933X_IRQCFG0_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_IRQCFG1_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_IRQCFG2_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_IRQCFG3_REG,
+               .val = 0x00000000,
+       },
+       //
+       {
+               .reg = SX933X_SCANPERIOD_REG,
+               .val = 0x00000032,
+       },
+       {
+               .reg = SX933X_GNRLCTRL2_REG,
+               .val = 0x3F001F, //enable phase0~phase4  0x00FF0001,
+       },
+       {
+               .reg = SX933X_AFEPARAMSPH0_REG,
+               .val = 0x00010001,
+       },
+       {
+               .reg = SX933X_AFEPHPH0_REG,
+               .val = 0x00A00BE3,
+       },
+       {
+               .reg = SX933X_AFEPARAMSPH1_REG,
+               .val = 0x300004D4,
+       },
+       {
+               .reg = SX933X_AFEPHPH1_REG,
+               .val = 0x00,
+       },
+       {
+               .reg = SX933X_AFEPARAMSPH2_REG,
+               .val = 0x300004D4,//0x44F,//AFE setting for phase2  3.85pf
+       },
+       {
+               .reg = SX933X_AFEPHPH2_REG,
+               .val = 0x00,//Configure for phase2
+       },
+       {
+               .reg = SX933X_AFEPARAMSPH3_REG,
+               .val = 0x300004D4,//0x44F,//AFE setting for phase3 3.3pf
+       },
+       {
+               .reg = SX933X_AFEPHPH3_REG,
+               .val = 0x00,//Configure for phase3
+       },
+       {
+               .reg = SX933X_AFEPARAMSPH4_REG,
+               .val = 0x300004D4,//0x44F,//AFE setting for phase4 9.9pf
+       },
+       {
+               .reg = SX933X_AFEPHPH4_REG,
+               .val = 0x00,//Configure for phase4
+       },
+       {
+               .reg = SX933X_AFEPARAMSPH5_REG,
+               .val = 0x300004D4,
+       },
+       {
+               .reg = SX933X_AFEPHPH5_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADCFILTPH0_REG,
+               .val = 0x10162000,
+       },
+       {
+               .reg = SX933X_AVGBFILTPH0_REG,
+               .val = 0x20400017,
+       },
+       {
+               .reg = SX933X_AVGAFILTPH0_REG,
+               .val = 0x31CF9110,
+       },
+       {
+               .reg = SX933X_ADVDIG0PH0_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG1PH0_REG,
+               .val = 0x00,
+       },
+       {
+               .reg = SX933X_ADVDIG2PH0_REG,
+               .val = 0x00,
+       },
+       {
+               .reg = SX933X_ADVDIG3PH0_REG ,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG4PH0_REG,
+               .val = 0x10000,
+       },
+       {
+               .reg = SX933X_ADCFILTPH1_REG,
+               .val = 0x100000,
+       },
+       {
+               .reg = SX933X_AVGBFILTPH1_REG,
+               .val = 0x20600C00,
+       },
+       {
+               .reg = SX933X_AVGAFILTPH1_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG0PH1_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG1PH1_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG2PH1_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG3PH1_REG ,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG4PH1_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADCFILTPH2_REG,
+               .val = 0x100000,
+       },
+       {
+               .reg = SX933X_AVGBFILTPH2_REG,
+               .val = 0x20600C00,
+       },
+       {
+               .reg = SX933X_AVGAFILTPH2_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG0PH2_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG1PH2_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG2PH2_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG3PH2_REG ,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG4PH2_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADCFILTPH3_REG,
+               .val = 0x100000,
+       },
+       {
+               .reg = SX933X_AVGBFILTPH3_REG,
+               .val = 0x20600C00,
+       },
+       {
+               .reg = SX933X_AVGAFILTPH3_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG0PH3_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG1PH3_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG2PH3_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG3PH3_REG ,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG4PH3_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADCFILTPH4_REG,
+               .val = 0x100000,
+       },
+       {
+               .reg = SX933X_AVGBFILTPH4_REG,
+               .val = 0x20600C00,
+       },
+       {
+               .reg = SX933X_AVGAFILTPH4_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG0PH4_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG1PH4_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG2PH4_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG3PH4_REG ,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG4PH4_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADCFILTPH5_REG,
+               .val = 0x100000,
+       },
+       {
+               .reg = SX933X_AVGBFILTPH5_REG,
+               .val = 0x20600C00,
+       },
+       {
+               .reg = SX933X_AVGAFILTPH5_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG0PH5_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG1PH5_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG2PH5_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG3PH5_REG ,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_ADVDIG4PH5_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_REFCORRA_REG,
+               .val = 0x7B13B10,
+       },
+       {
+               .reg = SX933X_REFCORRB_REG,
+               .val = 0x4000000,
+       },
+       {
+               .reg = SX933X_SMARTSAR0A_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_SMARTSAR1A_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_SMARTSAR2A_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_SMARTSAR0B_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_SMARTSAR1B_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_SMARTSAR2B_REG,
+               .val = 0x00000000,
+       },
+       //
+       {
+               .reg = SX933X_AUTOFREQ0_REG,
+               .val = 0x00000000,
+       },
+       {
+               .reg = SX933X_AUTOFREQ1_REG,
+               .val = 0x00000000,
+       },
+       //
+       {
+               .reg = SX933X_HOSTIRQMSK_REG,
+               .val = 0x00000078,
+       },
+       {
+               .reg = SX933X_HOSTIRQCTRL_REG,
+               .val = 0x00,
+       }
+};
+
+static struct _buttonInfo psmtcButtons[] =
+{
+       {
+               .ProxMask = SX933X_STAT0_PROXSTAT_PH0_FLAG,
+               .BodyMask = SX933X_STAT0_BODYSTAT_PH0_FLAG,
+               .name = "Moto_CapSense_Ch0",
+               .enabled = false,
+               .used = false,
+       },
+       {
+               .ProxMask = SX933X_STAT0_PROXSTAT_PH1_FLAG,
+               .BodyMask = SX933X_STAT0_BODYSTAT_PH1_FLAG,
+               .name = "Moto_CapSense_Ch1",
+               .enabled = false,
+               .used = false,
+       },
+       {
+               .ProxMask = SX933X_STAT0_PROXSTAT_PH2_FLAG,
+               .BodyMask = SX933X_STAT0_BODYSTAT_PH2_FLAG,
+               .name = "Moto_CapSense_Ch2",
+               .enabled = false,
+               .used = false,
+       },
+       {
+               .ProxMask = SX933X_STAT0_PROXSTAT_PH3_FLAG,
+               .BodyMask = SX933X_STAT0_BODYSTAT_PH3_FLAG,
+               .name = "Moto_CapSense_Ch3",
+               .enabled = false,
+               .used = false,
+       },
+       {
+               .ProxMask = SX933X_STAT0_PROXSTAT_PH4_FLAG,
+               .BodyMask = SX933X_STAT0_BODYSTAT_PH4_FLAG,
+               .name = "Moto_CapSense_Ch4",
+               .enabled = false,
+               .used = false,
+       },
+};
+
+struct sx933x_platform_data
+{
+       int i2c_reg_num;
+       u32 button_used_flag;
+       struct regulator *cap_vdd;
+       bool cap_vdd_en;
+       struct smtc_reg_data *pi2c_reg;
+       int irq_gpio;
+       pbuttonInformation_t pbuttonInformation;
+
+       int (*get_is_nirq_low)(void);
+
+       int     (*init_platform_hw)(struct i2c_client *client);
+       void    (*exit_platform_hw)(struct i2c_client *client);
+};
+typedef struct sx933x_platform_data sx933x_platform_data_t;
+typedef struct sx933x_platform_data *psx933x_platform_data_t;
+
+/***************************************
+ *  define data struct/interrupt
+ *
+ ***************************************/
+
+#define MAX_NUM_STATUS_BITS (8)
+
+typedef struct sx93XX sx93XX_t, *psx93XX_t;
+struct sx93XX
+{
+       void * bus; /* either i2c_client or spi_client */
+
+       struct device *pdev; /* common device struction for linux */
+
+       void *pDevice; /* device specific struct pointer */
+
+       /* Function Pointers */
+       int (*init)(psx93XX_t this); /* (re)initialize device */
+
+       /* since we are trying to avoid knowing registers, create a pointer to a
+        * common read register which would be to read what the interrupt source
+        * is from
+        */
+       int (*refreshStatus)(psx93XX_t this); /* read register status */
+
+       int (*get_nirq_low)(void); /* get whether nirq is low (platform data) */
+
+       /* array of functions to call for corresponding status bit */
+       void (*statusFunc[MAX_NUM_STATUS_BITS])(psx93XX_t this);
+
+       /* Global variable */
+       u8              failStatusCode; /*Fail status code*/
+       bool    reg_in_dts;
+
+       spinlock_t       lock; /* Spin Lock used for nirq worker function */
+       int irq; /* irq number used */
+
+       /* whether irq should be ignored.. cases if enable/disable irq is not used
+        * or does not work properly */
+       char irq_disabled;
+
+       u8 useIrqTimer; /* older models need irq timer for pen up cases */
+
+       int irqTimeout; /* msecs only set if useIrqTimer is true */
+
+       /* struct workqueue_struct *ts_workq;  */  /* if want to use non default */
+       struct delayed_work dworker; /* work struct for worker function */
+       u8 phaseselect;
+};
+
+int sx93XX_IRQ_init(psx93XX_t this);
+
+#endif
diff --git a/drivers/input/misc/sx933x_sar.c b/drivers/input/misc/sx933x_sar.c
new file mode 100755 (executable)
index 0000000..2a3084c
--- /dev/null
@@ -0,0 +1,1156 @@
+/*! \file sx933x.c
+ * \brief  SX933x Driver
+ *
+ * Driver for the SX933x
+ * Copyright (c) 2018 Semtech Corp
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#define DRIVER_NAME "sx933x"
+
+#define MAX_WRITE_ARRAY_SIZE 32
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/syscalls.h>
+//#include <linux/wakelock.h>
+#include <linux/uaccess.h>
+#include <linux/sort.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+#include <linux/sensors.h>
+#include "sx933x.h"    /* main struct, interrupt,init,pointers */
+
+
+#define SX933x_DEBUG 1
+#define LOG_TAG "[sar SX933x]: "
+
+#if SX933x_DEBUG
+#define LOG_INFO(fmt, args...)    pr_info(LOG_TAG fmt, ##args)
+#else
+#define LOG_INFO(fmt, args...)
+#endif
+#define LOG_DBG(fmt, args...)   pr_info(LOG_TAG fmt, ##args) 
+
+#define USE_DTS_REG
+
+#define SX933x_I2C_M_WR                 0 /* for i2c Write */
+#define SX933x_I2C_M_RD                 1 /* for i2c Read */
+
+#define IDLE                       0
+#define PROXACTIVE                       1
+#define BODYACTIVE                       2
+
+#define MAIN_SENSOR            1 //CS1
+
+/* Failer Index */
+#define SX933x_ID_ERROR        1
+#define SX933x_NIRQ_ERROR      2
+#define SX933x_CONN_ERROR      3
+#define SX933x_I2C_ERROR       4
+
+/*! \struct sx933x
+ * Specialized struct containing input event data, platform data, and
+ * last cap state read if needed.
+ */
+typedef struct sx933x
+{
+       pbuttonInformation_t pbuttonInformation;
+       psx933x_platform_data_t hw;             /* specific platform data settings */
+} sx933x_t, *psx933x_t;
+
+static int irq_gpio_num;
+static psx93XX_t global_sx933x;
+
+static int sx933x_get_nirq_state(void)
+{
+       return  !gpio_get_value(irq_gpio_num);
+}
+
+
+/*! \fn static int sx933x_i2c_write_16bit(psx93XX_t this, u8 address, u8 value)
+ * \brief Sends a write register to the device
+ * \param this Pointer to main parent struct
+ * \param address 8-bit register address
+ * \param value   8-bit register value to write to address
+ * \return Value from i2c_master_send
+ */
+
+static int sx933x_i2c_write_16bit(psx93XX_t this, u16 reg_addr, u32 buf)
+{
+       int ret =  -ENOMEM;
+       struct i2c_client *i2c = 0;
+       struct i2c_msg msg;
+       unsigned char w_buf[6];
+
+       if (this && this->bus)
+       {
+               i2c = this->bus;
+               w_buf[0] = (u8)(reg_addr>>8);
+               w_buf[1] = (u8)(reg_addr);
+               w_buf[2] = (u8)(buf>>24);
+               w_buf[3] = (u8)(buf>>16);
+               w_buf[4] = (u8)(buf>>8);
+               w_buf[5] = (u8)(buf);
+
+               msg.addr = i2c->addr;
+               msg.flags = SX933x_I2C_M_WR;
+               msg.len = 6; //2bytes regaddr + 4bytes data
+               msg.buf = (u8 *)w_buf;
+
+               ret = i2c_transfer(i2c->adapter, &msg, 1);
+               if (ret < 0)
+                       LOG_DBG("%s - i2c write reg 0x%x error %d\n", __func__, reg_addr, ret);
+
+       }
+       return ret;
+}
+
+/*! \fn static int sx933x_i2c_read_16bit(psx93XX_t this, u8 address, u8 *value)
+ * \brief Reads a register's value from the device
+ * \param this Pointer to main parent struct
+ * \param address 8-Bit address to read from
+ * \param value Pointer to 8-bit value to save register value to
+ * \return Value from i2c_smbus_read_byte_data if < 0. else 0
+ */
+static int sx933x_i2c_read_16bit(psx93XX_t this, u16 reg_addr, u32 *data32)
+{
+       int ret =  -ENOMEM;
+       struct i2c_client *i2c = 0;
+       struct i2c_msg msg[2];
+       u8 w_buf[2];
+       u8 buf[4];
+
+       if (this && this->bus)
+       {
+               i2c = this->bus;
+
+               w_buf[0] = (u8)(reg_addr>>8);
+               w_buf[1] = (u8)(reg_addr);
+
+               msg[0].addr = i2c->addr;
+               msg[0].flags = SX933x_I2C_M_WR;
+               msg[0].len = 2;
+               msg[0].buf = (u8 *)w_buf;
+
+               msg[1].addr = i2c->addr;;
+               msg[1].flags = SX933x_I2C_M_RD;
+               msg[1].len = 4;
+               msg[1].buf = (u8 *)buf;
+
+               ret = i2c_transfer(i2c->adapter, msg, 2);
+               if (ret < 0)
+                       LOG_DBG("%s - i2c read reg 0x%x error %d\n", __func__, reg_addr, ret);
+
+               data32[0] = ((u32)buf[0]<<24) | ((u32)buf[1]<<16) | ((u32)buf[2]<<8) | ((u32)buf[3]);
+
+       }
+       return ret;
+}
+
+
+
+
+//static int sx933x_set_mode(psx93XX_t this, unsigned char mode);
+
+/*! \fn static int read_regStat(psx93XX_t this)
+ * \brief Shortcut to read what caused interrupt.
+ * \details This is to keep the drivers a unified
+ * function that will read whatever register(s)
+ * provide information on why the interrupt was caused.
+ * \param this Pointer to main parent struct
+ * \return If successful, Value of bit(s) that cause interrupt, else 0
+ */
+static int read_regStat(psx93XX_t this)
+{
+       u32 data = 0;
+       if (this)
+       {
+               if (sx933x_i2c_read_16bit(this,SX933X_HOSTIRQSRC_REG,&data) > 0) //bug
+                       return (data & 0x00FF);
+       }
+       return 0;
+}
+
+static int sx933x_Hardware_Check(psx93XX_t this)
+{
+       int ret;
+       u32 idCode;
+       u8 loop = 0;
+       this->failStatusCode = 0;
+
+       //Check th IRQ Status
+       while(this->get_nirq_low && this->get_nirq_low())
+       {
+               read_regStat(this);
+               msleep(100);
+               if(++loop >10)
+               {
+                       this->failStatusCode = SX933x_NIRQ_ERROR;
+                       break;
+               }
+       }
+
+       //Check I2C Connection
+       ret = sx933x_i2c_read_16bit(this, SX933X_INFO_REG, &idCode);
+       if(ret < 0)
+       {
+               this->failStatusCode = SX933x_I2C_ERROR;
+       }
+
+       if(idCode!= SX933X_WHOAMI_VALUE)
+       {
+               this->failStatusCode = SX933x_ID_ERROR;
+       }
+
+       LOG_DBG("sx933x idcode = 0x%x, failcode = 0x%x\n", idCode, this->failStatusCode);
+       return (int)this->failStatusCode;
+}
+
+static int sx933x_global_variable_init(psx93XX_t this)
+{
+       this->irq_disabled = 0;
+       this->failStatusCode = 0;
+       this->reg_in_dts = true;
+       return 0;
+}
+
+/*! \brief Perform a manual offset calibration
+ * \param this Pointer to main parent struct
+ * \return Value return value from the write register
+ */
+static int manual_offset_calibration(psx93XX_t this)
+{
+       int ret = 0;
+       ret = sx933x_i2c_write_16bit(this, SX933X_CMD_REG, I2C_REGCMD_COMPEN);
+       return ret;
+
+}
+
+/****************************************************************************/
+/*! \brief sysfs show function for manual calibration which currently just
+ * returns register value.
+ */
+static ssize_t manual_offset_calibration_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       u32 reg_value = 0;
+       psx93XX_t this = dev_get_drvdata(dev);
+
+       LOG_DBG("Reading IRQSTAT_REG\n");
+       sx933x_i2c_read_16bit(this,SX933X_HOSTIRQSRC_REG,&reg_value);
+       return sprintf(buf, "%d\n", reg_value);
+}
+
+
+static ssize_t manual_offset_calibration_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       unsigned long val;
+       psx93XX_t this = dev_get_drvdata(dev);
+
+       if (kstrtoul(buf, 10, &val))                //(strict_strtoul(buf, 10, &val)) {
+       {
+               LOG_DBG(" %s - Invalid Argument\n", __func__);
+               return -EINVAL;
+       }
+
+       if (val)
+               manual_offset_calibration(this);
+
+       return count;
+}
+
+/****************************************************************************/
+static ssize_t sx933x_register_write_store(struct device *dev,
+               struct device_attribute *attr,  const char *buf, size_t count)
+{
+       u32 reg_address = 0, val = 0;
+       psx93XX_t this = dev_get_drvdata(dev);
+
+       if (sscanf(buf, "%x,%x", &reg_address, &val) != 2)
+       {
+               LOG_DBG("%s - The number of data are wrong\n",__func__);
+               return -EINVAL;
+       }
+
+       sx933x_i2c_write_16bit(this, reg_address, val);
+
+       LOG_DBG("%s - Register(0x%x) data(0x%x)\n",__func__, reg_address, val);
+       return count;
+}
+
+static ssize_t sx933x_register_read_store(struct device *dev,
+               struct device_attribute *attr,  const char *buf, size_t count)
+{
+       u32 val=0;
+       int regist = 0;
+       int nirq_state = 0;
+       psx93XX_t this = dev_get_drvdata(dev);
+
+       if (sscanf(buf, "%x", &regist) != 1)
+       {
+               LOG_DBG("%s - The number of data are wrong\n",__func__);
+               return -EINVAL;
+       }
+
+       sx933x_i2c_read_16bit(this, regist, &val);
+       nirq_state = sx933x_get_nirq_state();
+
+       LOG_DBG("%s - Register(0x%2x) data(0x%4x) nirq_state(%d)\n",__func__, regist, val, nirq_state);
+       return count;
+}
+
+static void read_rawData(psx93XX_t this)
+{
+       u8 csx, index;
+       s32 useful;
+       s32 average;
+       s32 diff;
+       u32 uData;
+       u16 offset;
+       //s32 state = 0;
+
+       if(this)
+       {
+               for(csx =0; csx<5; csx++)
+               {
+                       index = csx*4;
+                       sx933x_i2c_read_16bit(this, SX933X_USEPH0_REG + index, &uData);
+                       useful = (s32)uData>>10;
+                       sx933x_i2c_read_16bit(this, SX933X_AVGPH0_REG + index, &uData);
+                       average = (s32)uData>>10;
+                       sx933x_i2c_read_16bit(this, SX933X_DIFFPH0_REG + index, &uData);
+                       diff = (s32)uData>>10;
+                       sx933x_i2c_read_16bit(this, SX933X_OFFSETPH0_REG + index*2, &uData);
+                       offset = (u16)(uData & 0x7FFF);
+                       //state = psmtcButtons[csx].state;
+                       LOG_DBG("[PH: %d] Useful = %d Average = %d, DIFF = %d Offset = %d \n",
+                                       csx,useful,average,diff,offset);
+               }
+       }
+}
+
+static ssize_t sx933x_raw_data_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       char *p = buf;
+       int csx;
+       s32 useful, average, diff;
+       u32 uData;
+       u16 offset;
+       psx93XX_t this = dev_get_drvdata(dev);
+       if(this) {
+               for(csx =0; csx<5; csx++) {
+                       sx933x_i2c_read_16bit(this, SX933X_USEPH0_REG + csx*4, &uData);
+                       useful = (s32)uData>>10;
+                       sx933x_i2c_read_16bit(this, SX933X_AVGPH0_REG + csx*4, &uData);
+                       average = (s32)uData>>10;
+                       sx933x_i2c_read_16bit(this, SX933X_DIFFPH0_REG + csx*4, &uData);
+                       diff = (s32)uData>>10;
+                       sx933x_i2c_read_16bit(this, SX933X_OFFSETPH0_REG + csx*8, &uData);
+                       offset = (u16)(uData & 0x7FFF);
+                       p += snprintf(p, PAGE_SIZE, "[PH: %d] Useful = %d, Average = %d, DIFF = %d Offset = %d \n",
+                                       csx,useful,average,diff,offset);
+               }
+       }
+       return (p-buf);
+}
+
+static DEVICE_ATTR(manual_calibrate, 0664, manual_offset_calibration_show,manual_offset_calibration_store);
+static DEVICE_ATTR(register_write,  0664, NULL,sx933x_register_write_store);
+static DEVICE_ATTR(register_read,0664, NULL,sx933x_register_read_store);
+static DEVICE_ATTR(raw_data,0664,sx933x_raw_data_show,NULL);
+
+static struct attribute *sx933x_attributes[] =
+{
+       &dev_attr_manual_calibrate.attr,
+       &dev_attr_register_write.attr,
+       &dev_attr_register_read.attr,
+       &dev_attr_raw_data.attr,
+       NULL,
+};
+static struct attribute_group sx933x_attr_group =
+{
+       .attrs = sx933x_attributes,
+};
+
+/**************************************/
+
+/*! \brief  Initialize I2C config from platform data
+ * \param this Pointer to main parent struct
+ */
+static void sx933x_reg_init(psx93XX_t this)
+{
+       psx933x_t pDevice = 0;
+       psx933x_platform_data_t pdata = 0;
+       int i = 0;
+       uint32_t tmpvalue;
+       /* configure device */
+       if (this && (pDevice = this->pDevice) && (pdata = pDevice->hw))
+       {
+               /*******************************************************************************/
+               // try to initialize from device tree!
+               /*******************************************************************************/
+               while ( i < ARRAY_SIZE(sx933x_i2c_reg_setup))
+               {
+                       /* Write all registers/values contained in i2c_reg */
+                       LOG_DBG("Going to Write Reg: 0x%x Value: 0x%x\n",
+                                       sx933x_i2c_reg_setup[i].reg,sx933x_i2c_reg_setup[i].val);
+                       tmpvalue = sx933x_i2c_reg_setup[i].val;
+                       if (sx933x_i2c_reg_setup[i].reg == SX933X_GNRLCTRL2_REG)
+                       {
+                               if((sx933x_i2c_reg_setup[i].val & 0x3F) == 0)
+                               {
+                                       tmpvalue = (sx933x_i2c_reg_setup[i].val|0x3F);
+                               }
+                       }
+                       sx933x_i2c_write_16bit(this, sx933x_i2c_reg_setup[i].reg, tmpvalue);
+                       i++;
+               }
+#ifdef USE_DTS_REG
+               if (this->reg_in_dts == true)
+               {
+                       i = 0;
+                       while ( i < pdata->i2c_reg_num)
+                       {
+                               /* Write all registers/values contained in i2c_reg */
+                               LOG_DBG("Going to Write Reg from dts: 0x%x Value: 0x%x\n",
+                                               pdata->pi2c_reg[i].reg,pdata->pi2c_reg[i].val);
+                               sx933x_i2c_write_16bit(this, pdata->pi2c_reg[i].reg,pdata->pi2c_reg[i].val);
+                               i++;
+                       }
+               }
+#endif
+               /*******************************************************************************/
+               sx933x_i2c_write_16bit(this, SX933X_CMD_REG,SX933X_PHASE_CONTROL);  //enable phase control
+       }
+       else {
+               LOG_DBG("ERROR! platform data 0x%p\n",pDevice->hw);
+       }
+
+}
+
+
+/*! \fn static int initialize(psx93XX_t this)
+ * \brief Performs all initialization needed to configure the device
+ * \param this Pointer to main parent struct
+ * \return Last used command's return value (negative if error)
+ */
+static int initialize(psx93XX_t this)
+{
+       int ret, retry;
+       if (this)
+       {
+               LOG_DBG("SX933x income initialize\n");
+               /* prepare reset by disabling any irq handling */
+               this->irq_disabled = 1;
+               disable_irq(this->irq);
+               /* perform a reset */
+               for ( retry = 10; retry > 0; retry-- ) {
+                       if (sx933x_i2c_write_16bit(this, SX933X_RESET_REG, I2C_SOFTRESET_VALUE) >= 0)
+                               break;
+                       LOG_DBG("SX933x write SX933X_RESET_REG retry:%d\n", 11 - retry);
+                       msleep(10);
+               }
+               /* wait until the reset has finished by monitoring NIRQ */
+               LOG_DBG("Sent Software Reset. Waiting until device is back from reset to continue.\n");
+               /* just sleep for awhile instead of using a loop with reading irq status */
+               msleep(100);
+               ret = sx933x_global_variable_init(this);
+               sx933x_reg_init(this);
+               msleep(100); /* make sure everything is running */
+               manual_offset_calibration(this);
+
+               /* re-enable interrupt handling */
+               enable_irq(this->irq);
+
+               /* make sure no interrupts are pending since enabling irq will only
+                * work on next falling edge */
+               read_regStat(this);
+               return 0;
+       }
+       return -ENOMEM;
+}
+
+/*!
+ * \brief Handle what to do when a touch occurs
+ * \param this Pointer to main parent struct
+ */
+static void touchProcess(psx93XX_t this)
+{
+       int counter = 0;
+       u32 i = 0;
+       u32 touchFlag = 0;
+       int numberOfButtons = 0;
+       psx933x_t pDevice = NULL;
+       struct _buttonInfo *buttons = NULL;
+       struct input_dev *input = NULL;
+
+       struct _buttonInfo *pCurrentButton  = NULL;
+
+       if (this && (pDevice = this->pDevice))
+       {
+               sx933x_i2c_read_16bit(this, SX933X_STAT0_REG, &i);
+               LOG_DBG("touchProcess STAT0_REG:0x%08x\n", i);
+
+               buttons = pDevice->pbuttonInformation->buttons;
+               numberOfButtons = pDevice->pbuttonInformation->buttonSize;
+
+               if (unlikely( buttons==NULL ))
+               {
+                       LOG_DBG(":ERROR!! buttons NULL!!!\n");
+                       return;
+               }
+
+               for (counter = 0; counter < numberOfButtons; counter++)
+               {
+                       if (buttons[counter].enabled == false) {
+                               LOG_INFO("touchProcess %s disabled, ignor this\n", buttons[counter].name);
+                               continue;
+                       }
+                       if (buttons[counter].used== false) {
+                               LOG_INFO("touchProcess %s unused, ignor this\n", buttons[counter].name);
+                               continue;
+                       }
+                       pCurrentButton = &buttons[counter];                     
+                       if (pCurrentButton==NULL)
+                       {
+                               LOG_DBG("ERROR!! current button at index: %d NULL!!!\n", counter);
+                               return; // ERRORR!!!!
+                       }
+                       input = pCurrentButton->input_dev;
+                       if (input==NULL)
+                       {
+                               LOG_DBG("ERROR!! current button input at index: %d NULL!!!\n", counter);
+                               return; // ERRORR!!!!
+                       }
+
+                       touchFlag = i & (pCurrentButton->ProxMask | pCurrentButton->BodyMask);
+                       if (touchFlag == (pCurrentButton->ProxMask | pCurrentButton->BodyMask)) {
+                               if (pCurrentButton->state == BODYACTIVE)
+                                       LOG_DBG(" %s already BODYACTIVE\n", pCurrentButton->name);
+                               else {
+                                       input_report_abs(input, ABS_DISTANCE, 2);
+                                       input_sync(input);
+                                       pCurrentButton->state = BODYACTIVE;
+                                       LOG_DBG(" %s report 5mm BODYACTIVE\n", pCurrentButton->name);
+                               }
+                       } else if (touchFlag == pCurrentButton->ProxMask) {
+                               if (pCurrentButton->state == PROXACTIVE)
+                                       LOG_DBG(" %s already PROXACTIVE\n", pCurrentButton->name);
+                               else {
+                                       input_report_abs(input, ABS_DISTANCE, 1);
+                                       input_sync(input);
+                                       pCurrentButton->state = PROXACTIVE;
+                                       LOG_DBG(" %s report 15mm PROXACTIVE\n", pCurrentButton->name);
+                               }
+                       }else if (touchFlag == 0) {
+                               if (pCurrentButton->state == IDLE)
+                                       LOG_DBG("%s already released.\n", pCurrentButton->name);
+                               else {
+                                       input_report_abs(input, ABS_DISTANCE, 0);
+                                       input_sync(input);
+                                       pCurrentButton->state = IDLE;
+                                       LOG_DBG("%s report  released.\n", pCurrentButton->name);
+                               }
+                       }
+               }
+               LOG_INFO("Leaving touchProcess()\n");
+       }
+}
+
+static int sx933x_parse_dt(struct sx933x_platform_data *pdata, struct device *dev)
+{
+       struct device_node *dNode = dev->of_node;
+       enum of_gpio_flags flags;
+
+       if (dNode == NULL)
+               return -ENODEV;
+
+       pdata->irq_gpio= of_get_named_gpio_flags(dNode,
+                       "Semtech,nirq-gpio", 0, &flags);
+       irq_gpio_num = pdata->irq_gpio;
+       if (pdata->irq_gpio < 0)
+       {
+               LOG_DBG("%s - get irq_gpio error\n", __func__);
+               return -ENODEV;
+       }
+
+       pdata->button_used_flag = 0;
+       of_property_read_u32(dNode,"Semtech,button-flag",&pdata->button_used_flag);
+       LOG_INFO("%s -  used button 0x%x \n", __func__, pdata->button_used_flag);
+
+#ifdef USE_DTS_REG
+       // load in registers from device tree
+       of_property_read_u32(dNode,"Semtech,reg-num",&pdata->i2c_reg_num);
+       // layout is register, value, register, value....
+       // if an extra item is after just ignore it. reading the array in will cause it to fail anyway
+       LOG_INFO("%s -  size of elements %d \n", __func__,pdata->i2c_reg_num);
+       if (pdata->i2c_reg_num > 0)
+       {
+               // initialize platform reg data array
+               pdata->pi2c_reg = devm_kzalloc(dev,sizeof(struct smtc_reg_data)*pdata->i2c_reg_num, GFP_KERNEL);
+               if (unlikely(pdata->pi2c_reg == NULL))
+               {
+                       LOG_DBG("%s -  size of elements %d alloc error\n", __func__,pdata->i2c_reg_num);
+                       return -ENOMEM;
+               }
+
+               // initialize the array
+               if (of_property_read_u32_array(dNode,"Semtech,reg-init",(u32*)&(pdata->pi2c_reg[0]),sizeof(struct smtc_reg_data)*pdata->i2c_reg_num/sizeof(u32)))
+                       return -ENOMEM;
+       }
+#endif
+       LOG_INFO("%s -[%d] parse_dt complete\n", __func__,pdata->irq_gpio);
+       return 0;
+}
+
+/* get the NIRQ state (1->NIRQ-low, 0->NIRQ-high) */
+static int sx933x_init_platform_hw(struct i2c_client *client)
+{
+       psx93XX_t this = i2c_get_clientdata(client);
+       struct sx933x *pDevice = NULL;
+       struct sx933x_platform_data *pdata = NULL;
+
+       int rc = 0;
+
+       LOG_INFO("%s init_platform_hw start!",__func__);
+
+       if (this && (pDevice = this->pDevice) && (pdata = pDevice->hw))
+       {
+               if (gpio_is_valid(pdata->irq_gpio))
+               {
+                       rc = gpio_request(pdata->irq_gpio, "sx933x_irq_gpio");
+                       if (rc < 0)
+                       {
+                               LOG_DBG("SX933x Request gpio. Fail![%d]\n", rc);
+                               return rc;
+                       }
+                       rc = gpio_direction_input(pdata->irq_gpio);
+                       if (rc < 0)
+                       {
+                               LOG_DBG("SX933x Set gpio direction. Fail![%d]\n", rc);
+                               return rc;
+                       }
+                       this->irq = client->irq = gpio_to_irq(pdata->irq_gpio);
+               }
+               else
+               {
+                       LOG_DBG("SX933x Invalid irq gpio num.(init)\n");
+               }
+       }
+       else
+       {
+               LOG_DBG("%s - Do not init platform HW", __func__);
+       }
+       return rc;
+}
+
+static void sx933x_exit_platform_hw(struct i2c_client *client)
+{
+       psx93XX_t this = i2c_get_clientdata(client);
+       struct sx933x *pDevice = NULL;
+       struct sx933x_platform_data *pdata = NULL;
+
+       if (this && (pDevice = this->pDevice) && (pdata = pDevice->hw))
+       {
+               if (gpio_is_valid(pdata->irq_gpio))
+               {
+                       gpio_free(pdata->irq_gpio);
+               }
+               else
+               {
+                       LOG_DBG("Invalid irq gpio num.(exit)\n");
+               }
+       }
+       return;
+}
+
+static int capsensor_set_enable(struct sensors_classdev *sensors_cdev,
+               unsigned int enable)
+{
+       bool disableFlag = true;
+       int i = 0;
+       u32 temp = 0x0;
+
+       for (i = 0; i < ARRAY_SIZE(psmtcButtons); i++) {
+               if (strcmp(sensors_cdev->name, psmtcButtons[i].name) == 0) {
+                       if (enable == 1) {
+                               LOG_DBG("enable cap sensor : %s\n", sensors_cdev->name);
+                               sx933x_i2c_read_16bit(global_sx933x, SX933X_GNRLCTRL2_REG, &temp);
+                               temp = temp | 0x0000001F;
+                               LOG_INFO("set reg 0x%x val 0x%x\n", SX933X_GNRLCTRL2_REG, temp);
+                               sx933x_i2c_write_16bit(global_sx933x, SX933X_GNRLCTRL2_REG, temp);
+                               psmtcButtons[i].enabled = true;
+                               input_report_abs(psmtcButtons[i].input_dev, ABS_DISTANCE, 0);
+                               input_sync(psmtcButtons[i].input_dev);
+
+                               manual_offset_calibration(global_sx933x);
+                       } else if (enable == 0) {
+                               LOG_DBG("disable cap sensor : %s\n", sensors_cdev->name);
+                               psmtcButtons[i].enabled = false;
+                               input_report_abs(psmtcButtons[i].input_dev, ABS_DISTANCE, -1);
+                               input_sync(psmtcButtons[i].input_dev);
+                       } else {
+                               LOG_DBG("unknown enable symbol\n");
+                       }
+               }
+       }
+
+       //if all chs disabled, then disable all
+       for (i = 0; i < ARRAY_SIZE(psmtcButtons); i++) {
+               if (psmtcButtons[i].enabled) {
+                       disableFlag = false;
+                       break;
+               }
+       }
+       if (disableFlag) {
+               LOG_DBG("disable all chs\n");
+               sx933x_i2c_read_16bit(global_sx933x, SX933X_GNRLCTRL2_REG, &temp);
+               LOG_INFO("read reg 0x%x val 0x%x\n", SX933X_GNRLCTRL2_REG, temp);
+               temp = temp & 0xFFFFFFE0;
+               LOG_INFO("set reg 0x%x val 0x%x\n", SX933X_GNRLCTRL2_REG, temp);
+               sx933x_i2c_write_16bit(global_sx933x, SX933X_GNRLCTRL2_REG, temp);
+       }
+       return 0;
+}
+
+/*! \fn static int sx933x_probe(struct i2c_client *client, const struct i2c_device_id *id)
+ * \brief Probe function
+ * \param client pointer to i2c_client
+ * \param id pointer to i2c_device_id
+ * \return Whether probe was successful
+ */
+static int sx933x_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       int i = 0;
+       int err = 0;
+
+       psx93XX_t this = 0;
+       psx933x_t pDevice = 0;
+       psx933x_platform_data_t pplatData = 0;
+       struct totalButtonInformation *pButtonInformationData = NULL;
+       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+
+       LOG_DBG("sx933x_probe()\n");    
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA))
+       {
+               LOG_DBG("Check i2c functionality.Fail!\n");
+               err = -EIO;
+               return err;
+       }
+
+       this = devm_kzalloc(&client->dev,sizeof(sx93XX_t), GFP_KERNEL); /* create memory for main struct */
+       LOG_DBG("Initialized Main Memory: 0x%p\n",this);
+
+       pButtonInformationData = devm_kzalloc(&client->dev , sizeof(struct totalButtonInformation), GFP_KERNEL);
+       if (!pButtonInformationData)
+       {
+               LOG_DBG("Failed to allocate memory(totalButtonInformation)\n");
+               err = -ENOMEM;
+               return err;
+       }
+
+       pButtonInformationData->buttonSize = ARRAY_SIZE(psmtcButtons);
+       pButtonInformationData->buttons =  psmtcButtons;
+       pplatData = devm_kzalloc(&client->dev,sizeof(struct sx933x_platform_data), GFP_KERNEL);
+       if (!pplatData)
+       {
+               LOG_DBG("platform data is required!\n");
+               return -EINVAL;
+       }
+       pplatData->get_is_nirq_low = sx933x_get_nirq_state;
+       pplatData->pbuttonInformation = pButtonInformationData;
+
+       client->dev.platform_data = pplatData;
+       err = sx933x_parse_dt(pplatData, &client->dev);
+       if (err)
+       {
+               LOG_DBG("could not setup pin\n");
+               return ENODEV;
+       }
+
+       pplatData->init_platform_hw = sx933x_init_platform_hw;
+       LOG_INFO("SX933x init_platform_hw done!\n");
+
+       if (this)
+       {
+               LOG_INFO("SX933x initialize start!!");
+               /* In case we need to reinitialize data
+                * (e.q. if suspend reset device) */
+               this->init = initialize;
+               /* shortcut to read status of interrupt */
+               this->refreshStatus = read_regStat;
+               /* pointer to function from platform data to get pendown
+                * (1->NIRQ=0, 0->NIRQ=1) */
+               this->get_nirq_low = pplatData->get_is_nirq_low;
+               /* save irq in case we need to reference it */
+               this->irq = client->irq;
+               /* do we need to create an irq timer after interrupt ? */
+               this->useIrqTimer = 0;
+
+               /* Setup function to call on corresponding reg irq source bit */
+               if (MAX_NUM_STATUS_BITS>= 8)
+               {
+                       this->statusFunc[0] = 0; /* TXEN_STAT */
+                       this->statusFunc[1] = 0; /* UNUSED */
+                       this->statusFunc[2] = touchProcess; /* body&table */
+                       this->statusFunc[3] = read_rawData; /* CONV_STAT */
+                       this->statusFunc[4] = 0; /* COMP_STAT */
+                       this->statusFunc[5] = touchProcess; /* RELEASE_STAT */
+                       this->statusFunc[6] = touchProcess; /* TOUCH_STAT  */
+                       this->statusFunc[7] = 0; /* RESET_STAT */
+               }
+
+               /* setup i2c communication */
+               this->bus = client;
+               i2c_set_clientdata(client, this);
+
+               /* record device struct */
+               this->pdev = &client->dev;
+
+               /* create memory for device specific struct */
+               this->pDevice = pDevice = devm_kzalloc(&client->dev,sizeof(sx933x_t), GFP_KERNEL);
+               LOG_INFO("initialized Device Specific Memory: 0x%p\n",pDevice);
+
+               if (pDevice)
+               {
+                       /* for accessing items in user data (e.g. calibrate) */
+                       err = sysfs_create_group(&client->dev.kobj, &sx933x_attr_group);
+                       //sysfs_create_group(client, &sx933x_attr_group);
+
+                       /* Add Pointer to main platform data struct */
+                       pDevice->hw = pplatData;
+
+                       /* Check if we hava a platform initialization function to call*/
+                       if (pplatData->init_platform_hw)
+                               pplatData->init_platform_hw(client);
+
+                       /* Initialize the button information initialized with keycodes */
+                       pDevice->pbuttonInformation = pplatData->pbuttonInformation;
+
+                       for (i = 0; i < pButtonInformationData->buttonSize; i++)
+                       {
+                               if (pplatData->button_used_flag>>i & 0x01) {
+                                       pButtonInformationData->buttons[i].used = true;
+                                       pButtonInformationData->buttons[i].state = IDLE;
+                                       pButtonInformationData->buttons[i].input_dev = input_allocate_device();
+                                       if (!pButtonInformationData->buttons[i].input_dev)
+                                               return -ENOMEM;
+                                       pButtonInformationData->buttons[i].input_dev->name = pButtonInformationData->buttons[i].name;
+                                       /* Set all the keycodes */
+                                       __set_bit(EV_ABS, pButtonInformationData->buttons[i].input_dev->evbit);
+                                       input_set_abs_params(pButtonInformationData->buttons[i].input_dev, ABS_DISTANCE, -1, 100, 0, 0);
+
+                                       err = input_register_device(pButtonInformationData->buttons[i].input_dev);
+                                       /* report a unused val, then first val will report after enable */
+                                       input_report_abs(pButtonInformationData->buttons[i].input_dev, ABS_DISTANCE, -1);
+                                       input_sync(pButtonInformationData->buttons[i].input_dev);
+
+                                       pButtonInformationData->buttons[i].sensors_capsensor_cdev.sensors_enable = capsensor_set_enable;
+                                       pButtonInformationData->buttons[i].sensors_capsensor_cdev.sensors_poll_delay = NULL;
+                                       pButtonInformationData->buttons[i].sensors_capsensor_cdev.name = pButtonInformationData->buttons[i].name;
+                                       pButtonInformationData->buttons[i].sensors_capsensor_cdev.vendor = "semtech";
+                                       pButtonInformationData->buttons[i].sensors_capsensor_cdev.version = 1;
+                                       pButtonInformationData->buttons[i].sensors_capsensor_cdev.type = SENSOR_TYPE_MOTO_CAPSENSE;
+                                       pButtonInformationData->buttons[i].sensors_capsensor_cdev.max_range = "5";
+                                       pButtonInformationData->buttons[i].sensors_capsensor_cdev.resolution = "5.0";
+                                       pButtonInformationData->buttons[i].sensors_capsensor_cdev.sensor_power = "3";
+                                       pButtonInformationData->buttons[i].sensors_capsensor_cdev.min_delay = 0;
+                                       pButtonInformationData->buttons[i].sensors_capsensor_cdev.fifo_reserved_event_count = 0;
+                                       pButtonInformationData->buttons[i].sensors_capsensor_cdev.fifo_max_event_count = 0;
+                                       pButtonInformationData->buttons[i].sensors_capsensor_cdev.delay_msec = 100;
+                                       pButtonInformationData->buttons[i].sensors_capsensor_cdev.enabled = 0;
+                                       pButtonInformationData->buttons[i].enabled = false;
+
+                                       err = sensors_classdev_register(&pButtonInformationData->buttons[i].input_dev->dev, &pButtonInformationData->buttons[i].sensors_capsensor_cdev);
+                                       if (err < 0)
+                                               LOG_DBG("create %d cap sensor_class  file failed (%d)\n", i, err);
+                               }
+                       }
+               }
+
+               pplatData->cap_vdd = regulator_get(&client->dev, "cap_vdd");
+
+               if (IS_ERR(pplatData->cap_vdd)) {
+                       if (PTR_ERR(pplatData->cap_vdd) == -EPROBE_DEFER) {
+                               err = PTR_ERR(pplatData->cap_vdd);
+                               return err;
+                       }    
+                       LOG_DBG("%s: Failed to get regulator\n",
+                                       __func__);
+               } else {
+                       err = regulator_enable(pplatData->cap_vdd);
+                       if (err) {
+                               regulator_put(pplatData->cap_vdd);
+                               LOG_DBG("%s: Error %d enable regulator\n",
+                                               __func__, err);
+                               return err;
+                       }    
+                       pplatData->cap_vdd_en = true;
+                       LOG_DBG("cap_vdd regulator is %s\n",
+                                       regulator_is_enabled(pplatData->cap_vdd) ?
+                                       "on" : "off");
+               }
+               sx93XX_IRQ_init(this);
+               /* call init function pointer (this should initialize all registers */
+               if (this->init) {
+                       this->init(this);
+               }
+               else {
+                       LOG_DBG("No init function!!!!\n");
+                       return -ENOMEM;
+               }
+       }       else    {
+               return -1;
+       }
+
+       pplatData->exit_platform_hw = sx933x_exit_platform_hw;
+
+       if (sx933x_Hardware_Check(this) != 0) {
+               LOG_DBG("sx933x_Hardware_CheckFail!\n");
+               //return -1;
+       }
+
+       global_sx933x = this;
+       LOG_INFO("sx933x_probe() Done\n");
+       return 0;
+}
+
+/*! \fn static int sx933x_remove(struct i2c_client *client)
+ * \brief Called when device is to be removed
+ * \param client Pointer to i2c_client struct
+ * \return Value 0
+ */
+//static int __devexit sx933x_remove(struct i2c_client *client)
+static int sx933x_remove(struct i2c_client *client)
+{
+       psx933x_platform_data_t pplatData =0;
+       psx933x_t pDevice = 0; 
+       struct _buttonInfo *pCurrentbutton;
+       int i = 0;
+       psx93XX_t this = i2c_get_clientdata(client);
+       LOG_DBG("sx933x_remove");
+       if (this && (pDevice = this->pDevice))
+       {    
+               free_irq(this->irq, this);
+               cancel_delayed_work_sync(&(this->dworker));     
+
+               sysfs_remove_group(&client->dev.kobj, &sx933x_attr_group);
+               pplatData = client->dev.platform_data;
+               if (pplatData && pplatData->exit_platform_hw)
+                       pplatData->exit_platform_hw(client);
+               if (pplatData->cap_vdd_en) {
+                       regulator_disable(pplatData->cap_vdd); 
+                       regulator_put(pplatData->cap_vdd);
+               }
+               for (i = 0; i <pDevice->pbuttonInformation->buttonSize; i++) {
+                       pCurrentbutton = &(pDevice->pbuttonInformation->buttons[i]);
+                       if (pCurrentbutton->used == true) {
+                               sensors_classdev_unregister(&(pCurrentbutton->sensors_capsensor_cdev));
+                               input_unregister_device(pCurrentbutton->input_dev);
+                       }
+               }
+       }
+       return 0;
+}
+
+
+#if 1//def CONFIG_PM
+/*====================================================*/
+/***** Kernel Suspend *****/
+static int sx933x_suspend(struct device *dev)
+{
+       psx93XX_t this = dev_get_drvdata(dev);
+       if (this) {
+               disable_irq(this->irq);
+               //sx933x_i2c_write_16bit(this,SX933X_CPS_CTRL0_REG,0x20);//make sx933x in Sleep mode
+       }
+       return 0;
+}
+/***** Kernel Resume *****/
+static int sx933x_resume(struct device *dev)
+{
+       psx93XX_t this = dev_get_drvdata(dev);
+       if (this) {
+               enable_irq(this->irq);
+               //sx933x_i2c_write_16bit(this,SX933X_CPS_CTRL0_REG,0x27);//Exit from Sleep mode
+       }
+       return 0;
+}
+/*====================================================*/
+#else
+#define sx933x_suspend         NULL
+#define sx933x_resume          NULL
+#endif /* CONFIG_PM */
+
+static struct i2c_device_id sx933x_idtable[] =
+{
+       { DRIVER_NAME, 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, sx933x_idtable);
+#ifdef CONFIG_OF
+static struct of_device_id sx933x_match_table[] =
+{
+       { .compatible = "Semtech,sx933x",},
+       { },
+};
+#else
+#define sx933x_match_table NULL
+#endif
+static const struct dev_pm_ops sx933x_pm_ops =
+{
+       .suspend = sx933x_suspend,
+       .resume = sx933x_resume,
+};
+static struct i2c_driver sx933x_driver =
+{
+       .driver = {
+               .owner                  = THIS_MODULE,
+               .name                   = DRIVER_NAME,
+               .of_match_table = sx933x_match_table,
+               .pm                             = &sx933x_pm_ops,
+       },
+       .id_table               = sx933x_idtable,
+       .probe                  = sx933x_probe,
+       .remove                 = sx933x_remove,
+};
+static int __init sx933x_I2C_init(void)
+{
+       return i2c_add_driver(&sx933x_driver);
+}
+static void __exit sx933x_I2C_exit(void)
+{
+       i2c_del_driver(&sx933x_driver);
+}
+
+module_init(sx933x_I2C_init);
+module_exit(sx933x_I2C_exit);
+
+MODULE_AUTHOR("Semtech Corp. (http://www.semtech.com/)");
+MODULE_DESCRIPTION("SX933x Capacitive Proximity Controller Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1");
+
+static void sx93XX_schedule_work(psx93XX_t this, unsigned long delay)
+{
+       unsigned long flags;
+       if (this)
+       {
+               LOG_INFO("sx93XX_schedule_work()\n");
+               spin_lock_irqsave(&this->lock,flags);
+               /* Stop any pending penup queues */
+               cancel_delayed_work(&this->dworker);
+               //after waiting for a delay, this put the job in the kernel-global workqueue. so no need to create new thread in work queue.
+               schedule_delayed_work(&this->dworker,delay);
+               spin_unlock_irqrestore(&this->lock,flags);
+       }
+       else
+               LOG_DBG("sx93XX_schedule_work, NULL psx93XX_t\n");
+}
+
+static irqreturn_t sx93XX_irq(int irq, void *pvoid)
+{
+       psx93XX_t this = 0;
+       if (pvoid)
+       {
+               this = (psx93XX_t)pvoid;
+               if ((!this->get_nirq_low) || this->get_nirq_low())
+               {
+                       LOG_INFO("sx93XX_irq - call sx93XX_schedule_work\n");
+                       sx93XX_schedule_work(this,0);
+               }
+               else
+               {
+                       LOG_DBG("sx93XX_irq - nirq read high\n");
+               }
+       }
+       else
+       {
+               LOG_DBG("sx93XX_irq, NULL pvoid\n");
+       }
+       return IRQ_HANDLED;
+}
+
+static void sx93XX_worker_func(struct work_struct *work)
+{
+       psx93XX_t this = 0;
+       int status = 0;
+       int counter = 0;
+       u8 nirqLow = 0;
+       if (work)
+       {
+               this = container_of(work,sx93XX_t,dworker.work);
+
+               if (!this)
+               {
+                       LOG_DBG("sx93XX_worker_func, NULL sx93XX_t\n");
+                       return;
+               }
+               if (unlikely(this->useIrqTimer))
+               {
+                       if ((!this->get_nirq_low) || this->get_nirq_low())
+                       {
+                               nirqLow = 1;
+                       }
+               }
+               /* since we are not in an interrupt don't need to disable irq. */
+               status = this->refreshStatus(this);
+               counter = -1;
+               LOG_INFO("Worker_func - Refresh Status %d, use_timer_in_irq:%d\n", status, this->useIrqTimer);
+
+               while((++counter) < MAX_NUM_STATUS_BITS)   /* counter start from MSB */
+               {
+                       if (((status>>counter) & 0x01) && (this->statusFunc[counter]))
+                       {
+                               LOG_INFO("SX933x Function Pointer Found. Calling\n");
+                               this->statusFunc[counter](this);
+                       }
+               }
+               if (unlikely(this->useIrqTimer && nirqLow))
+               {
+                       /* Early models and if RATE=0 for newer models require a penup timer */
+                       /* Queue up the function again for checking on penup */
+                       sx93XX_schedule_work(this,msecs_to_jiffies(this->irqTimeout));
+               }
+       }
+       else
+       {
+               LOG_DBG("sx93XX_worker_func, NULL work_struct\n");
+       }
+}
+
+int sx93XX_IRQ_init(psx93XX_t this)
+{
+       int err = 0;
+       if (this && this->pDevice)
+       {
+               /* initialize spin lock */
+               spin_lock_init(&this->lock);
+               /* initialize worker function */
+               INIT_DELAYED_WORK(&this->dworker, sx93XX_worker_func);
+               /* initailize interrupt reporting */
+               this->irq_disabled = 0;
+               err = request_irq(this->irq, sx93XX_irq, IRQF_TRIGGER_FALLING,
+                               this->pdev->driver->name, this);
+               if (err)
+               {
+                       LOG_DBG("irq %d busy?\n", this->irq);
+                       return err;
+               }
+               LOG_DBG("registered with irq (%d)\n", this->irq);
+       }
+       return -ENOMEM;
+}
old mode 100644 (file)
new mode 100755 (executable)
index 931d0d8..4add8f7
@@ -733,6 +733,7 @@ static int s2mpu09_pmic_probe(struct platform_device *pdev)
                }
        }
 
+       s2mpu09_update_reg(s2mpu09->i2c, S2MPU09_PMIC_REG_L25CTRL, 0xC0, 0xC0);
        pr_info("%s s2mpu09 pmic driver Loading end\n", __func__);
        s2mpu09_update_reg(s2mpu09->i2c, S2MPU09_PMIC_REG_RTCBUF, 0x4, 0x4);