aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNoralf Trønnes <noralf@tronnes.org>2015-10-02 14:30:11 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2015-10-02 14:44:20 -0400
commit92deea1350f9fa97a841d45cd1f8228d5e8aa667 (patch)
tree6cabe72c00be0e5f0a7f426373f7651c4d28652a
parentd6f0c3d3a815aca40f1ea9daf6ed0d1f9e243185 (diff)
Input: add support for FocalTech FT6236 touchscreen controller
This adds support for the FT6x06 and the FT6x36 family of capacitive touch panel controllers, in particular the FT6236. Signed-off-by: Noralf Trønnes <noralf@tronnes.org> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt35
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt1
-rw-r--r--drivers/input/touchscreen/Kconfig13
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/ft6236.c327
5 files changed, 377 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt b/Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt
new file mode 100644
index 000000000000..777521da3da5
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt
@@ -0,0 +1,35 @@
1* FocalTech FT6236 I2C touchscreen controller
2
3Required properties:
4 - compatible : "focaltech,ft6236"
5 - reg : I2C slave address of the chip (0x38)
6 - interrupt-parent : a phandle pointing to the interrupt controller
7 serving the interrupt for this chip
8 - interrupts : interrupt specification for the touch controller
9 interrupt
10 - reset-gpios : GPIO specification for the RSTN input
11 - touchscreen-size-x : horizontal resolution of touchscreen (in pixels)
12 - touchscreen-size-y : vertical resolution of touchscreen (in pixels)
13
14Optional properties:
15 - touchscreen-fuzz-x : horizontal noise value of the absolute input
16 device (in pixels)
17 - touchscreen-fuzz-y : vertical noise value of the absolute input
18 device (in pixels)
19 - touchscreen-inverted-x : X axis is inverted (boolean)
20 - touchscreen-inverted-y : Y axis is inverted (boolean)
21 - touchscreen-swapped-x-y: X and Y axis are swapped (boolean)
22 Swapping is done after inverting the axis
23
24Example:
25
26 ft6x06@38 {
27 compatible = "focaltech,ft6236";
28 reg = <0x38>;
29 interrupt-parent = <&gpio>;
30 interrupts = <23 2>;
31 touchscreen-size-x = <320>;
32 touchscreen-size-y = <480>;
33 touchscreen-inverted-x;
34 touchscreen-swapped-x-y;
35 };
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 82d2ac97af74..3222b2ff475e 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -82,6 +82,7 @@ everspin Everspin Technologies, Inc.
82excito Excito 82excito Excito
83fcs Fairchild Semiconductor 83fcs Fairchild Semiconductor
84firefly Firefly 84firefly Firefly
85focaltech FocalTech Systems Co.,Ltd
85fsl Freescale Semiconductor 86fsl Freescale Semiconductor
86GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc. 87GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc.
87gef GE Fanuc Intelligent Platforms Embedded Systems, Inc. 88gef GE Fanuc Intelligent Platforms Embedded Systems, Inc.
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 600dcceff542..eda89b6b7e11 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -295,6 +295,19 @@ config TOUCHSCREEN_EGALAX
295 To compile this driver as a module, choose M here: the 295 To compile this driver as a module, choose M here: the
296 module will be called egalax_ts. 296 module will be called egalax_ts.
297 297
298config TOUCHSCREEN_FT6236
299 tristate "FT6236 I2C touchscreen"
300 depends on I2C
301 depends on GPIOLIB || COMPILE_TEST
302 help
303 Say Y here to enable support for the I2C connected FT6x06 and
304 FT6x36 family of capacitive touchscreen drivers.
305
306 If unsure, say N.
307
308 To compile this driver as a module, choose M here: the
309 module will be called ft6236.
310
298config TOUCHSCREEN_FUJITSU 311config TOUCHSCREEN_FUJITSU
299 tristate "Fujitsu serial touchscreen" 312 tristate "Fujitsu serial touchscreen"
300 select SERIO 313 select SERIO
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 1b79cc09744a..baba189e3e16 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
35obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o 35obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o
36obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o 36obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
37obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o 37obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
38obj-$(CONFIG_TOUCHSCREEN_FT6236) += ft6236.o
38obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o 39obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
39obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o 40obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o
40obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o 41obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
diff --git a/drivers/input/touchscreen/ft6236.c b/drivers/input/touchscreen/ft6236.c
new file mode 100644
index 000000000000..cccae193668e
--- /dev/null
+++ b/drivers/input/touchscreen/ft6236.c
@@ -0,0 +1,327 @@
1/*
2 * FocalTech FT6236 TouchScreen driver.
3 *
4 * Copyright (c) 2010 Focal tech Ltd.
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/delay.h>
17#include <linux/gpio/consumer.h>
18#include <linux/i2c.h>
19#include <linux/input.h>
20#include <linux/input/mt.h>
21#include <linux/interrupt.h>
22#include <linux/module.h>
23#include <linux/property.h>
24
25#define FT6236_MAX_TOUCH_POINTS 2
26
27#define FT6236_REG_TH_GROUP 0x80
28#define FT6236_REG_PERIODACTIVE 0x88
29#define FT6236_REG_LIB_VER_H 0xa1
30#define FT6236_REG_LIB_VER_L 0xa2
31#define FT6236_REG_CIPHER 0xa3
32#define FT6236_REG_FIRMID 0xa6
33#define FT6236_REG_FOCALTECH_ID 0xa8
34#define FT6236_REG_RELEASE_CODE_ID 0xaf
35
36#define FT6236_EVENT_PRESS_DOWN 0
37#define FT6236_EVENT_LIFT_UP 1
38#define FT6236_EVENT_CONTACT 2
39#define FT6236_EVENT_NO_EVENT 3
40
41struct ft6236_data {
42 struct i2c_client *client;
43 struct input_dev *input;
44 struct gpio_desc *reset_gpio;
45 u32 max_x;
46 u32 max_y;
47 bool invert_x;
48 bool invert_y;
49 bool swap_xy;
50};
51
52/*
53 * This struct is a touchpoint as stored in hardware. Note that the id,
54 * as well as the event, are stored in the upper nybble of the hi byte.
55 */
56struct ft6236_touchpoint {
57 union {
58 u8 xhi;
59 u8 event;
60 };
61 u8 xlo;
62 union {
63 u8 yhi;
64 u8 id;
65 };
66 u8 ylo;
67 u8 weight;
68 u8 misc;
69} __packed;
70
71/* This packet represents the register map as read from offset 0 */
72struct ft6236_packet {
73 u8 dev_mode;
74 u8 gest_id;
75 u8 touches;
76 struct ft6236_touchpoint points[FT6236_MAX_TOUCH_POINTS];
77} __packed;
78
79static int ft6236_read(struct i2c_client *client, u8 reg, u8 len, void *data)
80{
81 int error;
82
83 error = i2c_smbus_read_i2c_block_data(client, reg, len, data);
84 if (error < 0)
85 return error;
86
87 if (error != len)
88 return -EIO;
89
90 return 0;
91}
92
93static irqreturn_t ft6236_interrupt(int irq, void *dev_id)
94{
95 struct ft6236_data *ft6236 = dev_id;
96 struct device *dev = &ft6236->client->dev;
97 struct input_dev *input = ft6236->input;
98 struct ft6236_packet buf;
99 u8 touches;
100 int i, error;
101
102 error = ft6236_read(ft6236->client, 0, sizeof(buf), &buf);
103 if (error) {
104 dev_err(dev, "read touchdata failed %d\n", error);
105 return IRQ_HANDLED;
106 }
107
108 touches = buf.touches & 0xf;
109 if (touches > FT6236_MAX_TOUCH_POINTS) {
110 dev_dbg(dev,
111 "%d touch points reported, only %d are supported\n",
112 touches, FT6236_MAX_TOUCH_POINTS);
113 touches = FT6236_MAX_TOUCH_POINTS;
114 }
115
116 for (i = 0; i < touches; i++) {
117 struct ft6236_touchpoint *point = &buf.points[i];
118 u16 x = ((point->xhi & 0xf) << 8) | buf.points[i].xlo;
119 u16 y = ((point->yhi & 0xf) << 8) | buf.points[i].ylo;
120 u8 event = point->event >> 6;
121 u8 id = point->id >> 4;
122 bool act = (event == FT6236_EVENT_PRESS_DOWN ||
123 event == FT6236_EVENT_CONTACT);
124
125 input_mt_slot(input, id);
126 input_mt_report_slot_state(input, MT_TOOL_FINGER, act);
127 if (!act)
128 continue;
129
130 if (ft6236->invert_x)
131 x = ft6236->max_x - x;
132
133 if (ft6236->invert_y)
134 y = ft6236->max_y - y;
135
136 if (ft6236->swap_xy) {
137 input_report_abs(input, ABS_MT_POSITION_X, y);
138 input_report_abs(input, ABS_MT_POSITION_Y, x);
139 } else {
140 input_report_abs(input, ABS_MT_POSITION_X, x);
141 input_report_abs(input, ABS_MT_POSITION_Y, y);
142 }
143 }
144
145 input_mt_sync_frame(input);
146 input_sync(input);
147
148 return IRQ_HANDLED;
149}
150
151static u8 ft6236_debug_read_byte(struct ft6236_data *ft6236, u8 reg)
152{
153 struct i2c_client *client = ft6236->client;
154 u8 val = 0;
155 int error;
156
157 error = ft6236_read(client, reg, 1, &val);
158 if (error)
159 dev_dbg(&client->dev,
160 "error reading register 0x%02x: %d\n", reg, error);
161
162 return val;
163}
164
165static void ft6236_debug_info(struct ft6236_data *ft6236)
166{
167 struct device *dev = &ft6236->client->dev;
168
169 dev_dbg(dev, "Touch threshold is %d\n",
170 ft6236_debug_read_byte(ft6236, FT6236_REG_TH_GROUP) * 4);
171 dev_dbg(dev, "Report rate is %dHz\n",
172 ft6236_debug_read_byte(ft6236, FT6236_REG_PERIODACTIVE) * 10);
173 dev_dbg(dev, "Firmware library version 0x%02x%02x\n",
174 ft6236_debug_read_byte(ft6236, FT6236_REG_LIB_VER_H),
175 ft6236_debug_read_byte(ft6236, FT6236_REG_LIB_VER_L));
176 dev_dbg(dev, "Firmware version 0x%02x\n",
177 ft6236_debug_read_byte(ft6236, FT6236_REG_FIRMID));
178 dev_dbg(dev, "Chip vendor ID 0x%02x\n",
179 ft6236_debug_read_byte(ft6236, FT6236_REG_CIPHER));
180 dev_dbg(dev, "CTPM vendor ID 0x%02x\n",
181 ft6236_debug_read_byte(ft6236, FT6236_REG_FOCALTECH_ID));
182 dev_dbg(dev, "Release code version 0x%02x\n",
183 ft6236_debug_read_byte(ft6236, FT6236_REG_RELEASE_CODE_ID));
184}
185
186static void ft6236_reset(struct ft6236_data *ft6236)
187{
188 if (!ft6236->reset_gpio)
189 return;
190
191 gpiod_set_value_cansleep(ft6236->reset_gpio, 1);
192 usleep_range(5000, 20000);
193 gpiod_set_value_cansleep(ft6236->reset_gpio, 0);
194 msleep(300);
195}
196
197static int ft6236_probe(struct i2c_client *client,
198 const struct i2c_device_id *id)
199{
200 struct device *dev = &client->dev;
201 struct ft6236_data *ft6236;
202 struct input_dev *input;
203 u32 fuzz_x = 0, fuzz_y = 0;
204 u8 val;
205 int error;
206
207 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
208 return -ENXIO;
209
210 if (!client->irq) {
211 dev_err(dev, "irq is missing\n");
212 return -EINVAL;
213 }
214
215 ft6236 = devm_kzalloc(dev, sizeof(*ft6236), GFP_KERNEL);
216 if (!ft6236)
217 return -ENOMEM;
218
219 ft6236->client = client;
220 ft6236->reset_gpio = devm_gpiod_get_optional(dev, "reset",
221 GPIOD_OUT_LOW);
222 if (IS_ERR(ft6236->reset_gpio)) {
223 error = PTR_ERR(ft6236->reset_gpio);
224 if (error != -EPROBE_DEFER)
225 dev_err(dev, "error getting reset gpio: %d\n", error);
226 return error;
227 }
228
229 ft6236_reset(ft6236);
230
231 /* verify that the controller is present */
232 error = ft6236_read(client, 0x00, 1, &val);
233 if (error) {
234 dev_err(dev, "failed to read from controller: %d\n", error);
235 return error;
236 }
237
238 ft6236_debug_info(ft6236);
239
240 input = devm_input_allocate_device(dev);
241 if (!input)
242 return -ENOMEM;
243
244 ft6236->input = input;
245 input->name = client->name;
246 input->id.bustype = BUS_I2C;
247
248 if (device_property_read_u32(dev, "touchscreen-size-x",
249 &ft6236->max_x) ||
250 device_property_read_u32(dev, "touchscreen-size-y",
251 &ft6236->max_y)) {
252 dev_err(dev, "touchscreen-size-x and/or -y missing\n");
253 return -EINVAL;
254 }
255
256 device_property_read_u32(dev, "touchscreen-fuzz-x", &fuzz_x);
257 device_property_read_u32(dev, "touchscreen-fuzz-y", &fuzz_y);
258 ft6236->invert_x = device_property_read_bool(dev,
259 "touchscreen-inverted-x");
260 ft6236->invert_y = device_property_read_bool(dev,
261 "touchscreen-inverted-y");
262 ft6236->swap_xy = device_property_read_bool(dev,
263 "touchscreen-swapped-x-y");
264
265 if (ft6236->swap_xy) {
266 input_set_abs_params(input, ABS_MT_POSITION_X, 0,
267 ft6236->max_y, fuzz_y, 0);
268 input_set_abs_params(input, ABS_MT_POSITION_Y, 0,
269 ft6236->max_x, fuzz_x, 0);
270 } else {
271 input_set_abs_params(input, ABS_MT_POSITION_X, 0,
272 ft6236->max_x, fuzz_x, 0);
273 input_set_abs_params(input, ABS_MT_POSITION_Y, 0,
274 ft6236->max_y, fuzz_y, 0);
275 }
276
277 error = input_mt_init_slots(input, FT6236_MAX_TOUCH_POINTS,
278 INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
279 if (error)
280 return error;
281
282 error = devm_request_threaded_irq(dev, client->irq, NULL,
283 ft6236_interrupt, IRQF_ONESHOT,
284 client->name, ft6236);
285 if (error) {
286 dev_err(dev, "request irq %d failed: %d\n", client->irq, error);
287 return error;
288 }
289
290 error = input_register_device(input);
291 if (error) {
292 dev_err(dev, "failed to register input device: %d\n", error);
293 return error;
294 }
295
296 return 0;
297}
298
299#ifdef CONFIG_OF
300static const struct of_device_id ft6236_of_match[] = {
301 { .compatible = "focaltech,ft6236", },
302 { }
303};
304MODULE_DEVICE_TABLE(of, ft6236_of_match);
305#endif
306
307static const struct i2c_device_id ft6236_id[] = {
308 { "ft6236", },
309 { }
310};
311MODULE_DEVICE_TABLE(i2c, ft6236_id);
312
313static struct i2c_driver ft6236_driver = {
314 .driver = {
315 .name = "ft6236",
316 .owner = THIS_MODULE,
317 .of_match_table = of_match_ptr(ft6236_of_match),
318 },
319 .probe = ft6236_probe,
320 .id_table = ft6236_id,
321};
322module_i2c_driver(ft6236_driver);
323
324MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
325MODULE_AUTHOR("Noralf Trønnes <noralf@tronnes.org>");
326MODULE_DESCRIPTION("FocalTech FT6236 TouchScreen driver");
327MODULE_LICENSE("GPL");