summaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
authorMarek Vasut <marex@denx.de>2019-02-07 01:02:02 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2019-02-07 01:18:16 -0500
commit4958891764749304ac1511f6140ae3888c088e23 (patch)
tree5576aa02834b31131494599d12c94b00d20849a3 /drivers/input
parentc5d0e4b5154ac81cffdf6472d5f5e1408faa8ccd (diff)
Input: ili210x - add ILI251X support
Add support for ILI251x touch controller. This controller is similar to the ILI210x, except for the following differences: - Does not support I2C R-W transfer, Read must be followed by an obscenely long delay, and then followed by Write - Does support 10 simultaneous touch inputs. - Touch data format is slightly different, pressure reporting does not work although the touch data contain such information. Signed-off-by: Marek Vasut <marex@denx.de> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/touchscreen/ili210x.c118
1 files changed, 103 insertions, 15 deletions
diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c
index 4e550fe0cb15..6cfe463ac118 100644
--- a/drivers/input/touchscreen/ili210x.c
+++ b/drivers/input/touchscreen/ili210x.c
@@ -7,9 +7,11 @@
7#include <linux/delay.h> 7#include <linux/delay.h>
8#include <linux/workqueue.h> 8#include <linux/workqueue.h>
9#include <linux/gpio/consumer.h> 9#include <linux/gpio/consumer.h>
10#include <linux/of_device.h>
10#include <asm/unaligned.h> 11#include <asm/unaligned.h>
11 12
12#define MAX_TOUCHES 2 13#define ILI210X_TOUCHES 2
14#define ILI251X_TOUCHES 10
13#define DEFAULT_POLL_PERIOD 20 15#define DEFAULT_POLL_PERIOD 20
14 16
15/* Touchscreen commands */ 17/* Touchscreen commands */
@@ -33,17 +35,25 @@ struct firmware_version {
33 u8 minor; 35 u8 minor;
34} __packed; 36} __packed;
35 37
38enum ili2xxx_model {
39 MODEL_ILI210X,
40 MODEL_ILI251X,
41};
42
36struct ili210x { 43struct ili210x {
37 struct i2c_client *client; 44 struct i2c_client *client;
38 struct input_dev *input; 45 struct input_dev *input;
39 unsigned int poll_period; 46 unsigned int poll_period;
40 struct delayed_work dwork; 47 struct delayed_work dwork;
41 struct gpio_desc *reset_gpio; 48 struct gpio_desc *reset_gpio;
49 enum ili2xxx_model model;
50 unsigned int max_touches;
42}; 51};
43 52
44static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf, 53static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf,
45 size_t len) 54 size_t len)
46{ 55{
56 struct ili210x *priv = i2c_get_clientdata(client);
47 struct i2c_msg msg[2] = { 57 struct i2c_msg msg[2] = {
48 { 58 {
49 .addr = client->addr, 59 .addr = client->addr,
@@ -59,7 +69,38 @@ static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf,
59 } 69 }
60 }; 70 };
61 71
62 if (i2c_transfer(client->adapter, msg, 2) != 2) { 72 if (priv->model == MODEL_ILI251X) {
73 if (i2c_transfer(client->adapter, msg, 1) != 1) {
74 dev_err(&client->dev, "i2c transfer failed\n");
75 return -EIO;
76 }
77
78 usleep_range(5000, 5500);
79
80 if (i2c_transfer(client->adapter, msg + 1, 1) != 1) {
81 dev_err(&client->dev, "i2c transfer failed\n");
82 return -EIO;
83 }
84 } else {
85 if (i2c_transfer(client->adapter, msg, 2) != 2) {
86 dev_err(&client->dev, "i2c transfer failed\n");
87 return -EIO;
88 }
89 }
90
91 return 0;
92}
93
94static int ili210x_read(struct i2c_client *client, void *buf, size_t len)
95{
96 struct i2c_msg msg = {
97 .addr = client->addr,
98 .flags = I2C_M_RD,
99 .len = len,
100 .buf = buf,
101 };
102
103 if (i2c_transfer(client->adapter, &msg, 1) != 1) {
63 dev_err(&client->dev, "i2c transfer failed\n"); 104 dev_err(&client->dev, "i2c transfer failed\n");
64 return -EIO; 105 return -EIO;
65 } 106 }
@@ -71,7 +112,7 @@ static bool ili210x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata,
71 unsigned int finger, 112 unsigned int finger,
72 unsigned int *x, unsigned int *y) 113 unsigned int *x, unsigned int *y)
73{ 114{
74 if (finger >= MAX_TOUCHES) 115 if (finger >= ILI210X_TOUCHES)
75 return false; 116 return false;
76 117
77 if (touchdata[0] & BIT(finger)) 118 if (touchdata[0] & BIT(finger))
@@ -83,17 +124,43 @@ static bool ili210x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata,
83 return true; 124 return true;
84} 125}
85 126
127static bool ili251x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata,
128 unsigned int finger,
129 unsigned int *x, unsigned int *y)
130{
131 if (finger >= ILI251X_TOUCHES)
132 return false;
133
134 *x = get_unaligned_be16(touchdata + 1 + (finger * 5) + 0);
135 if (!(*x & BIT(15))) /* Touch indication */
136 return false;
137
138 *x &= 0x3fff;
139 *y = get_unaligned_be16(touchdata + 1 + (finger * 5) + 2);
140
141 return true;
142}
143
86static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata) 144static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata)
87{ 145{
88 struct input_dev *input = priv->input; 146 struct input_dev *input = priv->input;
89 int i; 147 int i;
90 bool touch; 148 bool contact = false, touch = false;
91 unsigned int x, y; 149 unsigned int x = 0, y = 0;
92 150
93 for (i = 0; i < MAX_TOUCHES; i++) { 151 for (i = 0; i < priv->max_touches; i++) {
94 input_mt_slot(input, i); 152 input_mt_slot(input, i);
95 153
96 touch = ili210x_touchdata_to_coords(priv, touchdata, i, &x, &y); 154 if (priv->model == MODEL_ILI210X) {
155 touch = ili210x_touchdata_to_coords(priv, touchdata,
156 i, &x, &y);
157 } else if (priv->model == MODEL_ILI251X) {
158 touch = ili251x_touchdata_to_coords(priv, touchdata,
159 i, &x, &y);
160 if (touch)
161 contact = true;
162 }
163
97 input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); 164 input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
98 if (touch) { 165 if (touch) {
99 input_report_abs(input, ABS_MT_POSITION_X, x); 166 input_report_abs(input, ABS_MT_POSITION_X, x);
@@ -104,7 +171,10 @@ static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata)
104 input_mt_report_pointer_emulation(input, false); 171 input_mt_report_pointer_emulation(input, false);
105 input_sync(input); 172 input_sync(input);
106 173
107 return touchdata[0] & 0xf3; 174 if (priv->model == MODEL_ILI210X)
175 contact = touchdata[0] & 0xf3;
176
177 return contact;
108} 178}
109 179
110static void ili210x_work(struct work_struct *work) 180static void ili210x_work(struct work_struct *work)
@@ -112,12 +182,20 @@ static void ili210x_work(struct work_struct *work)
112 struct ili210x *priv = container_of(work, struct ili210x, 182 struct ili210x *priv = container_of(work, struct ili210x,
113 dwork.work); 183 dwork.work);
114 struct i2c_client *client = priv->client; 184 struct i2c_client *client = priv->client;
115 u8 touchdata[1 + 4 * MAX_TOUCHES]; 185 u8 touchdata[64] = { 0 };
116 bool touch; 186 bool touch;
117 int error; 187 int error = -EINVAL;
188
189 if (priv->model == MODEL_ILI210X) {
190 error = ili210x_read_reg(client, REG_TOUCHDATA,
191 touchdata, sizeof(touchdata));
192 } else if (priv->model == MODEL_ILI251X) {
193 error = ili210x_read_reg(client, REG_TOUCHDATA,
194 touchdata, 31);
195 if (!error && touchdata[0] == 2)
196 error = ili210x_read(client, &touchdata[31], 20);
197 }
118 198
119 error = ili210x_read_reg(client, REG_TOUCHDATA,
120 touchdata, sizeof(touchdata));
121 if (error) { 199 if (error) {
122 dev_err(&client->dev, 200 dev_err(&client->dev,
123 "Unable to get touchdata, err = %d\n", error); 201 "Unable to get touchdata, err = %d\n", error);
@@ -198,9 +276,12 @@ static int ili210x_i2c_probe(struct i2c_client *client,
198 struct input_dev *input; 276 struct input_dev *input;
199 struct panel_info panel; 277 struct panel_info panel;
200 struct firmware_version firmware; 278 struct firmware_version firmware;
279 enum ili2xxx_model model;
201 int xmax, ymax; 280 int xmax, ymax;
202 int error; 281 int error;
203 282
283 model = (enum ili2xxx_model)id->driver_data;
284
204 dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver"); 285 dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver");
205 286
206 if (client->irq <= 0) { 287 if (client->irq <= 0) {
@@ -236,6 +317,11 @@ static int ili210x_i2c_probe(struct i2c_client *client,
236 priv->poll_period = DEFAULT_POLL_PERIOD; 317 priv->poll_period = DEFAULT_POLL_PERIOD;
237 INIT_DELAYED_WORK(&priv->dwork, ili210x_work); 318 INIT_DELAYED_WORK(&priv->dwork, ili210x_work);
238 priv->reset_gpio = reset_gpio; 319 priv->reset_gpio = reset_gpio;
320 priv->model = model;
321 if (model == MODEL_ILI210X)
322 priv->max_touches = ILI210X_TOUCHES;
323 if (model == MODEL_ILI251X)
324 priv->max_touches = ILI251X_TOUCHES;
239 325
240 i2c_set_clientdata(client, priv); 326 i2c_set_clientdata(client, priv);
241 327
@@ -274,7 +360,7 @@ static int ili210x_i2c_probe(struct i2c_client *client,
274 input_set_abs_params(input, ABS_Y, 0, ymax, 0, 0); 360 input_set_abs_params(input, ABS_Y, 0, ymax, 0, 0);
275 361
276 /* Multi touch */ 362 /* Multi touch */
277 input_mt_init_slots(input, MAX_TOUCHES, 0); 363 input_mt_init_slots(input, priv->max_touches, 0);
278 input_set_abs_params(input, ABS_MT_POSITION_X, 0, xmax, 0, 0); 364 input_set_abs_params(input, ABS_MT_POSITION_X, 0, xmax, 0, 0);
279 input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ymax, 0, 0); 365 input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ymax, 0, 0);
280 366
@@ -347,13 +433,15 @@ static SIMPLE_DEV_PM_OPS(ili210x_i2c_pm,
347 ili210x_i2c_suspend, ili210x_i2c_resume); 433 ili210x_i2c_suspend, ili210x_i2c_resume);
348 434
349static const struct i2c_device_id ili210x_i2c_id[] = { 435static const struct i2c_device_id ili210x_i2c_id[] = {
350 { "ili210x", 0 }, 436 { "ili210x", MODEL_ILI210X },
437 { "ili251x", MODEL_ILI251X },
351 { } 438 { }
352}; 439};
353MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id); 440MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id);
354 441
355static const struct of_device_id ili210x_dt_ids[] = { 442static const struct of_device_id ili210x_dt_ids[] = {
356 { .compatible = "ilitek,ili210x", }, 443 { .compatible = "ilitek,ili210x", .data = (void *)MODEL_ILI210X },
444 { .compatible = "ilitek,ili251x", .data = (void *)MODEL_ILI251X },
357 { }, 445 { },
358}; 446};
359MODULE_DEVICE_TABLE(of, ili210x_dt_ids); 447MODULE_DEVICE_TABLE(of, ili210x_dt_ids);