1 /* Bosch BMM150 pressure sensor
2 *
3 * Copyright (c) 2020 Facebook, Inc. and its affiliates
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Datasheet:
8 * https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmm150-ds001.pdf
9 */
10
11 #include <zephyr/kernel.h>
12 #include <zephyr/pm/device.h>
13 #include <zephyr/logging/log.h>
14
15 #include "bmm150.h"
16
17 LOG_MODULE_DECLARE(BMM150, CONFIG_SENSOR_LOG_LEVEL);
18
bmm150_handle_interrupts(const void * arg)19 static void bmm150_handle_interrupts(const void *arg)
20 {
21 const struct device *dev = (const struct device *)arg;
22 struct bmm150_data *data = dev->data;
23
24 if (data->drdy_handler) {
25 data->drdy_handler(dev, data->drdy_trigger);
26 }
27 }
28
29 #ifdef CONFIG_BMM150_TRIGGER_OWN_THREAD
30 static K_THREAD_STACK_DEFINE(bmm150_thread_stack,
31 CONFIG_BMM150_THREAD_STACK_SIZE);
32 static struct k_thread bmm150_thread;
33
bmm150_thread_main(void * arg1,void * unused1,void * unused2)34 static void bmm150_thread_main(void *arg1, void *unused1, void *unused2)
35 {
36 ARG_UNUSED(unused1);
37 ARG_UNUSED(unused2);
38 const struct device *dev = (const struct device *)arg1;
39 struct bmm150_data *data = dev->data;
40
41 while (1) {
42 k_sem_take(&data->sem, K_FOREVER);
43 bmm150_handle_interrupts(dev);
44 }
45 }
46 #endif
47
48 #ifdef CONFIG_BMM150_TRIGGER_GLOBAL_THREAD
bmm150_work_handler(struct k_work * work)49 static void bmm150_work_handler(struct k_work *work)
50 {
51 struct bmm150_data *data = CONTAINER_OF(work,
52 struct bmm150_data,
53 work);
54
55 bmm150_handle_interrupts(data->dev);
56 }
57 #endif
58
bmm150_gpio_callback(const struct device * port,struct gpio_callback * cb,uint32_t pin)59 static void bmm150_gpio_callback(const struct device *port,
60 struct gpio_callback *cb,
61 uint32_t pin)
62 {
63 struct bmm150_data *data = CONTAINER_OF(cb,
64 struct bmm150_data,
65 gpio_cb);
66
67 ARG_UNUSED(port);
68 ARG_UNUSED(pin);
69
70 #if defined(CONFIG_BMM150_TRIGGER_OWN_THREAD)
71 k_sem_give(&data->sem);
72 #elif defined(CONFIG_BMM150_TRIGGER_GLOBAL_THREAD)
73 k_work_submit(&data->work);
74 #elif defined(CONFIG_BMM150_TRIGGER_DIRECT)
75 bmm150_handle_interrupts(data->dev);
76 #endif
77 }
78
bmm150_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)79 int bmm150_trigger_set(
80 const struct device *dev,
81 const struct sensor_trigger *trig,
82 sensor_trigger_handler_t handler)
83 {
84 uint16_t values[BMM150_AXIS_XYZR_MAX];
85 struct bmm150_data *data = dev->data;
86 const struct bmm150_config *cfg = dev->config;
87
88 #ifdef CONFIG_PM_DEVICE
89 enum pm_device_state state;
90
91 (void)pm_device_state_get(dev, &state);
92 if (state != PM_DEVICE_STATE_ACTIVE) {
93 return -EBUSY;
94 }
95 #endif
96
97 if (trig->type != SENSOR_TRIG_DATA_READY) {
98 return -ENOTSUP;
99 }
100
101 data->drdy_trigger = trig;
102 data->drdy_handler = handler;
103
104 if (bmm150_reg_update_byte(dev,
105 BMM150_REG_INT_DRDY,
106 BMM150_MASK_DRDY_EN,
107 (handler != NULL) << BMM150_SHIFT_DRDY_EN) < 0) {
108 LOG_ERR("Failed to enable DRDY interrupt");
109 return -EIO;
110 }
111
112 /* Clean data registers */
113 if (cfg->bus_io->read(&cfg->bus, BMM150_REG_X_L, (uint8_t *)values, sizeof(values)) < 0) {
114 LOG_ERR("failed to read sample");
115 return -EIO;
116 }
117
118 return 0;
119 }
120
bmm150_trigger_mode_init(const struct device * dev)121 int bmm150_trigger_mode_init(const struct device *dev)
122 {
123 struct bmm150_data *data = dev->data;
124 const struct bmm150_config *cfg = dev->config;
125
126 if (!device_is_ready(cfg->drdy_int.port)) {
127 LOG_ERR("INT device is not ready");
128 return -ENODEV;
129 }
130
131 #if defined(CONFIG_BMM150_TRIGGER_OWN_THREAD)
132 k_sem_init(&data->sem, 0, 1);
133 k_thread_create(
134 &bmm150_thread,
135 bmm150_thread_stack,
136 CONFIG_BMM150_THREAD_STACK_SIZE,
137 bmm150_thread_main,
138 (void *)dev,
139 NULL,
140 NULL,
141 K_PRIO_COOP(CONFIG_BMM150_THREAD_PRIORITY),
142 0,
143 K_NO_WAIT);
144 #elif defined(CONFIG_BMM150_TRIGGER_GLOBAL_THREAD)
145 k_work_init(&data->work, bmm150_work_handler);
146 #endif
147
148 #if defined(CONFIG_BMM150_TRIGGER_GLOBAL_THREAD) || \
149 defined(CONFIG_BMM150_TRIGGER_DIRECT)
150 data->dev = dev;
151 #endif
152
153 gpio_init_callback(&data->gpio_cb,
154 bmm150_gpio_callback,
155 BIT(cfg->drdy_int.pin));
156
157 return gpio_add_callback(cfg->drdy_int.port, &data->gpio_cb);
158 }
159
bmm150_trigger_mode_power_ctrl(const struct device * dev,bool enable)160 int bmm150_trigger_mode_power_ctrl(const struct device *dev, bool enable)
161 {
162 const struct bmm150_config *cfg = dev->config;
163 int ret;
164
165 if (enable) {
166 ret = gpio_pin_configure_dt(&cfg->drdy_int, GPIO_INPUT);
167 if (ret < 0) {
168 return ret;
169 }
170 ret = gpio_pin_interrupt_configure_dt(&cfg->drdy_int,
171 GPIO_INT_EDGE_TO_ACTIVE);
172 } else {
173 ret = gpio_pin_interrupt_configure_dt(&cfg->drdy_int, GPIO_INT_DISABLE);
174 if (ret < 0) {
175 return ret;
176 }
177 ret = gpio_pin_configure_dt(&cfg->drdy_int, GPIO_DISCONNECTED);
178 }
179 return ret;
180 }
181