1 /*
2  * Copyright 2024 Google LLC
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT pixart_paw32xx
8 
9 #include <stdint.h>
10 #include <stdlib.h>
11 
12 #include <zephyr/device.h>
13 #include <zephyr/drivers/gpio.h>
14 #include <zephyr/drivers/spi.h>
15 #include <zephyr/input/input.h>
16 #include <zephyr/input/input_paw32xx.h>
17 #include <zephyr/kernel.h>
18 #include <zephyr/logging/log.h>
19 #include <zephyr/pm/device.h>
20 #include <zephyr/pm/device_runtime.h>
21 #include <zephyr/sys/util.h>
22 
23 LOG_MODULE_REGISTER(input_paw32xx, CONFIG_INPUT_LOG_LEVEL);
24 
25 #define PAW32XX_PRODUCT_ID1	0x00
26 #define PAW32XX_PRODUCT_ID2	0x01
27 #define PAW32XX_MOTION		0x02
28 #define PAW32XX_DELTA_X		0x03
29 #define PAW32XX_DELTA_Y		0x04
30 #define PAW32XX_OPERATION_MODE	0x05
31 #define PAW32XX_CONFIGURATION	0x06
32 #define PAW32XX_WRITE_PROTECT	0x09
33 #define PAW32XX_SLEEP1		0x0a
34 #define PAW32XX_SLEEP2		0x0b
35 #define PAW32XX_SLEEP3		0x0c
36 #define PAW32XX_CPI_X		0x0d
37 #define PAW32XX_CPI_Y		0x0e
38 #define PAW32XX_DELTA_XY_HI	0x12
39 #define PAW32XX_MOUSE_OPTION	0x19
40 
41 #define PRODUCT_ID_PAW32XX 0x30
42 #define SPI_WRITE BIT(7)
43 
44 #define MOTION_STATUS_MOTION BIT(7)
45 #define OPERATION_MODE_SLP_ENH	BIT(4)
46 #define OPERATION_MODE_SLP2_ENH	BIT(3)
47 #define OPERATION_MODE_SLP_MASK (OPERATION_MODE_SLP_ENH | OPERATION_MODE_SLP2_ENH)
48 #define CONFIGURATION_PD_ENH BIT(3)
49 #define CONFIGURATION_RESET BIT(7)
50 #define WRITE_PROTECT_ENABLE 0x00
51 #define WRITE_PROTECT_DISABLE 0x5a
52 #define MOUSE_OPTION_MOVX_INV_BIT 3
53 #define MOUSE_OPTION_MOVY_INV_BIT 4
54 
55 #define PAW32XX_DATA_SIZE_BITS 12
56 
57 #define RESET_DELAY_MS 2
58 
59 #define RES_STEP 38
60 #define RES_MIN (16 * RES_STEP)
61 #define RES_MAX (127 * RES_STEP)
62 
63 struct paw32xx_config {
64 	struct spi_dt_spec spi;
65 	struct gpio_dt_spec motion_gpio;
66 	uint16_t axis_x;
67 	uint16_t axis_y;
68 	int16_t res_cpi;
69 	bool invert_x;
70 	bool invert_y;
71 	bool force_awake;
72 };
73 
74 struct paw32xx_data {
75 	const struct device *dev;
76 	struct k_work motion_work;
77 	struct gpio_callback motion_cb;
78 };
79 
paw32xx_read_reg(const struct device * dev,uint8_t addr,uint8_t * value)80 static int paw32xx_read_reg(const struct device *dev, uint8_t addr, uint8_t *value)
81 {
82 	const struct paw32xx_config *cfg = dev->config;
83 
84 	const struct spi_buf tx_buf = {
85 		.buf = &addr,
86 		.len = sizeof(addr),
87 	};
88 	const struct spi_buf_set tx = {
89 		.buffers = &tx_buf,
90 		.count = 1,
91 	};
92 
93 	struct spi_buf rx_buf[] = {
94 		{
95 			.buf = NULL,
96 			.len = sizeof(addr),
97 		},
98 		{
99 			.buf = value,
100 			.len = 1,
101 		},
102 	};
103 	const struct spi_buf_set rx = {
104 		.buffers = rx_buf,
105 		.count = ARRAY_SIZE(rx_buf),
106 	};
107 
108 	return spi_transceive_dt(&cfg->spi, &tx, &rx);
109 }
110 
paw32xx_write_reg(const struct device * dev,uint8_t addr,uint8_t value)111 static int paw32xx_write_reg(const struct device *dev, uint8_t addr, uint8_t value)
112 {
113 	const struct paw32xx_config *cfg = dev->config;
114 
115 	uint8_t write_buf[] = {addr | SPI_WRITE, value};
116 	const struct spi_buf tx_buf = {
117 		.buf = write_buf,
118 		.len = sizeof(write_buf),
119 	};
120 	const struct spi_buf_set tx = {
121 		.buffers = &tx_buf,
122 		.count = 1,
123 	};
124 
125 	return spi_write_dt(&cfg->spi, &tx);
126 }
127 
paw32xx_update_reg(const struct device * dev,uint8_t addr,uint8_t mask,uint8_t value)128 static int paw32xx_update_reg(const struct device *dev, uint8_t addr, uint8_t mask, uint8_t value)
129 {
130 	uint8_t val;
131 	int ret;
132 
133 	ret = paw32xx_read_reg(dev, addr, &val);
134 	if (ret < 0) {
135 		return ret;
136 	}
137 
138 	val = (val & ~mask) | (value & mask);
139 
140 	ret = paw32xx_write_reg(dev, addr, val);
141 	if (ret < 0) {
142 		return ret;
143 	}
144 
145 	return 0;
146 }
147 
paw32xx_read_xy(const struct device * dev,int16_t * x,int16_t * y)148 static int paw32xx_read_xy(const struct device *dev, int16_t *x, int16_t *y)
149 {
150 	const struct paw32xx_config *cfg = dev->config;
151 	int ret;
152 
153 	uint8_t tx_data[] = {
154 		PAW32XX_DELTA_X,
155 		0xff,
156 		PAW32XX_DELTA_Y,
157 		0xff,
158 		PAW32XX_DELTA_XY_HI,
159 		0xff,
160 	};
161 	uint8_t rx_data[sizeof(tx_data)];
162 
163 	const struct spi_buf tx_buf = {
164 		.buf = tx_data,
165 		.len = sizeof(tx_data),
166 	};
167 	const struct spi_buf_set tx = {
168 		.buffers = &tx_buf,
169 		.count = 1,
170 	};
171 
172 	struct spi_buf rx_buf = {
173 		.buf = rx_data,
174 		.len = sizeof(rx_data),
175 	};
176 	const struct spi_buf_set rx = {
177 		.buffers = &rx_buf,
178 		.count = 1,
179 	};
180 
181 	ret = spi_transceive_dt(&cfg->spi, &tx, &rx);
182 	if (ret < 0) {
183 		return ret;
184 	}
185 
186 	*x = ((rx_data[5] << 4) & 0xf00) | rx_data[1];
187 	*y = ((rx_data[5] << 8) & 0xf00) | rx_data[3];
188 
189 	*x = sign_extend(*x, PAW32XX_DATA_SIZE_BITS - 1);
190 	*y = sign_extend(*y, PAW32XX_DATA_SIZE_BITS - 1);
191 
192 	return 0;
193 }
194 
paw32xx_motion_work_handler(struct k_work * work)195 static void paw32xx_motion_work_handler(struct k_work *work)
196 {
197 	struct paw32xx_data *data = CONTAINER_OF(
198 			work, struct paw32xx_data, motion_work);
199 	const struct device *dev = data->dev;
200 	const struct paw32xx_config *cfg = dev->config;
201 	uint8_t val;
202 	int16_t x, y;
203 	int ret;
204 
205 	ret = paw32xx_read_reg(dev, PAW32XX_MOTION, &val);
206 	if (ret < 0) {
207 		return;
208 	}
209 
210 	if ((val & MOTION_STATUS_MOTION) == 0x00) {
211 		return;
212 	}
213 
214 	ret = paw32xx_read_xy(dev, &x, &y);
215 	if (ret < 0) {
216 		return;
217 	}
218 
219 	LOG_DBG("x=%4d y=%4d", x, y);
220 
221 	input_report_rel(data->dev, cfg->axis_x, x, false, K_FOREVER);
222 	input_report_rel(data->dev, cfg->axis_y, y, true, K_FOREVER);
223 
224 	/* Trigger one more scan if more data is available. */
225 	if (gpio_pin_get_dt(&cfg->motion_gpio)) {
226 		k_work_submit(&data->motion_work);
227 	}
228 }
229 
paw32xx_motion_handler(const struct device * gpio_dev,struct gpio_callback * cb,uint32_t pins)230 static void paw32xx_motion_handler(const struct device *gpio_dev,
231 				   struct gpio_callback *cb,
232 				   uint32_t pins)
233 {
234 	struct paw32xx_data *data = CONTAINER_OF(
235 			cb, struct paw32xx_data, motion_cb);
236 
237 	k_work_submit(&data->motion_work);
238 }
239 
paw32xx_set_resolution(const struct device * dev,uint16_t res_cpi)240 int paw32xx_set_resolution(const struct device *dev, uint16_t res_cpi)
241 {
242 	uint8_t val;
243 	int ret;
244 
245 	if (!IN_RANGE(res_cpi, RES_MIN, RES_MAX)) {
246 		LOG_ERR("res_cpi out of range: %d", res_cpi);
247 		return -EINVAL;
248 	}
249 
250 	val = res_cpi / RES_STEP;
251 
252 	ret = paw32xx_write_reg(dev, PAW32XX_WRITE_PROTECT, WRITE_PROTECT_DISABLE);
253 	if (ret < 0) {
254 		return ret;
255 	}
256 
257 	ret = paw32xx_write_reg(dev, PAW32XX_CPI_X, val);
258 	if (ret < 0) {
259 		return ret;
260 	}
261 
262 	ret = paw32xx_write_reg(dev, PAW32XX_CPI_Y, val);
263 	if (ret < 0) {
264 		return ret;
265 	}
266 
267 	ret = paw32xx_write_reg(dev, PAW32XX_WRITE_PROTECT, WRITE_PROTECT_ENABLE);
268 	if (ret < 0) {
269 		return ret;
270 	}
271 
272 	return 0;
273 }
274 
paw32xx_force_awake(const struct device * dev,bool enable)275 int paw32xx_force_awake(const struct device *dev, bool enable)
276 {
277 	uint8_t val = enable ? 0 : OPERATION_MODE_SLP_MASK;
278 	int ret;
279 
280 	ret = paw32xx_write_reg(dev, PAW32XX_WRITE_PROTECT, WRITE_PROTECT_DISABLE);
281 	if (ret < 0) {
282 		return ret;
283 	}
284 
285 	ret = paw32xx_update_reg(dev, PAW32XX_OPERATION_MODE,
286 				 OPERATION_MODE_SLP_MASK, val);
287 	if (ret < 0) {
288 		return ret;
289 	}
290 
291 	ret = paw32xx_write_reg(dev, PAW32XX_WRITE_PROTECT, WRITE_PROTECT_ENABLE);
292 	if (ret < 0) {
293 		return ret;
294 	}
295 
296 	return 0;
297 }
298 
paw32xx_configure(const struct device * dev)299 static int paw32xx_configure(const struct device *dev)
300 {
301 	const struct paw32xx_config *cfg = dev->config;
302 	uint8_t val;
303 	int ret;
304 
305 	ret = paw32xx_read_reg(dev, PAW32XX_PRODUCT_ID1, &val);
306 	if (ret < 0) {
307 		return ret;
308 	}
309 
310 	if (val != PRODUCT_ID_PAW32XX) {
311 		LOG_ERR("Invalid product id: %02x", val);
312 		return -ENOTSUP;
313 	}
314 
315 	ret = paw32xx_update_reg(dev, PAW32XX_CONFIGURATION,
316 				 CONFIGURATION_RESET, CONFIGURATION_RESET);
317 	if (ret < 0) {
318 		return ret;
319 	}
320 
321 	k_sleep(K_MSEC(RESET_DELAY_MS));
322 
323 	if (cfg->invert_x || cfg->invert_y) {
324 		ret = paw32xx_write_reg(dev, PAW32XX_WRITE_PROTECT, WRITE_PROTECT_DISABLE);
325 		if (ret < 0) {
326 			return ret;
327 		}
328 
329 		ret = paw32xx_read_reg(dev, PAW32XX_MOUSE_OPTION, &val);
330 		if (ret < 0) {
331 			return ret;
332 		}
333 
334 		WRITE_BIT(val, MOUSE_OPTION_MOVX_INV_BIT, cfg->invert_x);
335 		WRITE_BIT(val, MOUSE_OPTION_MOVY_INV_BIT, cfg->invert_y);
336 
337 		ret = paw32xx_write_reg(dev, PAW32XX_MOUSE_OPTION, val);
338 		if (ret < 0) {
339 			return ret;
340 		}
341 
342 		ret = paw32xx_write_reg(dev, PAW32XX_WRITE_PROTECT, WRITE_PROTECT_ENABLE);
343 		if (ret < 0) {
344 			return ret;
345 		}
346 	}
347 
348 	if (cfg->res_cpi > 0) {
349 		paw32xx_set_resolution(dev, cfg->res_cpi);
350 	}
351 
352 	paw32xx_force_awake(dev, cfg->force_awake);
353 
354 	return 0;
355 }
356 
paw32xx_init(const struct device * dev)357 static int paw32xx_init(const struct device *dev)
358 {
359 	const struct paw32xx_config *cfg = dev->config;
360 	struct paw32xx_data *data = dev->data;
361 	int ret;
362 
363 	if (!spi_is_ready_dt(&cfg->spi)) {
364 		LOG_ERR("%s is not ready", cfg->spi.bus->name);
365 		return -ENODEV;
366 	}
367 
368 	data->dev = dev;
369 
370 	k_work_init(&data->motion_work, paw32xx_motion_work_handler);
371 
372 	if (!gpio_is_ready_dt(&cfg->motion_gpio)) {
373 		LOG_ERR("%s is not ready", cfg->motion_gpio.port->name);
374 		return -ENODEV;
375 	}
376 
377 	ret = gpio_pin_configure_dt(&cfg->motion_gpio, GPIO_INPUT);
378 	if (ret != 0) {
379 		LOG_ERR("Motion pin configuration failed: %d", ret);
380 		return ret;
381 	}
382 
383 	gpio_init_callback(&data->motion_cb, paw32xx_motion_handler,
384 			   BIT(cfg->motion_gpio.pin));
385 
386 	ret = gpio_add_callback_dt(&cfg->motion_gpio, &data->motion_cb);
387 	if (ret < 0) {
388 		LOG_ERR("Could not set motion callback: %d", ret);
389 		return ret;
390 	}
391 
392 	ret = paw32xx_configure(dev);
393 	if (ret != 0) {
394 		LOG_ERR("Device configuration failed: %d", ret);
395 		return ret;
396 	}
397 
398 	ret = gpio_pin_interrupt_configure_dt(&cfg->motion_gpio,
399 					      GPIO_INT_EDGE_TO_ACTIVE);
400 	if (ret != 0) {
401 		LOG_ERR("Motion interrupt configuration failed: %d", ret);
402 		return ret;
403 	}
404 
405 	ret = pm_device_runtime_enable(dev);
406 	if (ret < 0) {
407 		LOG_ERR("Failed to enable runtime power management: %d", ret);
408 		return ret;
409 	}
410 
411 	return 0;
412 }
413 
414 #ifdef CONFIG_PM_DEVICE
paw32xx_pm_action(const struct device * dev,enum pm_device_action action)415 static int paw32xx_pm_action(const struct device *dev,
416 			     enum pm_device_action action)
417 {
418 	int ret;
419 	uint8_t val;
420 
421 	switch (action) {
422 	case PM_DEVICE_ACTION_SUSPEND:
423 		val = CONFIGURATION_PD_ENH;
424 		break;
425 	case PM_DEVICE_ACTION_RESUME:
426 		val = 0;
427 		break;
428 	default:
429 		return -ENOTSUP;
430 	}
431 
432 	ret = paw32xx_update_reg(dev, PAW32XX_CONFIGURATION,
433 				 CONFIGURATION_PD_ENH, val);
434 	if (ret < 0) {
435 		return ret;
436 	}
437 
438 	return 0;
439 }
440 #endif
441 
442 #define PAW32XX_SPI_MODE (SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | \
443 			  SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_TRANSFER_MSB)
444 
445 #define PAW32XX_INIT(n)								\
446 	BUILD_ASSERT(IN_RANGE(DT_INST_PROP_OR(n, res_cpi, RES_MIN),		\
447 			      RES_MIN, RES_MAX), "invalid res-cpi");		\
448 										\
449 	static const struct paw32xx_config paw32xx_cfg_##n = {			\
450 		.spi = SPI_DT_SPEC_INST_GET(n, PAW32XX_SPI_MODE, 0),		\
451 		.motion_gpio = GPIO_DT_SPEC_INST_GET(n, motion_gpios),		\
452 		.axis_x = DT_INST_PROP(n, zephyr_axis_x),			\
453 		.axis_y = DT_INST_PROP(n, zephyr_axis_y),			\
454 		.res_cpi = DT_INST_PROP_OR(n, res_cpi, -1),			\
455 		.invert_x = DT_INST_PROP(n, invert_x),				\
456 		.invert_y = DT_INST_PROP(n, invert_y),				\
457 		.force_awake = DT_INST_PROP(n, force_awake),			\
458 	};									\
459 										\
460 	static struct paw32xx_data paw32xx_data_##n;				\
461 										\
462 	PM_DEVICE_DT_INST_DEFINE(n, paw32xx_pm_action);				\
463 										\
464 	DEVICE_DT_INST_DEFINE(n, paw32xx_init, PM_DEVICE_DT_INST_GET(n),	\
465 			      &paw32xx_data_##n, &paw32xx_cfg_##n,		\
466 			      POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY,		\
467 			      NULL);
468 
469 DT_INST_FOREACH_STATUS_OKAY(PAW32XX_INIT)
470