]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - drivers/input/touchscreen/ili210x.c
Input: ili210x - reorder probe
[mirror_ubuntu-hirsute-kernel.git] / drivers / input / touchscreen / ili210x.c
CommitLineData
5c6a7a62
OS
1#include <linux/module.h>
2#include <linux/i2c.h>
3#include <linux/interrupt.h>
4#include <linux/slab.h>
5#include <linux/input.h>
6#include <linux/input/mt.h>
7#include <linux/delay.h>
8#include <linux/workqueue.h>
201f3c80 9#include <linux/gpio/consumer.h>
e3559442 10#include <asm/unaligned.h>
5c6a7a62
OS
11
12#define MAX_TOUCHES 2
13#define DEFAULT_POLL_PERIOD 20
14
15/* Touchscreen commands */
16#define REG_TOUCHDATA 0x10
17#define REG_PANEL_INFO 0x20
18#define REG_FIRMWARE_VERSION 0x40
19#define REG_CALIBRATE 0xcc
20
e3559442 21struct panel_info {
5c6a7a62
OS
22 u8 x_low;
23 u8 x_high;
24 u8 y_low;
25 u8 y_high;
5c6a7a62
OS
26 u8 xchannel_num;
27 u8 ychannel_num;
28} __packed;
29
30struct firmware_version {
31 u8 id;
32 u8 major;
33 u8 minor;
34} __packed;
35
36struct ili210x {
37 struct i2c_client *client;
38 struct input_dev *input;
5c6a7a62
OS
39 unsigned int poll_period;
40 struct delayed_work dwork;
201f3c80 41 struct gpio_desc *reset_gpio;
5c6a7a62
OS
42};
43
44static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf,
45 size_t len)
46{
47 struct i2c_msg msg[2] = {
48 {
49 .addr = client->addr,
50 .flags = 0,
51 .len = 1,
52 .buf = &reg,
53 },
54 {
55 .addr = client->addr,
56 .flags = I2C_M_RD,
57 .len = len,
58 .buf = buf,
59 }
60 };
61
62 if (i2c_transfer(client->adapter, msg, 2) != 2) {
63 dev_err(&client->dev, "i2c transfer failed\n");
64 return -EIO;
65 }
66
67 return 0;
68}
69
e3559442
MV
70static bool ili210x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata,
71 unsigned int finger,
72 unsigned int *x, unsigned int *y)
73{
74 if (finger >= MAX_TOUCHES)
75 return false;
76
77 if (touchdata[0] & BIT(finger))
78 return false;
79
80 *x = get_unaligned_be16(touchdata + 1 + (finger * 4) + 0);
81 *y = get_unaligned_be16(touchdata + 1 + (finger * 4) + 2);
82
83 return true;
84}
85
86static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata)
5c6a7a62 87{
e3559442 88 struct input_dev *input = priv->input;
5c6a7a62
OS
89 int i;
90 bool touch;
91 unsigned int x, y;
5c6a7a62
OS
92
93 for (i = 0; i < MAX_TOUCHES; i++) {
94 input_mt_slot(input, i);
95
e3559442 96 touch = ili210x_touchdata_to_coords(priv, touchdata, i, &x, &y);
5c6a7a62
OS
97 input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
98 if (touch) {
5c6a7a62
OS
99 input_report_abs(input, ABS_MT_POSITION_X, x);
100 input_report_abs(input, ABS_MT_POSITION_Y, y);
101 }
102 }
103
104 input_mt_report_pointer_emulation(input, false);
105 input_sync(input);
e3559442
MV
106
107 return touchdata[0] & 0xf3;
5c6a7a62
OS
108}
109
5c6a7a62
OS
110static void ili210x_work(struct work_struct *work)
111{
112 struct ili210x *priv = container_of(work, struct ili210x,
113 dwork.work);
114 struct i2c_client *client = priv->client;
e3559442
MV
115 u8 touchdata[1 + 4 * MAX_TOUCHES];
116 bool touch;
5c6a7a62
OS
117 int error;
118
119 error = ili210x_read_reg(client, REG_TOUCHDATA,
e3559442 120 touchdata, sizeof(touchdata));
5c6a7a62
OS
121 if (error) {
122 dev_err(&client->dev,
123 "Unable to get touchdata, err = %d\n", error);
124 return;
125 }
126
e3559442 127 touch = ili210x_report_events(priv, touchdata);
5c6a7a62 128
e3559442 129 if (touch)
5c6a7a62
OS
130 schedule_delayed_work(&priv->dwork,
131 msecs_to_jiffies(priv->poll_period));
132}
133
134static irqreturn_t ili210x_irq(int irq, void *irq_data)
135{
136 struct ili210x *priv = irq_data;
137
138 schedule_delayed_work(&priv->dwork, 0);
139
140 return IRQ_HANDLED;
141}
142
143static ssize_t ili210x_calibrate(struct device *dev,
144 struct device_attribute *attr,
145 const char *buf, size_t count)
146{
147 struct i2c_client *client = to_i2c_client(dev);
148 struct ili210x *priv = i2c_get_clientdata(client);
149 unsigned long calibrate;
150 int rc;
151 u8 cmd = REG_CALIBRATE;
152
153 if (kstrtoul(buf, 10, &calibrate))
154 return -EINVAL;
155
156 if (calibrate > 1)
157 return -EINVAL;
158
159 if (calibrate) {
160 rc = i2c_master_send(priv->client, &cmd, sizeof(cmd));
161 if (rc != sizeof(cmd))
162 return -EIO;
163 }
164
165 return count;
166}
b27c0d0c 167static DEVICE_ATTR(calibrate, S_IWUSR, NULL, ili210x_calibrate);
5c6a7a62
OS
168
169static struct attribute *ili210x_attributes[] = {
170 &dev_attr_calibrate.attr,
171 NULL,
172};
173
174static const struct attribute_group ili210x_attr_group = {
175 .attrs = ili210x_attributes,
176};
177
201f3c80
MV
178static void ili210x_power_down(void *data)
179{
180 struct gpio_desc *reset_gpio = data;
181
182 gpiod_set_value_cansleep(reset_gpio, 1);
183}
184
1bdec5d9
MV
185static void ili210x_cancel_work(void *data)
186{
187 struct ili210x *priv = data;
188
189 cancel_delayed_work_sync(&priv->dwork);
190}
191
5298cc4c 192static int ili210x_i2c_probe(struct i2c_client *client,
5c6a7a62
OS
193 const struct i2c_device_id *id)
194{
195 struct device *dev = &client->dev;
5c6a7a62 196 struct ili210x *priv;
201f3c80 197 struct gpio_desc *reset_gpio;
5c6a7a62
OS
198 struct input_dev *input;
199 struct panel_info panel;
200 struct firmware_version firmware;
201 int xmax, ymax;
202 int error;
203
204 dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver");
205
5c6a7a62
OS
206 if (client->irq <= 0) {
207 dev_err(dev, "No IRQ!\n");
208 return -EINVAL;
209 }
210
201f3c80
MV
211 reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
212 if (IS_ERR(reset_gpio))
213 return PTR_ERR(reset_gpio);
214
215 if (reset_gpio) {
216 error = devm_add_action_or_reset(dev, ili210x_power_down,
217 reset_gpio);
218 if (error)
219 return error;
220
221 usleep_range(50, 100);
222 gpiod_set_value_cansleep(reset_gpio, 0);
223 msleep(100);
224 }
225
12294577
MV
226 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
227 if (!priv)
228 return -ENOMEM;
229
230 input = devm_input_allocate_device(dev);
231 if (!input)
232 return -ENOMEM;
233
234 priv->client = client;
235 priv->input = input;
236 priv->poll_period = DEFAULT_POLL_PERIOD;
237 INIT_DELAYED_WORK(&priv->dwork, ili210x_work);
238 priv->reset_gpio = reset_gpio;
239
240 i2c_set_clientdata(client, priv);
241
5c6a7a62
OS
242 /* Get firmware version */
243 error = ili210x_read_reg(client, REG_FIRMWARE_VERSION,
244 &firmware, sizeof(firmware));
245 if (error) {
246 dev_err(dev, "Failed to get firmware version, err: %d\n",
247 error);
248 return error;
249 }
250
251 /* get panel info */
252 error = ili210x_read_reg(client, REG_PANEL_INFO, &panel, sizeof(panel));
253 if (error) {
971bd8fa 254 dev_err(dev, "Failed to get panel information, err: %d\n",
5c6a7a62
OS
255 error);
256 return error;
257 }
258
e3559442
MV
259 xmax = panel.x_low | (panel.x_high << 8);
260 ymax = panel.y_low | (panel.y_high << 8);
5c6a7a62 261
5c6a7a62
OS
262 /* Setup input device */
263 input->name = "ILI210x Touchscreen";
264 input->id.bustype = BUS_I2C;
265 input->dev.parent = dev;
266
267 __set_bit(EV_SYN, input->evbit);
268 __set_bit(EV_KEY, input->evbit);
269 __set_bit(EV_ABS, input->evbit);
270 __set_bit(BTN_TOUCH, input->keybit);
271
272 /* Single touch */
273 input_set_abs_params(input, ABS_X, 0, xmax, 0, 0);
274 input_set_abs_params(input, ABS_Y, 0, ymax, 0, 0);
275
276 /* Multi touch */
b4adbbef 277 input_mt_init_slots(input, MAX_TOUCHES, 0);
5c6a7a62
OS
278 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);
280
1bdec5d9
MV
281 error = devm_add_action(dev, ili210x_cancel_work, priv);
282 if (error)
283 return error;
284
285 error = devm_request_irq(dev, client->irq, ili210x_irq, 0,
286 client->name, priv);
5c6a7a62
OS
287 if (error) {
288 dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n",
289 error);
1bdec5d9 290 return error;
5c6a7a62
OS
291 }
292
293 error = sysfs_create_group(&dev->kobj, &ili210x_attr_group);
294 if (error) {
295 dev_err(dev, "Unable to create sysfs attributes, err: %d\n",
296 error);
1bdec5d9 297 return error;
5c6a7a62
OS
298 }
299
300 error = input_register_device(priv->input);
301 if (error) {
971bd8fa 302 dev_err(dev, "Cannot register input device, err: %d\n", error);
5c6a7a62
OS
303 goto err_remove_sysfs;
304 }
305
d7ddf154 306 device_init_wakeup(dev, 1);
5c6a7a62
OS
307
308 dev_dbg(dev,
309 "ILI210x initialized (IRQ: %d), firmware version %d.%d.%d",
310 client->irq, firmware.id, firmware.major, firmware.minor);
311
312 return 0;
313
314err_remove_sysfs:
315 sysfs_remove_group(&dev->kobj, &ili210x_attr_group);
5c6a7a62
OS
316 return error;
317}
318
e2619cf7 319static int ili210x_i2c_remove(struct i2c_client *client)
5c6a7a62 320{
5c6a7a62 321 sysfs_remove_group(&client->dev.kobj, &ili210x_attr_group);
5c6a7a62
OS
322
323 return 0;
324}
325
02b6a58b 326static int __maybe_unused ili210x_i2c_suspend(struct device *dev)
5c6a7a62
OS
327{
328 struct i2c_client *client = to_i2c_client(dev);
329
330 if (device_may_wakeup(&client->dev))
331 enable_irq_wake(client->irq);
332
333 return 0;
334}
335
02b6a58b 336static int __maybe_unused ili210x_i2c_resume(struct device *dev)
5c6a7a62
OS
337{
338 struct i2c_client *client = to_i2c_client(dev);
339
340 if (device_may_wakeup(&client->dev))
341 disable_irq_wake(client->irq);
342
343 return 0;
344}
5c6a7a62
OS
345
346static SIMPLE_DEV_PM_OPS(ili210x_i2c_pm,
347 ili210x_i2c_suspend, ili210x_i2c_resume);
348
349static const struct i2c_device_id ili210x_i2c_id[] = {
350 { "ili210x", 0 },
351 { }
352};
353MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id);
354
355static struct i2c_driver ili210x_ts_driver = {
356 .driver = {
357 .name = "ili210x_i2c",
5c6a7a62
OS
358 .pm = &ili210x_i2c_pm,
359 },
360 .id_table = ili210x_i2c_id,
361 .probe = ili210x_i2c_probe,
1cb0aa88 362 .remove = ili210x_i2c_remove,
5c6a7a62
OS
363};
364
365module_i2c_driver(ili210x_ts_driver);
366
367MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>");
368MODULE_DESCRIPTION("ILI210X I2C Touchscreen Driver");
369MODULE_LICENSE("GPL");