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