diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index 86f65c04ee4..d553ecd4625 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -96,6 +96,7 @@ add_subdirectory_ifdef(CONFIG_LTR_F216A ltrf216a) add_subdirectory_ifdef(CONFIG_MAX17055 max17055) add_subdirectory_ifdef(CONFIG_MAX17262 max17262) add_subdirectory_ifdef(CONFIG_MAX30101 max30101) +add_subdirectory_ifdef(CONFIG_MAX31790_SENSOR max31790) add_subdirectory_ifdef(CONFIG_MAX31855 max31855) add_subdirectory_ifdef(CONFIG_MAX31865 max31865) add_subdirectory_ifdef(CONFIG_MAX31875 max31875) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index f939950d01c..fa956332534 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -176,6 +176,7 @@ source "drivers/sensor/ltrf216a/Kconfig" source "drivers/sensor/max17055/Kconfig" source "drivers/sensor/max17262/Kconfig" source "drivers/sensor/max30101/Kconfig" +source "drivers/sensor/max31790/Kconfig" source "drivers/sensor/max31855/Kconfig" source "drivers/sensor/max31865/Kconfig" source "drivers/sensor/max31875/Kconfig" diff --git a/drivers/sensor/max31790/CMakeLists.txt b/drivers/sensor/max31790/CMakeLists.txt new file mode 100644 index 00000000000..8dfdccb564d --- /dev/null +++ b/drivers/sensor/max31790/CMakeLists.txt @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources_ifdef(CONFIG_MAX31790_FAN_SPEED max31790_fan_speed.c) +zephyr_library_sources_ifdef(CONFIG_MAX31790_FAN_FAULT max31790_fan_fault.c) diff --git a/drivers/sensor/max31790/Kconfig b/drivers/sensor/max31790/Kconfig new file mode 100644 index 00000000000..ef703e4a69c --- /dev/null +++ b/drivers/sensor/max31790/Kconfig @@ -0,0 +1,25 @@ +# Copyright (c) 2024 SILA Embedded Solutions GmbH +# SPDX-License-Identifier: Apache-2.0 + +config MAX31790_SENSOR + bool "MAX31790 sensors" + default y + depends on MAX31790_FAN_SPEED || MAX31790_FAN_FAULT + help + Enable sensors for the MAX31790 PWM controller. + +config MAX31790_FAN_SPEED + bool "MAX31790 fan speed sensor" + default y + depends on DT_HAS_MAXIM_MAX31790_FAN_SPEED_ENABLED + select MFD + help + Enable driver for the MAX31790 fan speed sensor. + +config MAX31790_FAN_FAULT + bool "MAX31790 fan fault sensor" + default y + depends on DT_HAS_MAXIM_MAX31790_FAN_FAULT_ENABLED + select MFD + help + Enable driver for the MAX31790 fan fault sensor. diff --git a/drivers/sensor/max31790/max31790_fan_fault.c b/drivers/sensor/max31790/max31790_fan_fault.c new file mode 100644 index 00000000000..ec25000a761 --- /dev/null +++ b/drivers/sensor/max31790/max31790_fan_fault.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2024 SILA Embedded Solutions GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT maxim_max31790_fan_fault + +#include +#include +#include +#include + +#include "max31790_fan_fault.h" + +LOG_MODULE_REGISTER(MAX31790_FAN_FAULT, CONFIG_SENSOR_LOG_LEVEL); + +static int max31790_fan_fault_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + const struct max31790_fan_fault_config *config = dev->config; + struct max31790_fan_fault_data *data = dev->data; + int result; + uint8_t value; + + __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL); + + result = i2c_reg_read_byte_dt(&config->i2c, MAX37190_REGISTER_FANFAULTSTATUS1, &value); + if (result != 0) { + return result; + } + + data->value = value & 0x3F; + + return 0; +} + +static int max31790_fan_fault_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct max31790_fan_fault_data *data = dev->data; + + if ((enum sensor_channel_max31790)chan != SENSOR_CHAN_MAX31790_FAN_FAULT) { + LOG_ERR("%s: requesting unsupported channel %i", dev->name, chan); + return -ENOTSUP; + } + + val->val1 = data->value; + val->val2 = 0; + return 0; +} + +static const struct sensor_driver_api max31790_fan_fault_api = { + .sample_fetch = max31790_fan_fault_sample_fetch, + .channel_get = max31790_fan_fault_channel_get, +}; + +static int max31790_fan_fault_init(const struct device *dev) +{ + const struct max31790_fan_fault_config *config = dev->config; + + if (!i2c_is_ready_dt(&config->i2c)) { + LOG_ERR("I2C device not ready"); + return -ENODEV; + } + + return 0; +} + +#define MAX31790_FAN_FAULT_INIT(inst) \ + static const struct max31790_fan_fault_config max31790_fan_fault_##inst##_config = { \ + .i2c = I2C_DT_SPEC_GET(DT_INST_PARENT(inst)), \ + }; \ + \ + static struct max31790_fan_fault_data max31790_fan_fault_##inst##_data; \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, max31790_fan_fault_init, NULL, \ + &max31790_fan_fault_##inst##_data, \ + &max31790_fan_fault_##inst##_config, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &max31790_fan_fault_api); + +DT_INST_FOREACH_STATUS_OKAY(MAX31790_FAN_FAULT_INIT); diff --git a/drivers/sensor/max31790/max31790_fan_fault.h b/drivers/sensor/max31790/max31790_fan_fault.h new file mode 100644 index 00000000000..6045652a549 --- /dev/null +++ b/drivers/sensor/max31790/max31790_fan_fault.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024 SILA Embedded Solutions GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_MAX31790_MAX31790_FAN_FAULT_H_ +#define ZEPHYR_DRIVERS_SENSOR_MAX31790_MAX31790_FAN_FAULT_H_ + +#include + +struct max31790_fan_fault_config { + struct i2c_dt_spec i2c; +}; + +struct max31790_fan_fault_data { + uint16_t value; +}; + +#endif /* ZEPHYR_DRIVERS_SENSOR_MAX31790_MAX31790_FAN_FAULT_H_ */ diff --git a/drivers/sensor/max31790/max31790_fan_speed.c b/drivers/sensor/max31790/max31790_fan_speed.c new file mode 100644 index 00000000000..b0db008d8dc --- /dev/null +++ b/drivers/sensor/max31790/max31790_fan_speed.c @@ -0,0 +1,138 @@ +/* + * 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 const struct sensor_driver_api 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); diff --git a/drivers/sensor/max31790/max31790_fan_speed.h b/drivers/sensor/max31790/max31790_fan_speed.h new file mode 100644 index 00000000000..17d4e9c6787 --- /dev/null +++ b/drivers/sensor/max31790/max31790_fan_speed.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 SILA Embedded Solutions GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_MAX31790_MAX31790_FAN_SPEED_H_ +#define ZEPHYR_DRIVERS_SENSOR_MAX31790_MAX31790_FAN_SPEED_H_ + +#include + +struct max31790_fan_speed_config { + struct i2c_dt_spec i2c; + uint8_t channel_id; +}; + +struct max31790_fan_speed_data { + uint16_t rpm; +}; + +#endif /* ZEPHYR_DRIVERS_SENSOR_MAX31790_MAX31790_FAN_SPEED_H_ */ diff --git a/dts/bindings/sensor/maxim,max31790-fan-fault.yaml b/dts/bindings/sensor/maxim,max31790-fan-fault.yaml new file mode 100644 index 00000000000..529557e372f --- /dev/null +++ b/dts/bindings/sensor/maxim,max31790-fan-fault.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2024 SILA Embedded Solutions GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: fan fault measurement of Maxim Integrated MAX31790 PWM Controller + +compatible: "maxim,max31790-fan-fault" + +include: [sensor-device.yaml] + +on-bus: max31790 diff --git a/dts/bindings/sensor/maxim,max31790-fan-speed.yaml b/dts/bindings/sensor/maxim,max31790-fan-speed.yaml new file mode 100644 index 00000000000..709f1730a52 --- /dev/null +++ b/dts/bindings/sensor/maxim,max31790-fan-speed.yaml @@ -0,0 +1,23 @@ +# Copyright (c) 2024 SILA Embedded Solutions GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: fan speed measurement of Maxim Integrated MAX31790 PWM Controller + +compatible: "maxim,max31790-fan-speed" + +include: [sensor-device.yaml] + +on-bus: max31790 + +properties: + channel: + type: int + enum: + - 1 + - 2 + - 3 + - 4 + - 5 + - 6 + required: true + description: PWM channel number diff --git a/include/zephyr/drivers/sensor/max31790.h b/include/zephyr/drivers/sensor/max31790.h new file mode 100644 index 00000000000..d4f06ffc1f1 --- /dev/null +++ b/include/zephyr/drivers/sensor/max31790.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 SILA Embedded Solutions GmbH + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_MAX31790_H_ +#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_MAX31790_H_ + +#include + +/* MAX31790 specific channels */ +enum sensor_channel_max31790 { + SENSOR_CHAN_MAX31790_FAN_FAULT = SENSOR_CHAN_PRIV_START, +}; + +#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_MAX31790_H_ */