From af5969e135f0b045a24fd3fbeb3a7b5116f44512 Mon Sep 17 00:00:00 2001 From: Ryan Walker Date: Mon, 28 Nov 2022 15:26:53 -0800 Subject: [PATCH] Implemented iqs5xx driver --- drivers/touch/CMakeLists.txt | 1 + drivers/touch/Kconfig | 16 + drivers/touch/iqs5xx/CMakeLists.txt | 2 + drivers/touch/iqs5xx/Kconfig | 34 +++ drivers/touch/iqs5xx/iqs5xx.c | 344 ++++++++++++++++++++++ drivers/touch/iqs5xx/iqs5xx.h | 126 ++++++++ dts/bindings/touch/azoteq,iqs5xx.yaml | 12 + include/zephyr/drivers/touch.h | 117 ++++++++ samples/index.rst | 1 + samples/touch/iqs5xx/CMakeLists.txt | 7 + samples/touch/iqs5xx/README.rst | 47 +++ samples/touch/iqs5xx/boards/esp32.overlay | 13 + samples/touch/iqs5xx/prj.conf | 9 + samples/touch/iqs5xx/sample.yaml | 12 + samples/touch/iqs5xx/src/main.c | 39 +++ samples/touch/touch.rst | 10 + 16 files changed, 790 insertions(+) create mode 100644 drivers/touch/CMakeLists.txt create mode 100644 drivers/touch/Kconfig create mode 100644 drivers/touch/iqs5xx/CMakeLists.txt create mode 100644 drivers/touch/iqs5xx/Kconfig create mode 100644 drivers/touch/iqs5xx/iqs5xx.c create mode 100644 drivers/touch/iqs5xx/iqs5xx.h create mode 100644 dts/bindings/touch/azoteq,iqs5xx.yaml create mode 100644 include/zephyr/drivers/touch.h create mode 100644 samples/touch/iqs5xx/CMakeLists.txt create mode 100644 samples/touch/iqs5xx/README.rst create mode 100644 samples/touch/iqs5xx/boards/esp32.overlay create mode 100644 samples/touch/iqs5xx/prj.conf create mode 100644 samples/touch/iqs5xx/sample.yaml create mode 100644 samples/touch/iqs5xx/src/main.c create mode 100644 samples/touch/touch.rst diff --git a/drivers/touch/CMakeLists.txt b/drivers/touch/CMakeLists.txt new file mode 100644 index 0000000000000..32eb983847ab7 --- /dev/null +++ b/drivers/touch/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory_ifdef(CONFIG_IQS5XX iqs5xx) diff --git a/drivers/touch/Kconfig b/drivers/touch/Kconfig new file mode 100644 index 0000000000000..4ed469c0c1e44 --- /dev/null +++ b/drivers/touch/Kconfig @@ -0,0 +1,16 @@ +# Copyright 2022 Interrupt Labs +# SPDX-License-Identifier: Apache-2.0 +menuconfig TOUCH + bool "Touch Drivers" + help + Include touch drivers in system config + +if TOUCH +config TOUCH_INIT_PRIORITY + int "Touch init priority" + default 90 + help + Touch initialization priority. + +source "drivers/touch/iqs5xx/Kconfig" +endif # TOUCH diff --git a/drivers/touch/iqs5xx/CMakeLists.txt b/drivers/touch/iqs5xx/CMakeLists.txt new file mode 100644 index 0000000000000..b9d08e0affaf3 --- /dev/null +++ b/drivers/touch/iqs5xx/CMakeLists.txt @@ -0,0 +1,2 @@ +zephyr_library() +zephyr_library_sources(iqs5xx.c) diff --git a/drivers/touch/iqs5xx/Kconfig b/drivers/touch/iqs5xx/Kconfig new file mode 100644 index 0000000000000..d97baebda8886 --- /dev/null +++ b/drivers/touch/iqs5xx/Kconfig @@ -0,0 +1,34 @@ +# IQS5XX Trackpad Controller + +# Copyright (C) 2022 Ryan Walker +# SPDX-License-Identifier: Apache-2.0 + +config TOUCH_LOG_LEVEL + int "Log Level for Touch" + default 4 + +config IQS5XX + bool "IQS5XX Driver" + depends on I2C && GPIO + help + Projected capacitive trackpad/touchscreen controller. + +config IQS5XX_X_RES + int "IQS5XX X Resolution" + depends on IQS5XX + default 3072 + +config IQS5XX_Y_RES + int "IQS5XX Y Resolution" + depends on IQS5XX + default 2048 + +config IQS5XX_TOTAL_RX + int "IQS5XX RX Channels" + depends on IQS5XX + default 9 + +config IQS5XX_TOTAL_TX + int "IQS5XX RX Channels" + depends on IQS5XX + default 13 diff --git a/drivers/touch/iqs5xx/iqs5xx.c b/drivers/touch/iqs5xx/iqs5xx.c new file mode 100644 index 0000000000000..2d48b21329d5e --- /dev/null +++ b/drivers/touch/iqs5xx/iqs5xx.c @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2022 Ryan Walker + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT azoteq_iqs5xx + +#include +#include +#include +#include +#include +#include +LOG_MODULE_REGISTER(iqs5xx, CONFIG_TOUCH_LOG_LEVEL); + +#include "iqs5xx.h" + +static int iqs5xx_read_burst(const struct i2c_dt_spec *client, uint16_t reg, void *val, + uint16_t len) +{ + uint16_t be_reg = sys_cpu_to_be16(reg); + int ret, i; + bool fail = false; + + for (i = 0; i < IQS5XX_NUM_RETRIES; i++) { + ret = i2c_write_read_dt(client, &be_reg, sizeof(be_reg), val, len); + + if (ret >= 0) { + if (fail) + LOG_INF("I2C Error Corrected"); + return 0; + } + + LOG_ERR("I2C Transfer Failed, retrying"); + k_sleep(K_USEC(150)); + fail = true; + } + + LOG_ERR("Failed to read from address 0x%04X: %d\n", reg, ret); + + return ret; +} + +static int iqs5xx_read_word(const struct i2c_dt_spec *client, uint16_t reg, uint16_t *val) +{ + uint16_t val_buf; + int error; + + error = iqs5xx_read_burst(client, reg, &val_buf, sizeof(val_buf)); + if (error) { + return error; + } + + *val = sys_be16_to_cpu(val_buf); + + return 0; +} + +static int iqs5xx_write_burst(const struct i2c_dt_spec *client, uint16_t reg, const void *val, + uint16_t len) +{ + int ret, i; + uint16_t mlen = sizeof(reg) + len; + uint8_t mbuf[sizeof(reg) + IQS5XX_WR_BYTES_MAX]; + + if (len > IQS5XX_WR_BYTES_MAX) { + return -EINVAL; + } + + sys_put_be16(reg, mbuf); + memcpy(mbuf + sizeof(reg), val, len); + + /* + * The first addressing attempt outside of a communication window fails + * and must be retried, after which the device clock stretches until it + * is available. + */ + for (i = 0; i < IQS5XX_NUM_RETRIES; i++) { + ret = i2c_write_dt(client, mbuf, mlen); + if (ret == 0) { + return 0; + } + + k_sleep(K_USEC(200)); + } + + if (ret >= 0) { + ret = -EIO; + } + + LOG_ERR("Failed to write to address 0x%04X: %d\n", reg, ret); + + return ret; +} + +static int iqs5xx_write_word(const struct i2c_dt_spec *client, uint16_t reg, uint16_t val) +{ + uint16_t val_buf = sys_cpu_to_be16(val); + + return iqs5xx_write_burst(client, reg, &val_buf, sizeof(val_buf)); +} + +static int iqs5xx_write_byte(const struct i2c_dt_spec *client, uint16_t reg, uint8_t val) +{ + return iqs5xx_write_burst(client, reg, &val, sizeof(val)); +} + +static void setup_int(const struct device *dev, bool enable) +{ + const struct iqs5xx_dev_config *cfg = dev->config; + gpio_flags_t flags = enable ? GPIO_INT_EDGE_RISING : GPIO_INT_DISABLE; + + gpio_pin_interrupt_configure_dt(&cfg->rdy_gpio, flags); +} + +static void iqs5xx_gpio_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins) +{ + struct iqs5xx_data *data = CONTAINER_OF(cb, struct iqs5xx_data, gpio_cb); + + setup_int(data->dev, false); + k_work_submit(&data->work); +} + +static void iqs5xx_work_cb(struct k_work *work) +{ + struct iqs5xx_data *data = CONTAINER_OF(work, struct iqs5xx_data, work); + + const struct iqs5xx_dev_config *cfg = data->dev->config; + + iqs5xx_read_burst(&cfg->i2c, IQS5XX_GEST_EV0, &data->regmap, sizeof(data->regmap)); + + iqs5xx_write_byte(&cfg->i2c, IQS5XX_END_COMM, 0); + + /* Small delay required as the iqs twiddles the rdy pin. */ + k_sleep(K_USEC(50)); + + if (data->regmap.gesture_event[0]) { + switch (data->regmap.gesture_event[0] & 0b00111111) { + case IQS5XX_SINGLE_TAP: + LOG_DBG("Single Tap"); + break; + case IQS5XX_TAP_AND_HOLD: + LOG_DBG("Tap And Hold"); + break; + case IQS5XX_SWIPE_X_NEG: + LOG_DBG("Swipe X negative"); + break; + case IQS5XX_SWIPE_X_POS: + LOG_DBG("Swipe X positive"); + break; + case IQS5XX_SWIPE_Y_NEG: + LOG_DBG("Swipe Y negative"); + break; + case IQS5XX_SWIPE_Y_POS: + LOG_DBG("Swipe Y positive"); + break; + default: + LOG_DBG("%d", data->regmap.gesture_event[0]); + } + } + + if (data->regmap.gesture_event[1]) { + switch (data->regmap.gesture_event[1] & 0b00000111) { + case IQS5XX_TWO_FINGER_TAP: + LOG_DBG("Two Finger Tap"); + break; + case IQS5XX_SCROLL: + LOG_DBG("Scroll"); + break; + case IQS5XX_ZOOM: + LOG_DBG("Zoom"); + break; + default: + LOG_DBG("%d", data->regmap.gesture_event[1]); + } + } + + setup_int(data->dev, true); +} + +int iqs5xx_init_interrupt(const struct device *dev) +{ + struct iqs5xx_data *data = dev->data; + const struct iqs5xx_dev_config *cfg = dev->config; + int ret; + + if (!device_is_ready(cfg->rdy_gpio.port)) { + LOG_ERR("%s: device %s is not ready", dev->name, cfg->rdy_gpio.port->name); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&cfg->rdy_gpio, GPIO_INPUT | cfg->rdy_gpio.dt_flags); + if (ret < 0) { + return ret; + } + + gpio_init_callback(&data->gpio_cb, iqs5xx_gpio_callback, BIT(cfg->rdy_gpio.pin)); + + ret = gpio_add_callback(cfg->rdy_gpio.port, &data->gpio_cb); + if (ret < 0) { + return ret; + } + + data->dev = dev; + + data->work.handler = iqs5xx_work_cb; + return 0; +} + +static bool iqs5xx_two_finger_tap(const struct device *dev) +{ + struct iqs5xx_data *data = dev->data; + + if (data->regmap.gesture_event[0] & IQS5XX_TWO_FINGER_TAP) { + data->regmap.gesture_event[0] &= ~IQS5XX_TWO_FINGER_TAP; + return true; + } + + return false; +} + +static bool iqs5xx_single_tap(const struct device *dev) +{ + struct iqs5xx_data *data = dev->data; + + if (data->regmap.gesture_event[0] & IQS5XX_SINGLE_TAP) { + data->regmap.gesture_event[0] &= ~IQS5XX_SINGLE_TAP; + return true; + } + + return false; +} + +static int16_t iqs5xx_x_position_abs(const struct device *dev) +{ + struct iqs5xx_data *data = dev->data; + + return sys_be16_to_cpu(data->regmap.touch_data[0].abs_x); +} + +static int16_t iqs5xx_y_position_abs(const struct device *dev) +{ + struct iqs5xx_data *data = dev->data; + + return sys_be16_to_cpu(data->regmap.touch_data[0].abs_y); +} + +static int16_t iqs5xx_x_position_rel(const struct device *dev) +{ + struct iqs5xx_data *data = dev->data; + + return sys_be16_to_cpu(data->regmap.rel_x); +} + +static int16_t iqs5xx_y_position_rel(const struct device *dev) +{ + struct iqs5xx_data *data = dev->data; + + return sys_be16_to_cpu(data->regmap.rel_y); +} + +static int iqs5xx_num_fingers(const struct device *dev) +{ + struct iqs5xx_data *data = dev->data; + + return data->regmap.num_fin; +} + +static const struct touch_driver_api iqs5xx_driver_api = { + .single_tap = &iqs5xx_single_tap, + .two_finger_tap = &iqs5xx_two_finger_tap, + .x_pos_abs = &iqs5xx_x_position_abs, + .y_pos_abs = &iqs5xx_y_position_abs, + .x_pos_rel = &iqs5xx_x_position_rel, + .y_pos_rel = &iqs5xx_y_position_rel, + .num_fingers = &iqs5xx_num_fingers, +}; + +static int iqs5xx_init(const struct device *dev) +{ + const struct iqs5xx_dev_config *cfg = dev->config; + uint8_t value = 0; + int ret = 0; + int timeout = 0; + uint16_t k; + + if (!device_is_ready(cfg->i2c.bus)) { + LOG_ERR("Bus device is not ready"); + return -EINVAL; + } + + if (cfg->rdy_gpio.port) { + ret = iqs5xx_init_interrupt(dev); + if (ret < 0) { + LOG_ERR("Failed to initialize interrupt!"); + return ret; + } + } else { + LOG_ERR("RDY GPIO not Ready"); + } + + iqs5xx_read_word(&cfg->i2c, IQS5XX_PROD_NUM, &k); + + /* Configure trackpad size */ + iqs5xx_write_byte(&cfg->i2c, IQS5XX_TOTAL_RX, CONFIG_IQS5XX_TOTAL_RX); + iqs5xx_write_byte(&cfg->i2c, IQS5XX_TOTAL_TX, CONFIG_IQS5XX_TOTAL_TX); + + iqs5xx_write_byte(&cfg->i2c, IQS5XX_SINGLE_FINGER_GEST, IQS5XX_SINGLE_TAP); + + iqs5xx_write_byte(&cfg->i2c, IQS5XX_MULTI_FINGER_GEST, IQS5XX_TWO_FINGER_TAP); + + iqs5xx_write_byte(&cfg->i2c, IQS5XX_SYS_CTRL0, IQS5XX_ACK_RESET); + + iqs5xx_write_byte(&cfg->i2c, IQS5XX_SYS_CFG0, + IQS5XX_SETUP_COMPLETE | IQS5XX_WDT | IQS5XX_ALP_REATI | IQS5XX_REATI); + + iqs5xx_write_byte(&cfg->i2c, IQS5XX_SYS_CFG1, + IQS5XX_GESTURE_EVENT | IQS5XX_EVENT_MODE | IQS5XX_TP_EVENT); + + iqs5xx_write_word(&cfg->i2c, IQS5XX_X_RES, CONFIG_IQS5XX_X_RES); + iqs5xx_write_word(&cfg->i2c, IQS5XX_Y_RES, CONFIG_IQS5XX_Y_RES); + iqs5xx_write_byte(&cfg->i2c, IQS5XX_END_COMM, 0); + + LOG_INF("IQS Driver Probed. Product Number: 0x%x", k); + + setup_int(dev, true); + + return 0; +} + +#define IQS5XX_DEFINE(inst) \ + static struct iqs5xx_data iqs5xx_data_##inst;\ + \ + static const struct iqs5xx_dev_config iqs5xx_config_##inst = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst),\ + .rdy_gpio = GPIO_DT_SPEC_INST_GET(inst, rdy_gpios),\ + };\ + \ + DEVICE_DT_INST_DEFINE(inst, iqs5xx_init, NULL, &iqs5xx_data_##inst, \ + &iqs5xx_config_##inst, POST_KERNEL, CONFIG_TOUCH_INIT_PRIORITY, \ + &iqs5xx_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(IQS5XX_DEFINE) diff --git a/drivers/touch/iqs5xx/iqs5xx.h b/drivers/touch/iqs5xx/iqs5xx.h new file mode 100644 index 0000000000000..5b14e918f9ca8 --- /dev/null +++ b/drivers/touch/iqs5xx/iqs5xx.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2022 Ryan Walker + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#define IQS5XX_FW_FILE_LEN 64 +#define IQS5XX_NUM_RETRIES 10 +#define IQS5XX_NUM_CONTACTS 5 +#define IQS5XX_WR_BYTES_MAX 2 + +#define IQS5XX_PROD_NUM_IQS550 40 +#define IQS5XX_PROD_NUM_IQS572 58 +#define IQS5XX_PROD_NUM_IQS525 52 + +#define IQS5XX_SHOW_RESET BIT(7) +#define IQS5XX_ACK_RESET BIT(7) + +#define IQS5XX_SUSPEND BIT(0) +#define IQS5XX_RESUME 0 + +#define IQS5XX_SETUP_COMPLETE BIT(6) +#define IQS5XX_WDT BIT(5) +#define IQS5XX_ALP_REATI BIT(3) +#define IQS5XX_REATI BIT(2) + +#define IQS5XX_TP_EVENT BIT(2) +#define IQS5XX_GESTURE_EVENT BIT(1) +#define IQS5XX_EVENT_MODE BIT(0) + +#define IQS5XX_FLIP_X BIT(0) +#define IQS5XX_FLIP_Y BIT(1) + +#define IQS5XX_PROD_NUM 0x0000 +#define IQS5XX_GEST_EV0 0x000D +#define IQS5XX_GEST_EV1 0x000E +#define IQS5XX_SYS_INFO0 0x000F +#define IQS5XX_SYS_INFO1 0x0010 +#define IQS5XX_NUM_FINGERS 0x0011 +#define IQS5XX_SYS_CTRL0 0x0431 +#define IQS5XX_SYS_CTRL1 0x0432 +#define IQS5XX_REPORT_LP1 0x0580 +#define IQS5XX_REPORT_LP2 0x0582 +#define IQS5XX_TO_ACTIVE 0x0584 +#define IQS5XX_TO_IDLE_TCH 0x0585 +#define IQS5XX_TO_IDLE 0x0586 +#define IQS5XX_TO_LP1 0x0587 +#define IQS5XX_SYS_CFG0 0x058E +#define IQS5XX_SYS_CFG1 0x058F +#define IQS5XX_TOTAL_RX 0x063D +#define IQS5XX_TOTAL_TX 0x063E +#define IQS5XX_XY_CONFIG 0x0669 +#define IQS5XX_X_RES 0x066E +#define IQS5XX_Y_RES 0x0670 +#define IQS5XX_EXP_FILE 0x0677 +#define IQS5XX_SINGLE_FINGER_GEST 0x06b7 +#define IQS5XX_MULTI_FINGER_GEST 0x06b8 +#define IQS5XX_TAP_TIME 0x06b9 +#define IQS5XX_CHKSM 0x83C0 +#define IQS5XX_APP 0x8400 +#define IQS5XX_CSTM 0xBE00 +#define IQS5XX_PMAP_END 0xBFFF +#define IQS5XX_END_COMM 0xEEEE + +#define IQS5XX_CHKSM_LEN (IQS5XX_APP - IQS5XX_CHKSM) +#define IQS5XX_APP_LEN (IQS5XX_CSTM - IQS5XX_APP) +#define IQS5XX_CSTM_LEN (IQS5XX_PMAP_END + 1 - IQS5XX_CSTM) +#define IQS5XX_PMAP_LEN (IQS5XX_PMAP_END + 1 - IQS5XX_CHKSM) + +#define IQS5XX_REC_HDR_LEN 4 +#define IQS5XX_REC_LEN_MAX 255 +#define IQS5XX_REC_TYPE_DATA 0x00 +#define IQS5XX_REC_TYPE_EOF 0x01 + +#define IQS5XX_BL_ADDR_MASK 0x40 +#define IQS5XX_BL_CMD_VER 0x00 +#define IQS5XX_BL_CMD_READ 0x01 +#define IQS5XX_BL_CMD_EXEC 0x02 +#define IQS5XX_BL_CMD_CRC 0x03 +#define IQS5XX_BL_BLK_LEN_MAX 64 +#define IQS5XX_BL_ID 0x0200 +#define IQS5XX_BL_STATUS_NONE 0xEE +#define IQS5XX_BL_CRC_PASS 0x00 +#define IQS5XX_BL_CRC_FAIL 0x01 +#define IQS5XX_BL_ATTEMPTS 3 + +#define IQS5XX_SWIPE_Y_NEG 0x20 +#define IQS5XX_SWIPE_Y_POS 0x10 +#define IQS5XX_SWIPE_X_POS 0x08 +#define IQS5XX_SWIPE_X_NEG 0x04 +#define IQS5XX_TAP_AND_HOLD 0x02 +#define IQS5XX_SINGLE_TAP 0x01 + +#define IQS5XX_ZOOM 0x04 +#define IQS5XX_SCROLL 0x02 +#define IQS5XX_TWO_FINGER_TAP 0x01 + +struct iqs5xx_touch_data { + uint16_t abs_x; + uint16_t abs_y; + uint16_t touch_str; + uint8_t touch_area; +} __packed; + +struct iqs5xx_regmap { + uint8_t gesture_event[2]; + uint8_t sys_info[2]; + uint8_t num_fin; + uint16_t rel_x; + uint16_t rel_y; + struct iqs5xx_touch_data touch_data[IQS5XX_NUM_CONTACTS]; +} __packed; + +struct iqs5xx_data { + struct gpio_callback gpio_cb; + const struct device *dev; + struct iqs5xx_regmap regmap; + struct k_work work; +}; + +struct iqs5xx_dev_config { + struct i2c_dt_spec i2c; + struct gpio_dt_spec rdy_gpio; +}; diff --git a/dts/bindings/touch/azoteq,iqs5xx.yaml b/dts/bindings/touch/azoteq,iqs5xx.yaml new file mode 100644 index 0000000000000..aba0e4116f9cb --- /dev/null +++ b/dts/bindings/touch/azoteq,iqs5xx.yaml @@ -0,0 +1,12 @@ +description: IQS5XX Trackpad controller + +compatible: "azoteq,iqs5xx" + +include: i2c-device.yaml + +properties: + rdy-gpios: + type: phandle-array + required: true + description: | + The ready signal (RDY) from the IQSxxx. diff --git a/include/zephyr/drivers/touch.h b/include/zephyr/drivers/touch.h new file mode 100644 index 0000000000000..c72a93651432b --- /dev/null +++ b/include/zephyr/drivers/touch.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2022 Ryan Walker + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file drivers/touch.h + * + * @brief Public APIs for the touch driver. + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_TOUCH_H_ +#define ZEPHYR_INCLUDE_DRIVERS_TOUCH_H_ + +/** + * @brief Touch Interface + * @defgroup touch_interface Touch Interface + * @ingroup io_interfaces + * @{ + */ + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef bool (*single_tap_get_t)(const struct device *dev); +typedef bool (*two_finger_tap_get_t)(const struct device *dev); +typedef int16_t (*x_pos_get_abs_t)(const struct device *dev); +typedef int16_t (*y_pos_get_abs_t)(const struct device *dev); +typedef int16_t (*x_pos_get_rel_t)(const struct device *dev); +typedef int16_t (*y_pos_get_rel_t)(const struct device *dev); +typedef int (*num_fingers_get_t)(const struct device *dev); + +__subsystem struct touch_driver_api { + single_tap_get_t single_tap; + two_finger_tap_get_t two_finger_tap; + x_pos_get_abs_t x_pos_abs; + y_pos_get_abs_t y_pos_abs; + x_pos_get_rel_t x_pos_rel; + y_pos_get_rel_t y_pos_rel; + num_fingers_get_t num_fingers; +}; + +__syscall bool single_tap_get(const struct device *dev); +__syscall bool two_finger_tap_get(const struct device *dev); +__syscall int16_t x_pos_get_abs(const struct device *dev); +__syscall int16_t y_pos_get_abs(const struct device *dev); +__syscall int16_t x_pos_get_rel(const struct device *dev); +__syscall int16_t y_pos_get_rel(const struct device *dev); +__syscall int num_fingers_get(const struct device *dev); + +static inline bool z_impl_single_tap_get(const struct device *dev) +{ + const struct touch_driver_api *api = (const struct touch_driver_api *)dev->api; + + return api->single_tap(dev); +} + +static inline bool z_impl_two_finger_tap_get(const struct device *dev) +{ + const struct touch_driver_api *api = (const struct touch_driver_api *)dev->api; + + return api->two_finger_tap(dev); +} + +static inline int z_impl_num_fingers_get(const struct device *dev) +{ + const struct touch_driver_api *api = (const struct touch_driver_api *)dev->api; + + return api->num_fingers(dev); +} + +static inline int16_t z_impl_x_pos_get_abs(const struct device *dev) +{ + const struct touch_driver_api *api = (const struct touch_driver_api *)dev->api; + + return api->x_pos_abs(dev); +} + +static inline int16_t z_impl_y_pos_get_abs(const struct device *dev) +{ + const struct touch_driver_api *api = (const struct touch_driver_api *)dev->api; + + return api->y_pos_abs(dev); +} + +static inline int16_t z_impl_x_pos_get_rel(const struct device *dev) +{ + const struct touch_driver_api *api = (const struct touch_driver_api *)dev->api; + + return api->x_pos_rel(dev); +} + +static inline int16_t z_impl_y_pos_get_rel(const struct device *dev) +{ + const struct touch_driver_api *api = (const struct touch_driver_api *)dev->api; + + return api->y_pos_rel(dev); +} + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#include + +#endif /* ZEPHYR_INCLUDE_DRIVERS_TOUCH_H_ */ diff --git a/samples/index.rst b/samples/index.rst index 284c6908959b7..98319f0194265 100644 --- a/samples/index.rst +++ b/samples/index.rst @@ -16,6 +16,7 @@ Samples and Demos net/net.rst bluetooth/bluetooth.rst sensor/* + touch/* arch/* boards/* drivers/drivers.rst diff --git a/samples/touch/iqs5xx/CMakeLists.txt b/samples/touch/iqs5xx/CMakeLists.txt new file mode 100644 index 0000000000000..351cee429dac7 --- /dev/null +++ b/samples/touch/iqs5xx/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(iqs5xx) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/touch/iqs5xx/README.rst b/samples/touch/iqs5xx/README.rst new file mode 100644 index 0000000000000..a1791b2ceb58a --- /dev/null +++ b/samples/touch/iqs5xx/README.rst @@ -0,0 +1,47 @@ +.. _iqs5xx-sample: + +iqs5xx +###### + +Overview +******** + +This sample reads data from the iqs5xx devices and prints the data reported by the +driver. + +The source code shows how to: + +#. Get the trackpad device from the :ref:`devicetree ` as a + :c:struct:`device` +#. Print data from the device. + +.. _iqs5xx-sample-requirements: + +Requirements +************ + +Your board must: + +#. Have an iqs5xx connected via the i2c bus. +#. Have the RDY pin of the iqs5xx connected to the mcu. +#. Have pullup resistors installed on the i2c bus. + +Sample output +============= + +You should get a similar output as below. + +.. code-block:: console + +[00:00:00.424,000] i2c_esp32: I2C transfer error: -14 +[00:00:00.424,000] iqs5xx: I2C Transfer Failed, retrying +[00:00:00.425,000] i2c_esp32: I2C transfer error: -116 +[00:00:00.425,000] iqs5xx: I2C Transfer Failed, retrying +[00:00:00.445,000] iqs5xx: I2C Error Corrected +[00:00:00.449,000] iqs5xx: IQS Driver Probed. Product Number: 0x28 +[00:00:06.862,000] iqs5xx_sample: x: 810, y: 1145 +[00:00:06.873,000] iqs5xx_sample: x: 810, y: 1145 +[00:00:06.883,000] iqs5xx_sample: x: 828, y: 1188 +[00:00:06.893,000] iqs5xx_sample: x: 855, y: 1277 +[00:00:06.903,000] iqs5xx_sample: x: 893, y: 1408 +[00:00:06.913,000] iqs5xx_sample: x: 893, y: 1408 diff --git a/samples/touch/iqs5xx/boards/esp32.overlay b/samples/touch/iqs5xx/boards/esp32.overlay new file mode 100644 index 0000000000000..807f666c4ab34 --- /dev/null +++ b/samples/touch/iqs5xx/boards/esp32.overlay @@ -0,0 +1,13 @@ +&i2c0 { + status = "okay"; + clock-frequency = ; + sda-gpios = <&gpio0 21 GPIO_OPEN_DRAIN>; + scl-gpios = <&gpio0 22 GPIO_OPEN_DRAIN>; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; + iqs5xx: iqs5xx@74 { + compatible = "azoteq,iqs5xx"; + rdy-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; //IO34 + reg = <0x74>; + }; +}; diff --git a/samples/touch/iqs5xx/prj.conf b/samples/touch/iqs5xx/prj.conf new file mode 100644 index 0000000000000..83e526e444fe0 --- /dev/null +++ b/samples/touch/iqs5xx/prj.conf @@ -0,0 +1,9 @@ +CONFIG_LOG=y + +# Hardware Drivers +CONFIG_GPIO=y + +# Include IQS driver +CONFIG_I2C=y +CONFIG_TOUCH=y +CONFIG_IQS5XX=y diff --git a/samples/touch/iqs5xx/sample.yaml b/samples/touch/iqs5xx/sample.yaml new file mode 100644 index 0000000000000..808509514c407 --- /dev/null +++ b/samples/touch/iqs5xx/sample.yaml @@ -0,0 +1,12 @@ +sample: + name: Touch iqs5xx Sample. +tests: + sample.touch.iqs5xx: + tags: iqs5xx + platform_allow: esp32 + depends_on: i2c + harness: console + harness_config: + type: one_line + regex: + - "IQS Driver Probed. Product Number: (.*)" diff --git a/samples/touch/iqs5xx/src/main.c b/samples/touch/iqs5xx/src/main.c new file mode 100644 index 0000000000000..a5eedba7c3e69 --- /dev/null +++ b/samples/touch/iqs5xx/src/main.c @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2022 Ryan Walker + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define SLEEP_TIME_MS 10 + +LOG_MODULE_REGISTER(iqs5xx_sample, LOG_LEVEL_DBG); + +void main(void) +{ + const struct device *trackpad = DEVICE_DT_GET(DT_NODELABEL(iqs5xx)); + + if (!device_is_ready(trackpad)) { + LOG_ERR("Trackpad Not Ready!"); + return; + } + + while (true) { + if (num_fingers_get(trackpad)) { + int16_t x_pos = x_pos_get_abs(trackpad); + int16_t y_pos = y_pos_get_abs(trackpad); + + LOG_INF("x: %d, y: %d", x_pos, y_pos); + } + k_msleep(SLEEP_TIME_MS); + } +} diff --git a/samples/touch/touch.rst b/samples/touch/touch.rst new file mode 100644 index 0000000000000..4c8281e0e0dcd --- /dev/null +++ b/samples/touch/touch.rst @@ -0,0 +1,10 @@ +.. _touch-samples: + +Touch Samples +############## + +.. toctree:: + :maxdepth: 1 + :glob: + + **/*