1 /* ST Microelectronics LIS2DUX12 3-axis accelerometer driver
2 *
3 * Copyright (c) 2024 STMicroelectronics
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Datasheet:
8 * https://www.st.com/resource/en/datasheet/lis2dux12.pdf
9 */
10
11 #include <zephyr/drivers/sensor.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/device.h>
14 #include <zephyr/init.h>
15 #include <string.h>
16 #include <zephyr/sys/__assert.h>
17 #include <zephyr/sys/util_macro.h>
18 #include <zephyr/logging/log.h>
19
20 #include "lis2dux12.h"
21
22 #if DT_HAS_COMPAT_STATUS_OKAY(st_lis2dux12)
23 #include "lis2dux12_api.h"
24 #endif
25
26 #if DT_HAS_COMPAT_STATUS_OKAY(st_lis2duxs12)
27 #include "lis2duxs12_api.h"
28 #endif
29
30 LOG_MODULE_REGISTER(LIS2DUX12, CONFIG_SENSOR_LOG_LEVEL);
31
32 #define FOREACH_ODR_ENUM(ODR_VAL) \
33 ODR_VAL(LIS2DUX12_DT_ODR_OFF, 0.0f) \
34 ODR_VAL(LIS2DUX12_DT_ODR_1Hz_ULP, 1.0f) \
35 ODR_VAL(LIS2DUX12_DT_ODR_3Hz_ULP, 3.0f) \
36 ODR_VAL(LIS2DUX12_DT_ODR_25Hz_ULP, 25.0f) \
37 ODR_VAL(LIS2DUX12_DT_ODR_6Hz, 6.0f) \
38 ODR_VAL(LIS2DUX12_DT_ODR_12Hz5, 12.50f) \
39 ODR_VAL(LIS2DUX12_DT_ODR_25Hz, 25.0f) \
40 ODR_VAL(LIS2DUX12_DT_ODR_50Hz, 50.0f) \
41 ODR_VAL(LIS2DUX12_DT_ODR_100Hz, 100.0f) \
42 ODR_VAL(LIS2DUX12_DT_ODR_200Hz, 200.0f) \
43 ODR_VAL(LIS2DUX12_DT_ODR_400Hz, 400.0f) \
44 ODR_VAL(LIS2DUX12_DT_ODR_800Hz, 800.0f)
45
46 #define GENERATE_VAL(ENUM, VAL) VAL,
47
48 static const float lis2dux12_odr_map[LIS2DUX12_DT_ODR_END] = {FOREACH_ODR_ENUM(GENERATE_VAL)};
49
lis2dux12_freq_to_odr_val(const struct device * dev,uint16_t freq)50 static int lis2dux12_freq_to_odr_val(const struct device *dev, uint16_t freq)
51 {
52 const struct lis2dux12_config *cfg = dev->config;
53
54 /* constrain loop to prevent erroneous power mode/odr combinations */
55 size_t i = (cfg->pm != LIS2DUX12_OPER_MODE_LOW_POWER) ? LIS2DUX12_DT_ODR_6Hz
56 : LIS2DUX12_DT_ODR_1Hz_ULP;
57 size_t len = (cfg->pm != LIS2DUX12_OPER_MODE_LOW_POWER) ? LIS2DUX12_DT_ODR_END
58 : LIS2DUX12_DT_ODR_6Hz;
59
60 while (i < len) {
61 if (freq <= lis2dux12_odr_map[i]) {
62 return i;
63 }
64 ++i;
65 }
66
67 return -EINVAL;
68 }
69
lis2dux12_set_fs(const struct device * dev,int16_t fs)70 static int lis2dux12_set_fs(const struct device *dev, int16_t fs)
71 {
72 int ret;
73 uint8_t range;
74 const struct lis2dux12_config *const cfg = dev->config;
75 const struct lis2dux12_chip_api *chip_api = cfg->chip_api;
76
77 switch (fs) {
78 case 2:
79 range = LIS2DUX12_DT_FS_2G;
80 break;
81 case 4:
82 range = LIS2DUX12_DT_FS_4G;
83 break;
84 case 8:
85 range = LIS2DUX12_DT_FS_8G;
86 break;
87 case 16:
88 range = LIS2DUX12_DT_FS_16G;
89 break;
90 default:
91 LOG_ERR("fs [%d] not supported.", fs);
92 return -EINVAL;
93 }
94
95 ret = chip_api->set_range(dev, range);
96 if (ret < 0) {
97 LOG_ERR("%s: range init error %d", dev->name, range);
98 return ret;
99 }
100
101 LOG_DBG("%s: set fs to %d g", dev->name, fs);
102 return ret;
103 }
104
lis2dux12_accel_config(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)105 static int lis2dux12_accel_config(const struct device *dev, enum sensor_channel chan,
106 enum sensor_attribute attr, const struct sensor_value *val)
107 {
108 int odr_val;
109 const struct lis2dux12_config *const cfg = dev->config;
110 const struct lis2dux12_chip_api *chip_api = cfg->chip_api;
111
112 switch (attr) {
113 case SENSOR_ATTR_FULL_SCALE:
114 return lis2dux12_set_fs(dev, sensor_ms2_to_g(val));
115 case SENSOR_ATTR_SAMPLING_FREQUENCY:
116 odr_val = lis2dux12_freq_to_odr_val(dev, val->val1);
117 if (odr_val < 0) {
118 LOG_ERR("%d Hz not supported or wrong operating mode.", val->val1);
119 return odr_val;
120 }
121
122 LOG_DBG("%s: set odr to %d Hz", dev->name, val->val1);
123
124 return chip_api->set_odr_raw(dev, odr_val);
125 default:
126 LOG_ERR("Accel attribute not supported.");
127 return -ENOTSUP;
128 }
129
130 return 0;
131 }
132
lis2dux12_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)133 static int lis2dux12_attr_set(const struct device *dev, enum sensor_channel chan,
134 enum sensor_attribute attr, const struct sensor_value *val)
135 {
136 switch (chan) {
137 case SENSOR_CHAN_ACCEL_XYZ:
138 return lis2dux12_accel_config(dev, chan, attr, val);
139 default:
140 LOG_ERR("attr_set() not supported on this channel.");
141 return -ENOTSUP;
142 }
143
144 return 0;
145 }
146
lis2dux12_sample_fetch(const struct device * dev,enum sensor_channel chan)147 static int lis2dux12_sample_fetch(const struct device *dev, enum sensor_channel chan)
148 {
149 const struct lis2dux12_config *const cfg = dev->config;
150 const struct lis2dux12_chip_api *chip_api = cfg->chip_api;
151 int ret;
152
153 switch (chan) {
154 case SENSOR_CHAN_ACCEL_XYZ:
155 ret = chip_api->sample_fetch_accel(dev);
156 break;
157 #if defined(CONFIG_LIS2DUX12_ENABLE_TEMP)
158 case SENSOR_CHAN_DIE_TEMP:
159 ret = chip_api->sample_fetch_temp(dev);
160 break;
161 #endif
162 case SENSOR_CHAN_ALL:
163 ret = chip_api->sample_fetch_accel(dev);
164 if (ret != 0)
165 break;
166 #if defined(CONFIG_LIS2DUX12_ENABLE_TEMP)
167 ret = chip_api->sample_fetch_temp(dev);
168 #endif
169 break;
170 default:
171 return -ENOTSUP;
172 }
173
174 return ret;
175 }
176
lis2dux12_convert(struct sensor_value * val,int raw_val,float gain)177 static inline void lis2dux12_convert(struct sensor_value *val, int raw_val, float gain)
178 {
179 int64_t dval;
180
181 /* Gain is in mg/LSB */
182 /* Convert to m/s^2 */
183 dval = ((int64_t)raw_val * gain * SENSOR_G) / 1000;
184 val->val1 = dval / 1000000LL;
185 val->val2 = dval % 1000000LL;
186 }
187
lis2dux12_get_channel(enum sensor_channel chan,struct sensor_value * val,struct lis2dux12_data * data,float gain)188 static inline int lis2dux12_get_channel(enum sensor_channel chan, struct sensor_value *val,
189 struct lis2dux12_data *data, float gain)
190 {
191 switch (chan) {
192 case SENSOR_CHAN_ACCEL_X:
193 lis2dux12_convert(val, data->sample_x, gain);
194 break;
195 case SENSOR_CHAN_ACCEL_Y:
196 lis2dux12_convert(val, data->sample_y, gain);
197 break;
198 case SENSOR_CHAN_ACCEL_Z:
199 lis2dux12_convert(val, data->sample_z, gain);
200 break;
201 case SENSOR_CHAN_ACCEL_XYZ:
202 lis2dux12_convert(val, data->sample_x, gain);
203 lis2dux12_convert(val + 1, data->sample_y, gain);
204 lis2dux12_convert(val + 2, data->sample_z, gain);
205 break;
206 #if defined(CONFIG_LIS2DUX12_ENABLE_TEMP)
207 case SENSOR_CHAN_DIE_TEMP:
208 sensor_value_from_float(val, data->sample_temp);
209 break;
210 #endif
211 default:
212 return -ENOTSUP;
213 }
214
215 return 0;
216 }
217
lis2dux12_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)218 static int lis2dux12_channel_get(const struct device *dev, enum sensor_channel chan,
219 struct sensor_value *val)
220 {
221 struct lis2dux12_data *data = dev->data;
222
223 return lis2dux12_get_channel(chan, val, data, data->gain);
224 }
225
226 static DEVICE_API(sensor, lis2dux12_driver_api) = {
227 .attr_set = lis2dux12_attr_set,
228 #if defined(CONFIG_LIS2DUX12_TRIGGER)
229 .trigger_set = lis2dux12_trigger_set,
230 #endif
231 .sample_fetch = lis2dux12_sample_fetch,
232 .channel_get = lis2dux12_channel_get,
233 };
234
235 /*
236 * Device creation macro, shared by LIS2DUX12_DEFINE_SPI() and
237 * LIS2DUX12_DEFINE_I2C().
238 */
239
240 /*
241 * Instantiation macros used when a device is on a SPI bus.
242 */
243
244 #ifdef CONFIG_LIS2DUX12_TRIGGER
245 #define LIS2DUX12_CFG_IRQ(inst) \
246 .trig_enabled = true, \
247 .int1_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int1_gpios, {0}), \
248 .int2_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int2_gpios, {0}), \
249 .drdy_pin = DT_INST_PROP(inst, drdy_pin),
250 #else
251 #define LIS2DUX12_CFG_IRQ(inst)
252 #endif /* CONFIG_LIS2DUX12_TRIGGER */
253
254 #define LIS2DUX12_CONFIG_COMMON(inst, name) \
255 .chip_api = &name##_chip_api, \
256 .range = DT_INST_PROP(inst, range), \
257 .pm = DT_INST_PROP(inst, power_mode), \
258 .odr = DT_INST_PROP(inst, odr), \
259 IF_ENABLED(UTIL_OR(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \
260 DT_INST_NODE_HAS_PROP(inst, int2_gpios)), \
261 (LIS2DUX12_CFG_IRQ(inst))) \
262
263 #define LIS2DUX12_SPI_OPERATION \
264 (SPI_WORD_SET(8) | SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA)
265
266 /*
267 * Instantiation macros used when a device is on a SPI bus.
268 */
269 #define LIS2DUX12_CONFIG_SPI(inst, name) \
270 { \
271 STMEMSC_CTX_SPI(&lis2dux12_config_##name##_##inst.stmemsc_cfg), \
272 .stmemsc_cfg = { \
273 .spi = SPI_DT_SPEC_INST_GET(inst, LIS2DUX12_SPI_OPERATION, 0), \
274 }, \
275 LIS2DUX12_CONFIG_COMMON(inst, name) \
276 }
277
278 /*
279 * Instantiation macros used when a device is on an I2C bus.
280 */
281 #define LIS2DUX12_CONFIG_I2C(inst, name) \
282 { \
283 STMEMSC_CTX_I2C(&lis2dux12_config_##name##_##inst.stmemsc_cfg), \
284 .stmemsc_cfg = { \
285 .i2c = I2C_DT_SPEC_INST_GET(inst), \
286 }, \
287 LIS2DUX12_CONFIG_COMMON(inst, name) \
288 }
289
290 /*
291 * Main instantiation macro. Use of COND_CODE_1() selects the right
292 * bus-specific macro at preprocessor time.
293 */
294
295 #define LIS2DUX12_DEFINE(inst, name) \
296 static struct lis2dux12_data lis2dux12_data_##name##_##inst; \
297 static const struct lis2dux12_config lis2dux12_config_##name##_##inst = \
298 COND_CODE_1(DT_INST_ON_BUS(inst, spi), \
299 (LIS2DUX12_CONFIG_SPI(inst, name)), \
300 (LIS2DUX12_CONFIG_I2C(inst, name))); \
301 \
302 SENSOR_DEVICE_DT_INST_DEFINE(inst, name##_init, NULL, \
303 &lis2dux12_data_##name##_##inst, \
304 &lis2dux12_config_##name##_##inst, POST_KERNEL, \
305 CONFIG_SENSOR_INIT_PRIORITY, \
306 &lis2dux12_driver_api);
307
308
309 #define DT_DRV_COMPAT st_lis2dux12
310 DT_INST_FOREACH_STATUS_OKAY_VARGS(LIS2DUX12_DEFINE, DT_DRV_COMPAT)
311 #undef DT_DRV_COMPAT
312
313 #define DT_DRV_COMPAT st_lis2duxs12
314 DT_INST_FOREACH_STATUS_OKAY_VARGS(LIS2DUX12_DEFINE, DT_DRV_COMPAT)
315 #undef DT_DRV_COMPAT
316