162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2012-2013 MundoReader S.L. 462306a36Sopenharmony_ci * Author: Heiko Stuebner <heiko@sntech.de> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * based in parts on Nook zforce driver 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Copyright (C) 2010 Barnes & Noble, Inc. 962306a36Sopenharmony_ci * Author: Pieter Truter<ptruter@intrinsyc.com> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/hrtimer.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/input.h> 1662306a36Sopenharmony_ci#include <linux/interrupt.h> 1762306a36Sopenharmony_ci#include <linux/i2c.h> 1862306a36Sopenharmony_ci#include <linux/delay.h> 1962306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 2062306a36Sopenharmony_ci#include <linux/device.h> 2162306a36Sopenharmony_ci#include <linux/sysfs.h> 2262306a36Sopenharmony_ci#include <linux/input/mt.h> 2362306a36Sopenharmony_ci#include <linux/platform_data/zforce_ts.h> 2462306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 2562306a36Sopenharmony_ci#include <linux/of.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define WAIT_TIMEOUT msecs_to_jiffies(1000) 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define FRAME_START 0xee 3062306a36Sopenharmony_ci#define FRAME_MAXSIZE 257 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* Offsets of the different parts of the payload the controller sends */ 3362306a36Sopenharmony_ci#define PAYLOAD_HEADER 0 3462306a36Sopenharmony_ci#define PAYLOAD_LENGTH 1 3562306a36Sopenharmony_ci#define PAYLOAD_BODY 2 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* Response offsets */ 3862306a36Sopenharmony_ci#define RESPONSE_ID 0 3962306a36Sopenharmony_ci#define RESPONSE_DATA 1 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* Commands */ 4262306a36Sopenharmony_ci#define COMMAND_DEACTIVATE 0x00 4362306a36Sopenharmony_ci#define COMMAND_INITIALIZE 0x01 4462306a36Sopenharmony_ci#define COMMAND_RESOLUTION 0x02 4562306a36Sopenharmony_ci#define COMMAND_SETCONFIG 0x03 4662306a36Sopenharmony_ci#define COMMAND_DATAREQUEST 0x04 4762306a36Sopenharmony_ci#define COMMAND_SCANFREQ 0x08 4862306a36Sopenharmony_ci#define COMMAND_STATUS 0X1e 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* 5162306a36Sopenharmony_ci * Responses the controller sends as a result of 5262306a36Sopenharmony_ci * command requests 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_ci#define RESPONSE_DEACTIVATE 0x00 5562306a36Sopenharmony_ci#define RESPONSE_INITIALIZE 0x01 5662306a36Sopenharmony_ci#define RESPONSE_RESOLUTION 0x02 5762306a36Sopenharmony_ci#define RESPONSE_SETCONFIG 0x03 5862306a36Sopenharmony_ci#define RESPONSE_SCANFREQ 0x08 5962306a36Sopenharmony_ci#define RESPONSE_STATUS 0X1e 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * Notifications are sent by the touch controller without 6362306a36Sopenharmony_ci * being requested by the driver and include for example 6462306a36Sopenharmony_ci * touch indications 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_ci#define NOTIFICATION_TOUCH 0x04 6762306a36Sopenharmony_ci#define NOTIFICATION_BOOTCOMPLETE 0x07 6862306a36Sopenharmony_ci#define NOTIFICATION_OVERRUN 0x25 6962306a36Sopenharmony_ci#define NOTIFICATION_PROXIMITY 0x26 7062306a36Sopenharmony_ci#define NOTIFICATION_INVALID_COMMAND 0xfe 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#define ZFORCE_REPORT_POINTS 2 7362306a36Sopenharmony_ci#define ZFORCE_MAX_AREA 0xff 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#define STATE_DOWN 0 7662306a36Sopenharmony_ci#define STATE_MOVE 1 7762306a36Sopenharmony_ci#define STATE_UP 2 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci#define SETCONFIG_DUALTOUCH (1 << 0) 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistruct zforce_point { 8262306a36Sopenharmony_ci int coord_x; 8362306a36Sopenharmony_ci int coord_y; 8462306a36Sopenharmony_ci int state; 8562306a36Sopenharmony_ci int id; 8662306a36Sopenharmony_ci int area_major; 8762306a36Sopenharmony_ci int area_minor; 8862306a36Sopenharmony_ci int orientation; 8962306a36Sopenharmony_ci int pressure; 9062306a36Sopenharmony_ci int prblty; 9162306a36Sopenharmony_ci}; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/* 9462306a36Sopenharmony_ci * @client the i2c_client 9562306a36Sopenharmony_ci * @input the input device 9662306a36Sopenharmony_ci * @suspending in the process of going to suspend (don't emit wakeup 9762306a36Sopenharmony_ci * events for commands executed to suspend the device) 9862306a36Sopenharmony_ci * @suspended device suspended 9962306a36Sopenharmony_ci * @access_mutex serialize i2c-access, to keep multipart reads together 10062306a36Sopenharmony_ci * @command_done completion to wait for the command result 10162306a36Sopenharmony_ci * @command_mutex serialize commands sent to the ic 10262306a36Sopenharmony_ci * @command_waiting the id of the command that is currently waiting 10362306a36Sopenharmony_ci * for a result 10462306a36Sopenharmony_ci * @command_result returned result of the command 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_cistruct zforce_ts { 10762306a36Sopenharmony_ci struct i2c_client *client; 10862306a36Sopenharmony_ci struct input_dev *input; 10962306a36Sopenharmony_ci const struct zforce_ts_platdata *pdata; 11062306a36Sopenharmony_ci char phys[32]; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci struct regulator *reg_vdd; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci struct gpio_desc *gpio_int; 11562306a36Sopenharmony_ci struct gpio_desc *gpio_rst; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci bool suspending; 11862306a36Sopenharmony_ci bool suspended; 11962306a36Sopenharmony_ci bool boot_complete; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci /* Firmware version information */ 12262306a36Sopenharmony_ci u16 version_major; 12362306a36Sopenharmony_ci u16 version_minor; 12462306a36Sopenharmony_ci u16 version_build; 12562306a36Sopenharmony_ci u16 version_rev; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci struct mutex access_mutex; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci struct completion command_done; 13062306a36Sopenharmony_ci struct mutex command_mutex; 13162306a36Sopenharmony_ci int command_waiting; 13262306a36Sopenharmony_ci int command_result; 13362306a36Sopenharmony_ci}; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic int zforce_command(struct zforce_ts *ts, u8 cmd) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct i2c_client *client = ts->client; 13862306a36Sopenharmony_ci char buf[3]; 13962306a36Sopenharmony_ci int ret; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci dev_dbg(&client->dev, "%s: 0x%x\n", __func__, cmd); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci buf[0] = FRAME_START; 14462306a36Sopenharmony_ci buf[1] = 1; /* data size, command only */ 14562306a36Sopenharmony_ci buf[2] = cmd; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci mutex_lock(&ts->access_mutex); 14862306a36Sopenharmony_ci ret = i2c_master_send(client, &buf[0], ARRAY_SIZE(buf)); 14962306a36Sopenharmony_ci mutex_unlock(&ts->access_mutex); 15062306a36Sopenharmony_ci if (ret < 0) { 15162306a36Sopenharmony_ci dev_err(&client->dev, "i2c send data request error: %d\n", ret); 15262306a36Sopenharmony_ci return ret; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci return 0; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic void zforce_reset_assert(struct zforce_ts *ts) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci gpiod_set_value_cansleep(ts->gpio_rst, 1); 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic void zforce_reset_deassert(struct zforce_ts *ts) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci gpiod_set_value_cansleep(ts->gpio_rst, 0); 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic int zforce_send_wait(struct zforce_ts *ts, const char *buf, int len) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci struct i2c_client *client = ts->client; 17162306a36Sopenharmony_ci int ret; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci ret = mutex_trylock(&ts->command_mutex); 17462306a36Sopenharmony_ci if (!ret) { 17562306a36Sopenharmony_ci dev_err(&client->dev, "already waiting for a command\n"); 17662306a36Sopenharmony_ci return -EBUSY; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci dev_dbg(&client->dev, "sending %d bytes for command 0x%x\n", 18062306a36Sopenharmony_ci buf[1], buf[2]); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci ts->command_waiting = buf[2]; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci mutex_lock(&ts->access_mutex); 18562306a36Sopenharmony_ci ret = i2c_master_send(client, buf, len); 18662306a36Sopenharmony_ci mutex_unlock(&ts->access_mutex); 18762306a36Sopenharmony_ci if (ret < 0) { 18862306a36Sopenharmony_ci dev_err(&client->dev, "i2c send data request error: %d\n", ret); 18962306a36Sopenharmony_ci goto unlock; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci dev_dbg(&client->dev, "waiting for result for command 0x%x\n", buf[2]); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (wait_for_completion_timeout(&ts->command_done, WAIT_TIMEOUT) == 0) { 19562306a36Sopenharmony_ci ret = -ETIME; 19662306a36Sopenharmony_ci goto unlock; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci ret = ts->command_result; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ciunlock: 20262306a36Sopenharmony_ci mutex_unlock(&ts->command_mutex); 20362306a36Sopenharmony_ci return ret; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic int zforce_command_wait(struct zforce_ts *ts, u8 cmd) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci struct i2c_client *client = ts->client; 20962306a36Sopenharmony_ci char buf[3]; 21062306a36Sopenharmony_ci int ret; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci dev_dbg(&client->dev, "%s: 0x%x\n", __func__, cmd); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci buf[0] = FRAME_START; 21562306a36Sopenharmony_ci buf[1] = 1; /* data size, command only */ 21662306a36Sopenharmony_ci buf[2] = cmd; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci ret = zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf)); 21962306a36Sopenharmony_ci if (ret < 0) { 22062306a36Sopenharmony_ci dev_err(&client->dev, "i2c send data request error: %d\n", ret); 22162306a36Sopenharmony_ci return ret; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci return 0; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic int zforce_resolution(struct zforce_ts *ts, u16 x, u16 y) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci struct i2c_client *client = ts->client; 23062306a36Sopenharmony_ci char buf[7] = { FRAME_START, 5, COMMAND_RESOLUTION, 23162306a36Sopenharmony_ci (x & 0xff), ((x >> 8) & 0xff), 23262306a36Sopenharmony_ci (y & 0xff), ((y >> 8) & 0xff) }; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci dev_dbg(&client->dev, "set resolution to (%d,%d)\n", x, y); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci return zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf)); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic int zforce_scan_frequency(struct zforce_ts *ts, u16 idle, u16 finger, 24062306a36Sopenharmony_ci u16 stylus) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci struct i2c_client *client = ts->client; 24362306a36Sopenharmony_ci char buf[9] = { FRAME_START, 7, COMMAND_SCANFREQ, 24462306a36Sopenharmony_ci (idle & 0xff), ((idle >> 8) & 0xff), 24562306a36Sopenharmony_ci (finger & 0xff), ((finger >> 8) & 0xff), 24662306a36Sopenharmony_ci (stylus & 0xff), ((stylus >> 8) & 0xff) }; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci dev_dbg(&client->dev, 24962306a36Sopenharmony_ci "set scan frequency to (idle: %d, finger: %d, stylus: %d)\n", 25062306a36Sopenharmony_ci idle, finger, stylus); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci return zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf)); 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistatic int zforce_setconfig(struct zforce_ts *ts, char b1) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci struct i2c_client *client = ts->client; 25862306a36Sopenharmony_ci char buf[7] = { FRAME_START, 5, COMMAND_SETCONFIG, 25962306a36Sopenharmony_ci b1, 0, 0, 0 }; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci dev_dbg(&client->dev, "set config to (%d)\n", b1); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci return zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf)); 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic int zforce_start(struct zforce_ts *ts) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct i2c_client *client = ts->client; 26962306a36Sopenharmony_ci const struct zforce_ts_platdata *pdata = ts->pdata; 27062306a36Sopenharmony_ci int ret; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci dev_dbg(&client->dev, "starting device\n"); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci ret = zforce_command_wait(ts, COMMAND_INITIALIZE); 27562306a36Sopenharmony_ci if (ret) { 27662306a36Sopenharmony_ci dev_err(&client->dev, "Unable to initialize, %d\n", ret); 27762306a36Sopenharmony_ci return ret; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci ret = zforce_resolution(ts, pdata->x_max, pdata->y_max); 28162306a36Sopenharmony_ci if (ret) { 28262306a36Sopenharmony_ci dev_err(&client->dev, "Unable to set resolution, %d\n", ret); 28362306a36Sopenharmony_ci goto error; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci ret = zforce_scan_frequency(ts, 10, 50, 50); 28762306a36Sopenharmony_ci if (ret) { 28862306a36Sopenharmony_ci dev_err(&client->dev, "Unable to set scan frequency, %d\n", 28962306a36Sopenharmony_ci ret); 29062306a36Sopenharmony_ci goto error; 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci ret = zforce_setconfig(ts, SETCONFIG_DUALTOUCH); 29462306a36Sopenharmony_ci if (ret) { 29562306a36Sopenharmony_ci dev_err(&client->dev, "Unable to set config\n"); 29662306a36Sopenharmony_ci goto error; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci /* start sending touch events */ 30062306a36Sopenharmony_ci ret = zforce_command(ts, COMMAND_DATAREQUEST); 30162306a36Sopenharmony_ci if (ret) { 30262306a36Sopenharmony_ci dev_err(&client->dev, "Unable to request data\n"); 30362306a36Sopenharmony_ci goto error; 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci /* 30762306a36Sopenharmony_ci * Per NN, initial cal. take max. of 200msec. 30862306a36Sopenharmony_ci * Allow time to complete this calibration 30962306a36Sopenharmony_ci */ 31062306a36Sopenharmony_ci msleep(200); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci return 0; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cierror: 31562306a36Sopenharmony_ci zforce_command_wait(ts, COMMAND_DEACTIVATE); 31662306a36Sopenharmony_ci return ret; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic int zforce_stop(struct zforce_ts *ts) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci struct i2c_client *client = ts->client; 32262306a36Sopenharmony_ci int ret; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci dev_dbg(&client->dev, "stopping device\n"); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci /* Deactivates touch sensing and puts the device into sleep. */ 32762306a36Sopenharmony_ci ret = zforce_command_wait(ts, COMMAND_DEACTIVATE); 32862306a36Sopenharmony_ci if (ret != 0) { 32962306a36Sopenharmony_ci dev_err(&client->dev, "could not deactivate device, %d\n", 33062306a36Sopenharmony_ci ret); 33162306a36Sopenharmony_ci return ret; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci return 0; 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic int zforce_touch_event(struct zforce_ts *ts, u8 *payload) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci struct i2c_client *client = ts->client; 34062306a36Sopenharmony_ci const struct zforce_ts_platdata *pdata = ts->pdata; 34162306a36Sopenharmony_ci struct zforce_point point; 34262306a36Sopenharmony_ci int count, i, num = 0; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci count = payload[0]; 34562306a36Sopenharmony_ci if (count > ZFORCE_REPORT_POINTS) { 34662306a36Sopenharmony_ci dev_warn(&client->dev, 34762306a36Sopenharmony_ci "too many coordinates %d, expected max %d\n", 34862306a36Sopenharmony_ci count, ZFORCE_REPORT_POINTS); 34962306a36Sopenharmony_ci count = ZFORCE_REPORT_POINTS; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci for (i = 0; i < count; i++) { 35362306a36Sopenharmony_ci point.coord_x = 35462306a36Sopenharmony_ci payload[9 * i + 2] << 8 | payload[9 * i + 1]; 35562306a36Sopenharmony_ci point.coord_y = 35662306a36Sopenharmony_ci payload[9 * i + 4] << 8 | payload[9 * i + 3]; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (point.coord_x > pdata->x_max || 35962306a36Sopenharmony_ci point.coord_y > pdata->y_max) { 36062306a36Sopenharmony_ci dev_warn(&client->dev, "coordinates (%d,%d) invalid\n", 36162306a36Sopenharmony_ci point.coord_x, point.coord_y); 36262306a36Sopenharmony_ci point.coord_x = point.coord_y = 0; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci point.state = payload[9 * i + 5] & 0x0f; 36662306a36Sopenharmony_ci point.id = (payload[9 * i + 5] & 0xf0) >> 4; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* determine touch major, minor and orientation */ 36962306a36Sopenharmony_ci point.area_major = max(payload[9 * i + 6], 37062306a36Sopenharmony_ci payload[9 * i + 7]); 37162306a36Sopenharmony_ci point.area_minor = min(payload[9 * i + 6], 37262306a36Sopenharmony_ci payload[9 * i + 7]); 37362306a36Sopenharmony_ci point.orientation = payload[9 * i + 6] > payload[9 * i + 7]; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci point.pressure = payload[9 * i + 8]; 37662306a36Sopenharmony_ci point.prblty = payload[9 * i + 9]; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci dev_dbg(&client->dev, 37962306a36Sopenharmony_ci "point %d/%d: state %d, id %d, pressure %d, prblty %d, x %d, y %d, amajor %d, aminor %d, ori %d\n", 38062306a36Sopenharmony_ci i, count, point.state, point.id, 38162306a36Sopenharmony_ci point.pressure, point.prblty, 38262306a36Sopenharmony_ci point.coord_x, point.coord_y, 38362306a36Sopenharmony_ci point.area_major, point.area_minor, 38462306a36Sopenharmony_ci point.orientation); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* the zforce id starts with "1", so needs to be decreased */ 38762306a36Sopenharmony_ci input_mt_slot(ts->input, point.id - 1); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, 39062306a36Sopenharmony_ci point.state != STATE_UP); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (point.state != STATE_UP) { 39362306a36Sopenharmony_ci input_report_abs(ts->input, ABS_MT_POSITION_X, 39462306a36Sopenharmony_ci point.coord_x); 39562306a36Sopenharmony_ci input_report_abs(ts->input, ABS_MT_POSITION_Y, 39662306a36Sopenharmony_ci point.coord_y); 39762306a36Sopenharmony_ci input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, 39862306a36Sopenharmony_ci point.area_major); 39962306a36Sopenharmony_ci input_report_abs(ts->input, ABS_MT_TOUCH_MINOR, 40062306a36Sopenharmony_ci point.area_minor); 40162306a36Sopenharmony_ci input_report_abs(ts->input, ABS_MT_ORIENTATION, 40262306a36Sopenharmony_ci point.orientation); 40362306a36Sopenharmony_ci num++; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci input_mt_sync_frame(ts->input); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci input_mt_report_finger_count(ts->input, num); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci input_sync(ts->input); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci return 0; 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic int zforce_read_packet(struct zforce_ts *ts, u8 *buf) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci struct i2c_client *client = ts->client; 41962306a36Sopenharmony_ci int ret; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci mutex_lock(&ts->access_mutex); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci /* read 2 byte message header */ 42462306a36Sopenharmony_ci ret = i2c_master_recv(client, buf, 2); 42562306a36Sopenharmony_ci if (ret < 0) { 42662306a36Sopenharmony_ci dev_err(&client->dev, "error reading header: %d\n", ret); 42762306a36Sopenharmony_ci goto unlock; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (buf[PAYLOAD_HEADER] != FRAME_START) { 43162306a36Sopenharmony_ci dev_err(&client->dev, "invalid frame start: %d\n", buf[0]); 43262306a36Sopenharmony_ci ret = -EIO; 43362306a36Sopenharmony_ci goto unlock; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (buf[PAYLOAD_LENGTH] == 0) { 43762306a36Sopenharmony_ci dev_err(&client->dev, "invalid payload length: %d\n", 43862306a36Sopenharmony_ci buf[PAYLOAD_LENGTH]); 43962306a36Sopenharmony_ci ret = -EIO; 44062306a36Sopenharmony_ci goto unlock; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* read the message */ 44462306a36Sopenharmony_ci ret = i2c_master_recv(client, &buf[PAYLOAD_BODY], buf[PAYLOAD_LENGTH]); 44562306a36Sopenharmony_ci if (ret < 0) { 44662306a36Sopenharmony_ci dev_err(&client->dev, "error reading payload: %d\n", ret); 44762306a36Sopenharmony_ci goto unlock; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci dev_dbg(&client->dev, "read %d bytes for response command 0x%x\n", 45162306a36Sopenharmony_ci buf[PAYLOAD_LENGTH], buf[PAYLOAD_BODY]); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ciunlock: 45462306a36Sopenharmony_ci mutex_unlock(&ts->access_mutex); 45562306a36Sopenharmony_ci return ret; 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic void zforce_complete(struct zforce_ts *ts, int cmd, int result) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci struct i2c_client *client = ts->client; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if (ts->command_waiting == cmd) { 46362306a36Sopenharmony_ci dev_dbg(&client->dev, "completing command 0x%x\n", cmd); 46462306a36Sopenharmony_ci ts->command_result = result; 46562306a36Sopenharmony_ci complete(&ts->command_done); 46662306a36Sopenharmony_ci } else { 46762306a36Sopenharmony_ci dev_dbg(&client->dev, "command %d not for us\n", cmd); 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cistatic irqreturn_t zforce_irq(int irq, void *dev_id) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci struct zforce_ts *ts = dev_id; 47462306a36Sopenharmony_ci struct i2c_client *client = ts->client; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci if (ts->suspended && device_may_wakeup(&client->dev)) 47762306a36Sopenharmony_ci pm_wakeup_event(&client->dev, 500); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci return IRQ_WAKE_THREAD; 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic irqreturn_t zforce_irq_thread(int irq, void *dev_id) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci struct zforce_ts *ts = dev_id; 48562306a36Sopenharmony_ci struct i2c_client *client = ts->client; 48662306a36Sopenharmony_ci int ret; 48762306a36Sopenharmony_ci u8 payload_buffer[FRAME_MAXSIZE]; 48862306a36Sopenharmony_ci u8 *payload; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* 49162306a36Sopenharmony_ci * When still suspended, return. 49262306a36Sopenharmony_ci * Due to the level-interrupt we will get re-triggered later. 49362306a36Sopenharmony_ci */ 49462306a36Sopenharmony_ci if (ts->suspended) { 49562306a36Sopenharmony_ci msleep(20); 49662306a36Sopenharmony_ci return IRQ_HANDLED; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci dev_dbg(&client->dev, "handling interrupt\n"); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci /* Don't emit wakeup events from commands run by zforce_suspend */ 50262306a36Sopenharmony_ci if (!ts->suspending && device_may_wakeup(&client->dev)) 50362306a36Sopenharmony_ci pm_stay_awake(&client->dev); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* 50662306a36Sopenharmony_ci * Run at least once and exit the loop if 50762306a36Sopenharmony_ci * - the optional interrupt GPIO isn't specified 50862306a36Sopenharmony_ci * (there is only one packet read per ISR invocation, then) 50962306a36Sopenharmony_ci * or 51062306a36Sopenharmony_ci * - the GPIO isn't active any more 51162306a36Sopenharmony_ci * (packet read until the level GPIO indicates that there is 51262306a36Sopenharmony_ci * no IRQ any more) 51362306a36Sopenharmony_ci */ 51462306a36Sopenharmony_ci do { 51562306a36Sopenharmony_ci ret = zforce_read_packet(ts, payload_buffer); 51662306a36Sopenharmony_ci if (ret < 0) { 51762306a36Sopenharmony_ci dev_err(&client->dev, 51862306a36Sopenharmony_ci "could not read packet, ret: %d\n", ret); 51962306a36Sopenharmony_ci break; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci payload = &payload_buffer[PAYLOAD_BODY]; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci switch (payload[RESPONSE_ID]) { 52562306a36Sopenharmony_ci case NOTIFICATION_TOUCH: 52662306a36Sopenharmony_ci /* 52762306a36Sopenharmony_ci * Always report touch-events received while 52862306a36Sopenharmony_ci * suspending, when being a wakeup source 52962306a36Sopenharmony_ci */ 53062306a36Sopenharmony_ci if (ts->suspending && device_may_wakeup(&client->dev)) 53162306a36Sopenharmony_ci pm_wakeup_event(&client->dev, 500); 53262306a36Sopenharmony_ci zforce_touch_event(ts, &payload[RESPONSE_DATA]); 53362306a36Sopenharmony_ci break; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci case NOTIFICATION_BOOTCOMPLETE: 53662306a36Sopenharmony_ci ts->boot_complete = payload[RESPONSE_DATA]; 53762306a36Sopenharmony_ci zforce_complete(ts, payload[RESPONSE_ID], 0); 53862306a36Sopenharmony_ci break; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci case RESPONSE_INITIALIZE: 54162306a36Sopenharmony_ci case RESPONSE_DEACTIVATE: 54262306a36Sopenharmony_ci case RESPONSE_SETCONFIG: 54362306a36Sopenharmony_ci case RESPONSE_RESOLUTION: 54462306a36Sopenharmony_ci case RESPONSE_SCANFREQ: 54562306a36Sopenharmony_ci zforce_complete(ts, payload[RESPONSE_ID], 54662306a36Sopenharmony_ci payload[RESPONSE_DATA]); 54762306a36Sopenharmony_ci break; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci case RESPONSE_STATUS: 55062306a36Sopenharmony_ci /* 55162306a36Sopenharmony_ci * Version Payload Results 55262306a36Sopenharmony_ci * [2:major] [2:minor] [2:build] [2:rev] 55362306a36Sopenharmony_ci */ 55462306a36Sopenharmony_ci ts->version_major = (payload[RESPONSE_DATA + 1] << 8) | 55562306a36Sopenharmony_ci payload[RESPONSE_DATA]; 55662306a36Sopenharmony_ci ts->version_minor = (payload[RESPONSE_DATA + 3] << 8) | 55762306a36Sopenharmony_ci payload[RESPONSE_DATA + 2]; 55862306a36Sopenharmony_ci ts->version_build = (payload[RESPONSE_DATA + 5] << 8) | 55962306a36Sopenharmony_ci payload[RESPONSE_DATA + 4]; 56062306a36Sopenharmony_ci ts->version_rev = (payload[RESPONSE_DATA + 7] << 8) | 56162306a36Sopenharmony_ci payload[RESPONSE_DATA + 6]; 56262306a36Sopenharmony_ci dev_dbg(&ts->client->dev, 56362306a36Sopenharmony_ci "Firmware Version %04x:%04x %04x:%04x\n", 56462306a36Sopenharmony_ci ts->version_major, ts->version_minor, 56562306a36Sopenharmony_ci ts->version_build, ts->version_rev); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci zforce_complete(ts, payload[RESPONSE_ID], 0); 56862306a36Sopenharmony_ci break; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci case NOTIFICATION_INVALID_COMMAND: 57162306a36Sopenharmony_ci dev_err(&ts->client->dev, "invalid command: 0x%x\n", 57262306a36Sopenharmony_ci payload[RESPONSE_DATA]); 57362306a36Sopenharmony_ci break; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci default: 57662306a36Sopenharmony_ci dev_err(&ts->client->dev, 57762306a36Sopenharmony_ci "unrecognized response id: 0x%x\n", 57862306a36Sopenharmony_ci payload[RESPONSE_ID]); 57962306a36Sopenharmony_ci break; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci } while (gpiod_get_value_cansleep(ts->gpio_int)); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci if (!ts->suspending && device_may_wakeup(&client->dev)) 58462306a36Sopenharmony_ci pm_relax(&client->dev); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci dev_dbg(&client->dev, "finished interrupt\n"); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci return IRQ_HANDLED; 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cistatic int zforce_input_open(struct input_dev *dev) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci struct zforce_ts *ts = input_get_drvdata(dev); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci return zforce_start(ts); 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistatic void zforce_input_close(struct input_dev *dev) 59962306a36Sopenharmony_ci{ 60062306a36Sopenharmony_ci struct zforce_ts *ts = input_get_drvdata(dev); 60162306a36Sopenharmony_ci struct i2c_client *client = ts->client; 60262306a36Sopenharmony_ci int ret; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci ret = zforce_stop(ts); 60562306a36Sopenharmony_ci if (ret) 60662306a36Sopenharmony_ci dev_warn(&client->dev, "stopping zforce failed\n"); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci return; 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_cistatic int zforce_suspend(struct device *dev) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 61462306a36Sopenharmony_ci struct zforce_ts *ts = i2c_get_clientdata(client); 61562306a36Sopenharmony_ci struct input_dev *input = ts->input; 61662306a36Sopenharmony_ci int ret = 0; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci mutex_lock(&input->mutex); 61962306a36Sopenharmony_ci ts->suspending = true; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci /* 62262306a36Sopenharmony_ci * When configured as a wakeup source device should always wake 62362306a36Sopenharmony_ci * the system, therefore start device if necessary. 62462306a36Sopenharmony_ci */ 62562306a36Sopenharmony_ci if (device_may_wakeup(&client->dev)) { 62662306a36Sopenharmony_ci dev_dbg(&client->dev, "suspend while being a wakeup source\n"); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci /* Need to start device, if not open, to be a wakeup source. */ 62962306a36Sopenharmony_ci if (!input_device_enabled(input)) { 63062306a36Sopenharmony_ci ret = zforce_start(ts); 63162306a36Sopenharmony_ci if (ret) 63262306a36Sopenharmony_ci goto unlock; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci enable_irq_wake(client->irq); 63662306a36Sopenharmony_ci } else if (input_device_enabled(input)) { 63762306a36Sopenharmony_ci dev_dbg(&client->dev, 63862306a36Sopenharmony_ci "suspend without being a wakeup source\n"); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci ret = zforce_stop(ts); 64162306a36Sopenharmony_ci if (ret) 64262306a36Sopenharmony_ci goto unlock; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci disable_irq(client->irq); 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci ts->suspended = true; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ciunlock: 65062306a36Sopenharmony_ci ts->suspending = false; 65162306a36Sopenharmony_ci mutex_unlock(&input->mutex); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci return ret; 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic int zforce_resume(struct device *dev) 65762306a36Sopenharmony_ci{ 65862306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 65962306a36Sopenharmony_ci struct zforce_ts *ts = i2c_get_clientdata(client); 66062306a36Sopenharmony_ci struct input_dev *input = ts->input; 66162306a36Sopenharmony_ci int ret = 0; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci mutex_lock(&input->mutex); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci ts->suspended = false; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci if (device_may_wakeup(&client->dev)) { 66862306a36Sopenharmony_ci dev_dbg(&client->dev, "resume from being a wakeup source\n"); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci disable_irq_wake(client->irq); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci /* need to stop device if it was not open on suspend */ 67362306a36Sopenharmony_ci if (!input_device_enabled(input)) { 67462306a36Sopenharmony_ci ret = zforce_stop(ts); 67562306a36Sopenharmony_ci if (ret) 67662306a36Sopenharmony_ci goto unlock; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci } else if (input_device_enabled(input)) { 67962306a36Sopenharmony_ci dev_dbg(&client->dev, "resume without being a wakeup source\n"); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci enable_irq(client->irq); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci ret = zforce_start(ts); 68462306a36Sopenharmony_ci if (ret < 0) 68562306a36Sopenharmony_ci goto unlock; 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ciunlock: 68962306a36Sopenharmony_ci mutex_unlock(&input->mutex); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci return ret; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(zforce_pm_ops, zforce_suspend, zforce_resume); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_cistatic void zforce_reset(void *data) 69762306a36Sopenharmony_ci{ 69862306a36Sopenharmony_ci struct zforce_ts *ts = data; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci zforce_reset_assert(ts); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci udelay(10); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci if (!IS_ERR(ts->reg_vdd)) 70562306a36Sopenharmony_ci regulator_disable(ts->reg_vdd); 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_cistatic struct zforce_ts_platdata *zforce_parse_dt(struct device *dev) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci struct zforce_ts_platdata *pdata; 71162306a36Sopenharmony_ci struct device_node *np = dev->of_node; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci if (!np) 71462306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 71762306a36Sopenharmony_ci if (!pdata) { 71862306a36Sopenharmony_ci dev_err(dev, "failed to allocate platform data\n"); 71962306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci if (of_property_read_u32(np, "x-size", &pdata->x_max)) { 72362306a36Sopenharmony_ci dev_err(dev, "failed to get x-size property\n"); 72462306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 72562306a36Sopenharmony_ci } 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci if (of_property_read_u32(np, "y-size", &pdata->y_max)) { 72862306a36Sopenharmony_ci dev_err(dev, "failed to get y-size property\n"); 72962306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci return pdata; 73362306a36Sopenharmony_ci} 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_cistatic int zforce_probe(struct i2c_client *client) 73662306a36Sopenharmony_ci{ 73762306a36Sopenharmony_ci const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev); 73862306a36Sopenharmony_ci struct zforce_ts *ts; 73962306a36Sopenharmony_ci struct input_dev *input_dev; 74062306a36Sopenharmony_ci int ret; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci if (!pdata) { 74362306a36Sopenharmony_ci pdata = zforce_parse_dt(&client->dev); 74462306a36Sopenharmony_ci if (IS_ERR(pdata)) 74562306a36Sopenharmony_ci return PTR_ERR(pdata); 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci ts = devm_kzalloc(&client->dev, sizeof(struct zforce_ts), GFP_KERNEL); 74962306a36Sopenharmony_ci if (!ts) 75062306a36Sopenharmony_ci return -ENOMEM; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci ts->gpio_rst = devm_gpiod_get_optional(&client->dev, "reset", 75362306a36Sopenharmony_ci GPIOD_OUT_HIGH); 75462306a36Sopenharmony_ci if (IS_ERR(ts->gpio_rst)) { 75562306a36Sopenharmony_ci ret = PTR_ERR(ts->gpio_rst); 75662306a36Sopenharmony_ci dev_err(&client->dev, 75762306a36Sopenharmony_ci "failed to request reset GPIO: %d\n", ret); 75862306a36Sopenharmony_ci return ret; 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (ts->gpio_rst) { 76262306a36Sopenharmony_ci ts->gpio_int = devm_gpiod_get_optional(&client->dev, "irq", 76362306a36Sopenharmony_ci GPIOD_IN); 76462306a36Sopenharmony_ci if (IS_ERR(ts->gpio_int)) { 76562306a36Sopenharmony_ci ret = PTR_ERR(ts->gpio_int); 76662306a36Sopenharmony_ci dev_err(&client->dev, 76762306a36Sopenharmony_ci "failed to request interrupt GPIO: %d\n", ret); 76862306a36Sopenharmony_ci return ret; 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci } else { 77162306a36Sopenharmony_ci /* 77262306a36Sopenharmony_ci * Deprecated GPIO handling for compatibility 77362306a36Sopenharmony_ci * with legacy binding. 77462306a36Sopenharmony_ci */ 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci /* INT GPIO */ 77762306a36Sopenharmony_ci ts->gpio_int = devm_gpiod_get_index(&client->dev, NULL, 0, 77862306a36Sopenharmony_ci GPIOD_IN); 77962306a36Sopenharmony_ci if (IS_ERR(ts->gpio_int)) { 78062306a36Sopenharmony_ci ret = PTR_ERR(ts->gpio_int); 78162306a36Sopenharmony_ci dev_err(&client->dev, 78262306a36Sopenharmony_ci "failed to request interrupt GPIO: %d\n", ret); 78362306a36Sopenharmony_ci return ret; 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci /* RST GPIO */ 78762306a36Sopenharmony_ci ts->gpio_rst = devm_gpiod_get_index(&client->dev, NULL, 1, 78862306a36Sopenharmony_ci GPIOD_OUT_HIGH); 78962306a36Sopenharmony_ci if (IS_ERR(ts->gpio_rst)) { 79062306a36Sopenharmony_ci ret = PTR_ERR(ts->gpio_rst); 79162306a36Sopenharmony_ci dev_err(&client->dev, 79262306a36Sopenharmony_ci "failed to request reset GPIO: %d\n", ret); 79362306a36Sopenharmony_ci return ret; 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci ts->reg_vdd = devm_regulator_get_optional(&client->dev, "vdd"); 79862306a36Sopenharmony_ci if (IS_ERR(ts->reg_vdd)) { 79962306a36Sopenharmony_ci ret = PTR_ERR(ts->reg_vdd); 80062306a36Sopenharmony_ci if (ret == -EPROBE_DEFER) 80162306a36Sopenharmony_ci return ret; 80262306a36Sopenharmony_ci } else { 80362306a36Sopenharmony_ci ret = regulator_enable(ts->reg_vdd); 80462306a36Sopenharmony_ci if (ret) 80562306a36Sopenharmony_ci return ret; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci /* 80862306a36Sopenharmony_ci * according to datasheet add 100us grace time after regular 80962306a36Sopenharmony_ci * regulator enable delay. 81062306a36Sopenharmony_ci */ 81162306a36Sopenharmony_ci udelay(100); 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci ret = devm_add_action(&client->dev, zforce_reset, ts); 81562306a36Sopenharmony_ci if (ret) { 81662306a36Sopenharmony_ci dev_err(&client->dev, "failed to register reset action, %d\n", 81762306a36Sopenharmony_ci ret); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci /* hereafter the regulator will be disabled by the action */ 82062306a36Sopenharmony_ci if (!IS_ERR(ts->reg_vdd)) 82162306a36Sopenharmony_ci regulator_disable(ts->reg_vdd); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci return ret; 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci snprintf(ts->phys, sizeof(ts->phys), 82762306a36Sopenharmony_ci "%s/input0", dev_name(&client->dev)); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci input_dev = devm_input_allocate_device(&client->dev); 83062306a36Sopenharmony_ci if (!input_dev) { 83162306a36Sopenharmony_ci dev_err(&client->dev, "could not allocate input device\n"); 83262306a36Sopenharmony_ci return -ENOMEM; 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci mutex_init(&ts->access_mutex); 83662306a36Sopenharmony_ci mutex_init(&ts->command_mutex); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci ts->pdata = pdata; 83962306a36Sopenharmony_ci ts->client = client; 84062306a36Sopenharmony_ci ts->input = input_dev; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci input_dev->name = "Neonode zForce touchscreen"; 84362306a36Sopenharmony_ci input_dev->phys = ts->phys; 84462306a36Sopenharmony_ci input_dev->id.bustype = BUS_I2C; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci input_dev->open = zforce_input_open; 84762306a36Sopenharmony_ci input_dev->close = zforce_input_close; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci __set_bit(EV_KEY, input_dev->evbit); 85062306a36Sopenharmony_ci __set_bit(EV_SYN, input_dev->evbit); 85162306a36Sopenharmony_ci __set_bit(EV_ABS, input_dev->evbit); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci /* For multi touch */ 85462306a36Sopenharmony_ci input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, 85562306a36Sopenharmony_ci pdata->x_max, 0, 0); 85662306a36Sopenharmony_ci input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, 85762306a36Sopenharmony_ci pdata->y_max, 0, 0); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 86062306a36Sopenharmony_ci ZFORCE_MAX_AREA, 0, 0); 86162306a36Sopenharmony_ci input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0, 86262306a36Sopenharmony_ci ZFORCE_MAX_AREA, 0, 0); 86362306a36Sopenharmony_ci input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0); 86462306a36Sopenharmony_ci input_mt_init_slots(input_dev, ZFORCE_REPORT_POINTS, INPUT_MT_DIRECT); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci input_set_drvdata(ts->input, ts); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci init_completion(&ts->command_done); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci /* 87162306a36Sopenharmony_ci * The zforce pulls the interrupt low when it has data ready. 87262306a36Sopenharmony_ci * After it is triggered the isr thread runs until all the available 87362306a36Sopenharmony_ci * packets have been read and the interrupt is high again. 87462306a36Sopenharmony_ci * Therefore we can trigger the interrupt anytime it is low and do 87562306a36Sopenharmony_ci * not need to limit it to the interrupt edge. 87662306a36Sopenharmony_ci */ 87762306a36Sopenharmony_ci ret = devm_request_threaded_irq(&client->dev, client->irq, 87862306a36Sopenharmony_ci zforce_irq, zforce_irq_thread, 87962306a36Sopenharmony_ci IRQF_TRIGGER_LOW | IRQF_ONESHOT, 88062306a36Sopenharmony_ci input_dev->name, ts); 88162306a36Sopenharmony_ci if (ret) { 88262306a36Sopenharmony_ci dev_err(&client->dev, "irq %d request failed\n", client->irq); 88362306a36Sopenharmony_ci return ret; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci i2c_set_clientdata(client, ts); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci /* let the controller boot */ 88962306a36Sopenharmony_ci zforce_reset_deassert(ts); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci ts->command_waiting = NOTIFICATION_BOOTCOMPLETE; 89262306a36Sopenharmony_ci if (wait_for_completion_timeout(&ts->command_done, WAIT_TIMEOUT) == 0) 89362306a36Sopenharmony_ci dev_warn(&client->dev, "bootcomplete timed out\n"); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci /* need to start device to get version information */ 89662306a36Sopenharmony_ci ret = zforce_command_wait(ts, COMMAND_INITIALIZE); 89762306a36Sopenharmony_ci if (ret) { 89862306a36Sopenharmony_ci dev_err(&client->dev, "unable to initialize, %d\n", ret); 89962306a36Sopenharmony_ci return ret; 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci /* this gets the firmware version among other information */ 90362306a36Sopenharmony_ci ret = zforce_command_wait(ts, COMMAND_STATUS); 90462306a36Sopenharmony_ci if (ret < 0) { 90562306a36Sopenharmony_ci dev_err(&client->dev, "couldn't get status, %d\n", ret); 90662306a36Sopenharmony_ci zforce_stop(ts); 90762306a36Sopenharmony_ci return ret; 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci /* stop device and put it into sleep until it is opened */ 91162306a36Sopenharmony_ci ret = zforce_stop(ts); 91262306a36Sopenharmony_ci if (ret < 0) 91362306a36Sopenharmony_ci return ret; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci device_set_wakeup_capable(&client->dev, true); 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci ret = input_register_device(input_dev); 91862306a36Sopenharmony_ci if (ret) { 91962306a36Sopenharmony_ci dev_err(&client->dev, "could not register input device, %d\n", 92062306a36Sopenharmony_ci ret); 92162306a36Sopenharmony_ci return ret; 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci return 0; 92562306a36Sopenharmony_ci} 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_cistatic struct i2c_device_id zforce_idtable[] = { 92862306a36Sopenharmony_ci { "zforce-ts", 0 }, 92962306a36Sopenharmony_ci { } 93062306a36Sopenharmony_ci}; 93162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, zforce_idtable); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci#ifdef CONFIG_OF 93462306a36Sopenharmony_cistatic const struct of_device_id zforce_dt_idtable[] = { 93562306a36Sopenharmony_ci { .compatible = "neonode,zforce" }, 93662306a36Sopenharmony_ci {}, 93762306a36Sopenharmony_ci}; 93862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, zforce_dt_idtable); 93962306a36Sopenharmony_ci#endif 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_cistatic struct i2c_driver zforce_driver = { 94262306a36Sopenharmony_ci .driver = { 94362306a36Sopenharmony_ci .name = "zforce-ts", 94462306a36Sopenharmony_ci .pm = pm_sleep_ptr(&zforce_pm_ops), 94562306a36Sopenharmony_ci .of_match_table = of_match_ptr(zforce_dt_idtable), 94662306a36Sopenharmony_ci }, 94762306a36Sopenharmony_ci .probe = zforce_probe, 94862306a36Sopenharmony_ci .id_table = zforce_idtable, 94962306a36Sopenharmony_ci}; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_cimodule_i2c_driver(zforce_driver); 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ciMODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); 95462306a36Sopenharmony_ciMODULE_DESCRIPTION("zForce TouchScreen Driver"); 95562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 956