1 /*
2 * Copyright (c) 2020,2023 NXP
3 * Copyright (c) 2020 Mark Olsson <mark@markolsson.se>
4 * Copyright (c) 2020 Teslabs Engineering S.L.
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #define DT_DRV_COMPAT focaltech_ft5336
10
11 #include <zephyr/drivers/gpio.h>
12 #include <zephyr/drivers/i2c.h>
13 #include <zephyr/input/input.h>
14 #include <zephyr/input/input_touch.h>
15 #include <zephyr/pm/device.h>
16 #include <zephyr/pm/device_runtime.h>
17 #include <zephyr/sys/util.h>
18
19 #include <zephyr/logging/log.h>
20 LOG_MODULE_REGISTER(ft5336, CONFIG_INPUT_LOG_LEVEL);
21
22 /* FT5336 used registers */
23 #define REG_TD_STATUS 0x02U
24 #define REG_P1_XH 0x03U
25 #define REG_G_PMODE 0xA5U
26
27 /* REG_TD_STATUS: Touch points. */
28 #define TOUCH_POINTS_POS 0U
29 #define TOUCH_POINTS_MSK 0x0FU
30
31 /* REG_Pn_XH: Events. */
32 #define EVENT_POS 6U
33 #define EVENT_MSK 0x03U
34
35 #define EVENT_PRESS_DOWN 0x00U
36 #define EVENT_LIFT_UP 0x01U
37 #define EVENT_CONTACT 0x02U
38 #define EVENT_NONE 0x03U
39
40 /* REG_Pn_YH: Touch ID */
41 #define TOUCH_ID_POS 4U
42 #define TOUCH_ID_MSK 0x0FU
43
44 #define TOUCH_ID_INVALID 0x0FU
45
46 /* REG_Pn_XH and REG_Pn_YH: Position */
47 #define POSITION_H_MSK 0x0FU
48
49 /* REG_G_PMODE: Power Consume Mode */
50 #define PMOD_HIBERNATE 0x03U
51
52 /** FT5336 configuration (DT). */
53 struct ft5336_config {
54 struct input_touchscreen_common_config common;
55 /** I2C bus. */
56 struct i2c_dt_spec bus;
57 struct gpio_dt_spec reset_gpio;
58 #ifdef CONFIG_INPUT_FT5336_INTERRUPT
59 /** Interrupt GPIO information. */
60 struct gpio_dt_spec int_gpio;
61 #endif
62 };
63
64 /** FT5336 data. */
65 struct ft5336_data {
66 /** Device pointer. */
67 const struct device *dev;
68 /** Work queue (for deferred read). */
69 struct k_work work;
70 #ifdef CONFIG_INPUT_FT5336_INTERRUPT
71 /** Interrupt GPIO callback. */
72 struct gpio_callback int_gpio_cb;
73 #else
74 /** Timer (polling mode). */
75 struct k_timer timer;
76 #endif
77 /** Last pressed state. */
78 bool pressed_old;
79 };
80
81 INPUT_TOUCH_STRUCT_CHECK(struct ft5336_config);
82
ft5336_process(const struct device * dev)83 static int ft5336_process(const struct device *dev)
84 {
85 const struct ft5336_config *config = dev->config;
86 struct ft5336_data *data = dev->data;
87
88 int r;
89 uint8_t points;
90 uint8_t coords[4U];
91 uint16_t row, col;
92 bool pressed;
93
94 /* obtain number of touch points */
95 r = i2c_reg_read_byte_dt(&config->bus, REG_TD_STATUS, &points);
96 if (r < 0) {
97 return r;
98 }
99
100 points = FIELD_GET(TOUCH_POINTS_MSK, points);
101 if (points != 0) {
102 /* Any number of touches still counts as one touch. All touch
103 * points except the first are ignored. Obtain first point
104 * X, Y coordinates from:
105 * REG_P1_XH, REG_P1_XL, REG_P1_YH, REG_P1_YL.
106 * We ignore the Event Flag because Zephyr only cares about
107 * pressed / not pressed and not press down / lift up
108 */
109 r = i2c_burst_read_dt(&config->bus, REG_P1_XH, coords, sizeof(coords));
110 if (r < 0) {
111 return r;
112 }
113
114 row = ((coords[0] & POSITION_H_MSK) << 8U) | coords[1];
115 col = ((coords[2] & POSITION_H_MSK) << 8U) | coords[3];
116
117 uint8_t touch_id = FIELD_GET(TOUCH_ID_MSK, coords[2]);
118
119 if (touch_id != TOUCH_ID_INVALID) {
120 pressed = true;
121 LOG_DBG("points: %d, touch_id: %d, row: %d, col: %d",
122 points, touch_id, row, col);
123 } else {
124 pressed = false;
125 LOG_WRN("bad TOUCH_ID: row: %d, col: %d", row, col);
126 }
127 } else {
128 /* no touch = no press */
129 pressed = false;
130 }
131
132 if (pressed) {
133 input_touchscreen_report_pos(dev, col, row, K_FOREVER);
134 input_report_key(dev, INPUT_BTN_TOUCH, 1, true, K_FOREVER);
135 } else if (data->pressed_old && !pressed) {
136 input_report_key(dev, INPUT_BTN_TOUCH, 0, true, K_FOREVER);
137 }
138 data->pressed_old = pressed;
139
140 return 0;
141 }
142
ft5336_work_handler(struct k_work * work)143 static void ft5336_work_handler(struct k_work *work)
144 {
145 struct ft5336_data *data = CONTAINER_OF(work, struct ft5336_data, work);
146
147 ft5336_process(data->dev);
148 }
149
150 #ifdef CONFIG_INPUT_FT5336_INTERRUPT
ft5336_isr_handler(const struct device * dev,struct gpio_callback * cb,uint32_t pins)151 static void ft5336_isr_handler(const struct device *dev,
152 struct gpio_callback *cb, uint32_t pins)
153 {
154 struct ft5336_data *data = CONTAINER_OF(cb, struct ft5336_data, int_gpio_cb);
155
156 k_work_submit(&data->work);
157 }
158 #else
ft5336_timer_handler(struct k_timer * timer)159 static void ft5336_timer_handler(struct k_timer *timer)
160 {
161 struct ft5336_data *data = CONTAINER_OF(timer, struct ft5336_data, timer);
162
163 k_work_submit(&data->work);
164 }
165 #endif
166
ft5336_init(const struct device * dev)167 static int ft5336_init(const struct device *dev)
168 {
169 const struct ft5336_config *config = dev->config;
170 struct ft5336_data *data = dev->data;
171 int r;
172
173 if (!device_is_ready(config->bus.bus)) {
174 LOG_ERR("I2C controller device not ready");
175 return -ENODEV;
176 }
177
178 data->dev = dev;
179
180 k_work_init(&data->work, ft5336_work_handler);
181
182 if (config->reset_gpio.port != NULL) {
183 /* Enable reset GPIO and assert reset */
184 r = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_ACTIVE);
185 if (r < 0) {
186 LOG_ERR("Could not enable reset GPIO");
187 return r;
188 }
189 /*
190 * Datasheet requires reset be held low 1 ms, or
191 * 1 ms + 100us if powering on controller. Hold low for
192 * 5 ms to be safe.
193 */
194 k_sleep(K_MSEC(5));
195 /* Pull reset pin high to complete reset sequence */
196 r = gpio_pin_set_dt(&config->reset_gpio, 0);
197 if (r < 0) {
198 return r;
199 }
200 }
201
202 #ifdef CONFIG_INPUT_FT5336_INTERRUPT
203 if (!gpio_is_ready_dt(&config->int_gpio)) {
204 LOG_ERR("Interrupt GPIO controller device not ready");
205 return -ENODEV;
206 }
207
208 r = gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT);
209 if (r < 0) {
210 LOG_ERR("Could not configure interrupt GPIO pin");
211 return r;
212 }
213
214 r = gpio_pin_interrupt_configure_dt(&config->int_gpio,
215 GPIO_INT_EDGE_TO_ACTIVE);
216 if (r < 0) {
217 LOG_ERR("Could not configure interrupt GPIO interrupt.");
218 return r;
219 }
220
221 gpio_init_callback(&data->int_gpio_cb, ft5336_isr_handler,
222 BIT(config->int_gpio.pin));
223 r = gpio_add_callback(config->int_gpio.port, &data->int_gpio_cb);
224 if (r < 0) {
225 LOG_ERR("Could not set gpio callback");
226 return r;
227 }
228 #else
229 k_timer_init(&data->timer, ft5336_timer_handler, NULL);
230 k_timer_start(&data->timer, K_MSEC(CONFIG_INPUT_FT5336_PERIOD),
231 K_MSEC(CONFIG_INPUT_FT5336_PERIOD));
232 #endif
233
234 r = pm_device_runtime_enable(dev);
235 if (r < 0 && r != -ENOTSUP) {
236 LOG_ERR("Failed to enable runtime power management");
237 return r;
238 }
239
240 return 0;
241 }
242
243 #ifdef CONFIG_PM_DEVICE
ft5336_pm_action(const struct device * dev,enum pm_device_action action)244 static int ft5336_pm_action(const struct device *dev,
245 enum pm_device_action action)
246 {
247 const struct ft5336_config *config = dev->config;
248 #ifndef CONFIG_INPUT_FT5336_INTERRUPT
249 struct ft5336_data *data = dev->data;
250 #endif
251 int ret;
252
253 if (config->reset_gpio.port == NULL) {
254 return -ENOTSUP;
255 }
256
257 switch (action) {
258 case PM_DEVICE_ACTION_SUSPEND:
259 ret = i2c_reg_write_byte_dt(&config->bus,
260 REG_G_PMODE, PMOD_HIBERNATE);
261 if (ret < 0) {
262 return ret;
263 }
264
265 #ifndef CONFIG_INPUT_FT5336_INTERRUPT
266 k_timer_stop(&data->timer);
267 #endif
268 break;
269 case PM_DEVICE_ACTION_RESUME:
270 ret = gpio_pin_set_dt(&config->reset_gpio, 1);
271 if (ret < 0) {
272 return ret;
273 }
274
275 k_sleep(K_MSEC(5));
276
277 ret = gpio_pin_set_dt(&config->reset_gpio, 0);
278 if (ret < 0) {
279 return ret;
280 }
281
282 #ifndef CONFIG_INPUT_FT5336_INTERRUPT
283 k_timer_start(&data->timer,
284 K_MSEC(CONFIG_INPUT_FT5336_PERIOD),
285 K_MSEC(CONFIG_INPUT_FT5336_PERIOD));
286 #endif
287 break;
288 default:
289 return -ENOTSUP;
290 }
291
292 return 0;
293 }
294 #endif
295
296 #define FT5336_INIT(index) \
297 PM_DEVICE_DT_INST_DEFINE(index, ft5336_pm_action); \
298 static const struct ft5336_config ft5336_config_##index = { \
299 .common = INPUT_TOUCH_DT_INST_COMMON_CONFIG_INIT(index), \
300 .bus = I2C_DT_SPEC_INST_GET(index), \
301 .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(index, reset_gpios, {0}), \
302 IF_ENABLED(CONFIG_INPUT_FT5336_INTERRUPT, \
303 (.int_gpio = GPIO_DT_SPEC_INST_GET(index, int_gpios),)) \
304 }; \
305 static struct ft5336_data ft5336_data_##index; \
306 DEVICE_DT_INST_DEFINE(index, ft5336_init, PM_DEVICE_DT_INST_GET(index), \
307 &ft5336_data_##index, &ft5336_config_##index, \
308 POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL);
309
310 DT_INST_FOREACH_STATUS_OKAY(FT5336_INIT)
311