1 /* ST Microelectronics IIS2MDC 3-axis magnetometer sensor
2 *
3 * Copyright (c) 2020 STMicroelectronics
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Datasheet:
8 * https://www.st.com/resource/en/datasheet/iis2mdc.pdf
9 */
10
11 #define DT_DRV_COMPAT st_iis2mdc
12
13 #include <zephyr/kernel.h>
14 #include <zephyr/drivers/sensor.h>
15 #include <zephyr/drivers/gpio.h>
16 #include <zephyr/logging/log.h>
17 #include "iis2mdc.h"
18
19 LOG_MODULE_DECLARE(IIS2MDC, CONFIG_SENSOR_LOG_LEVEL);
20
iis2mdc_enable_int(const struct device * dev,int enable)21 static int iis2mdc_enable_int(const struct device *dev, int enable)
22 {
23 struct iis2mdc_data *iis2mdc = dev->data;
24
25 /* set interrupt on mag */
26 return iis2mdc_drdy_on_pin_set(iis2mdc->ctx, enable);
27 }
28
29 /* link external trigger to event data ready */
iis2mdc_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)30 int iis2mdc_trigger_set(const struct device *dev,
31 const struct sensor_trigger *trig,
32 sensor_trigger_handler_t handler)
33 {
34 struct iis2mdc_data *iis2mdc = dev->data;
35 int16_t raw[3];
36
37 if (trig->chan == SENSOR_CHAN_MAGN_XYZ) {
38 iis2mdc->handler_drdy = handler;
39 iis2mdc->trig_drdy = trig;
40 if (handler) {
41 /* fetch raw data sample: re-trigger lost interrupt */
42 iis2mdc_magnetic_raw_get(iis2mdc->ctx, raw);
43
44 return iis2mdc_enable_int(dev, 1);
45 } else {
46 return iis2mdc_enable_int(dev, 0);
47 }
48 }
49
50 return -ENOTSUP;
51 }
52
53 /* handle the drdy event: read data and call handler if registered any */
iis2mdc_handle_interrupt(const struct device * dev)54 static void iis2mdc_handle_interrupt(const struct device *dev)
55 {
56 struct iis2mdc_data *iis2mdc = dev->data;
57 const struct iis2mdc_dev_config *const config = dev->config;
58
59 if (iis2mdc->handler_drdy != NULL) {
60 iis2mdc->handler_drdy(dev, iis2mdc->trig_drdy);
61 }
62
63 gpio_pin_interrupt_configure_dt(&config->gpio_drdy,
64 GPIO_INT_EDGE_TO_ACTIVE);
65 }
66
iis2mdc_gpio_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)67 static void iis2mdc_gpio_callback(const struct device *dev,
68 struct gpio_callback *cb, uint32_t pins)
69 {
70 struct iis2mdc_data *iis2mdc =
71 CONTAINER_OF(cb, struct iis2mdc_data, gpio_cb);
72 const struct iis2mdc_dev_config *const config = iis2mdc->dev->config;
73
74 ARG_UNUSED(pins);
75
76 gpio_pin_interrupt_configure_dt(&config->gpio_drdy, GPIO_INT_DISABLE);
77
78 #if defined(CONFIG_IIS2MDC_TRIGGER_OWN_THREAD)
79 k_sem_give(&iis2mdc->gpio_sem);
80 #elif defined(CONFIG_IIS2MDC_TRIGGER_GLOBAL_THREAD)
81 k_work_submit(&iis2mdc->work);
82 #endif
83 }
84
85 #ifdef CONFIG_IIS2MDC_TRIGGER_OWN_THREAD
iis2mdc_thread(struct iis2mdc_data * iis2mdc)86 static void iis2mdc_thread(struct iis2mdc_data *iis2mdc)
87 {
88 while (1) {
89 k_sem_take(&iis2mdc->gpio_sem, K_FOREVER);
90 iis2mdc_handle_interrupt(iis2mdc->dev);
91 }
92 }
93 #endif
94
95 #ifdef CONFIG_IIS2MDC_TRIGGER_GLOBAL_THREAD
iis2mdc_work_cb(struct k_work * work)96 static void iis2mdc_work_cb(struct k_work *work)
97 {
98 struct iis2mdc_data *iis2mdc =
99 CONTAINER_OF(work, struct iis2mdc_data, work);
100
101 iis2mdc_handle_interrupt(iis2mdc->dev);
102 }
103 #endif
104
iis2mdc_init_interrupt(const struct device * dev)105 int iis2mdc_init_interrupt(const struct device *dev)
106 {
107 struct iis2mdc_data *iis2mdc = dev->data;
108 const struct iis2mdc_dev_config *const config = dev->config;
109 int ret;
110
111 /* setup data ready gpio interrupt */
112 if (!device_is_ready(config->gpio_drdy.port)) {
113 LOG_ERR("Cannot get pointer to drdy_gpio device");
114 return -ENODEV;
115 }
116
117 #if defined(CONFIG_IIS2MDC_TRIGGER_OWN_THREAD)
118 k_sem_init(&iis2mdc->gpio_sem, 0, K_SEM_MAX_LIMIT);
119 k_thread_create(&iis2mdc->thread, iis2mdc->thread_stack,
120 CONFIG_IIS2MDC_THREAD_STACK_SIZE,
121 (k_thread_entry_t)iis2mdc_thread, iis2mdc,
122 NULL, NULL, K_PRIO_COOP(CONFIG_IIS2MDC_THREAD_PRIORITY),
123 0, K_NO_WAIT);
124 #elif defined(CONFIG_IIS2MDC_TRIGGER_GLOBAL_THREAD)
125 iis2mdc->work.handler = iis2mdc_work_cb;
126 #endif
127
128 ret = gpio_pin_configure_dt(&config->gpio_drdy, GPIO_INPUT);
129 if (ret < 0) {
130 LOG_ERR("Could not configure gpio");
131 return ret;
132 }
133
134 gpio_init_callback(&iis2mdc->gpio_cb,
135 iis2mdc_gpio_callback,
136 BIT(config->gpio_drdy.pin));
137
138 if (gpio_add_callback(config->gpio_drdy.port, &iis2mdc->gpio_cb) < 0) {
139 LOG_DBG("Could not set gpio callback");
140 return -EIO;
141 }
142
143 return gpio_pin_interrupt_configure_dt(&config->gpio_drdy,
144 GPIO_INT_EDGE_TO_ACTIVE);
145 }
146