Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | /* ST Microelectronics IIS2DH 3-axis accelerometer driver * * Copyright (c) 2020 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 * * Datasheet: * https://www.st.com/resource/en/datasheet/iis2dh.pdf */ #include <zephyr/kernel.h> #include <zephyr/drivers/sensor.h> #include <zephyr/drivers/gpio.h> #include <zephyr/logging/log.h> #include "iis2dh.h" LOG_MODULE_DECLARE(IIS2DH, CONFIG_SENSOR_LOG_LEVEL); /** * iis2dh_enable_int - enable selected int pin to generate interrupt */ static int iis2dh_enable_drdy(const struct device *dev, enum sensor_trigger_type type, int enable) { struct iis2dh_data *iis2dh = dev->data; iis2dh_ctrl_reg3_t reg3; /* set interrupt for pin INT1 */ iis2dh_pin_int1_config_get(iis2dh->ctx, ®3); reg3.i1_drdy1 = enable; return iis2dh_pin_int1_config_set(iis2dh->ctx, ®3); } /** * iis2dh_trigger_set - link external trigger to event data ready */ int iis2dh_trigger_set(const struct device *dev, const struct sensor_trigger *trig, sensor_trigger_handler_t handler) { struct iis2dh_data *iis2dh = dev->data; int16_t raw[3]; int state = (handler != NULL) ? PROPERTY_ENABLE : PROPERTY_DISABLE; switch (trig->type) { case SENSOR_TRIG_DATA_READY: iis2dh->drdy_handler = handler; if (state) { /* dummy read: re-trigger interrupt */ iis2dh_acceleration_raw_get(iis2dh->ctx, raw); } return iis2dh_enable_drdy(dev, SENSOR_TRIG_DATA_READY, state); default: LOG_ERR("Unsupported sensor trigger"); return -ENOTSUP; } } static int iis2dh_handle_drdy_int(const struct device *dev) { struct iis2dh_data *data = dev->data; struct sensor_trigger drdy_trig = { .type = SENSOR_TRIG_DATA_READY, .chan = SENSOR_CHAN_ALL, }; if (data->drdy_handler) { data->drdy_handler(dev, &drdy_trig); } return 0; } /** * iis2dh_handle_interrupt - handle the drdy event * read data and call handler if registered any */ static void iis2dh_handle_interrupt(const struct device *dev) { struct iis2dh_data *iis2dh = dev->data; const struct iis2dh_device_config *cfg = dev->config; iis2dh_handle_drdy_int(dev); gpio_pin_interrupt_configure(iis2dh->gpio, cfg->int_gpio_pin, GPIO_INT_EDGE_TO_ACTIVE); } static void iis2dh_gpio_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins) { struct iis2dh_data *iis2dh = CONTAINER_OF(cb, struct iis2dh_data, gpio_cb); if ((pins & BIT(iis2dh->gpio_pin)) == 0U) { return; } gpio_pin_interrupt_configure(dev, iis2dh->gpio_pin, GPIO_INT_DISABLE); #if defined(CONFIG_IIS2DH_TRIGGER_OWN_THREAD) k_sem_give(&iis2dh->gpio_sem); #elif defined(CONFIG_IIS2DH_TRIGGER_GLOBAL_THREAD) k_work_submit(&iis2dh->work); #endif /* CONFIG_IIS2DH_TRIGGER_OWN_THREAD */ } #ifdef CONFIG_IIS2DH_TRIGGER_OWN_THREAD static void iis2dh_thread(struct iis2dh_data *iis2dh) { while (1) { k_sem_take(&iis2dh->gpio_sem, K_FOREVER); iis2dh_handle_interrupt(iis2dh->dev); } } #endif /* CONFIG_IIS2DH_TRIGGER_OWN_THREAD */ #ifdef CONFIG_IIS2DH_TRIGGER_GLOBAL_THREAD static void iis2dh_work_cb(struct k_work *work) { struct iis2dh_data *iis2dh = CONTAINER_OF(work, struct iis2dh_data, work); iis2dh_handle_interrupt(iis2dh->dev); } #endif /* CONFIG_IIS2DH_TRIGGER_GLOBAL_THREAD */ int iis2dh_init_interrupt(const struct device *dev) { struct iis2dh_data *iis2dh = dev->data; const struct iis2dh_device_config *cfg = dev->config; int ret; /* setup data ready gpio interrupt */ iis2dh->gpio = device_get_binding(cfg->int_gpio_port); if (iis2dh->gpio == NULL) { LOG_DBG("Cannot get pointer to %s device", cfg->int_gpio_port); return -EINVAL; } iis2dh->dev = dev; #if defined(CONFIG_IIS2DH_TRIGGER_OWN_THREAD) k_sem_init(&iis2dh->gpio_sem, 0, K_SEM_MAX_LIMIT); k_thread_create(&iis2dh->thread, iis2dh->thread_stack, CONFIG_IIS2DH_THREAD_STACK_SIZE, (k_thread_entry_t)iis2dh_thread, iis2dh, 0, NULL, K_PRIO_COOP(CONFIG_IIS2DH_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_IIS2DH_TRIGGER_GLOBAL_THREAD) iis2dh->work.handler = iis2dh_work_cb; #endif /* CONFIG_IIS2DH_TRIGGER_OWN_THREAD */ iis2dh->gpio_pin = cfg->int_gpio_pin; ret = gpio_pin_configure(iis2dh->gpio, cfg->int_gpio_pin, GPIO_INPUT | cfg->int_gpio_flags); if (ret < 0) { LOG_DBG("Could not configure gpio"); return ret; } gpio_init_callback(&iis2dh->gpio_cb, iis2dh_gpio_callback, BIT(cfg->int_gpio_pin)); if (gpio_add_callback(iis2dh->gpio, &iis2dh->gpio_cb) < 0) { LOG_DBG("Could not set gpio callback"); return -EIO; } /* enable drdy on int1 in pulse mode */ if (iis2dh_int1_pin_notification_mode_set(iis2dh->ctx, IIS2DH_INT1_PULSED)) { return -EIO; } return gpio_pin_interrupt_configure(iis2dh->gpio, cfg->int_gpio_pin, GPIO_INT_EDGE_TO_ACTIVE); } |