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