diff --git a/drivers/sensor/apds9960/Kconfig b/drivers/sensor/apds9960/Kconfig index 7f6b4bb00a5bd..986372139d5ab 100644 --- a/drivers/sensor/apds9960/Kconfig +++ b/drivers/sensor/apds9960/Kconfig @@ -135,4 +135,20 @@ config APDS9960_PPULSE_COUNT range 1 64 default 8 +config APDS9960_ENABLE_GESTURE + bool "Gesture Sense" + default n + help + Enable Gesture Sense. + +config APDS9960_GESTURE_PROXIMITY + int "Gesture Proximity Enter Threshold" + range 0 255 + default 40 + +config APDS9960_GESTURE_DIFFERENCE + int "Minimum IR diode difference for gesture" + range 0 255 + default 5 + endif # APDS9960 diff --git a/drivers/sensor/apds9960/apds9960.c b/drivers/sensor/apds9960/apds9960.c index 32bb14caa22d2..bc3d9431b392b 100644 --- a/drivers/sensor/apds9960/apds9960.c +++ b/drivers/sensor/apds9960/apds9960.c @@ -22,7 +22,7 @@ #include #include -#include "apds9960.h" +#include LOG_MODULE_REGISTER(APDS9960, CONFIG_SENSOR_LOG_LEVEL); @@ -48,6 +48,112 @@ static void apds9960_gpio_callback(const struct device *dev, } #endif +#if CONFIG_APDS9960_ENABLE_GESTURE +static int apds9960_gesture_fetch(const struct device *dev) +{ + const struct apds9960_config *config = dev->config; + struct apds9960_data *data = dev->data; + + uint8_t gesture_fifo_cnt; + uint8_t gstatus; + uint8_t gesture_fifo[4]; + int tmp_up; + int tmp_left; + int net_up = 0; + int net_left = 0; + + bool up_trig = false; + bool down_trig = false; + bool left_trig = false; + bool right_trig = false; + + data->gesture = APDS9960_GESTURE_NONE; + + if (i2c_reg_read_byte_dt(&config->i2c, + APDS9960_GSTATUS_REG, &gstatus)) { + return -EIO; + } + + while (gstatus & APDS9960_GSTATUS_GVALID) { + if (i2c_reg_read_byte_dt(&config->i2c, + APDS9960_GFLVL_REG, &gesture_fifo_cnt)) { + return -EIO; + } + + for (int i = 0; i < gesture_fifo_cnt; ++i) { + /* Read up fifo and adjacent registers */ + if (i2c_burst_read_dt(&config->i2c, + APDS9960_GFIFO_U_REG, + (uint8_t *) gesture_fifo, + 4)) { + return -EIO; + } + + tmp_up = (int) gesture_fifo[0] - (int) gesture_fifo[1]; + tmp_left = (int) gesture_fifo[2] - (int) gesture_fifo[3]; + + if (abs(tmp_up) > CONFIG_APDS9960_GESTURE_DIFFERENCE) { + net_up = tmp_up; + } + if (abs(tmp_left) > CONFIG_APDS9960_GESTURE_DIFFERENCE) { + net_left = tmp_left; + } + + if (net_up > 0) { + if (down_trig) { + data->gesture = APDS9960_GESTURE_DOWN; + up_trig = false; + down_trig = false; + left_trig = false; + right_trig = false; + } else { + up_trig = true; + } + } else if (net_up < 0) { + if (up_trig) { + data->gesture = APDS9960_GESTURE_UP; + up_trig = false; + down_trig = false; + left_trig = false; + right_trig = false; + } else { + down_trig = true; + } + } + if (net_left > 0) { + if (right_trig) { + data->gesture = APDS9960_GESTURE_RIGHT; + up_trig = false; + down_trig = false; + left_trig = false; + right_trig = false; + } else { + left_trig = true; + } + } else if (net_left < 0) { + if (left_trig) { + data->gesture = APDS9960_GESTURE_LEFT; + up_trig = false; + down_trig = false; + left_trig = false; + right_trig = false; + } else { + right_trig = true; + } + } + } + + if (i2c_reg_read_byte_dt(&config->i2c, + APDS9960_GSTATUS_REG, &gstatus)) { + return -EIO; + } + } + LOG_DBG("Net up: 0x%x, Net left: 0x%x", net_up, net_left); + + return 0; +} +#endif + static int apds9960_sample_fetch(const struct device *dev, enum sensor_channel chan) { @@ -63,6 +169,12 @@ static int apds9960_sample_fetch(const struct device *dev, return -ENOTSUP; } +#ifdef CONFIG_APDS9960_ENABLE_GESTURE + if (apds9960_gesture_fetch(dev)) { + return -EIO; + } +#endif + #ifndef CONFIG_APDS9960_TRIGGER #ifdef CONFIG_APDS9960_FETCH_MODE_INTERRUPT apds9960_setup_int(config, true); @@ -90,16 +202,9 @@ static int apds9960_sample_fetch(const struct device *dev, start_time = k_uptime_get(); #ifdef CONFIG_APDS9960_ENABLE_ALS while (!(tmp & APDS9960_STATUS_AINT)) { - k_sleep(K_MSEC(APDS9960_DEFAULT_WAIT_TIME)); - if (i2c_reg_read_byte_dt(&config->i2c, APDS9960_STATUS_REG, &tmp)) { - return -EIO; - } - if ((k_uptime_get() - start_time) > APDS9960_MAX_WAIT_TIME) { - return -ETIMEDOUT; - } - } #else while (!(tmp & APDS9960_STATUS_PINT)) { +#endif k_sleep(K_MSEC(APDS9960_DEFAULT_WAIT_TIME)); if (i2c_reg_read_byte_dt(&config->i2c, APDS9960_STATUS_REG, &tmp)) { return -EIO; @@ -108,7 +213,6 @@ static int apds9960_sample_fetch(const struct device *dev, return -ETIMEDOUT; } } -#endif #endif LOG_DBG("status: 0x%x", tmp); @@ -172,6 +276,12 @@ static int apds9960_channel_get(const struct device *dev, val->val1 = sys_le16_to_cpu(data->sample_crgb[3]); val->val2 = 0; break; +#endif +#ifdef CONFIG_APDS9960_ENABLE_GESTURE + case SENSOR_CHAN_APDS9960_GESTURE: + val->val1 = data->gesture; + val->val2 = 0; + break; #endif case SENSOR_CHAN_PROX: val->val1 = data->pdata; @@ -304,6 +414,45 @@ static int apds9960_ambient_setup(const struct device *dev) } #endif +#ifdef CONFIG_APDS9960_ENABLE_GESTURE +static int apds9960_gesture_setup(const struct device *dev) +{ + const struct apds9960_config *config = dev->config; + + if (i2c_reg_write_byte_dt(&config->i2c, + APDS9960_GPENTH_REG, CONFIG_APDS9960_GESTURE_PROXIMITY)) { + LOG_ERR("Gesture proximity enter not set."); + return -EIO; + } + if (i2c_reg_write_byte_dt(&config->i2c, + APDS9960_GEXTH_REG, CONFIG_APDS9960_GESTURE_PROXIMITY)) { + LOG_ERR("Gesture interrupt not set."); + return -EIO; + } + if (i2c_reg_write_byte_dt(&config->i2c, + APDS9960_GCONFIG1_REG, 0)) { + LOG_ERR("Gesture interrupt not set."); + return -EIO; + } + if (i2c_reg_write_byte_dt(&config->i2c, + APDS9960_GCONFIG2_REG, APDS9960_GGAIN_4X)) { + LOG_ERR("Gesture interrupt not set."); + return -EIO; + } + if (i2c_reg_write_byte_dt(&config->i2c, + APDS9960_GCONFIG4_REG, 0)) { + LOG_ERR("Gesture interrupt not set."); + return -EIO; + } + if (i2c_reg_update_byte_dt(&config->i2c, APDS9960_ENABLE_REG, APDS9960_ENABLE_GEN, + APDS9960_ENABLE_GEN)) { + LOG_ERR("Gesture on bit not set."); + return -EIO; + } + return 0; +} +#endif + static int apds9960_sensor_setup(const struct device *dev) { const struct apds9960_config *config = dev->config; @@ -385,6 +534,13 @@ static int apds9960_sensor_setup(const struct device *dev) } #endif +#ifdef CONFIG_APDS9960_ENABLE_GESTURE + if (apds9960_gesture_setup(dev)) { + LOG_ERR("Failed to setup gesture functionality"); + return -EIO; + } +#endif + #ifdef CONFIG_APDS9960_FETCH_MODE_POLL if (i2c_reg_update_byte_dt(&config->i2c, APDS9960_ENABLE_REG, APDS9960_ENABLE_PON, APDS9960_ENABLE_PON)) { diff --git a/drivers/sensor/apds9960/apds9960_trigger.c b/drivers/sensor/apds9960/apds9960_trigger.c index 245fdab68fba0..d8a7a3d2a2924 100644 --- a/drivers/sensor/apds9960/apds9960_trigger.c +++ b/drivers/sensor/apds9960/apds9960_trigger.c @@ -10,7 +10,7 @@ #include #include #include -#include "apds9960.h" +#include extern struct apds9960_data apds9960_driver; diff --git a/drivers/sensor/apds9960/apds9960.h b/include/zephyr/drivers/sensor/apds9960.h similarity index 96% rename from drivers/sensor/apds9960/apds9960.h rename to include/zephyr/drivers/sensor/apds9960.h index d40d12ac3fd46..df6d3a1dec186 100644 --- a/drivers/sensor/apds9960/apds9960.h +++ b/include/zephyr/drivers/sensor/apds9960.h @@ -9,6 +9,7 @@ #define ZEPHYR_DRIVERS_SENSOR_APDS9960_APDS9960_H_ #include +#include #define APDS9960_ENABLE_REG 0x80 #define APDS9960_ENABLE_GEN BIT(6) @@ -227,12 +228,26 @@ struct apds9960_config { uint8_t pled_boost; }; +/* apds9960 specific channels */ +enum sensor_channel_apds9960 { + SENSOR_CHAN_APDS9960_GESTURE = SENSOR_CHAN_PRIV_START, +}; + +enum apds9960_gesture { + APDS9960_GESTURE_NONE, + APDS9960_GESTURE_UP, + APDS9960_GESTURE_DOWN, + APDS9960_GESTURE_LEFT, + APDS9960_GESTURE_RIGHT, +}; + struct apds9960_data { struct gpio_callback gpio_cb; struct k_work work; const struct device *dev; uint16_t sample_crgb[4]; uint8_t pdata; + enum apds9960_gesture gesture; #ifdef CONFIG_APDS9960_TRIGGER sensor_trigger_handler_t p_th_handler; diff --git a/samples/sensor/apds9960/prj.conf b/samples/sensor/apds9960/prj.conf index 9f4b4aa1c8c87..8147a7762c95e 100644 --- a/samples/sensor/apds9960/prj.conf +++ b/samples/sensor/apds9960/prj.conf @@ -9,3 +9,5 @@ CONFIG_I2C_LOG_LEVEL_INF=y CONFIG_APDS9960_TRIGGER_GLOBAL_THREAD=n CONFIG_PM_DEVICE=n + +CONFIG_APDS9960_ENABLE_GESTURE=n diff --git a/samples/sensor/apds9960/src/main.c b/samples/sensor/apds9960/src/main.c index ab96ae7990f18..220992631b6e7 100644 --- a/samples/sensor/apds9960/src/main.c +++ b/samples/sensor/apds9960/src/main.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -24,10 +25,18 @@ static void trigger_handler(const struct device *dev, } #endif +char states[5][6] = { + "NONE", + "UP", + "DOWN", + "LEFT", + "RIGHT", +}; + int main(void) { const struct device *dev; - struct sensor_value intensity, pdata; + struct sensor_value intensity, pdata, gesture; printk("APDS9960 sample application\n"); dev = DEVICE_DT_GET_ONE(avago_apds9960); @@ -72,9 +81,10 @@ int main(void) sensor_channel_get(dev, SENSOR_CHAN_LIGHT, &intensity); sensor_channel_get(dev, SENSOR_CHAN_PROX, &pdata); + sensor_channel_get(dev, SENSOR_CHAN_APDS9960_GESTURE, &gesture); - printk("ambient light intensity %d, proximity %d\n", - intensity.val1, pdata.val1); + printk("ambient light intensity %d, proximity %d, gesture %s\n", + intensity.val1, pdata.val1, states[gesture.val1]); #ifdef CONFIG_PM_DEVICE pm_device_action_run(dev, PM_DEVICE_ACTION_SUSPEND);