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