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