From: hq_guohongtao5_tmp Date: Wed, 29 Aug 2018 08:11:20 +0000 (+0800) Subject: (CR):[kane]:kernel: add sar sensor sx9325 drivers X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=c4d52451e347a986929f2accfac48662bf539afa;p=GitHub%2Fmoto-9609%2Fandroid_kernel_motorola_exynos9610.git (CR):[kane]:kernel: add sar sensor sx9325 drivers add sar sensor sx9325 drivers Change-Id: I701d32e90ad56d0444df5b8029de6225bf3acf10 Signed-off-by: hq_guohongtao5_tmp --- diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index f2cd79560060..b9e8ce9cf087 100755 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -84,4 +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 +obj-$(CONFIG_SARSENSOR_SX9325) += sx9325_sar.o diff --git a/drivers/input/misc/sx9325_sar.c b/drivers/input/misc/sx9325_sar.c new file mode 100755 index 000000000000..7eb01fb16908 --- /dev/null +++ b/drivers/input/misc/sx9325_sar.c @@ -0,0 +1,1717 @@ +/* + * file sx9325_sar.c + * brief SX9325 Driver for two channel SAP using + * + * Driver for the SX9325 + * Copyright (c) 2015-2016 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 "sx9325" +#define USE_SENSORS_CLASS +#define USE_KERNEL_SUSPEND + +#define MAX_WRITE_ARRAY_SIZE 32 + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_FB) +#include +#endif + +/* main struct, interrupt,init,pointers */ +#include "sx9325_sar.h" + + +#define IDLE 0 +#define ACTIVE 1 +#define S_PROX 1 +#define S_BODY 2 + +#define SX9325_DEBUG 1 +#define LOG_TAG "SX9325 " + +#if SX9325_DEBUG +#define LOG_INFO(fmt, args...) pr_info(LOG_TAG fmt, ##args) +#else +#define LOG_INFO(fmt, args...) +#endif + +#define LOG_DBG(fmt, args...) pr_debug(LOG_TAG fmt, ##args) +#define LOG_ERR(fmt, args...) pr_err(LOG_TAG fmt, ##args) + +static int sx9325_debug_enable = 1; + +static int last_val; +static int mEnabled; +static int programming_done; +psx93XX_t sx9325_sar_ptr; + +/** + * struct sx9325 + * Specialized struct containing input event data, platform data, and + * last cap state read if needed. + */ +typedef struct sx9325 { + pbuttonInformation_t pbuttonInformation; + psx9325_platform_data_t hw; /* specific platform data settings */ +} sx9325_t, *psx9325_t; + +static void ForcetoTouched(psx93XX_t this) +{ + psx9325_t pDevice = NULL; + struct input_dev *input_top = NULL; + struct input_dev *input_bottom = NULL; + struct _buttonInfo *pCurrentButton = NULL; + + pDevice = this->pDevice; + if (this && pDevice) { + LOG_INFO("ForcetoTouched()\n"); + + pCurrentButton = pDevice->pbuttonInformation->buttons; + input_top = pDevice->pbuttonInformation->input_top; + input_bottom = pDevice->pbuttonInformation->input_bottom; + pCurrentButton->state = ACTIVE; + last_val = 1; + if (mEnabled) { + input_report_abs(input_top, ABS_DISTANCE, 1); + input_sync(input_top); + input_report_abs(input_bottom, ABS_DISTANCE, 1); + input_sync(input_bottom); + } + LOG_INFO("Leaving ForcetoTouched()\n"); + } +} + +/** + * 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); + if (sx9325_debug_enable) + LOG_DBG("write_register Addr: \ + 0x%x Val: 0x%x Return: %d\n", + address, value, returnValue); + } + if (returnValue < 0) { + ForcetoTouched(this); + LOG_INFO("Write_register-ForcetoTouched()\n"); + } + 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; + returnValue = i2c_smbus_read_byte_data(i2c, address); + if (sx9325_debug_enable) + LOG_DBG("read_register Addr: 0x%x Return: 0x%x\n", + address, returnValue); + if (returnValue >= 0) { + *value = returnValue; + return 0; + } else { + return returnValue; + } + } + ForcetoTouched(this); + LOG_INFO("read_register-ForcetoTouched()\n"); + return -ENOMEM; +} + +/** + * detect if sx9325 exist or not + * return 1 if chip exist else return 0 + */ +static int sx9325_detect(struct i2c_client *client) +{ + s32 returnValue = 0, i; + u8 address = SX932x_WHOAMI_REG; + u8 value_9325 = SX932x_WHOAMI_VALUE; + + if (client) { + for (i = 0; i < 3; i++) { + returnValue = i2c_smbus_read_byte_data(client, address); + LOG_INFO("sx9325 read_register for %d time Addr:\ + 0x%x Return: 0x%x\n", + i, address, returnValue); + if (value_9325 == returnValue){ + LOG_INFO("sx9325 detect success !\n"); + return 1; + } + } + } + LOG_ERR("sx9325 detect failed !!!\n"); + 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); + + LOG_INFO("Reading IRQSTAT_REG\n"); + read_register(this, SX932x_IRQSTAT_REG, ®_value); + return scnprintf(buf, PAGE_SIZE, "%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) { + LOG_INFO("Performing manual_offset_calibration()\n"); + manual_offset_calibration(this); + } + return count; +} + +static DEVICE_ATTR(calibrate, 0644, manual_offset_calibration_show, + manual_offset_calibration_store); +static struct attribute *sx9325_attributes[] = { + &dev_attr_calibrate.attr, + NULL, +}; +static struct attribute_group sx9325_attr_group = { + .attrs = sx9325_attributes, +}; + +/** + * 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; +} + +static void read_rawData(psx93XX_t this) +{ + u8 msb = 0, lsb = 0; + unsigned int ii; + + if (this) { + for (ii = 0; ii < USE_CHANNEL_NUM; ii++) { + /* here to check the CSx */ + write_register(this, SX932x_CPSRD, ii); + msleep(100); + read_register(this, SX932x_USEMSB, &msb); + read_register(this, SX932x_USELSB, &lsb); + LOG_INFO("sx9325 cs%d USEFUL msb = 0x%x, lsb = 0x%x\n", + ii, msb, lsb); + read_register(this, SX932x_AVGMSB, &msb); + read_register(this, SX932x_AVGLSB, &lsb); + LOG_INFO("sx9325 cs%d AVERAGE msb = 0x%x, lsb = 0x%x\n", + ii, msb, lsb); + read_register(this, SX932x_DIFFMSB, &msb); + read_register(this, SX932x_DIFFLSB, &lsb); + LOG_INFO("sx9325 cs%d DIFF msb = 0x%x, lsb = 0x%x\n", + ii, msb, lsb); + read_register(this, SX932x_OFFSETMSB, &msb); + read_register(this, SX932x_OFFSETLSB, &lsb); + LOG_INFO("sx9325 cs%d OFFSET msb = 0x%x, lsb = 0x%x\n", + ii, msb, lsb); + } + } +} + +/** + * brief Initialize I2C config from platform data + * param this Pointer to main parent struct + * + */ +static void hw_init(psx93XX_t this) +{ + psx9325_t pDevice = 0; + psx9325_platform_data_t pdata = 0; + int i = 0; + /* configure device */ + LOG_INFO("Going to Setup I2C Registers\n"); + pDevice = this->pDevice; + pdata = pDevice->hw; + if (this && pDevice && pdata) { + while (i < pdata->i2c_reg_num) { + /* Write all registers/values contained in i2c_reg */ + if (sx9325_debug_enable) + LOG_DBG("Going to Write Reg: \ + 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++; + } + + write_register(this, SX932x_CTRL1_REG, + this->board->cust_prox_ctrl0); + write_register(this, SX932x_CPSRD, + this->board->cust_raw_data_channel); + } else { + LOG_ERR("ERROR! platform data 0x%p\n", pDevice->hw); + /* Force to touched if error */ + ForcetoTouched(this); + LOG_INFO("Hardware_init-ForcetoTouched()\n"); + } +} + +/** + * 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) { + /* prepare reset by disabling any irq handling */ + this->irq_disabled = 1; + disable_irq(this->irq); + /* perform a reset */ + ret = write_register(this, SX932x_SOFTRESET_REG, + SX932x_SOFTRESET); + if (ret < 0) + goto error_exit; + /* wait until the reset has finished by monitoring NIRQ */ + LOG_INFO("Software Reset. Waiting device back to continue.\n"); + /* just sleep for awhile instead of using a loop + * with reading irq status */ + msleep(300); + /* + * while(this->get_nirq_low && this->get_nirq_low()) + * { read_regStat(this); } + */ + LOG_INFO("Device back from the reset, continuing. NIRQ = %d\n", + this->get_nirq_low(this->board->irq_gpio)); + hw_init(this); + msleep(100); /* make sure everything is running */ + ret = manual_offset_calibration(this); + if (ret < 0) + goto error_exit; + /* re-enable interrupt handling */ + enable_irq(this->irq); + this->irq_disabled = 0; + + /* make sure no interrupts are pending + * since enabling irq will only + * work on next falling edge */ + read_regStat(this); + LOG_INFO("Exiting initialize(). NIRQ = %d\n", + this->get_nirq_low(this->board->irq_gpio)); + programming_done = ACTIVE; + return 0; + } + return -ENOMEM; + +error_exit: + programming_done = IDLE; + return ret; +} + +/** + * 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; + u8 Lsb,Msb; + int numberOfButtons = 0; + psx9325_t pDevice = NULL; + struct _buttonInfo *buttons = NULL; + struct input_dev *input_top = NULL; + struct input_dev *input_bottom = NULL; + struct _buttonInfo *pCurrentButton = NULL; + struct sx9325_platform_data *board; + + pDevice = this->pDevice; + board = this->board; + if (this && pDevice) { + if (sx9325_debug_enable) + LOG_DBG("Inside touchProcess()\n"); + + read_register(this, SX932x_STAT0_REG, &Lsb); + read_register(this, SX932x_STAT1_REG, &Msb); + Lsb = (u8)(Lsb&0x0F); + Msb = (u8)(Msb&0x0F); + i = (u8)((Msb<<4)|Lsb); + + buttons = pDevice->pbuttonInformation->buttons; + input_top = pDevice->pbuttonInformation->input_top; + input_bottom = pDevice->pbuttonInformation->input_bottom; + numberOfButtons = pDevice->pbuttonInformation->buttonSize; + + if (unlikely((buttons == NULL) || (input_top == NULL) || + (input_bottom == NULL))) { + LOG_ERR("ERROR!! buttons or input NULL!!!\n"); + return; + } + + for (counter = 0; counter < numberOfButtons; counter++) { + pCurrentButton = &buttons[counter]; + if (pCurrentButton == NULL) { + LOG_ERR("ERR!current button index: %d NULL!\n", + counter); + return; /* ERRORR!!!! */ + } + switch (pCurrentButton->state) { + case IDLE: /* Button is being in far state! */ + if ((i & pCurrentButton->mask) == + pCurrentButton->mask) { + LOG_INFO("CS %d State=BODY.\n", + counter); + if (board->cap_channel_top == counter) { + input_report_abs(input_top, + ABS_DISTANCE, 2); + input_sync(input_top); + } else if (board->cap_channel_bottom == + counter) { + input_report_abs(input_bottom, + ABS_DISTANCE, 2); + input_sync(input_bottom); + } + pCurrentButton->state = S_BODY; + last_val = 2; + } else if ((i & pCurrentButton->mask) == + (pCurrentButton->mask & 0x0f)) { + LOG_INFO("CS %d State=PROX.\n", + counter); + if (board->cap_channel_top == counter) { + input_report_abs(input_top, + ABS_DISTANCE, 1); + input_sync(input_top); + } else if (board->cap_channel_bottom == + counter) { + input_report_abs(input_bottom, + ABS_DISTANCE, 1); + input_sync(input_bottom); + } + pCurrentButton->state = S_PROX; + last_val = 0; + } else { + if (sx9325_debug_enable) + LOG_DBG("CS %d still in" + "IDLE State.\n", + counter); + } + break; + case S_PROX: /* Button is being in proximity! */ + if ((i & pCurrentButton->mask) == + pCurrentButton->mask) { + LOG_INFO("CS %d State=BODY.\n", + counter); + if (board->cap_channel_top == counter) { + input_report_abs(input_top, + ABS_DISTANCE, 2); + input_sync(input_top); + } else if (board->cap_channel_bottom == + counter) { + input_report_abs(input_bottom, + ABS_DISTANCE, 2); + input_sync(input_bottom); + } + pCurrentButton->state = S_BODY; + last_val = 2; + } else if ((i & pCurrentButton->mask) == + (pCurrentButton->mask & 0x0f)) { + if (sx9325_debug_enable) + LOG_INFO("CS %d still in PROX State.\n", + counter); + } else{ + if (sx9325_debug_enable) + LOG_DBG("CS %d State=IDLE.\n", + counter); + if (board->cap_channel_top == counter) { + input_report_abs(input_top, + ABS_DISTANCE, 0); + input_sync(input_top); + } else if (board->cap_channel_bottom == + counter) { + input_report_abs(input_bottom, + ABS_DISTANCE, 0); + input_sync(input_bottom); + } + pCurrentButton->state = IDLE; + last_val = 0; + } + break; + case S_BODY: /* Button is being in 0mm! */ + if ((i & pCurrentButton->mask) == + pCurrentButton->mask) { + if (sx9325_debug_enable) + LOG_INFO("CS %d still in BODY State.\n", + counter); + } else if ((i & pCurrentButton->mask) == + (pCurrentButton->mask & 0x0f)) { + LOG_INFO("CS %d State=PROX.\n", + counter); + if (board->cap_channel_top == counter) { + input_report_abs(input_top, + ABS_DISTANCE, 1); + input_sync(input_top); + } else if (board->cap_channel_bottom + == counter) { + input_report_abs(input_bottom, + ABS_DISTANCE, 1); + input_sync(input_bottom); + } + pCurrentButton->state = S_PROX; + last_val = 1; + } else{ + if (sx9325_debug_enable) + LOG_DBG("CS %d State=IDLE.\n", + counter); + if (board->cap_channel_top == counter) { + input_report_abs(input_top, + ABS_DISTANCE, 0); + input_sync(input_top); + } else if (board->cap_channel_bottom + == counter) { + input_report_abs(input_bottom, + ABS_DISTANCE, 0); + input_sync(input_bottom); + } + pCurrentButton->state = IDLE; + last_val = 0; + } + break; + /* Shouldn't be here, device only + * allowed ACTIVE or IDLE */ + default: + break; + }; + } + if (sx9325_debug_enable) + LOG_DBG("Leaving touchProcess()\n"); + } +} + +static int sx9325_get_nirq_state(unsigned irq_gpio) +{ + if (irq_gpio) + return !gpio_get_value(irq_gpio); + + LOG_ERR("sx9325 irq_gpio is not set."); + return -EINVAL; +} + +static struct _totalButtonInformation smtcButtonInformation = { + .buttons = psmtcButtons, + .buttonSize = ARRAY_SIZE(psmtcButtons), +}; + +/** + *fn static void sx9325_reg_setup_init(struct i2c_client *client) + *brief read reg val form dts + * reg_array_len for regs needed change num + * data_array_val's format + */ +static void sx9325_reg_setup_init(struct i2c_client *client) +{ + u32 data_array_len = 0; + u32 *data_array; + int ret, i, j; + struct device_node *np = client->dev.of_node; + + ret = of_property_read_u32(np, "reg_array_len", &data_array_len); + if (ret < 0) { + LOG_ERR("data_array_len read error"); + return; + } + data_array = kmalloc(data_array_len * 2 * sizeof(u32), GFP_KERNEL); + ret = of_property_read_u32_array(np, "reg_array_val", + data_array, + data_array_len*2); + if (ret < 0) { + LOG_ERR("data_array_val read error"); + return; + } + for (i = 0; i < ARRAY_SIZE(sx9325_i2c_reg_setup); i++) { + for (j = 0; j < data_array_len*2; j += 2) { + if (data_array[j] == sx9325_i2c_reg_setup[i].reg) { + sx9325_i2c_reg_setup[i].val = data_array[j+1]; + LOG_INFO("read dtsi 0x%02x:0x%02x set reg\n", + data_array[j], data_array[j+1]); + } + } + } + kfree(data_array); + /*for test*/ + /*for (i = 0; i < ARRAY_SIZE(sx9325_i2c_reg_setup); i++) { + dev_err(&client->dev, "%x:%x", + sx9325_i2c_reg_setup[i].reg, + sx9325_i2c_reg_setup[i].val); + }*/ +} + +static void sx9325_platform_data_of_init(struct i2c_client *client, + psx9325_platform_data_t pplatData) +{ + struct device_node *np = client->dev.of_node; + u32 scan_period, sensor_en, raw_data_channel; + u32 cap_channel_top, cap_channel_bottom; + int ret; + + client->irq = of_get_gpio(np, 0); + pplatData->irq_gpio = client->irq; + + ret = of_property_read_u32(np, "cap,use_channel", &sensor_en); + if (ret) + sensor_en = DUMMY_USE_CHANNEL; + + ret = of_property_read_u32(np, "cap,use_channel_top", &cap_channel_top); + if (ret) + sensor_en = DUMMY_USE_CHANNEL; + + ret = of_property_read_u32(np, "cap,use_channel_bottom", + &cap_channel_bottom); + if (ret) + sensor_en = DUMMY_USE_CHANNEL; + + ret = of_property_read_u32(np, "cap,scan_period", &scan_period); + if (ret) + scan_period = DUMMY_SCAN_PERIOD; + + ret = of_property_read_u32(np, "cap,raw_data_channel", + &raw_data_channel); + if (ret) + raw_data_channel = DUMMY_RAW_DATA_CHANNEL; + + pplatData->cust_prox_ctrl0 = (scan_period << 4) | sensor_en; + pplatData->cust_raw_data_channel = raw_data_channel; + pplatData->cap_channel_top = (int)cap_channel_top; + pplatData->cap_channel_bottom = (int)cap_channel_bottom; + + pplatData->get_is_nirq_low = sx9325_get_nirq_state; + pplatData->init_platform_hw = NULL; + /* pointer to an exit function. Here in case needed in the future */ + /* + *.exit_platform_hw = sx9325_exit_ts, + */ + pplatData->exit_platform_hw = NULL; + sx9325_reg_setup_init(client); + pplatData->pi2c_reg = sx9325_i2c_reg_setup; + pplatData->i2c_reg_num = ARRAY_SIZE(sx9325_i2c_reg_setup); + + pplatData->pbuttonInformation = &smtcButtonInformation; +} + +static ssize_t reset_show(struct class *class, + struct class_attribute *attr, + char *buf) +{ + return snprintf(buf, 8, "%d\n", programming_done); +} + +static ssize_t reset_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t count) +{ + psx93XX_t this = sx9325_sar_ptr; + psx9325_t pDevice = NULL; + struct input_dev *input_top = NULL; + struct input_dev *input_bottom = NULL; + + pDevice = this->pDevice; + input_top = pDevice->pbuttonInformation->input_top; + input_bottom = pDevice->pbuttonInformation->input_bottom; + + if (!count || (this == NULL)) + return -EINVAL; + + if (!strncmp(buf, "reset", 5) || !strncmp(buf, "1", 1)) + write_register(this, SX932x_STAT2_REG, 0x0F); + + input_report_abs(input_top, ABS_DISTANCE, 0); + input_sync(input_top); + input_report_abs(input_bottom, ABS_DISTANCE, 0); + input_sync(input_bottom); + + return count; +} + +static CLASS_ATTR_RW(reset); + +static ssize_t enable_show(struct class *class, + struct class_attribute *attr, + char *buf) +{ + return snprintf(buf, 8, "%d\n", mEnabled); +} + +static ssize_t enable_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t count) +{ + psx93XX_t this = sx9325_sar_ptr; + psx9325_t pDevice = NULL; + struct input_dev *input_top = NULL; + struct input_dev *input_bottom = NULL; + + pDevice = this->pDevice; + input_top = pDevice->pbuttonInformation->input_top; + input_bottom = pDevice->pbuttonInformation->input_bottom; + + if (!count || (this == NULL)) + return -EINVAL; + + if ((!strncmp(buf, "1", 1)) && (mEnabled == 0)) { + LOG_INFO("enable cap sensor\n"); + initialize(this); + + input_report_abs(input_top, ABS_DISTANCE, 0); + input_sync(input_top); + input_report_abs(input_bottom, ABS_DISTANCE, 0); + input_sync(input_bottom); + mEnabled = 1; + } else if ((!strncmp(buf, "0", 1)) && (mEnabled == 1)) { + LOG_INFO("disable cap sensor\n"); + + write_register(this, SX932x_CTRL1_REG, 0x10); + write_register(this, SX932x_IRQ_ENABLE_REG, 0x00); + + input_report_abs(input_top, ABS_DISTANCE, -1); + input_sync(input_top); + input_report_abs(input_bottom, ABS_DISTANCE, -1); + input_sync(input_bottom); + mEnabled = 0; + } else { + LOG_ERR("unknown enable symbol\n"); + } + + return count; +} + +#ifdef USE_SENSORS_CLASS +static int capsensor_set_enable(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + psx93XX_t this = sx9325_sar_ptr; + psx9325_t pDevice = NULL; + struct input_dev *input_top = NULL; + struct input_dev *input_bottom = NULL; + + pDevice = this->pDevice; + input_top = pDevice->pbuttonInformation->input_top; + input_bottom = pDevice->pbuttonInformation->input_bottom; + + if ((enable == 1) && (mEnabled == 0)) { + LOG_INFO("enable cap sensor\n"); + initialize(this); + + input_report_abs(input_top, ABS_DISTANCE, 0); + input_sync(input_top); + input_report_abs(input_bottom, ABS_DISTANCE, 0); + input_sync(input_bottom); + mEnabled = 1; + } else if ((enable == 0) && (mEnabled == 1)) { + LOG_INFO("disable cap sensor\n"); + + write_register(this, SX932x_CTRL1_REG, 0x00); + write_register(this, SX932x_IRQ_ENABLE_REG, 0x00); + + input_report_abs(input_top, ABS_DISTANCE, -1); + input_sync(input_top); + input_report_abs(input_bottom, ABS_DISTANCE, -1); + input_sync(input_bottom); + mEnabled = 0; + } else { + LOG_ERR("unknown enable symbol\n"); + } + + return 0; +} +#endif + +static CLASS_ATTR_RW(enable); +static ssize_t reg_show(struct class *class, + struct class_attribute *attr, + char *buf) +{ + u16 i = 0; + u8 reg_value = 0; + u16 register_number = 0; + psx93XX_t this = sx9325_sar_ptr; + char *p = buf; + + if (this->read_flag) { + this->read_flag = 0; + read_register(this, this->read_reg, ®_value); + p += snprintf(p, PAGE_SIZE, "%02x\n", reg_value); + return (p-buf); + } + + read_register(this, SX932x_IRQSTAT_REG, ®_value); + p += snprintf(p, PAGE_SIZE, "IRQSTAT(0x%02x)=0x%02x\n", + SX932x_IRQSTAT_REG, reg_value); + + read_register(this, SX932x_STAT0_REG, ®_value); + p += snprintf(p, PAGE_SIZE, "STAT0(0x%02x)=0x%02x\n", + SX932x_STAT0_REG, reg_value); + + read_register(this, SX932x_STAT1_REG, ®_value); + p += snprintf(p, PAGE_SIZE, "STAT1(0x%02x)=0x%02x\n", + SX932x_STAT1_REG, reg_value); + + read_register(this, SX932x_STAT2_REG, ®_value); + p += snprintf(p, PAGE_SIZE, "STAT2(0x%02x)=0x%02x\n", + SX932x_STAT2_REG, reg_value); + + read_register(this, SX932x_STAT3_REG, ®_value); + p += snprintf(p, PAGE_SIZE, "STAT3(0x%02x)=0x%02x\n", + SX932x_STAT3_REG, reg_value); + + register_number = sizeof(sx9325_i2c_reg_setup)/sizeof(smtc_reg_data_t); + + for (i = 0; i < register_number; i++) + { + read_register(this, sx9325_i2c_reg_setup[i].reg, ®_value); + p += snprintf(p, PAGE_SIZE, "ENABLE(0x%02x)=0x%02x\n", + sx9325_i2c_reg_setup[i].reg, reg_value); + } + + read_register(this, SX932x_CPSRD, ®_value); + p += snprintf(p, PAGE_SIZE, "CPSRD(0x%02x)=0x%02x\n", + SX932x_CPSRD, reg_value); + + read_register(this, SX932x_USEMSB, ®_value); + p += snprintf(p, PAGE_SIZE, "USEMSB(0x%02x)=0x%02x\n", + SX932x_USEMSB, reg_value); + + read_register(this, SX932x_USELSB, ®_value); + p += snprintf(p, PAGE_SIZE, "USELSB(0x%02x)=0x%02x\n", + SX932x_USELSB, reg_value); + + read_register(this, SX932x_AVGMSB, ®_value); + p += snprintf(p, PAGE_SIZE, "AVGMSB(0x%02x)=0x%02x\n", + SX932x_AVGMSB, reg_value); + + read_register(this, SX932x_AVGLSB, ®_value); + p += snprintf(p, PAGE_SIZE, "AVGLSB(0x%02x)=0x%02x\n", + SX932x_AVGLSB, reg_value); + + read_register(this, SX932x_DIFFMSB, ®_value); + p += snprintf(p, PAGE_SIZE, "DIFFMSB(0x%02x)=0x%02x\n", + SX932x_DIFFMSB, reg_value); + + read_register(this, SX932x_DIFFLSB, ®_value); + p += snprintf(p, PAGE_SIZE, "DIFFLSB(0x%02x)=0x%02x\n", + SX932x_DIFFLSB, reg_value); + + read_register(this, SX932x_OFFSETMSB, ®_value); + p += snprintf(p, PAGE_SIZE, "OFFSETMSB(0x%02x)=0x%02x\n", + SX932x_OFFSETMSB, reg_value); + + read_register(this, SX932x_OFFSETLSB, ®_value); + p += snprintf(p, PAGE_SIZE, "OFFSETLSB(0x%02x)=0x%02x\n", + SX932x_OFFSETLSB, reg_value); + + reg_value = gpio_get_value(this->board->irq_gpio); + p += snprintf(p, PAGE_SIZE, "NIRQ=%d\n", reg_value); + + return (p-buf); +} + +static ssize_t reg_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t count) +{ + psx93XX_t this = sx9325_sar_ptr; + unsigned int val, reg, opt; + + if (strcmp("select_ch0\n", buf) == 0) { + write_register(this, SX932x_CPSRD, 0x00); + } else if (strcmp("select_ch1\n", buf) == 0) { + write_register(this, SX932x_CPSRD, 0x01); + } else if (strcmp("select_ch2\n", buf) == 0) { + write_register(this, SX932x_CPSRD, 0x02); + } else if (strcmp("calibrate\n", buf) == 0) { + write_register(this, SX932x_STAT2_REG, 0x0f); + } else if (sscanf(buf, "%x,%x,%x", ®, &val, &opt) == 3) { + LOG_DBG("%s, read reg = 0x%02x\n", __func__, *(u8 *)®); + this->read_reg = *((u8 *)®); + this->read_flag = 1; + } else if (sscanf(buf, "%x,%x", ®, &val) == 2) { + LOG_DBG("%s,reg = 0x%02x, val = 0x%02x\n", + __func__, *(u8 *)®, *(u8 *)&val); + write_register(this, *((u8 *)®), *((u8 *)&val)); + } + + return count; +} + +static CLASS_ATTR_RW(reg); + +static void ps_notify_callback_work(struct work_struct *work) +{ + psx93XX_t this = container_of(work, sx93XX_t, ps_notify_work); + psx9325_t pDevice = NULL; + struct input_dev *input_top = NULL; + struct input_dev *input_bottom = NULL; + int ret = 0; + + pDevice = this->pDevice; + input_top = pDevice->pbuttonInformation->input_top; + input_bottom = pDevice->pbuttonInformation->input_bottom; + + mutex_lock(&this->mutex); + if (mEnabled) { + LOG_INFO("Usb insert,going to force calibrate\n"); + ret = write_register(this, SX932x_CTRL1_REG, 0x00); + if (ret < 0) + LOG_ERR(" Usb insert,calibrate cap sensor failed\n"); + msleep(100); + ret = write_register(this, SX932x_CTRL1_REG, + this->board->cust_prox_ctrl0); + if (ret < 0) + LOG_ERR(" Usb insert,enabel cap sensor failed\n"); + } + mutex_unlock(&this->mutex); + input_report_abs(input_top, ABS_DISTANCE, 0); + input_sync(input_top); + input_report_abs(input_bottom, ABS_DISTANCE, 0); + input_sync(input_bottom); +} + +static int ps_get_state(struct power_supply *psy, bool *present) +{ + union power_supply_propval pval = { 0 }; + int retval; + + retval = power_supply_get_property(psy, POWER_SUPPLY_PROP_PRESENT, + &pval); + if (retval) { + LOG_ERR("%s psy get property failed\n", psy->desc->name); + return retval; + } + *present = (pval.intval) ? true : false; + LOG_INFO("%s is %s\n", psy->desc->name, + (*present) ? "present" : "not present"); + return 0; +} + +static int ps_notify_callback(struct notifier_block *self, + unsigned long event, void *p) +{ + psx93XX_t this = container_of(self, sx93XX_t, ps_notif); + struct power_supply *psy = p; + bool present; + int retval; + + if ((event == PSY_EVENT_PROP_ADDED || event == PSY_EVENT_PROP_CHANGED) + && psy && psy->desc->get_property && psy->desc->name && + !strncmp(psy->desc->name, "usb", sizeof("usb"))) { + LOG_INFO("ps notification: event = %lu\n", event); + retval = ps_get_state(psy, &present); + if (retval) { + LOG_ERR("psy get property failed\n"); + return retval; + } + + if (event == PSY_EVENT_PROP_CHANGED) { + if (this->ps_is_present == present) { + LOG_INFO("ps present state not change\n"); + return 0; + } + } + this->ps_is_present = present; + schedule_work(&this->ps_notify_work); + } + + return 0; +} + +#if defined(CONFIG_FB) +static void fb_notify_resume_work(struct work_struct *work) +{ + psx93XX_t this = container_of(work, sx93XX_t, fb_notify_work); + psx9325_t pDevice = NULL; + struct input_dev *input_top = NULL; + struct input_dev *input_bottom = NULL; + int ret = 0; + + pDevice = this->pDevice; + input_top = pDevice->pbuttonInformation->input_top; + input_bottom = pDevice->pbuttonInformation->input_bottom; + + if (sx9325_debug_enable) + LOG_INFO("Lcd suspend/resume event,going to force reset\n"); + ret = write_register(this, SX932x_STAT2_REG, 0x0f); + if (ret < 0) + LOG_ERR(" Lcd suspend/resume,reset cap sensor failed\n"); +} + +static int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int *blank; + psx93XX_t this = container_of(self, sx93XX_t, fb_notif); + + if ((event == FB_EVENT_BLANK) && + evdata && evdata->data) { + blank = evdata->data; + if ((*blank == FB_BLANK_POWERDOWN) + || (*blank == FB_BLANK_UNBLANK)) { + if (sx9325_debug_enable) + LOG_INFO("fb event = %lu blank = %d\n", + event, *blank); + schedule_work(&this->fb_notify_work); + } + } + + return 0; +} +#endif + +static struct class capsense_class = { + .name = "capsense", + .owner = THIS_MODULE, +}; + +/** + * fn static int sx9325_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 sx9325_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + psx93XX_t this = 0; + psx9325_t pDevice = 0; + psx9325_platform_data_t pplatData = 0; + int ret; + struct input_dev *input_top = NULL; + struct input_dev *input_bottom = NULL; + struct power_supply *psy = NULL; + + LOG_INFO("sx9325_probe()\n"); + + /* detect if sx9325 exist or not */ + if (sx9325_detect(client) == 0) + return -ENODEV; + + pplatData = kzalloc(sizeof(pplatData), GFP_KERNEL); + sx9325_platform_data_of_init(client, pplatData); + client->dev.platform_data = pplatData; + + if (!pplatData) { + LOG_ERR("platform data is required!\n"); + return -EINVAL; + } + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_WORD_DATA)) + return -EIO; + + /* create memory for main struct */ + this = kzalloc(sizeof(sx93XX_t), GFP_KERNEL); + LOG_INFO("\t Initialized Main Memory: 0x%p\n", this); + + if (this) { + /* 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 = gpio_to_irq(client->irq); + /* do we need to create an irq timer after interrupt ? */ + this->useIrqTimer = 0; + this->board = pplatData; + /* Setup function to call on corresponding reg irq source bit */ + if (MAX_NUM_STATUS_BITS >= 8) { + this->statusFunc[0] = 0; /* TXEN_STAT */ + this->statusFunc[1] = 0; /* UNUSED */ + this->statusFunc[2] = touchProcess; /* BODY/TABLE */ + this->statusFunc[3] = read_rawData; /* CONV_STAT */ + this->statusFunc[4] = 0; /* COMP_STAT */ + this->statusFunc[5] = touchProcess; /* RELEASE_STAT */ + this->statusFunc[6] = touchProcess; /* TOUCH_STAT */ + this->statusFunc[7] = 0; /* RESET_STAT */ + } + + /* setup i2c communication */ + this->bus = client; + i2c_set_clientdata(client, this); + + /* record device struct */ + this->pdev = &client->dev; + + /* create memory for device specific struct */ + this->pDevice = pDevice = kzalloc(sizeof(sx9325_t), GFP_KERNEL); + LOG_INFO("\t Initialized Device Specific Memory: 0x%p\n", + pDevice); + sx9325_sar_ptr = this; + if (pDevice) { + /* for accessing items in user data (e.g. calibrate) */ + ret = sysfs_create_group(&client->dev.kobj, + &sx9325_attr_group); + + + /* Check if we hava a platform + * initialization function to call*/ + if (pplatData->init_platform_hw) + pplatData->init_platform_hw(); + + /* Add Pointer to main platform data struct */ + pDevice->hw = pplatData; + + /* Initialize the button information + * initialized with keycodes */ + pDevice->pbuttonInformation = + pplatData->pbuttonInformation; + + /* Create the input device */ + input_top = input_allocate_device(); + if (!input_top) + return -ENOMEM; + + /* Set all the keycodes */ + __set_bit(EV_ABS, input_top->evbit); + input_set_abs_params(input_top, ABS_DISTANCE, + -1, 100, 0, 0); + /* save the input pointer and finish initialization */ + pDevice->pbuttonInformation->input_top = + input_top; + input_top->name = "SX9325 Cap Touch top"; + if (input_register_device(input_top)) { + LOG_ERR("add top cap touch unsuccess\n"); + return -ENOMEM; + } + /* Create the input device */ + input_bottom = input_allocate_device(); + if (!input_bottom) + return -ENOMEM; + /* Set all the keycodes */ + __set_bit(EV_ABS, input_bottom->evbit); + input_set_abs_params(input_bottom, ABS_DISTANCE, + -1, 100, 0, 0); + /* save the input pointer and finish initialization */ + pDevice->pbuttonInformation->input_bottom = + input_bottom; + /* save the input pointer and finish initialization */ + input_bottom->name = "SX9325 Cap Touch bottom"; + if (input_register_device(input_bottom)) { + LOG_ERR("add bottom cap touch unsuccess\n"); + return -ENOMEM; + } + } + + ret = class_register(&capsense_class); + if (ret < 0) { + LOG_ERR("Create fsys class failed (%d)\n", ret); + return ret; + } + + ret = class_create_file(&capsense_class, &class_attr_reset); + if (ret < 0) { + LOG_ERR("Create reset file failed (%d)\n", ret); + return ret; + } + + ret = class_create_file(&capsense_class, &class_attr_enable); + if (ret < 0) { + LOG_ERR("Create enable file failed (%d)\n", ret); + return ret; + } + + ret = class_create_file(&capsense_class, &class_attr_reg); + if (ret < 0) { + LOG_ERR("Create reg file failed (%d)\n", ret); + return ret; + } + +#ifdef USE_SENSORS_CLASS + sensors_capsensor_top_cdev.sensors_enable = + capsensor_set_enable; + sensors_capsensor_top_cdev.sensors_poll_delay = NULL; + ret = sensors_classdev_register(&input_top->dev, + &sensors_capsensor_top_cdev); + if (ret < 0) + LOG_ERR("create top cap sensor_class file \ + failed (%d)\n", ret); + sensors_capsensor_bottom_cdev.sensors_enable = + capsensor_set_enable; + sensors_capsensor_bottom_cdev.sensors_poll_delay = NULL; + ret = sensors_classdev_register(&input_bottom->dev, + &sensors_capsensor_bottom_cdev); + if (ret < 0) + LOG_ERR("create bottom cap sensor_class file \ + failed (%d)\n", ret); +#endif + 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; + } + LOG_ERR("%s: Failed to get regulator\n", + __func__); + } else { + int error = regulator_enable(pplatData->cap_vdd); + + if (error) { + regulator_put(pplatData->cap_vdd); + LOG_ERR("%s: Error %d enable regulator\n", + __func__, error); + return error; + } + pplatData->cap_vdd_en = true; + LOG_INFO("cap_vdd regulator is %s\n", + regulator_is_enabled(pplatData->cap_vdd) ? + "on" : "off"); + } +#if 0 + pplatData->cap_svdd = regulator_get(&client->dev, "cap_svdd"); + if (!IS_ERR(pplatData->cap_svdd)) { + ret = regulator_enable(pplatData->cap_svdd); + if (ret) { + regulator_put(pplatData->cap_svdd); + LOG_ERR("Failed to enable cap_svdd\n"); + goto err_svdd_error; + } + pplatData->cap_svdd_en = true; + LOG_INFO("cap_svdd regulator is %s\n", + regulator_is_enabled(pplatData->cap_svdd) ? + "on" : "off"); + } else { + ret = PTR_ERR(pplatData->cap_vdd); + if (ret == -EPROBE_DEFER) + goto err_svdd_error; + } +#endif + sx93XX_sar_init(this); + + write_register(this, SX932x_CTRL1_REG, 0x10); + write_register(this, SX932x_IRQ_ENABLE_REG, 0x00); + mEnabled = 0; + + INIT_WORK(&this->ps_notify_work, ps_notify_callback_work); + this->ps_notif.notifier_call = ps_notify_callback; + ret = power_supply_reg_notifier(&this->ps_notif); + if (ret) { + LOG_ERR( + "Unable to register ps_notifier: %d\n", ret); + goto free_ps_notifier; + } + + psy = power_supply_get_by_name("usb"); + if (psy) { + ret = ps_get_state(psy, &this->ps_is_present); + if (ret) { + LOG_ERR( + "psy get property failed rc=%d\n", + ret); + goto free_ps_notifier; + } + } + +#if defined(CONFIG_FB) + INIT_WORK(&this->fb_notify_work, fb_notify_resume_work); + this->fb_notif.notifier_call = fb_notifier_callback; + ret = fb_register_client(&this->fb_notif); + if (ret) { + LOG_ERR("Unable to register fb_notifier: %d\n", ret); + goto free_fb_notifier; + } +#endif + return 0; + } + return -ENOMEM; + +free_fb_notifier: + power_supply_unreg_notifier(&this->ps_notif); + +free_ps_notifier: + LOG_ERR("%s free ps notifier:.\n", __func__); + regulator_disable(pplatData->cap_svdd); + regulator_put(pplatData->cap_svdd); +#if 0 +err_svdd_error: + LOG_ERR("%s svdd defer.\n", __func__); + regulator_disable(pplatData->cap_vdd); + regulator_put(pplatData->cap_vdd); +#endif +err_vdd_defer: + LOG_ERR("%s input free device.\n", __func__); + input_free_device(input_top); + input_free_device(input_bottom); + + return ret; +} + +/** + * fn static int sx9325_remove(struct i2c_client *client) + * brief Called when device is to be removed + * param client Pointer to i2c_client struct + * return Value from sx93XX_sar_remove() + */ +static int sx9325_remove(struct i2c_client *client) +{ + psx9325_platform_data_t pplatData = 0; + psx9325_t pDevice = 0; + psx93XX_t this = i2c_get_clientdata(client); + + pDevice = this->pDevice; + if (this && pDevice) { +#if defined(CONFIG_FB) + fb_unregister_client(&this->fb_notif); +#endif + power_supply_unreg_notifier(&this->ps_notif); + +#ifdef USE_SENSORS_CLASS + sensors_classdev_unregister(&sensors_capsensor_top_cdev); + sensors_classdev_unregister(&sensors_capsensor_bottom_cdev); +#endif + input_unregister_device(pDevice->pbuttonInformation->input_top); + input_unregister_device( + pDevice->pbuttonInformation->input_bottom); + + if (this->board->cap_svdd_en) { + regulator_disable(this->board->cap_svdd); + regulator_put(this->board->cap_svdd); + } + + if (this->board->cap_vdd_en) { + regulator_disable(this->board->cap_vdd); + regulator_put(this->board->cap_vdd); + } +#ifdef USE_SENSORS_CLASS + sensors_classdev_unregister(&sensors_capsensor_top_cdev); + sensors_classdev_unregister(&sensors_capsensor_bottom_cdev); +#endif + sysfs_remove_group(&client->dev.kobj, &sx9325_attr_group); + pplatData = client->dev.platform_data; + if (pplatData && pplatData->exit_platform_hw) + pplatData->exit_platform_hw(); + kfree(this->pDevice); + } + return sx93XX_sar_remove(this); +} + +#if defined(USE_KERNEL_SUSPEND) +/*====================================================*/ +/***** Kernel Suspend *****/ +static int sx9325_suspend(struct device *dev, pm_message_t mesg) +{ + psx93XX_t this = dev_get_drvdata(dev); + + sx9325_irq_disable(this); + return 0; +} +/***** Kernel Resume *****/ +static int sx9325_resume(struct device *dev) +{ + psx93XX_t this = dev_get_drvdata(dev); + + sx9325_irq_enable(this); + return 0; +} +/*====================================================*/ +#endif + +#ifdef CONFIG_OF +static const struct of_device_id sx9325_match_tbl[] = { + { .compatible = "semtech,sx9325" ,}, + { }, +}; +#endif + +static struct i2c_device_id sx9325_idtable[] = { + { DRIVER_NAME, 0 }, + { } +}; + +static struct i2c_driver sx9325_driver = { + + .probe = sx9325_probe, + .remove = sx9325_remove, + .id_table = sx9325_idtable, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, +#if defined(USE_KERNEL_SUSPEND) + .suspend = sx9325_suspend, + .resume = sx9325_resume, +#endif +#ifdef CONFIG_OF + .of_match_table = sx9325_match_tbl, +#endif + }, + +}; + +static int __init sx9325_init(void) +{ + int ret = 0; + ret = i2c_add_driver(&sx9325_driver); + if (ret) { + LOG_ERR("%s: failed to add i2c driver", __func__); + goto err_driver; + } + + LOG_DBG("%s: finished\n", __func__); + +err_driver: + return ret; +} +static void __exit sx9325_exit(void) +{ + i2c_del_driver(&sx9325_driver); +} + +#ifdef USE_THREADED_IRQ +static void sx93XX_process_interrupt(psx93XX_t this, u8 nirqlow) +{ + int status = 0; + int counter = 0; + + if (!this) { + LOG_ERR("sx93XX_worker_func, NULL sx93XX_t\n"); + return; + } + /* since we are not in an interrupt don't need to disable irq. */ + status = this->refreshStatus(this); + counter = -1; + if (sx9325_debug_enable) + LOG_DBG("Worker - Refresh Status %d\n", status); + + while ((++counter) < MAX_NUM_STATUS_BITS) { /* counter start from MSB */ + if (((status >> counter) & 0x01) + && (this->statusFunc[counter])) { + if (sx9325_debug_enable) + LOG_DBG("Function %d Pointer Found. Calling\n" + ,counter); + this->statusFunc[counter](this); + } + } + if (unlikely(this->useIrqTimer && nirqlow)) { + /* In case we need to send a timer for example on a touchscreen + * checking penup, perform this here + */ + cancel_delayed_work(&this->dworker); + schedule_delayed_work(&this->dworker, + msecs_to_jiffies(this->irqTimeout)); + LOG_INFO("Schedule Irq timer"); + } +} + + +static void sx93XX_worker_func(struct work_struct *work) +{ + psx93XX_t this = 0; + + if (work) { + this = container_of(work, sx93XX_t, dworker.work); + if (!this) { + LOG_ERR("sx93XX_worker_func, NULL sx93XX_t\n"); + return; + } + if ((!this->get_nirq_low) + || (!this->get_nirq_low(this->board->irq_gpio))) { + /* only run if nirq is high */ + sx93XX_process_interrupt(this, 0); + } + } else { + LOG_ERR("sx93XX_worker_func, NULL work_struct\n"); + } +} +static irqreturn_t sx93XX_interrupt_thread(int irq, void *data) +{ + psx93XX_t this = 0; + + this = data; + + mutex_lock(&this->mutex); + if (sx9325_debug_enable) + LOG_DBG("sx93XX_irq\n"); + if ((!this->get_nirq_low) || this->get_nirq_low(this->board->irq_gpio)) + sx93XX_process_interrupt(this, 1); + else { + if (sx9325_debug_enable) + LOG_DBG("sx93XX_irq - nirq read high\n"); + } + mutex_unlock(&this->mutex); + return IRQ_HANDLED; +} +#else +static void sx93XX_schedule_work(psx93XX_t this, unsigned long delay) +{ + unsigned long flags; + + if (this) { + LOG_INFO("sx93XX_schedule_work()\n"); + spin_lock_irqsave(&this->lock, flags); + /* Stop any pending penup queues */ + cancel_delayed_work(&this->dworker); + /* + * after waiting for a delay, this put the job + * in the kernel-global workqueue. + * so no need to create new thread in work queue. + */ + schedule_delayed_work(&this->dworker, delay); + spin_unlock_irqrestore(&this->lock, flags); + } else + LOG_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 (sx9325_debug_enable) + LOG_DBG("sx93XX_irq\n"); + if ((!this->get_nirq_low) + || this->get_nirq_low(this->board->irq_gpio)) { + if (sx9325_debug_enable) + LOG_DBG("sx93XX_irq - Schedule Work\n"); + sx93XX_schedule_work(this, 0); + } else { + if (sx9325_debug_enable) + LOG_DBG("sx93XX_irq - nirq read high\n"); + } + } else + LOG_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) { + LOG_ERR("sx93XX_worker_func, NULL sx93XX_t\n"); + return; + } + if (unlikely(this->useIrqTimer)) { + if ((!this->get_nirq_low) + || this->get_nirq_low(this->board->irq_gpio)) + nirqLow = 1; + } + /* since we are not in an interrupt + * don't need to disable irq. */ + status = this->refreshStatus(this); + counter = -1; + if (sx9325_debug_enable) + LOG_DBG("Worker - Refresh Status %d\n", status); + /* counter start from MSB */ + while ((++counter) < MAX_NUM_STATUS_BITS) { + if (((status >> counter) & 0x01) + && (this->statusFunc[counter])) { + LOG_INFO("Function %d Pointer Found. Calling\n" + ,counter); + this->statusFunc[counter](this); + } + } + if (unlikely(this->useIrqTimer && nirqLow)) { + /* Early models and if RATE=0 for newer models + * require a penup timer; + * Queue up the function again for checking on penup */ + sx93XX_schedule_work(this, + msecs_to_jiffies(this->irqTimeout)); + } + } else { + LOG_ERR("sx93XX_worker_func, NULL work_struct\n"); + } +} +#endif + +void sx9325_irq_disable(psx93XX_t this) +{ + if (this) { + write_register(this, SX932x_CTRL1_REG, + this->board->cust_prox_ctrl0&0xdf); + if (sx9325_debug_enable) + LOG_INFO("sx9325 suspend: disable irq!\n"); + disable_irq(this->irq); + } +} +void sx9325_irq_enable(psx93XX_t this) +{ + if (this) { + if (sx9325_debug_enable) + LOG_INFO("sx9325 resume: enable irq!\n"); +#ifdef USE_THREADED_IRQ + mutex_lock(&this->mutex); + /* Just in case need to reset any uncaught interrupts */ + sx93XX_process_interrupt(this, 0); + mutex_unlock(&this->mutex); +#else + sx93XX_schedule_work(this, 0); +#endif + enable_irq(this->irq); + write_register(this, SX932x_CTRL1_REG, + this->board->cust_prox_ctrl0|0x20); + LOG_INFO("sx9325 resume: end!\n"); + } +} + +int sx93XX_sar_init(psx93XX_t this) +{ + int err = 0; + + if (this && this->pDevice) { +#ifdef USE_THREADED_IRQ + + /* initialize worker function */ + INIT_DELAYED_WORK(&this->dworker, sx93XX_worker_func); + + + /* initialize mutex */ + mutex_init(&this->mutex); + /* initailize interrupt reporting */ + this->irq_disabled = 0; + err = request_threaded_irq(this->irq, NULL, + sx93XX_interrupt_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + this->pdev->driver->name, + this); +#else + /* 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); +#endif + if (err) { + LOG_ERR("irq %d busy?\n", this->irq); + return err; + } +#ifdef USE_THREADED_IRQ + LOG_INFO("registered with threaded irq (%d)\n", this->irq); +#else + LOG_INFO("registered with irq (%d)\n", this->irq); +#endif + /* call init function pointer: + * this should initialize all registers */ + if (this->init) + return this->init(this); + LOG_ERR("No init function!!!!\n"); + } + return -ENOMEM; +} + +int sx93XX_sar_remove(psx93XX_t this) +{ + if (this) { + /* Cancel the Worker Func */ + cancel_delayed_work_sync(&this->dworker); + free_irq(this->irq, this); + kfree(this); + return 0; + } + return -ENOMEM; +} +module_init(sx9325_init); +module_exit(sx9325_exit); + +MODULE_AUTHOR("Semtech Corp. (http://www.semtech.com/)"); +MODULE_DESCRIPTION("SX9325 Capacitive Touch Controller Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.1"); diff --git a/drivers/input/misc/sx9325_sar.h b/drivers/input/misc/sx9325_sar.h new file mode 100755 index 000000000000..d8d351dbb0e5 --- /dev/null +++ b/drivers/input/misc/sx9325_sar.h @@ -0,0 +1,571 @@ +/* + * 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 SX9325_TRIPLE_H +#define SX9325_TRIPLE_H + +#include +#include +#include +#include +#include +/* + * I2C Registers + */ + +#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 +#define SX932x_REV_VALUE 0x22 + + +/* CpsStat */ +#define SX932x_TCHCMPSTAT_TCHCOMB_FLAG 0x88 +/* enable body stat */ +#define SX932x_TCHCMPSTAT_TCHSTAT2_FLAG 0x44 +/* enable body stat */ +#define SX932x_TCHCMPSTAT_TCHSTAT1_FLAG 0x22 +/* enable body stat */ +#define SX932x_TCHCMPSTAT_TCHSTAT0_FLAG 0x11 + + + +/* useful channel number */ +#define USE_CHANNEL_NUM 3 + +/* default settings */ +/* Channel enable: CS0:1,CS1:2,CS2:4,COMB:8 + * Defines the Active scan period : + * 0000: Min (no idle time) + * 0001: 15ms + * 0010: 30 ms (Typ.) + * 0011: 45 ms + * 0100: 60 ms + * 0101: 90 ms + * 0110: 120 ms + * 0111: 200 ms + * 1000: 400 ms + * 1001: 600 ms + * 1010: 800 ms + * 1011: 1 s + * 1100: 2 s + * 1101: 3 s + * 1110: 4 s + * 1111: 5 s + */ +#define DUMMY_USE_CHANNEL 0x1 +#define DUMMY_SCAN_PERIOD 0x2 +#define DUMMY_RAW_DATA_CHANNEL 0x00 + +/* Cap sensor report key, including cs0, cs1, cs2 and comb */ +#define KEY_CAP_CS0 0x270 +#define KEY_CAP_CS1 0x271 +#define KEY_CAP_CS2 0x272 +#define KEY_CAP_COMB 0x272 + +/************************************** +* 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_top; + struct input_dev *input_bottom; +}; + +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 sx9325_i2c_reg_setup[] = { +/*Interrupt and config*/ + { + .reg = SX932x_IRQ_ENABLE_REG, //0x05 + .val = 0x64, // 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 = 0x09, // 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,//0x04, // CS2:HZ CS1:Input CS0 :HZ + }, + { + .reg = SX932x_AFE_PH1_REG, //0x29 + .val = 0x04,//0x10, // CS2:Input CS1:HZ Shield CS0 :HZ + }, + { + .reg = SX932x_AFE_PH2_REG, //0x2A + .val = 0x10,//0x1B, //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 = 0x13, // Digital Gain(ph0/1) : off(001) Digital Filter(ph0/1) : 1-1/2(001) + }, + { + .reg = SX932x_PROX_CTRL1_REG, //0x31 + .val = 0x0a, // 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 = 0x0a, //AVGFREEZEDIS : on(0) ,AVGNEGFILT :1-1/2(001) ,AVGPOSFILT : 1-1/256(100) + }, + { + .reg = SX932x_PROX_CTRL5_REG, //0x35 + .val = 0x0a, //FARCOND: PROXDIFF < (THRESH.HYST), HYST : None, CLOSEDEB : off ,FARDEB : off + }, + { + .reg = SX932x_PROX_CTRL6_REG, //0x36 + .val = 0x1e, // Prox Theshold(ph0/1) : 200 + }, + { + .reg = SX932x_PROX_CTRL7_REG, //0x37 + .val = 0x15, // 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 = 0x18,//0x10, + }, + { + .reg = SX932x_ADV_CTRL3_REG, + .val = 0x2a, + }, + { + .reg = SX932x_ADV_CTRL4_REG, + .val = 0x02, + }, + { + .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 = 0x11, + }, + { + .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 = 0x00, + }, + { + .reg = SX932x_ADV_CTRL18_REG, + .val = 0x00, + }, + { + .reg = SX932x_ADV_CTRL19_REG, + .val = 0xF0, + }, + { + .reg = SX932x_ADV_CTRL20_REG, + .val = 0xF0, + }, + /*Sensor enable*/ + { + .reg = SX932x_CTRL1_REG, //0x11 + .val = 0x24, //enable PH2 + }, +}; + + + + +static struct _buttonInfo psmtcButtons[] = { + { + .keycode = KEY_CAP_CS0, + .mask = SX932x_TCHCMPSTAT_TCHSTAT0_FLAG, + }, + { + .keycode = KEY_CAP_CS1, + .mask = SX932x_TCHCMPSTAT_TCHSTAT1_FLAG, + }, + { + .keycode = KEY_CAP_CS2, + .mask = SX932x_TCHCMPSTAT_TCHSTAT2_FLAG, + }, + { + .keycode = KEY_CAP_COMB, + .mask = SX932x_TCHCMPSTAT_TCHCOMB_FLAG, + }, +}; + +struct sx9325_platform_data { + int i2c_reg_num; + struct smtc_reg_data *pi2c_reg; + struct regulator *cap_vdd; + struct regulator *cap_svdd; + bool cap_vdd_en; + bool cap_svdd_en; + unsigned irq_gpio; + /* used for custom setting for channel and scan period */ + u32 cust_prox_ctrl0; + u32 cust_raw_data_channel; + int cap_channel_top; + int cap_channel_bottom; + pbuttonInformation_t pbuttonInformation; + + int (*get_is_nirq_low)(unsigned irq_gpio); + int (*init_platform_hw)(void); + void (*exit_platform_hw)(void); +}; +typedef struct sx9325_platform_data sx9325_platform_data_t; +typedef struct sx9325_platform_data *psx9325_platform_data_t; + +#ifdef USE_SENSORS_CLASS +static struct sensors_classdev sensors_capsensor_top_cdev = { + .name = "capsense_top", + .vendor = "semtech", + .version = 1, + .type = SENSOR_TYPE_MOTO_CAPSENSE, + .max_range = "5", + .resolution = "5.0", + .sensor_power = "3", + .min_delay = 0, /* in microseconds */ + .fifo_reserved_event_count = 0, + .fifo_max_event_count = 0, + .enabled = 0, + .delay_msec = 100, + .sensors_enable = NULL, + .sensors_poll_delay = NULL, +}; +static struct sensors_classdev sensors_capsensor_bottom_cdev = { + .name = "capsense_bottom", + .vendor = "semtech", + .version = 1, + .type = SENSOR_TYPE_MOTO_CAPSENSE, + .max_range = "5", + .resolution = "5.0", + .sensor_power = "3", + .min_delay = 0, /* in microseconds */ + .fifo_reserved_event_count = 0, + .fifo_max_event_count = 0, + .enabled = 0, + .delay_msec = 100, + .sensors_enable = NULL, + .sensors_poll_delay = NULL, +}; +#endif +/*************************************** +* define data struct/interrupt +* @pdev: pdev common device struction for linux +* @dworker: work struct for worker function +* @board: constant pointer to platform data +* @mutex: mutex for interrupt process +* @lock: Spin Lock used for nirq worker function +* @bus: either i2c_client or spi_client +* @pDevice: device specific struct pointer +*@read_flag : used for dump specified register +* @irq: irq number used +* @irqTimeout: msecs only set if useIrqTimer is true +* @irq_disabled: whether irq should be ignored +* @irq_gpio: irq gpio number +* @useIrqTimer: older models need irq timer for pen up cases +* @read_reg: record reg address which want to read +*@cust_prox_ctrl0 : used for custom setting for channel and scan period +* @init: (re)initialize device +* @refreshStatus: read register status +* @get_nirq_low: get whether nirq is low (platform data) +* @statusFunc: array of functions to call for corresponding status bit +***************************************/ +#define USE_THREADED_IRQ + +#define MAX_NUM_STATUS_BITS (8) + +typedef struct sx93XX sx93XX_t, *psx93XX_t; +struct sx93XX { + struct device *pdev; + struct delayed_work dworker; + struct sx9325_platform_data *board; +#if defined(USE_THREADED_IRQ) + struct mutex mutex; +#else + spinlock_t lock; +#endif + void *bus; + void *pDevice; + int read_flag; + int irq; + int irqTimeout; + char irq_disabled; + /* whether irq should be ignored.. + * cases if enable/disable irq is not used + * or does not work properly */ + u8 useIrqTimer; + u8 read_reg; + + struct work_struct ps_notify_work; + struct notifier_block ps_notif; + bool ps_is_present; + +#if defined(CONFIG_FB) + struct work_struct fb_notify_work; + struct notifier_block fb_notif; +#endif + + /* Function Pointers */ + int (*init)(psx93XX_t this); + /* 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); + int (*get_nirq_low)(unsigned irq_gpio); + + void (*statusFunc[MAX_NUM_STATUS_BITS])(psx93XX_t this); + +}; + +void sx9325_irq_disable(psx93XX_t this); +void sx9325_irq_enable(psx93XX_t this); +int sx93XX_sar_init(psx93XX_t this); +int sx93XX_sar_remove(psx93XX_t this); + +#endif diff --git a/drivers/input/misc/sx932x.c b/drivers/input/misc/sx932x.c deleted file mode 100755 index ea499002dd8d..000000000000 --- a/drivers/input/misc/sx932x.c +++ /dev/null @@ -1,971 +0,0 @@ -/*! \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; - 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; - 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 deleted file mode 100755 index 759d09b15d3c..000000000000 --- a/drivers/input/misc/sx932x.h +++ /dev/null @@ -1,461 +0,0 @@ -/* -* 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 diff --git a/include/linux/sensors.h b/include/linux/sensors.h index c20e876efe12..5666bee68d55 100755 --- a/include/linux/sensors.h +++ b/include/linux/sensors.h @@ -51,6 +51,7 @@ #define SENSOR_TYPE_DEVICE_PRIVATE_BASE 0x10000 #define SENSOR_TYPE_CAP_PROX (SENSOR_TYPE_DEVICE_PRIVATE_BASE + 2) +#define SENSOR_TYPE_MOTO_CAPSENSE (SENSOR_TYPE_DEVICE_PRIVATE_BASE + 16) enum LIS3DH_AXIS { AXIS_X = 0,