1 /*
2 * Copyright (c) 2019 Thomas Schmid <tom@lfence.de>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT meas_ms5607
8
9 #include <zephyr/init.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/sys/byteorder.h>
12 #include <zephyr/drivers/sensor.h>
13 #include <zephyr/sys/__assert.h>
14
15 #include "ms5607.h"
16
17 #define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL
18 #include <zephyr/logging/log.h>
19 LOG_MODULE_REGISTER(ms5607);
20
ms5607_compensate(struct ms5607_data * data,const int32_t adc_temperature,const int32_t adc_pressure)21 static void ms5607_compensate(struct ms5607_data *data,
22 const int32_t adc_temperature,
23 const int32_t adc_pressure)
24 {
25 int64_t dT;
26 int64_t OFF;
27 int64_t SENS;
28 int64_t temp_sq;
29 int64_t Ti;
30 int64_t OFFi;
31 int64_t SENSi;
32
33 /* first order compensation as per datasheet
34 * (https://www.te.com/usa-en/product-CAT-BLPS0035.html) section
35 * PRESSURE AND TEMPERATURE CALCULATION
36 */
37
38 dT = adc_temperature - ((int32_t)(data->t_ref) << 8);
39 data->temperature = 2000 + (dT * data->tempsens) / (1ll << 23);
40 OFF = ((int64_t)(data->off_t1) << 17) + (dT * data->tco) / (1ll << 6);
41 SENS = ((int64_t)(data->sens_t1) << 16) + (dT * data->tcs) / (1ll << 7);
42
43 /* Second order compensation as per datasheet
44 * (https://www.te.com/usa-en/product-CAT-BLPS0035.html) section
45 * SECOND ORDER TEMPERATURE COMPENSATION
46 */
47
48 temp_sq = (int64_t)(data->temperature - 2000) *
49 (int64_t)(data->temperature - 2000);
50 if (data->temperature < 2000) {
51 Ti = (dT * dT) / (1ll << 31);
52 OFFi = (61ll * temp_sq) / (1ll << 4);
53 SENSi = 2ll * temp_sq;
54 if (data->temperature < -1500) {
55 temp_sq = (int64_t)(data->temperature + 1500) *
56 (int64_t)(data->temperature + 1500);
57 OFFi += 15ll * temp_sq;
58 SENSi += 8ll * temp_sq;
59 }
60 } else {
61 SENSi = 0;
62 OFFi = 0;
63 Ti = 0;
64 }
65
66 OFF -= OFFi;
67 SENS -= SENSi;
68
69 data->temperature -= Ti;
70 data->pressure = (SENS * (int64_t)adc_pressure / (1ll << 21) - OFF) /
71 (1ll << 15);
72 }
73
ms5607_read_prom(const struct ms5607_config * config,uint8_t cmd,uint16_t * val)74 static int ms5607_read_prom(const struct ms5607_config *config, uint8_t cmd,
75 uint16_t *val)
76 {
77 int err;
78
79 err = config->tf->read_prom(config, cmd, val);
80 if (err < 0) {
81 LOG_ERR("Error reading prom");
82 return err;
83 }
84
85 return 0;
86 }
87
ms5607_get_measurement(const struct ms5607_config * config,uint32_t * val,uint8_t cmd,uint8_t delay)88 static int ms5607_get_measurement(const struct ms5607_config *config,
89 uint32_t *val,
90 uint8_t cmd,
91 uint8_t delay)
92 {
93 int err;
94
95 *val = 0U;
96
97 err = config->tf->start_conversion(config, cmd);
98 if (err < 0) {
99 return err;
100 }
101
102 k_msleep(delay);
103
104 err = config->tf->read_adc(config, val);
105 if (err < 0) {
106 return err;
107 }
108
109 return 0;
110 }
111
ms5607_sample_fetch(const struct device * dev,enum sensor_channel channel)112 static int ms5607_sample_fetch(const struct device *dev,
113 enum sensor_channel channel)
114 {
115 const struct ms5607_config *config = dev->config;
116 struct ms5607_data *data = dev->data;
117 int err;
118 uint32_t adc_pressure, adc_temperature;
119
120 __ASSERT_NO_MSG(channel == SENSOR_CHAN_ALL);
121
122 err = ms5607_get_measurement(config,
123 &adc_pressure,
124 data->pressure_conv_cmd,
125 data->pressure_conv_delay);
126 if (err < 0) {
127 return err;
128 }
129
130 err = ms5607_get_measurement(config,
131 &adc_temperature,
132 data->temperature_conv_cmd,
133 data->temperature_conv_delay);
134 if (err < 0) {
135 return err;
136 }
137
138 ms5607_compensate(data, adc_temperature, adc_pressure);
139 return 0;
140 }
141
ms5607_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)142 static int ms5607_channel_get(const struct device *dev,
143 enum sensor_channel chan,
144 struct sensor_value *val)
145 {
146 const struct ms5607_data *data = dev->data;
147
148 switch (chan) {
149 case SENSOR_CHAN_AMBIENT_TEMP:
150 val->val1 = data->temperature / 100;
151 val->val2 = data->temperature % 100 * 10000;
152 break;
153 case SENSOR_CHAN_PRESS:
154 val->val1 = data->pressure / 100;
155 val->val2 = data->pressure % 100 * 10000;
156 break;
157 default:
158 return -ENOTSUP;
159 }
160
161 return 0;
162 }
163
ms5607_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)164 static int ms5607_attr_set(const struct device *dev, enum sensor_channel chan,
165 enum sensor_attribute attr,
166 const struct sensor_value *val)
167 {
168 struct ms5607_data *data = dev->data;
169 uint8_t p_conv_cmd, t_conv_cmd, conv_delay;
170
171 if (attr != SENSOR_ATTR_OVERSAMPLING) {
172 return -ENOTSUP;
173 }
174
175 switch (val->val1) {
176 case 4096:
177 p_conv_cmd = MS5607_CMD_CONV_P_4096;
178 t_conv_cmd = MS5607_CMD_CONV_T_4096;
179 conv_delay = 9U;
180 break;
181 case 2048:
182 p_conv_cmd = MS5607_CMD_CONV_P_2048;
183 t_conv_cmd = MS5607_CMD_CONV_T_2048;
184 conv_delay = 5U;
185 break;
186 case 1024:
187 p_conv_cmd = MS5607_CMD_CONV_P_1024;
188 t_conv_cmd = MS5607_CMD_CONV_T_1024;
189 conv_delay = 3U;
190 break;
191 case 512:
192 p_conv_cmd = MS5607_CMD_CONV_P_512;
193 t_conv_cmd = MS5607_CMD_CONV_T_512;
194 conv_delay = 2U;
195 break;
196 case 256:
197 p_conv_cmd = MS5607_CMD_CONV_P_256;
198 t_conv_cmd = MS5607_CMD_CONV_T_256;
199 conv_delay = 1U;
200 break;
201 default:
202 LOG_ERR("invalid oversampling rate %d", val->val1);
203 return -EINVAL;
204 }
205
206 switch (chan) {
207 case SENSOR_CHAN_ALL:
208 data->pressure_conv_cmd = p_conv_cmd;
209 data->temperature_conv_cmd = t_conv_cmd;
210 data->temperature_conv_delay = conv_delay;
211 data->pressure_conv_delay = conv_delay;
212 break;
213 case SENSOR_CHAN_PRESS:
214 data->pressure_conv_cmd = p_conv_cmd;
215 data->pressure_conv_delay = conv_delay;
216 break;
217 case SENSOR_CHAN_AMBIENT_TEMP:
218 data->temperature_conv_cmd = t_conv_cmd;
219 data->temperature_conv_delay = conv_delay;
220 break;
221 default:
222 return -ENOTSUP;
223 }
224
225 return 0;
226 }
227
ms5607_init(const struct device * dev)228 static int ms5607_init(const struct device *dev)
229 {
230 const struct ms5607_config *const config = dev->config;
231 struct ms5607_data *data = dev->data;
232 struct sensor_value val;
233 int err;
234
235 err = config->tf->bus_check(config);
236 if (err < 0) {
237 return err;
238 }
239
240 data->pressure = 0;
241 data->temperature = 0;
242
243
244 val.val1 = MS5607_PRES_OVER_DEFAULT;
245 err = ms5607_attr_set(dev, SENSOR_CHAN_PRESS, SENSOR_ATTR_OVERSAMPLING,
246 &val);
247 if (err < 0) {
248 return err;
249 }
250
251 val.val1 = MS5607_TEMP_OVER_DEFAULT;
252 err = ms5607_attr_set(dev, SENSOR_CHAN_AMBIENT_TEMP,
253 SENSOR_ATTR_OVERSAMPLING, &val);
254 if (err < 0) {
255 return err;
256 }
257
258 err = config->tf->reset(config);
259 if (err < 0) {
260 return err;
261 }
262
263 k_sleep(K_MSEC(2));
264
265 err = ms5607_read_prom(config, MS5607_CMD_CONV_READ_OFF_T1,
266 &data->off_t1);
267 if (err < 0) {
268 return err;
269 }
270
271 LOG_DBG("OFF_T1: %d", data->off_t1);
272
273 err = ms5607_read_prom(config, MS5607_CMD_CONV_READ_SENSE_T1,
274 &data->sens_t1);
275 if (err < 0) {
276 return err;
277 }
278
279 LOG_DBG("SENSE_T1: %d", data->sens_t1);
280
281 err = ms5607_read_prom(config, MS5607_CMD_CONV_READ_T_REF, &data->t_ref);
282 if (err < 0) {
283 return err;
284 }
285
286 LOG_DBG("T_REF: %d", data->t_ref);
287
288 err = ms5607_read_prom(config, MS5607_CMD_CONV_READ_TCO, &data->tco);
289 if (err < 0) {
290 return err;
291 }
292
293 LOG_DBG("TCO: %d", data->tco);
294
295 err = ms5607_read_prom(config, MS5607_CMD_CONV_READ_TCS, &data->tcs);
296 if (err < 0) {
297 return err;
298 }
299
300 LOG_DBG("TCS: %d", data->tcs);
301
302 err = ms5607_read_prom(config, MS5607_CMD_CONV_READ_TEMPSENS,
303 &data->tempsens);
304 if (err < 0) {
305 return err;
306 }
307
308 LOG_DBG("TEMPSENS: %d", data->tempsens);
309
310 return 0;
311 }
312
313 static DEVICE_API(sensor, ms5607_api_funcs) = {
314 .attr_set = ms5607_attr_set,
315 .sample_fetch = ms5607_sample_fetch,
316 .channel_get = ms5607_channel_get,
317 };
318
319 #define MS5607_SPI_OPERATION (SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | \
320 SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_TRANSFER_MSB)
321
322 /* Initializes a struct ms5607_config for an instance on a SPI bus. */
323 #define MS5607_CONFIG_SPI(inst) \
324 { \
325 .tf = &ms5607_spi_transfer_function, \
326 .bus_cfg.spi = SPI_DT_SPEC_INST_GET(inst, \
327 MS5607_SPI_OPERATION, \
328 0), \
329 }
330
331 /* Initializes a struct ms5607_config for an instance on a I2C bus. */
332 #define MS5607_CONFIG_I2C(inst) \
333 { \
334 .tf = &ms5607_i2c_transfer_function, \
335 .bus_cfg.i2c = I2C_DT_SPEC_INST_GET(inst), \
336 }
337
338 /*
339 * Main instantiation macro, which selects the correct bus-specific
340 * instantiation macros for the instance.
341 */
342 #define MS5607_DEFINE(inst) \
343 static struct ms5607_data ms5607_data_##inst; \
344 static const struct ms5607_config ms5607_config_##inst = \
345 COND_CODE_1(DT_INST_ON_BUS(inst, spi), \
346 (MS5607_CONFIG_SPI(inst)), \
347 (MS5607_CONFIG_I2C(inst))); \
348 SENSOR_DEVICE_DT_INST_DEFINE(inst, \
349 ms5607_init, \
350 NULL, \
351 &ms5607_data_##inst, \
352 &ms5607_config_##inst, \
353 POST_KERNEL, \
354 CONFIG_SENSOR_INIT_PRIORITY, \
355 &ms5607_api_funcs);
356
357 /* Create the struct device for every status "okay" node in the devicetree. */
358 DT_INST_FOREACH_STATUS_OKAY(MS5607_DEFINE)
359