1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Driver for Himax hx83112b touchscreens
4 *
5 * Copyright (C) 2022 Job Noorman <job@noorman.info>
6 *
7 * This code is based on "Himax Android Driver Sample Code for QCT platform":
8 *
9 * Copyright (C) 2017 Himax Corporation.
10 */
11
12#include <linux/delay.h>
13#include <linux/err.h>
14#include <linux/gpio/consumer.h>
15#include <linux/i2c.h>
16#include <linux/input.h>
17#include <linux/input/mt.h>
18#include <linux/input/touchscreen.h>
19#include <linux/interrupt.h>
20#include <linux/kernel.h>
21#include <linux/regmap.h>
22
23#define HIMAX_ID_83112B			0x83112b
24
25#define HIMAX_MAX_POINTS		10
26
27#define HIMAX_REG_CFG_SET_ADDR		0x00
28#define HIMAX_REG_CFG_INIT_READ		0x0c
29#define HIMAX_REG_CFG_READ_VALUE	0x08
30#define HIMAX_REG_READ_EVENT		0x30
31
32#define HIMAX_CFG_PRODUCT_ID		0x900000d0
33
34#define HIMAX_INVALID_COORD		0xffff
35
36struct himax_event_point {
37	__be16 x;
38	__be16 y;
39} __packed;
40
41struct himax_event {
42	struct himax_event_point points[HIMAX_MAX_POINTS];
43	u8 majors[HIMAX_MAX_POINTS];
44	u8 pad0[2];
45	u8 num_points;
46	u8 pad1[2];
47	u8 checksum_fix;
48} __packed;
49
50static_assert(sizeof(struct himax_event) == 56);
51
52struct himax_ts_data {
53	struct gpio_desc *gpiod_rst;
54	struct input_dev *input_dev;
55	struct i2c_client *client;
56	struct regmap *regmap;
57	struct touchscreen_properties props;
58};
59
60static const struct regmap_config himax_regmap_config = {
61	.reg_bits = 8,
62	.val_bits = 32,
63	.val_format_endian = REGMAP_ENDIAN_LITTLE,
64};
65
66static int himax_read_config(struct himax_ts_data *ts, u32 address, u32 *dst)
67{
68	int error;
69
70	error = regmap_write(ts->regmap, HIMAX_REG_CFG_SET_ADDR, address);
71	if (error)
72		return error;
73
74	error = regmap_write(ts->regmap, HIMAX_REG_CFG_INIT_READ, 0x0);
75	if (error)
76		return error;
77
78	error = regmap_read(ts->regmap, HIMAX_REG_CFG_READ_VALUE, dst);
79	if (error)
80		return error;
81
82	return 0;
83}
84
85static void himax_reset(struct himax_ts_data *ts)
86{
87	gpiod_set_value_cansleep(ts->gpiod_rst, 1);
88
89	/* Delay copied from downstream driver */
90	msleep(20);
91	gpiod_set_value_cansleep(ts->gpiod_rst, 0);
92
93	/*
94	 * The downstream driver doesn't contain this delay but is seems safer
95	 * to include it. The range is just a guess that seems to work well.
96	 */
97	usleep_range(1000, 1100);
98}
99
100static int himax_read_product_id(struct himax_ts_data *ts, u32 *product_id)
101{
102	int error;
103
104	error = himax_read_config(ts, HIMAX_CFG_PRODUCT_ID, product_id);
105	if (error)
106		return error;
107
108	*product_id >>= 8;
109	return 0;
110}
111
112static int himax_check_product_id(struct himax_ts_data *ts)
113{
114	int error;
115	u32 product_id;
116
117	error = himax_read_product_id(ts, &product_id);
118	if (error)
119		return error;
120
121	dev_dbg(&ts->client->dev, "Product id: %x\n", product_id);
122
123	switch (product_id) {
124	case HIMAX_ID_83112B:
125		return 0;
126
127	default:
128		dev_err(&ts->client->dev,
129			"Unknown product id: %x\n", product_id);
130		return -EINVAL;
131	}
132}
133
134static int himax_input_register(struct himax_ts_data *ts)
135{
136	int error;
137
138	ts->input_dev = devm_input_allocate_device(&ts->client->dev);
139	if (!ts->input_dev) {
140		dev_err(&ts->client->dev, "Failed to allocate input device\n");
141		return -ENOMEM;
142	}
143
144	ts->input_dev->name = "Himax Touchscreen";
145
146	input_set_capability(ts->input_dev, EV_ABS, ABS_MT_POSITION_X);
147	input_set_capability(ts->input_dev, EV_ABS, ABS_MT_POSITION_Y);
148	input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 200, 0, 0);
149	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 200, 0, 0);
150
151	touchscreen_parse_properties(ts->input_dev, true, &ts->props);
152
153	error = input_mt_init_slots(ts->input_dev, HIMAX_MAX_POINTS,
154				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
155	if (error) {
156		dev_err(&ts->client->dev,
157			"Failed to initialize MT slots: %d\n", error);
158		return error;
159	}
160
161	error = input_register_device(ts->input_dev);
162	if (error) {
163		dev_err(&ts->client->dev,
164			"Failed to register input device: %d\n", error);
165		return error;
166	}
167
168	return 0;
169}
170
171static u8 himax_event_get_num_points(const struct himax_event *event)
172{
173	if (event->num_points == 0xff)
174		return 0;
175	else
176		return event->num_points & 0x0f;
177}
178
179static bool himax_process_event_point(struct himax_ts_data *ts,
180				      const struct himax_event *event,
181				      int point_index)
182{
183	const struct himax_event_point *point = &event->points[point_index];
184	u16 x = be16_to_cpu(point->x);
185	u16 y = be16_to_cpu(point->y);
186	u8 w = event->majors[point_index];
187
188	if (x == HIMAX_INVALID_COORD || y == HIMAX_INVALID_COORD)
189		return false;
190
191	input_mt_slot(ts->input_dev, point_index);
192	input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
193	touchscreen_report_pos(ts->input_dev, &ts->props, x, y, true);
194	input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w);
195	input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
196	return true;
197}
198
199static void himax_process_event(struct himax_ts_data *ts,
200				const struct himax_event *event)
201{
202	int i;
203	int num_points_left = himax_event_get_num_points(event);
204
205	for (i = 0; i < HIMAX_MAX_POINTS && num_points_left > 0; i++) {
206		if (himax_process_event_point(ts, event, i))
207			num_points_left--;
208	}
209
210	input_mt_sync_frame(ts->input_dev);
211	input_sync(ts->input_dev);
212}
213
214static bool himax_verify_checksum(struct himax_ts_data *ts,
215				  const struct himax_event *event)
216{
217	u8 *data = (u8 *)event;
218	int i;
219	u16 checksum = 0;
220
221	for (i = 0; i < sizeof(*event); i++)
222		checksum += data[i];
223
224	if ((checksum & 0x00ff) != 0) {
225		dev_err(&ts->client->dev, "Wrong event checksum: %04x\n",
226			checksum);
227		return false;
228	}
229
230	return true;
231}
232
233static int himax_handle_input(struct himax_ts_data *ts)
234{
235	int error;
236	struct himax_event event;
237
238	error = regmap_raw_read(ts->regmap, HIMAX_REG_READ_EVENT, &event,
239				sizeof(event));
240	if (error) {
241		dev_err(&ts->client->dev, "Failed to read input event: %d\n",
242			error);
243		return error;
244	}
245
246	/*
247	 * Only process the current event when it has a valid checksum but
248	 * don't consider it a fatal error when it doesn't.
249	 */
250	if (himax_verify_checksum(ts, &event))
251		himax_process_event(ts, &event);
252
253	return 0;
254}
255
256static irqreturn_t himax_irq_handler(int irq, void *dev_id)
257{
258	int error;
259	struct himax_ts_data *ts = dev_id;
260
261	error = himax_handle_input(ts);
262	if (error)
263		return IRQ_NONE;
264
265	return IRQ_HANDLED;
266}
267
268static int himax_probe(struct i2c_client *client)
269{
270	int error;
271	struct device *dev = &client->dev;
272	struct himax_ts_data *ts;
273
274	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
275		dev_err(dev, "I2C check functionality failed\n");
276		return -ENXIO;
277	}
278
279	ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
280	if (!ts)
281		return -ENOMEM;
282
283	i2c_set_clientdata(client, ts);
284	ts->client = client;
285
286	ts->regmap = devm_regmap_init_i2c(client, &himax_regmap_config);
287	error = PTR_ERR_OR_ZERO(ts->regmap);
288	if (error) {
289		dev_err(dev, "Failed to initialize regmap: %d\n", error);
290		return error;
291	}
292
293	ts->gpiod_rst = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
294	error = PTR_ERR_OR_ZERO(ts->gpiod_rst);
295	if (error) {
296		dev_err(dev, "Failed to get reset GPIO: %d\n", error);
297		return error;
298	}
299
300	himax_reset(ts);
301
302	error = himax_check_product_id(ts);
303	if (error)
304		return error;
305
306	error = himax_input_register(ts);
307	if (error)
308		return error;
309
310	error = devm_request_threaded_irq(dev, client->irq, NULL,
311					  himax_irq_handler, IRQF_ONESHOT,
312					  client->name, ts);
313	if (error)
314		return error;
315
316	return 0;
317}
318
319static int himax_suspend(struct device *dev)
320{
321	struct himax_ts_data *ts = dev_get_drvdata(dev);
322
323	disable_irq(ts->client->irq);
324	return 0;
325}
326
327static int himax_resume(struct device *dev)
328{
329	struct himax_ts_data *ts = dev_get_drvdata(dev);
330
331	enable_irq(ts->client->irq);
332	return 0;
333}
334
335static DEFINE_SIMPLE_DEV_PM_OPS(himax_pm_ops, himax_suspend, himax_resume);
336
337static const struct i2c_device_id himax_ts_id[] = {
338	{ "hx83112b", 0 },
339	{ /* sentinel */ }
340};
341MODULE_DEVICE_TABLE(i2c, himax_ts_id);
342
343#ifdef CONFIG_OF
344static const struct of_device_id himax_of_match[] = {
345	{ .compatible = "himax,hx83112b" },
346	{ /* sentinel */ }
347};
348MODULE_DEVICE_TABLE(of, himax_of_match);
349#endif
350
351static struct i2c_driver himax_ts_driver = {
352	.probe = himax_probe,
353	.id_table = himax_ts_id,
354	.driver = {
355		.name = "Himax-hx83112b-TS",
356		.of_match_table = of_match_ptr(himax_of_match),
357		.pm = pm_sleep_ptr(&himax_pm_ops),
358	},
359};
360module_i2c_driver(himax_ts_driver);
361
362MODULE_AUTHOR("Job Noorman <job@noorman.info>");
363MODULE_DESCRIPTION("Himax hx83112b touchscreen driver");
364MODULE_LICENSE("GPL");
365