From b9f900faa70920a55a6307ce4a7164e5a1c03a6a Mon Sep 17 00:00:00 2001 From: Cedric Vincent Date: Sat, 25 Sep 2021 12:06:43 +0200 Subject: [PATCH] feat(sensor): Add Pimoroni PIM447 trackball driver. --- app/drivers/sensor/CMakeLists.txt | 3 +- app/drivers/sensor/Kconfig | 3 +- .../sensor/trackball_pim447/CMakeLists.txt | 4 + app/drivers/sensor/trackball_pim447/Kconfig | 8 + .../trackball_pim447/trackball_pim447.c | 167 ++++++++++++++++++ 5 files changed, 183 insertions(+), 2 deletions(-) create mode 100644 app/drivers/sensor/trackball_pim447/CMakeLists.txt create mode 100644 app/drivers/sensor/trackball_pim447/Kconfig create mode 100644 app/drivers/sensor/trackball_pim447/trackball_pim447.c diff --git a/app/drivers/sensor/CMakeLists.txt b/app/drivers/sensor/CMakeLists.txt index b549320f..d5e35e75 100644 --- a/app/drivers/sensor/CMakeLists.txt +++ b/app/drivers/sensor/CMakeLists.txt @@ -2,4 +2,5 @@ # SPDX-License-Identifier: MIT add_subdirectory_ifdef(CONFIG_ZMK_BATTERY battery) -add_subdirectory_ifdef(CONFIG_EC11 ec11) \ No newline at end of file +add_subdirectory_ifdef(CONFIG_EC11 ec11) +add_subdirectory_ifdef(CONFIG_ZMK_TRACKBALL_PIM447 trackball_pim447) diff --git a/app/drivers/sensor/Kconfig b/app/drivers/sensor/Kconfig index a828f6c6..fcf451a1 100644 --- a/app/drivers/sensor/Kconfig +++ b/app/drivers/sensor/Kconfig @@ -2,4 +2,5 @@ # SPDX-License-Identifier: MIT rsource "battery/Kconfig" -rsource "ec11/Kconfig" \ No newline at end of file +rsource "ec11/Kconfig" +rsource "trackball_pim447/Kconfig" diff --git a/app/drivers/sensor/trackball_pim447/CMakeLists.txt b/app/drivers/sensor/trackball_pim447/CMakeLists.txt new file mode 100644 index 00000000..03e20c65 --- /dev/null +++ b/app/drivers/sensor/trackball_pim447/CMakeLists.txt @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() +zephyr_library_sources(trackball_pim447.c) diff --git a/app/drivers/sensor/trackball_pim447/Kconfig b/app/drivers/sensor/trackball_pim447/Kconfig new file mode 100644 index 00000000..ac837b93 --- /dev/null +++ b/app/drivers/sensor/trackball_pim447/Kconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config ZMK_TRACKBALL_PIM447 + bool "ZMK PIM447 trackball" + depends on I2C + help + Enable I2C-based driver for Pimoroni PIM447 trackball. diff --git a/app/drivers/sensor/trackball_pim447/trackball_pim447.c b/app/drivers/sensor/trackball_pim447/trackball_pim447.c new file mode 100644 index 00000000..6efb1ef8 --- /dev/null +++ b/app/drivers/sensor/trackball_pim447/trackball_pim447.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT pimoroni_trackball_pim447 + +#include +#include + +#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL +#include +LOG_MODULE_REGISTER(trackball_pim447); + +#define TRACKBALL_PIM447_REG_LEFT 0x04 +#define TRACKBALL_PIM447_REG_RIGHT 0x05 +#define TRACKBALL_PIM447_REG_UP 0x06 +#define TRACKBALL_PIM447_REG_DOWN 0x07 +#define TRACKBALL_PIM447_REG_SWITCH 0x08 + +#define TRACKBALL_PIM447_REG_MIN TRACKBALL_PIM447_REG_LEFT +#define TRACKBALL_PIM447_REG_MAX TRACKBALL_PIM447_REG_SWITCH + +struct trackball_pim447_data { + const struct device *i2c_dev; + int32_t dx; + int32_t dy; + int32_t dz; +}; + +static int trackball_pim447_read_reg(const struct device *dev, + uint8_t reg, uint8_t *value) +{ + struct trackball_pim447_data *data = dev->data; + + if (reg < TRACKBALL_PIM447_REG_MIN || reg > TRACKBALL_PIM447_REG_MAX) { + return -ENOTSUP; + } + + int status = i2c_reg_read_byte(data->i2c_dev, DT_INST_REG_ADDR(0), + reg, value); + if (status < 0) { + LOG_ERR("Sensor reg read byte failed"); + return status; + } + + return 0; +} + +static int trackball_pim447_read_axis(const struct device *dev, + uint8_t reg_negative, + uint8_t reg_positive, + int32_t *value) +{ + uint8_t value_negative; + uint8_t value_positive; + int status; + + status = trackball_pim447_read_reg(dev, reg_negative, &value_negative); + if (status < 0) { + return status; + } + + status = trackball_pim447_read_reg(dev, reg_positive, &value_positive); + if (status < 0) { + return status; + } + + *value = value_positive - value_negative; + + return 0; +} + +static int trackball_pim447_sample_fetch(const struct device *dev, + enum sensor_channel chan) +{ + struct trackball_pim447_data *data = dev->data; + int status; + + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_POS_DX) { + status = trackball_pim447_read_axis(dev, + TRACKBALL_PIM447_REG_LEFT, + TRACKBALL_PIM447_REG_RIGHT, + &data->dx); + if (status < 0) { + return status; + } + } + + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_POS_DY) { + status = trackball_pim447_read_axis(dev, + TRACKBALL_PIM447_REG_UP, + TRACKBALL_PIM447_REG_DOWN, + &data->dy); + if (status < 0) { + return status; + } + } + + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_POS_DZ) { + uint8_t value; + status = trackball_pim447_read_reg(dev, + TRACKBALL_PIM447_REG_SWITCH, + &value); + if (status < 0) { + return status; + } + + data->dz = value; + } + + return 0; +} + +static int trackball_pim447_channel_get(const struct device *dev, + enum sensor_channel chan, + struct sensor_value *val) +{ + struct trackball_pim447_data *data = dev->data; + + /* Not used. */ + val->val2 = 0; + + switch (chan) { + case SENSOR_CHAN_POS_DX: + val->val1 = data->dx; + break; + + case SENSOR_CHAN_POS_DY: + val->val1 = data->dy; + break; + + case SENSOR_CHAN_POS_DZ: + val->val1 = data->dz; + break; + + default: + return -ENOTSUP; + } + + return 0; +} + +static int trackball_pim447_init(const struct device *dev) +{ + struct trackball_pim447_data *data = dev->data; + + data->i2c_dev = device_get_binding(DT_INST_BUS_LABEL(0)); + if (data->i2c_dev == NULL) { + LOG_ERR("Failed to get I2C device"); + return -EINVAL; + } + + return 0; +} + +static struct trackball_pim447_data trackball_pim447_data; + +static const struct sensor_driver_api trackball_pim447_api = { + .sample_fetch = trackball_pim447_sample_fetch, + .channel_get = trackball_pim447_channel_get, +}; + +DEVICE_DT_INST_DEFINE(0, &trackball_pim447_init, device_pm_control_nop, + &trackball_pim447_data, NULL, POST_KERNEL, + CONFIG_SENSOR_INIT_PRIORITY, &trackball_pim447_api);