summaryrefslogtreecommitdiff
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
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
-rw-r--r--board/mec1322_evb/board.c15
-rw-r--r--board/mec1322_evb/board.h1
-rw-r--r--chip/mec1322/build.mk1
-rw-r--r--chip/mec1322/fan.c159
-rw-r--r--chip/mec1322/registers.h18
5 files changed, 194 insertions, 0 deletions
diff --git a/board/mec1322_evb/board.c b/board/mec1322_evb/board.c
index d2638056a3..73a2a19bb4 100644
--- a/board/mec1322_evb/board.c
+++ b/board/mec1322_evb/board.c
@@ -4,6 +4,7 @@
*/
/* MEC1322 eval board-specific configuration */
+#include "fan.h"
#include "gpio.h"
#include "registers.h"
#include "util.h"
@@ -23,5 +24,19 @@ BUILD_ASSERT(ARRAY_SIZE(gpio_list) == GPIO_COUNT);
/* Pins with alternate functions */
const struct gpio_alt_func gpio_alt_funcs[] = {
{GPIO_PORT(16), 0x24, 1, MODULE_UART}, /* UART0 */
+ {GPIO_PORT(3), (1 << 4), 3, MODULE_PWM_FAN},
+ {GPIO_PORT(14), (1 << 0), 3, MODULE_PWM_FAN},
};
const int gpio_alt_funcs_count = ARRAY_SIZE(gpio_alt_funcs);
+
+/* Physical fans. These are logically separate from pwm_channels. */
+const struct fan_t fans[] = {
+ {.flags = FAN_USE_RPM_MODE,
+ .rpm_min = 1500,
+ .rpm_max = 8000,
+ .ch = 0,
+ .pgood_gpio = -1,
+ .enable_gpio = -1,
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(fans) == CONFIG_FANS);
diff --git a/board/mec1322_evb/board.h b/board/mec1322_evb/board.h
index 6d44570dbb..128a66fb17 100644
--- a/board/mec1322_evb/board.h
+++ b/board/mec1322_evb/board.h
@@ -11,6 +11,7 @@
/* Optional features */
#define CONFIG_SYSTEM_UNLOCKED /* Allow dangerous commands */
#define CONFIG_WATCHDOG_HELP
+#define CONFIG_FANS 1
/* Modules we want to exclude */
#undef CONFIG_EEPROM
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