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 static int icn8318_suspend(struct device
*dev
)
153 struct icn8318_data
*data
= i2c_get_clientdata(to_i2c_client(dev
));
155 mutex_lock(&data
->input
->mutex
);
156 if (input_device_enabled(data
->input
))
157 icn8318_stop(data
->input
);
158 mutex_unlock(&data
->input
->mutex
);
163 static int icn8318_resume(struct device
*dev
)
165 struct icn8318_data
*data
= i2c_get_clientdata(to_i2c_client(dev
));
167 mutex_lock(&data
->input
->mutex
);
168 if (input_device_enabled(data
->input
))
169 icn8318_start(data
->input
);
170 mutex_unlock(&data
->input
->mutex
);
175 static DEFINE_SIMPLE_DEV_PM_OPS(icn8318_pm_ops
, icn8318_suspend
, icn8318_resume
);
177 static int icn8318_probe(struct i2c_client
*client
)
179 struct device
*dev
= &client
->dev
;
180 struct icn8318_data
*data
;
181 struct input_dev
*input
;
185 dev_err(dev
, "Error no irq specified\n");
189 data
= devm_kzalloc(dev
, sizeof(*data
), GFP_KERNEL
);
193 data
->wake_gpio
= devm_gpiod_get(dev
, "wake", GPIOD_OUT_LOW
);
194 if (IS_ERR(data
->wake_gpio
))
195 return dev_err_probe(dev
, PTR_ERR(data
->wake_gpio
), "Error getting wake gpio\n");
197 input
= devm_input_allocate_device(dev
);
201 input
->name
= client
->name
;
202 input
->id
.bustype
= BUS_I2C
;
203 input
->open
= icn8318_start
;
204 input
->close
= icn8318_stop
;
205 input
->dev
.parent
= dev
;
207 input_set_capability(input
, EV_ABS
, ABS_MT_POSITION_X
);
208 input_set_capability(input
, EV_ABS
, ABS_MT_POSITION_Y
);
210 touchscreen_parse_properties(input
, true, &data
->prop
);
211 if (!input_abs_get_max(input
, ABS_MT_POSITION_X
) ||
212 !input_abs_get_max(input
, ABS_MT_POSITION_Y
)) {
213 dev_err(dev
, "Error touchscreen-size-x and/or -y missing\n");
217 error
= input_mt_init_slots(input
, ICN8318_MAX_TOUCHES
,
218 INPUT_MT_DIRECT
| INPUT_MT_DROP_UNUSED
);
222 data
->client
= client
;
224 input_set_drvdata(input
, data
);
226 error
= devm_request_threaded_irq(dev
, client
->irq
, NULL
, icn8318_irq
,
227 IRQF_ONESHOT
, client
->name
, data
);
229 dev_err(dev
, "Error requesting irq: %d\n", error
);
233 /* Stop device till opened */
234 icn8318_stop(data
->input
);
236 error
= input_register_device(input
);
240 i2c_set_clientdata(client
, data
);
245 static const struct of_device_id icn8318_of_match
[] = {
246 { .compatible
= "chipone,icn8318" },
249 MODULE_DEVICE_TABLE(of
, icn8318_of_match
);
251 /* This is useless for OF-enabled devices, but it is needed by I2C subsystem */
252 static const struct i2c_device_id icn8318_i2c_id
[] = {
255 MODULE_DEVICE_TABLE(i2c
, icn8318_i2c_id
);
257 static struct i2c_driver icn8318_driver
= {
259 .name
= "chipone_icn8318",
260 .pm
= pm_sleep_ptr(&icn8318_pm_ops
),
261 .of_match_table
= icn8318_of_match
,
263 .probe
= icn8318_probe
,
264 .id_table
= icn8318_i2c_id
,
267 module_i2c_driver(icn8318_driver
);
269 MODULE_DESCRIPTION("ChipOne icn8318 I2C Touchscreen Driver");
270 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
271 MODULE_LICENSE("GPL");