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