1 /*
2  * Copyright (c) 2024 Joel Jaldemark
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT ilitek_ili2132a
8 
9 #include <zephyr/drivers/gpio.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/input/input.h>
12 #include <zephyr/pm/device.h>
13 #include <zephyr/sys/byteorder.h>
14 
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(ili2132a, CONFIG_INPUT_LOG_LEVEL);
17 
18 #define IS_TOUCHED_BIT 0x40
19 #define TIP            1
20 #define X_COORD        2
21 #define Y_COORD        4
22 
23 struct ili2132a_data {
24 	const struct device *dev;
25 	struct gpio_callback gpio_cb;
26 	struct k_work work;
27 };
28 
29 struct ili2132a_config {
30 	struct i2c_dt_spec i2c;
31 	struct gpio_dt_spec rst;
32 	struct gpio_dt_spec irq;
33 };
34 
gpio_isr(const struct device * dev,struct gpio_callback * cb,uint32_t pin)35 static void gpio_isr(const struct device *dev, struct gpio_callback *cb, uint32_t pin)
36 {
37 	struct ili2132a_data *data = CONTAINER_OF(cb, struct ili2132a_data, gpio_cb);
38 
39 	k_work_submit(&data->work);
40 }
41 
ili2132a_process(const struct device * dev)42 static void ili2132a_process(const struct device *dev)
43 {
44 	const struct ili2132a_config *dev_cfg = dev->config;
45 	uint8_t buf[8];
46 	uint16_t x, y;
47 	int ret;
48 
49 	ret = i2c_read_dt(&dev_cfg->i2c, buf, sizeof(buf));
50 	if (ret < 0) {
51 		LOG_ERR("Failed to read data: %d", ret);
52 		return;
53 	}
54 
55 	if (buf[TIP] & IS_TOUCHED_BIT) {
56 		x = sys_get_le16(&buf[X_COORD]);
57 		y = sys_get_le16(&buf[Y_COORD]);
58 		input_report_abs(dev, INPUT_ABS_X, x, false, K_FOREVER);
59 		input_report_abs(dev, INPUT_ABS_Y, y, false, K_FOREVER);
60 		input_report_key(dev, INPUT_BTN_TOUCH, 1, true, K_FOREVER);
61 	} else {
62 		input_report_key(dev, INPUT_BTN_TOUCH, 0, true, K_FOREVER);
63 	}
64 }
65 
ili2132a_work_handler(struct k_work * work_item)66 static void ili2132a_work_handler(struct k_work *work_item)
67 {
68 	struct ili2132a_data *data = CONTAINER_OF(work_item, struct ili2132a_data, work);
69 
70 	ili2132a_process(data->dev);
71 }
72 
ili2132a_init(const struct device * dev)73 static int ili2132a_init(const struct device *dev)
74 {
75 	struct ili2132a_data *data = dev->data;
76 	const struct ili2132a_config *dev_cfg = dev->config;
77 	int ret;
78 
79 	if (!i2c_is_ready_dt(&dev_cfg->i2c)) {
80 		LOG_ERR("%s is not ready", dev_cfg->i2c.bus->name);
81 		return -ENODEV;
82 	}
83 
84 	if (!gpio_is_ready_dt(&dev_cfg->rst)) {
85 		LOG_ERR("Reset GPIO controller device not ready");
86 		return -ENODEV;
87 	}
88 
89 	if (!gpio_is_ready_dt(&dev_cfg->irq)) {
90 		LOG_ERR("Interrupt GPIO controller device not ready");
91 		return -ENODEV;
92 	}
93 
94 	data->dev = dev;
95 
96 	ret = gpio_pin_configure_dt(&dev_cfg->irq, GPIO_INPUT);
97 	if (ret < 0) {
98 		LOG_ERR("Could not configure interrupt gpio");
99 		return ret;
100 	}
101 
102 	ret = gpio_pin_configure_dt(&dev_cfg->rst, GPIO_OUTPUT_ACTIVE);
103 	if (ret < 0) {
104 		LOG_ERR("Could not configure reset gpio");
105 		return ret;
106 	}
107 
108 	ret = gpio_pin_set_dt(&dev_cfg->rst, 0);
109 	if (ret < 0) {
110 		return ret;
111 	}
112 
113 	gpio_init_callback(&data->gpio_cb, gpio_isr, BIT(dev_cfg->irq.pin));
114 	ret = gpio_add_callback(dev_cfg->irq.port, &data->gpio_cb);
115 	if (ret < 0) {
116 		LOG_ERR("Could not set gpio callback");
117 		return ret;
118 	}
119 
120 	ret = gpio_pin_interrupt_configure_dt(&dev_cfg->irq, GPIO_INT_EDGE_FALLING);
121 	if (ret < 0) {
122 		LOG_ERR("Could not configure interrupt");
123 		return ret;
124 	}
125 
126 	k_work_init(&data->work, ili2132a_work_handler);
127 
128 	return 0;
129 }
130 #define ILI2132A_INIT(index)                                                                       \
131 	static const struct ili2132a_config ili2132a_config_##index = {                            \
132 		.i2c = I2C_DT_SPEC_INST_GET(index),                                                \
133 		.rst = GPIO_DT_SPEC_INST_GET(index, rst_gpios),                                    \
134 		.irq = GPIO_DT_SPEC_INST_GET(index, irq_gpios),                                    \
135 	};                                                                                         \
136 	static struct ili2132a_data ili2132a_data_##index;                                         \
137 	DEVICE_DT_INST_DEFINE(index, ili2132a_init, NULL, &ili2132a_data_##index,                  \
138 			      &ili2132a_config_##index, POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY,   \
139 			      NULL);
140 
141 DT_INST_FOREACH_STATUS_OKAY(ILI2132A_INIT)
142