--- /dev/null
+/*! \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,®_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", ®_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", ®ist) != 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
--- /dev/null
+/*\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