summaryrefslogtreecommitdiff
path: root/chip
diff options
context:
space:
mode:
authorVic (Chun-Ju) Yang <victoryang@chromium.org>2013-11-29 12:20:22 +0800
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2013-12-04 13:34:56 +0000
commit06e60734910d952830c2102cd2ab002ddc99029b (patch)
tree9d1f1ba042987e5d81e26bf8acedbe463c74d282 /chip
parent715ad86d43f0695363d3749f2c202f5e3f7e3bd2 (diff)
downloadchrome-ec-06e60734910d952830c2102cd2ab002ddc99029b.tar.gz
mec1322: Fan control driver
This adds the driver for PWM duty cycle based and RPM based fan control. BUG=chrome-os-partner:24107 TEST='fanset 5000' and fan spins up. 'fanset 8000' and fan spins faster. 'fanset 0' and fan stops. 'fanduty 30' and fan spins up. 'fanduty 50' and fan spins faster. 'fanduty 30' and fan slows down. 'fanset 6000' and fan goes to ~6000 RPM. Unplug fan power and see 'fan 0 stalled'. Plug power back and doesn't see stall warning anymore. BRANCH=None Change-Id: Ice3e5c03686cde57894e888e34ae2070c33b4e4d Signed-off-by: Vic (Chun-Ju) Yang <victoryang@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/178402
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