aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJelle van der Waa <jelle@vdwaa.nl>2017-01-14 13:25:02 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2017-02-09 16:54:51 -0500
commit83f66a6f08fa4004d6fb9d50c57735067bbbb405 (patch)
tree006b080925a040a0bcfa9cafdcef85931e5e619f
parent45536d373a21d441bd488f618b6e3e9bfae839f3 (diff)
Input: add driver for Zeitec ZET6223
This is a basic driver for the Zeitec ZET6223 I2C touchscreen controllers. The driver does not support firmware loading, which is not required for all tablets which contain this chip. Signed-off-by: Jelle van der Waa <jelle@vdwaa.nl> Acked-by: Rob Herring <robh@kernel.org> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/zet6223.txt32
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt1
-rw-r--r--drivers/input/touchscreen/Kconfig11
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/zet6223.c267
5 files changed, 312 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/input/touchscreen/zet6223.txt b/Documentation/devicetree/bindings/input/touchscreen/zet6223.txt
new file mode 100644
index 000000000000..fe6a1feef703
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/zet6223.txt
@@ -0,0 +1,32 @@
1Zeitec ZET6223 I2C touchscreen controller
2
3Required properties:
4- compatible : "zeitec,zet6223"
5- reg : I2C slave address of the chip (0x76)
6- interrupt-parent : a phandle pointing to the interrupt controller
7 serving the interrupt for this chip
8- interrupts : interrupt specification for the zet6223 interrupt
9
10Optional properties:
11
12- vio-supply : Specification for VIO supply (1.8V or 3.3V,
13 depending on system interface needs).
14- vcc-supply : Specification for 3.3V VCC supply.
15- touchscreen-size-x : See touchscreen.txt
16- touchscreen-size-y : See touchscreen.txt
17- touchscreen-inverted-x : See touchscreen.txt
18- touchscreen-inverted-y : See touchscreen.txt
19- touchscreen-swapped-x-y : See touchscreen.txt
20
21Example:
22
23i2c@00000000 {
24
25 zet6223: touchscreen@76 {
26 compatible = "zeitec,zet6223";
27 reg = <0x76>;
28 interrupt-parent = <&pio>;
29 interrupts = <6 11 IRQ_TYPE_EDGE_FALLING>
30 };
31
32};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 16d3b5e7f5d1..e6f63f4a0d6d 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -329,6 +329,7 @@ xes Extreme Engineering Solutions (X-ES)
329xillybus Xillybus Ltd. 329xillybus Xillybus Ltd.
330xlnx Xilinx 330xlnx Xilinx
331zarlink Zarlink Semiconductor 331zarlink Zarlink Semiconductor
332zeitec ZEITEC Semiconductor Co., LTD.
332zii Zodiac Inflight Innovations 333zii Zodiac Inflight Innovations
333zte ZTE Corp. 334zte ZTE Corp.
334zyxel ZyXEL Communications Corp. 335zyxel ZyXEL Communications Corp.
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 8650c94e29d0..033599777651 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -1165,6 +1165,17 @@ config TOUCHSCREEN_TPS6507X
1165 To compile this driver as a module, choose M here: the 1165 To compile this driver as a module, choose M here: the
1166 module will be called tps6507x_ts. 1166 module will be called tps6507x_ts.
1167 1167
1168config TOUCHSCREEN_ZET6223
1169 tristate "Zeitec ZET6223 touchscreen driver"
1170 depends on I2C
1171 help
1172 Say Y here if you have a touchscreen using Zeitec ZET6223
1173
1174 If unsure, say N.
1175
1176 To compile this driver as a module, choose M here: the
1177 module will be called zet6223.
1178
1168config TOUCHSCREEN_ZFORCE 1179config TOUCHSCREEN_ZFORCE
1169 tristate "Neonode zForce infrared touchscreens" 1180 tristate "Neonode zForce infrared touchscreens"
1170 depends on I2C 1181 depends on I2C
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index e41e3c7aa427..b622e5344137 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -95,6 +95,7 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
95obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o 95obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
96obj-$(CONFIG_TOUCHSCREEN_SX8654) += sx8654.o 96obj-$(CONFIG_TOUCHSCREEN_SX8654) += sx8654.o
97obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o 97obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
98obj-$(CONFIG_TOUCHSCREEN_ZET6223) += zet6223.o
98obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o 99obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o
99obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o 100obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o
100obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o 101obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o
diff --git a/drivers/input/touchscreen/zet6223.c b/drivers/input/touchscreen/zet6223.c
new file mode 100644
index 000000000000..e7fb00b511ec
--- /dev/null
+++ b/drivers/input/touchscreen/zet6223.c
@@ -0,0 +1,267 @@
1/*
2 * Copyright (C) 2016, Jelle van der Waa <jelle@vdwaa.nl>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the Free
6 * Software Foundation; either version 2 of the License, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 */
14
15#include <linux/delay.h>
16#include <linux/i2c.h>
17#include <linux/input.h>
18#include <linux/input/mt.h>
19#include <linux/input/touchscreen.h>
20#include <linux/interrupt.h>
21#include <linux/module.h>
22#include <linux/regulator/consumer.h>
23#include <asm/unaligned.h>
24
25#define ZET6223_MAX_FINGERS 16
26#define ZET6223_MAX_PKT_SIZE (3 + 4 * ZET6223_MAX_FINGERS)
27
28#define ZET6223_CMD_INFO 0xB2
29#define ZET6223_CMD_INFO_LENGTH 17
30#define ZET6223_VALID_PACKET 0x3c
31
32#define ZET6223_POWER_ON_DELAY_MSEC 30
33
34struct zet6223_ts {
35 struct i2c_client *client;
36 struct input_dev *input;
37 struct regulator *vcc;
38 struct regulator *vio;
39 struct touchscreen_properties prop;
40 struct regulator_bulk_data supplies[2];
41 u16 max_x;
42 u16 max_y;
43 u8 fingernum;
44};
45
46static int zet6223_start(struct input_dev *dev)
47{
48 struct zet6223_ts *ts = input_get_drvdata(dev);
49
50 enable_irq(ts->client->irq);
51
52 return 0;
53}
54
55static void zet6223_stop(struct input_dev *dev)
56{
57 struct zet6223_ts *ts = input_get_drvdata(dev);
58
59 disable_irq(ts->client->irq);
60}
61
62static irqreturn_t zet6223_irq(int irq, void *dev_id)
63{
64 struct zet6223_ts *ts = dev_id;
65 u16 finger_bits;
66
67 /*
68 * First 3 bytes are an identifier, two bytes of finger data.
69 * X, Y data per finger is 4 bytes.
70 */
71 u8 bufsize = 3 + 4 * ts->fingernum;
72 u8 buf[ZET6223_MAX_PKT_SIZE];
73 int i;
74 int ret;
75 int error;
76
77 ret = i2c_master_recv(ts->client, buf, bufsize);
78 if (ret != bufsize) {
79 error = ret < 0 ? ret : -EIO;
80 dev_err_ratelimited(&ts->client->dev,
81 "Error reading input data: %d\n", error);
82 return IRQ_HANDLED;
83 }
84
85 if (buf[0] != ZET6223_VALID_PACKET)
86 return IRQ_HANDLED;
87
88 finger_bits = get_unaligned_be16(buf + 1);
89 for (i = 0; i < ts->fingernum; i++) {
90 if (!(finger_bits & BIT(15 - i)))
91 continue;
92
93 input_mt_slot(ts->input, i);
94 input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, true);
95 input_event(ts->input, EV_ABS, ABS_MT_POSITION_X,
96 ((buf[i + 3] >> 4) << 8) + buf[i + 4]);
97 input_event(ts->input, EV_ABS, ABS_MT_POSITION_Y,
98 ((buf[i + 3] & 0xF) << 8) + buf[i + 5]);
99 }
100
101 input_mt_sync_frame(ts->input);
102 input_sync(ts->input);
103
104 return IRQ_HANDLED;
105}
106
107static void zet6223_power_off(void *_ts)
108{
109 struct zet6223_ts *ts = _ts;
110
111 regulator_bulk_disable(ARRAY_SIZE(ts->supplies), ts->supplies);
112}
113
114static int zet6223_power_on(struct zet6223_ts *ts)
115{
116 struct device *dev = &ts->client->dev;
117 int error;
118
119 ts->supplies[0].supply = "vio";
120 ts->supplies[1].supply = "vcc";
121
122 error = devm_regulator_bulk_get(dev, ARRAY_SIZE(ts->supplies),
123 ts->supplies);
124 if (error)
125 return error;
126
127 error = regulator_bulk_enable(ARRAY_SIZE(ts->supplies), ts->supplies);
128 if (error)
129 return error;
130
131 msleep(ZET6223_POWER_ON_DELAY_MSEC);
132
133 error = devm_add_action_or_reset(dev, zet6223_power_off, ts);
134 if (error) {
135 dev_err(dev, "failed to install poweroff action: %d\n", error);
136 return error;
137 }
138
139 return 0;
140}
141
142static int zet6223_query_device(struct zet6223_ts *ts)
143{
144 u8 buf[ZET6223_CMD_INFO_LENGTH];
145 u8 cmd = ZET6223_CMD_INFO;
146 int ret;
147 int error;
148
149 ret = i2c_master_send(ts->client, &cmd, sizeof(cmd));
150 if (ret != sizeof(cmd)) {
151 error = ret < 0 ? ret : -EIO;
152 dev_err(&ts->client->dev,
153 "touchpanel info cmd failed: %d\n", error);
154 return error;
155 }
156
157 ret = i2c_master_recv(ts->client, buf, sizeof(buf));
158 if (ret != sizeof(buf)) {
159 error = ret < 0 ? ret : -EIO;
160 dev_err(&ts->client->dev,
161 "failed to retrieve touchpanel info: %d\n", error);
162 return error;
163 }
164
165 ts->fingernum = buf[15] & 0x7F;
166 if (ts->fingernum > ZET6223_MAX_FINGERS) {
167 dev_warn(&ts->client->dev,
168 "touchpanel reports %d fingers, limiting to %d\n",
169 ts->fingernum, ZET6223_MAX_FINGERS);
170 ts->fingernum = ZET6223_MAX_FINGERS;
171 }
172
173 ts->max_x = get_unaligned_le16(&buf[8]);
174 ts->max_y = get_unaligned_le16(&buf[10]);
175
176 return 0;
177}
178
179static int zet6223_probe(struct i2c_client *client,
180 const struct i2c_device_id *id)
181{
182 struct device *dev = &client->dev;
183 struct zet6223_ts *ts;
184 struct input_dev *input;
185 int error;
186
187 if (!client->irq) {
188 dev_err(dev, "no irq specified\n");
189 return -EINVAL;
190 }
191
192 ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
193 if (!ts)
194 return -ENOMEM;
195
196 ts->client = client;
197
198 error = zet6223_power_on(ts);
199 if (error)
200 return error;
201
202 error = zet6223_query_device(ts);
203 if (error)
204 return error;
205
206 ts->input = input = devm_input_allocate_device(dev);
207 if (!input)
208 return -ENOMEM;
209
210 input_set_drvdata(input, ts);
211
212 input->name = client->name;
213 input->id.bustype = BUS_I2C;
214 input->open = zet6223_start;
215 input->close = zet6223_stop;
216
217 input_set_abs_params(input, ABS_MT_POSITION_X, 0, ts->max_x, 0, 0);
218 input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ts->max_y, 0, 0);
219
220 touchscreen_parse_properties(input, true, &ts->prop);
221
222 error = input_mt_init_slots(input, ts->fingernum,
223 INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
224 if (error)
225 return error;
226
227 error = devm_request_threaded_irq(dev, client->irq, NULL, zet6223_irq,
228 IRQF_ONESHOT, client->name, ts);
229 if (error) {
230 dev_err(dev, "failed to request irq %d: %d\n",
231 client->irq, error);
232 return error;
233 }
234
235 zet6223_stop(input);
236
237 error = input_register_device(input);
238 if (error)
239 return error;
240
241 return 0;
242}
243
244static const struct of_device_id zet6223_of_match[] = {
245 { .compatible = "zeitec,zet6223" },
246 { }
247};
248
249static const struct i2c_device_id zet6223_id[] = {
250 { "zet6223", 0},
251 { }
252};
253MODULE_DEVICE_TABLE(i2c, zet6223_id);
254
255static struct i2c_driver zet6223_driver = {
256 .driver = {
257 .name = "zet6223",
258 .of_match_table = zet6223_of_match,
259 },
260 .probe = zet6223_probe,
261 .id_table = zet6223_id
262};
263module_i2c_driver(zet6223_driver);
264
265MODULE_AUTHOR("Jelle van der Waa <jelle@vdwaa.nl>");
266MODULE_DESCRIPTION("ZEITEC zet622x I2C touchscreen driver");
267MODULE_LICENSE("GPL");