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.
|
invensense InvenSense Inc.
|
||||||
isee ISEE 2007 S.L.
|
isee ISEE 2007 S.L.
|
||||||
isil Intersil
|
isil Intersil
|
||||||
|
ite ITE Tech. Inc.
|
||||||
jedec JEDEC Solid State Technology Association
|
jedec JEDEC Solid State Technology Association
|
||||||
karo Ka-Ro electronics GmbH
|
karo Ka-Ro electronics GmbH
|
||||||
keymile Keymile GmbH
|
keymile Keymile GmbH
|
||||||
|
|
|
@ -22,12 +22,16 @@
|
||||||
#include <linux/firmware.h>
|
#include <linux/firmware.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
#include <linux/slab.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 MAX_BUFFER_SIZE 144
|
||||||
#define DEVICE_NAME "IT7260"
|
#define DEVICE_NAME "IT7260"
|
||||||
#define SCREEN_X_RESOLUTION 320
|
#define SCREEN_X_RESOLUTION 320
|
||||||
#define SCREEN_Y_RESOLUTION 320
|
#define SCREEN_Y_RESOLUTION 320
|
||||||
|
#define DEBUGFS_DIR_NAME "ts_debug"
|
||||||
|
|
||||||
/* all commands writes go to this idx */
|
/* all commands writes go to this idx */
|
||||||
#define BUF_COMMAND 0x20
|
#define BUF_COMMAND 0x20
|
||||||
|
@ -98,6 +102,11 @@
|
||||||
/* use this to include integers in commands */
|
/* use this to include integers in commands */
|
||||||
#define CMD_UINT16(v) ((uint8_t)(v)) , ((uint8_t)((v) >> 8))
|
#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 {
|
struct FingerData {
|
||||||
uint8_t xLo;
|
uint8_t xLo;
|
||||||
|
@ -128,24 +137,65 @@ struct PointData {
|
||||||
#define FD_PRESSURE_HIGH 0x08
|
#define FD_PRESSURE_HIGH 0x08
|
||||||
#define FD_PRESSURE_HEAVY 0x0F
|
#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 IT7260_ts_data {
|
||||||
struct i2c_client *client;
|
struct i2c_client *client;
|
||||||
struct input_dev *input_dev;
|
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 fwUploadResult;
|
||||||
static int8_t calibrationWasSuccessful;
|
static int8_t calibrationWasSuccessful;
|
||||||
static bool devicePresent;
|
static bool devicePresent;
|
||||||
static DEFINE_MUTEX(sleepModeMutex);
|
|
||||||
static bool chipAwake;
|
|
||||||
static bool hadFingerDown;
|
static bool hadFingerDown;
|
||||||
static bool isDeviceSuspend;
|
|
||||||
static struct input_dev *input_dev;
|
static struct input_dev *input_dev;
|
||||||
static struct IT7260_ts_data *gl_ts;
|
static struct IT7260_ts_data *gl_ts;
|
||||||
|
|
||||||
#define LOGE(...) pr_err(DEVICE_NAME ": " __VA_ARGS__)
|
#define LOGE(...) pr_err(DEVICE_NAME ": " __VA_ARGS__)
|
||||||
#define LOGI(...) printk(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 */
|
/* internal use func - does not make sure chip is ready before read */
|
||||||
static bool i2cReadNoReadyCheck(uint8_t bufferIndex, uint8_t *dataBuffer,
|
static bool i2cReadNoReadyCheck(uint8_t bufferIndex, uint8_t *dataBuffer,
|
||||||
uint16_t dataLength)
|
uint16_t dataLength)
|
||||||
|
@ -397,6 +447,21 @@ static bool chipGetVersions(uint8_t *verFw, uint8_t *verCfg, bool logIt)
|
||||||
return ret;
|
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,
|
static ssize_t sysfsUpgradeStore(struct device *dev,
|
||||||
struct device_attribute *attr, const char *buf, size_t count)
|
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
|
* 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
|
* writing to buf. To fix this now we actually return the sleep status
|
||||||
*/
|
*/
|
||||||
if (!mutex_lock_interruptible(&sleepModeMutex)) {
|
*buf = gl_ts->suspended ? '1' : '0';
|
||||||
*buf = chipAwake ? '1' : '0';
|
|
||||||
mutex_unlock(&sleepModeMutex);
|
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
|
||||||
return -EINTR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t sysfsSleepStore(struct device *dev,
|
static ssize_t sysfsSleepStore(struct device *dev,
|
||||||
struct device_attribute *attr, const char *buf, size_t count)
|
struct device_attribute *attr, const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
static const uint8_t cmdGoSleep[] = {CMD_PWR_CTL,
|
int go_to_sleep, ret;
|
||||||
0x00, PWR_CTL_SLEEP_MODE};
|
|
||||||
int goToSleepVal, ret;
|
|
||||||
bool goToWake;
|
|
||||||
uint8_t dummy;
|
|
||||||
|
|
||||||
ret = kstrtoint(buf, 10, &goToSleepVal);
|
ret = kstrtoint(buf, 10, &goToSleepVal);
|
||||||
/* convert to bool of proper polarity */
|
|
||||||
goToWake = !goToSleepVal;
|
|
||||||
|
|
||||||
if (!mutex_lock_interruptible(&sleepModeMutex)) {
|
/* (gl_ts->suspended == true && goToSleepVal > 0) means
|
||||||
if ((chipAwake && goToWake) || (!chipAwake && !goToWake))
|
* device is already suspended and you want it to be in sleep,
|
||||||
LOGE("duplicate request to %s chip\n",
|
* (gl_ts->suspended == false && goToSleepVal == 0) means
|
||||||
goToWake ? "wake" : "sleep");
|
* device is already active and you also want it to be active.
|
||||||
else if (goToWake) {
|
*/
|
||||||
i2cReadNoReadyCheck(BUF_QUERY, &dummy, sizeof(dummy));
|
if ((gl_ts->suspended && go_to_sleep > 0) ||
|
||||||
enable_irq(gl_ts->client->irq);
|
(!gl_ts->suspended && go_to_sleep == 0))
|
||||||
LOGI("touch is going to wake!\n");
|
dev_err(dev, "duplicate request to %s chip\n",
|
||||||
} else {
|
go_to_sleep ? "sleep" : "wake");
|
||||||
|
else if (go_to_sleep) {
|
||||||
disable_irq(gl_ts->client->irq);
|
disable_irq(gl_ts->client->irq);
|
||||||
i2cWriteNoReadyCheck(BUF_COMMAND, cmdGoSleep,
|
IT7260_ts_chipLowPowerMode(true);
|
||||||
sizeof(cmdGoSleep));
|
dev_dbg(dev, "touch is going to sleep...\n");
|
||||||
LOGI("touch is going to sleep...\n");
|
|
||||||
}
|
|
||||||
chipAwake = goToWake;
|
|
||||||
mutex_unlock(&sleepModeMutex);
|
|
||||||
return count;
|
|
||||||
} else {
|
} 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,
|
static DEVICE_ATTR(status, S_IRUGO|S_IWUSR|S_IWGRP,
|
||||||
sysfsStatusShow, sysfsStatusStore);
|
sysfsStatusShow, sysfsStatusStore);
|
||||||
|
@ -667,6 +721,13 @@ void sendCalibrationCmd(void)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(sendCalibrationCmd);
|
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,
|
static void readFingerData(uint16_t *xP, uint16_t *yP, uint8_t *pressureP,
|
||||||
const struct FingerData *fd)
|
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;
|
*pressureP = fd->pressure & FD_PRESSURE_BITS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void readTouchDataPoint(void)
|
static irqreturn_t IT7260_ts_threaded_handler(int irq, void *devid)
|
||||||
{
|
{
|
||||||
struct PointData pointData;
|
struct PointData pointData;
|
||||||
uint8_t devStatus;
|
uint8_t devStatus;
|
||||||
uint8_t pressure = FD_PRESSURE_NONE;
|
uint8_t pressure = FD_PRESSURE_NONE;
|
||||||
uint16_t x, y;
|
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 */
|
/* verify there is point data to read & it is readable and valid */
|
||||||
i2cReadNoReadyCheck(BUF_QUERY, &devStatus, sizeof(devStatus));
|
i2cReadNoReadyCheck(BUF_QUERY, &devStatus, sizeof(devStatus));
|
||||||
if (!((devStatus & PT_INFO_BITS) & PT_INFO_YES)) {
|
if (!((devStatus & PT_INFO_BITS) & PT_INFO_YES)) {
|
||||||
pr_err("readTouchDataPoint() called when no data available (0x%02X)\n",
|
return IRQ_HANDLED;
|
||||||
devStatus);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (!i2cReadNoReadyCheck(BUF_POINT_INFO, (void *)&pointData,
|
if (!i2cReadNoReadyCheck(BUF_POINT_INFO, (void *)&pointData,
|
||||||
sizeof(pointData))) {
|
sizeof(pointData))) {
|
||||||
pr_err("readTouchDataPoint() failed to read point data buffer\n");
|
dev_err(&gl_ts->client->dev,
|
||||||
return;
|
"readTouchDataPoint() failed to read point data buffer\n");
|
||||||
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
if ((pointData.flags & PD_FLAGS_DATA_TYPE_BITS) !=
|
if ((pointData.flags & PD_FLAGS_DATA_TYPE_BITS) !=
|
||||||
PD_FLAGS_DATA_TYPE_TOUCH) {
|
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);
|
pointData.flags);
|
||||||
return;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pointData.flags & PD_FLAGS_HAVE_FINGERS) & 1)
|
if ((pointData.flags & PD_FLAGS_HAVE_FINGERS) & 1)
|
||||||
readFingerData(&x, &y, &pressure, pointData.fd);
|
readFingerData(&x, &y, &pressure, pointData.fd);
|
||||||
|
|
||||||
if (pressure >= FD_PRESSURE_LIGHT) {
|
if (pressure >= FD_PRESSURE_LIGHT) {
|
||||||
|
|
||||||
if (!hadFingerDown)
|
if (!hadFingerDown)
|
||||||
hadFingerDown = true;
|
hadFingerDown = true;
|
||||||
|
|
||||||
readFingerData(&x, &y, &pressure, pointData.fd);
|
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_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);
|
input_sync(gl_ts->input_dev);
|
||||||
|
|
||||||
|
|
||||||
} else if (hadFingerDown) {
|
} else if (hadFingerDown) {
|
||||||
hadFingerDown = false;
|
hadFingerDown = false;
|
||||||
|
|
||||||
input_report_key(gl_ts->input_dev, BTN_TOUCH, 0);
|
input_report_key(gl_ts->input_dev, BTN_TOUCH, 0);
|
||||||
|
input_mt_sync(gl_ts->input_dev);
|
||||||
input_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();
|
pm_relax(&gl_ts->client->dev);
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool chipIdentifyIT7260(void)
|
static bool chipIdentifyIT7260(void)
|
||||||
|
@ -782,9 +862,11 @@ static int IT7260_ts_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
static const uint8_t cmdStart[] = {CMD_UNKNOWN_7};
|
static const uint8_t cmdStart[] = {CMD_UNKNOWN_7};
|
||||||
struct IT7260_i2c_platform_data *pdata;
|
struct IT7260_ts_platform_data *pdata;
|
||||||
uint8_t rsp[2];
|
uint8_t rsp[2];
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
int rc;
|
||||||
|
struct dentry *temp;
|
||||||
|
|
||||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||||
LOGE("need I2C_FUNC_I2C\n");
|
LOGE("need I2C_FUNC_I2C\n");
|
||||||
|
@ -805,13 +887,100 @@ static int IT7260_ts_probe(struct i2c_client *client,
|
||||||
|
|
||||||
gl_ts->client = client;
|
gl_ts->client = client;
|
||||||
i2c_set_clientdata(client, gl_ts);
|
i2c_set_clientdata(client, gl_ts);
|
||||||
|
|
||||||
|
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;
|
pdata = client->dev.platform_data;
|
||||||
|
|
||||||
|
if (!pdata)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
gl_ts->pdata = pdata;
|
||||||
if (sysfs_create_group(&(client->dev.kobj), &it7260_attrstatus_group)) {
|
if (sysfs_create_group(&(client->dev.kobj), &it7260_attrstatus_group)) {
|
||||||
dev_err(&client->dev, "failed to register sysfs #1\n");
|
dev_err(&client->dev, "failed to register sysfs #1\n");
|
||||||
goto err_sysfs_grp_create_1;
|
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()) {
|
if (!chipIdentifyIT7260()) {
|
||||||
LOGI("chipIdentifyIT7260 FAIL");
|
LOGI("chipIdentifyIT7260 FAIL");
|
||||||
goto err_ident_fail_or_input_alloc;
|
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(INPUT_PROP_DIRECT,input_dev->propbit);
|
||||||
set_bit(BTN_TOUCH, input_dev->keybit);
|
set_bit(BTN_TOUCH, input_dev->keybit);
|
||||||
set_bit(KEY_SLEEP,input_dev->keybit);
|
set_bit(KEY_SLEEP,input_dev->keybit);
|
||||||
set_bit(KEY_WAKEUP,input_dev->keybit);
|
|
||||||
set_bit(KEY_POWER,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_MT_POSITION_X, 0,
|
||||||
input_set_abs_params(input_dev, ABS_Y, 0, SCREEN_Y_RESOLUTION, 0, 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)) {
|
if (input_register_device(input_dev)) {
|
||||||
LOGE("failed to register input device\n");
|
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;
|
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;
|
devicePresent = true;
|
||||||
|
|
||||||
i2cWriteNoReadyCheck(BUF_COMMAND, cmdStart, sizeof(cmdStart));
|
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));
|
i2cReadNoReadyCheck(BUF_RESPONSE, rsp, sizeof(rsp));
|
||||||
mdelay(10);
|
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;
|
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:
|
err_sysfs_grp_create_2:
|
||||||
free_irq(client->irq, gl_ts);
|
free_irq(client->irq, gl_ts);
|
||||||
|
|
||||||
|
@ -874,6 +1088,10 @@ err_irq_reg:
|
||||||
input_dev = NULL;
|
input_dev = NULL;
|
||||||
|
|
||||||
err_input_register:
|
err_input_register:
|
||||||
|
if (pdata->wakeup) {
|
||||||
|
cancel_work_sync(&gl_ts->work_pm_relax);
|
||||||
|
device_init_wakeup(&client->dev, false);
|
||||||
|
}
|
||||||
if (input_dev)
|
if (input_dev)
|
||||||
input_free_device(input_dev);
|
input_free_device(input_dev);
|
||||||
|
|
||||||
|
@ -889,10 +1107,108 @@ err_out:
|
||||||
|
|
||||||
static int IT7260_ts_remove(struct i2c_client *client)
|
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;
|
devicePresent = false;
|
||||||
return 0;
|
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[] = {
|
static const struct i2c_device_id IT7260_ts_id[] = {
|
||||||
{ DEVICE_NAME, 0},
|
{ DEVICE_NAME, 0},
|
||||||
{}
|
{}
|
||||||
|
@ -901,33 +1217,22 @@ static const struct i2c_device_id IT7260_ts_id[] = {
|
||||||
MODULE_DEVICE_TABLE(i2c, IT7260_ts_id);
|
MODULE_DEVICE_TABLE(i2c, IT7260_ts_id);
|
||||||
|
|
||||||
static const struct of_device_id IT7260_match_table[] = {
|
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 = {
|
static struct i2c_driver IT7260_ts_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.name = DEVICE_NAME,
|
.name = DEVICE_NAME,
|
||||||
.of_match_table = IT7260_match_table,
|
.of_match_table = IT7260_match_table,
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
.pm = &IT7260_ts_dev_pm_ops,
|
||||||
|
#endif
|
||||||
},
|
},
|
||||||
.probe = IT7260_ts_probe,
|
.probe = IT7260_ts_probe,
|
||||||
.remove = IT7260_ts_remove,
|
.remove = IT7260_ts_remove,
|
||||||
.id_table = IT7260_ts_id,
|
.id_table = IT7260_ts_id,
|
||||||
.resume = IT7260_ts_resume,
|
|
||||||
.suspend = IT7260_ts_suspend,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module_i2c_driver(IT7260_ts_driver);
|
module_i2c_driver(IT7260_ts_driver);
|
||||||
|
|
Loading…
Add table
Reference in a new issue