diff --git a/drivers/input/input_pat912x.c b/drivers/input/input_pat912x.c index 616984ddac57d7f..3336098cbaccbc2 100644 --- a/drivers/input/input_pat912x.c +++ b/drivers/input/input_pat912x.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,9 @@ LOG_MODULE_REGISTER(input_pat912x, CONFIG_INPUT_LOG_LEVEL); #define WRITE_PROTECT_ENABLE 0x00 #define WRITE_PROTECT_DISABLE 0x5a #define MOTION_STATUS_MOTION BIT(7) +#define RES_SCALING_FACTOR 5 +#define OPERATION_MODE_SLEEP_1_EN BIT(4) +#define OPERATION_MODE_SLEEP_12_EN (BIT(4) | BIT(3)) #define PAT912X_DATA_SIZE_BITS 12 @@ -57,6 +61,12 @@ struct pat912x_config { struct gpio_dt_spec motion_gpio; int32_t axis_x; int32_t axis_y; + int16_t res_x_cpi; + int16_t res_y_cpi; + bool invert_x; + bool invert_y; + bool sleep1_enable; + bool sleep2_enable; }; struct pat912x_data { @@ -102,6 +112,13 @@ static void pat912x_motion_work_handler(struct k_work *work) x = sign_extend(x, PAT912X_DATA_SIZE_BITS - 1); y = sign_extend(y, PAT912X_DATA_SIZE_BITS - 1); + if (cfg->invert_x) { + x *= -1; + } + if (cfg->invert_y) { + y *= -1; + } + LOG_DBG("x=%4d y=%4d", x, y); if (cfg->axis_x >= 0) { @@ -128,6 +145,41 @@ static void pat912x_motion_handler(const struct device *gpio_dev, k_work_submit(&data->motion_work); } +int pat912x_set_resolution(const struct device *dev, + int16_t res_x_cpi, int16_t res_y_cpi) +{ + const struct pat912x_config *cfg = dev->config; + int ret; + + if (res_x_cpi >= 0) { + if (!IN_RANGE(res_x_cpi, 0, UINT8_MAX * RES_SCALING_FACTOR)) { + LOG_ERR("res_x_cpi out of range: %d", res_x_cpi); + return -EINVAL; + } + + ret = i2c_reg_write_byte_dt(&cfg->i2c, PAT912X_RES_X, + res_x_cpi / RES_SCALING_FACTOR); + if (ret < 0) { + return ret; + } + } + + if (res_y_cpi >= 0) { + if (!IN_RANGE(res_y_cpi, 0, UINT8_MAX * RES_SCALING_FACTOR)) { + LOG_ERR("res_y_cpi out of range: %d", res_y_cpi); + return -EINVAL; + } + + ret = i2c_reg_write_byte_dt(&cfg->i2c, PAT912X_RES_Y, + res_y_cpi / RES_SCALING_FACTOR); + if (ret < 0) { + return ret; + } + } + + return 0; +} + static int pat912x_configure(const struct device *dev) { const struct pat912x_config *cfg = dev->config; @@ -156,6 +208,29 @@ static int pat912x_configure(const struct device *dev) return ret; } + ret = pat912x_set_resolution(dev, cfg->res_x_cpi, cfg->res_y_cpi); + if (ret < 0) { + return ret; + } + + if (cfg->sleep1_enable && cfg->sleep2_enable) { + ret = i2c_reg_update_byte_dt(&cfg->i2c, + PAT912X_OPERATION_MODE, + OPERATION_MODE_SLEEP_12_EN, + OPERATION_MODE_SLEEP_12_EN); + if (ret < 0) { + return ret; + } + } else if (cfg->sleep1_enable) { + ret = i2c_reg_update_byte_dt(&cfg->i2c, + PAT912X_OPERATION_MODE, + OPERATION_MODE_SLEEP_12_EN, + OPERATION_MODE_SLEEP_1_EN); + if (ret < 0) { + return ret; + } + } + return 0; } @@ -254,6 +329,12 @@ static int pat912x_pm_action(const struct device *dev, .motion_gpio = GPIO_DT_SPEC_INST_GET(n, motion_gpios), \ .axis_x = DT_INST_PROP_OR(n, zephyr_axis_x, -1), \ .axis_y = DT_INST_PROP_OR(n, zephyr_axis_y, -1), \ + .res_x_cpi = DT_INST_PROP_OR(n, res_x_cpi, -1), \ + .res_y_cpi = DT_INST_PROP_OR(n, res_y_cpi, -1), \ + .invert_x = DT_INST_PROP(n, invert_x), \ + .invert_y = DT_INST_PROP(n, invert_y), \ + .sleep1_enable = DT_INST_PROP(n, sleep1_enable), \ + .sleep2_enable = DT_INST_PROP(n, sleep2_enable), \ }; \ \ static struct pat912x_data pat912x_data_##n; \ diff --git a/dts/bindings/input/pixart,pat912x.yaml b/dts/bindings/input/pixart,pat912x.yaml index 0a50161032c2c61..354e265c021e396 100644 --- a/dts/bindings/input/pixart,pat912x.yaml +++ b/dts/bindings/input/pixart,pat912x.yaml @@ -25,3 +25,35 @@ properties: description: | The input code for the Y axis to report for the device, typically any of INPUT_REL_*. No report produced for the device Y axis if unspecified. + + res-x-cpi: + type: int + description: | + CPI resolution for the X axis, range 0 to 1275, rounded down to the + closest supported value in increments of 5. + + res-y-cpi: + type: int + description: | + CPI resolution for the Y axis, range 0 to 1275, rounded down to the + closest supported value in increments of 5. + + invert-x: + type: boolean + description: | + Invert X axis values. + + invert-y: + type: boolean + description: | + Invert Y axis values. + + sleep1-enable: + type: boolean + description: | + Enable sleep1 mode. + + sleep2-enable: + type: boolean + description: | + Enable sleep2 mode, only valid if sleep1 is also enabled. diff --git a/include/zephyr/input/input_pat912x.h b/include/zephyr/input/input_pat912x.h new file mode 100644 index 000000000000000..8cbb738d1185d9a --- /dev/null +++ b/include/zephyr/input/input_pat912x.h @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_INPUT_PAT912X_H_ +#define ZEPHYR_INCLUDE_INPUT_PAT912X_H_ + +/** + * @brief Set resolution on a pat912x device + * + * @param dev pat912x device. + * @param res_x_cpi CPI resolution for the X axis, 0 to 1275, -1 to keep the + * current value. + * @param res_y_cpi CPI resolution for the Y axis, 0 to 1275, -1 to keep the + * current value. + */ +int pat912x_set_resolution(const struct device *dev, + int16_t res_x_cpi, int16_t res_y_cpi); + +#endif /* ZEPHYR_INCLUDE_INPUT_PAT912X_H_ */ diff --git a/tests/drivers/build_all/input/app.overlay b/tests/drivers/build_all/input/app.overlay index dc1d2375397cb17..6cfaae7066b7985 100644 --- a/tests/drivers/build_all/input/app.overlay +++ b/tests/drivers/build_all/input/app.overlay @@ -204,6 +204,12 @@ motion-gpios = <&test_gpio 0 0>; zephyr,axis-x = <0>; zephyr,axis-y = <1>; + res-x-cpi = <0>; + res-y-cpi = <0>; + invert-x; + invert-y; + sleep1-enable; + sleep2-enable; }; };