/* * Copyright (c) 2024 SILA Embedded Solutions GmbH * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT maxim_max31790_fan_speed #include #include #include #include #include "max31790_fan_speed.h" #define FACTOR_RPM_TO_HZ 60 #define TACH_COUNT_FREQUENCY (MAX31790_OSCILLATOR_FREQUENCY_IN_HZ / 4) #define TACH_COUNTS_PER_REVOLUTION 2 LOG_MODULE_REGISTER(MAX31790_FAN_SPEED, CONFIG_SENSOR_LOG_LEVEL); static int max31790_fan_speed_sample_fetch(const struct device *dev, enum sensor_channel chan) { const struct max31790_fan_speed_config *config = dev->config; struct max31790_fan_speed_data *data = dev->data; uint16_t tach_count; uint8_t fan_dynamics; uint8_t number_tach_periods_counted; uint8_t speed_range; uint8_t register_address; int result; __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL); register_address = MAX37190_REGISTER_TACHCOUNTMSB(config->channel_id); result = i2c_write_read_dt(&config->i2c, ®ister_address, sizeof(register_address), &tach_count, sizeof(tach_count)); tach_count = sys_be16_to_cpu(tach_count); if (result != 0) { return result; } result = i2c_reg_read_byte_dt( &config->i2c, MAX31790_REGISTER_FANDYNAMICS(config->channel_id), &fan_dynamics); if (result != 0) { return result; } tach_count = tach_count >> 5; speed_range = MAX31790_FANXDYNAMCIS_SPEED_RANGE_GET(fan_dynamics); switch (speed_range) { case 0: number_tach_periods_counted = 1; break; case 1: number_tach_periods_counted = 2; break; case 2: number_tach_periods_counted = 4; break; case 3: number_tach_periods_counted = 8; break; case 4: number_tach_periods_counted = 16; break; case 5: __fallthrough; case 6: __fallthrough; case 7: number_tach_periods_counted = 32; break; default: LOG_ERR("%s: invalid speed range %i", dev->name, speed_range); return -EINVAL; } if (tach_count == 0) { LOG_WRN("%s: tach count is zero", dev->name); data->rpm = UINT16_MAX; } else { LOG_DBG("%s: %i tach periods counted, %i tach count", dev->name, number_tach_periods_counted, tach_count); data->rpm = FACTOR_RPM_TO_HZ * TACH_COUNT_FREQUENCY * number_tach_periods_counted / (tach_count * TACH_COUNTS_PER_REVOLUTION); } return 0; } static int max31790_fan_speed_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { struct max31790_fan_speed_data *data = dev->data; if (chan != SENSOR_CHAN_RPM) { LOG_ERR("%s: requesting unsupported channel %i", dev->name, chan); return -ENOTSUP; } val->val1 = data->rpm; val->val2 = 0; return 0; } static DEVICE_API(sensor, max31790_fan_speed_api) = { .sample_fetch = max31790_fan_speed_sample_fetch, .channel_get = max31790_fan_speed_channel_get, }; static int max31790_fan_speed_init(const struct device *dev) { const struct max31790_fan_speed_config *config = dev->config; if (!i2c_is_ready_dt(&config->i2c)) { LOG_ERR("I2C device not ready"); return -ENODEV; } return 0; } #define MAX31790_FAN_SPEED_INIT(inst) \ static const struct max31790_fan_speed_config max31790_fan_speed_##inst##_config = { \ .i2c = I2C_DT_SPEC_GET(DT_INST_PARENT(inst)), \ .channel_id = DT_INST_PROP(inst, channel) - 1, \ }; \ \ static struct max31790_fan_speed_data max31790_fan_speed_##inst##_data; \ \ SENSOR_DEVICE_DT_INST_DEFINE(inst, max31790_fan_speed_init, NULL, \ &max31790_fan_speed_##inst##_data, \ &max31790_fan_speed_##inst##_config, POST_KERNEL, \ CONFIG_SENSOR_INIT_PRIORITY, &max31790_fan_speed_api); DT_INST_FOREACH_STATUS_OKAY(MAX31790_FAN_SPEED_INIT);