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, &register_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