summaryrefslogtreecommitdiff
path: root/chip/npcx/fan.c
diff options
context:
space:
mode:
Diffstat (limited to 'chip/npcx/fan.c')
-rw-r--r--chip/npcx/fan.c549
1 files changed, 0 insertions, 549 deletions
diff --git a/chip/npcx/fan.c b/chip/npcx/fan.c
deleted file mode 100644
index f0b3215ce0..0000000000
--- a/chip/npcx/fan.c
+++ /dev/null
@@ -1,549 +0,0 @@
-/* Copyright 2014 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.
- */
-
-/* NPCX fan control module. */
-
-#include "clock.h"
-#include "clock_chip.h"
-#include "fan.h"
-#include "fan_chip.h"
-#include "gpio.h"
-#include "hooks.h"
-#include "registers.h"
-#include "util.h"
-#include "pwm.h"
-#include "pwm_chip.h"
-#include "console.h"
-#include "timer.h"
-#include "task.h"
-#include "hooks.h"
-#include "system.h"
-#include "math_util.h"
-
-#if !(DEBUG_FAN)
-#define CPRINTS(...)
-#else
-#define CPRINTS(format, args...) cprints(CC_PWM, format, ## args)
-#endif
-
-/* Tacho measurement state */
-enum tacho_measure_state {
- /* Tacho normal state */
- TACHO_NORMAL = 0,
- /* Tacho underflow state */
- TACHO_UNDERFLOW
-};
-
-/* Fan mode */
-enum tacho_fan_mode {
- /* FAN rpm mode */
- TACHO_FAN_RPM = 0,
- /* FAN duty mode */
- TACHO_FAN_DUTY,
-};
-
-/* Fan status data structure */
-struct fan_status_t {
- /* Current state of the measurement */
- enum tacho_measure_state cur_state;
- /* Fan mode */
- enum tacho_fan_mode fan_mode;
- /* MFT sampling freq*/
- uint32_t mft_freq;
- /* Actual rpm */
- int rpm_actual;
- /* Target rpm */
- int rpm_target;
- /* Automatic fan status */
- enum fan_status auto_status;
-};
-
-/* Global variables */
-static volatile struct fan_status_t fan_status[FAN_CH_COUNT];
-static int rpm_pre[FAN_CH_COUNT];
-
-/*
- * Fan specifications. If they (PULSES_ROUND and RPM_DEVIATION) cannot meet
- * the followings, please replace them with correct one in board-level driver.
- */
-
-/* Pulses per round */
-#ifndef PULSES_ROUND
-#define PULSES_ROUND 2 /* 4-phases pwm-type fan. (2-phases should be 1) */
-#endif
-
-/* Rpm deviation (Unit:percent) */
-#ifndef RPM_DEVIATION
-#define RPM_DEVIATION 7
-#endif
-
-/*
- * RPM = 60 * f / (n * TACH)
- * n = Pulses per round
- * f = Tachometer (MFT) operation freq
- * TACH = Counts of tachometer
- */
-#define TACH_TO_RPM(ch, tach) \
- ((fan_status[ch].mft_freq * 60 / PULSES_ROUND) / MAX((tach), 1))
-
-/* MFT TCNT default count */
-#define TACHO_MAX_CNT (BIT(16) - 1)
-
-/* Margin of target rpm */
-#define RPM_MARGIN(rpm_target) (((rpm_target) * RPM_DEVIATION) / 100)
-
-/**
- * MFT get fan rpm value
- *
- * @param ch operation channel
- * @return actual rpm
- */
-static int mft_fan_rpm(int ch)
-{
- volatile struct fan_status_t *p_status = fan_status + ch;
- int mdl = mft_channels[ch].module;
- int tacho;
-
- /* Check whether MFT underflow flag is occurred */
- if (IS_BIT_SET(NPCX_TECTRL(mdl), NPCX_TECTRL_TCPND)) {
- /* Clear pending flags */
- SET_BIT(NPCX_TECLR(mdl), NPCX_TECLR_TCCLR);
-
- /*
- * Flag TDPND means mft underflow happen,
- * but let MFT still can re-measure actual rpm
- * when user change pwm/fan duty during
- * TACHO_UNDERFLOW state.
- */
- p_status->cur_state = TACHO_UNDERFLOW;
- p_status->auto_status = FAN_STATUS_STOPPED;
- CPRINTS("Tacho is underflow !");
-
- return 0;
- }
-
- /* Check whether MFT capture flag is set, else return previous rpm */
- if (IS_BIT_SET(NPCX_TECTRL(mdl), NPCX_TECTRL_TAPND))
- /* Clear pending flags */
- SET_BIT(NPCX_TECLR(mdl), NPCX_TECLR_TACLR);
- else
- return p_status->rpm_actual;
-
- p_status->cur_state = TACHO_NORMAL;
- /*
- * Start of the last tacho cycle is detected -
- * calculated tacho cycle duration
- */
- tacho = TACHO_MAX_CNT - NPCX_TCRA(mdl);
- /* Transfer tacho to actual rpm */
- return (tacho > 0) ? (TACH_TO_RPM(ch, tacho)) : 0;
-}
-
-/**
- * Set fan prescaler based on apb1 clock
- *
- * @param none
- * @return none
- * @notes changed when initial or HOOK_FREQ_CHANGE command
- */
-void mft_set_apb1_prescaler(int ch)
-{
- int mdl = mft_channels[ch].module;
- uint16_t prescaler_divider = 0;
-
- /* Set clock prescaler divider to MFT module*/
- prescaler_divider = (uint16_t)(clock_get_apb1_freq()
- / fan_status[ch].mft_freq);
- if (prescaler_divider >= 1)
- prescaler_divider = prescaler_divider - 1;
- if (prescaler_divider > 0xFF)
- prescaler_divider = 0xFF;
-
- NPCX_TPRSC(mdl) = (uint8_t) prescaler_divider;
-}
-
-/**
- * Fan configuration.
- *
- * @param ch operation channel
- * @param enable_mft_read_rpm FAN_USE_RPM_MODE enable flag
- * @return none
- */
-static void fan_config(int ch, int enable_mft_read_rpm)
-{
- int mdl = mft_channels[ch].module;
- int pwm_id = mft_channels[ch].pwm_id;
- enum npcx_mft_clk_src clk_src = mft_channels[ch].clk_src;
-
- volatile struct fan_status_t *p_status = fan_status + ch;
-
- /* Setup pwm with fan spec. */
- pwm_config(pwm_id);
-
- /* Need to initialize MFT or not */
- if (enable_mft_read_rpm) {
-
- /* Initialize tacho sampling rate */
- if (clk_src == TCKC_LFCLK)
- p_status->mft_freq = INT_32K_CLOCK;
- else if (clk_src == TCKC_PRESCALE_APB1_CLK)
- p_status->mft_freq = clock_get_apb1_freq();
- else
- p_status->mft_freq = 0;
-
- /* Set mode 5 to MFT module */
- SET_FIELD(NPCX_TMCTRL(mdl), NPCX_TMCTRL_MDSEL_FIELD,
- NPCX_MFT_MDSEL_5);
-
- /* Set MFT operation frequency */
- if (clk_src == TCKC_PRESCALE_APB1_CLK)
- mft_set_apb1_prescaler(ch);
-
- /* Set the low power mode or not. */
- UPDATE_BIT(NPCX_TCKC(mdl), NPCX_TCKC_LOW_PWR,
- clk_src == TCKC_LFCLK);
-
- /* Set the default count-down timer. */
- NPCX_TCNT1(mdl) = TACHO_MAX_CNT;
- NPCX_TCRA(mdl) = TACHO_MAX_CNT;
-
- /* Set the edge polarity to rising. */
- SET_BIT(NPCX_TMCTRL(mdl), NPCX_TMCTRL_TAEDG);
- /* Enable capture TCNT1 into TCRA and preset TCNT1. */
- SET_BIT(NPCX_TMCTRL(mdl), NPCX_TMCTRL_TAEN);
- /* Enable input debounce logic into TA. */
- SET_BIT(NPCX_TCFG(mdl), NPCX_TCFG_TADBEN);
-
- /* Set the clock source type and start capturing */
- SET_FIELD(NPCX_TCKC(mdl), NPCX_TCKC_C1CSEL_FIELD, clk_src);
- }
-
- /* Set default fan states */
- p_status->cur_state = TACHO_NORMAL;
- p_status->fan_mode = TACHO_FAN_DUTY;
- p_status->auto_status = FAN_STATUS_STOPPED;
-}
-
-/**
- * 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);
-
- CPRINTS("fan%d: duty %d, rpm_diff %d", ch, duty, rpm_diff);
-}
-
-/**
- * Smart fan control function.
- *
- * @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;
-}
-
-/**
- * Tick function for fan control.
- *
- * @return none
- */
-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->fan_mode != TACHO_FAN_RPM) {
- /* Fan in duty mode still want rpm_actual being updated. */
- p_status->rpm_actual = mft_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;
- }
- if (!fan_get_enabled(ch))
- continue;
- /* Get actual rpm */
- p_status->rpm_actual = mft_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);
-
-/*****************************************************************************/
-/* IC specific low-level driver */
-
-/**
- * Set fan duty cycle.
- *
- * @param ch operation channel
- * @param percent duty cycle percent
- * @return none
- */
-void fan_set_duty(int ch, int percent)
-{
- int pwm_id = mft_channels[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);
-}
-
-/**
- * Get fan duty cycle.
- *
- * @param ch operation channel
- * @return duty cycle
- */
-int fan_get_duty(int ch)
-{
- int pwm_id = mft_channels[ch].pwm_id;
-
- /* Return percent */
- return pwm_get_duty(pwm_id);
-}
-/**
- * Check fan is rpm operation mode.
- *
- * @param ch operation channel
- * @return rpm operation mode or not
- */
-int fan_get_rpm_mode(int ch)
-{
- return fan_status[ch].fan_mode == TACHO_FAN_RPM ? 1 : 0;
-}
-
-/**
- * Set fan to rpm operation mode.
- *
- * @param ch operation channel
- * @param rpm_mode rpm operation mode flag
- * @return none
- */
-void fan_set_rpm_mode(int ch, int rpm_mode)
-{
- if (rpm_mode)
- fan_status[ch].fan_mode = TACHO_FAN_RPM;
- else
- fan_status[ch].fan_mode = TACHO_FAN_DUTY;
-}
-
-/**
- * Get fan actual operation rpm.
- *
- * @param ch operation channel
- * @return actual operation rpm value
- */
-int fan_get_rpm_actual(int ch)
-{
- /* Check PWM is enabled first */
- if (fan_get_duty(ch) == 0)
- return 0;
-
- CPRINTS("fan %d: get actual rpm = %d", ch, fan_status[ch].rpm_actual);
- return fan_status[ch].rpm_actual;
-}
-
-/**
- * Check fan enabled.
- *
- * @param ch operation channel
- * @return enabled or not
- */
-int fan_get_enabled(int ch)
-{
- int pwm_id = mft_channels[ch].pwm_id;
-
- return pwm_get_enabled(pwm_id);
-}
-/**
- * Set fan enabled.
- *
- * @param ch operation channel
- * @param enabled enabled flag
- * @return none
- */
-void fan_set_enabled(int ch, int enabled)
-{
- int pwm_id = mft_channels[ch].pwm_id;
-
- if (!enabled)
- fan_status[ch].auto_status = FAN_STATUS_STOPPED;
- pwm_enable(pwm_id, enabled);
-}
-
-/**
- * Get fan setting rpm.
- *
- * @param ch operation channel
- * @return setting rpm value
- */
-int fan_get_rpm_target(int ch)
-{
- return fan_status[ch].rpm_target;
-}
-
-/**
- * Set fan setting rpm.
- *
- * @param ch operation channel
- * @param rpm setting rpm value
- * @return none
- */
-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;
- CPRINTS("fan %d: set target rpm = %d", ch, fan_status[ch].rpm_target);
-}
-
-/**
- * Check fan operation status.
- *
- * @param ch operation channel
- * @return fan_status fan operation status
- */
-enum fan_status fan_get_status(int ch)
-{
- return fan_status[ch].auto_status;
-}
-
-/**
- * Check fan is stall condition.
- *
- * @param ch operation channel
- * @return non-zero if fan is enabled but stalled
- */
-int fan_is_stalled(int ch)
-{
- return fan_get_enabled(ch) && fan_get_duty(ch) &&
- fan_status[ch].cur_state == TACHO_UNDERFLOW;
-}
-
-/**
- * Fan channel setup.
- *
- * @param ch operation channel
- * @param flags input flags
- * @return none
- */
-void fan_channel_setup(int ch, unsigned int flags)
-{
- fan_config(ch, (flags & FAN_USE_RPM_MODE));
-}
-
-/**
- * Fan initial.
- *
- * @param none
- * @return none
- */
-static void fan_init(void)
-{
- /* Enable the fan module and delay a few clocks */
- clock_enable_peripheral(CGC_OFFSET_FAN, CGC_FAN_MASK, CGC_MODE_ALL);
-}
-DECLARE_HOOK(HOOK_INIT, fan_init, HOOK_PRIO_INIT_FAN);