1 /* ST Microelectronics LPS2XDF pressure and temperature sensor
2  *
3  * Copyright (c) 2023 STMicroelectronics
4  * Copyright (c) 2023 PHYTEC Messtechnik GmbH
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  *
8  * Datasheet:
9  * https://www.st.com/resource/en/datasheet/ilps22qs.pdf
10  * https://www.st.com/resource/en/datasheet/lps22df.pdf
11  * https://www.st.com/resource/en/datasheet/lps28df.pdf
12  */
13 
14 #include <zephyr/drivers/sensor.h>
15 #include <zephyr/kernel.h>
16 #include <zephyr/device.h>
17 #include <zephyr/init.h>
18 #include <zephyr/sys/byteorder.h>
19 #include <zephyr/sys/__assert.h>
20 #include <zephyr/logging/log.h>
21 
22 #include "lps2xdf.h"
23 
24 #if DT_HAS_COMPAT_STATUS_OKAY(st_ilps22qs)
25 #include "ilps22qs.h"
26 #endif
27 
28 #if DT_HAS_COMPAT_STATUS_OKAY(st_lps22df)
29 #include "lps22df.h"
30 #endif
31 
32 #if DT_HAS_COMPAT_STATUS_OKAY(st_lps28dfw)
33 #include "lps28dfw.h"
34 #endif
35 
36 LOG_MODULE_REGISTER(LPS2XDF, CONFIG_SENSOR_LOG_LEVEL);
37 
38 static const uint16_t lps2xdf_map[] = {0, 1, 4, 10, 25, 50, 75, 100, 200};
39 
lps2xdf_odr_set(const struct device * dev,uint16_t freq)40 static int lps2xdf_odr_set(const struct device *dev, uint16_t freq)
41 {
42 	int odr;
43 	const struct lps2xdf_config *const cfg = dev->config;
44 	const struct lps2xdf_chip_api *chip_api = cfg->chip_api;
45 
46 	for (odr = 0; odr < ARRAY_SIZE(lps2xdf_map); odr++) {
47 		if (freq == lps2xdf_map[odr]) {
48 			break;
49 		}
50 	}
51 
52 	if (odr == ARRAY_SIZE(lps2xdf_map)) {
53 		LOG_DBG("bad frequency");
54 		return -EINVAL;
55 	}
56 
57 	if (chip_api->mode_set_odr_raw(dev, odr)) {
58 		LOG_DBG("failed to set sampling rate");
59 		return -EIO;
60 	}
61 
62 	return 0;
63 }
64 
lps2xdf_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)65 static int lps2xdf_attr_set(const struct device *dev, enum sensor_channel chan,
66 			    enum sensor_attribute attr, const struct sensor_value *val)
67 {
68 	if (chan != SENSOR_CHAN_ALL) {
69 		LOG_WRN("attr_set() not supported on this channel.");
70 		return -ENOTSUP;
71 	}
72 
73 	switch (attr) {
74 	case SENSOR_ATTR_SAMPLING_FREQUENCY:
75 		return lps2xdf_odr_set(dev, val->val1);
76 	default:
77 		LOG_DBG("operation not supported.");
78 		return -ENOTSUP;
79 	}
80 
81 	return 0;
82 }
83 
lps2xdf_press_convert(const struct device * dev,struct sensor_value * val,int32_t raw_val)84 static inline void lps2xdf_press_convert(const struct device *dev,
85 					 struct sensor_value *val,
86 					 int32_t raw_val)
87 {
88 	const struct lps2xdf_config *const cfg = dev->config;
89 	int32_t press_tmp = raw_val >> 8; /* raw value is left aligned (24 msb) */
90 	int divider;
91 
92 	/* Pressure sensitivity is:
93 	 * - 4096 LSB/hPa for Full-Scale of 260 - 1260 hPa:
94 	 * - 2048 LSB/hPa for Full-Scale of 260 - 4060 hPa:
95 	 * Also convert hPa into kPa
96 	 */
97 	if (cfg->fs == 0) {
98 		divider = 40960;
99 	} else {
100 		divider = 20480;
101 	}
102 	val->val1 = press_tmp / divider;
103 
104 	/* For the decimal part use (3125 / 128) as a factor instead of
105 	 * (1000000 / 40960) to avoid int32 overflow
106 	 */
107 	val->val2 = (press_tmp % divider) * 3125 / 128;
108 }
109 
110 
lps2xdf_temp_convert(struct sensor_value * val,int16_t raw_val)111 static inline void lps2xdf_temp_convert(struct sensor_value *val, int16_t raw_val)
112 {
113 	/* Temperature sensitivity is 100 LSB/deg C */
114 	val->val1 = raw_val / 100;
115 	val->val2 = ((int32_t)raw_val % 100) * 10000;
116 }
117 
lps2xdf_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)118 static int lps2xdf_channel_get(const struct device *dev, enum sensor_channel chan,
119 			       struct sensor_value *val)
120 {
121 	struct lps2xdf_data *data = dev->data;
122 
123 	if (chan == SENSOR_CHAN_PRESS) {
124 		lps2xdf_press_convert(dev, val, data->sample_press);
125 	} else if (chan == SENSOR_CHAN_AMBIENT_TEMP) {
126 		lps2xdf_temp_convert(val, data->sample_temp);
127 	} else {
128 		return -ENOTSUP;
129 	}
130 
131 	return 0;
132 }
133 
lps2xdf_sample_fetch(const struct device * dev,enum sensor_channel chan)134 static int lps2xdf_sample_fetch(const struct device *dev, enum sensor_channel chan)
135 {
136 	const struct lps2xdf_config *const cfg = dev->config;
137 	const struct lps2xdf_chip_api *chip_api = cfg->chip_api;
138 
139 	__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);
140 
141 	return chip_api->sample_fetch(dev, chan);
142 }
143 
144 static DEVICE_API(sensor, lps2xdf_driver_api) = {
145 	.attr_set = lps2xdf_attr_set,
146 	.sample_fetch = lps2xdf_sample_fetch,
147 	.channel_get = lps2xdf_channel_get,
148 #if CONFIG_LPS2XDF_TRIGGER
149 	.trigger_set = lps2xdf_trigger_set,
150 #endif
151 };
152 
153 #ifdef CONFIG_LPS2XDF_TRIGGER
154 #define LPS2XDF_CFG_IRQ(inst)                                                  \
155 	.trig_enabled = true,                                                  \
156 	.gpio_int = GPIO_DT_SPEC_INST_GET(inst, drdy_gpios),                   \
157 	.drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed)
158 #else
159 #define LPS2XDF_CFG_IRQ(inst)
160 #endif /* CONFIG_LPS2XDF_TRIGGER */
161 
162 #define LPS2XDF_CONFIG_COMMON(inst, name)                                      \
163 	.odr = DT_INST_PROP(inst, odr),                                        \
164 	.lpf = DT_INST_PROP(inst, lpf),                                        \
165 	.avg = DT_INST_PROP(inst, avg),                                        \
166 	.chip_api = &name##_chip_api,                                          \
167 	IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, fs),                            \
168 		   (.fs = DT_INST_PROP(inst, fs),))                            \
169 	IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, drdy_gpios),                    \
170 		   (LPS2XDF_CFG_IRQ(inst)))
171 
172 #define LPS2XDF_SPI_OPERATION (SPI_WORD_SET(8) | SPI_OP_MODE_MASTER |          \
173 			       SPI_MODE_CPOL | SPI_MODE_CPHA)
174 
175 #define LPS2XDF_CONFIG_SPI(inst, name)                                         \
176 {                                                                              \
177 	STMEMSC_CTX_SPI(&lps2xdf_config_##name##_##inst.stmemsc_cfg),          \
178 	.stmemsc_cfg = {                                                       \
179 		.spi = SPI_DT_SPEC_INST_GET(inst, LPS2XDF_SPI_OPERATION, 0),   \
180 	},                                                                     \
181 	LPS2XDF_CONFIG_COMMON(inst, name)                                      \
182 }
183 
184 #define LPS2XDF_CONFIG_I2C(inst, name)                                         \
185 {                                                                              \
186 	STMEMSC_CTX_I2C(&lps2xdf_config_##name##_##inst.stmemsc_cfg),          \
187 	.stmemsc_cfg = {                                                       \
188 		.i2c = I2C_DT_SPEC_INST_GET(inst),                             \
189 	},                                                                     \
190 	LPS2XDF_CONFIG_COMMON(inst, name)                                      \
191 }
192 
193 #define LPS2XDF_CONFIG_I3C(inst, name)                                         \
194 {                                                                              \
195 	STMEMSC_CTX_I3C(&lps2xdf_config_##name##_##inst.stmemsc_cfg),          \
196 	.stmemsc_cfg = {                                                       \
197 		.i3c = &lps2xdf_data_##name##_##inst.i3c_dev,                  \
198 	},                                                                     \
199 	.i3c.bus = DEVICE_DT_GET(DT_INST_BUS(inst)),                           \
200 	.i3c.dev_id = I3C_DEVICE_ID_DT_INST(inst),                             \
201 	LPS2XDF_CONFIG_COMMON(inst, name)                                      \
202 }
203 
204 #define LPS2XDF_CONFIG_I3C_OR_I2C(inst, name)                                  \
205 	COND_CODE_0(DT_INST_PROP_BY_IDX(inst, reg, 1),                         \
206 		    (LPS2XDF_CONFIG_I2C(inst, name)),                          \
207 		    (LPS2XDF_CONFIG_I3C(inst, name)))
208 
209 #define LPS2XDF_DEFINE(inst, name)                                                           \
210 	static struct lps2xdf_data lps2xdf_data_##name##_##inst;                             \
211 	static const struct lps2xdf_config lps2xdf_config_##name##_##inst = COND_CODE_1(     \
212 		DT_INST_ON_BUS(inst, spi),                                                   \
213 		(LPS2XDF_CONFIG_SPI(inst, name)),                                            \
214 		(COND_CODE_1(DT_INST_ON_BUS(inst, i3c),                                      \
215 			     (LPS2XDF_CONFIG_I3C_OR_I2C(inst, name)),                        \
216 			     (LPS2XDF_CONFIG_I2C(inst, name)))));                            \
217 											     \
218 	SENSOR_DEVICE_DT_INST_DEFINE(inst, name##_init, NULL, &lps2xdf_data_##name##_##inst, \
219 				     &lps2xdf_config_##name##_##inst, POST_KERNEL,           \
220 				     CONFIG_SENSOR_INIT_PRIORITY, &lps2xdf_driver_api);
221 
222 #define DT_DRV_COMPAT st_ilps22qs
223 DT_INST_FOREACH_STATUS_OKAY_VARGS(LPS2XDF_DEFINE, DT_DRV_COMPAT)
224 #undef DT_DRV_COMPAT
225 
226 #define DT_DRV_COMPAT st_lps22df
227 DT_INST_FOREACH_STATUS_OKAY_VARGS(LPS2XDF_DEFINE, DT_DRV_COMPAT)
228 #undef DT_DRV_COMPAT
229 
230 #define DT_DRV_COMPAT st_lps28dfw
231 DT_INST_FOREACH_STATUS_OKAY_VARGS(LPS2XDF_DEFINE, DT_DRV_COMPAT)
232 #undef DT_DRV_COMPAT
233