xref: /linux/drivers/input/touchscreen/hynitron-cst816x.c (revision e3966940559d52aa1800a008dcfeec218dd31f88)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Driver for I2C connected Hynitron CST816x Series Touchscreen
4  *
5  * Copyright (C) 2025 Oleh Kuzhylnyi <kuzhylol@gmail.com>
6  */
7 
8 #include <linux/delay.h>
9 #include <linux/device.h>
10 #include <linux/err.h>
11 #include <linux/gpio/consumer.h>
12 #include <linux/i2c.h>
13 #include <linux/input.h>
14 #include <linux/unaligned.h>
15 #include <linux/interrupt.h>
16 #include <linux/module.h>
17 
18 #define CST816X_RD_REG		0x01
19 #define CST816X_NUM_KEYS	5
20 
21 struct cst816x_touch {
22 	u8 gest;
23 	u8 active;
24 	u16 abs_x;
25 	u16 abs_y;
26 } __packed;
27 
28 struct cst816x_priv {
29 	struct i2c_client *client;
30 	struct gpio_desc *reset;
31 	struct input_dev *input;
32 	unsigned int keycode[CST816X_NUM_KEYS];
33 	unsigned int keycodemax;
34 };
35 
36 static int cst816x_parse_keycodes(struct device *dev, struct cst816x_priv *priv)
37 {
38 	int count;
39 	int error;
40 
41 	if (device_property_present(dev, "linux,keycodes")) {
42 		count = device_property_count_u32(dev, "linux,keycodes");
43 		if (count < 0) {
44 			error = count;
45 			dev_err(dev, "failed to count keys: %d\n", error);
46 			return error;
47 		} else if (count > ARRAY_SIZE(priv->keycode)) {
48 			dev_err(dev, "too many keys defined: %d\n", count);
49 			return -EINVAL;
50 		}
51 		priv->keycodemax = count;
52 
53 		error = device_property_read_u32_array(dev, "linux,keycodes",
54 						       priv->keycode,
55 						       priv->keycodemax);
56 		if (error) {
57 			dev_err(dev, "failed to read keycodes: %d\n", error);
58 			return error;
59 		}
60 	}
61 
62 	return 0;
63 }
64 
65 static int cst816x_i2c_read_register(struct cst816x_priv *priv, u8 reg,
66 				     void *buf, size_t len)
67 {
68 	struct i2c_msg xfer[] = {
69 		{
70 			.addr = priv->client->addr,
71 			.flags = 0,
72 			.buf = &reg,
73 			.len = sizeof(reg),
74 		},
75 		{
76 			.addr = priv->client->addr,
77 			.flags = I2C_M_RD,
78 			.buf = buf,
79 			.len = len,
80 		},
81 	};
82 	int error;
83 	int ret;
84 
85 	ret = i2c_transfer(priv->client->adapter, xfer, ARRAY_SIZE(xfer));
86 	if (ret != ARRAY_SIZE(xfer)) {
87 		error = ret < 0 ? ret : -EIO;
88 		dev_err(&priv->client->dev, "i2c rx err: %d\n", error);
89 		return error;
90 	}
91 
92 	return 0;
93 }
94 
95 static u8 cst816x_gest_idx(u8 gest)
96 {
97 	u8 index;
98 
99 	switch (gest) {
100 	case 0x01: /* Slide up gesture */
101 	case 0x02: /* Slide down gesture */
102 	case 0x03: /* Slide left gesture */
103 	case 0x04: /* Slide right gesture */
104 		index = gest;
105 		break;
106 	case 0x0c: /* Long press gesture */
107 	default:
108 		index = CST816X_NUM_KEYS;
109 		break;
110 	}
111 
112 	return index - 1;
113 }
114 
115 static bool cst816x_process_touch(struct cst816x_priv *priv,
116 				  struct cst816x_touch *tch)
117 {
118 	if (cst816x_i2c_read_register(priv, CST816X_RD_REG, tch, sizeof(*tch)))
119 		return false;
120 
121 	tch->abs_x = get_unaligned_be16(&tch->abs_x) & GENMASK(11, 0);
122 	tch->abs_y = get_unaligned_be16(&tch->abs_y) & GENMASK(11, 0);
123 
124 	dev_dbg(&priv->client->dev, "x: %u, y: %u, t: %u, g: 0x%x\n",
125 		tch->abs_x, tch->abs_y, tch->active, tch->gest);
126 
127 	return true;
128 }
129 
130 static int cst816x_register_input(struct cst816x_priv *priv)
131 {
132 	priv->input = devm_input_allocate_device(&priv->client->dev);
133 	if (!priv->input)
134 		return -ENOMEM;
135 
136 	priv->input->name = "Hynitron CST816x Series Touchscreen";
137 	priv->input->phys = "input/ts";
138 	priv->input->id.bustype = BUS_I2C;
139 
140 	input_set_drvdata(priv->input, priv);
141 
142 	input_set_abs_params(priv->input, ABS_X, 0, 240, 0, 0);
143 	input_set_abs_params(priv->input, ABS_Y, 0, 240, 0, 0);
144 	input_set_capability(priv->input, EV_KEY, BTN_TOUCH);
145 
146 	priv->input->keycode = priv->keycode;
147 	priv->input->keycodesize = sizeof(priv->keycode[0]);
148 	priv->input->keycodemax = priv->keycodemax;
149 
150 	for (int i = 0; i < priv->keycodemax; i++) {
151 		if (priv->keycode[i] == KEY_RESERVED)
152 			continue;
153 
154 		input_set_capability(priv->input, EV_KEY, priv->keycode[i]);
155 	}
156 
157 	return input_register_device(priv->input);
158 }
159 
160 static void cst816x_reset(struct cst816x_priv *priv)
161 {
162 	gpiod_set_value_cansleep(priv->reset, 1);
163 	msleep(50);
164 	gpiod_set_value_cansleep(priv->reset, 0);
165 	msleep(100);
166 }
167 
168 static irqreturn_t cst816x_irq_cb(int irq, void *cookie)
169 {
170 	struct cst816x_priv *priv = cookie;
171 	struct cst816x_touch tch;
172 
173 	if (!cst816x_process_touch(priv, &tch))
174 		return IRQ_HANDLED;
175 
176 	input_report_abs(priv->input, ABS_X, tch.abs_x);
177 	input_report_abs(priv->input, ABS_Y, tch.abs_y);
178 
179 	if (tch.gest)
180 		input_report_key(priv->input,
181 				 priv->keycode[cst816x_gest_idx(tch.gest)],
182 				 tch.active);
183 
184 	input_report_key(priv->input, BTN_TOUCH, tch.active);
185 
186 	input_sync(priv->input);
187 
188 	return IRQ_HANDLED;
189 }
190 
191 static int cst816x_probe(struct i2c_client *client)
192 {
193 	struct device *dev = &client->dev;
194 	struct cst816x_priv *priv;
195 	int error;
196 
197 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
198 	if (!priv)
199 		return -ENOMEM;
200 
201 	priv->client = client;
202 
203 	priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
204 	if (IS_ERR(priv->reset))
205 		return dev_err_probe(dev, PTR_ERR(priv->reset),
206 				     "gpio reset request failed\n");
207 
208 	if (priv->reset)
209 		cst816x_reset(priv);
210 
211 	error = cst816x_parse_keycodes(dev, priv);
212 	if (error)
213 		dev_warn(dev, "no gestures found in dt\n");
214 
215 	error = cst816x_register_input(priv);
216 	if (error)
217 		return dev_err_probe(dev, error, "input register failed\n");
218 
219 	error = devm_request_threaded_irq(dev, client->irq,
220 					  NULL, cst816x_irq_cb, IRQF_ONESHOT,
221 					  dev_driver_string(dev), priv);
222 	if (error)
223 		return dev_err_probe(dev, error, "irq request failed\n");
224 
225 	return 0;
226 }
227 
228 static const struct i2c_device_id cst816x_id[] = {
229 	{ .name = "cst816s", 0 },
230 	{ }
231 };
232 MODULE_DEVICE_TABLE(i2c, cst816x_id);
233 
234 static const struct of_device_id cst816x_of_match[] = {
235 	{ .compatible = "hynitron,cst816s", },
236 	{ }
237 };
238 MODULE_DEVICE_TABLE(of, cst816x_of_match);
239 
240 static struct i2c_driver cst816x_driver = {
241 	.driver = {
242 		.name = "cst816x",
243 		.of_match_table = cst816x_of_match,
244 	},
245 	.id_table = cst816x_id,
246 	.probe = cst816x_probe,
247 };
248 
249 module_i2c_driver(cst816x_driver);
250 
251 MODULE_AUTHOR("Oleh Kuzhylnyi <kuzhylol@gmail.com>");
252 MODULE_DESCRIPTION("Hynitron CST816x Series Touchscreen Driver");
253 MODULE_LICENSE("GPL");
254