sensor: add sar sensor drivers
authorhq_guohongtao5_tmp <guohongtao5@huaqin.com>
Thu, 2 Aug 2018 06:58:56 +0000 (14:58 +0800)
committerxiest1 <xiest1@lenovo.com>
Tue, 5 Nov 2019 09:29:38 +0000 (17:29 +0800)
add sar sensor drivers

Bug:HQ00000000

Workaround:no

Change-Id: Ie19158a239feb69a76f7eb547b4ab5a96587c406
Signed-off-by: hq_guohongtao5_tmp <guohongtao5@huaqin.com>
arch/arm64/boot/dts/exynos/exynos9609-wing.dts
arch/arm64/boot/dts/exynos/wing-sensor.dtsi [new file with mode: 0755]
arch/arm64/configs/wing_defconfig
drivers/input/misc/Kconfig [changed mode: 0644->0755]
drivers/input/misc/Makefile [changed mode: 0644->0755]
drivers/input/misc/sx932x.c [new file with mode: 0755]
drivers/input/misc/sx932x.h [new file with mode: 0755]

index 38ffdc96c97394258770e6048c9650ec6d26f68a..65ab95abd13fe62fd9a31c7b8047052df36708eb 100755 (executable)
@@ -17,6 +17,7 @@
 #include "modem-ss360ap-sit-pdata.dtsi"
 #include "exynos9610-display-lcd.dtsi"
 #include "novatek-nt36xxx-i2c.dtsi"
+#include "wing-sensor.dtsi"
 
 / {
        compatible = "samsung,exynos9610", "samsung,WING";
                samsung,pin-drv = <0>;
        };
 */
+       cap_int_status: cap_int_status {
+               samsung,pins = "gpa2-6";
+               samsung,pin-function = <0>;
+               samsung,pin-val = <1>;
+               samsung,pin-pud = <1>;
+       };
 };
 
 &pinctrl_4 {
diff --git a/arch/arm64/boot/dts/exynos/wing-sensor.dtsi b/arch/arm64/boot/dts/exynos/wing-sensor.dtsi
new file mode 100755 (executable)
index 0000000..315a480
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2010 - 2017 Novatek, Inc.
+ *
+ * $Revision: 22971 $
+ * $Date: 2018-02-08 16:05:40 +0800 (ι€±ε››, 08 δΊŒζœˆ 2018) $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+
+&hsi2c_7 {
+       status = "okay";
+       samsung,reset-before-trans;
+       clock-frequency = <400000>;
+       Semtech_sx9320@28 {
+               compatible = "Semtech,sx932x";
+               reg = <0x28>;
+               cap_vdd-supply = <&l3_reg>;
+               Semtech,nirq-gpio = <&gpa2 6 0>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&cap_int_status>;
+               egistec,gpio_rst = <&gpa1 1 0>;
+               status = "ok";  /**/
+               Semtech,reg-num = <46>; /* total registers number to initialize*/
+                       Semtech,reg-init  = /bits/ 8 < 0x10 0x16
+                                0x20 0x00
+                                0x23 0x00
+                                0x24 0x44
+                                0x26 0x01
+                                0x27 0x44
+                                0x28 0x01 /*PH0 to CS0 input*/
+                                0x29 0x04
+                                0x2A 0x10 /*PH2 CS2-input,CS1-dync,CS0-HZ*/
+                                0x2B 0x00
+                                0x2C 0x12
+                                0x2D 0x08
+                                0x30 0x09
+                                0x31 0x09
+                                0x32 0x08
+                                0x33 0x20
+                                0x34 0x0C
+                                0x35 0x00
+                                0x36 0x1b
+                                0x37 0x1b
+                                0x40 0x00
+                                0x41 0x00
+                                0x42 0x00
+                                0x43 0x00
+                                0x44 0x00
+                                0x45 0x05
+                                0x46 0x00
+                                0x47 0x00
+                                0x48 0x00
+                                0x49 0x80
+                                0x4A 0x00
+                                0x4B 0x00
+                                0x4C 0x00
+                                0x4D 0x00
+                                0x4E 0x80
+                                0x4F 0x0C
+                                0x50 0x00
+                                0x51 0x70
+                                0x52 0x20
+                                0x53 0xE1
+                                0x54 0xF0
+                                0x05 0x70
+                                0x06 0x00
+                                0x07 0x00
+                                0x08 0x00
+                               0x11 0x27>;
+
+       };
+
+};
index 85cd6f6cfad78787cc442ae47f718b6381ca15f7..48fa4efb38ca4d6a90bdc41a4175882dee2662a7 100644 (file)
@@ -529,3 +529,4 @@ CONFIG_HARDENED_USERCOPY=y
 CONFIG_SECURITY_SELINUX=y
 CONFIG_CRYPTO_DISKCIPHER=y
 CONFIG_EXYNOS_FMP=y
+CONFIG_SARSENSOR_SX9325=y
old mode 100644 (file)
new mode 100755 (executable)
index 4588c86..4846cb3
@@ -881,4 +881,11 @@ config INPUT_S2MU106_HAPTIC
         The Haptic Motor driver support both ERM and
         LRA type actuators.
 
+config SARSENSOR_SX9325
+       bool "SARSENSOR SX9325"
+       default n
+       help
+         Say Y here if you have a sar sensor SX9325 connected
+         to your system.If unsure, say N.
+
 endif
old mode 100644 (file)
new mode 100755 (executable)
index d89ef46..f2cd795
@@ -84,3 +84,4 @@ 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_SX9325) += sx932x.o
\ No newline at end of file
diff --git a/drivers/input/misc/sx932x.c b/drivers/input/misc/sx932x.c
new file mode 100755 (executable)
index 0000000..d94b438
--- /dev/null
@@ -0,0 +1,974 @@
+/*! \file sx932x.c\r
+ * \brief  SX9320 Driver\r
+ *\r
+ * Driver for the SX9320 \r
+ * Copyright (c) 2011 Semtech Corp\r
+ *\r
+ *  This program is free software; you can redistribute it and/or modify\r
+ *  it under the terms of the GNU General Public License version 2 as\r
+ *  published by the Free Software Foundation.\r
+ */\r
+#define DEBUG\r
+#define DRIVER_NAME "sx932x"\r
+\r
+#define MAX_WRITE_ARRAY_SIZE 32\r
+\r
+#include <linux/module.h>\r
+#include <linux/slab.h>\r
+#include <linux/i2c.h>\r
+#include <linux/init.h>\r
+#include <linux/delay.h>\r
+#include <linux/input.h>\r
+#include <linux/fs.h>\r
+#include <linux/device.h>\r
+#include <linux/interrupt.h>\r
+#include <linux/syscalls.h>\r
+#include <linux/wakelock.h>\r
+#include <linux/uaccess.h>\r
+#include <linux/sort.h> \r
+#include <linux/gpio.h>\r
+#include <linux/of_gpio.h>\r
+#include <linux/regulator/consumer.h>\r
+#include "sx932x.h"    /* main struct, interrupt,init,pointers */\r
+\r
+#define IDLE                   0\r
+#define ACTIVE                 1\r
+\r
+#define SX932x_NIRQ            34\r
+\r
+#define MAIN_SENSOR            1 //CS1\r
+\r
+/* Failer Index */\r
+#define SX932x_ID_ERROR        1\r
+#define SX932x_NIRQ_ERROR      2\r
+#define SX932x_CONN_ERROR      3\r
+#define SX932x_I2C_ERROR       4\r
+\r
+#define PROXOFFSET_LOW                 1500\r
+\r
+#define SX932x_ANALOG_GAIN             1\r
+#define SX932x_DIGITAL_GAIN            1\r
+#define SX932x_ANALOG_RANGE            2.65\r
+\r
+#define        TOUCH_CHECK_REF_AMB      0 // 44523\r
+#define        TOUCH_CHECK_SLOPE        0 // 50\r
+#define        TOUCH_CHECK_MAIN_AMB     0 // 151282\r
+\r
+/*! \struct sx932x\r
+ * Specialized struct containing input event data, platform data, and\r
+ * last cap state read if needed.\r
+ */\r
+typedef struct sx932x\r
+{\r
+       pbuttonInformation_t pbuttonInformation;\r
+       psx932x_platform_data_t hw;             /* specific platform data settings */\r
+} sx932x_t, *psx932x_t;\r
+\r
+static int irq_gpio_num;\r
+\r
+/*! \fn static int write_register(psx93XX_t this, u8 address, u8 value)\r
+ * \brief Sends a write register to the device\r
+ * \param this Pointer to main parent struct \r
+ * \param address 8-bit register address\r
+ * \param value   8-bit register value to write to address\r
+ * \return Value from i2c_master_send\r
+ */\r
+\r
+static int write_register(psx93XX_t this, u8 address, u8 value)\r
+{\r
+       struct i2c_client *i2c = 0;\r
+       char buffer[2];\r
+       int returnValue = 0;\r
+\r
+       buffer[0] = address;\r
+       buffer[1] = value;\r
+       returnValue = -ENOMEM;\r
+\r
+       if (this && this->bus) {\r
+               i2c = this->bus;\r
+               returnValue = i2c_master_send(i2c,buffer,2);\r
+               #ifdef DEBUG\r
+               dev_info(&i2c->dev,"write_register Address: 0x%x Value: 0x%x Return: %d\n",\r
+                                                                                                               address,value,returnValue);\r
+               #endif\r
+       }\r
+       return returnValue;\r
+}\r
+\r
+/*! \fn static int read_register(psx93XX_t this, u8 address, u8 *value) \r
+* \brief Reads a register's value from the device\r
+* \param this Pointer to main parent struct \r
+* \param address 8-Bit address to read from\r
+* \param value Pointer to 8-bit value to save register value to \r
+* \return Value from i2c_smbus_read_byte_data if < 0. else 0\r
+*/\r
+static int read_register(psx93XX_t this, u8 address, u8 *value)\r
+{\r
+       struct i2c_client *i2c = 0;\r
+       s32 returnValue = 0;\r
+\r
+       if (this && value && this->bus) {\r
+               i2c = this->bus;\r
+               dev_info(&i2c->dev, "read_register Address:i2c:%s 0x%x Return: 0x%x\n",this->bus,\r
+                                                                                                               address,returnValue);\r
+               returnValue = i2c_smbus_read_byte_data(i2c,address);\r
+               \r
+               #ifdef DEBUG\r
+               dev_info(&i2c->dev, "read_register Address: 0x%x Return: 0x%x\n",\r
+                                                                                                               address,returnValue);\r
+               #endif\r
+\r
+               if (returnValue >= 0) {\r
+                       *value = returnValue;\r
+                       return 0;\r
+               } \r
+               else {\r
+                       return returnValue;\r
+               }\r
+       }\r
+       return -ENOMEM;\r
+}\r
+\r
+//static int sx9320_set_mode(psx93XX_t this, unsigned char mode);\r
+\r
+/*! \fn static int read_regStat(psx93XX_t this)\r
+ * \brief Shortcut to read what caused interrupt.\r
+ * \details This is to keep the drivers a unified\r
+ * function that will read whatever register(s) \r
+ * provide information on why the interrupt was caused.\r
+ * \param this Pointer to main parent struct \r
+ * \return If successful, Value of bit(s) that cause interrupt, else 0\r
+ */\r
+static int read_regStat(psx93XX_t this)\r
+{\r
+       u8 data = 0;\r
+       if (this) {\r
+               if (read_register(this,SX932x_IRQSTAT_REG,&data) == 0)\r
+               return (data & 0x00FF);\r
+       }\r
+       return 0;\r
+}\r
+\r
+/*********************************************************************/\r
+/*! \brief Perform a manual offset calibration\r
+* \param this Pointer to main parent struct \r
+* \return Value return value from the write register\r
+ */\r
+static int manual_offset_calibration(psx93XX_t this)\r
+{\r
+       s32 returnValue = 0;\r
+       returnValue = write_register(this,SX932x_STAT2_REG,0x0F);\r
+       return returnValue;\r
+}\r
+/*! \brief sysfs show function for manual calibration which currently just\r
+ * returns register value.\r
+ */\r
+static ssize_t manual_offset_calibration_show(struct device *dev,\r
+                                                               struct device_attribute *attr, char *buf)\r
+{\r
+       u8 reg_value = 0;\r
+       psx93XX_t this = dev_get_drvdata(dev);\r
+\r
+       dev_info(this->pdev, "Reading IRQSTAT_REG\n");\r
+       read_register(this,SX932x_IRQSTAT_REG,&reg_value);\r
+       return sprintf(buf, "%d\n", reg_value);\r
+}\r
+\r
+/*! \brief sysfs store function for manual calibration\r
+ */\r
+static ssize_t manual_offset_calibration_store(struct device *dev,\r
+                       struct device_attribute *attr,const char *buf, size_t count)\r
+{\r
+       psx93XX_t this = dev_get_drvdata(dev);\r
+       unsigned long val;\r
+       if (kstrtoul(buf, 0, &val))\r
+       return -EINVAL;\r
+       if (val) {\r
+               dev_info( this->pdev, "Performing manual_offset_calibration()\n");\r
+               manual_offset_calibration(this);\r
+       }\r
+       return count;\r
+}\r
+\r
+static int sx932x_Hardware_Check(psx93XX_t this)\r
+{\r
+       int ret;\r
+       u8 failcode;\r
+       u8 loop = 0;\r
+       this->failStatusCode = 0;\r
+       \r
+       //Check th IRQ Status\r
+       while(this->get_nirq_low && this->get_nirq_low()){\r
+               read_regStat(this);\r
+               msleep(100);\r
+               if(++loop >10){\r
+                       this->failStatusCode = SX932x_NIRQ_ERROR;\r
+                       break;\r
+               }\r
+       }\r
+       \r
+       //Check I2C Connection\r
+       ret = read_register(this, SX932x_WHOAMI_REG, &failcode);\r
+       if(ret < 0){\r
+               this->failStatusCode = SX932x_I2C_ERROR;\r
+       }\r
+               \r
+       if(failcode!= SX932x_WHOAMI_VALUE){\r
+               this->failStatusCode = SX932x_ID_ERROR;\r
+       }\r
+       \r
+       dev_info(this->pdev, "sx932x failcode = 0x%x\n",this->failStatusCode);\r
+       return (int)this->failStatusCode;\r
+}\r
+\r
+\r
+/*********************************************************************/\r
+static int sx932x_global_variable_init(psx93XX_t this)\r
+{\r
+       this->irq_disabled = 0;\r
+       this->failStatusCode = 0;\r
+       this->reg_in_dts = true;\r
+       return 0;\r
+}\r
+\r
+static ssize_t sx932x_register_write_store(struct device *dev,\r
+                       struct device_attribute *attr, const char *buf, size_t count)\r
+{\r
+       int reg_address = 0, val = 0;\r
+       psx93XX_t this = dev_get_drvdata(dev);\r
+\r
+       if (sscanf(buf, "%x,%x", &reg_address, &val) != 2) {\r
+               pr_err("[SX9320]: %s - The number of data are wrong\n",__func__);\r
+               return -EINVAL;\r
+       }\r
+\r
+       write_register(this, (unsigned char)reg_address, (unsigned char)val);\r
+       pr_info("[SX9320]: %s - Register(0x%x) data(0x%x)\n",__func__, reg_address, val);\r
+\r
+       return count;\r
+}\r
+//read registers not include the advanced one\r
+static ssize_t sx932x_register_read_store(struct device *dev,\r
+                       struct device_attribute *attr, const char *buf, size_t count)\r
+{\r
+       u8 val=0;\r
+       int regist = 0;\r
+       psx93XX_t this = dev_get_drvdata(dev);\r
+\r
+       dev_info(this->pdev, "Reading register\n");\r
+\r
+       if (sscanf(buf, "%x", &regist) != 1) {\r
+               pr_err("[SX9320]: %s - The number of data are wrong\n",__func__);\r
+               return -EINVAL;\r
+       }\r
+       dev_info(this->pdev, "regist = 0x%x\n",regist);\r
+       read_register(this, regist, &val);\r
+       pr_info("[SX9320]: %s - Register(0x%2x) data(0x%2x)\n",__func__, regist, val);\r
+\r
+       return count;\r
+}\r
+\r
+static ssize_t sx932x_register_read_show(struct device *dev,\r
+                       struct device_attribute *attr,  char *buf)\r
+{\r
+       u8 val=0;\r
+       u8 val1=0;\r
+       psx93XX_t this = dev_get_drvdata(dev);\r
+\r
+       dev_info(this->pdev, "Reading register\n");\r
+       read_register(this, SX932x_DIFFMSB, &val);\r
+       read_register(this, SX932x_DIFFLSB, &val1);\r
+       dev_info(this->pdev,"[SX9320]: %s - Register(0x%2x) data(0x%2x)\n",__func__, SX932x_DIFFMSB, val);\r
+       dev_info(this->pdev,"[SX9320]: %s - Register(0x%2x) data(0x%2x)\n",__func__, SX932x_DIFFLSB, val1);\r
+       return sprintf(buf, "%x%x\n", val,val1);\r
+}\r
+static void read_rawData(psx93XX_t this)\r
+{\r
+       u8 msb=0, lsb=0;\r
+       u8 csx;\r
+       s32 useful;\r
+       s32 average;\r
+       s32 diff;\r
+       u16 offset;\r
+       if(this){\r
+               for(csx =0; csx<4; csx++){\r
+                       write_register(this,SX932x_CPSRD,csx);//here to check the CS1, also can read other channel              \r
+                       read_register(this,SX932x_USEMSB,&msb);\r
+                       read_register(this,SX932x_USELSB,&lsb);\r
+                       useful = (s32)((msb << 8) | lsb);\r
+                       \r
+                       read_register(this,SX932x_AVGMSB,&msb);\r
+                       read_register(this,SX932x_AVGLSB,&lsb);\r
+                       average = (s32)((msb << 8) | lsb);\r
+                       \r
+                       read_register(this,SX932x_DIFFMSB,&msb);\r
+                       read_register(this,SX932x_DIFFLSB,&lsb);\r
+                       diff = (s32)((msb << 8) | lsb);\r
+                       \r
+                       read_register(this,SX932x_OFFSETMSB,&msb);\r
+                       read_register(this,SX932x_OFFSETLSB,&lsb);\r
+                       offset = (u16)((msb << 8) | lsb);\r
+                       if (useful > 32767)\r
+                               useful -= 65536;\r
+                       if (average > 32767)\r
+                               average -= 65536;\r
+                       if (diff > 32767)\r
+                               diff -= 65536;\r
+                       dev_info(this->pdev, " [CS: %d] Useful = %d Average = %d, DIFF = %d Offset = %d \n",csx,useful,average,diff,offset);\r
+               }\r
+       }\r
+}\r
+\r
+static ssize_t sx932x_raw_data_show(struct device *dev,\r
+                                               struct device_attribute *attr, char *buf)\r
+{\r
+       psx93XX_t this = dev_get_drvdata(dev);\r
+       read_rawData(this);\r
+       return 0;\r
+}\r
+\r
+static DEVICE_ATTR(manual_calibrate, 0664, manual_offset_calibration_show,manual_offset_calibration_store);\r
+static DEVICE_ATTR(register_write,  0664, NULL,sx932x_register_write_store);\r
+static DEVICE_ATTR(register_read,0664, sx932x_register_read_show,sx932x_register_read_store);\r
+static DEVICE_ATTR(raw_data,0664,sx932x_raw_data_show,NULL);\r
+static struct attribute *sx932x_attributes[] = {\r
+       &dev_attr_manual_calibrate.attr,\r
+       &dev_attr_register_write.attr,\r
+       &dev_attr_register_read.attr,\r
+       &dev_attr_raw_data.attr,\r
+       NULL,\r
+};\r
+static struct attribute_group sx932x_attr_group = {\r
+       .attrs = sx932x_attributes,\r
+};\r
+\r
+/****************************************************/\r
+/*! \brief  Initialize I2C config from platform data\r
+ * \param this Pointer to main parent struct \r
+ */\r
+static void sx932x_reg_init(psx93XX_t this)\r
+{\r
+       psx932x_t pDevice = 0;\r
+       psx932x_platform_data_t pdata = 0;\r
+       int i = 0;\r
+       /* configure device */ \r
+       dev_info(this->pdev, "Going to Setup I2C Registers\n");\r
+       if (this && (pDevice = this->pDevice) && (pdata = pDevice->hw))\r
+       {\r
+               /*******************************************************************************/\r
+               // try to initialize from device tree!\r
+               /*******************************************************************************/\r
+               if (this->reg_in_dts == true) {\r
+                       while ( i < pdata->i2c_reg_num) {\r
+                               /* Write all registers/values contained in i2c_reg */\r
+                               dev_info(this->pdev, "Going to Write Reg from dts: 0x%x Value: 0x%x\n",\r
+                               pdata->pi2c_reg[i].reg,pdata->pi2c_reg[i].val);\r
+                               write_register(this, pdata->pi2c_reg[i].reg,pdata->pi2c_reg[i].val);\r
+                               i++;\r
+                       }\r
+               } else { // use static ones!!\r
+                       while ( i < ARRAY_SIZE(sx932x_i2c_reg_setup)) {\r
+                               /* Write all registers/values contained in i2c_reg */\r
+                               dev_info(this->pdev, "Going to Write Reg: 0x%x Value: 0x%x\n",\r
+                               sx932x_i2c_reg_setup[i].reg,sx932x_i2c_reg_setup[i].val);\r
+                               write_register(this, sx932x_i2c_reg_setup[i].reg,sx932x_i2c_reg_setup[i].val);\r
+                               i++;\r
+                       }\r
+               }\r
+       /*******************************************************************************/\r
+       } else {\r
+               dev_err(this->pdev, "ERROR! platform data 0x%p\n",pDevice->hw);\r
+       }\r
+\r
+}\r
+\r
+\r
+/*! \fn static int initialize(psx93XX_t this)\r
+ * \brief Performs all initialization needed to configure the device\r
+ * \param this Pointer to main parent struct \r
+ * \return Last used command's return value (negative if error)\r
+ */\r
+static int initialize(psx93XX_t this)\r
+{\r
+       int ret;\r
+       if (this) {\r
+               pr_info("SX9320 income initialize\n");\r
+               /* prepare reset by disabling any irq handling */\r
+               this->irq_disabled = 1;\r
+               disable_irq(this->irq);\r
+               /* perform a reset */\r
+               write_register(this,SX932x_SOFTRESET_REG,SX932x_SOFTRESET);\r
+               /* wait until the reset has finished by monitoring NIRQ */\r
+               dev_info(this->pdev, "Sent Software Reset. Waiting until device is back from reset to continue.\n");\r
+               /* just sleep for awhile instead of using a loop with reading irq status */\r
+               msleep(100);\r
+               \r
+               ret = sx932x_global_variable_init(this);\r
+               \r
+               sx932x_reg_init(this);\r
+               msleep(100); /* make sure everything is running */\r
+               manual_offset_calibration(this);\r
+\r
+               /* re-enable interrupt handling */\r
+               enable_irq(this->irq);\r
+               \r
+               /* make sure no interrupts are pending since enabling irq will only\r
+               * work on next falling edge */\r
+               read_regStat(this);\r
+               return 0;\r
+       }\r
+       return -ENOMEM;\r
+}\r
+\r
+/*! \r
+ * \brief Handle what to do when a touch occurs\r
+ * \param this Pointer to main parent struct \r
+ */\r
+static void touchProcess(psx93XX_t this)\r
+{\r
+       int counter = 0;\r
+       u8 i = 0;\r
+       int numberOfButtons = 0;\r
+       psx932x_t pDevice = NULL;\r
+       struct _buttonInfo *buttons = NULL;\r
+       struct input_dev *input = NULL;\r
+\r
+       struct _buttonInfo *pCurrentButton  = NULL;\r
+\r
+       if (this && (pDevice = this->pDevice))\r
+       {\r
+               //dev_info(this->pdev, "Inside touchProcess()\n");\r
+               read_register(this, SX932x_STAT0_REG, &i);\r
+\r
+               buttons = pDevice->pbuttonInformation->buttons;\r
+               input = pDevice->pbuttonInformation->input;\r
+               numberOfButtons = pDevice->pbuttonInformation->buttonSize;\r
+\r
+               if (unlikely( (buttons==NULL) || (input==NULL) )) {\r
+                       dev_err(this->pdev, "ERROR!! buttons or input NULL!!!\n");\r
+                       return;\r
+               }\r
+\r
+               for (counter = 0; counter < numberOfButtons; counter++) {\r
+                       pCurrentButton = &buttons[counter];\r
+                       if (pCurrentButton==NULL) {\r
+                               dev_err(this->pdev,"ERROR!! current button at index: %d NULL!!!\n", counter);\r
+                               return; // ERRORR!!!!\r
+                       }\r
+                       switch (pCurrentButton->state) {\r
+                               case IDLE: /* Button is not being touched! */\r
+                                       if (((i & pCurrentButton->mask) == pCurrentButton->mask)) {\r
+                                               /* User pressed button */\r
+                                               dev_info(this->pdev, "cap button %d touched\n", counter);\r
+                                               input_report_key(input, pCurrentButton->keycode, 1);\r
+                                               pCurrentButton->state = ACTIVE;\r
+                                       } else {\r
+                                               dev_info(this->pdev, "Button %d already released.\n",counter);\r
+                                       }\r
+                                       break;\r
+                               case ACTIVE: /* Button is being touched! */ \r
+                                       if (((i & pCurrentButton->mask) != pCurrentButton->mask)) {\r
+                                               /* User released button */\r
+                                               dev_info(this->pdev, "cap button %d released\n",counter);\r
+                                               input_report_key(input, pCurrentButton->keycode, 0);\r
+                                               pCurrentButton->state = IDLE;\r
+                                       } else {\r
+                                               dev_info(this->pdev, "Button %d still touched.\n",counter);\r
+                                       }\r
+                                       break;\r
+                               default: /* Shouldn't be here, device only allowed ACTIVE or IDLE */\r
+                                       break;\r
+                       };\r
+               }\r
+               input_sync(input);\r
+\r
+   //dev_info(this->pdev, "Leaving touchProcess()\n");\r
+  }\r
+}\r
+\r
+static int sx932x_parse_dt(struct sx932x_platform_data *pdata, struct device *dev)\r
+{\r
+       struct device_node *dNode = dev->of_node;\r
+       enum of_gpio_flags flags;\r
+       int ret;\r
+       if (dNode == NULL)\r
+               return -ENODEV;\r
+       \r
+       pdata->irq_gpio= of_get_named_gpio_flags(dNode,\r
+                                                                                       "Semtech,nirq-gpio", 0, &flags);\r
+       irq_gpio_num = pdata->irq_gpio;\r
+       if (pdata->irq_gpio < 0) {\r
+               pr_err("[SENSOR]: %s - get irq_gpio error\n", __func__);\r
+               return -ENODEV;\r
+       }\r
+       \r
+       /***********************************************************************/\r
+       // load in registers from device tree\r
+       of_property_read_u32(dNode,"Semtech,reg-num",&pdata->i2c_reg_num);\r
+       // layout is register, value, register, value....\r
+       // if an extra item is after just ignore it. reading the array in will cause it to fail anyway\r
+       pr_info("[SX9320]:%s -  size of elements %d \n", __func__,pdata->i2c_reg_num);\r
+       if (pdata->i2c_reg_num > 0) {\r
+                // initialize platform reg data array\r
+                pdata->pi2c_reg = devm_kzalloc(dev,sizeof(struct smtc_reg_data)*pdata->i2c_reg_num, GFP_KERNEL);\r
+                if (unlikely(pdata->pi2c_reg == NULL)) {\r
+                       return -ENOMEM;\r
+               }\r
+\r
+        // initialize the array\r
+               if (of_property_read_u8_array(dNode,"Semtech,reg-init",(u8*)&(pdata->pi2c_reg[0]),sizeof(struct smtc_reg_data)*pdata->i2c_reg_num))\r
+               return -ENOMEM;\r
+       }\r
+       /***********************************************************************/\r
+       pr_info("[SX9320]: %s -[%d] parse_dt complete\n", __func__,pdata->irq_gpio);\r
+       return 0;\r
+}\r
+       struct pinctrl *pinctrl_int;\r
+/* get the NIRQ state (1->NIRQ-low, 0->NIRQ-high) */\r
+static int sx932x_init_platform_hw(struct i2c_client *client)\r
+{\r
+       psx93XX_t this = i2c_get_clientdata(client);\r
+       struct sx932x *pDevice = NULL;\r
+       struct sx932x_platform_data *pdata = NULL;\r
+\r
+       int rc;\r
+\r
+       pr_info("[SX9320] : %s init_platform_hw start!",__func__);\r
+\r
+       if (this && (pDevice = this->pDevice) && (pdata = pDevice->hw)) {\r
+               if (gpio_is_valid(pdata->irq_gpio)) {\r
+                       rc = gpio_request(pdata->irq_gpio, "sx9320_irq_gpio");\r
+                       if (rc < 0) {\r
+                               dev_err(this->pdev, "SX9320 Request gpio. Fail![%d]\n", rc);\r
+                               return rc;\r
+                       }\r
+                       rc = gpio_direction_input(pdata->irq_gpio);\r
+                       if (rc < 0) {\r
+                               dev_err(this->pdev, "SX9320 Set gpio direction. Fail![%d]\n", rc);\r
+                               return rc;\r
+                       }\r
+                       pinctrl_int = devm_pinctrl_get_select(this->pdev, "default");\r
+                       \r
+                       this->irq = client->irq = gpio_to_irq(pdata->irq_gpio);\r
+               }\r
+               else {\r
+                       dev_err(this->pdev, "SX9320 Invalid irq gpio num.(init)\n");\r
+               }\r
+       }\r
+       else {\r
+               pr_err("[SX9320] : %s - Do not init platform HW", __func__);\r
+       }\r
+       \r
+       pr_err("[SX9320]: %s - sx9320_irq_debug\n",__func__);\r
+       return rc;\r
+}\r
+\r
+static void sx932x_exit_platform_hw(struct i2c_client *client)\r
+{\r
+       psx93XX_t this = i2c_get_clientdata(client);\r
+       struct sx932x *pDevice = NULL;\r
+       struct sx932x_platform_data *pdata = NULL;\r
+       printk("%s:test\n",__func__);\r
+       if (this && (pDevice = this->pDevice) && (pdata = pDevice->hw)) {\r
+               if (gpio_is_valid(pdata->irq_gpio)) {\r
+                       gpio_free(pdata->irq_gpio);\r
+               }\r
+               else {\r
+                       dev_err(this->pdev, "Invalid irq gpio num.(exit)\n");\r
+               }\r
+       }\r
+       return;\r
+}\r
+\r
+static int sx932x_get_nirq_state(void)\r
+{\r
+       return  !gpio_get_value(irq_gpio_num);\r
+}\r
+\r
+/*! \fn static int sx932x_probe(struct i2c_client *client, const struct i2c_device_id *id)\r
+ * \brief Probe function\r
+ * \param client pointer to i2c_client\r
+ * \param id pointer to i2c_device_id\r
+ * \return Whether probe was successful\r
+ */\r
+static int sx932x_probe(struct i2c_client *client, const struct i2c_device_id *id)\r
+{    \r
+       int i = 0;\r
+       int err = 0;\r
+       int ret = 0;\r
+       u8 data1 = 0;\r
+       int  q = 0;\r
+       psx93XX_t this = 0;\r
+       psx932x_t pDevice = 0;\r
+       psx932x_platform_data_t pplatData = 0;\r
+       struct totalButtonInformation *pButtonInformationData = NULL;\r
+       struct input_dev *input = NULL;\r
+       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);\r
+\r
+       dev_info(&client->dev, "sx932x_probe()\n");\r
+\r
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)) {\r
+               dev_err(&client->dev, "Check i2c functionality.Fail!\n");\r
+               err = -EIO;\r
+               return err;\r
+       }\r
+\r
+       this = devm_kzalloc(&client->dev,sizeof(sx93XX_t), GFP_KERNEL); /* create memory for main struct */\r
+       dev_info(&client->dev, "\t Initialized Main Memory: 0x%p\n",this);\r
+\r
+       pButtonInformationData = devm_kzalloc(&client->dev , sizeof(struct totalButtonInformation), GFP_KERNEL);\r
+       if (!pButtonInformationData) {\r
+               dev_err(&client->dev, "Failed to allocate memory(totalButtonInformation)\n");\r
+               err = -ENOMEM;\r
+               return err;\r
+       }\r
+\r
+       pButtonInformationData->buttonSize = ARRAY_SIZE(psmtcButtons);\r
+       pButtonInformationData->buttons =  psmtcButtons;\r
+       pplatData = devm_kzalloc(&client->dev,sizeof(struct sx932x_platform_data), GFP_KERNEL);\r
+       if (!pplatData) {\r
+               dev_err(&client->dev, "platform data is required!\n");\r
+               return -EINVAL;\r
+       }\r
+       pplatData->cap_vdd = regulator_get(&client->dev, "cap_vdd");\r
+       if (IS_ERR(pplatData->cap_vdd)) {\r
+               if (PTR_ERR(pplatData->cap_vdd) == -EPROBE_DEFER) {\r
+                       ret = PTR_ERR(pplatData->cap_vdd);\r
+                       //goto err_vdd_defer;\r
+               }\r
+               dev_err(&client->dev,"%s: Failed to get regulator\n",\r
+                               __func__);\r
+       } else {\r
+               int error = regulator_enable(pplatData->cap_vdd);\r
+\r
+               if (error) {\r
+                       regulator_put(pplatData->cap_vdd);\r
+                       dev_err(&client->dev,"%s: Error %d enable regulator\n",\r
+                                       __func__, error);\r
+                       return error;\r
+               }\r
+               pplatData->cap_vdd_en = true;\r
+               dev_info(&client->dev,"cap_vdd regulator is %s\n",\r
+                       regulator_is_enabled(pplatData->cap_vdd) ?\r
+                       "on" : "off");\r
+       }\r
+       pplatData->get_is_nirq_low = sx932x_get_nirq_state;\r
+       pplatData->pbuttonInformation = pButtonInformationData;\r
\r
+       client->dev.platform_data = pplatData; \r
+       err = sx932x_parse_dt(pplatData, &client->dev);\r
+       if (err) {\r
+               dev_err(&client->dev, "could not setup pin\n");\r
+               return ENODEV;\r
+       }\r
+\r
+       pplatData->init_platform_hw = sx932x_init_platform_hw;\r
+       dev_err(&client->dev, "SX9320 init_platform_hw done!\n");\r
+       \r
+       if (this){\r
+               dev_info(&client->dev, "SX9320 initialize start!!");\r
+               /* In case we need to reinitialize data \r
+               * (e.q. if suspend reset device) */\r
+               this->init = initialize;\r
+               /* shortcut to read status of interrupt */\r
+               this->refreshStatus = read_regStat;\r
+               /* pointer to function from platform data to get pendown \r
+               * (1->NIRQ=0, 0->NIRQ=1) */\r
+               this->get_nirq_low = pplatData->get_is_nirq_low;\r
+               /* save irq in case we need to reference it */\r
+               this->irq = client->irq;\r
+               /* do we need to create an irq timer after interrupt ? */\r
+               this->useIrqTimer = 0;\r
+\r
+               /* Setup function to call on corresponding reg irq source bit */\r
+               if (MAX_NUM_STATUS_BITS>= 8)\r
+               {\r
+                       this->statusFunc[0] = 0; /* TXEN_STAT */\r
+                       this->statusFunc[1] = 0; /* UNUSED */\r
+                       this->statusFunc[2] = 0; /* UNUSED */\r
+                       this->statusFunc[3] = read_rawData; /* CONV_STAT */\r
+                       this->statusFunc[4] = 0; /* COMP_STAT */\r
+                       this->statusFunc[5] = touchProcess; /* RELEASE_STAT */\r
+                       this->statusFunc[6] = touchProcess; /* TOUCH_STAT  */\r
+                       this->statusFunc[7] = 0; /* RESET_STAT */\r
+               }\r
+\r
+               /* setup i2c communication */\r
+               this->bus = client;\r
+               i2c_set_clientdata(client, this);\r
+\r
+               /* record device struct */\r
+               this->pdev = &client->dev;\r
+\r
+               /* create memory for device specific struct */\r
+               this->pDevice = pDevice = devm_kzalloc(&client->dev,sizeof(sx932x_t), GFP_KERNEL);\r
+               dev_info(&client->dev, "\t Initialized Device Specific Memory: 0x%p\n",pDevice);\r
+\r
+               if (pDevice){\r
+                       /* for accessing items in user data (e.g. calibrate) */\r
+                       err = sysfs_create_group(&client->dev.kobj, &sx932x_attr_group);\r
+                       //sysfs_create_group(client, &sx932x_attr_group);\r
+\r
+                       /* Add Pointer to main platform data struct */\r
+                       pDevice->hw = pplatData;\r
+\r
+                       /* Check if we hava a platform initialization function to call*/\r
+                       if (pplatData->init_platform_hw)\r
+                       pplatData->init_platform_hw(client);\r
+\r
+                       /* Initialize the button information initialized with keycodes */\r
+                       pDevice->pbuttonInformation = pplatData->pbuttonInformation;\r
+                       /* Create the input device */\r
+                       input = input_allocate_device();\r
+                       if (!input) {\r
+                               return -ENOMEM;\r
+                       }\r
+                       /* Set all the keycodes */\r
+                       __set_bit(EV_KEY, input->evbit);\r
+                       #if 1\r
+                       for (i = 0; i < pButtonInformationData->buttonSize; i++) {\r
+                               __set_bit(pButtonInformationData->buttons[i].keycode,input->keybit);\r
+                               pButtonInformationData->buttons[i].state = IDLE;\r
+                       }\r
+                       #endif\r
+                       /* save the input pointer and finish initialization */\r
+                       pButtonInformationData->input = input;\r
+                       input->name = "SX9320 Cap Touch";\r
+                       input->id.bustype = BUS_I2C;\r
+                       if(input_register_device(input)){\r
+                               return -ENOMEM;\r
+                       }\r
+               }\r
+\r
+               sx93XX_IRQ_init(this);\r
+               /* call init function pointer (this should initialize all registers */\r
+               if (this->init){\r
+                       this->init(this);\r
+               }else{\r
+                       dev_err(this->pdev,"No init function!!!!\n");\r
+                       return -ENOMEM;\r
+               }\r
+       }else{\r
+               return -1;\r
+       }\r
+\r
+       sx932x_Hardware_Check(this);\r
+       pplatData->exit_platform_hw = sx932x_exit_platform_hw;\r
+       dev_info(&client->dev, "sx932x_probe() Done\n");\r
+\r
+       return 0;\r
+}\r
+\r
+/*! \fn static int sx932x_remove(struct i2c_client *client)\r
+ * \brief Called when device is to be removed\r
+ * \param client Pointer to i2c_client struct\r
+ * \return Value from sx93XX_remove()\r
+ */\r
+//static int __devexit sx932x_remove(struct i2c_client *client)\r
+static int sx932x_remove(struct i2c_client *client)\r
+{\r
+       psx932x_platform_data_t pplatData =0;\r
+       psx932x_t pDevice = 0;\r
+       psx93XX_t this = i2c_get_clientdata(client);\r
+       if (this && (pDevice = this->pDevice))\r
+       {\r
+               input_unregister_device(pDevice->pbuttonInformation->input);\r
+\r
+               sysfs_remove_group(&client->dev.kobj, &sx932x_attr_group);\r
+               pplatData = client->dev.platform_data;\r
+               if (pplatData && pplatData->exit_platform_hw)\r
+                       pplatData->exit_platform_hw(client);\r
+               kfree(this->pDevice);\r
+       }\r
+       return sx93XX_remove(this);\r
+}\r
+#if 1//def CONFIG_PM\r
+/*====================================================*/\r
+/***** Kernel Suspend *****/\r
+static int sx932x_suspend(struct device *dev)\r
+{\r
+       psx93XX_t this = dev_get_drvdata(dev);\r
+       sx93XX_suspend(this);\r
+       return 0;\r
+}\r
+/***** Kernel Resume *****/\r
+static int sx932x_resume(struct device *dev)\r
+{\r
+       psx93XX_t this = dev_get_drvdata(dev);\r
+       sx93XX_resume(this);\r
+       return 0;\r
+}\r
+/*====================================================*/\r
+#else\r
+#define sx932x_suspend         NULL\r
+#define sx932x_resume          NULL\r
+#endif /* CONFIG_PM */\r
+\r
+static struct i2c_device_id sx932x_idtable[] = {\r
+       { DRIVER_NAME, 0 },\r
+       { }\r
+};\r
+MODULE_DEVICE_TABLE(i2c, sx932x_idtable);\r
+#ifdef CONFIG_OF\r
+static struct of_device_id sx932x_match_table[] = {\r
+       { .compatible = "Semtech,sx932x",},\r
+       { },\r
+};\r
+#else\r
+#define sx932x_match_table NULL\r
+#endif\r
+static const struct dev_pm_ops sx932x_pm_ops = {\r
+       .suspend = sx932x_suspend,\r
+       .resume = sx932x_resume,\r
+};\r
+static struct i2c_driver sx932x_driver = {\r
+       .driver = {\r
+               .owner                  = THIS_MODULE,\r
+               .name                   = DRIVER_NAME,\r
+               .of_match_table = sx932x_match_table,\r
+               .pm                             = &sx932x_pm_ops,\r
+       },\r
+       .id_table               = sx932x_idtable,\r
+       .probe                  = sx932x_probe,\r
+       .remove                 = sx932x_remove,\r
+};\r
+static int __init sx932x_I2C_init(void)\r
+{\r
+       return i2c_add_driver(&sx932x_driver);\r
+}\r
+static void __exit sx932x_I2C_exit(void)\r
+{\r
+       i2c_del_driver(&sx932x_driver);\r
+}\r
+\r
+module_init(sx932x_I2C_init);\r
+module_exit(sx932x_I2C_exit);\r
+\r
+MODULE_AUTHOR("Semtech Corp. (http://www.semtech.com/)");\r
+MODULE_DESCRIPTION("SX9320 Capacitive Touch Controller Driver");\r
+MODULE_LICENSE("GPL");\r
+MODULE_VERSION("0.1");\r
+\r
+static void sx93XX_schedule_work(psx93XX_t this, unsigned long delay)\r
+{\r
+       unsigned long flags;\r
+       if (this) {\r
+               dev_info(this->pdev, "sx93XX_schedule_work()\n");\r
+               spin_lock_irqsave(&this->lock,flags);\r
+               /* Stop any pending penup queues */\r
+               cancel_delayed_work(&this->dworker);\r
+               //after waiting for a delay, this put the job in the kernel-global workqueue. so no need to create new thread in work queue.\r
+               schedule_delayed_work(&this->dworker,delay);\r
+               spin_unlock_irqrestore(&this->lock,flags);\r
+       }\r
+       else\r
+               printk(KERN_ERR "sx93XX_schedule_work, NULL psx93XX_t\n");\r
+} \r
+\r
+static irqreturn_t sx93XX_irq(int irq, void *pvoid)\r
+{\r
+       psx93XX_t this = 0;\r
+       if (pvoid) {\r
+               this = (psx93XX_t)pvoid;\r
+               if ((!this->get_nirq_low) || this->get_nirq_low()) {\r
+               sx93XX_schedule_work(this,0);\r
+               }\r
+               else{\r
+                       dev_err(this->pdev, "sx93XX_irq - nirq read high\n");\r
+               }\r
+       }\r
+       else{\r
+               printk(KERN_ERR "sx93XX_irq, NULL pvoid\n");\r
+       }\r
+       return IRQ_HANDLED;\r
+}\r
+\r
+static void sx93XX_worker_func(struct work_struct *work)\r
+{\r
+       psx93XX_t this = 0;\r
+       int status = 0;\r
+       int counter = 0;\r
+       u8 nirqLow = 0;\r
+       if (work) {\r
+               this = container_of(work,sx93XX_t,dworker.work);\r
+\r
+               if (!this) {\r
+                       printk(KERN_ERR "sx93XX_worker_func, NULL sx93XX_t\n");\r
+                       return;\r
+               }\r
+               if (unlikely(this->useIrqTimer)) {\r
+                       if ((!this->get_nirq_low) || this->get_nirq_low()) {\r
+                               nirqLow = 1;\r
+                       }\r
+               }\r
+               /* since we are not in an interrupt don't need to disable irq. */\r
+               status = this->refreshStatus(this);\r
+               counter = -1;\r
+               dev_dbg(this->pdev, "Worker - Refresh Status %d\n",status);\r
+               \r
+               while((++counter) < MAX_NUM_STATUS_BITS) { /* counter start from MSB */\r
+                       if (((status>>counter) & 0x01) && (this->statusFunc[counter])) {\r
+                               dev_info(this->pdev, "SX9320 Function Pointer Found. Calling\n");\r
+                               this->statusFunc[counter](this);\r
+                       }\r
+               }\r
+               if (unlikely(this->useIrqTimer && nirqLow))\r
+               {       /* Early models and if RATE=0 for newer models require a penup timer */\r
+                       /* Queue up the function again for checking on penup */\r
+                       sx93XX_schedule_work(this,msecs_to_jiffies(this->irqTimeout));\r
+               }\r
+       } else {\r
+               printk(KERN_ERR "sx93XX_worker_func, NULL work_struct\n");\r
+       }\r
+}\r
+\r
+int sx93XX_remove(psx93XX_t this)\r
+{\r
+       if (this) {\r
+               cancel_delayed_work_sync(&this->dworker); /* Cancel the Worker Func */\r
+               /*destroy_workqueue(this->workq); */\r
+               free_irq(this->irq, this);\r
+               kfree(this);\r
+               return 0;\r
+       }\r
+       return -ENOMEM;\r
+}\r
+void sx93XX_suspend(psx93XX_t this)\r
+{\r
+       if (this)\r
+               disable_irq(this->irq);\r
+\r
+       //write_register(this,SX932x_CTRL1_REG,0x20);//make sx932x in Sleep mode\r
+}\r
+void sx93XX_resume(psx93XX_t this)\r
+{\r
+       if (this) {\r
+               sx93XX_schedule_work(this,0);\r
+               if (this->init)\r
+                       this->init(this);\r
+       enable_irq(this->irq);\r
+       }\r
+}\r
+\r
+int sx93XX_IRQ_init(psx93XX_t this)\r
+{\r
+       int err = 0;\r
+       if (this && this->pDevice)\r
+       {\r
+               /* initialize spin lock */\r
+               spin_lock_init(&this->lock);\r
+               /* initialize worker function */\r
+               INIT_DELAYED_WORK(&this->dworker, sx93XX_worker_func);\r
+               /* initailize interrupt reporting */\r
+               this->irq_disabled = 0;\r
+               err = request_irq(this->irq, sx93XX_irq, IRQF_TRIGGER_FALLING,\r
+                                                       this->pdev->driver->name, this);\r
+               if (err) {\r
+                       dev_err(this->pdev, "irq %d busy?\n", this->irq);\r
+                       return err;\r
+               }\r
+               printk("%s:test registered with irq \n",__func__);\r
+               dev_info(this->pdev, "registered with irq (%d)\n", this->irq);\r
+       }\r
+       return -ENOMEM;\r
+}\r
diff --git a/drivers/input/misc/sx932x.h b/drivers/input/misc/sx932x.h
new file mode 100755 (executable)
index 0000000..759d09b
--- /dev/null
@@ -0,0 +1,461 @@
+/*\r
+* This program is free software; you can redistribute it and/or\r
+* modify it under the terms of the GNU General Public License\r
+* version 2 as published by the Free Software Foundation.\r
+*/\r
+#ifndef SX932x_H\r
+#define SX932x_H\r
+\r
+#include <linux/device.h>\r
+#include <linux/slab.h>\r
+#include <linux/interrupt.h>\r
+\r
+#if 0\r
+#include <linux/wakelock.h>\r
+#include <linux/earlysuspend.h>\r
+#include <linux/suspend.h>\r
+#endif\r
+\r
+/*\r
+*  I2C Registers\r
+*/\r
+//-Interrupt and status\r
+#define SX932x_IRQSTAT_REG             0x00\r
+#define SX932x_STAT0_REG               0x01\r
+#define SX932x_STAT1_REG               0x02\r
+#define SX932x_STAT2_REG               0x03\r
+#define SX932x_STAT3_REG               0x04\r
+#define SX932x_IRQ_ENABLE_REG  0x05\r
+#define SX932x_IRQCFG0_REG             0x06\r
+#define SX932x_IRQCFG1_REG             0x07\r
+#define SX932x_IRQCFG2_REG             0x08\r
+//-General control\r
+#define SX932x_CTRL0_REG               0x10\r
+#define SX932x_CTRL1_REG               0x11\r
+#define SX932x_I2CADDR_REG             0x14\r
+#define SX932x_CLKSPRD                 0x15\r
+//-AFE Control\r
+#define SX932x_AFE_CTRL0_REG   0x20\r
+#define SX932x_AFE_CTRL1_REG   0x21\r
+#define SX932x_AFE_CTRL2_REG   0x22\r
+#define SX932x_AFE_CTRL3_REG   0x23\r
+#define SX932x_AFE_CTRL4_REG   0x24\r
+#define SX932x_AFE_CTRL5_REG   0x25\r
+#define SX932x_AFE_CTRL6_REG   0x26\r
+#define SX932x_AFE_CTRL7_REG   0x27\r
+#define SX932x_AFE_PH0_REG             0x28\r
+#define SX932x_AFE_PH1_REG             0x29\r
+#define SX932x_AFE_PH2_REG             0x2A\r
+#define SX932x_AFE_PH3_REG             0x2B\r
+#define SX932x_AFE_CTRL8               0x2C\r
+#define SX932x_AFE_CTRL9               0x2D\r
+//-Main Digital Processing (Prox) control\r
+#define SX932x_PROX_CTRL0_REG  0x30\r
+#define SX932x_PROX_CTRL1_REG  0x31\r
+#define SX932x_PROX_CTRL2_REG  0x32\r
+#define SX932x_PROX_CTRL3_REG  0x33\r
+#define SX932x_PROX_CTRL4_REG  0x34\r
+#define SX932x_PROX_CTRL5_REG  0x35\r
+#define SX932x_PROX_CTRL6_REG  0x36\r
+#define SX932x_PROX_CTRL7_REG  0x37\r
+//-Advanced Digital Processing control\r
+#define SX932x_ADV_CTRL0_REG   0x40\r
+#define SX932x_ADV_CTRL1_REG   0x41\r
+#define SX932x_ADV_CTRL2_REG   0x42\r
+#define SX932x_ADV_CTRL3_REG   0x43\r
+#define SX932x_ADV_CTRL4_REG   0x44\r
+#define SX932x_ADV_CTRL5_REG   0x45\r
+#define SX932x_ADV_CTRL6_REG   0x46\r
+#define SX932x_ADV_CTRL7_REG   0x47\r
+#define SX932x_ADV_CTRL8_REG   0x48\r
+#define SX932x_ADV_CTRL9_REG   0x49\r
+#define SX932x_ADV_CTRL10_REG  0x4A\r
+#define SX932x_ADV_CTRL11_REG  0x4B\r
+#define SX932x_ADV_CTRL12_REG  0x4C\r
+#define SX932x_ADV_CTRL13_REG  0x4D\r
+#define SX932x_ADV_CTRL14_REG  0x4E\r
+#define SX932x_ADV_CTRL15_REG  0x4F\r
+#define SX932x_ADV_CTRL16_REG  0x50\r
+#define SX932x_ADV_CTRL17_REG  0x51\r
+#define SX932x_ADV_CTRL18_REG  0x52\r
+#define SX932x_ADV_CTRL19_REG  0x53\r
+#define SX932x_ADV_CTRL20_REG  0x54\r
+/*      Sensor Readback */\r
+#define SX932x_CPSRD                   0x60\r
+#define SX932x_USEMSB                  0x61\r
+#define SX932x_USELSB                  0x62\r
+#define SX932x_AVGMSB                  0x63\r
+#define SX932x_AVGLSB                  0x64\r
+#define SX932x_DIFFMSB                 0x65\r
+#define SX932x_DIFFLSB                 0x66\r
+#define SX932x_OFFSETMSB               0x67\r
+#define SX932x_OFFSETLSB               0x68\r
+#define SX932x_SARMSB                  0x69\r
+#define SX932x_SARLSB                  0x6A\r
+\r
+#define SX932x_SOFTRESET_REG   0x9F\r
+#define SX932x_WHOAMI_REG              0xFA\r
+#define SX932x_REV_REG                 0xFB\r
+\r
+/*      IrqStat 0:Inactive 1:Active     */\r
+#define SX932x_IRQSTAT_RESET_FLAG              0x80\r
+#define SX932x_IRQSTAT_TOUCH_FLAG              0x40\r
+#define SX932x_IRQSTAT_RELEASE_FLAG            0x20\r
+#define SX932x_IRQSTAT_COMPDONE_FLAG   0x10\r
+#define SX932x_IRQSTAT_CONV_FLAG               0x08\r
+#define SX932x_IRQSTAT_PROG2_FLAG              0x04\r
+#define SX932x_IRQSTAT_PROG1_FLAG              0x02\r
+#define SX932x_IRQSTAT_PROG0_FLAG              0x01\r
+\r
+\r
+/* RegStat0  */\r
+#define SX932x_PROXSTAT_PH3_FLAG               0x08\r
+#define SX932x_PROXSTAT_PH2_FLAG               0x04\r
+#define SX932x_PROXSTAT_PH1_FLAG               0x02\r
+#define SX932x_PROXSTAT_PH0_FLAG               0x01\r
+\r
+/*      SoftReset */\r
+#define SX932x_SOFTRESET                               0xDE\r
+#define SX932x_WHOAMI_VALUE                            0x22  //just for sx9325\r
+#define SX932x_REV_VALUE                               0x22 //just for sx9325\r
+\r
+#define LGE_SENSOR\r
+\r
+/**************************************\r
+*   define platform data\r
+*\r
+**************************************/\r
+struct smtc_reg_data {\r
+       unsigned char reg;\r
+       unsigned char val;\r
+};\r
+typedef struct smtc_reg_data smtc_reg_data_t;\r
+typedef struct smtc_reg_data *psmtc_reg_data_t;\r
+\r
+\r
+struct _buttonInfo {\r
+       /*! The Key to send to the input */\r
+       int keycode;\r
+       /*! Mask to look for on Touch Status */\r
+       int mask;\r
+       /*! Current state of button. */\r
+       int state;\r
+};\r
+\r
+struct totalButtonInformation {\r
+       struct _buttonInfo *buttons;\r
+       int buttonSize;\r
+       struct input_dev *input;\r
+};\r
+\r
+typedef struct totalButtonInformation buttonInformation_t;\r
+typedef struct totalButtonInformation *pbuttonInformation_t;\r
+\r
+/* Define Registers that need to be initialized to values different than\r
+* default\r
+*/\r
+static struct smtc_reg_data sx932x_i2c_reg_setup[] = {\r
+//Interrupt and config\r
+       {\r
+               .reg = SX932x_IRQ_ENABLE_REG,   //0x05\r
+               .val = 0x70,                                    // Enavle Close and Far -> enable compensation interrupt\r
+       },\r
+       {\r
+               .reg = SX932x_IRQCFG0_REG,              //0x06\r
+               .val = 0x00,                                    //\r
+       },\r
+       {\r
+               .reg = SX932x_IRQCFG1_REG,              //0x07  \r
+               .val = 0x00,\r
+       },\r
+       {\r
+               .reg = SX932x_IRQCFG2_REG,              //0x08\r
+               .val = 0x00,                                    //Activ Low\r
+       },\r
+       //--------General control\r
+       {\r
+               .reg = SX932x_CTRL0_REG,    //0x10\r
+               .val = 0x16,       // Scanperiod : 100ms(10110)\r
+       },\r
+       {\r
+               .reg = SX932x_I2CADDR_REG,   //0x14\r
+               .val = 0x00,       //I2C Address : 0x28\r
+       },\r
+       {\r
+               .reg = SX932x_CLKSPRD,    //0x15\r
+               .val = 0x00,       //\r
+       },\r
+       //--------AFE Control\r
+       {\r
+               .reg = SX932x_AFE_CTRL0_REG,   //0x20\r
+               .val = 0x00,       // CSx pin during sleep mode : HZ\r
+       },\r
+       {\r
+               .reg = SX932x_AFE_CTRL1_REG,   //0x21\r
+               .val = 0x10,       //reserved\r
+       },\r
+       {\r
+               .reg = SX932x_AFE_CTRL2_REG,   //0x22\r
+               .val = 0x00,       //reserved\r
+       },\r
+       {\r
+               .reg = SX932x_AFE_CTRL3_REG,   //0x23\r
+               .val = 0x00,       //Analog Range(ph0/1) : Small\r
+       },\r
+       {\r
+               .reg = SX932x_AFE_CTRL4_REG,   //0x24\r
+               .val = 0x44,       //Sampling Freq(ph0/1) : 83.33khz(01000), Resolution(ph0/1) : 128(100)\r
+       },\r
+       {\r
+               .reg = SX932x_AFE_CTRL5_REG,   //0x25\r
+               .val = 0x00,       //reserved\r
+       },\r
+       {\r
+               .reg = SX932x_AFE_CTRL6_REG,   //0x26\r
+               .val = 0x01,       //big//Analog Range(ph2/3) : Small\r
+       },\r
+       {\r
+               .reg = SX932x_AFE_CTRL7_REG,   //0x27\r
+               .val = 0x44,       //Sampling Freq(ph2/3) : 83.33khz(01000), Resolution(ph2/3) : 128(100)\r
+       },\r
+       {\r
+               .reg = SX932x_AFE_PH0_REG,   //0x28\r
+               .val = 0x01,       // CS2:HZ CS1:Input CS0 :HZ\r
+       },\r
+       {\r
+               .reg = SX932x_AFE_PH1_REG,     //0x29\r
+               .val = 0x4,       // CS2:Input CS1:HZ Shield CS0 :HZ\r
+       },\r
+       {\r
+               .reg = SX932x_AFE_PH2_REG,   //0x2A\r
+               .val = 0x10,       //CS2:HZ CS1:HZ CS0 :HZ  \r
+       },\r
+       {\r
+               .reg = SX932x_AFE_PH3_REG,   //0x2B\r
+               .val = 0x00,       //CS2:HZ CS1:HZ CS0 :HZ\r
+       },\r
+       {\r
+               .reg = SX932x_AFE_CTRL8,    //0x2C\r
+               .val = 0x12,       // input register(kohm) 4(0010)\r
+       },\r
+       {\r
+               .reg = SX932x_AFE_CTRL9,    //0x2D\r
+               .val = 0x08,       // Analg gain : x1(1000)\r
+       },\r
+       //--------PROX control\r
+       {\r
+               .reg = SX932x_PROX_CTRL0_REG,  //0x30\r
+               .val = 0x09,       // Digital Gain(ph0/1) : off(001) Digital Filter(ph0/1) : 1-1/2(001)\r
+       },\r
+       {\r
+               .reg = SX932x_PROX_CTRL1_REG,  //0x31\r
+               .val = 0x09,       // Digital Gain(ph2/3) : off(001) Digital Filter(ph2/3) : 1-1/2(001)\r
+       },\r
+       {\r
+               .reg = SX932x_PROX_CTRL2_REG,  //0x32\r
+               .val = 0x08,       //AVGNEGTHRESH : 16384\r
+       },\r
+       {\r
+               .reg = SX932x_PROX_CTRL3_REG,  // 0x33 \r
+               .val = 0x20,       //AVGPOSTHRESH : 16384\r
+       },\r
+       {\r
+               .reg = SX932x_PROX_CTRL4_REG,  //0x34 \r
+               .val = 0x0C,       //AVGFREEZEDIS : on(0) ,AVGNEGFILT :1-1/2(001) ,AVGPOSFILT : 1-1/256(100)\r
+       },\r
+       {\r
+               .reg = SX932x_PROX_CTRL5_REG,  //0x35\r
+               .val = 0x00,       //FARCOND: PROXDIFF < (THRESH.HYST), HYST : None, CLOSEDEB : off ,FARDEB : off\r
+       },\r
+       {\r
+               .reg = SX932x_PROX_CTRL6_REG,  //0x36\r
+               .val = 0x1B,       // Prox Theshold(ph0/1) : 200\r
+       },\r
+       {\r
+               .reg = SX932x_PROX_CTRL7_REG,  //0x37\r
+               .val = 0x1B,       // Prox Theshold(ph2/3) : 200\r
+       },\r
+       //--------Advanced control (defult)\r
+       {\r
+               .reg = SX932x_ADV_CTRL0_REG,\r
+               .val = 0x00,\r
+       },\r
+       {\r
+               .reg = SX932x_ADV_CTRL1_REG,\r
+               .val = 0x00,\r
+       },\r
+       {\r
+               .reg = SX932x_ADV_CTRL2_REG,\r
+               .val = 0x00,\r
+       },\r
+       {\r
+               .reg = SX932x_ADV_CTRL3_REG,\r
+               .val = 0x00,\r
+       },\r
+       {\r
+               .reg = SX932x_ADV_CTRL4_REG,\r
+               .val = 0x00,\r
+       },\r
+       {\r
+               .reg = SX932x_ADV_CTRL5_REG,\r
+               .val = 0x05,\r
+       },\r
+       {\r
+               .reg = SX932x_ADV_CTRL6_REG,\r
+               .val = 0x00,\r
+       },\r
+       {\r
+               .reg = SX932x_ADV_CTRL7_REG,\r
+               .val = 0x00,\r
+       },\r
+       {\r
+               .reg = SX932x_ADV_CTRL8_REG,\r
+               .val = 0x00,\r
+       },\r
+       {\r
+               .reg = SX932x_ADV_CTRL9_REG,\r
+               .val = 0x80,\r
+       },\r
+       {\r
+               .reg = SX932x_ADV_CTRL10_REG,\r
+               .val = 0x00,\r
+       },\r
+       {\r
+               .reg = SX932x_ADV_CTRL11_REG,\r
+               .val = 0x00,\r
+       },\r
+       {\r
+               .reg = SX932x_ADV_CTRL12_REG,\r
+               .val = 0x00,\r
+       },\r
+       {\r
+               .reg = SX932x_ADV_CTRL13_REG,\r
+               .val = 0x00,\r
+       },\r
+       {\r
+               .reg = SX932x_ADV_CTRL14_REG,\r
+               .val = 0x80,\r
+       },\r
+       {\r
+               .reg = SX932x_ADV_CTRL15_REG,\r
+               .val = 0x0C,\r
+       },\r
+       {\r
+               .reg = SX932x_ADV_CTRL16_REG,\r
+               .val = 0x00,\r
+       },\r
+       {\r
+               .reg = SX932x_ADV_CTRL17_REG,\r
+               .val = 0x70,\r
+       },\r
+       {\r
+               .reg = SX932x_ADV_CTRL18_REG,\r
+               .val = 0x20,\r
+       },\r
+       {\r
+               .reg = SX932x_ADV_CTRL19_REG,\r
+               .val = 0xe1,\r
+       },\r
+       {\r
+               .reg = SX932x_ADV_CTRL20_REG,\r
+               .val = 0xF0,\r
+       },\r
+       //--------Sensor enable\r
+       {\r
+               .reg = SX932x_CTRL1_REG,    //0x11\r
+               .val = 0x27,       //enable PH2\r
+       },\r
+};\r
+\r
+static struct _buttonInfo psmtcButtons[] = {\r
+       {\r
+               .keycode = KEY_0,\r
+               .mask = SX932x_PROXSTAT_PH0_FLAG,\r
+       },\r
+       {\r
+               .keycode = KEY_1,\r
+               .mask = SX932x_PROXSTAT_PH1_FLAG,\r
+       },\r
+       {\r
+               .keycode = KEY_2,\r
+               .mask = SX932x_PROXSTAT_PH2_FLAG,\r
+       },\r
+       {\r
+               .keycode = KEY_3,\r
+               .mask = SX932x_PROXSTAT_PH3_FLAG,\r
+       },\r
+};\r
+\r
+struct sx932x_platform_data {\r
+       int i2c_reg_num;\r
+       struct smtc_reg_data *pi2c_reg;\r
+       int irq_gpio;\r
+       struct regulator *cap_vdd;\r
+       bool cap_vdd_en;\r
+       pbuttonInformation_t pbuttonInformation;\r
+\r
+       int (*get_is_nirq_low)(void);\r
+       u8 input_mainsensor;  // 0x01 ~ 0x02,//Startup function\r
+       u8 input_refsensor;   // 0x00 ~ 0x02,//Startup function\r
+       \r
+       int     (*init_platform_hw)(struct i2c_client *client);\r
+       void    (*exit_platform_hw)(struct i2c_client *client);\r
+};\r
+typedef struct sx932x_platform_data sx932x_platform_data_t;\r
+typedef struct sx932x_platform_data *psx932x_platform_data_t;\r
+\r
+/***************************************\r
+*  define data struct/interrupt\r
+*\r
+***************************************/\r
+\r
+#define MAX_NUM_STATUS_BITS (8)\r
+\r
+typedef struct sx93XX sx93XX_t, *psx93XX_t;\r
+struct sx93XX \r
+{\r
+       void * bus; /* either i2c_client or spi_client */\r
+\r
+       struct device *pdev; /* common device struction for linux */\r
+\r
+       void *pDevice; /* device specific struct pointer */\r
+\r
+       /* Function Pointers */\r
+       int (*init)(psx93XX_t this); /* (re)initialize device */\r
+\r
+       /* since we are trying to avoid knowing registers, create a pointer to a\r
+       * common read register which would be to read what the interrupt source\r
+       * is from \r
+       */\r
+       int (*refreshStatus)(psx93XX_t this); /* read register status */\r
+\r
+       int (*get_nirq_low)(void); /* get whether nirq is low (platform data) */\r
+\r
+       /* array of functions to call for corresponding status bit */\r
+       void (*statusFunc[MAX_NUM_STATUS_BITS])(psx93XX_t this); \r
+       \r
+       /* Global variable */\r
+       u8              failStatusCode; /*Fail status code*/\r
+       bool    reg_in_dts;\r
+\r
+       spinlock_t       lock; /* Spin Lock used for nirq worker function */\r
+       int irq; /* irq number used */\r
+\r
+       /* whether irq should be ignored.. cases if enable/disable irq is not used\r
+       * or does not work properly */\r
+       char irq_disabled;\r
+\r
+       u8 useIrqTimer; /* older models need irq timer for pen up cases */\r
+\r
+       int irqTimeout; /* msecs only set if useIrqTimer is true */\r
+\r
+       /* struct workqueue_struct *ts_workq;  */  /* if want to use non default */\r
+       struct delayed_work dworker; /* work struct for worker function */\r
+};\r
+\r
+void sx93XX_suspend(psx93XX_t this);\r
+void sx93XX_resume(psx93XX_t this);\r
+int sx93XX_IRQ_init(psx93XX_t this);\r
+int sx93XX_remove(psx93XX_t this);\r
+\r
+#endif\r