1 /*
2  * Copyright (c) 2021, Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT invensense_mpu9250
8 
9 #include <zephyr/sys/byteorder.h>
10 #include <zephyr/logging/log.h>
11 #include <zephyr/devicetree.h>
12 
13 #include "mpu9250.h"
14 
15 #ifdef CONFIG_MPU9250_MAGN_EN
16 #include "ak8963.h"
17 #endif
18 
19 LOG_MODULE_REGISTER(MPU9250, CONFIG_SENSOR_LOG_LEVEL);
20 
21 
22 #define MPU9250_REG_CHIP_ID		0x75
23 #define MPU9250_CHIP_ID			0x71
24 
25 #define MPU9250_REG_SR_DIV		0x19
26 
27 #define MPU9250_REG_CONFIG		0x1A
28 #define MPU9250_GYRO_DLPF_MAX		7
29 
30 #define MPU9250_REG_GYRO_CFG		0x1B
31 #define MPU9250_GYRO_FS_SHIFT		3
32 #define MPU9250_GYRO_FS_MAX		3
33 
34 #define MPU9250_REG_ACCEL_CFG		0x1C
35 #define MPU9250_ACCEL_FS_SHIFT		3
36 #define MPU9250_ACCEL_FS_MAX		3
37 
38 #define MPU9250_REG_ACCEL_CFG2		0x1D
39 #define MPU9250_ACCEL_DLPF_MAX		7
40 
41 #define MPU9250_REG_DATA_START		0x3B
42 
43 #define MPU0259_TEMP_SENSITIVITY	334
44 #define MPU9250_TEMP_OFFSET		21
45 
46 #define MPU9250_REG_PWR_MGMT1		0x6B
47 #define MPU9250_SLEEP_EN		BIT(6)
48 
49 
50 #ifdef CONFIG_MPU9250_MAGN_EN
51 #define MPU9250_READ_BUF_SIZE 11
52 #else
53 #define MPU9250_READ_BUF_SIZE 7
54 #endif
55 
56 
57 /* see "Accelerometer Measurements" section from register map description */
mpu9250_convert_accel(struct sensor_value * val,int16_t raw_val,uint16_t sensitivity_shift)58 static void mpu9250_convert_accel(struct sensor_value *val, int16_t raw_val,
59 				  uint16_t sensitivity_shift)
60 {
61 	int64_t conv_val;
62 
63 	conv_val = ((int64_t)raw_val * SENSOR_G) >> sensitivity_shift;
64 	val->val1 = conv_val / 1000000;
65 	val->val2 = conv_val % 1000000;
66 }
67 
68 /* see "Gyroscope Measurements" section from register map description */
mpu9250_convert_gyro(struct sensor_value * val,int16_t raw_val,uint16_t sensitivity_x10)69 static void mpu9250_convert_gyro(struct sensor_value *val, int16_t raw_val,
70 				 uint16_t sensitivity_x10)
71 {
72 	int64_t conv_val;
73 
74 	conv_val = ((int64_t)raw_val * SENSOR_PI * 10) /
75 		   (sensitivity_x10 * 180U);
76 	val->val1 = conv_val / 1000000;
77 	val->val2 = conv_val % 1000000;
78 }
79 
80 /* see "Temperature Measurement" section from register map description */
mpu9250_convert_temp(struct sensor_value * val,int16_t raw_val)81 static inline void mpu9250_convert_temp(struct sensor_value *val,
82 					int16_t raw_val)
83 {
84 	/* Temp[*C] = (raw / sensitivity) + offset */
85 	val->val1 = (raw_val / MPU0259_TEMP_SENSITIVITY) + MPU9250_TEMP_OFFSET;
86 	val->val2 = (((int64_t)(raw_val % MPU0259_TEMP_SENSITIVITY) * 1000000)
87 				/ MPU0259_TEMP_SENSITIVITY);
88 
89 	if (val->val2 < 0) {
90 		val->val1--;
91 		val->val2 += 1000000;
92 	} else if (val->val2 >= 1000000) {
93 		val->val1++;
94 		val->val2 -= 1000000;
95 	}
96 }
97 
mpu9250_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)98 static int mpu9250_channel_get(const struct device *dev,
99 			       enum sensor_channel chan,
100 			       struct sensor_value *val)
101 {
102 	struct mpu9250_data *drv_data = dev->data;
103 #ifdef CONFIG_MPU9250_MAGN_EN
104 	int ret;
105 #endif
106 
107 	switch (chan) {
108 	case SENSOR_CHAN_ACCEL_XYZ:
109 		mpu9250_convert_accel(val, drv_data->accel_x,
110 				      drv_data->accel_sensitivity_shift);
111 		mpu9250_convert_accel(val + 1, drv_data->accel_y,
112 				      drv_data->accel_sensitivity_shift);
113 		mpu9250_convert_accel(val + 2, drv_data->accel_z,
114 				      drv_data->accel_sensitivity_shift);
115 		break;
116 	case SENSOR_CHAN_ACCEL_X:
117 		mpu9250_convert_accel(val, drv_data->accel_x,
118 				      drv_data->accel_sensitivity_shift);
119 		break;
120 	case SENSOR_CHAN_ACCEL_Y:
121 		mpu9250_convert_accel(val, drv_data->accel_y,
122 				      drv_data->accel_sensitivity_shift);
123 		break;
124 	case SENSOR_CHAN_ACCEL_Z:
125 		mpu9250_convert_accel(val, drv_data->accel_z,
126 				      drv_data->accel_sensitivity_shift);
127 		break;
128 	case SENSOR_CHAN_GYRO_XYZ:
129 		mpu9250_convert_gyro(val, drv_data->gyro_x,
130 				     drv_data->gyro_sensitivity_x10);
131 		mpu9250_convert_gyro(val + 1, drv_data->gyro_y,
132 				     drv_data->gyro_sensitivity_x10);
133 		mpu9250_convert_gyro(val + 2, drv_data->gyro_z,
134 				     drv_data->gyro_sensitivity_x10);
135 		break;
136 	case SENSOR_CHAN_GYRO_X:
137 		mpu9250_convert_gyro(val, drv_data->gyro_x,
138 				     drv_data->gyro_sensitivity_x10);
139 		break;
140 	case SENSOR_CHAN_GYRO_Y:
141 		mpu9250_convert_gyro(val, drv_data->gyro_y,
142 				     drv_data->gyro_sensitivity_x10);
143 		break;
144 	case SENSOR_CHAN_GYRO_Z:
145 		mpu9250_convert_gyro(val, drv_data->gyro_z,
146 				     drv_data->gyro_sensitivity_x10);
147 		break;
148 #ifdef CONFIG_MPU9250_MAGN_EN
149 	case SENSOR_CHAN_MAGN_XYZ:
150 		ret = ak8963_convert_magn(val, drv_data->magn_x,
151 					  drv_data->magn_scale_x,
152 					  drv_data->magn_st2);
153 		if (ret < 0) {
154 			return ret;
155 		}
156 		ret = ak8963_convert_magn(val + 1, drv_data->magn_y,
157 					  drv_data->magn_scale_y,
158 					  drv_data->magn_st2);
159 		if (ret < 0) {
160 			return ret;
161 		}
162 		ret = ak8963_convert_magn(val + 2, drv_data->magn_z,
163 					  drv_data->magn_scale_z,
164 					  drv_data->magn_st2);
165 		return ret;
166 	case SENSOR_CHAN_MAGN_X:
167 		return ak8963_convert_magn(val, drv_data->magn_x,
168 				    drv_data->magn_scale_x,
169 				    drv_data->magn_st2);
170 	case SENSOR_CHAN_MAGN_Y:
171 		return ak8963_convert_magn(val, drv_data->magn_y,
172 				    drv_data->magn_scale_y,
173 				    drv_data->magn_st2);
174 	case SENSOR_CHAN_MAGN_Z:
175 		return ak8963_convert_magn(val, drv_data->magn_z,
176 				    drv_data->magn_scale_z,
177 				    drv_data->magn_st2);
178 	case SENSOR_CHAN_DIE_TEMP:
179 		mpu9250_convert_temp(val, drv_data->temp);
180 		break;
181 #endif
182 	default:
183 		return -ENOTSUP;
184 	}
185 
186 	return 0;
187 }
188 
mpu9250_sample_fetch(const struct device * dev,enum sensor_channel chan)189 static int mpu9250_sample_fetch(const struct device *dev,
190 				enum sensor_channel chan)
191 {
192 	struct mpu9250_data *drv_data = dev->data;
193 	const struct mpu9250_config *cfg = dev->config;
194 	int16_t buf[MPU9250_READ_BUF_SIZE];
195 	int ret;
196 
197 	ret = i2c_burst_read_dt(&cfg->i2c,
198 				MPU9250_REG_DATA_START, (uint8_t *)buf,
199 				sizeof(buf));
200 	if (ret < 0) {
201 		LOG_ERR("Failed to read data sample.");
202 		return ret;
203 	}
204 
205 	drv_data->accel_x = sys_be16_to_cpu(buf[0]);
206 	drv_data->accel_y = sys_be16_to_cpu(buf[1]);
207 	drv_data->accel_z = sys_be16_to_cpu(buf[2]);
208 	drv_data->temp = sys_be16_to_cpu(buf[3]);
209 	drv_data->gyro_x = sys_be16_to_cpu(buf[4]);
210 	drv_data->gyro_y = sys_be16_to_cpu(buf[5]);
211 	drv_data->gyro_z = sys_be16_to_cpu(buf[6]);
212 #ifdef CONFIG_MPU9250_MAGN_EN
213 	drv_data->magn_x = sys_le16_to_cpu(buf[7]);
214 	drv_data->magn_y = sys_le16_to_cpu(buf[8]);
215 	drv_data->magn_z = sys_le16_to_cpu(buf[9]);
216 	drv_data->magn_st2 = ((uint8_t *)buf)[20];
217 	LOG_DBG("magn_st2: %u", drv_data->magn_st2);
218 #endif
219 
220 	return 0;
221 }
222 
223 static DEVICE_API(sensor, mpu9250_driver_api) = {
224 #if CONFIG_MPU9250_TRIGGER
225 	.trigger_set = mpu9250_trigger_set,
226 #endif
227 	.sample_fetch = mpu9250_sample_fetch,
228 	.channel_get = mpu9250_channel_get,
229 };
230 
231 /* measured in degrees/sec x10 to avoid floating point */
232 static const uint16_t mpu9250_gyro_sensitivity_x10[] = {
233 	1310, 655, 328, 164
234 };
235 
mpu9250_init(const struct device * dev)236 static int mpu9250_init(const struct device *dev)
237 {
238 	struct mpu9250_data *drv_data = dev->data;
239 	const struct mpu9250_config *cfg = dev->config;
240 	uint8_t id;
241 	int ret;
242 
243 	if (!device_is_ready(cfg->i2c.bus)) {
244 		LOG_ERR("I2C dev %s not ready", cfg->i2c.bus->name);
245 		return -ENODEV;
246 	}
247 
248 	/* check chip ID */
249 	ret = i2c_reg_read_byte_dt(&cfg->i2c, MPU9250_REG_CHIP_ID, &id);
250 	if (ret < 0) {
251 		LOG_ERR("Failed to read chip ID.");
252 		return ret;
253 	}
254 
255 	if (id != MPU9250_CHIP_ID) {
256 		LOG_ERR("Invalid chip ID.");
257 		return -ENOTSUP;
258 	}
259 
260 	/* wake up chip */
261 	ret = i2c_reg_update_byte_dt(&cfg->i2c,
262 				     MPU9250_REG_PWR_MGMT1,
263 				     MPU9250_SLEEP_EN, 0);
264 	if (ret < 0) {
265 		LOG_ERR("Failed to wake up chip.");
266 		return ret;
267 	}
268 
269 	if (cfg->accel_fs > MPU9250_ACCEL_FS_MAX) {
270 		LOG_ERR("Accel FS is too big: %d", cfg->accel_fs);
271 		return -EINVAL;
272 	}
273 
274 	ret = i2c_reg_write_byte_dt(&cfg->i2c, MPU9250_REG_ACCEL_CFG,
275 				    cfg->accel_fs << MPU9250_ACCEL_FS_SHIFT);
276 	if (ret < 0) {
277 		LOG_ERR("Failed to write accel full-scale range.");
278 		return ret;
279 	}
280 	drv_data->accel_sensitivity_shift = 14 - cfg->accel_fs;
281 
282 	if (cfg->gyro_fs > MPU9250_GYRO_FS_MAX) {
283 		LOG_ERR("Gyro FS is too big: %d", cfg->gyro_fs);
284 		return -EINVAL;
285 	}
286 
287 	ret = i2c_reg_write_byte_dt(&cfg->i2c, MPU9250_REG_GYRO_CFG,
288 				    cfg->gyro_fs << MPU9250_GYRO_FS_SHIFT);
289 	if (ret < 0) {
290 		LOG_ERR("Failed to write gyro full-scale range.");
291 		return ret;
292 	}
293 
294 	if (cfg->gyro_dlpf > MPU9250_GYRO_DLPF_MAX) {
295 		LOG_ERR("Gyro DLPF is too big: %d", cfg->gyro_dlpf);
296 		return -EINVAL;
297 	}
298 
299 	ret = i2c_reg_write_byte_dt(&cfg->i2c, MPU9250_REG_CONFIG,
300 				    cfg->gyro_dlpf);
301 	if (ret < 0) {
302 		LOG_ERR("Failed to write gyro digital LPF settings.");
303 		return ret;
304 	}
305 
306 	if (cfg->accel_dlpf > MPU9250_ACCEL_DLPF_MAX) {
307 		LOG_ERR("Accel DLPF is too big: %d", cfg->accel_dlpf);
308 		return -EINVAL;
309 	}
310 
311 	ret = i2c_reg_write_byte_dt(&cfg->i2c, MPU9250_REG_ACCEL_CFG2,
312 				    cfg->accel_dlpf);
313 	if (ret < 0) {
314 		LOG_ERR("Failed to write accel digital LPF settings.");
315 		return ret;
316 	}
317 
318 	ret = i2c_reg_write_byte_dt(&cfg->i2c, MPU9250_REG_SR_DIV,
319 				    cfg->gyro_sr_div);
320 	if (ret < 0) {
321 		LOG_ERR("Failed to write gyro ODR divider.");
322 		return ret;
323 	}
324 
325 	drv_data->gyro_sensitivity_x10 =
326 				mpu9250_gyro_sensitivity_x10[cfg->gyro_fs];
327 
328 #ifdef CONFIG_MPU9250_MAGN_EN
329 	ret = ak8963_init(dev);
330 	if (ret < 0) {
331 		LOG_ERR("Failed to initialize AK8963.");
332 		return ret;
333 	}
334 #endif
335 
336 #ifdef CONFIG_MPU9250_TRIGGER
337 	ret = mpu9250_init_interrupt(dev);
338 	if (ret < 0) {
339 		LOG_ERR("Failed to initialize interrupts.");
340 		return ret;
341 	}
342 #endif
343 
344 	return 0;
345 }
346 
347 
348 #define INIT_MPU9250_INST(inst)						\
349 	static struct mpu9250_data mpu9250_data_##inst;			\
350 	static const struct mpu9250_config mpu9250_cfg_##inst = {	\
351 	.i2c = I2C_DT_SPEC_INST_GET(inst),				\
352 	.gyro_sr_div = DT_INST_PROP(inst, gyro_sr_div),			\
353 	.gyro_dlpf = DT_INST_ENUM_IDX(inst, gyro_dlpf),			\
354 	.gyro_fs = DT_INST_ENUM_IDX(inst, gyro_fs),			\
355 	.accel_fs = DT_INST_ENUM_IDX(inst, accel_fs),			\
356 	.accel_dlpf = DT_INST_ENUM_IDX(inst, accel_dlpf),		\
357 	IF_ENABLED(CONFIG_MPU9250_TRIGGER,				\
358 		  (.int_pin = GPIO_DT_SPEC_INST_GET(inst, irq_gpios)))	\
359 	};								\
360 									\
361 	SENSOR_DEVICE_DT_INST_DEFINE(inst, mpu9250_init, NULL,		\
362 			      &mpu9250_data_##inst, &mpu9250_cfg_##inst,\
363 			      POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY,	\
364 			      &mpu9250_driver_api);
365 
366 DT_INST_FOREACH_STATUS_OKAY(INIT_MPU9250_INST)
367