summaryrefslogtreecommitdiff
path: root/chip
diff options
context:
space:
mode:
Diffstat (limited to 'chip')
-rw-r--r--chip/mec1322/build.mk1
-rw-r--r--chip/mec1322/fan.c159
-rw-r--r--chip/mec1322/registers.h18
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