1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Driver for ChipOne icn8318 i2c touchscreen controller
5 * Copyright (c) 2015 Red Hat Inc.
8 * Hans de Goede <hdegoede@redhat.com>
11 #include <linux/gpio/consumer.h>
12 #include <linux/interrupt.h>
13 #include <linux/i2c.h>
14 #include <linux/input.h>
15 #include <linux/input/mt.h>
16 #include <linux/input/touchscreen.h>
17 #include <linux/module.h>
20 #define ICN8318_REG_POWER 4
21 #define ICN8318_REG_TOUCHDATA 16
23 #define ICN8318_POWER_ACTIVE 0
24 #define ICN8318_POWER_MONITOR 1
25 #define ICN8318_POWER_HIBERNATE 2
27 #define ICN8318_MAX_TOUCHES 5
29 struct icn8318_touch
{
33 __u8 pressure
; /* Seems more like finger width then pressure really */
35 /* The difference between 2 and 3 is unclear */
36 #define ICN8318_EVENT_NO_DATA 1 /* No finger seen yet since wakeup */
37 #define ICN8318_EVENT_UPDATE1 2 /* New or updated coordinates */
38 #define ICN8318_EVENT_UPDATE2 3 /* New or updated coordinates */
39 #define ICN8318_EVENT_END 4 /* Finger lifted */
42 struct icn8318_touch_data
{
45 struct icn8318_touch touches
[ICN8318_MAX_TOUCHES
];
49 struct i2c_client
*client
;
50 struct input_dev
*input
;
51 struct gpio_desc
*wake_gpio
;
52 struct touchscreen_properties prop
;
55 static int icn8318_read_touch_data(struct i2c_client
*client
,
56 struct icn8318_touch_data
*touch_data
)
58 u8 reg
= ICN8318_REG_TOUCHDATA
;
59 struct i2c_msg msg
[2] = {
68 .len
= sizeof(struct icn8318_touch_data
),
69 .buf
= (u8
*)touch_data
73 return i2c_transfer(client
->adapter
, msg
, 2);
76 static inline bool icn8318_touch_active(u8 event
)
78 return (event
== ICN8318_EVENT_UPDATE1
) ||
79 (event
== ICN8318_EVENT_UPDATE2
);
82 static irqreturn_t
icn8318_irq(int irq
, void *dev_id
)
84 struct icn8318_data
*data
= dev_id
;
85 struct device
*dev
= &data
->client
->dev
;
86 struct icn8318_touch_data touch_data
;
89 ret
= icn8318_read_touch_data(data
->client
, &touch_data
);
91 dev_err(dev
, "Error reading touch data: %d\n", ret
);
95 if (touch_data
.softbutton
) {
97 * Other data is invalid when a softbutton is pressed.
98 * This needs some extra devicetree bindings to map the icn8318
99 * softbutton codes to evdev codes. Currently no known devices
105 if (touch_data
.touch_count
> ICN8318_MAX_TOUCHES
) {
106 dev_warn(dev
, "Too much touches %d > %d\n",
107 touch_data
.touch_count
, ICN8318_MAX_TOUCHES
);
108 touch_data
.touch_count
= ICN8318_MAX_TOUCHES
;
111 for (i
= 0; i
< touch_data
.touch_count
; i
++) {
112 struct icn8318_touch
*touch
= &touch_data
.touches
[i
];
113 bool act
= icn8318_touch_active(touch
->event
);
115 input_mt_slot(data
->input
, touch
->slot
);
116 input_mt_report_slot_state(data
->input
, MT_TOOL_FINGER
, act
);
120 touchscreen_report_pos(data
->input
, &data
->prop
,
121 be16_to_cpu(touch
->x
),
122 be16_to_cpu(touch
->y
), true);
125 input_mt_sync_frame(data
->input
);
126 input_sync(data
->input
);
131 static int icn8318_start(struct input_dev
*dev
)
133 struct icn8318_data
*data
= input_get_drvdata(dev
);
135 enable_irq(data
->client
->irq
);
136 gpiod_set_value_cansleep(data
->wake_gpio
, 1);
141 static void icn8318_stop(struct input_dev
*dev
)
143 struct icn8318_data
*data
= input_get_drvdata(dev
);
145 disable_irq(data
->client
->irq
);
146 i2c_smbus_write_byte_data(data
->client
, ICN8318_REG_POWER
,
147 ICN8318_POWER_HIBERNATE
);
148 gpiod_set_value_cansleep(data
->wake_gpio
, 0);
151 #ifdef CONFIG_PM_SLEEP
152 static int icn8318_suspend(struct device
*dev
)
154 struct icn8318_data
*data
= i2c_get_clientdata(to_i2c_client(dev
));
156 mutex_lock(&data
->input
->mutex
);
157 if (input_device_enabled(data
->input
))
158 icn8318_stop(data
->input
);
159 mutex_unlock(&data
->input
->mutex
);
164 static int icn8318_resume(struct device
*dev
)
166 struct icn8318_data
*data
= i2c_get_clientdata(to_i2c_client(dev
));
168 mutex_lock(&data
->input
->mutex
);
169 if (input_device_enabled(data
->input
))
170 icn8318_start(data
->input
);
171 mutex_unlock(&data
->input
->mutex
);
177 static SIMPLE_DEV_PM_OPS(icn8318_pm_ops
, icn8318_suspend
, icn8318_resume
);
179 static int icn8318_probe(struct i2c_client
*client
,
180 const struct i2c_device_id
*id
)
182 struct device
*dev
= &client
->dev
;
183 struct icn8318_data
*data
;
184 struct input_dev
*input
;
188 dev_err(dev
, "Error no irq specified\n");
192 data
= devm_kzalloc(dev
, sizeof(*data
), GFP_KERNEL
);
196 data
->wake_gpio
= devm_gpiod_get(dev
, "wake", GPIOD_OUT_LOW
);
197 if (IS_ERR(data
->wake_gpio
)) {
198 error
= PTR_ERR(data
->wake_gpio
);
199 if (error
!= -EPROBE_DEFER
)
200 dev_err(dev
, "Error getting wake gpio: %d\n", error
);
204 input
= devm_input_allocate_device(dev
);
208 input
->name
= client
->name
;
209 input
->id
.bustype
= BUS_I2C
;
210 input
->open
= icn8318_start
;
211 input
->close
= icn8318_stop
;
212 input
->dev
.parent
= dev
;
214 input_set_capability(input
, EV_ABS
, ABS_MT_POSITION_X
);
215 input_set_capability(input
, EV_ABS
, ABS_MT_POSITION_Y
);
217 touchscreen_parse_properties(input
, true, &data
->prop
);
218 if (!input_abs_get_max(input
, ABS_MT_POSITION_X
) ||
219 !input_abs_get_max(input
, ABS_MT_POSITION_Y
)) {
220 dev_err(dev
, "Error touchscreen-size-x and/or -y missing\n");
224 error
= input_mt_init_slots(input
, ICN8318_MAX_TOUCHES
,
225 INPUT_MT_DIRECT
| INPUT_MT_DROP_UNUSED
);
229 data
->client
= client
;
231 input_set_drvdata(input
, data
);
233 error
= devm_request_threaded_irq(dev
, client
->irq
, NULL
, icn8318_irq
,
234 IRQF_ONESHOT
, client
->name
, data
);
236 dev_err(dev
, "Error requesting irq: %d\n", error
);
240 /* Stop device till opened */
241 icn8318_stop(data
->input
);
243 error
= input_register_device(input
);
247 i2c_set_clientdata(client
, data
);
252 static const struct of_device_id icn8318_of_match
[] = {
253 { .compatible
= "chipone,icn8318" },
256 MODULE_DEVICE_TABLE(of
, icn8318_of_match
);
258 /* This is useless for OF-enabled devices, but it is needed by I2C subsystem */
259 static const struct i2c_device_id icn8318_i2c_id
[] = {
262 MODULE_DEVICE_TABLE(i2c
, icn8318_i2c_id
);
264 static struct i2c_driver icn8318_driver
= {
266 .name
= "chipone_icn8318",
267 .pm
= &icn8318_pm_ops
,
268 .of_match_table
= icn8318_of_match
,
270 .probe
= icn8318_probe
,
271 .id_table
= icn8318_i2c_id
,
274 module_i2c_driver(icn8318_driver
);
276 MODULE_DESCRIPTION("ChipOne icn8318 I2C Touchscreen Driver");
277 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
278 MODULE_LICENSE("GPL");