2 * Driver for ChipOne icn8318 i2c touchscreen controller
4 * Copyright (c) 2015 Red Hat Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
12 * Hans de Goede <hdegoede@redhat.com>
15 #include <linux/gpio/consumer.h>
16 #include <linux/interrupt.h>
17 #include <linux/i2c.h>
18 #include <linux/input.h>
19 #include <linux/input/mt.h>
20 #include <linux/module.h>
23 #define ICN8318_REG_POWER 4
24 #define ICN8318_REG_TOUCHDATA 16
26 #define ICN8318_POWER_ACTIVE 0
27 #define ICN8318_POWER_MONITOR 1
28 #define ICN8318_POWER_HIBERNATE 2
30 #define ICN8318_MAX_TOUCHES 5
32 struct icn8318_touch
{
36 __u8 pressure
; /* Seems more like finger width then pressure really */
38 /* The difference between 2 and 3 is unclear */
39 #define ICN8318_EVENT_NO_DATA 1 /* No finger seen yet since wakeup */
40 #define ICN8318_EVENT_UPDATE1 2 /* New or updated coordinates */
41 #define ICN8318_EVENT_UPDATE2 3 /* New or updated coordinates */
42 #define ICN8318_EVENT_END 4 /* Finger lifted */
45 struct icn8318_touch_data
{
48 struct icn8318_touch touches
[ICN8318_MAX_TOUCHES
];
52 struct i2c_client
*client
;
53 struct input_dev
*input
;
54 struct gpio_desc
*wake_gpio
;
62 static int icn8318_read_touch_data(struct i2c_client
*client
,
63 struct icn8318_touch_data
*touch_data
)
65 u8 reg
= ICN8318_REG_TOUCHDATA
;
66 struct i2c_msg msg
[2] = {
75 .len
= sizeof(struct icn8318_touch_data
),
76 .buf
= (u8
*)touch_data
80 return i2c_transfer(client
->adapter
, msg
, 2);
83 static inline bool icn8318_touch_active(u8 event
)
85 return (event
== ICN8318_EVENT_UPDATE1
) ||
86 (event
== ICN8318_EVENT_UPDATE2
);
89 static irqreturn_t
icn8318_irq(int irq
, void *dev_id
)
91 struct icn8318_data
*data
= dev_id
;
92 struct device
*dev
= &data
->client
->dev
;
93 struct icn8318_touch_data touch_data
;
96 ret
= icn8318_read_touch_data(data
->client
, &touch_data
);
98 dev_err(dev
, "Error reading touch data: %d\n", ret
);
102 if (touch_data
.softbutton
) {
104 * Other data is invalid when a softbutton is pressed.
105 * This needs some extra devicetree bindings to map the icn8318
106 * softbutton codes to evdev codes. Currently no known devices
112 if (touch_data
.touch_count
> ICN8318_MAX_TOUCHES
) {
113 dev_warn(dev
, "Too much touches %d > %d\n",
114 touch_data
.touch_count
, ICN8318_MAX_TOUCHES
);
115 touch_data
.touch_count
= ICN8318_MAX_TOUCHES
;
118 for (i
= 0; i
< touch_data
.touch_count
; i
++) {
119 struct icn8318_touch
*touch
= &touch_data
.touches
[i
];
120 bool act
= icn8318_touch_active(touch
->event
);
122 input_mt_slot(data
->input
, touch
->slot
);
123 input_mt_report_slot_state(data
->input
, MT_TOOL_FINGER
, act
);
127 x
= be16_to_cpu(touch
->x
);
128 y
= be16_to_cpu(touch
->y
);
136 if (!data
->swap_x_y
) {
137 input_event(data
->input
, EV_ABS
, ABS_MT_POSITION_X
, x
);
138 input_event(data
->input
, EV_ABS
, ABS_MT_POSITION_Y
, y
);
140 input_event(data
->input
, EV_ABS
, ABS_MT_POSITION_X
, y
);
141 input_event(data
->input
, EV_ABS
, ABS_MT_POSITION_Y
, x
);
145 input_mt_sync_frame(data
->input
);
146 input_sync(data
->input
);
151 static int icn8318_start(struct input_dev
*dev
)
153 struct icn8318_data
*data
= input_get_drvdata(dev
);
155 enable_irq(data
->client
->irq
);
156 gpiod_set_value_cansleep(data
->wake_gpio
, 1);
161 static void icn8318_stop(struct input_dev
*dev
)
163 struct icn8318_data
*data
= input_get_drvdata(dev
);
165 disable_irq(data
->client
->irq
);
166 i2c_smbus_write_byte_data(data
->client
, ICN8318_REG_POWER
,
167 ICN8318_POWER_HIBERNATE
);
168 gpiod_set_value_cansleep(data
->wake_gpio
, 0);
171 #ifdef CONFIG_PM_SLEEP
172 static int icn8318_suspend(struct device
*dev
)
174 struct icn8318_data
*data
= i2c_get_clientdata(to_i2c_client(dev
));
176 mutex_lock(&data
->input
->mutex
);
177 if (data
->input
->users
)
178 icn8318_stop(data
->input
);
179 mutex_unlock(&data
->input
->mutex
);
184 static int icn8318_resume(struct device
*dev
)
186 struct icn8318_data
*data
= i2c_get_clientdata(to_i2c_client(dev
));
188 mutex_lock(&data
->input
->mutex
);
189 if (data
->input
->users
)
190 icn8318_start(data
->input
);
191 mutex_unlock(&data
->input
->mutex
);
197 static SIMPLE_DEV_PM_OPS(icn8318_pm_ops
, icn8318_suspend
, icn8318_resume
);
199 static int icn8318_probe(struct i2c_client
*client
,
200 const struct i2c_device_id
*id
)
202 struct device
*dev
= &client
->dev
;
203 struct device_node
*np
= dev
->of_node
;
204 struct icn8318_data
*data
;
205 struct input_dev
*input
;
206 u32 fuzz_x
= 0, fuzz_y
= 0;
210 dev_err(dev
, "Error no irq specified\n");
214 data
= devm_kzalloc(dev
, sizeof(*data
), GFP_KERNEL
);
218 data
->wake_gpio
= devm_gpiod_get(dev
, "wake", GPIOD_OUT_LOW
);
219 if (IS_ERR(data
->wake_gpio
)) {
220 error
= PTR_ERR(data
->wake_gpio
);
221 if (error
!= -EPROBE_DEFER
)
222 dev_err(dev
, "Error getting wake gpio: %d\n", error
);
226 if (of_property_read_u32(np
, "touchscreen-size-x", &data
->max_x
) ||
227 of_property_read_u32(np
, "touchscreen-size-y", &data
->max_y
)) {
228 dev_err(dev
, "Error touchscreen-size-x and/or -y missing\n");
233 of_property_read_u32(np
, "touchscreen-fuzz-x", &fuzz_x
);
234 of_property_read_u32(np
, "touchscreen-fuzz-y", &fuzz_y
);
235 data
->invert_x
= of_property_read_bool(np
, "touchscreen-inverted-x");
236 data
->invert_y
= of_property_read_bool(np
, "touchscreen-inverted-y");
237 data
->swap_x_y
= of_property_read_bool(np
, "touchscreen-swapped-x-y");
239 input
= devm_input_allocate_device(dev
);
243 input
->name
= client
->name
;
244 input
->id
.bustype
= BUS_I2C
;
245 input
->open
= icn8318_start
;
246 input
->close
= icn8318_stop
;
247 input
->dev
.parent
= dev
;
249 if (!data
->swap_x_y
) {
250 input_set_abs_params(input
, ABS_MT_POSITION_X
, 0,
251 data
->max_x
, fuzz_x
, 0);
252 input_set_abs_params(input
, ABS_MT_POSITION_Y
, 0,
253 data
->max_y
, fuzz_y
, 0);
255 input_set_abs_params(input
, ABS_MT_POSITION_X
, 0,
256 data
->max_y
, fuzz_y
, 0);
257 input_set_abs_params(input
, ABS_MT_POSITION_Y
, 0,
258 data
->max_x
, fuzz_x
, 0);
261 error
= input_mt_init_slots(input
, ICN8318_MAX_TOUCHES
,
262 INPUT_MT_DIRECT
| INPUT_MT_DROP_UNUSED
);
266 data
->client
= client
;
268 input_set_drvdata(input
, data
);
270 error
= devm_request_threaded_irq(dev
, client
->irq
, NULL
, icn8318_irq
,
271 IRQF_ONESHOT
, client
->name
, data
);
273 dev_err(dev
, "Error requesting irq: %d\n", error
);
277 /* Stop device till opened */
278 icn8318_stop(data
->input
);
280 error
= input_register_device(input
);
284 i2c_set_clientdata(client
, data
);
289 static const struct of_device_id icn8318_of_match
[] = {
290 { .compatible
= "chipone,icn8318" },
293 MODULE_DEVICE_TABLE(of
, icn8318_of_match
);
295 /* This is useless for OF-enabled devices, but it is needed by I2C subsystem */
296 static const struct i2c_device_id icn8318_i2c_id
[] = {
299 MODULE_DEVICE_TABLE(i2c
, icn8318_i2c_id
);
301 static struct i2c_driver icn8318_driver
= {
303 .owner
= THIS_MODULE
,
304 .name
= "chipone_icn8318",
305 .pm
= &icn8318_pm_ops
,
306 .of_match_table
= icn8318_of_match
,
308 .probe
= icn8318_probe
,
309 .id_table
= icn8318_i2c_id
,
312 module_i2c_driver(icn8318_driver
);
314 MODULE_DESCRIPTION("ChipOne icn8318 I2C Touchscreen Driver");
315 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
316 MODULE_LICENSE("GPL");