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