1 /*
2 * Copyright (c) 2024 SILA Embedded Solutions GmbH
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT maxim_max31790_fan_speed
8
9 #include <zephyr/drivers/mfd/max31790.h>
10 #include <zephyr/drivers/sensor.h>
11 #include <zephyr/logging/log.h>
12 #include <zephyr/sys/byteorder.h>
13
14 #include "max31790_fan_speed.h"
15
16 #define FACTOR_RPM_TO_HZ 60
17 #define TACH_COUNT_FREQUENCY (MAX31790_OSCILLATOR_FREQUENCY_IN_HZ / 4)
18 #define TACH_COUNTS_PER_REVOLUTION 2
19
20 LOG_MODULE_REGISTER(MAX31790_FAN_SPEED, CONFIG_SENSOR_LOG_LEVEL);
21
max31790_fan_speed_sample_fetch(const struct device * dev,enum sensor_channel chan)22 static int max31790_fan_speed_sample_fetch(const struct device *dev, enum sensor_channel chan)
23 {
24 const struct max31790_fan_speed_config *config = dev->config;
25 struct max31790_fan_speed_data *data = dev->data;
26 uint16_t tach_count;
27 uint8_t fan_dynamics;
28 uint8_t number_tach_periods_counted;
29 uint8_t speed_range;
30 uint8_t register_address;
31 int result;
32
33 __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);
34
35 register_address = MAX37190_REGISTER_TACHCOUNTMSB(config->channel_id);
36 result = i2c_write_read_dt(&config->i2c, ®ister_address, sizeof(register_address),
37 &tach_count, sizeof(tach_count));
38 tach_count = sys_be16_to_cpu(tach_count);
39 if (result != 0) {
40 return result;
41 }
42
43 result = i2c_reg_read_byte_dt(
44 &config->i2c, MAX31790_REGISTER_FANDYNAMICS(config->channel_id), &fan_dynamics);
45 if (result != 0) {
46 return result;
47 }
48
49 tach_count = tach_count >> 5;
50 speed_range = MAX31790_FANXDYNAMCIS_SPEED_RANGE_GET(fan_dynamics);
51
52 switch (speed_range) {
53 case 0:
54 number_tach_periods_counted = 1;
55 break;
56 case 1:
57 number_tach_periods_counted = 2;
58 break;
59 case 2:
60 number_tach_periods_counted = 4;
61 break;
62 case 3:
63 number_tach_periods_counted = 8;
64 break;
65 case 4:
66 number_tach_periods_counted = 16;
67 break;
68 case 5:
69 __fallthrough;
70 case 6:
71 __fallthrough;
72 case 7:
73 number_tach_periods_counted = 32;
74 break;
75 default:
76 LOG_ERR("%s: invalid speed range %i", dev->name, speed_range);
77 return -EINVAL;
78 }
79
80 if (tach_count == 0) {
81 LOG_WRN("%s: tach count is zero", dev->name);
82 data->rpm = UINT16_MAX;
83 } else {
84 LOG_DBG("%s: %i tach periods counted, %i tach count", dev->name,
85 number_tach_periods_counted, tach_count);
86 data->rpm = FACTOR_RPM_TO_HZ * TACH_COUNT_FREQUENCY * number_tach_periods_counted /
87 (tach_count * TACH_COUNTS_PER_REVOLUTION);
88 }
89
90 return 0;
91 }
92
max31790_fan_speed_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)93 static int max31790_fan_speed_channel_get(const struct device *dev, enum sensor_channel chan,
94 struct sensor_value *val)
95 {
96 struct max31790_fan_speed_data *data = dev->data;
97
98 if (chan != SENSOR_CHAN_RPM) {
99 LOG_ERR("%s: requesting unsupported channel %i", dev->name, chan);
100 return -ENOTSUP;
101 }
102
103 val->val1 = data->rpm;
104 val->val2 = 0;
105 return 0;
106 }
107
108 static DEVICE_API(sensor, max31790_fan_speed_api) = {
109 .sample_fetch = max31790_fan_speed_sample_fetch,
110 .channel_get = max31790_fan_speed_channel_get,
111 };
112
max31790_fan_speed_init(const struct device * dev)113 static int max31790_fan_speed_init(const struct device *dev)
114 {
115 const struct max31790_fan_speed_config *config = dev->config;
116
117 if (!i2c_is_ready_dt(&config->i2c)) {
118 LOG_ERR("I2C device not ready");
119 return -ENODEV;
120 }
121
122 return 0;
123 }
124
125 #define MAX31790_FAN_SPEED_INIT(inst) \
126 static const struct max31790_fan_speed_config max31790_fan_speed_##inst##_config = { \
127 .i2c = I2C_DT_SPEC_GET(DT_INST_PARENT(inst)), \
128 .channel_id = DT_INST_PROP(inst, channel) - 1, \
129 }; \
130 \
131 static struct max31790_fan_speed_data max31790_fan_speed_##inst##_data; \
132 \
133 SENSOR_DEVICE_DT_INST_DEFINE(inst, max31790_fan_speed_init, NULL, \
134 &max31790_fan_speed_##inst##_data, \
135 &max31790_fan_speed_##inst##_config, POST_KERNEL, \
136 CONFIG_SENSOR_INIT_PRIORITY, &max31790_fan_speed_api);
137
138 DT_INST_FOREACH_STATUS_OKAY(MAX31790_FAN_SPEED_INIT);
139