Loading drivers/input/touchscreen/it7258_ts_i2c.c +208 −66 Original line number Diff line number Diff line Loading @@ -24,11 +24,14 @@ #include <linux/slab.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 Loading Loading @@ -99,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; Loading Loading @@ -148,13 +156,15 @@ struct IT7260_ts_data { const struct IT7260_ts_platform_data *pdata; struct regulator *vdd; struct regulator *avdd; #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; Loading @@ -163,6 +173,26 @@ 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 = isDeviceSuspend; 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) Loading Loading @@ -414,6 +444,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) { Loading Loading @@ -586,48 +631,33 @@ 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); *buf = isDeviceSuspend ? '1' : '0'; return 1; } else { return -EINTR; } } 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; 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 { if ((isDeviceSuspend && goToSleepVal > 0) || (!isDeviceSuspend && goToSleepVal == 0)) dev_err(dev, "duplicate request to %s chip\n", goToSleepVal ? "sleep" : "wake"); else if (goToSleepVal) { 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; 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"); } isDeviceSuspend = goToSleepVal; return count; } Loading Loading @@ -684,6 +714,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) { Loading @@ -701,7 +738,7 @@ 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; Loading @@ -711,49 +748,46 @@ static void readTouchDataPoint(void) /* 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); } } static irqreturn_t IT7260_ts_threaded_handler(int irq, void *devid) { readTouchDataPoint(); return IRQ_HANDLED; } Loading Loading @@ -803,6 +837,7 @@ static int IT7260_ts_probe(struct i2c_client *client, 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"); Loading Loading @@ -940,8 +975,11 @@ static int IT7260_ts_probe(struct i2c_client *client, 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 (input_register_device(input_dev)) { LOGE("failed to register input device\n"); Loading @@ -959,6 +997,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)); Loading @@ -966,8 +1013,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); Loading @@ -991,45 +1066,112 @@ 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); devicePresent = false; return 0; } static const struct i2c_device_id IT7260_ts_id[] = { { DEVICE_NAME, 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; MODULE_DEVICE_TABLE(i2c, IT7260_ts_id); 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->input_dev->dev)); else if (*blank == FB_BLANK_POWERDOWN || *blank == FB_BLANK_VSYNC_SUSPEND) IT7260_ts_suspend(&(gl_ts->input_dev->dev)); } } static const struct of_device_id IT7260_match_table[] = { { .compatible = "ite,it7260_ts",}, {}, }; return 0; } #endif static int IT7260_ts_resume(struct i2c_client *i2cdev) #ifdef CONFIG_PM static int IT7260_ts_resume(struct device *dev) { if (!isDeviceSuspend) { dev_info(dev, "Already in resume state\n"); return 0; } /* put the device in active powr mode */ IT7260_ts_chipLowPowerMode(false); enable_irq(gl_ts->client->irq); isDeviceSuspend = false; return 0; } static int IT7260_ts_suspend(struct i2c_client *i2cdev, pm_message_t pmesg) static int IT7260_ts_suspend(struct device *dev) { if (isDeviceSuspend) { dev_info(dev, "Already in suspend state\n"); return 0; } disable_irq(gl_ts->client->irq); /* put the device in active powr mode */ IT7260_ts_chipLowPowerMode(true); IT7260_ts_release_all(); isDeviceSuspend = 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}, {} }; MODULE_DEVICE_TABLE(i2c, IT7260_ts_id); static const struct of_device_id IT7260_match_table[] = { { .compatible = "ite,it7260_ts",}, {}, }; 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 Loading
drivers/input/touchscreen/it7258_ts_i2c.c +208 −66 Original line number Diff line number Diff line Loading @@ -24,11 +24,14 @@ #include <linux/slab.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 Loading Loading @@ -99,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; Loading Loading @@ -148,13 +156,15 @@ struct IT7260_ts_data { const struct IT7260_ts_platform_data *pdata; struct regulator *vdd; struct regulator *avdd; #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; Loading @@ -163,6 +173,26 @@ 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 = isDeviceSuspend; 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) Loading Loading @@ -414,6 +444,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) { Loading Loading @@ -586,48 +631,33 @@ 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); *buf = isDeviceSuspend ? '1' : '0'; return 1; } else { return -EINTR; } } 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; 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 { if ((isDeviceSuspend && goToSleepVal > 0) || (!isDeviceSuspend && goToSleepVal == 0)) dev_err(dev, "duplicate request to %s chip\n", goToSleepVal ? "sleep" : "wake"); else if (goToSleepVal) { 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; 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"); } isDeviceSuspend = goToSleepVal; return count; } Loading Loading @@ -684,6 +714,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) { Loading @@ -701,7 +738,7 @@ 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; Loading @@ -711,49 +748,46 @@ static void readTouchDataPoint(void) /* 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); } } static irqreturn_t IT7260_ts_threaded_handler(int irq, void *devid) { readTouchDataPoint(); return IRQ_HANDLED; } Loading Loading @@ -803,6 +837,7 @@ static int IT7260_ts_probe(struct i2c_client *client, 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"); Loading Loading @@ -940,8 +975,11 @@ static int IT7260_ts_probe(struct i2c_client *client, 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 (input_register_device(input_dev)) { LOGE("failed to register input device\n"); Loading @@ -959,6 +997,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)); Loading @@ -966,8 +1013,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); Loading @@ -991,45 +1066,112 @@ 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); devicePresent = false; return 0; } static const struct i2c_device_id IT7260_ts_id[] = { { DEVICE_NAME, 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; MODULE_DEVICE_TABLE(i2c, IT7260_ts_id); 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->input_dev->dev)); else if (*blank == FB_BLANK_POWERDOWN || *blank == FB_BLANK_VSYNC_SUSPEND) IT7260_ts_suspend(&(gl_ts->input_dev->dev)); } } static const struct of_device_id IT7260_match_table[] = { { .compatible = "ite,it7260_ts",}, {}, }; return 0; } #endif static int IT7260_ts_resume(struct i2c_client *i2cdev) #ifdef CONFIG_PM static int IT7260_ts_resume(struct device *dev) { if (!isDeviceSuspend) { dev_info(dev, "Already in resume state\n"); return 0; } /* put the device in active powr mode */ IT7260_ts_chipLowPowerMode(false); enable_irq(gl_ts->client->irq); isDeviceSuspend = false; return 0; } static int IT7260_ts_suspend(struct i2c_client *i2cdev, pm_message_t pmesg) static int IT7260_ts_suspend(struct device *dev) { if (isDeviceSuspend) { dev_info(dev, "Already in suspend state\n"); return 0; } disable_irq(gl_ts->client->irq); /* put the device in active powr mode */ IT7260_ts_chipLowPowerMode(true); IT7260_ts_release_all(); isDeviceSuspend = 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}, {} }; MODULE_DEVICE_TABLE(i2c, IT7260_ts_id); static const struct of_device_id IT7260_match_table[] = { { .compatible = "ite,it7260_ts",}, {}, }; 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