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 | /* ST Microelectronics LIS2MDL 3-axis magnetometer sensor * * Copyright (c) 2018-2019 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 * * Datasheet: * https://www.st.com/resource/en/datasheet/lis2mdl.pdf */ #define DT_DRV_COMPAT st_lis2mdl #include <zephyr/kernel.h> #include <zephyr/drivers/sensor.h> #include <zephyr/drivers/gpio.h> #include <zephyr/logging/log.h> #include "lis2mdl.h" LOG_MODULE_DECLARE(LIS2MDL, CONFIG_SENSOR_LOG_LEVEL); static int lis2mdl_enable_int(const struct device *dev, int enable) { const struct lis2mdl_config *cfg = dev->config; stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; LOG_DBG("Set int with %d", enable); /* set interrupt on mag */ return lis2mdl_drdy_on_pin_set(ctx, enable); } /* link external trigger to event data ready */ int lis2mdl_trigger_set(const struct device *dev, const struct sensor_trigger *trig, sensor_trigger_handler_t handler) { const struct lis2mdl_config *cfg = dev->config; stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; struct lis2mdl_data *lis2mdl = dev->data; int16_t raw[3]; if (!cfg->trig_enabled) { LOG_ERR("trigger_set op not supported"); return -ENOTSUP; } if (trig->chan == SENSOR_CHAN_MAGN_XYZ) { lis2mdl->handler_drdy = handler; if (handler) { /* fetch raw data sample: re-trigger lost interrupt */ lis2mdl_magnetic_raw_get(ctx, raw); return lis2mdl_enable_int(dev, 1); } else { return lis2mdl_enable_int(dev, 0); } } return -ENOTSUP; } /* handle the drdy event: read data and call handler if registered any */ static void lis2mdl_handle_interrupt(const struct device *dev) { struct lis2mdl_data *lis2mdl = dev->data; const struct lis2mdl_config *const cfg = dev->config; struct sensor_trigger drdy_trigger = { .type = SENSOR_TRIG_DATA_READY, }; if (lis2mdl->handler_drdy != NULL) { lis2mdl->handler_drdy(dev, &drdy_trigger); } if (cfg->single_mode) { k_sem_give(&lis2mdl->fetch_sem); } gpio_pin_interrupt_configure_dt(&cfg->gpio_drdy, GPIO_INT_EDGE_TO_ACTIVE); } static void lis2mdl_gpio_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins) { struct lis2mdl_data *lis2mdl = CONTAINER_OF(cb, struct lis2mdl_data, gpio_cb); const struct lis2mdl_config *const cfg = lis2mdl->dev->config; ARG_UNUSED(pins); gpio_pin_interrupt_configure_dt(&cfg->gpio_drdy, GPIO_INT_DISABLE); #if defined(CONFIG_LIS2MDL_TRIGGER_OWN_THREAD) k_sem_give(&lis2mdl->gpio_sem); #elif defined(CONFIG_LIS2MDL_TRIGGER_GLOBAL_THREAD) k_work_submit(&lis2mdl->work); #endif } #ifdef CONFIG_LIS2MDL_TRIGGER_OWN_THREAD static void lis2mdl_thread(struct lis2mdl_data *lis2mdl) { while (1) { k_sem_take(&lis2mdl->gpio_sem, K_FOREVER); lis2mdl_handle_interrupt(lis2mdl->dev); } } #endif #ifdef CONFIG_LIS2MDL_TRIGGER_GLOBAL_THREAD static void lis2mdl_work_cb(struct k_work *work) { struct lis2mdl_data *lis2mdl = CONTAINER_OF(work, struct lis2mdl_data, work); lis2mdl_handle_interrupt(lis2mdl->dev); } #endif int lis2mdl_init_interrupt(const struct device *dev) { struct lis2mdl_data *lis2mdl = dev->data; const struct lis2mdl_config *const cfg = dev->config; int ret; /* setup data ready gpio interrupt */ if (!device_is_ready(cfg->gpio_drdy.port)) { LOG_ERR("Cannot get pointer to drdy_gpio device"); return -EINVAL; } #if defined(CONFIG_LIS2MDL_TRIGGER_OWN_THREAD) k_sem_init(&lis2mdl->gpio_sem, 0, K_SEM_MAX_LIMIT); k_thread_create(&lis2mdl->thread, lis2mdl->thread_stack, CONFIG_LIS2MDL_THREAD_STACK_SIZE, (k_thread_entry_t)lis2mdl_thread, lis2mdl, NULL, NULL, K_PRIO_COOP(CONFIG_LIS2MDL_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_LIS2MDL_TRIGGER_GLOBAL_THREAD) lis2mdl->work.handler = lis2mdl_work_cb; #endif ret = gpio_pin_configure_dt(&cfg->gpio_drdy, GPIO_INPUT); if (ret < 0) { LOG_ERR("Could not configure gpio"); return ret; } gpio_init_callback(&lis2mdl->gpio_cb, lis2mdl_gpio_callback, BIT(cfg->gpio_drdy.pin)); if (gpio_add_callback(cfg->gpio_drdy.port, &lis2mdl->gpio_cb) < 0) { LOG_ERR("Could not set gpio callback"); return -EIO; } return gpio_pin_interrupt_configure_dt(&cfg->gpio_drdy, GPIO_INT_EDGE_TO_ACTIVE); } |