diff options
Diffstat (limited to 'chip')
-rw-r--r-- | chip/mec1322/build.mk | 1 | ||||
-rw-r--r-- | chip/mec1322/fan.c | 159 | ||||
-rw-r--r-- | chip/mec1322/registers.h | 18 |
3 files changed, 178 insertions, 0 deletions
diff --git a/chip/mec1322/build.mk b/chip/mec1322/build.mk index 8ee67de6aa..0f7262b8f9 100644 --- a/chip/mec1322/build.mk +++ b/chip/mec1322/build.mk @@ -13,6 +13,7 @@ CFLAGS_CPU+=-march=armv7e-m -mcpu=cortex-m4 # Required chip modules chip-y=clock.o gpio.o hwtimer.o system.o uart.o jtag.o +chip-$(CONFIG_FANS)+=fan.o chip-$(CONFIG_LPC)+=lpc.o chip-$(CONFIG_PWM)+=pwm.o chip-$(CONFIG_WATCHDOG)+=watchdog.o diff --git a/chip/mec1322/fan.c b/chip/mec1322/fan.c new file mode 100644 index 0000000000..9636bc816e --- /dev/null +++ b/chip/mec1322/fan.c @@ -0,0 +1,159 @@ +/* Copyright (c) 2013 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. + */ + +/* MEC1322 fan control module. */ + +/* This assumes 2-pole fan. For each rotation, 5 edges are measured. */ + +#include "fan.h" +#include "registers.h" +#include "util.h" + +/* Maximum tach reading/target value */ +#define MAX_TACH 0x1fff + +/* Tach target value for disable fan */ +#define FAN_OFF_TACH 0xfff8 + +/* + * RPM = (n - 1) * m * f * 60 / poles / TACH + * n = number of edges = 5 + * m = multiplier defined by RANGE = 2 in our case + * f = 32.768K + * poles = 2 + */ +#define RPM_TO_TACH(rpm) MIN((7864320 / MAX((rpm), 1)), MAX_TACH) +#define TACH_TO_RPM(tach) (7864320 / MAX((tach), 1)) + +static int rpm_setting; +static int duty_setting; +static int in_rpm_mode = 1; + + +static void clear_status(void) +{ + /* Clear DRIVE_FAIL, FAN_SPIN, and FAN_STALL bits */ + MEC1322_FAN_STATUS = 0x23; +} + +void fan_set_enabled(int ch, int enabled) +{ + if (in_rpm_mode) { + if (enabled) + fan_set_rpm_target(ch, rpm_setting); + else + MEC1322_FAN_TARGET = FAN_OFF_TACH; + } else { + if (enabled) + fan_set_duty(ch, duty_setting); + else + MEC1322_FAN_SETTING = 0; + } + clear_status(); +} + +int fan_get_enabled(int ch) +{ + if (in_rpm_mode) + return (MEC1322_FAN_TARGET & 0xff00) != 0xff00; + else + return !!MEC1322_FAN_SETTING; +} + +void fan_set_duty(int ch, int percent) +{ + if (percent < 0) + percent = 0; + else if (percent > 100) + percent = 100; + + duty_setting = percent; + MEC1322_FAN_SETTING = percent * 255 / 100; + clear_status(); +} + +int fan_get_duty(int ch) +{ + return duty_setting; +} + +int fan_get_rpm_mode(int ch) +{ + return !!(MEC1322_FAN_CFG1 & (1 << 7)); +} + +void fan_set_rpm_mode(int ch, int rpm_mode) +{ + if (rpm_mode) + MEC1322_FAN_CFG1 |= 1 << 7; + else + MEC1322_FAN_CFG1 &= ~(1 << 7); + clear_status(); +} + +int fan_get_rpm_actual(int ch) +{ + if ((MEC1322_FAN_READING >> 8) == 0xff) + return 0; + else + return TACH_TO_RPM(MEC1322_FAN_READING >> 3); +} + +int fan_get_rpm_target(int ch) +{ + return rpm_setting; +} + +void fan_set_rpm_target(int ch, int rpm) +{ + rpm_setting = rpm; + MEC1322_FAN_TARGET = RPM_TO_TACH(rpm) << 3; + clear_status(); +} + +enum fan_status fan_get_status(int ch) +{ + uint8_t sts = MEC1322_FAN_STATUS; + + if (sts & ((1 << 5) | (1 << 1))) + return FAN_STATUS_FRUSTRATED; + if (fan_get_rpm_actual(ch) == 0) + return FAN_STATUS_STOPPED; + return FAN_STATUS_LOCKED; +} + +int fan_is_stalled(int ch) +{ + uint8_t sts = MEC1322_FAN_STATUS; + if (fan_get_rpm_actual(ch)) { + MEC1322_FAN_STATUS = 0x1; + return 0; + } + return sts & 0x1; +} + +void fan_channel_setup(int ch, unsigned int flags) +{ + /* + * Fan configuration 1 register: + * 0x80 = bit 7 = RPM mode (0x00 if FAN_USE_RPM_MODE not set) + * 0x20 = bits 6:5 = min 1000 RPM, multiplier = 2 + * 0x08 = bits 4:3 = 5 edges, 2 poles + * 0x03 = bits 2:0 = 400 ms update time + * + * Fan configuration 2 register: + * 0x00 = bit 6 = Ramp control disabled + * 0x00 = bit 5 = Glitch filter enabled + * 0x18 = bits 4:3 = Using both derivative options + * 0x02 = bits 2:1 = error range is 50 RPM + * 0x00 = bits 0 = normal polarity + */ + if (flags & FAN_USE_RPM_MODE) + MEC1322_FAN_CFG1 = 0xab; + else + MEC1322_FAN_CFG1 = 0x2b; + MEC1322_FAN_CFG2 = 0x1a; + clear_status(); +} diff --git a/chip/mec1322/registers.h b/chip/mec1322/registers.h index 8a134415f1..e1827fbc61 100644 --- a/chip/mec1322/registers.h +++ b/chip/mec1322/registers.h @@ -189,6 +189,24 @@ static inline uintptr_t gpio_port_base(int port_id) #define MEC1322_ACPI_EC_OS2EC(x, y) REG8(MEC1322_ACPI_EC_BASE(x) + 0x108 + (y)) +/* FAN */ +#define MEC1322_FAN_BASE 0x4000a000 +#define MEC1322_FAN_SETTING REG8(MEC1322_FAN_BASE + 0x0) +#define MEC1322_FAN_PWM_DIVIDE REG8(MEC1322_FAN_BASE + 0x1) +#define MEC1322_FAN_CFG1 REG8(MEC1322_FAN_BASE + 0x2) +#define MEC1322_FAN_CFG2 REG8(MEC1322_FAN_BASE + 0x3) +#define MEC1322_FAN_GAIN REG8(MEC1322_FAN_BASE + 0x5) +#define MEC1322_FAN_SPIN_UP REG8(MEC1322_FAN_BASE + 0x6) +#define MEC1322_FAN_STEP REG8(MEC1322_FAN_BASE + 0x7) +#define MEC1322_FAN_MIN_DRV REG8(MEC1322_FAN_BASE + 0x8) +#define MEC1322_FAN_VALID_CNT REG8(MEC1322_FAN_BASE + 0x9) +#define MEC1322_FAN_DRV_FAIL REG16(MEC1322_FAN_BASE + 0xa) +#define MEC1322_FAN_TARGET REG16(MEC1322_FAN_BASE + 0xc) +#define MEC1322_FAN_READING REG16(MEC1322_FAN_BASE + 0xe) +#define MEC1322_FAN_BASE_FREQ REG8(MEC1322_FAN_BASE + 0x10) +#define MEC1322_FAN_STATUS REG8(MEC1322_FAN_BASE + 0x11) + + /* IRQ Numbers */ #define MEC1322_IRQ_I2C_0 0 #define MEC1322_IRQ_I2C_1 1 |