diff options
Diffstat (limited to 'zephyr/shim/src/fan.c')
-rw-r--r-- | zephyr/shim/src/fan.c | 380 |
1 files changed, 0 insertions, 380 deletions
diff --git a/zephyr/shim/src/fan.c b/zephyr/shim/src/fan.c deleted file mode 100644 index 932688fc9c..0000000000 --- a/zephyr/shim/src/fan.c +++ /dev/null @@ -1,380 +0,0 @@ -/* Copyright 2021 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "fan.h" -#include "pwm.h" -#include "pwm/pwm.h" -#include "system.h" -#include "math_util.h" -#include "hooks.h" -#include "gpio_signal.h" -#include "gpio.h" -#include <logging/log.h> -#include <sys/util_macro.h> -#include <drivers/sensor.h> - -LOG_MODULE_REGISTER(fan_shim, LOG_LEVEL_ERR); - -#define FAN_CONFIGS(node_id) \ - const struct fan_conf node_id##_conf = { \ - .flags = (COND_CODE_1(DT_PROP(node_id, not_use_rpm_mode), \ - (0), (FAN_USE_RPM_MODE))) | \ - (COND_CODE_1(DT_PROP(node_id, use_fast_start), \ - (FAN_USE_FAST_START), (0))), \ - .ch = node_id, \ - .pgood_gpio = COND_CODE_1( \ - DT_NODE_HAS_PROP(node_id, pgood_gpio), \ - (GPIO_SIGNAL(DT_PHANDLE(node_id, pgood_gpio))), \ - (GPIO_UNIMPLEMENTED)), \ - .enable_gpio = COND_CODE_1( \ - DT_NODE_HAS_PROP(node_id, enable_gpio), \ - (GPIO_SIGNAL(DT_PHANDLE(node_id, enable_gpio))), \ - (GPIO_UNIMPLEMENTED)), \ - }; \ - const struct fan_rpm node_id##_rpm = { \ - .rpm_min = DT_PROP(node_id, rpm_min), \ - .rpm_start = DT_PROP(node_id, rpm_start), \ - .rpm_max = DT_PROP(node_id, rpm_max), \ - }; - -#define FAN_INST(node_id) \ - [node_id] = { \ - .conf = &node_id##_conf, \ - .rpm = &node_id##_rpm, \ - }, - -#define FAN_CONTROL_INST(node_id) \ - [node_id] = { \ - .pwm_id = PWM_CHANNEL(DT_PHANDLE(node_id, pwm)), \ - }, - -#if DT_NODE_EXISTS(DT_INST(0, named_fans)) -DT_FOREACH_CHILD(DT_INST(0, named_fans), FAN_CONFIGS) -#endif /* named_fan */ - -const struct fan_t fans[] = { -#if DT_NODE_EXISTS(DT_INST(0, named_fans)) - DT_FOREACH_CHILD(DT_INST(0, named_fans), FAN_INST) -#endif /* named_fan */ -}; - -#define TACHO_DEV_INIT(node_id) { \ - fan_control[node_id].tach = \ - DEVICE_DT_GET(DT_PHANDLE(node_id, tach)); \ - } - -/* Rpm deviation (Unit:percent) */ -#ifndef RPM_DEVIATION -#define RPM_DEVIATION 7 -#endif - -/* Margin of target rpm */ -#define RPM_MARGIN(rpm_target) (((rpm_target)*RPM_DEVIATION) / 100) - -/* Fan mode */ -enum fan_mode { - /* FAN rpm mode */ - FAN_RPM = 0, - /* FAN duty mode */ - FAN_DUTY, -}; - -/* Fan status data structure */ -struct fan_status_t { - /* Fan mode */ - enum fan_mode current_fan_mode; - /* Actual rpm */ - int rpm_actual; - /* Target rpm */ - int rpm_target; - /* Fan config flags */ - unsigned int flags; - /* Automatic fan status */ - enum fan_status auto_status; -}; - -/* Data structure to define tachometer. */ -struct fan_control_t { - const struct device *tach; - enum pwm_channel pwm_id; -}; - -static struct fan_status_t fan_status[FAN_CH_COUNT]; -static int rpm_pre[FAN_CH_COUNT]; -static struct fan_control_t fan_control[] = { -#if DT_NODE_EXISTS(DT_INST(0, named_fans)) - DT_FOREACH_CHILD(DT_INST(0, named_fans), FAN_CONTROL_INST) -#endif /* named_fan */ -}; - -/** - * Get fan rpm value - * - * @param ch operation channel - * @return Actual rpm - */ -static int fan_rpm(int ch) -{ - struct sensor_value val = { 0 }; - - sensor_sample_fetch_chan(fan_control[ch].tach, SENSOR_CHAN_RPM); - sensor_channel_get(fan_control[ch].tach, SENSOR_CHAN_RPM, &val); - return (int)val.val1; -} - -/** - * Check all fans are stopped - * - * @return 1: all fans are stopped. 0: else. - */ -static int fan_all_disabled(void) -{ - int ch; - - for (ch = 0; ch < fan_get_count(); ch++) - if (fan_status[ch].auto_status != FAN_STATUS_STOPPED) - return 0; - return 1; -} - -/** - * Adjust fan duty by difference between target and actual rpm - * - * @param ch operation channel - * @param rpm_diff difference between target and actual rpm - * @param duty current fan duty - */ -static void fan_adjust_duty(int ch, int rpm_diff, int duty) -{ - int duty_step = 0; - - /* Find suitable duty step */ - if (ABS(rpm_diff) >= 2000) - duty_step = 20; - else if (ABS(rpm_diff) >= 1000) - duty_step = 10; - else if (ABS(rpm_diff) >= 500) - duty_step = 5; - else if (ABS(rpm_diff) >= 250) - duty_step = 3; - else - duty_step = 1; - - /* Adjust fan duty step by step */ - if (rpm_diff > 0) - duty = MIN(duty + duty_step, 100); - else - duty = MAX(duty - duty_step, 1); - - fan_set_duty(ch, duty); - - LOG_DBG("fan%d: duty %d, rpm_diff %d", ch, duty, rpm_diff); -} - -/** - * Smart fan control function. - * - * The function sets the pwm duty to reach the target rpm - * - * @param ch operation channel - * @param rpm_actual actual operation rpm value - * @param rpm_target target operation rpm value - * @return current fan control status - */ -enum fan_status fan_smart_control(int ch, int rpm_actual, int rpm_target) -{ - int duty, rpm_diff; - - /* wait rpm is stable */ - if (ABS(rpm_actual - rpm_pre[ch]) > RPM_MARGIN(rpm_actual)) { - rpm_pre[ch] = rpm_actual; - return FAN_STATUS_CHANGING; - } - - /* Record previous rpm */ - rpm_pre[ch] = rpm_actual; - - /* Adjust PWM duty */ - rpm_diff = rpm_target - rpm_actual; - duty = fan_get_duty(ch); - if (duty == 0 && rpm_target == 0) - return FAN_STATUS_STOPPED; - - /* Increase PWM duty */ - if (rpm_diff > RPM_MARGIN(rpm_target)) { - if (duty == 100) - return FAN_STATUS_FRUSTRATED; - - fan_adjust_duty(ch, rpm_diff, duty); - return FAN_STATUS_CHANGING; - /* Decrease PWM duty */ - } else if (rpm_diff < -RPM_MARGIN(rpm_target)) { - if (duty == 1 && rpm_target != 0) - return FAN_STATUS_FRUSTRATED; - - fan_adjust_duty(ch, rpm_diff, duty); - return FAN_STATUS_CHANGING; - } - - return FAN_STATUS_LOCKED; -} - -void fan_tick_func(void) -{ - int ch; - - for (ch = 0; ch < FAN_CH_COUNT; ch++) { - volatile struct fan_status_t *p_status = fan_status + ch; - /* Make sure rpm mode is enabled */ - if (p_status->current_fan_mode != FAN_RPM) { - /* Fan in duty mode still want rpm_actual being updated. - */ - if (p_status->flags & FAN_USE_RPM_MODE) { - p_status->rpm_actual = fan_rpm(ch); - if (p_status->rpm_actual > 0) - p_status->auto_status = - FAN_STATUS_LOCKED; - else - p_status->auto_status = - FAN_STATUS_STOPPED; - continue; - } else { - if (fan_get_duty(ch) > 0) - p_status->auto_status = - FAN_STATUS_LOCKED; - else - p_status->auto_status = - FAN_STATUS_STOPPED; - } - continue; - } - if (!fan_get_enabled(ch)) - continue; - /* Get actual rpm */ - p_status->rpm_actual = fan_rpm(ch); - /* Do smart fan stuff */ - p_status->auto_status = fan_smart_control( - ch, p_status->rpm_actual, p_status->rpm_target); - } -} -DECLARE_HOOK(HOOK_TICK, fan_tick_func, HOOK_PRIO_DEFAULT); - -int fan_get_duty(int ch) -{ - enum pwm_channel pwm_id = fan_control[ch].pwm_id; - - /* Return percent */ - return pwm_get_duty(pwm_id); -} - -int fan_get_rpm_mode(int ch) -{ - return fan_status[ch].current_fan_mode == FAN_RPM ? 1 : 0; -} - -void fan_set_rpm_mode(int ch, int rpm_mode) -{ - if (rpm_mode && (fan_status[ch].flags & FAN_USE_RPM_MODE)) - fan_status[ch].current_fan_mode = FAN_RPM; - else - fan_status[ch].current_fan_mode = FAN_DUTY; -} - -int fan_get_rpm_actual(int ch) -{ - /* Check PWM is enabled first */ - if (fan_get_duty(ch) == 0) - return 0; - - LOG_DBG("fan %d: get actual rpm = %d", ch, fan_status[ch].rpm_actual); - return fan_status[ch].rpm_actual; -} - -int fan_get_enabled(int ch) -{ - enum pwm_channel pwm_id = fan_control[ch].pwm_id; - - return pwm_get_enabled(pwm_id); -} - -void fan_set_enabled(int ch, int enabled) -{ - enum pwm_channel pwm_id = fan_control[ch].pwm_id; - - if (!enabled) - fan_status[ch].auto_status = FAN_STATUS_STOPPED; - pwm_enable(pwm_id, enabled); -} - -void fan_channel_setup(int ch, unsigned int flags) -{ - volatile struct fan_status_t *p_status = fan_status + ch; - - if (flags & FAN_USE_RPM_MODE) { - DT_FOREACH_CHILD(DT_INST(0, named_fans), TACHO_DEV_INIT) - } - - p_status->flags = flags; - /* Set default fan states */ - p_status->current_fan_mode = FAN_DUTY; - p_status->auto_status = FAN_STATUS_STOPPED; -} - -void fan_set_duty(int ch, int percent) -{ - enum pwm_channel pwm_id = fan_control[ch].pwm_id; - - /* duty is zero */ - if (!percent) { - fan_status[ch].auto_status = FAN_STATUS_STOPPED; - if (fan_all_disabled()) - enable_sleep(SLEEP_MASK_FAN); - } else - disable_sleep(SLEEP_MASK_FAN); - - /* Set the duty cycle of PWM */ - pwm_set_duty(pwm_id, percent); -} - -int fan_get_rpm_target(int ch) -{ - return fan_status[ch].rpm_target; -} - -enum fan_status fan_get_status(int ch) -{ - return fan_status[ch].auto_status; -} - -void fan_set_rpm_target(int ch, int rpm) -{ - if (rpm == 0) { - /* If rpm = 0, disable PWM immediately. Why?*/ - fan_set_duty(ch, 0); - } else { - /* This is the counterpart of disabling PWM above. */ - if (!fan_get_enabled(ch)) - fan_set_enabled(ch, 1); - if (rpm > fans[ch].rpm->rpm_max) - rpm = fans[ch].rpm->rpm_max; - else if (rpm < fans[ch].rpm->rpm_min) - rpm = fans[ch].rpm->rpm_min; - } - - /* Set target rpm */ - fan_status[ch].rpm_target = rpm; - LOG_DBG("fan %d: set target rpm = %d", ch, fan_status[ch].rpm_target); -} - -int fan_is_stalled(int ch) -{ - int is_pgood = 1; - - if (gpio_is_implemented(fans[ch].conf->enable_gpio)) - is_pgood = gpio_get_level(fans[ch].conf->enable_gpio); - - return fan_get_enabled(ch) && fan_get_duty(ch) && - !fan_get_rpm_actual(ch) && is_pgood; -} |