1 /*
2  * Copyright (c) 2022, Felipe Neves
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT ams_as5600
8 
9 #include <errno.h>
10 #include <zephyr/sys/__assert.h>
11 #include <zephyr/sys/util.h>
12 #include <zephyr/device.h>
13 #include <zephyr/init.h>
14 #include <zephyr/drivers/sensor.h>
15 #include <zephyr/drivers/i2c.h>
16 #include <zephyr/logging/log.h>
17 LOG_MODULE_REGISTER(ams_as5600, CONFIG_SENSOR_LOG_LEVEL);
18 
19 #define AS5600_ANGLE_REGISTER_H 0x0E
20 #define AS5600_FULL_ANGLE		360
21 #define AS5600_PULSES_PER_REV	4096
22 #define AS5600_MILLION_UNIT	1000000
23 
24 struct as5600_dev_cfg {
25 	struct i2c_dt_spec i2c_port;
26 };
27 
28 /* Device run time data */
29 struct as5600_dev_data {
30 	uint16_t position;
31 };
32 
as5600_fetch(const struct device * dev,enum sensor_channel chan)33 static int as5600_fetch(const struct device *dev, enum sensor_channel chan)
34 {
35 	struct as5600_dev_data *dev_data = dev->data;
36 	const struct as5600_dev_cfg *dev_cfg = dev->config;
37 
38 	uint8_t read_data[2] = {0, 0};
39 	uint8_t angle_reg = AS5600_ANGLE_REGISTER_H;
40 
41 	int err = i2c_write_read_dt(&dev_cfg->i2c_port,
42 						&angle_reg,
43 						1,
44 						&read_data,
45 						sizeof(read_data));
46 
47 	/* invalid readings preserves the last good value */
48 	if (!err) {
49 		dev_data->position = ((uint16_t)read_data[0] << 8) | read_data[1];
50 	}
51 
52 	return err;
53 }
54 
as5600_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)55 static int as5600_get(const struct device *dev, enum sensor_channel chan,
56 			struct sensor_value *val)
57 {
58 	struct as5600_dev_data *dev_data = dev->data;
59 
60 	if (chan == SENSOR_CHAN_ROTATION) {
61 		val->val1 = ((int32_t)dev_data->position * AS5600_FULL_ANGLE) /
62 							AS5600_PULSES_PER_REV;
63 
64 		val->val2 = (((int32_t)dev_data->position * AS5600_FULL_ANGLE) %
65 			     AS5600_PULSES_PER_REV) * (AS5600_MILLION_UNIT / AS5600_PULSES_PER_REV);
66 	} else {
67 		return -ENOTSUP;
68 	}
69 
70 	return 0;
71 }
72 
as5600_initialize(const struct device * dev)73 static int as5600_initialize(const struct device *dev)
74 {
75 	struct as5600_dev_data *const dev_data = dev->data;
76 
77 	dev_data->position = 0;
78 
79 	LOG_INF("Device %s initialized", dev->name);
80 
81 	return 0;
82 }
83 
84 static DEVICE_API(sensor, as5600_driver_api) = {
85 	.sample_fetch = as5600_fetch,
86 	.channel_get = as5600_get,
87 };
88 
89 #define AS5600_INIT(n)						\
90 	static struct as5600_dev_data as5600_data##n;		\
91 	static const struct as5600_dev_cfg as5600_cfg##n = {\
92 		.i2c_port = I2C_DT_SPEC_INST_GET(n)	\
93 	};	\
94 									\
95 	SENSOR_DEVICE_DT_INST_DEFINE(n, as5600_initialize, NULL,	\
96 			    &as5600_data##n, &as5600_cfg##n, \
97 			    POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY,	\
98 			    &as5600_driver_api);
99 
100 DT_INST_FOREACH_STATUS_OKAY(AS5600_INIT)
101