18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2012-2013 MundoReader S.L. 48c2ecf20Sopenharmony_ci * Author: Heiko Stuebner <heiko@sntech.de> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * based in parts on Nook zforce driver 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright (C) 2010 Barnes & Noble, Inc. 98c2ecf20Sopenharmony_ci * Author: Pieter Truter<ptruter@intrinsyc.com> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/hrtimer.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/input.h> 168c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 178c2ecf20Sopenharmony_ci#include <linux/i2c.h> 188c2ecf20Sopenharmony_ci#include <linux/delay.h> 198c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 208c2ecf20Sopenharmony_ci#include <linux/device.h> 218c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 228c2ecf20Sopenharmony_ci#include <linux/input/mt.h> 238c2ecf20Sopenharmony_ci#include <linux/platform_data/zforce_ts.h> 248c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 258c2ecf20Sopenharmony_ci#include <linux/of.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define WAIT_TIMEOUT msecs_to_jiffies(1000) 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define FRAME_START 0xee 308c2ecf20Sopenharmony_ci#define FRAME_MAXSIZE 257 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* Offsets of the different parts of the payload the controller sends */ 338c2ecf20Sopenharmony_ci#define PAYLOAD_HEADER 0 348c2ecf20Sopenharmony_ci#define PAYLOAD_LENGTH 1 358c2ecf20Sopenharmony_ci#define PAYLOAD_BODY 2 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* Response offsets */ 388c2ecf20Sopenharmony_ci#define RESPONSE_ID 0 398c2ecf20Sopenharmony_ci#define RESPONSE_DATA 1 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* Commands */ 428c2ecf20Sopenharmony_ci#define COMMAND_DEACTIVATE 0x00 438c2ecf20Sopenharmony_ci#define COMMAND_INITIALIZE 0x01 448c2ecf20Sopenharmony_ci#define COMMAND_RESOLUTION 0x02 458c2ecf20Sopenharmony_ci#define COMMAND_SETCONFIG 0x03 468c2ecf20Sopenharmony_ci#define COMMAND_DATAREQUEST 0x04 478c2ecf20Sopenharmony_ci#define COMMAND_SCANFREQ 0x08 488c2ecf20Sopenharmony_ci#define COMMAND_STATUS 0X1e 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* 518c2ecf20Sopenharmony_ci * Responses the controller sends as a result of 528c2ecf20Sopenharmony_ci * command requests 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_ci#define RESPONSE_DEACTIVATE 0x00 558c2ecf20Sopenharmony_ci#define RESPONSE_INITIALIZE 0x01 568c2ecf20Sopenharmony_ci#define RESPONSE_RESOLUTION 0x02 578c2ecf20Sopenharmony_ci#define RESPONSE_SETCONFIG 0x03 588c2ecf20Sopenharmony_ci#define RESPONSE_SCANFREQ 0x08 598c2ecf20Sopenharmony_ci#define RESPONSE_STATUS 0X1e 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * Notifications are sent by the touch controller without 638c2ecf20Sopenharmony_ci * being requested by the driver and include for example 648c2ecf20Sopenharmony_ci * touch indications 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_ci#define NOTIFICATION_TOUCH 0x04 678c2ecf20Sopenharmony_ci#define NOTIFICATION_BOOTCOMPLETE 0x07 688c2ecf20Sopenharmony_ci#define NOTIFICATION_OVERRUN 0x25 698c2ecf20Sopenharmony_ci#define NOTIFICATION_PROXIMITY 0x26 708c2ecf20Sopenharmony_ci#define NOTIFICATION_INVALID_COMMAND 0xfe 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#define ZFORCE_REPORT_POINTS 2 738c2ecf20Sopenharmony_ci#define ZFORCE_MAX_AREA 0xff 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#define STATE_DOWN 0 768c2ecf20Sopenharmony_ci#define STATE_MOVE 1 778c2ecf20Sopenharmony_ci#define STATE_UP 2 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci#define SETCONFIG_DUALTOUCH (1 << 0) 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistruct zforce_point { 828c2ecf20Sopenharmony_ci int coord_x; 838c2ecf20Sopenharmony_ci int coord_y; 848c2ecf20Sopenharmony_ci int state; 858c2ecf20Sopenharmony_ci int id; 868c2ecf20Sopenharmony_ci int area_major; 878c2ecf20Sopenharmony_ci int area_minor; 888c2ecf20Sopenharmony_ci int orientation; 898c2ecf20Sopenharmony_ci int pressure; 908c2ecf20Sopenharmony_ci int prblty; 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* 948c2ecf20Sopenharmony_ci * @client the i2c_client 958c2ecf20Sopenharmony_ci * @input the input device 968c2ecf20Sopenharmony_ci * @suspending in the process of going to suspend (don't emit wakeup 978c2ecf20Sopenharmony_ci * events for commands executed to suspend the device) 988c2ecf20Sopenharmony_ci * @suspended device suspended 998c2ecf20Sopenharmony_ci * @access_mutex serialize i2c-access, to keep multipart reads together 1008c2ecf20Sopenharmony_ci * @command_done completion to wait for the command result 1018c2ecf20Sopenharmony_ci * @command_mutex serialize commands sent to the ic 1028c2ecf20Sopenharmony_ci * @command_waiting the id of the command that is currently waiting 1038c2ecf20Sopenharmony_ci * for a result 1048c2ecf20Sopenharmony_ci * @command_result returned result of the command 1058c2ecf20Sopenharmony_ci */ 1068c2ecf20Sopenharmony_cistruct zforce_ts { 1078c2ecf20Sopenharmony_ci struct i2c_client *client; 1088c2ecf20Sopenharmony_ci struct input_dev *input; 1098c2ecf20Sopenharmony_ci const struct zforce_ts_platdata *pdata; 1108c2ecf20Sopenharmony_ci char phys[32]; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci struct regulator *reg_vdd; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci struct gpio_desc *gpio_int; 1158c2ecf20Sopenharmony_ci struct gpio_desc *gpio_rst; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci bool suspending; 1188c2ecf20Sopenharmony_ci bool suspended; 1198c2ecf20Sopenharmony_ci bool boot_complete; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* Firmware version information */ 1228c2ecf20Sopenharmony_ci u16 version_major; 1238c2ecf20Sopenharmony_ci u16 version_minor; 1248c2ecf20Sopenharmony_ci u16 version_build; 1258c2ecf20Sopenharmony_ci u16 version_rev; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci struct mutex access_mutex; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci struct completion command_done; 1308c2ecf20Sopenharmony_ci struct mutex command_mutex; 1318c2ecf20Sopenharmony_ci int command_waiting; 1328c2ecf20Sopenharmony_ci int command_result; 1338c2ecf20Sopenharmony_ci}; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int zforce_command(struct zforce_ts *ts, u8 cmd) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct i2c_client *client = ts->client; 1388c2ecf20Sopenharmony_ci char buf[3]; 1398c2ecf20Sopenharmony_ci int ret; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "%s: 0x%x\n", __func__, cmd); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci buf[0] = FRAME_START; 1448c2ecf20Sopenharmony_ci buf[1] = 1; /* data size, command only */ 1458c2ecf20Sopenharmony_ci buf[2] = cmd; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci mutex_lock(&ts->access_mutex); 1488c2ecf20Sopenharmony_ci ret = i2c_master_send(client, &buf[0], ARRAY_SIZE(buf)); 1498c2ecf20Sopenharmony_ci mutex_unlock(&ts->access_mutex); 1508c2ecf20Sopenharmony_ci if (ret < 0) { 1518c2ecf20Sopenharmony_ci dev_err(&client->dev, "i2c send data request error: %d\n", ret); 1528c2ecf20Sopenharmony_ci return ret; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci return 0; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic void zforce_reset_assert(struct zforce_ts *ts) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(ts->gpio_rst, 1); 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic void zforce_reset_deassert(struct zforce_ts *ts) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(ts->gpio_rst, 0); 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic int zforce_send_wait(struct zforce_ts *ts, const char *buf, int len) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci struct i2c_client *client = ts->client; 1718c2ecf20Sopenharmony_ci int ret; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci ret = mutex_trylock(&ts->command_mutex); 1748c2ecf20Sopenharmony_ci if (!ret) { 1758c2ecf20Sopenharmony_ci dev_err(&client->dev, "already waiting for a command\n"); 1768c2ecf20Sopenharmony_ci return -EBUSY; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "sending %d bytes for command 0x%x\n", 1808c2ecf20Sopenharmony_ci buf[1], buf[2]); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci ts->command_waiting = buf[2]; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci mutex_lock(&ts->access_mutex); 1858c2ecf20Sopenharmony_ci ret = i2c_master_send(client, buf, len); 1868c2ecf20Sopenharmony_ci mutex_unlock(&ts->access_mutex); 1878c2ecf20Sopenharmony_ci if (ret < 0) { 1888c2ecf20Sopenharmony_ci dev_err(&client->dev, "i2c send data request error: %d\n", ret); 1898c2ecf20Sopenharmony_ci goto unlock; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "waiting for result for command 0x%x\n", buf[2]); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (wait_for_completion_timeout(&ts->command_done, WAIT_TIMEOUT) == 0) { 1958c2ecf20Sopenharmony_ci ret = -ETIME; 1968c2ecf20Sopenharmony_ci goto unlock; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci ret = ts->command_result; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ciunlock: 2028c2ecf20Sopenharmony_ci mutex_unlock(&ts->command_mutex); 2038c2ecf20Sopenharmony_ci return ret; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic int zforce_command_wait(struct zforce_ts *ts, u8 cmd) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct i2c_client *client = ts->client; 2098c2ecf20Sopenharmony_ci char buf[3]; 2108c2ecf20Sopenharmony_ci int ret; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "%s: 0x%x\n", __func__, cmd); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci buf[0] = FRAME_START; 2158c2ecf20Sopenharmony_ci buf[1] = 1; /* data size, command only */ 2168c2ecf20Sopenharmony_ci buf[2] = cmd; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci ret = zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf)); 2198c2ecf20Sopenharmony_ci if (ret < 0) { 2208c2ecf20Sopenharmony_ci dev_err(&client->dev, "i2c send data request error: %d\n", ret); 2218c2ecf20Sopenharmony_ci return ret; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci return 0; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic int zforce_resolution(struct zforce_ts *ts, u16 x, u16 y) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci struct i2c_client *client = ts->client; 2308c2ecf20Sopenharmony_ci char buf[7] = { FRAME_START, 5, COMMAND_RESOLUTION, 2318c2ecf20Sopenharmony_ci (x & 0xff), ((x >> 8) & 0xff), 2328c2ecf20Sopenharmony_ci (y & 0xff), ((y >> 8) & 0xff) }; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "set resolution to (%d,%d)\n", x, y); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci return zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf)); 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic int zforce_scan_frequency(struct zforce_ts *ts, u16 idle, u16 finger, 2408c2ecf20Sopenharmony_ci u16 stylus) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci struct i2c_client *client = ts->client; 2438c2ecf20Sopenharmony_ci char buf[9] = { FRAME_START, 7, COMMAND_SCANFREQ, 2448c2ecf20Sopenharmony_ci (idle & 0xff), ((idle >> 8) & 0xff), 2458c2ecf20Sopenharmony_ci (finger & 0xff), ((finger >> 8) & 0xff), 2468c2ecf20Sopenharmony_ci (stylus & 0xff), ((stylus >> 8) & 0xff) }; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci dev_dbg(&client->dev, 2498c2ecf20Sopenharmony_ci "set scan frequency to (idle: %d, finger: %d, stylus: %d)\n", 2508c2ecf20Sopenharmony_ci idle, finger, stylus); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci return zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf)); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic int zforce_setconfig(struct zforce_ts *ts, char b1) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci struct i2c_client *client = ts->client; 2588c2ecf20Sopenharmony_ci char buf[7] = { FRAME_START, 5, COMMAND_SETCONFIG, 2598c2ecf20Sopenharmony_ci b1, 0, 0, 0 }; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "set config to (%d)\n", b1); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci return zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf)); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic int zforce_start(struct zforce_ts *ts) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci struct i2c_client *client = ts->client; 2698c2ecf20Sopenharmony_ci const struct zforce_ts_platdata *pdata = ts->pdata; 2708c2ecf20Sopenharmony_ci int ret; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "starting device\n"); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci ret = zforce_command_wait(ts, COMMAND_INITIALIZE); 2758c2ecf20Sopenharmony_ci if (ret) { 2768c2ecf20Sopenharmony_ci dev_err(&client->dev, "Unable to initialize, %d\n", ret); 2778c2ecf20Sopenharmony_ci return ret; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci ret = zforce_resolution(ts, pdata->x_max, pdata->y_max); 2818c2ecf20Sopenharmony_ci if (ret) { 2828c2ecf20Sopenharmony_ci dev_err(&client->dev, "Unable to set resolution, %d\n", ret); 2838c2ecf20Sopenharmony_ci goto error; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci ret = zforce_scan_frequency(ts, 10, 50, 50); 2878c2ecf20Sopenharmony_ci if (ret) { 2888c2ecf20Sopenharmony_ci dev_err(&client->dev, "Unable to set scan frequency, %d\n", 2898c2ecf20Sopenharmony_ci ret); 2908c2ecf20Sopenharmony_ci goto error; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci ret = zforce_setconfig(ts, SETCONFIG_DUALTOUCH); 2948c2ecf20Sopenharmony_ci if (ret) { 2958c2ecf20Sopenharmony_ci dev_err(&client->dev, "Unable to set config\n"); 2968c2ecf20Sopenharmony_ci goto error; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* start sending touch events */ 3008c2ecf20Sopenharmony_ci ret = zforce_command(ts, COMMAND_DATAREQUEST); 3018c2ecf20Sopenharmony_ci if (ret) { 3028c2ecf20Sopenharmony_ci dev_err(&client->dev, "Unable to request data\n"); 3038c2ecf20Sopenharmony_ci goto error; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci /* 3078c2ecf20Sopenharmony_ci * Per NN, initial cal. take max. of 200msec. 3088c2ecf20Sopenharmony_ci * Allow time to complete this calibration 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_ci msleep(200); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci return 0; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cierror: 3158c2ecf20Sopenharmony_ci zforce_command_wait(ts, COMMAND_DEACTIVATE); 3168c2ecf20Sopenharmony_ci return ret; 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic int zforce_stop(struct zforce_ts *ts) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci struct i2c_client *client = ts->client; 3228c2ecf20Sopenharmony_ci int ret; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "stopping device\n"); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* Deactivates touch sensing and puts the device into sleep. */ 3278c2ecf20Sopenharmony_ci ret = zforce_command_wait(ts, COMMAND_DEACTIVATE); 3288c2ecf20Sopenharmony_ci if (ret != 0) { 3298c2ecf20Sopenharmony_ci dev_err(&client->dev, "could not deactivate device, %d\n", 3308c2ecf20Sopenharmony_ci ret); 3318c2ecf20Sopenharmony_ci return ret; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci return 0; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic int zforce_touch_event(struct zforce_ts *ts, u8 *payload) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct i2c_client *client = ts->client; 3408c2ecf20Sopenharmony_ci const struct zforce_ts_platdata *pdata = ts->pdata; 3418c2ecf20Sopenharmony_ci struct zforce_point point; 3428c2ecf20Sopenharmony_ci int count, i, num = 0; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci count = payload[0]; 3458c2ecf20Sopenharmony_ci if (count > ZFORCE_REPORT_POINTS) { 3468c2ecf20Sopenharmony_ci dev_warn(&client->dev, 3478c2ecf20Sopenharmony_ci "too many coordinates %d, expected max %d\n", 3488c2ecf20Sopenharmony_ci count, ZFORCE_REPORT_POINTS); 3498c2ecf20Sopenharmony_ci count = ZFORCE_REPORT_POINTS; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 3538c2ecf20Sopenharmony_ci point.coord_x = 3548c2ecf20Sopenharmony_ci payload[9 * i + 2] << 8 | payload[9 * i + 1]; 3558c2ecf20Sopenharmony_ci point.coord_y = 3568c2ecf20Sopenharmony_ci payload[9 * i + 4] << 8 | payload[9 * i + 3]; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (point.coord_x > pdata->x_max || 3598c2ecf20Sopenharmony_ci point.coord_y > pdata->y_max) { 3608c2ecf20Sopenharmony_ci dev_warn(&client->dev, "coordinates (%d,%d) invalid\n", 3618c2ecf20Sopenharmony_ci point.coord_x, point.coord_y); 3628c2ecf20Sopenharmony_ci point.coord_x = point.coord_y = 0; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci point.state = payload[9 * i + 5] & 0x0f; 3668c2ecf20Sopenharmony_ci point.id = (payload[9 * i + 5] & 0xf0) >> 4; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci /* determine touch major, minor and orientation */ 3698c2ecf20Sopenharmony_ci point.area_major = max(payload[9 * i + 6], 3708c2ecf20Sopenharmony_ci payload[9 * i + 7]); 3718c2ecf20Sopenharmony_ci point.area_minor = min(payload[9 * i + 6], 3728c2ecf20Sopenharmony_ci payload[9 * i + 7]); 3738c2ecf20Sopenharmony_ci point.orientation = payload[9 * i + 6] > payload[9 * i + 7]; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci point.pressure = payload[9 * i + 8]; 3768c2ecf20Sopenharmony_ci point.prblty = payload[9 * i + 9]; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci dev_dbg(&client->dev, 3798c2ecf20Sopenharmony_ci "point %d/%d: state %d, id %d, pressure %d, prblty %d, x %d, y %d, amajor %d, aminor %d, ori %d\n", 3808c2ecf20Sopenharmony_ci i, count, point.state, point.id, 3818c2ecf20Sopenharmony_ci point.pressure, point.prblty, 3828c2ecf20Sopenharmony_ci point.coord_x, point.coord_y, 3838c2ecf20Sopenharmony_ci point.area_major, point.area_minor, 3848c2ecf20Sopenharmony_ci point.orientation); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* the zforce id starts with "1", so needs to be decreased */ 3878c2ecf20Sopenharmony_ci input_mt_slot(ts->input, point.id - 1); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, 3908c2ecf20Sopenharmony_ci point.state != STATE_UP); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (point.state != STATE_UP) { 3938c2ecf20Sopenharmony_ci input_report_abs(ts->input, ABS_MT_POSITION_X, 3948c2ecf20Sopenharmony_ci point.coord_x); 3958c2ecf20Sopenharmony_ci input_report_abs(ts->input, ABS_MT_POSITION_Y, 3968c2ecf20Sopenharmony_ci point.coord_y); 3978c2ecf20Sopenharmony_ci input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, 3988c2ecf20Sopenharmony_ci point.area_major); 3998c2ecf20Sopenharmony_ci input_report_abs(ts->input, ABS_MT_TOUCH_MINOR, 4008c2ecf20Sopenharmony_ci point.area_minor); 4018c2ecf20Sopenharmony_ci input_report_abs(ts->input, ABS_MT_ORIENTATION, 4028c2ecf20Sopenharmony_ci point.orientation); 4038c2ecf20Sopenharmony_ci num++; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci input_mt_sync_frame(ts->input); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci input_mt_report_finger_count(ts->input, num); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci input_sync(ts->input); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci return 0; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic int zforce_read_packet(struct zforce_ts *ts, u8 *buf) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci struct i2c_client *client = ts->client; 4198c2ecf20Sopenharmony_ci int ret; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci mutex_lock(&ts->access_mutex); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci /* read 2 byte message header */ 4248c2ecf20Sopenharmony_ci ret = i2c_master_recv(client, buf, 2); 4258c2ecf20Sopenharmony_ci if (ret < 0) { 4268c2ecf20Sopenharmony_ci dev_err(&client->dev, "error reading header: %d\n", ret); 4278c2ecf20Sopenharmony_ci goto unlock; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (buf[PAYLOAD_HEADER] != FRAME_START) { 4318c2ecf20Sopenharmony_ci dev_err(&client->dev, "invalid frame start: %d\n", buf[0]); 4328c2ecf20Sopenharmony_ci ret = -EIO; 4338c2ecf20Sopenharmony_ci goto unlock; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (buf[PAYLOAD_LENGTH] == 0) { 4378c2ecf20Sopenharmony_ci dev_err(&client->dev, "invalid payload length: %d\n", 4388c2ecf20Sopenharmony_ci buf[PAYLOAD_LENGTH]); 4398c2ecf20Sopenharmony_ci ret = -EIO; 4408c2ecf20Sopenharmony_ci goto unlock; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci /* read the message */ 4448c2ecf20Sopenharmony_ci ret = i2c_master_recv(client, &buf[PAYLOAD_BODY], buf[PAYLOAD_LENGTH]); 4458c2ecf20Sopenharmony_ci if (ret < 0) { 4468c2ecf20Sopenharmony_ci dev_err(&client->dev, "error reading payload: %d\n", ret); 4478c2ecf20Sopenharmony_ci goto unlock; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "read %d bytes for response command 0x%x\n", 4518c2ecf20Sopenharmony_ci buf[PAYLOAD_LENGTH], buf[PAYLOAD_BODY]); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ciunlock: 4548c2ecf20Sopenharmony_ci mutex_unlock(&ts->access_mutex); 4558c2ecf20Sopenharmony_ci return ret; 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic void zforce_complete(struct zforce_ts *ts, int cmd, int result) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci struct i2c_client *client = ts->client; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if (ts->command_waiting == cmd) { 4638c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "completing command 0x%x\n", cmd); 4648c2ecf20Sopenharmony_ci ts->command_result = result; 4658c2ecf20Sopenharmony_ci complete(&ts->command_done); 4668c2ecf20Sopenharmony_ci } else { 4678c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "command %d not for us\n", cmd); 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic irqreturn_t zforce_irq(int irq, void *dev_id) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci struct zforce_ts *ts = dev_id; 4748c2ecf20Sopenharmony_ci struct i2c_client *client = ts->client; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (ts->suspended && device_may_wakeup(&client->dev)) 4778c2ecf20Sopenharmony_ci pm_wakeup_event(&client->dev, 500); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci return IRQ_WAKE_THREAD; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic irqreturn_t zforce_irq_thread(int irq, void *dev_id) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci struct zforce_ts *ts = dev_id; 4858c2ecf20Sopenharmony_ci struct i2c_client *client = ts->client; 4868c2ecf20Sopenharmony_ci int ret; 4878c2ecf20Sopenharmony_ci u8 payload_buffer[FRAME_MAXSIZE]; 4888c2ecf20Sopenharmony_ci u8 *payload; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci /* 4918c2ecf20Sopenharmony_ci * When still suspended, return. 4928c2ecf20Sopenharmony_ci * Due to the level-interrupt we will get re-triggered later. 4938c2ecf20Sopenharmony_ci */ 4948c2ecf20Sopenharmony_ci if (ts->suspended) { 4958c2ecf20Sopenharmony_ci msleep(20); 4968c2ecf20Sopenharmony_ci return IRQ_HANDLED; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "handling interrupt\n"); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci /* Don't emit wakeup events from commands run by zforce_suspend */ 5028c2ecf20Sopenharmony_ci if (!ts->suspending && device_may_wakeup(&client->dev)) 5038c2ecf20Sopenharmony_ci pm_stay_awake(&client->dev); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* 5068c2ecf20Sopenharmony_ci * Run at least once and exit the loop if 5078c2ecf20Sopenharmony_ci * - the optional interrupt GPIO isn't specified 5088c2ecf20Sopenharmony_ci * (there is only one packet read per ISR invocation, then) 5098c2ecf20Sopenharmony_ci * or 5108c2ecf20Sopenharmony_ci * - the GPIO isn't active any more 5118c2ecf20Sopenharmony_ci * (packet read until the level GPIO indicates that there is 5128c2ecf20Sopenharmony_ci * no IRQ any more) 5138c2ecf20Sopenharmony_ci */ 5148c2ecf20Sopenharmony_ci do { 5158c2ecf20Sopenharmony_ci ret = zforce_read_packet(ts, payload_buffer); 5168c2ecf20Sopenharmony_ci if (ret < 0) { 5178c2ecf20Sopenharmony_ci dev_err(&client->dev, 5188c2ecf20Sopenharmony_ci "could not read packet, ret: %d\n", ret); 5198c2ecf20Sopenharmony_ci break; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci payload = &payload_buffer[PAYLOAD_BODY]; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci switch (payload[RESPONSE_ID]) { 5258c2ecf20Sopenharmony_ci case NOTIFICATION_TOUCH: 5268c2ecf20Sopenharmony_ci /* 5278c2ecf20Sopenharmony_ci * Always report touch-events received while 5288c2ecf20Sopenharmony_ci * suspending, when being a wakeup source 5298c2ecf20Sopenharmony_ci */ 5308c2ecf20Sopenharmony_ci if (ts->suspending && device_may_wakeup(&client->dev)) 5318c2ecf20Sopenharmony_ci pm_wakeup_event(&client->dev, 500); 5328c2ecf20Sopenharmony_ci zforce_touch_event(ts, &payload[RESPONSE_DATA]); 5338c2ecf20Sopenharmony_ci break; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci case NOTIFICATION_BOOTCOMPLETE: 5368c2ecf20Sopenharmony_ci ts->boot_complete = payload[RESPONSE_DATA]; 5378c2ecf20Sopenharmony_ci zforce_complete(ts, payload[RESPONSE_ID], 0); 5388c2ecf20Sopenharmony_ci break; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci case RESPONSE_INITIALIZE: 5418c2ecf20Sopenharmony_ci case RESPONSE_DEACTIVATE: 5428c2ecf20Sopenharmony_ci case RESPONSE_SETCONFIG: 5438c2ecf20Sopenharmony_ci case RESPONSE_RESOLUTION: 5448c2ecf20Sopenharmony_ci case RESPONSE_SCANFREQ: 5458c2ecf20Sopenharmony_ci zforce_complete(ts, payload[RESPONSE_ID], 5468c2ecf20Sopenharmony_ci payload[RESPONSE_DATA]); 5478c2ecf20Sopenharmony_ci break; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci case RESPONSE_STATUS: 5508c2ecf20Sopenharmony_ci /* 5518c2ecf20Sopenharmony_ci * Version Payload Results 5528c2ecf20Sopenharmony_ci * [2:major] [2:minor] [2:build] [2:rev] 5538c2ecf20Sopenharmony_ci */ 5548c2ecf20Sopenharmony_ci ts->version_major = (payload[RESPONSE_DATA + 1] << 8) | 5558c2ecf20Sopenharmony_ci payload[RESPONSE_DATA]; 5568c2ecf20Sopenharmony_ci ts->version_minor = (payload[RESPONSE_DATA + 3] << 8) | 5578c2ecf20Sopenharmony_ci payload[RESPONSE_DATA + 2]; 5588c2ecf20Sopenharmony_ci ts->version_build = (payload[RESPONSE_DATA + 5] << 8) | 5598c2ecf20Sopenharmony_ci payload[RESPONSE_DATA + 4]; 5608c2ecf20Sopenharmony_ci ts->version_rev = (payload[RESPONSE_DATA + 7] << 8) | 5618c2ecf20Sopenharmony_ci payload[RESPONSE_DATA + 6]; 5628c2ecf20Sopenharmony_ci dev_dbg(&ts->client->dev, 5638c2ecf20Sopenharmony_ci "Firmware Version %04x:%04x %04x:%04x\n", 5648c2ecf20Sopenharmony_ci ts->version_major, ts->version_minor, 5658c2ecf20Sopenharmony_ci ts->version_build, ts->version_rev); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci zforce_complete(ts, payload[RESPONSE_ID], 0); 5688c2ecf20Sopenharmony_ci break; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci case NOTIFICATION_INVALID_COMMAND: 5718c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, "invalid command: 0x%x\n", 5728c2ecf20Sopenharmony_ci payload[RESPONSE_DATA]); 5738c2ecf20Sopenharmony_ci break; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci default: 5768c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, 5778c2ecf20Sopenharmony_ci "unrecognized response id: 0x%x\n", 5788c2ecf20Sopenharmony_ci payload[RESPONSE_ID]); 5798c2ecf20Sopenharmony_ci break; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci } while (gpiod_get_value_cansleep(ts->gpio_int)); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (!ts->suspending && device_may_wakeup(&client->dev)) 5848c2ecf20Sopenharmony_ci pm_relax(&client->dev); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "finished interrupt\n"); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci return IRQ_HANDLED; 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cistatic int zforce_input_open(struct input_dev *dev) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci struct zforce_ts *ts = input_get_drvdata(dev); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci return zforce_start(ts); 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cistatic void zforce_input_close(struct input_dev *dev) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci struct zforce_ts *ts = input_get_drvdata(dev); 6018c2ecf20Sopenharmony_ci struct i2c_client *client = ts->client; 6028c2ecf20Sopenharmony_ci int ret; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci ret = zforce_stop(ts); 6058c2ecf20Sopenharmony_ci if (ret) 6068c2ecf20Sopenharmony_ci dev_warn(&client->dev, "stopping zforce failed\n"); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci return; 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_cistatic int __maybe_unused zforce_suspend(struct device *dev) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 6148c2ecf20Sopenharmony_ci struct zforce_ts *ts = i2c_get_clientdata(client); 6158c2ecf20Sopenharmony_ci struct input_dev *input = ts->input; 6168c2ecf20Sopenharmony_ci int ret = 0; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci mutex_lock(&input->mutex); 6198c2ecf20Sopenharmony_ci ts->suspending = true; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci /* 6228c2ecf20Sopenharmony_ci * When configured as a wakeup source device should always wake 6238c2ecf20Sopenharmony_ci * the system, therefore start device if necessary. 6248c2ecf20Sopenharmony_ci */ 6258c2ecf20Sopenharmony_ci if (device_may_wakeup(&client->dev)) { 6268c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "suspend while being a wakeup source\n"); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci /* Need to start device, if not open, to be a wakeup source. */ 6298c2ecf20Sopenharmony_ci if (!input->users) { 6308c2ecf20Sopenharmony_ci ret = zforce_start(ts); 6318c2ecf20Sopenharmony_ci if (ret) 6328c2ecf20Sopenharmony_ci goto unlock; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci enable_irq_wake(client->irq); 6368c2ecf20Sopenharmony_ci } else if (input->users) { 6378c2ecf20Sopenharmony_ci dev_dbg(&client->dev, 6388c2ecf20Sopenharmony_ci "suspend without being a wakeup source\n"); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci ret = zforce_stop(ts); 6418c2ecf20Sopenharmony_ci if (ret) 6428c2ecf20Sopenharmony_ci goto unlock; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci disable_irq(client->irq); 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci ts->suspended = true; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ciunlock: 6508c2ecf20Sopenharmony_ci ts->suspending = false; 6518c2ecf20Sopenharmony_ci mutex_unlock(&input->mutex); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci return ret; 6548c2ecf20Sopenharmony_ci} 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_cistatic int __maybe_unused zforce_resume(struct device *dev) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 6598c2ecf20Sopenharmony_ci struct zforce_ts *ts = i2c_get_clientdata(client); 6608c2ecf20Sopenharmony_ci struct input_dev *input = ts->input; 6618c2ecf20Sopenharmony_ci int ret = 0; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci mutex_lock(&input->mutex); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci ts->suspended = false; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (device_may_wakeup(&client->dev)) { 6688c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "resume from being a wakeup source\n"); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci disable_irq_wake(client->irq); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci /* need to stop device if it was not open on suspend */ 6738c2ecf20Sopenharmony_ci if (!input->users) { 6748c2ecf20Sopenharmony_ci ret = zforce_stop(ts); 6758c2ecf20Sopenharmony_ci if (ret) 6768c2ecf20Sopenharmony_ci goto unlock; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci } else if (input->users) { 6798c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "resume without being a wakeup source\n"); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci enable_irq(client->irq); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci ret = zforce_start(ts); 6848c2ecf20Sopenharmony_ci if (ret < 0) 6858c2ecf20Sopenharmony_ci goto unlock; 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ciunlock: 6898c2ecf20Sopenharmony_ci mutex_unlock(&input->mutex); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci return ret; 6928c2ecf20Sopenharmony_ci} 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(zforce_pm_ops, zforce_suspend, zforce_resume); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_cistatic void zforce_reset(void *data) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci struct zforce_ts *ts = data; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci zforce_reset_assert(ts); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci udelay(10); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci if (!IS_ERR(ts->reg_vdd)) 7058c2ecf20Sopenharmony_ci regulator_disable(ts->reg_vdd); 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic struct zforce_ts_platdata *zforce_parse_dt(struct device *dev) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci struct zforce_ts_platdata *pdata; 7118c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (!np) 7148c2ecf20Sopenharmony_ci return ERR_PTR(-ENOENT); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 7178c2ecf20Sopenharmony_ci if (!pdata) { 7188c2ecf20Sopenharmony_ci dev_err(dev, "failed to allocate platform data\n"); 7198c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "x-size", &pdata->x_max)) { 7238c2ecf20Sopenharmony_ci dev_err(dev, "failed to get x-size property\n"); 7248c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "y-size", &pdata->y_max)) { 7288c2ecf20Sopenharmony_ci dev_err(dev, "failed to get y-size property\n"); 7298c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci return pdata; 7338c2ecf20Sopenharmony_ci} 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_cistatic int zforce_probe(struct i2c_client *client, 7368c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 7378c2ecf20Sopenharmony_ci{ 7388c2ecf20Sopenharmony_ci const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev); 7398c2ecf20Sopenharmony_ci struct zforce_ts *ts; 7408c2ecf20Sopenharmony_ci struct input_dev *input_dev; 7418c2ecf20Sopenharmony_ci int ret; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci if (!pdata) { 7448c2ecf20Sopenharmony_ci pdata = zforce_parse_dt(&client->dev); 7458c2ecf20Sopenharmony_ci if (IS_ERR(pdata)) 7468c2ecf20Sopenharmony_ci return PTR_ERR(pdata); 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci ts = devm_kzalloc(&client->dev, sizeof(struct zforce_ts), GFP_KERNEL); 7508c2ecf20Sopenharmony_ci if (!ts) 7518c2ecf20Sopenharmony_ci return -ENOMEM; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci ts->gpio_rst = devm_gpiod_get_optional(&client->dev, "reset", 7548c2ecf20Sopenharmony_ci GPIOD_OUT_HIGH); 7558c2ecf20Sopenharmony_ci if (IS_ERR(ts->gpio_rst)) { 7568c2ecf20Sopenharmony_ci ret = PTR_ERR(ts->gpio_rst); 7578c2ecf20Sopenharmony_ci dev_err(&client->dev, 7588c2ecf20Sopenharmony_ci "failed to request reset GPIO: %d\n", ret); 7598c2ecf20Sopenharmony_ci return ret; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci if (ts->gpio_rst) { 7638c2ecf20Sopenharmony_ci ts->gpio_int = devm_gpiod_get_optional(&client->dev, "irq", 7648c2ecf20Sopenharmony_ci GPIOD_IN); 7658c2ecf20Sopenharmony_ci if (IS_ERR(ts->gpio_int)) { 7668c2ecf20Sopenharmony_ci ret = PTR_ERR(ts->gpio_int); 7678c2ecf20Sopenharmony_ci dev_err(&client->dev, 7688c2ecf20Sopenharmony_ci "failed to request interrupt GPIO: %d\n", ret); 7698c2ecf20Sopenharmony_ci return ret; 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci } else { 7728c2ecf20Sopenharmony_ci /* 7738c2ecf20Sopenharmony_ci * Deprecated GPIO handling for compatibility 7748c2ecf20Sopenharmony_ci * with legacy binding. 7758c2ecf20Sopenharmony_ci */ 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci /* INT GPIO */ 7788c2ecf20Sopenharmony_ci ts->gpio_int = devm_gpiod_get_index(&client->dev, NULL, 0, 7798c2ecf20Sopenharmony_ci GPIOD_IN); 7808c2ecf20Sopenharmony_ci if (IS_ERR(ts->gpio_int)) { 7818c2ecf20Sopenharmony_ci ret = PTR_ERR(ts->gpio_int); 7828c2ecf20Sopenharmony_ci dev_err(&client->dev, 7838c2ecf20Sopenharmony_ci "failed to request interrupt GPIO: %d\n", ret); 7848c2ecf20Sopenharmony_ci return ret; 7858c2ecf20Sopenharmony_ci } 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci /* RST GPIO */ 7888c2ecf20Sopenharmony_ci ts->gpio_rst = devm_gpiod_get_index(&client->dev, NULL, 1, 7898c2ecf20Sopenharmony_ci GPIOD_OUT_HIGH); 7908c2ecf20Sopenharmony_ci if (IS_ERR(ts->gpio_rst)) { 7918c2ecf20Sopenharmony_ci ret = PTR_ERR(ts->gpio_rst); 7928c2ecf20Sopenharmony_ci dev_err(&client->dev, 7938c2ecf20Sopenharmony_ci "failed to request reset GPIO: %d\n", ret); 7948c2ecf20Sopenharmony_ci return ret; 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci ts->reg_vdd = devm_regulator_get_optional(&client->dev, "vdd"); 7998c2ecf20Sopenharmony_ci if (IS_ERR(ts->reg_vdd)) { 8008c2ecf20Sopenharmony_ci ret = PTR_ERR(ts->reg_vdd); 8018c2ecf20Sopenharmony_ci if (ret == -EPROBE_DEFER) 8028c2ecf20Sopenharmony_ci return ret; 8038c2ecf20Sopenharmony_ci } else { 8048c2ecf20Sopenharmony_ci ret = regulator_enable(ts->reg_vdd); 8058c2ecf20Sopenharmony_ci if (ret) 8068c2ecf20Sopenharmony_ci return ret; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci /* 8098c2ecf20Sopenharmony_ci * according to datasheet add 100us grace time after regular 8108c2ecf20Sopenharmony_ci * regulator enable delay. 8118c2ecf20Sopenharmony_ci */ 8128c2ecf20Sopenharmony_ci udelay(100); 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci ret = devm_add_action(&client->dev, zforce_reset, ts); 8168c2ecf20Sopenharmony_ci if (ret) { 8178c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to register reset action, %d\n", 8188c2ecf20Sopenharmony_ci ret); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci /* hereafter the regulator will be disabled by the action */ 8218c2ecf20Sopenharmony_ci if (!IS_ERR(ts->reg_vdd)) 8228c2ecf20Sopenharmony_ci regulator_disable(ts->reg_vdd); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci return ret; 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci snprintf(ts->phys, sizeof(ts->phys), 8288c2ecf20Sopenharmony_ci "%s/input0", dev_name(&client->dev)); 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci input_dev = devm_input_allocate_device(&client->dev); 8318c2ecf20Sopenharmony_ci if (!input_dev) { 8328c2ecf20Sopenharmony_ci dev_err(&client->dev, "could not allocate input device\n"); 8338c2ecf20Sopenharmony_ci return -ENOMEM; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci mutex_init(&ts->access_mutex); 8378c2ecf20Sopenharmony_ci mutex_init(&ts->command_mutex); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci ts->pdata = pdata; 8408c2ecf20Sopenharmony_ci ts->client = client; 8418c2ecf20Sopenharmony_ci ts->input = input_dev; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci input_dev->name = "Neonode zForce touchscreen"; 8448c2ecf20Sopenharmony_ci input_dev->phys = ts->phys; 8458c2ecf20Sopenharmony_ci input_dev->id.bustype = BUS_I2C; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci input_dev->open = zforce_input_open; 8488c2ecf20Sopenharmony_ci input_dev->close = zforce_input_close; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci __set_bit(EV_KEY, input_dev->evbit); 8518c2ecf20Sopenharmony_ci __set_bit(EV_SYN, input_dev->evbit); 8528c2ecf20Sopenharmony_ci __set_bit(EV_ABS, input_dev->evbit); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci /* For multi touch */ 8558c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, 8568c2ecf20Sopenharmony_ci pdata->x_max, 0, 0); 8578c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, 8588c2ecf20Sopenharmony_ci pdata->y_max, 0, 0); 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 8618c2ecf20Sopenharmony_ci ZFORCE_MAX_AREA, 0, 0); 8628c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0, 8638c2ecf20Sopenharmony_ci ZFORCE_MAX_AREA, 0, 0); 8648c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0); 8658c2ecf20Sopenharmony_ci input_mt_init_slots(input_dev, ZFORCE_REPORT_POINTS, INPUT_MT_DIRECT); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci input_set_drvdata(ts->input, ts); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci init_completion(&ts->command_done); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci /* 8728c2ecf20Sopenharmony_ci * The zforce pulls the interrupt low when it has data ready. 8738c2ecf20Sopenharmony_ci * After it is triggered the isr thread runs until all the available 8748c2ecf20Sopenharmony_ci * packets have been read and the interrupt is high again. 8758c2ecf20Sopenharmony_ci * Therefore we can trigger the interrupt anytime it is low and do 8768c2ecf20Sopenharmony_ci * not need to limit it to the interrupt edge. 8778c2ecf20Sopenharmony_ci */ 8788c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(&client->dev, client->irq, 8798c2ecf20Sopenharmony_ci zforce_irq, zforce_irq_thread, 8808c2ecf20Sopenharmony_ci IRQF_TRIGGER_LOW | IRQF_ONESHOT, 8818c2ecf20Sopenharmony_ci input_dev->name, ts); 8828c2ecf20Sopenharmony_ci if (ret) { 8838c2ecf20Sopenharmony_ci dev_err(&client->dev, "irq %d request failed\n", client->irq); 8848c2ecf20Sopenharmony_ci return ret; 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci i2c_set_clientdata(client, ts); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci /* let the controller boot */ 8908c2ecf20Sopenharmony_ci zforce_reset_deassert(ts); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci ts->command_waiting = NOTIFICATION_BOOTCOMPLETE; 8938c2ecf20Sopenharmony_ci if (wait_for_completion_timeout(&ts->command_done, WAIT_TIMEOUT) == 0) 8948c2ecf20Sopenharmony_ci dev_warn(&client->dev, "bootcomplete timed out\n"); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci /* need to start device to get version information */ 8978c2ecf20Sopenharmony_ci ret = zforce_command_wait(ts, COMMAND_INITIALIZE); 8988c2ecf20Sopenharmony_ci if (ret) { 8998c2ecf20Sopenharmony_ci dev_err(&client->dev, "unable to initialize, %d\n", ret); 9008c2ecf20Sopenharmony_ci return ret; 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci /* this gets the firmware version among other information */ 9048c2ecf20Sopenharmony_ci ret = zforce_command_wait(ts, COMMAND_STATUS); 9058c2ecf20Sopenharmony_ci if (ret < 0) { 9068c2ecf20Sopenharmony_ci dev_err(&client->dev, "couldn't get status, %d\n", ret); 9078c2ecf20Sopenharmony_ci zforce_stop(ts); 9088c2ecf20Sopenharmony_ci return ret; 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci /* stop device and put it into sleep until it is opened */ 9128c2ecf20Sopenharmony_ci ret = zforce_stop(ts); 9138c2ecf20Sopenharmony_ci if (ret < 0) 9148c2ecf20Sopenharmony_ci return ret; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci device_set_wakeup_capable(&client->dev, true); 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci ret = input_register_device(input_dev); 9198c2ecf20Sopenharmony_ci if (ret) { 9208c2ecf20Sopenharmony_ci dev_err(&client->dev, "could not register input device, %d\n", 9218c2ecf20Sopenharmony_ci ret); 9228c2ecf20Sopenharmony_ci return ret; 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci return 0; 9268c2ecf20Sopenharmony_ci} 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_cistatic struct i2c_device_id zforce_idtable[] = { 9298c2ecf20Sopenharmony_ci { "zforce-ts", 0 }, 9308c2ecf20Sopenharmony_ci { } 9318c2ecf20Sopenharmony_ci}; 9328c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, zforce_idtable); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 9358c2ecf20Sopenharmony_cistatic const struct of_device_id zforce_dt_idtable[] = { 9368c2ecf20Sopenharmony_ci { .compatible = "neonode,zforce" }, 9378c2ecf20Sopenharmony_ci {}, 9388c2ecf20Sopenharmony_ci}; 9398c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, zforce_dt_idtable); 9408c2ecf20Sopenharmony_ci#endif 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_cistatic struct i2c_driver zforce_driver = { 9438c2ecf20Sopenharmony_ci .driver = { 9448c2ecf20Sopenharmony_ci .name = "zforce-ts", 9458c2ecf20Sopenharmony_ci .pm = &zforce_pm_ops, 9468c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(zforce_dt_idtable), 9478c2ecf20Sopenharmony_ci }, 9488c2ecf20Sopenharmony_ci .probe = zforce_probe, 9498c2ecf20Sopenharmony_ci .id_table = zforce_idtable, 9508c2ecf20Sopenharmony_ci}; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_cimodule_i2c_driver(zforce_driver); 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ciMODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); 9558c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("zForce TouchScreen Driver"); 9568c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 957