diff options
author | Mika Penttilä <mika.penttila@nextfour.com> | 2016-08-03 02:52:32 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2016-08-03 03:49:00 -0400 |
commit | a485cb037fe64367ec14813f018edb87799c5eb1 (patch) | |
tree | 5fa170560a3084e3dd2ac451e6ef3576a3cd41fa | |
parent | b27c0d0c3bf3073e8ae19875eb1d3755c5e8c072 (diff) |
Input: add driver for SiS 9200 family I2C touchscreen controllers
This is a driver for SiS 9200 family touchscreen controllers using I2C bus.
Signed-off-by: Mika Penttilä <mika.penttila@nextfour.com>
Acked-by: Tammy Tseng <tammy_tseng@sis.com>
Acked-by: Yuger Yu <yuger_yu@sis.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r-- | Documentation/devicetree/bindings/input/touchscreen/sis_i2c.txt | 33 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/vendor-prefixes.txt | 1 | ||||
-rw-r--r-- | drivers/input/touchscreen/Kconfig | 12 | ||||
-rw-r--r-- | drivers/input/touchscreen/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/touchscreen/sis_i2c.c | 413 |
5 files changed, 460 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/input/touchscreen/sis_i2c.txt b/Documentation/devicetree/bindings/input/touchscreen/sis_i2c.txt new file mode 100644 index 000000000000..d87ad14f1efe --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/sis_i2c.txt | |||
@@ -0,0 +1,33 @@ | |||
1 | * SiS I2C Multiple Touch Controller | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: must be "sis,9200-ts" | ||
5 | - reg: i2c slave address | ||
6 | - interrupt-parent: the phandle for the interrupt controller | ||
7 | (see interrupt binding [0]) | ||
8 | - interrupts: touch controller interrupt (see interrupt | ||
9 | binding [0]) | ||
10 | |||
11 | Optional properties: | ||
12 | - pinctrl-names: should be "default" (see pinctrl binding [1]). | ||
13 | - pinctrl-0: a phandle pointing to the pin settings for the | ||
14 | device (see pinctrl binding [1]). | ||
15 | - attn-gpios: the gpio pin used as attention line | ||
16 | - reset-gpios: the gpio pin used to reset the controller | ||
17 | - wakeup-source: touchscreen can be used as a wakeup source | ||
18 | |||
19 | [0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt | ||
20 | [1]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt | ||
21 | |||
22 | Example: | ||
23 | |||
24 | sis9255@5c { | ||
25 | compatible = "sis,9200-ts"; | ||
26 | reg = <0x5c>; | ||
27 | pinctrl-names = "default"; | ||
28 | pinctrl-0 = <&pinctrl_sis>; | ||
29 | interrupt-parent = <&gpio3>; | ||
30 | interrupts = <19 IRQ_TYPE_EDGE_FALLING>; | ||
31 | irq-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>; | ||
32 | reset-gpios = <&gpio2 30 GPIO_ACTIVE_LOW>; | ||
33 | }; | ||
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 80fdbe2ce088..99029cfed459 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt | |||
@@ -221,6 +221,7 @@ simtek | |||
221 | sii Seiko Instruments, Inc. | 221 | sii Seiko Instruments, Inc. |
222 | silergy Silergy Corp. | 222 | silergy Silergy Corp. |
223 | sirf SiRF Technology, Inc. | 223 | sirf SiRF Technology, Inc. |
224 | sis Silicon Integrated Systems Corp. | ||
224 | sitronix Sitronix Technology Corporation | 225 | sitronix Sitronix Technology Corporation |
225 | skyworks Skyworks Solutions, Inc. | 226 | skyworks Skyworks Solutions, Inc. |
226 | smsc Standard Microsystems Corporation | 227 | smsc Standard Microsystems Corporation |
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 6abcd1766092..8d893cefb0e3 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
@@ -1071,6 +1071,18 @@ config TOUCHSCREEN_SILEAD | |||
1071 | To compile this driver as a module, choose M here: the | 1071 | To compile this driver as a module, choose M here: the |
1072 | module will be called silead. | 1072 | module will be called silead. |
1073 | 1073 | ||
1074 | config TOUCHSCREEN_SIS_I2C | ||
1075 | tristate "SiS 9200 family I2C touchscreen" | ||
1076 | depends on I2C | ||
1077 | depends on GPIOLIB || COMPILE_TEST | ||
1078 | help | ||
1079 | This enables support for SiS 9200 family over I2C based touchscreens. | ||
1080 | |||
1081 | If unsure, say N. | ||
1082 | |||
1083 | To compile this driver as a module, choose M here: the | ||
1084 | module will be called sis_i2c. | ||
1085 | |||
1074 | config TOUCHSCREEN_ST1232 | 1086 | config TOUCHSCREEN_ST1232 |
1075 | tristate "Sitronix ST1232 touchscreen controllers" | 1087 | tristate "Sitronix ST1232 touchscreen controllers" |
1076 | depends on I2C | 1088 | depends on I2C |
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 3b598c901677..b4373d6be402 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile | |||
@@ -65,6 +65,7 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o | |||
65 | obj-$(CONFIG_TOUCHSCREEN_RM_TS) += raydium_i2c_ts.o | 65 | obj-$(CONFIG_TOUCHSCREEN_RM_TS) += raydium_i2c_ts.o |
66 | obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o | 66 | obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o |
67 | obj-$(CONFIG_TOUCHSCREEN_SILEAD) += silead.o | 67 | obj-$(CONFIG_TOUCHSCREEN_SILEAD) += silead.o |
68 | obj-$(CONFIG_TOUCHSCREEN_SIS_I2C) += sis_i2c.o | ||
68 | obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o | 69 | obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o |
69 | obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o | 70 | obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o |
70 | obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o | 71 | obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o |
diff --git a/drivers/input/touchscreen/sis_i2c.c b/drivers/input/touchscreen/sis_i2c.c new file mode 100644 index 000000000000..8d93f8c9a403 --- /dev/null +++ b/drivers/input/touchscreen/sis_i2c.c | |||
@@ -0,0 +1,413 @@ | |||
1 | /* | ||
2 | * Touch Screen driver for SiS 9200 family I2C Touch panels | ||
3 | * | ||
4 | * Copyright (C) 2015 SiS, Inc. | ||
5 | * Copyright (C) 2016 Nextfour Group | ||
6 | * | ||
7 | * This software is licensed under the terms of the GNU General Public | ||
8 | * License version 2, as published by the Free Software Foundation, and | ||
9 | * may be copied, distributed, and modified under those terms. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/crc-itu-t.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/i2c.h> | ||
20 | #include <linux/input.h> | ||
21 | #include <linux/input/mt.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/gpio/consumer.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <asm/unaligned.h> | ||
27 | |||
28 | #define SIS_I2C_NAME "sis_i2c_ts" | ||
29 | |||
30 | /* | ||
31 | * The I2C packet format: | ||
32 | * le16 byte count | ||
33 | * u8 Report ID | ||
34 | * <contact data - variable length> | ||
35 | * u8 Number of contacts | ||
36 | * le16 Scan Time (optional) | ||
37 | * le16 CRC | ||
38 | * | ||
39 | * One touch point information consists of 6+ bytes, the order is: | ||
40 | * u8 contact state | ||
41 | * u8 finger id | ||
42 | * le16 x axis | ||
43 | * le16 y axis | ||
44 | * u8 contact width (optional) | ||
45 | * u8 contact height (optional) | ||
46 | * u8 pressure (optional) | ||
47 | * | ||
48 | * Maximum amount of data transmitted in one shot is 64 bytes, if controller | ||
49 | * needs to report more contacts than fit in one packet it will send true | ||
50 | * number of contacts in first packet and 0 as number of contacts in second | ||
51 | * packet. | ||
52 | */ | ||
53 | |||
54 | #define SIS_MAX_PACKET_SIZE 64 | ||
55 | |||
56 | #define SIS_PKT_LEN_OFFSET 0 | ||
57 | #define SIS_PKT_REPORT_OFFSET 2 /* Report ID/type */ | ||
58 | #define SIS_PKT_CONTACT_OFFSET 3 /* First contact */ | ||
59 | |||
60 | #define SIS_SCAN_TIME_LEN 2 | ||
61 | |||
62 | /* Supported report types */ | ||
63 | #define SIS_ALL_IN_ONE_PACKAGE 0x10 | ||
64 | #define SIS_PKT_IS_TOUCH(x) (((x) & 0x0f) == 0x01) | ||
65 | #define SIS_PKT_IS_HIDI2C(x) (((x) & 0x0f) == 0x06) | ||
66 | |||
67 | /* Contact properties within report */ | ||
68 | #define SIS_PKT_HAS_AREA(x) ((x) & BIT(4)) | ||
69 | #define SIS_PKT_HAS_PRESSURE(x) ((x) & BIT(5)) | ||
70 | #define SIS_PKT_HAS_SCANTIME(x) ((x) & BIT(6)) | ||
71 | |||
72 | /* Contact size */ | ||
73 | #define SIS_BASE_LEN_PER_CONTACT 6 | ||
74 | #define SIS_AREA_LEN_PER_CONTACT 2 | ||
75 | #define SIS_PRESSURE_LEN_PER_CONTACT 1 | ||
76 | |||
77 | /* Offsets within contact data */ | ||
78 | #define SIS_CONTACT_STATUS_OFFSET 0 | ||
79 | #define SIS_CONTACT_ID_OFFSET 1 /* Contact ID */ | ||
80 | #define SIS_CONTACT_X_OFFSET 2 | ||
81 | #define SIS_CONTACT_Y_OFFSET 4 | ||
82 | #define SIS_CONTACT_WIDTH_OFFSET 6 | ||
83 | #define SIS_CONTACT_HEIGHT_OFFSET 7 | ||
84 | #define SIS_CONTACT_PRESSURE_OFFSET(id) (SIS_PKT_HAS_AREA(id) ? 8 : 6) | ||
85 | |||
86 | /* Individual contact state */ | ||
87 | #define SIS_STATUS_UP 0x0 | ||
88 | #define SIS_STATUS_DOWN 0x3 | ||
89 | |||
90 | /* Touchscreen parameters */ | ||
91 | #define SIS_MAX_FINGERS 10 | ||
92 | #define SIS_MAX_X 4095 | ||
93 | #define SIS_MAX_Y 4095 | ||
94 | #define SIS_MAX_PRESSURE 255 | ||
95 | |||
96 | /* Resolution diagonal */ | ||
97 | #define SIS_AREA_LENGTH_LONGER 5792 | ||
98 | /*((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5*/ | ||
99 | #define SIS_AREA_LENGTH_SHORT 5792 | ||
100 | #define SIS_AREA_UNIT (5792 / 32) | ||
101 | |||
102 | struct sis_ts_data { | ||
103 | struct i2c_client *client; | ||
104 | struct input_dev *input; | ||
105 | |||
106 | struct gpio_desc *attn_gpio; | ||
107 | struct gpio_desc *reset_gpio; | ||
108 | |||
109 | u8 packet[SIS_MAX_PACKET_SIZE]; | ||
110 | }; | ||
111 | |||
112 | static int sis_read_packet(struct i2c_client *client, u8 *buf, | ||
113 | unsigned int *num_contacts, | ||
114 | unsigned int *contact_size) | ||
115 | { | ||
116 | int count_idx; | ||
117 | int ret; | ||
118 | u16 len; | ||
119 | u16 crc, pkg_crc; | ||
120 | u8 report_id; | ||
121 | |||
122 | ret = i2c_master_recv(client, buf, SIS_MAX_PACKET_SIZE); | ||
123 | if (ret <= 0) | ||
124 | return -EIO; | ||
125 | |||
126 | len = get_unaligned_le16(&buf[SIS_PKT_LEN_OFFSET]); | ||
127 | if (len > SIS_MAX_PACKET_SIZE) { | ||
128 | dev_err(&client->dev, | ||
129 | "%s: invalid packet length (%d vs %d)\n", | ||
130 | __func__, len, SIS_MAX_PACKET_SIZE); | ||
131 | return -E2BIG; | ||
132 | } | ||
133 | |||
134 | if (len < 10) | ||
135 | return -EINVAL; | ||
136 | |||
137 | report_id = buf[SIS_PKT_REPORT_OFFSET]; | ||
138 | count_idx = len - 1; | ||
139 | *contact_size = SIS_BASE_LEN_PER_CONTACT; | ||
140 | |||
141 | if (report_id != SIS_ALL_IN_ONE_PACKAGE) { | ||
142 | if (SIS_PKT_IS_TOUCH(report_id)) { | ||
143 | /* | ||
144 | * Calculate CRC ignoring packet length | ||
145 | * in the beginning and CRC transmitted | ||
146 | * at the end of the packet. | ||
147 | */ | ||
148 | crc = crc_itu_t(0, buf + 2, len - 2 - 2); | ||
149 | pkg_crc = get_unaligned_le16(&buf[len - 2]); | ||
150 | |||
151 | if (crc != pkg_crc) { | ||
152 | dev_err(&client->dev, | ||
153 | "%s: CRC Error (%d vs %d)\n", | ||
154 | __func__, crc, pkg_crc); | ||
155 | return -EINVAL; | ||
156 | } | ||
157 | |||
158 | count_idx -= 2; | ||
159 | |||
160 | } else if (!SIS_PKT_IS_HIDI2C(report_id)) { | ||
161 | dev_err(&client->dev, | ||
162 | "%s: invalid packet ID %#02x\n", | ||
163 | __func__, report_id); | ||
164 | return -EINVAL; | ||
165 | } | ||
166 | |||
167 | if (SIS_PKT_HAS_SCANTIME(report_id)) | ||
168 | count_idx -= SIS_SCAN_TIME_LEN; | ||
169 | |||
170 | if (SIS_PKT_HAS_AREA(report_id)) | ||
171 | *contact_size += SIS_AREA_LEN_PER_CONTACT; | ||
172 | if (SIS_PKT_HAS_PRESSURE(report_id)) | ||
173 | *contact_size += SIS_PRESSURE_LEN_PER_CONTACT; | ||
174 | } | ||
175 | |||
176 | *num_contacts = buf[count_idx]; | ||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static int sis_ts_report_contact(struct sis_ts_data *ts, const u8 *data, u8 id) | ||
181 | { | ||
182 | struct input_dev *input = ts->input; | ||
183 | int slot; | ||
184 | u8 status = data[SIS_CONTACT_STATUS_OFFSET]; | ||
185 | u8 pressure; | ||
186 | u8 height, width; | ||
187 | u16 x, y; | ||
188 | |||
189 | if (status != SIS_STATUS_DOWN && status != SIS_STATUS_UP) { | ||
190 | dev_err(&ts->client->dev, "Unexpected touch status: %#02x\n", | ||
191 | data[SIS_CONTACT_STATUS_OFFSET]); | ||
192 | return -EINVAL; | ||
193 | } | ||
194 | |||
195 | slot = input_mt_get_slot_by_key(input, data[SIS_CONTACT_ID_OFFSET]); | ||
196 | if (slot < 0) | ||
197 | return -ENOENT; | ||
198 | |||
199 | input_mt_slot(input, slot); | ||
200 | input_mt_report_slot_state(input, MT_TOOL_FINGER, | ||
201 | status == SIS_STATUS_DOWN); | ||
202 | |||
203 | if (status == SIS_STATUS_DOWN) { | ||
204 | pressure = height = width = 1; | ||
205 | if (id != SIS_ALL_IN_ONE_PACKAGE) { | ||
206 | if (SIS_PKT_HAS_AREA(id)) { | ||
207 | width = data[SIS_CONTACT_WIDTH_OFFSET]; | ||
208 | height = data[SIS_CONTACT_HEIGHT_OFFSET]; | ||
209 | } | ||
210 | |||
211 | if (SIS_PKT_HAS_PRESSURE(id)) | ||
212 | pressure = | ||
213 | data[SIS_CONTACT_PRESSURE_OFFSET(id)]; | ||
214 | } | ||
215 | |||
216 | x = get_unaligned_le16(&data[SIS_CONTACT_X_OFFSET]); | ||
217 | y = get_unaligned_le16(&data[SIS_CONTACT_Y_OFFSET]); | ||
218 | |||
219 | input_report_abs(input, ABS_MT_TOUCH_MAJOR, | ||
220 | width * SIS_AREA_UNIT); | ||
221 | input_report_abs(input, ABS_MT_TOUCH_MINOR, | ||
222 | height * SIS_AREA_UNIT); | ||
223 | input_report_abs(input, ABS_MT_PRESSURE, pressure); | ||
224 | input_report_abs(input, ABS_MT_POSITION_X, x); | ||
225 | input_report_abs(input, ABS_MT_POSITION_Y, y); | ||
226 | } | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static void sis_ts_handle_packet(struct sis_ts_data *ts) | ||
232 | { | ||
233 | const u8 *contact; | ||
234 | unsigned int num_to_report = 0; | ||
235 | unsigned int num_contacts; | ||
236 | unsigned int num_reported; | ||
237 | unsigned int contact_size; | ||
238 | int error; | ||
239 | u8 report_id; | ||
240 | |||
241 | do { | ||
242 | error = sis_read_packet(ts->client, ts->packet, | ||
243 | &num_contacts, &contact_size); | ||
244 | if (error) | ||
245 | break; | ||
246 | |||
247 | if (num_to_report == 0) { | ||
248 | num_to_report = num_contacts; | ||
249 | } else if (num_contacts != 0) { | ||
250 | dev_err(&ts->client->dev, | ||
251 | "%s: nonzero (%d) point count in tail packet\n", | ||
252 | __func__, num_contacts); | ||
253 | break; | ||
254 | } | ||
255 | |||
256 | report_id = ts->packet[SIS_PKT_REPORT_OFFSET]; | ||
257 | contact = &ts->packet[SIS_PKT_CONTACT_OFFSET]; | ||
258 | num_reported = 0; | ||
259 | |||
260 | while (num_to_report > 0) { | ||
261 | error = sis_ts_report_contact(ts, contact, report_id); | ||
262 | if (error) | ||
263 | break; | ||
264 | |||
265 | contact += contact_size; | ||
266 | num_to_report--; | ||
267 | num_reported++; | ||
268 | |||
269 | if (report_id != SIS_ALL_IN_ONE_PACKAGE && | ||
270 | num_reported >= 5) { | ||
271 | /* | ||
272 | * The remainder of contacts is sent | ||
273 | * in the 2nd packet. | ||
274 | */ | ||
275 | break; | ||
276 | } | ||
277 | } | ||
278 | } while (num_to_report > 0); | ||
279 | |||
280 | input_mt_sync_frame(ts->input); | ||
281 | input_sync(ts->input); | ||
282 | } | ||
283 | |||
284 | static irqreturn_t sis_ts_irq_handler(int irq, void *dev_id) | ||
285 | { | ||
286 | struct sis_ts_data *ts = dev_id; | ||
287 | |||
288 | do { | ||
289 | sis_ts_handle_packet(ts); | ||
290 | } while (ts->attn_gpio && gpiod_get_value_cansleep(ts->attn_gpio)); | ||
291 | |||
292 | return IRQ_HANDLED; | ||
293 | } | ||
294 | |||
295 | static void sis_ts_reset(struct sis_ts_data *ts) | ||
296 | { | ||
297 | if (ts->reset_gpio) { | ||
298 | /* Get out of reset */ | ||
299 | usleep_range(1000, 2000); | ||
300 | gpiod_set_value(ts->reset_gpio, 1); | ||
301 | usleep_range(1000, 2000); | ||
302 | gpiod_set_value(ts->reset_gpio, 0); | ||
303 | msleep(100); | ||
304 | } | ||
305 | } | ||
306 | |||
307 | static int sis_ts_probe(struct i2c_client *client, | ||
308 | const struct i2c_device_id *id) | ||
309 | { | ||
310 | struct sis_ts_data *ts; | ||
311 | struct input_dev *input; | ||
312 | int error; | ||
313 | |||
314 | ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); | ||
315 | if (!ts) | ||
316 | return -ENOMEM; | ||
317 | |||
318 | ts->client = client; | ||
319 | i2c_set_clientdata(client, ts); | ||
320 | |||
321 | ts->attn_gpio = devm_gpiod_get_optional(&client->dev, | ||
322 | "attn", GPIOD_IN); | ||
323 | if (IS_ERR(ts->attn_gpio)) { | ||
324 | error = PTR_ERR(ts->attn_gpio); | ||
325 | if (error != -EPROBE_DEFER) | ||
326 | dev_err(&client->dev, | ||
327 | "Failed to get attention GPIO: %d\n", error); | ||
328 | return error; | ||
329 | } | ||
330 | |||
331 | ts->reset_gpio = devm_gpiod_get_optional(&client->dev, | ||
332 | "reset", GPIOD_OUT_LOW); | ||
333 | if (IS_ERR(ts->reset_gpio)) { | ||
334 | error = PTR_ERR(ts->reset_gpio); | ||
335 | if (error != -EPROBE_DEFER) | ||
336 | dev_err(&client->dev, | ||
337 | "Failed to get reset GPIO: %d\n", error); | ||
338 | return error; | ||
339 | } | ||
340 | |||
341 | sis_ts_reset(ts); | ||
342 | |||
343 | ts->input = input = devm_input_allocate_device(&client->dev); | ||
344 | if (!input) { | ||
345 | dev_err(&client->dev, "Failed to allocate input device\n"); | ||
346 | return -ENOMEM; | ||
347 | } | ||
348 | |||
349 | input->name = "SiS Touchscreen"; | ||
350 | input->id.bustype = BUS_I2C; | ||
351 | |||
352 | input_set_abs_params(input, ABS_MT_POSITION_X, 0, SIS_MAX_X, 0, 0); | ||
353 | input_set_abs_params(input, ABS_MT_POSITION_Y, 0, SIS_MAX_Y, 0, 0); | ||
354 | input_set_abs_params(input, ABS_MT_PRESSURE, 0, SIS_MAX_PRESSURE, 0, 0); | ||
355 | input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, | ||
356 | 0, SIS_AREA_LENGTH_LONGER, 0, 0); | ||
357 | input_set_abs_params(input, ABS_MT_TOUCH_MINOR, | ||
358 | 0, SIS_AREA_LENGTH_SHORT, 0, 0); | ||
359 | |||
360 | error = input_mt_init_slots(input, SIS_MAX_FINGERS, INPUT_MT_DIRECT); | ||
361 | if (error) { | ||
362 | dev_err(&client->dev, | ||
363 | "Failed to initialize MT slots: %d\n", error); | ||
364 | return error; | ||
365 | } | ||
366 | |||
367 | error = devm_request_threaded_irq(&client->dev, client->irq, | ||
368 | NULL, sis_ts_irq_handler, | ||
369 | IRQF_ONESHOT, | ||
370 | client->name, ts); | ||
371 | if (error) { | ||
372 | dev_err(&client->dev, "Failed to request IRQ: %d\n", error); | ||
373 | return error; | ||
374 | } | ||
375 | |||
376 | error = input_register_device(ts->input); | ||
377 | if (error) { | ||
378 | dev_err(&client->dev, | ||
379 | "Failed to register input device: %d\n", error); | ||
380 | return error; | ||
381 | } | ||
382 | |||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | #ifdef CONFIG_OF | ||
387 | static const struct of_device_id sis_ts_dt_ids[] = { | ||
388 | { .compatible = "sis,9200-ts" }, | ||
389 | { /* sentinel */ } | ||
390 | }; | ||
391 | MODULE_DEVICE_TABLE(of, sis_ts_dt_ids); | ||
392 | #endif | ||
393 | |||
394 | static const struct i2c_device_id sis_ts_id[] = { | ||
395 | { SIS_I2C_NAME, 0 }, | ||
396 | { "9200-ts", 0 }, | ||
397 | { /* sentinel */ } | ||
398 | }; | ||
399 | MODULE_DEVICE_TABLE(i2c, sis_ts_id); | ||
400 | |||
401 | static struct i2c_driver sis_ts_driver = { | ||
402 | .driver = { | ||
403 | .name = SIS_I2C_NAME, | ||
404 | .of_match_table = of_match_ptr(sis_ts_dt_ids), | ||
405 | }, | ||
406 | .probe = sis_ts_probe, | ||
407 | .id_table = sis_ts_id, | ||
408 | }; | ||
409 | module_i2c_driver(sis_ts_driver); | ||
410 | |||
411 | MODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver"); | ||
412 | MODULE_LICENSE("GPL v2"); | ||
413 | MODULE_AUTHOR("Mika Penttilä <mika.penttila@nextfour.com>"); | ||