Merge "input: touchscreen: add touch to wake feature in ITEtech driver"
This commit is contained in:
commit
8560f5d5ea
3 changed files with 416 additions and 71 deletions
|
@ -0,0 +1,39 @@
|
|||
ITE Tech. touch controller
|
||||
|
||||
The ITE Tech. touch controller is connected to host processor
|
||||
via i2c. The controller generates interrupts when the user
|
||||
touches the panel. The host controller is expected to read
|
||||
the touch coordinates over i2c and pass the coordinates to
|
||||
the rest of the system.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : should be "ite,it7260_ts"
|
||||
- reg : i2c slave address of the device
|
||||
- interrupt-parent : parent of interrupt
|
||||
- interrupts : touch sample interrupt to indicate presence or release
|
||||
of fingers on the panel.
|
||||
- ite,irq-gpio : irq gpio which is to provide interrupts to host,
|
||||
same as "interrupts" node. It will also
|
||||
contain active low or active high information.
|
||||
- ite,reset-gpio : reset gpio to control the reset of chip
|
||||
|
||||
Optional properties:
|
||||
- avdd-supply : Analog power supply needed to power device
|
||||
- vdd-supply : Power source required to pull up i2c bus
|
||||
- ite,wakeup : boolean, use this to support touch-to-wake feature.
|
||||
|
||||
Example:
|
||||
i2c@f9927000 {
|
||||
it7260@46 {
|
||||
compatible = "ite,it7260_ts";
|
||||
reg = <0x46>;
|
||||
interrupt-parent = <&msmgpio>;
|
||||
interrupts = <17 0x2>;
|
||||
avdd-supply = <&pm8226_l19>;
|
||||
vdd-supply = <&pm8226_lvs1>;
|
||||
ite,reset-gpio = <&msmgpio 16 0x00>;
|
||||
ite,irq-gpio = <&msmgpio 17 0x2008>;
|
||||
ite,wakeup;
|
||||
};
|
||||
};
|
|
@ -120,6 +120,7 @@ intercontrol Inter Control Group
|
|||
invensense InvenSense Inc.
|
||||
isee ISEE 2007 S.L.
|
||||
isil Intersil
|
||||
ite ITE Tech. Inc.
|
||||
jedec JEDEC Solid State Technology Association
|
||||
karo Ka-Ro electronics GmbH
|
||||
keymile Keymile GmbH
|
||||
|
|
|
@ -22,12 +22,16 @@
|
|||
#include <linux/firmware.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/wakelock.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#define MAX_BUFFER_SIZE 144
|
||||
#define DEVICE_NAME "IT7260"
|
||||
#define SCREEN_X_RESOLUTION 320
|
||||
#define SCREEN_Y_RESOLUTION 320
|
||||
#define DEBUGFS_DIR_NAME "ts_debug"
|
||||
|
||||
/* all commands writes go to this idx */
|
||||
#define BUF_COMMAND 0x20
|
||||
|
@ -98,6 +102,11 @@
|
|||
/* use this to include integers in commands */
|
||||
#define CMD_UINT16(v) ((uint8_t)(v)) , ((uint8_t)((v) >> 8))
|
||||
|
||||
/* Function declarations */
|
||||
static int fb_notifier_callback(struct notifier_block *self,
|
||||
unsigned long event, void *data);
|
||||
static int IT7260_ts_resume(struct device *dev);
|
||||
static int IT7260_ts_suspend(struct device *dev);
|
||||
|
||||
struct FingerData {
|
||||
uint8_t xLo;
|
||||
|
@ -128,24 +137,65 @@ struct PointData {
|
|||
#define FD_PRESSURE_HIGH 0x08
|
||||
#define FD_PRESSURE_HEAVY 0x0F
|
||||
|
||||
#define IT_VTG_MIN_UV 1800000
|
||||
#define IT_VTG_MAX_UV 1800000
|
||||
#define IT_I2C_VTG_MIN_UV 2600000
|
||||
#define IT_I2C_VTG_MAX_UV 3300000
|
||||
|
||||
struct IT7260_ts_platform_data {
|
||||
u32 irqflags;
|
||||
u32 irq_gpio;
|
||||
u32 irq_gpio_flags;
|
||||
u32 reset_gpio;
|
||||
u32 reset_gpio_flags;
|
||||
bool wakeup;
|
||||
};
|
||||
|
||||
struct IT7260_ts_data {
|
||||
struct i2c_client *client;
|
||||
struct input_dev *input_dev;
|
||||
const struct IT7260_ts_platform_data *pdata;
|
||||
struct regulator *vdd;
|
||||
struct regulator *avdd;
|
||||
bool device_needs_wakeup;
|
||||
bool suspended;
|
||||
struct work_struct work_pm_relax;
|
||||
#ifdef CONFIG_FB
|
||||
struct notifier_block fb_notif;
|
||||
#endif
|
||||
struct dentry *dir;
|
||||
};
|
||||
|
||||
static int8_t fwUploadResult;
|
||||
static int8_t calibrationWasSuccessful;
|
||||
static bool devicePresent;
|
||||
static DEFINE_MUTEX(sleepModeMutex);
|
||||
static bool chipAwake;
|
||||
static bool hadFingerDown;
|
||||
static bool isDeviceSuspend;
|
||||
static struct input_dev *input_dev;
|
||||
static struct IT7260_ts_data *gl_ts;
|
||||
|
||||
#define LOGE(...) pr_err(DEVICE_NAME ": " __VA_ARGS__)
|
||||
#define LOGI(...) printk(DEVICE_NAME ": " __VA_ARGS__)
|
||||
|
||||
static int IT7260_debug_suspend_set(void *_data, u64 val)
|
||||
{
|
||||
if (val)
|
||||
IT7260_ts_suspend(&gl_ts->client->dev);
|
||||
else
|
||||
IT7260_ts_resume(&gl_ts->client->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int IT7260_debug_suspend_get(void *_data, u64 *val)
|
||||
{
|
||||
*val = gl_ts->suspended;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SIMPLE_ATTRIBUTE(debug_suspend_fops, IT7260_debug_suspend_get,
|
||||
IT7260_debug_suspend_set, "%lld\n");
|
||||
|
||||
/* internal use func - does not make sure chip is ready before read */
|
||||
static bool i2cReadNoReadyCheck(uint8_t bufferIndex, uint8_t *dataBuffer,
|
||||
uint16_t dataLength)
|
||||
|
@ -397,6 +447,21 @@ static bool chipGetVersions(uint8_t *verFw, uint8_t *verCfg, bool logIt)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int IT7260_ts_chipLowPowerMode(bool low)
|
||||
{
|
||||
static const uint8_t cmdGoSleep[] = {CMD_PWR_CTL,
|
||||
0x00, PWR_CTL_SLEEP_MODE};
|
||||
uint8_t dummy;
|
||||
|
||||
if (low)
|
||||
i2cWriteNoReadyCheck(BUF_COMMAND, cmdGoSleep,
|
||||
sizeof(cmdGoSleep));
|
||||
else
|
||||
i2cReadNoReadyCheck(BUF_QUERY, &dummy, sizeof(dummy));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t sysfsUpgradeStore(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
|
@ -569,50 +634,39 @@ static ssize_t sysfsSleepShow(struct device *dev,
|
|||
* leaking a byte of kernel data (by claiming to return a byte but not
|
||||
* writing to buf. To fix this now we actually return the sleep status
|
||||
*/
|
||||
if (!mutex_lock_interruptible(&sleepModeMutex)) {
|
||||
*buf = chipAwake ? '1' : '0';
|
||||
mutex_unlock(&sleepModeMutex);
|
||||
return 1;
|
||||
} else {
|
||||
return -EINTR;
|
||||
}
|
||||
*buf = gl_ts->suspended ? '1' : '0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
static ssize_t sysfsSleepStore(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
static const uint8_t cmdGoSleep[] = {CMD_PWR_CTL,
|
||||
0x00, PWR_CTL_SLEEP_MODE};
|
||||
int goToSleepVal, ret;
|
||||
bool goToWake;
|
||||
uint8_t dummy;
|
||||
int go_to_sleep, ret;
|
||||
|
||||
ret = kstrtoint(buf, 10, &goToSleepVal);
|
||||
/* convert to bool of proper polarity */
|
||||
goToWake = !goToSleepVal;
|
||||
|
||||
if (!mutex_lock_interruptible(&sleepModeMutex)) {
|
||||
if ((chipAwake && goToWake) || (!chipAwake && !goToWake))
|
||||
LOGE("duplicate request to %s chip\n",
|
||||
goToWake ? "wake" : "sleep");
|
||||
else if (goToWake) {
|
||||
i2cReadNoReadyCheck(BUF_QUERY, &dummy, sizeof(dummy));
|
||||
enable_irq(gl_ts->client->irq);
|
||||
LOGI("touch is going to wake!\n");
|
||||
} else {
|
||||
disable_irq(gl_ts->client->irq);
|
||||
i2cWriteNoReadyCheck(BUF_COMMAND, cmdGoSleep,
|
||||
sizeof(cmdGoSleep));
|
||||
LOGI("touch is going to sleep...\n");
|
||||
}
|
||||
chipAwake = goToWake;
|
||||
mutex_unlock(&sleepModeMutex);
|
||||
return count;
|
||||
/* (gl_ts->suspended == true && goToSleepVal > 0) means
|
||||
* device is already suspended and you want it to be in sleep,
|
||||
* (gl_ts->suspended == false && goToSleepVal == 0) means
|
||||
* device is already active and you also want it to be active.
|
||||
*/
|
||||
if ((gl_ts->suspended && go_to_sleep > 0) ||
|
||||
(!gl_ts->suspended && go_to_sleep == 0))
|
||||
dev_err(dev, "duplicate request to %s chip\n",
|
||||
go_to_sleep ? "sleep" : "wake");
|
||||
else if (go_to_sleep) {
|
||||
disable_irq(gl_ts->client->irq);
|
||||
IT7260_ts_chipLowPowerMode(true);
|
||||
dev_dbg(dev, "touch is going to sleep...\n");
|
||||
} else {
|
||||
return -EINTR;
|
||||
IT7260_ts_chipLowPowerMode(false);
|
||||
enable_irq(gl_ts->client->irq);
|
||||
dev_dbg(dev, "touch is going to wake!\n");
|
||||
}
|
||||
}
|
||||
gl_ts->suspended = go_to_sleep;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(status, S_IRUGO|S_IWUSR|S_IWGRP,
|
||||
sysfsStatusShow, sysfsStatusStore);
|
||||
|
@ -667,6 +721,13 @@ void sendCalibrationCmd(void)
|
|||
}
|
||||
EXPORT_SYMBOL(sendCalibrationCmd);
|
||||
|
||||
static void IT7260_ts_release_all(void)
|
||||
{
|
||||
input_report_key(gl_ts->input_dev, BTN_TOUCH, 0);
|
||||
input_mt_sync(gl_ts->input_dev);
|
||||
input_sync(gl_ts->input_dev);
|
||||
}
|
||||
|
||||
static void readFingerData(uint16_t *xP, uint16_t *yP, uint8_t *pressureP,
|
||||
const struct FingerData *fd)
|
||||
{
|
||||
|
@ -684,60 +745,79 @@ static void readFingerData(uint16_t *xP, uint16_t *yP, uint8_t *pressureP,
|
|||
*pressureP = fd->pressure & FD_PRESSURE_BITS;
|
||||
}
|
||||
|
||||
static void readTouchDataPoint(void)
|
||||
static irqreturn_t IT7260_ts_threaded_handler(int irq, void *devid)
|
||||
{
|
||||
struct PointData pointData;
|
||||
uint8_t devStatus;
|
||||
uint8_t pressure = FD_PRESSURE_NONE;
|
||||
uint16_t x, y;
|
||||
|
||||
/* This code adds the touch-to-wake functioanlity to the ITE tech
|
||||
* driver. When the device is in suspend driver, it sends the
|
||||
* KEY_WAKEUP event to wake the device. The pm_stay_awake() call
|
||||
* tells the pm core to stay awake until the CPU cores up already. The
|
||||
* schedule_work() call schedule a work that tells the pm core to relax
|
||||
* once the CPU cores are up.
|
||||
*/
|
||||
if (gl_ts->device_needs_wakeup) {
|
||||
pm_stay_awake(&gl_ts->client->dev);
|
||||
gl_ts->device_needs_wakeup = false;
|
||||
input_report_key(gl_ts->input_dev, KEY_WAKEUP, 1);
|
||||
input_sync(gl_ts->input_dev);
|
||||
input_report_key(gl_ts->input_dev, KEY_WAKEUP, 0);
|
||||
input_sync(gl_ts->input_dev);
|
||||
schedule_work(&gl_ts->work_pm_relax);
|
||||
}
|
||||
|
||||
/* verify there is point data to read & it is readable and valid */
|
||||
i2cReadNoReadyCheck(BUF_QUERY, &devStatus, sizeof(devStatus));
|
||||
if (!((devStatus & PT_INFO_BITS) & PT_INFO_YES)) {
|
||||
pr_err("readTouchDataPoint() called when no data available (0x%02X)\n",
|
||||
devStatus);
|
||||
return;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
if (!i2cReadNoReadyCheck(BUF_POINT_INFO, (void *)&pointData,
|
||||
sizeof(pointData))) {
|
||||
pr_err("readTouchDataPoint() failed to read point data buffer\n");
|
||||
return;
|
||||
dev_err(&gl_ts->client->dev,
|
||||
"readTouchDataPoint() failed to read point data buffer\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
if ((pointData.flags & PD_FLAGS_DATA_TYPE_BITS) !=
|
||||
PD_FLAGS_DATA_TYPE_TOUCH) {
|
||||
pr_err("readTouchDataPoint() dropping non-point data of type 0x%02X\n",
|
||||
dev_err(&gl_ts->client->dev,
|
||||
"readTouchDataPoint() dropping non-point data of type 0x%02X\n",
|
||||
pointData.flags);
|
||||
return;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if ((pointData.flags & PD_FLAGS_HAVE_FINGERS) & 1)
|
||||
readFingerData(&x, &y, &pressure, pointData.fd);
|
||||
|
||||
if (pressure >= FD_PRESSURE_LIGHT) {
|
||||
|
||||
if (!hadFingerDown)
|
||||
hadFingerDown = true;
|
||||
|
||||
readFingerData(&x, &y, &pressure, pointData.fd);
|
||||
|
||||
input_report_abs(gl_ts->input_dev, ABS_X, x);
|
||||
input_report_abs(gl_ts->input_dev, ABS_Y, y);
|
||||
input_report_key(gl_ts->input_dev, BTN_TOUCH, 1);
|
||||
input_report_abs(gl_ts->input_dev, ABS_MT_POSITION_X, x);
|
||||
input_report_abs(gl_ts->input_dev, ABS_MT_POSITION_Y, y);
|
||||
input_mt_sync(gl_ts->input_dev);
|
||||
input_sync(gl_ts->input_dev);
|
||||
|
||||
|
||||
} else if (hadFingerDown) {
|
||||
hadFingerDown = false;
|
||||
|
||||
input_report_key(gl_ts->input_dev, BTN_TOUCH, 0);
|
||||
input_mt_sync(gl_ts->input_dev);
|
||||
input_sync(gl_ts->input_dev);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t IT7260_ts_threaded_handler(int irq, void *devid)
|
||||
static void IT7260_ts_work_func(struct work_struct *work)
|
||||
{
|
||||
readTouchDataPoint();
|
||||
return IRQ_HANDLED;
|
||||
pm_relax(&gl_ts->client->dev);
|
||||
}
|
||||
|
||||
static bool chipIdentifyIT7260(void)
|
||||
|
@ -782,9 +862,11 @@ static int IT7260_ts_probe(struct i2c_client *client,
|
|||
const struct i2c_device_id *id)
|
||||
{
|
||||
static const uint8_t cmdStart[] = {CMD_UNKNOWN_7};
|
||||
struct IT7260_i2c_platform_data *pdata;
|
||||
struct IT7260_ts_platform_data *pdata;
|
||||
uint8_t rsp[2];
|
||||
int ret = -1;
|
||||
int rc;
|
||||
struct dentry *temp;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
LOGE("need I2C_FUNC_I2C\n");
|
||||
|
@ -805,13 +887,100 @@ static int IT7260_ts_probe(struct i2c_client *client,
|
|||
|
||||
gl_ts->client = client;
|
||||
i2c_set_clientdata(client, gl_ts);
|
||||
pdata = client->dev.platform_data;
|
||||
|
||||
if (client->dev.platform_data == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
if (client->dev.of_node) {
|
||||
pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
} else
|
||||
pdata = client->dev.platform_data;
|
||||
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
|
||||
gl_ts->pdata = pdata;
|
||||
if (sysfs_create_group(&(client->dev.kobj), &it7260_attrstatus_group)) {
|
||||
dev_err(&client->dev, "failed to register sysfs #1\n");
|
||||
goto err_sysfs_grp_create_1;
|
||||
}
|
||||
|
||||
gl_ts->vdd = regulator_get(&gl_ts->client->dev, "vdd");
|
||||
if (IS_ERR(gl_ts->vdd)) {
|
||||
dev_err(&gl_ts->client->dev,
|
||||
"Regulator get failed vdd\n");
|
||||
gl_ts->vdd = NULL;
|
||||
} else {
|
||||
rc = regulator_set_voltage(gl_ts->vdd,
|
||||
IT_VTG_MIN_UV, IT_VTG_MAX_UV);
|
||||
if (rc)
|
||||
dev_err(&gl_ts->client->dev,
|
||||
"Regulator set_vtg failed vdd\n");
|
||||
}
|
||||
|
||||
gl_ts->avdd = regulator_get(&gl_ts->client->dev, "avdd");
|
||||
if (IS_ERR(gl_ts->avdd)) {
|
||||
dev_err(&gl_ts->client->dev,
|
||||
"Regulator get failed avdd\n");
|
||||
gl_ts->avdd = NULL;
|
||||
} else {
|
||||
rc = regulator_set_voltage(gl_ts->avdd, IT_I2C_VTG_MIN_UV,
|
||||
IT_I2C_VTG_MAX_UV);
|
||||
if (rc)
|
||||
dev_err(&gl_ts->client->dev,
|
||||
"Regulator get failed avdd\n");
|
||||
}
|
||||
|
||||
if (gl_ts->vdd) {
|
||||
rc = regulator_enable(gl_ts->vdd);
|
||||
if (rc) {
|
||||
dev_err(&gl_ts->client->dev,
|
||||
"Regulator vdd enable failed rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
if (gl_ts->avdd) {
|
||||
rc = regulator_enable(gl_ts->avdd);
|
||||
if (rc) {
|
||||
dev_err(&gl_ts->client->dev,
|
||||
"Regulator avdd enable failed rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/* reset gpio info */
|
||||
pdata->reset_gpio = of_get_named_gpio_flags(client->dev.of_node,
|
||||
"ite,reset-gpio", 0,
|
||||
&pdata->reset_gpio_flags);
|
||||
if (gpio_is_valid(pdata->reset_gpio)) {
|
||||
if (gpio_request(pdata->reset_gpio, "ite_reset_gpio"))
|
||||
dev_err(&gl_ts->client->dev,
|
||||
"gpio_request failed for reset GPIO\n");
|
||||
if (gpio_direction_output(pdata->reset_gpio, 0))
|
||||
dev_err(&gl_ts->client->dev,
|
||||
"gpio_direction_output for reset GPIO\n");
|
||||
dev_dbg(&gl_ts->client->dev, "Reset GPIO %d\n",
|
||||
pdata->reset_gpio);
|
||||
} else {
|
||||
return pdata->reset_gpio;
|
||||
}
|
||||
|
||||
/* irq gpio info */
|
||||
pdata->irq_gpio = of_get_named_gpio_flags(client->dev.of_node,
|
||||
"ite,irq-gpio", 0, &pdata->irq_gpio_flags);
|
||||
if (gpio_is_valid(pdata->irq_gpio)) {
|
||||
dev_dbg(&gl_ts->client->dev, "IRQ GPIO %d, IRQ # %d\n",
|
||||
pdata->irq_gpio, gpio_to_irq(pdata->irq_gpio));
|
||||
} else {
|
||||
return pdata->irq_gpio;
|
||||
}
|
||||
|
||||
pdata->wakeup = of_property_read_bool(client->dev.of_node,
|
||||
"ite,wakeup");
|
||||
|
||||
if (!chipIdentifyIT7260()) {
|
||||
LOGI("chipIdentifyIT7260 FAIL");
|
||||
goto err_ident_fail_or_input_alloc;
|
||||
|
@ -836,10 +1005,18 @@ static int IT7260_ts_probe(struct i2c_client *client,
|
|||
set_bit(INPUT_PROP_DIRECT,input_dev->propbit);
|
||||
set_bit(BTN_TOUCH, input_dev->keybit);
|
||||
set_bit(KEY_SLEEP,input_dev->keybit);
|
||||
set_bit(KEY_WAKEUP,input_dev->keybit);
|
||||
set_bit(KEY_POWER,input_dev->keybit);
|
||||
input_set_abs_params(input_dev, ABS_X, 0, SCREEN_X_RESOLUTION, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_Y, 0, SCREEN_Y_RESOLUTION, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
|
||||
SCREEN_X_RESOLUTION, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
|
||||
SCREEN_Y_RESOLUTION, 0, 0);
|
||||
input_set_drvdata(gl_ts->input_dev, gl_ts);
|
||||
|
||||
if (pdata->wakeup) {
|
||||
set_bit(KEY_WAKEUP, gl_ts->input_dev->keybit);
|
||||
INIT_WORK(&gl_ts->work_pm_relax, IT7260_ts_work_func);
|
||||
device_init_wakeup(&client->dev, pdata->wakeup);
|
||||
}
|
||||
|
||||
if (input_register_device(input_dev)) {
|
||||
LOGE("failed to register input device\n");
|
||||
|
@ -857,6 +1034,15 @@ static int IT7260_ts_probe(struct i2c_client *client,
|
|||
goto err_sysfs_grp_create_2;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_FB)
|
||||
gl_ts->fb_notif.notifier_call = fb_notifier_callback;
|
||||
|
||||
ret = fb_register_client(&gl_ts->fb_notif);
|
||||
if (ret)
|
||||
dev_err(&client->dev, "Unable to register fb_notifier: %d\n",
|
||||
ret);
|
||||
#endif
|
||||
|
||||
devicePresent = true;
|
||||
|
||||
i2cWriteNoReadyCheck(BUF_COMMAND, cmdStart, sizeof(cmdStart));
|
||||
|
@ -864,8 +1050,36 @@ static int IT7260_ts_probe(struct i2c_client *client,
|
|||
i2cReadNoReadyCheck(BUF_RESPONSE, rsp, sizeof(rsp));
|
||||
mdelay(10);
|
||||
|
||||
gl_ts->dir = debugfs_create_dir(DEBUGFS_DIR_NAME, NULL);
|
||||
if (gl_ts->dir == NULL || IS_ERR(gl_ts->dir)) {
|
||||
dev_err(&client->dev,
|
||||
"%s: Failed to create debugfs directory, rc = %ld\n",
|
||||
__func__, PTR_ERR(gl_ts->dir));
|
||||
ret = PTR_ERR(gl_ts->dir);
|
||||
goto err_create_debugfs_dir;
|
||||
}
|
||||
|
||||
temp = debugfs_create_file("suspend", S_IRUSR | S_IWUSR, gl_ts->dir,
|
||||
gl_ts, &debug_suspend_fops);
|
||||
if (temp == NULL || IS_ERR(temp)) {
|
||||
dev_err(&client->dev,
|
||||
"%s: Failed to create suspend debugfs file, rc = %ld\n",
|
||||
__func__, PTR_ERR(temp));
|
||||
ret = PTR_ERR(temp);
|
||||
goto err_create_debugfs_file;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_create_debugfs_file:
|
||||
debugfs_remove_recursive(gl_ts->dir);
|
||||
err_create_debugfs_dir:
|
||||
#if defined(CONFIG_FB)
|
||||
if (fb_unregister_client(&gl_ts->fb_notif))
|
||||
dev_err(&client->dev, "Error occurred while unregistering fb_notifier.\n");
|
||||
#endif
|
||||
sysfs_remove_group(&(client->dev.kobj), &it7260_attr_group);
|
||||
|
||||
err_sysfs_grp_create_2:
|
||||
free_irq(client->irq, gl_ts);
|
||||
|
||||
|
@ -874,6 +1088,10 @@ err_irq_reg:
|
|||
input_dev = NULL;
|
||||
|
||||
err_input_register:
|
||||
if (pdata->wakeup) {
|
||||
cancel_work_sync(&gl_ts->work_pm_relax);
|
||||
device_init_wakeup(&client->dev, false);
|
||||
}
|
||||
if (input_dev)
|
||||
input_free_device(input_dev);
|
||||
|
||||
|
@ -889,10 +1107,108 @@ err_out:
|
|||
|
||||
static int IT7260_ts_remove(struct i2c_client *client)
|
||||
{
|
||||
debugfs_remove_recursive(gl_ts->dir);
|
||||
#if defined(CONFIG_FB)
|
||||
if (fb_unregister_client(&gl_ts->fb_notif))
|
||||
dev_err(&client->dev, "Error occurred while unregistering fb_notifier.\n");
|
||||
#endif
|
||||
sysfs_remove_group(&(client->dev.kobj), &it7260_attr_group);
|
||||
if (gl_ts->pdata->wakeup) {
|
||||
cancel_work_sync(&gl_ts->work_pm_relax);
|
||||
device_init_wakeup(&client->dev, false);
|
||||
}
|
||||
devicePresent = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_FB)
|
||||
static int fb_notifier_callback(struct notifier_block *self,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
struct fb_event *evdata = data;
|
||||
int *blank;
|
||||
|
||||
if (evdata && evdata->data && gl_ts && gl_ts->client) {
|
||||
if (event == FB_EVENT_BLANK) {
|
||||
blank = evdata->data;
|
||||
if (*blank == FB_BLANK_UNBLANK)
|
||||
IT7260_ts_resume(&(gl_ts->client->dev));
|
||||
else if (*blank == FB_BLANK_POWERDOWN ||
|
||||
*blank == FB_BLANK_VSYNC_SUSPEND)
|
||||
IT7260_ts_suspend(&(gl_ts->client->dev));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int IT7260_ts_resume(struct device *dev)
|
||||
{
|
||||
if (!gl_ts->suspended) {
|
||||
dev_info(dev, "Already in resume state\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (device_may_wakeup(dev)) {
|
||||
if (gl_ts->device_needs_wakeup) {
|
||||
gl_ts->device_needs_wakeup = false;
|
||||
disable_irq_wake(gl_ts->client->irq);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* put the device in active power mode */
|
||||
IT7260_ts_chipLowPowerMode(false);
|
||||
|
||||
enable_irq(gl_ts->client->irq);
|
||||
gl_ts->suspended = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int IT7260_ts_suspend(struct device *dev)
|
||||
{
|
||||
if (gl_ts->suspended) {
|
||||
dev_info(dev, "Already in suspend state\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (device_may_wakeup(dev)) {
|
||||
if (!gl_ts->device_needs_wakeup) {
|
||||
gl_ts->device_needs_wakeup = true;
|
||||
enable_irq_wake(gl_ts->client->irq);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
disable_irq(gl_ts->client->irq);
|
||||
|
||||
/* put the device in low power mode */
|
||||
IT7260_ts_chipLowPowerMode(true);
|
||||
|
||||
IT7260_ts_release_all();
|
||||
gl_ts->suspended = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops IT7260_ts_dev_pm_ops = {
|
||||
.suspend = IT7260_ts_suspend,
|
||||
.resume = IT7260_ts_resume,
|
||||
};
|
||||
#else
|
||||
static int IT7260_ts_resume(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int IT7260_ts_suspend(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id IT7260_ts_id[] = {
|
||||
{ DEVICE_NAME, 0},
|
||||
{}
|
||||
|
@ -901,33 +1217,22 @@ static const struct i2c_device_id IT7260_ts_id[] = {
|
|||
MODULE_DEVICE_TABLE(i2c, IT7260_ts_id);
|
||||
|
||||
static const struct of_device_id IT7260_match_table[] = {
|
||||
{ .compatible = "ITE,IT7260_ts",},
|
||||
{ .compatible = "ite,it7260_ts",},
|
||||
{},
|
||||
};
|
||||
|
||||
static int IT7260_ts_resume(struct i2c_client *i2cdev)
|
||||
{
|
||||
isDeviceSuspend = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int IT7260_ts_suspend(struct i2c_client *i2cdev, pm_message_t pmesg)
|
||||
{
|
||||
isDeviceSuspend = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver IT7260_ts_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DEVICE_NAME,
|
||||
.of_match_table = IT7260_match_table,
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &IT7260_ts_dev_pm_ops,
|
||||
#endif
|
||||
},
|
||||
.probe = IT7260_ts_probe,
|
||||
.remove = IT7260_ts_remove,
|
||||
.id_table = IT7260_ts_id,
|
||||
.resume = IT7260_ts_resume,
|
||||
.suspend = IT7260_ts_suspend,
|
||||
};
|
||||
|
||||
module_i2c_driver(IT7260_ts_driver);
|
||||
|
|
Loading…
Add table
Reference in a new issue