1 /*
2  * Copyright (c) 2022 Mizuki Agawa <agawa.mizuki@fujitsu.com>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT invensense_icp10125
8 
9 #include <zephyr/drivers/i2c.h>
10 #include <zephyr/drivers/sensor.h>
11 #include <zephyr/logging/log.h>
12 #include <zephyr/sys/byteorder.h>
13 
14 #ifdef CONFIG_ICP10125_CHECK_CRC
15 #include <zephyr/sys/crc.h>
16 #endif /* CONFIG_ICP10125_CHECK_CRC */
17 
18 LOG_MODULE_REGISTER(ICP10125, CONFIG_SENSOR_LOG_LEVEL);
19 
20 #define CRC_POLY	 0x31
21 #define SENSOR_DATA_SIZE 2
22 
23 #define AMBIENT_TEMP_DATA_NUM		1
24 #define PRESS_DATA_NUM			2
25 #define PRESS_AND_AMBIENT_TEMP_DATA_NUM (AMBIENT_TEMP_DATA_NUM + PRESS_DATA_NUM)
26 
27 enum {
28 	LOW_POWER,
29 	NORMAL,
30 	LOW_NOISE,
31 	ULTRA_LOW_NOISE,
32 	NUM_MEASURE_MODE
33 };
34 
35 struct icp10125_data {
36 	uint16_t raw_ambient_temp;
37 	uint32_t raw_press;
38 	float sensor_constants[4];
39 };
40 
41 struct icp10125_dev_config {
42 	struct i2c_dt_spec i2c;
43 	uint8_t ambient_temp_mode;
44 	uint8_t press_mode;
45 };
46 
47 struct icp10125_cmd {
48 	uint8_t data[2];
49 };
50 
51 struct icp10125_sensor_data {
52 	uint8_t data[2];
53 	uint8_t crc;
54 };
55 
56 struct icp10125_otp_read_setup {
57 	struct icp10125_cmd cmd;
58 	uint8_t data[3];
59 } __packed __aligned(1);
60 
61 /* ambient temperature measurement command for each mode.
62  * (Section 5.2 MEASUREMENT COMMANDS in the Datasheet)
63  */
64 static const struct icp10125_cmd ambient_temp_measurement_cmds[] = {
65 	{{0x60, 0x9C}}, {{0x68, 0x25}}, {{0x70, 0xDF}}, {{0x78, 0x66}}
66 };
67 
68 /* pressure measurement command for each mode.
69  * (Section 5.2 MEASUREMENT COMMANDS in the Datasheet)
70  */
71 static const struct icp10125_cmd press_measurement_cmds[] = {
72 	{{0x40, 0x1A}}, {{0x48, 0xA3}}, {{0x50, 0x59}}, {{0x59, 0xE0}}
73 };
74 
75 /* Request preparation for OTP data read. It should issue before data read request.
76  * (Section 5.2 MEASUREMENT COMMANDS in the Datasheet)
77  */
78 static const struct icp10125_otp_read_setup otp_read_setup = {
79 		.cmd = {{0xC5, 0x95}},
80 		.data = {0x00, 0x66, 0x9C}
81 };
82 
83 /* OTP data read request.
84  * After issue this command 2byte x 4 sensor constant value can readable.
85  */
86 static const struct icp10125_cmd otp_read_request_cmd = {{0xC7, 0xF7}};
87 
88 /* The max conversion time for each modes.
89  * (Section 2.2 OPERATION MODES in the Datasheet)
90  */
91 static const uint32_t conv_time_max[] = {1800, 6300, 23800, 94500};
92 
93 /* The typical conversion time for each modes.
94  * (Section 2.2 OPERATION MODES in the Datasheet)
95  */
96 static const uint32_t conv_time_typ[] = {1600, 5600, 20800, 83200};
97 
98 /* The Datasheet has no mention of the constants and formulas.
99  * Instead, it shows only how to use it in the sample code.
100  * Since there is no detailed description in the ICP10125 product manual,
101  * the calculation of the pressure implements is the same as shown in
102  * the 5.11 SAMPLE CODE: EXAMPLE C SYNTAX
103  */
104 
icp10125_calculate_conversion_constants(const float * p_LUT,float * A,float * B,float * C)105 static void icp10125_calculate_conversion_constants(const float *p_LUT, float *A, float *B,
106 						    float *C)
107 {
108 	const float p_Pa[] = {45000.0, 80000.0, 105000.0};
109 
110 	*C = (p_LUT[0] * p_LUT[1] * (p_Pa[0] - p_Pa[1]) +
111 	      p_LUT[1] * p_LUT[2] * (p_Pa[1] - p_Pa[2]) +
112 	      p_LUT[2] * p_LUT[0] * (p_Pa[2] - p_Pa[0])) /
113 	     (p_LUT[2] * (p_Pa[0] - p_Pa[1]) + p_LUT[0] * (p_Pa[1] - p_Pa[2]) +
114 	      p_LUT[1] * (p_Pa[2] - p_Pa[0]));
115 	*A = (p_Pa[0] * p_LUT[0] - p_Pa[1] * p_LUT[1] - (p_Pa[1] - p_Pa[0]) * (*C)) /
116 	     (p_LUT[0] - p_LUT[1]);
117 	*B = (p_Pa[0] - (*A)) * (p_LUT[0] + (*C));
118 }
119 
icp10125_calc_calibrated_ambient_temp(const struct icp10125_data * data)120 static float icp10125_calc_calibrated_ambient_temp(const struct icp10125_data *data)
121 {
122 	return -45.f + 175.f / 65536.f * data->raw_ambient_temp;
123 }
124 
icp10125_calc_calibrated_press(const struct icp10125_data * data)125 static float icp10125_calc_calibrated_press(const struct icp10125_data *data)
126 {
127 	const float quadr_factor = 1 / 16777216.0;
128 	const float offst_factor = 2048.0;
129 	const float LUT_lower = 3.5 * (1 << 20);
130 	const float LUT_upper = 11.5 * (1 << 20);
131 	float t;
132 	float in[3];
133 	float A, B, C;
134 
135 	t = data->raw_ambient_temp - 32768.f;
136 	in[0] = LUT_lower + (data->sensor_constants[0] * t * t) * quadr_factor;
137 	in[1] = offst_factor * data->sensor_constants[3] +
138 		(data->sensor_constants[1] * t * t) * quadr_factor;
139 	in[2] = LUT_upper + (data->sensor_constants[2] * t * t) * quadr_factor;
140 	icp10125_calculate_conversion_constants(in, &A, &B, &C);
141 
142 	return A + B / (C + data->raw_press);
143 }
144 
145 /* End of porting the 5.11 SAMPLE CODE: EXAMPLE C SYNTAX */
146 
icp10125_read_otp(const struct device * dev)147 static int icp10125_read_otp(const struct device *dev)
148 {
149 	struct icp10125_data *data = dev->data;
150 	struct icp10125_sensor_data sensor_data;
151 
152 	const struct icp10125_dev_config *cfg = dev->config;
153 	int rc = 0;
154 
155 	rc = i2c_write_dt(&cfg->i2c, (uint8_t *)&otp_read_setup, sizeof(otp_read_setup));
156 	if (rc < 0) {
157 		LOG_ERR("Failed to write otp_read_setup.\n");
158 		return rc;
159 	}
160 
161 	for (size_t i = 0; i < ARRAY_SIZE(data->sensor_constants); i++) {
162 		rc = i2c_write_dt(&cfg->i2c, (uint8_t *)&otp_read_request_cmd,
163 				  sizeof(otp_read_request_cmd));
164 		if (rc < 0) {
165 			LOG_ERR("Failed to write otp_read_request.\n");
166 			return rc;
167 		}
168 
169 		rc = i2c_read_dt(&cfg->i2c, (uint8_t *)&sensor_data, sizeof(sensor_data));
170 		if (rc < 0) {
171 			LOG_ERR("Failed to read otp_read_request.\n");
172 			return rc;
173 		}
174 
175 		data->sensor_constants[i] = sys_get_be16(sensor_data.data);
176 	}
177 
178 	return 0;
179 }
180 
181 #ifdef CONFIG_ICP10125_CHECK_CRC
icp10125_check_crc(const uint8_t * data,const size_t len)182 static int icp10125_check_crc(const uint8_t *data, const size_t len)
183 {
184 	/* Details of CRC are described in Chapter 5 Section 8 of the product
185 	 * specifications.
186 	 */
187 	return crc8(data, len, CRC_POLY, 0xFF, false);
188 }
189 #endif
190 
icp10125_measure(const struct i2c_dt_spec * i2c,const struct icp10125_cmd * cmds,const uint8_t mode,struct icp10125_sensor_data * sensor_data,const size_t data_num)191 static int icp10125_measure(const struct i2c_dt_spec *i2c, const struct icp10125_cmd *cmds,
192 			    const uint8_t mode, struct icp10125_sensor_data *sensor_data,
193 			    const size_t data_num)
194 {
195 	int rc = 0;
196 
197 	rc = i2c_write_dt(i2c, (uint8_t *)&cmds[mode], sizeof(cmds[mode]));
198 	if (rc < 0) {
199 		LOG_ERR("Failed to start measurement.\n");
200 		return rc;
201 	}
202 
203 	/* Wait for the sensor to become readable.
204 	 * First wait for the typical time and then read.
205 	 * If that fails, wait until the time to surely became readable.
206 	 */
207 	k_sleep(K_USEC(conv_time_typ[mode]));
208 	if (i2c_read_dt(i2c, (uint8_t *)sensor_data, sizeof(sensor_data[0]) * data_num) < 0) {
209 		k_sleep(K_USEC(conv_time_max[mode] - conv_time_typ[mode]));
210 		rc = i2c_read_dt(i2c, (uint8_t *)sensor_data, sizeof(sensor_data[0]) * data_num);
211 		if (rc < 0) {
212 			LOG_ERR("Failed to read measurement.\n");
213 			return rc;
214 		}
215 	}
216 
217 #ifdef CONFIG_ICP10125_CHECK_CRC
218 	/* Calculate CRC from Chapter 5 Section 8 of ICP10125 Product manuals. */
219 	for (size_t i = 0; i < data_num; i++) {
220 		if (!icp10125_check_crc(sensor_data[i].data, SENSOR_DATA_SIZE)) {
221 			LOG_ERR("Sensor data has invalid CRC.\n");
222 			return -EIO;
223 		}
224 	}
225 #endif /* CONFIG_ICP10125_CHECK_CRC */
226 
227 	return 0;
228 }
229 
icp10125_sample_fetch(const struct device * dev,const enum sensor_channel chan)230 static int icp10125_sample_fetch(const struct device *dev, const enum sensor_channel chan)
231 {
232 	struct icp10125_data *data = dev->data;
233 	const struct icp10125_dev_config *cfg = dev->config;
234 	uint8_t endian_conversion[3];
235 	struct icp10125_sensor_data sensor_data[PRESS_AND_AMBIENT_TEMP_DATA_NUM] = {0};
236 	int rc = 0;
237 
238 	if (!(chan == SENSOR_CHAN_AMBIENT_TEMP || chan == SENSOR_CHAN_PRESS ||
239 	      chan == SENSOR_CHAN_ALL)) {
240 		return -ENOTSUP;
241 	}
242 
243 	if (chan == SENSOR_CHAN_AMBIENT_TEMP) {
244 		rc = icp10125_measure(&cfg->i2c, ambient_temp_measurement_cmds,
245 				      cfg->ambient_temp_mode, sensor_data, AMBIENT_TEMP_DATA_NUM);
246 		if (rc < 0) {
247 			return rc;
248 		}
249 
250 		data->raw_ambient_temp = sys_get_be16(sensor_data[0].data);
251 	} else {
252 		rc = icp10125_measure(&cfg->i2c, press_measurement_cmds, cfg->press_mode,
253 				      sensor_data, PRESS_AND_AMBIENT_TEMP_DATA_NUM);
254 		if (rc < 0) {
255 			return rc;
256 		}
257 
258 		endian_conversion[0] = sensor_data[0].data[0];
259 		endian_conversion[1] = sensor_data[0].data[1];
260 		endian_conversion[2] = sensor_data[1].data[0];
261 		data->raw_press = sys_get_be24(endian_conversion);
262 		data->raw_ambient_temp = sys_get_be16(sensor_data[2].data);
263 	}
264 
265 	return 0;
266 }
267 
icp10125_convert_press_value(struct icp10125_data * data,struct sensor_value * val)268 static void icp10125_convert_press_value(struct icp10125_data *data, struct sensor_value *val)
269 {
270 	sensor_value_from_float(val, icp10125_calc_calibrated_press(data) / 1000.f);
271 }
272 
icp10125_convert_ambient_temp_value(struct icp10125_data * data,struct sensor_value * val)273 static void icp10125_convert_ambient_temp_value(struct icp10125_data *data,
274 						struct sensor_value *val)
275 {
276 	sensor_value_from_float(val, icp10125_calc_calibrated_ambient_temp(data));
277 }
278 
icp10125_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)279 static int icp10125_channel_get(const struct device *dev, enum sensor_channel chan,
280 				struct sensor_value *val)
281 {
282 	struct icp10125_data *data = dev->data;
283 
284 	if (chan == SENSOR_CHAN_AMBIENT_TEMP) {
285 		icp10125_convert_ambient_temp_value(data, val);
286 	} else if (chan == SENSOR_CHAN_PRESS) {
287 		icp10125_convert_press_value(data, val);
288 	} else {
289 		return -ENOTSUP;
290 	}
291 
292 	return 0;
293 }
294 
icp10125_init(const struct device * dev)295 static int icp10125_init(const struct device *dev)
296 {
297 	int rc = icp10125_read_otp(dev);
298 
299 	if (rc < 0) {
300 		return rc;
301 	}
302 
303 	return 0;
304 }
305 
306 static const struct sensor_driver_api icp10125_api_funcs = {
307 	.sample_fetch = icp10125_sample_fetch,
308 	.channel_get = icp10125_channel_get,
309 };
310 
311 #define ICP10125_DEFINE(inst)                                                                      \
312 	static struct icp10125_data icp10125_drv_##inst;                                           \
313 	static const struct icp10125_dev_config icp10125_config_##inst = {                         \
314 		.i2c = I2C_DT_SPEC_INST_GET(inst),                                                 \
315 		.ambient_temp_mode = DT_INST_ENUM_IDX(inst, temperature_measurement_mode),         \
316 		.press_mode = DT_INST_ENUM_IDX(inst, pressure_measurement_mode)};                  \
317 	DEVICE_DT_INST_DEFINE(inst, icp10125_init, NULL, &icp10125_drv_##inst,                     \
318 			      &icp10125_config_##inst, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY,   \
319 			      &icp10125_api_funcs);
320 
321 DT_INST_FOREACH_STATUS_OKAY(ICP10125_DEFINE)
322