1 /*
2  * Copyright (c) 2024 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/drivers/sensor.h>
9 #include <zephyr/init.h>
10 #include <zephyr/drivers/gpio.h>
11 #include <zephyr/pm/device.h>
12 #include <zephyr/sys/byteorder.h>
13 #include <zephyr/sys/__assert.h>
14 #include <zephyr/logging/log.h>
15 #include <math.h>
16 
17 #include "mmc56x3.h"
18 
19 LOG_MODULE_REGISTER(MMC56X3, CONFIG_SENSOR_LOG_LEVEL);
20 
21 K_TIMER_DEFINE(meas_req_timer, NULL, NULL);
22 
23 #if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0
24 #warning "MMC56X3 driver enabled without any devices"
25 #endif
26 
mmc56x3_bus_check(const struct device * dev)27 static inline int mmc56x3_bus_check(const struct device *dev)
28 {
29 	const struct mmc56x3_dev_config *config = dev->config;
30 
31 	return config->bus_io->check(&config->bus);
32 }
33 
mmc56x3_reg_read(const struct device * dev,uint8_t reg,uint8_t * buf,int size)34 static inline int mmc56x3_reg_read(const struct device *dev, uint8_t reg, uint8_t *buf, int size)
35 {
36 	const struct mmc56x3_dev_config *config = dev->config;
37 
38 	return config->bus_io->read(&config->bus, reg, buf, size);
39 }
40 
mmc56x3_reg_write(const struct device * dev,uint8_t reg,uint8_t val)41 static inline int mmc56x3_reg_write(const struct device *dev, uint8_t reg, uint8_t val)
42 {
43 	const struct mmc56x3_dev_config *config = dev->config;
44 
45 	return config->bus_io->write(&config->bus, reg, val);
46 }
47 
mmc56x3_raw_read(const struct device * dev,uint8_t * buf,int size)48 static inline int mmc56x3_raw_read(const struct device *dev, uint8_t *buf, int size)
49 {
50 	const struct mmc56x3_dev_config *config = dev->config;
51 
52 	return config->bus_io->raw_read(&config->bus, buf, size);
53 }
54 
mmc56x3_raw_write(const struct device * dev,uint8_t * buf,int size)55 static inline int mmc56x3_raw_write(const struct device *dev, uint8_t *buf, int size)
56 {
57 	const struct mmc56x3_dev_config *config = dev->config;
58 
59 	return config->bus_io->raw_write(&config->bus, buf, size);
60 }
61 
mmc56x3_chip_set_auto_self_reset(const struct device * dev,bool auto_sr)62 static int mmc56x3_chip_set_auto_self_reset(const struct device *dev, bool auto_sr)
63 {
64 	struct mmc56x3_data *data = dev->data;
65 	struct mmc56x3_config *config = &data->config;
66 
67 	if (auto_sr) {
68 		data->ctrl0_cache |= MMC56X3_CMD_AUTO_SELF_RESET_EN;
69 	} else {
70 		data->ctrl0_cache &= ~MMC56X3_CMD_AUTO_SELF_RESET_EN;
71 	}
72 
73 	int ret = mmc56x3_reg_write(dev, MMC56X3_REG_INTERNAL_CTRL_0, data->ctrl0_cache);
74 
75 	if (ret < 0) {
76 		LOG_DBG("Setting auto_sr_en bit failed: %d", ret);
77 	} else {
78 		config->auto_sr = auto_sr;
79 	}
80 
81 	return ret;
82 }
83 
84 /* Set ODR to 0 to turn off */
mmc56x3_chip_set_continuous_mode(const struct device * dev,uint16_t odr)85 static int mmc56x3_chip_set_continuous_mode(const struct device *dev, uint16_t odr)
86 {
87 	struct mmc56x3_data *data = dev->data;
88 	struct mmc56x3_config *config = &data->config;
89 	int ret;
90 
91 	if (odr > 255) {
92 		odr = 1000;
93 		data->ctrl2_cache |= MMC56X3_CMD_HPOWER;
94 		ret = mmc56x3_reg_write(dev, MMC56X3_REG_INTERNAL_ODR, 255);
95 	} else {
96 		ret  = mmc56x3_reg_write(dev, MMC56X3_REG_INTERNAL_ODR, (uint8_t) odr);
97 	}
98 
99 	if (ret < 0) {
100 		LOG_DBG("Setting ODR failed: %d", ret);
101 	} else {
102 		config->magn_odr = odr;
103 	}
104 
105 	if (odr > 0) {
106 		data->ctrl0_cache |= MMC56X3_CMD_CMM_FREQ_EN;
107 		data->ctrl2_cache |= MMC56X3_CMD_CMM_EN;
108 	} else {
109 		data->ctrl0_cache &= ~MMC56X3_CMD_CMM_FREQ_EN;
110 		data->ctrl2_cache &= ~MMC56X3_CMD_CMM_EN;
111 	}
112 
113 	ret = mmc56x3_reg_write(dev, MMC56X3_REG_INTERNAL_CTRL_0, data->ctrl0_cache);
114 	if (ret < 0) {
115 		LOG_DBG("Setting cmm_freq_en bit failed: %d", ret);
116 	}
117 
118 	ret = mmc56x3_reg_write(dev, MMC56X3_REG_INTERNAL_CTRL_2, data->ctrl2_cache);
119 	if (ret < 0) {
120 		LOG_DBG("Setting cmm_en bit failed: %d", ret);
121 	}
122 
123 	/* Wait required to get readings normally afterwards */
124 	k_sleep(K_MSEC(10));
125 
126 	return ret;
127 }
128 
mmc56x3_is_continuous_mode(const struct device * dev)129 static bool mmc56x3_is_continuous_mode(const struct device *dev)
130 {
131 	struct mmc56x3_data *data = dev->data;
132 
133 	return data->ctrl2_cache & MMC56X3_CMD_CMM_EN;
134 }
135 
mmc56x3_chip_set_decimation_filter(const struct device * dev,bool bw0,bool bw1)136 int mmc56x3_chip_set_decimation_filter(const struct device *dev, bool bw0, bool bw1)
137 {
138 	struct mmc56x3_data *data = dev->data;
139 	struct mmc56x3_config *config = &data->config;
140 
141 	data->ctrl1_cache |= (bw0 ? BIT(0) : 0);
142 	data->ctrl1_cache |= (bw1 ? BIT(1) : 0);
143 
144 	config->bw0 = bw0;
145 	config->bw1 = bw1;
146 
147 	return mmc56x3_reg_write(dev, MMC56X3_REG_INTERNAL_CTRL_1, data->ctrl1_cache);
148 }
149 
mmc56x3_chip_init(const struct device * dev)150 static int mmc56x3_chip_init(const struct device *dev)
151 {
152 	int ret;
153 	uint8_t chip_id;
154 
155 	ret = mmc56x3_bus_check(dev);
156 	if (ret < 0) {
157 		LOG_DBG("bus check failed: %d", ret);
158 		return ret;
159 	}
160 
161 	ret = mmc56x3_reg_read(dev, MMC56X3_REG_ID, &chip_id, 1);
162 	if (ret < 0) {
163 		LOG_DBG("ID read failed: %d", ret);
164 		return ret;
165 	}
166 
167 	if (chip_id == MMC56X3_CHIP_ID) {
168 		LOG_DBG("ID OK");
169 	} else {
170 		LOG_DBG("bad chip id 0x%x", chip_id);
171 		return -ENOTSUP;
172 	}
173 
174 	ret = mmc56x3_reg_write(dev, MMC56X3_REG_INTERNAL_CTRL_1, MMC56X3_CMD_SW_RESET);
175 	if (ret < 0) {
176 		LOG_DBG("SW reset failed: %d", ret);
177 	}
178 
179 	k_sleep(K_MSEC(20));
180 
181 	ret = mmc56x3_reg_write(dev, MMC56X3_REG_INTERNAL_CTRL_0, MMC56X3_CMD_SET);
182 	if (ret < 0) {
183 		LOG_DBG("Magnetic set failed: %d", ret);
184 	}
185 
186 	k_sleep(K_MSEC(1));
187 
188 	ret = mmc56x3_reg_write(dev, MMC56X3_REG_INTERNAL_CTRL_0, MMC56X3_CMD_RESET);
189 	if (ret < 0) {
190 		LOG_DBG("Magnetic reset failed: %d", ret);
191 	}
192 
193 	k_sleep(K_MSEC(1));
194 
195 	struct mmc56x3_data *data = dev->data;
196 	const struct mmc56x3_config *config = &data->config;
197 
198 	ret = mmc56x3_chip_set_continuous_mode(dev, config->magn_odr);
199 
200 	ret = mmc56x3_chip_set_decimation_filter(dev, config->bw0, config->bw1);
201 
202 	ret = mmc56x3_chip_set_auto_self_reset(dev, config->auto_sr);
203 
204 	if (ret < 0) {
205 		return ret;
206 	}
207 
208 	return 0;
209 }
210 
mmc56x3_wait_until_ready(const struct device * dev)211 static int mmc56x3_wait_until_ready(const struct device *dev)
212 {
213 	uint8_t status = 0;
214 	int ret;
215 
216 	/* Wait for measurement to be completed */
217 	do {
218 		k_sleep(K_MSEC(3));
219 		ret = mmc56x3_reg_read(dev, MMC56X3_REG_STATUS, &status, 1);
220 		if (ret < 0) {
221 			return ret;
222 		}
223 	} while ((status & 0xC0) != (MMC56X3_STATUS_MEAS_M_DONE | MMC56X3_STATUS_MEAS_T_DONE));
224 
225 	return 0;
226 }
227 
mmc56x3_sample_fetch_helper(const struct device * dev,enum sensor_channel chan,struct mmc56x3_data * data)228 int mmc56x3_sample_fetch_helper(const struct device *dev, enum sensor_channel chan,
229 				struct mmc56x3_data *data)
230 {
231 	int32_t raw_magn_x, raw_magn_y, raw_magn_z;
232 	int ret;
233 
234 	if (!mmc56x3_is_continuous_mode(dev)) {
235 		/* Temperature cannot be read in continuous mode */
236 		uint8_t raw_temp;
237 
238 		ret = mmc56x3_reg_write(dev, MMC56X3_REG_INTERNAL_CTRL_0, MMC56X3_CMD_TAKE_MEAS_T);
239 		if (ret < 0) {
240 			return ret;
241 		}
242 
243 		k_timer_start(&meas_req_timer, K_MSEC(10), K_NO_WAIT);
244 		k_timer_status_sync(&meas_req_timer);
245 
246 		ret = mmc56x3_reg_write(dev, MMC56X3_REG_INTERNAL_CTRL_0, MMC56X3_CMD_TAKE_MEAS_M);
247 		if (ret < 0) {
248 			return ret;
249 		}
250 
251 		ret = mmc56x3_wait_until_ready(dev);
252 		if (ret < 0) {
253 			return ret;
254 		}
255 
256 		ret = mmc56x3_reg_read(dev, MMC56X3_REG_TEMP, &raw_temp, 1);
257 		if (ret < 0) {
258 			return ret;
259 		}
260 		data->temp = raw_temp;
261 	}
262 
263 	uint8_t sig = MMC56X3_REG_MAGN_X_OUT_0;
264 
265 	ret = mmc56x3_raw_write(dev, &sig, 1);
266 	if (ret < 0) {
267 		return ret;
268 	}
269 
270 	uint8_t buf[9];
271 
272 	ret = mmc56x3_raw_read(dev, buf, 9);
273 	if (ret < 0) {
274 		return ret;
275 	}
276 
277 	/* 20-bit precision default */
278 	raw_magn_x = (uint32_t)buf[0] << 12 | (uint32_t)buf[1] << 4 | (uint32_t)buf[6] >> 4;
279 	raw_magn_x -= (uint32_t)1 << 19;
280 	data->magn_x = raw_magn_x;
281 
282 	raw_magn_y = (uint32_t)buf[2] << 12 | (uint32_t)buf[3] << 4 | (uint32_t)buf[7] >> 4;
283 	raw_magn_y -= (uint32_t)1 << 19;
284 	data->magn_y = raw_magn_y;
285 
286 	raw_magn_z = (uint32_t)buf[4] << 12 | (uint32_t)buf[5] << 4 | (uint32_t)buf[8] >> 4;
287 	raw_magn_z -= (uint32_t)1 << 19;
288 	data->magn_z = raw_magn_z;
289 
290 	return 0;
291 }
292 
mmc56x3_sample_fetch(const struct device * dev,enum sensor_channel chan)293 int mmc56x3_sample_fetch(const struct device *dev, enum sensor_channel chan)
294 {
295 	struct mmc56x3_data *data = dev->data;
296 
297 	return mmc56x3_sample_fetch_helper(dev, chan, data);
298 }
299 
convert_double_to_sensor_val(double d,struct sensor_value * val)300 static void convert_double_to_sensor_val(double d, struct sensor_value *val)
301 {
302 	val->val1 = (int32_t)d;
303 	int32_t precision = 1000000;
304 
305 	val->val2 = ((int32_t)(d * precision)) - (val->val1 * precision);
306 }
307 
mmc56x3_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)308 static int mmc56x3_channel_get(const struct device *dev, enum sensor_channel chan,
309 			       struct sensor_value *val)
310 {
311 	struct mmc56x3_data *data = dev->data;
312 
313 	switch (chan) {
314 	case SENSOR_CHAN_AMBIENT_TEMP:
315 		convert_double_to_sensor_val(MMC56X3_TEMP_BASE + (data->temp * MMC56X3_TEMP_RES),
316 					     val);
317 		break;
318 	case SENSOR_CHAN_MAGN_X:
319 		convert_double_to_sensor_val(data->magn_x * MMC56X3_MAGN_GAUSS_RES, val);
320 		break;
321 	case SENSOR_CHAN_MAGN_Y:
322 		convert_double_to_sensor_val(data->magn_y * MMC56X3_MAGN_GAUSS_RES, val);
323 		break;
324 	case SENSOR_CHAN_MAGN_Z:
325 		convert_double_to_sensor_val(data->magn_z * MMC56X3_MAGN_GAUSS_RES, val);
326 		break;
327 	case SENSOR_CHAN_MAGN_XYZ:
328 		convert_double_to_sensor_val(data->magn_x * MMC56X3_MAGN_GAUSS_RES, val);
329 		convert_double_to_sensor_val(data->magn_y * MMC56X3_MAGN_GAUSS_RES, val + 1);
330 		convert_double_to_sensor_val(data->magn_z * MMC56X3_MAGN_GAUSS_RES, val + 2);
331 		break;
332 	default:
333 		return -ENOTSUP;
334 	}
335 
336 	return 0;
337 }
338 
mmc56x3_chip_configure(const struct device * dev,struct mmc56x3_config * new_config)339 static int mmc56x3_chip_configure(const struct device *dev, struct mmc56x3_config *new_config)
340 {
341 	struct mmc56x3_data *data = dev->data;
342 	struct mmc56x3_config *config = &data->config;
343 
344 	int ret = 0;
345 
346 	if (new_config->magn_odr != config->magn_odr) {
347 		ret = mmc56x3_chip_set_continuous_mode(dev, new_config->magn_odr);
348 	}
349 
350 	if ((new_config->bw0 != config->bw0) || (new_config->bw1 != config->bw1)) {
351 		ret = mmc56x3_chip_set_decimation_filter(dev, new_config->bw0, new_config->bw1);
352 	}
353 
354 	if (new_config->auto_sr != config->auto_sr) {
355 		ret = mmc56x3_chip_set_auto_self_reset(dev, config->auto_sr);
356 	}
357 
358 	return ret;
359 }
360 
mmc56x3_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)361 static int mmc56x3_attr_set(const struct device *dev, enum sensor_channel chan,
362 			    enum sensor_attribute attr, const struct sensor_value *val)
363 {
364 	struct mmc56x3_config new_config = {};
365 	int ret = 0;
366 
367 	__ASSERT_NO_MSG(val != NULL);
368 
369 	switch (chan) {
370 	case SENSOR_CHAN_MAGN_X:
371 	case SENSOR_CHAN_MAGN_Y:
372 	case SENSOR_CHAN_MAGN_Z:
373 	case SENSOR_CHAN_MAGN_XYZ:
374 		if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) {
375 			new_config.magn_odr = val->val1;
376 		} else if ((enum sensor_attribute_mmc56x3)attr ==
377 			   SENSOR_ATTR_BANDWIDTH_SELECTION_BITS_0) {
378 			new_config.bw0 = val->val1 ? true : false;
379 		} else if ((enum sensor_attribute_mmc56x3)attr ==
380 			   SENSOR_ATTR_BANDWIDTH_SELECTION_BITS_1) {
381 			new_config.bw1 = val->val1 ? true : false;
382 		} else if ((enum sensor_attribute_mmc56x3)attr ==
383 			   SENSOR_ATTR_AUTOMATIC_SELF_RESET) {
384 			new_config.auto_sr = val->val1 ? true : false;
385 		} else {
386 			LOG_ERR("Unsupported attribute");
387 			ret = -ENOTSUP;
388 		}
389 		break;
390 	default:
391 		LOG_ERR("Unsupported channel");
392 		ret = -EINVAL;
393 		break;
394 	}
395 
396 	if (ret) {
397 		return ret;
398 	}
399 
400 	return mmc56x3_chip_configure(dev, &new_config);
401 }
402 
mmc56x3_attr_get(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,struct sensor_value * val)403 static int mmc56x3_attr_get(const struct device *dev, enum sensor_channel chan,
404 			    enum sensor_attribute attr, struct sensor_value *val)
405 {
406 	struct mmc56x3_data *data = dev->data;
407 	struct mmc56x3_config *config = &data->config;
408 	int ret = 0;
409 
410 	__ASSERT_NO_MSG(val != NULL);
411 
412 	switch (chan) {
413 	case SENSOR_CHAN_MAGN_X:
414 	case SENSOR_CHAN_MAGN_Y:
415 	case SENSOR_CHAN_MAGN_Z:
416 	case SENSOR_CHAN_MAGN_XYZ:
417 		if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) {
418 			val->val1 = config->magn_odr;
419 		} else if ((enum sensor_attribute_mmc56x3)attr ==
420 			   SENSOR_ATTR_BANDWIDTH_SELECTION_BITS_0) {
421 			val->val1 = config->bw0;
422 		} else if ((enum sensor_attribute_mmc56x3)attr ==
423 			   SENSOR_ATTR_BANDWIDTH_SELECTION_BITS_1) {
424 			val->val1 = config->bw1;
425 		} else if ((enum sensor_attribute_mmc56x3)attr ==
426 			   SENSOR_ATTR_AUTOMATIC_SELF_RESET) {
427 			val->val1 = config->auto_sr;
428 		} else {
429 			LOG_ERR("Unsupported attribute");
430 			ret = -ENOTSUP;
431 		}
432 		break;
433 	default:
434 		LOG_ERR("Unsupported channel");
435 		ret = -EINVAL;
436 		break;
437 	}
438 
439 	return ret;
440 }
441 
442 static DEVICE_API(sensor, mmc56x3_api_funcs) = {
443 	.sample_fetch = mmc56x3_sample_fetch,
444 	.channel_get = mmc56x3_channel_get,
445 	.attr_get = mmc56x3_attr_get,
446 	.attr_set = mmc56x3_attr_set,
447 #ifdef CONFIG_SENSOR_ASYNC_API
448 	.submit = mmc56x3_submit,
449 	.get_decoder = mmc56x3_get_decoder,
450 #endif
451 };
452 
453 #define MMC56X3_DT_DEV_CONFIG_INIT(inst)                                                           \
454 	{                                                                                          \
455 		.bus.i2c = I2C_DT_SPEC_INST_GET(inst),                                             \
456 		.bus_io = &mmc56x3_bus_io_i2c,                                                     \
457 	}
458 
459 #define MMC56X3_DT_DATA_CONFIG_INIT(inst)                                                          \
460 	{                                                                                          \
461 		.magn_odr = DT_INST_PROP(inst, magn_odr),                                          \
462 		.bw0 = DT_INST_PROP(inst, bandwidth_selection_bits_0),                             \
463 		.bw1 = DT_INST_PROP(inst, bandwidth_selection_bits_1),                             \
464 		.auto_sr = DT_INST_PROP(inst, auto_self_reset),                                    \
465 	}
466 
467 #define MMC56X3_DATA_INIT(inst)                                                                    \
468 	static struct mmc56x3_data mmc56x3_data_##inst = {                                         \
469 		.config = MMC56X3_DT_DATA_CONFIG_INIT(inst),                                       \
470 	};
471 
472 #define MMC56X3_DEFINE(inst)                                                                       \
473 	MMC56X3_DATA_INIT(inst);                                                                   \
474 	const static struct mmc56x3_dev_config mmc56x3_dev_config_##inst =  \
475 		MMC56X3_DT_DEV_CONFIG_INIT(inst);                                                  \
476 	SENSOR_DEVICE_DT_INST_DEFINE(inst, mmc56x3_chip_init, NULL, &mmc56x3_data_##inst,          \
477 				     &mmc56x3_dev_config_##inst, POST_KERNEL,                      \
478 				     CONFIG_SENSOR_INIT_PRIORITY, &mmc56x3_api_funcs);
479 
480 /* Create the struct device for every status "okay" node in the devicetree. */
481 DT_INST_FOREACH_STATUS_OKAY(MMC56X3_DEFINE)
482