summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill Richardson <wfrichar@chromium.org>2013-10-29 09:49:19 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2013-10-30 01:03:43 +0000
commit497e29254286a8bf8858e3a5e5495cc098f119a4 (patch)
tree0c0aeaaef32e75e2c7237131333e819fdb9003d9
parent7e78087a91ff5c00a695ee769edd20fb62c04bc9 (diff)
downloadchrome-ec-497e29254286a8bf8858e3a5e5495cc098f119a4.tar.gz
Start separating LM4 pwm logic from fan logic.
On the LM4, all pwm functions are implemented through hardware "fan" modules. This change abstracts the hardware fan stuff from the higher level pwm and fan control logic. Those are still chip-specific at the moment, but may be moved into common with a future CL. BUG=chrome-os-partner:23530 BRANCH=none TEST=manual Code refactoring only, no new behavior. All tests build and pass, and I tested on Link with some manual pwm and fan commands on the EC console. > fanduty 30 > faninfo Should report ~4500 RPM > fanset 7000 > faninfo Should report ~48% duty cycle. > fanauto Back to automatic control. > kblight 0 > kblight 10 > kblight 50 > kblight 100 Keyboard backlight should glow appropriately. Change-Id: I7558f36b2626e555fc8dabdd12660fa484a93b7f Signed-off-by: Bill Richardson <wfrichar@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/174991 Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--Makefile4
-rw-r--r--chip/lm4/build.mk4
-rw-r--r--chip/lm4/fan.c172
-rw-r--r--chip/lm4/fan_chip.c180
-rw-r--r--chip/lm4/fan_chip.h27
-rw-r--r--chip/lm4/pwm.c89
6 files changed, 273 insertions, 203 deletions
diff --git a/Makefile b/Makefile
index 10a9c1f019..078b09c267 100644
--- a/Makefile
+++ b/Makefile
@@ -53,8 +53,8 @@ include util/lock/build.mk
includes+=$(includes-y)
-objs_from_dir=$(foreach obj, $($(2)-y), \
- $(out)/$(1)/$(firstword $($(2)-mock-$(PROJECT)-$(obj)) $(obj)))
+objs_from_dir=$(sort $(foreach obj, $($(2)-y), \
+ $(out)/$(1)/$(firstword $($(2)-mock-$(PROJECT)-$(obj)) $(obj))))
# Get all sources to build
all-y=$(call objs_from_dir,core/$(CORE),core)
diff --git a/chip/lm4/build.mk b/chip/lm4/build.mk
index 74ecd64d02..551df6e2ac 100644
--- a/chip/lm4/build.mk
+++ b/chip/lm4/build.mk
@@ -15,12 +15,12 @@ chip-y=clock.o gpio.o hwtimer.o jtag.o system.o uart.o
# Optional chip modules
chip-$(CONFIG_ADC)+=adc.o chip_temp_sensor.o
chip-$(CONFIG_EEPROM)+=eeprom.o
-chip-$(CONFIG_FAN)+=fan.o
+chip-$(CONFIG_FAN)+=fan.o fan_chip.o
chip-$(CONFIG_FLASH)+=flash.o
chip-$(CONFIG_I2C)+=i2c.o
chip-$(CONFIG_LPC)+=lpc.o
chip-$(CONFIG_PECI)+=peci.o
-chip-$(CONFIG_PWM)+=pwm.o
+chip-$(CONFIG_PWM)+=pwm.o fan_chip.o
chip-$(CONFIG_SPI)+=spi.o
chip-$(CONFIG_WATCHDOG)+=watchdog.o
chip-$(HAS_TASK_KEYSCAN)+=keyboard_raw.o
diff --git a/chip/lm4/fan.c b/chip/lm4/fan.c
index f584f69240..e8a77c3e91 100644
--- a/chip/lm4/fan.c
+++ b/chip/lm4/fan.c
@@ -3,12 +3,13 @@
* found in the LICENSE file.
*/
-/* PWM control module for Chromebook fans */
+/* Chrome OS fan control */
#include "clock.h"
#include "common.h"
#include "console.h"
#include "fan.h"
+#include "fan_chip.h"
#include "gpio.h"
#include "hooks.h"
#include "host_command.h"
@@ -19,119 +20,27 @@
#include "timer.h"
#include "util.h"
-/*****************************************************************************/
-/* Chip-specific stuff */
-
-/* Maximum RPM for fan controller */
-#define MAX_RPM 0x1fff
-/* Max PWM for fan controller */
-#define MAX_PWM 0x1ff
-/*
- * Scaling factor for requested/actual RPM for CPU fan. We need this because
- * the fan controller on Blizzard filters tach pulses that are less than 64
- * 15625Hz ticks apart, which works out to ~7000rpm on an unscaled fan. By
- * telling the controller we actually have twice as many edges per revolution,
- * the controller can handle fans that actually go twice as fast. See
- * crosbug.com/p/7718.
- */
-#define CPU_FAN_SCALE 2
-
-static int fan_get_enabled(void)
-{
- return pwm_get_enabled(PWM_CH_FAN);
-}
+/* True if we're listening to the thermal control task. False if we're setting
+ * things manually. */
+static int thermal_control_enabled;
static void fan_set_enabled(int enable)
{
- pwm_enable(PWM_CH_FAN, enable);
+ fan_chip_set_enabled(CONFIG_FAN_CH_CPU, enable);
#ifdef CONFIG_FAN_EN_GPIO
gpio_set_level(CONFIG_FAN_EN_GPIO, enable);
-#endif /* CONFIG_FAN_EN_GPIO */
-}
-
-static int fan_get_rpm_mode(void)
-{
- return (LM4_FAN_FANCH(CONFIG_FAN_CH_CPU) & 0x0001) ? 0 : 1;
-}
-
-static void fan_set_rpm_mode(int rpm_mode)
-{
- int was_enabled = fan_get_enabled();
- int was_rpm = fan_get_rpm_mode();
-
- if (!was_rpm && rpm_mode) {
- /* Enable RPM control */
- fan_set_enabled(0);
- LM4_FAN_FANCH(CONFIG_FAN_CH_CPU) &= ~0x0001;
- fan_set_enabled(was_enabled);
- } else if (was_rpm && !rpm_mode) {
- /* Disable RPM mode */
- fan_set_enabled(0);
- LM4_FAN_FANCH(CONFIG_FAN_CH_CPU) |= 0x0001;
- fan_set_enabled(was_enabled);
- }
-}
-
-static int fan_get_rpm_actual(void)
-{
- return (LM4_FAN_FANCST(CONFIG_FAN_CH_CPU) & MAX_RPM) * CPU_FAN_SCALE;
+#endif /* CONFIG_FAN_EN_GPIO */
}
-static int fan_get_rpm_target(void)
-{
- return (LM4_FAN_FANCMD(CONFIG_FAN_CH_CPU) & MAX_RPM) * CPU_FAN_SCALE;
-}
-
-static void fan_set_rpm_target(int rpm)
-{
- /* Apply fan scaling */
- if (rpm > 0)
- rpm /= CPU_FAN_SCALE;
-
- /* Treat out-of-range requests as requests for maximum fan speed */
- if (rpm < 0 || rpm > MAX_RPM)
- rpm = MAX_RPM;
-
- LM4_FAN_FANCMD(CONFIG_FAN_CH_CPU) = rpm;
-}
-
-static int fan_get_status(void)
-{
- return (LM4_FAN_FANSTS >> (2 * CONFIG_FAN_CH_CPU)) & 0x03;
-}
-static const char * const human_status[] = {
- "not spinning", "changing", "locked", "frustrated"
-};
-
-/**
- * Return non-zero if fan is enabled but stalled.
- */
-static int fan_is_stalled(void)
-{
- /* Must be enabled with non-zero target to stall */
- if (!fan_get_enabled() || fan_get_rpm_target() == 0)
- return 0;
-
- /* Check for stall condition */
- return (((LM4_FAN_FANSTS >> (2 * CONFIG_FAN_CH_CPU)) & 0x03) == 0) ?
- 1 : 0;
-}
-
-/*****************************************************************************/
-/* Control functions */
-
-/* True if we're listening to the thermal control task. False if we're setting
- * things manually. */
-static int thermal_control_enabled;
-
static void fan_set_thermal_control_enabled(int enable)
{
thermal_control_enabled = enable;
/* If controlling the fan, need it in RPM-control mode */
if (enable)
- fan_set_rpm_mode(1);
+ fan_chip_channel_setup(CONFIG_FAN_CH_CPU,
+ FAN_CHIP_USE_RPM_MODE);
}
/* The thermal task will only call this function with pct in [0,100]. */
@@ -144,13 +53,13 @@ test_mockable void pwm_fan_set_percent_needed(int pct)
rpm = pwm_fan_percent_to_rpm(pct);
- fan_set_rpm_target(rpm);
+ fan_chip_set_rpm_target(CONFIG_FAN_CH_CPU, rpm);
}
static void fan_set_duty_cycle(int percent)
{
/* Move the fan to manual control */
- fan_set_rpm_mode(0);
+ fan_chip_set_rpm_mode(CONFIG_FAN_CH_CPU, 0);
/* Always enable the fan */
fan_set_enabled(1);
@@ -159,12 +68,7 @@ static void fan_set_duty_cycle(int percent)
fan_set_thermal_control_enabled(0);
/* Set the duty cycle */
- pwm_set_duty(PWM_CH_FAN, percent);
-}
-
-static int fan_get_duty_cycle(void)
-{
- return pwm_get_duty(PWM_CH_FAN);
+ fan_chip_set_duty(CONFIG_FAN_CH_CPU, percent);
}
/*****************************************************************************/
@@ -180,18 +84,26 @@ DECLARE_CONSOLE_COMMAND(fanauto, cc_fanauto,
"Enable thermal fan control",
NULL);
-
static int cc_faninfo(int argc, char **argv)
{
+ static const char * const human_status[] = {
+ "not spinning", "changing", "locked", "frustrated"
+ };
int tmp;
- ccprintf("Actual: %4d rpm\n", fan_get_rpm_actual());
- ccprintf("Target: %4d rpm\n", fan_get_rpm_target());
- ccprintf("Duty: %d%%\n", fan_get_duty_cycle());
- tmp = fan_get_status();
+
+ ccprintf("Actual: %4d rpm\n",
+ fan_chip_get_rpm_actual(CONFIG_FAN_CH_CPU));
+ ccprintf("Target: %4d rpm\n",
+ fan_chip_get_rpm_target(CONFIG_FAN_CH_CPU));
+ ccprintf("Duty: %d%%\n",
+ fan_chip_get_duty(CONFIG_FAN_CH_CPU));
+ tmp = fan_chip_get_status(CONFIG_FAN_CH_CPU);
ccprintf("Status: %d (%s)\n", tmp, human_status[tmp]);
- ccprintf("Mode: %s\n", fan_get_rpm_mode() ? "rpm" : "duty");
+ ccprintf("Mode: %s\n",
+ fan_chip_get_rpm_mode(CONFIG_FAN_CH_CPU) ? "rpm" : "duty");
ccprintf("Auto: %s\n", thermal_control_enabled ? "yes" : "no");
- ccprintf("Enable: %s\n", fan_get_enabled() ? "yes" : "no");
+ ccprintf("Enable: %s\n",
+ fan_chip_get_enabled(CONFIG_FAN_CH_CPU) ? "yes" : "no");
#ifdef CONFIG_FAN_PGOOD_GPIO
ccprintf("Power: %s\n",
#ifdef CONFIG_FAN_EN_GPIO
@@ -229,7 +141,7 @@ static int cc_fanset(int argc, char **argv)
}
/* Move the fan to automatic control */
- fan_set_rpm_mode(1);
+ fan_chip_set_rpm_mode(CONFIG_FAN_CH_CPU, 1);
/* Always enable the fan */
fan_set_enabled(1);
@@ -237,7 +149,7 @@ static int cc_fanset(int argc, char **argv)
/* Disable thermal engine automatic fan control. */
fan_set_thermal_control_enabled(0);
- fan_set_rpm_target(rpm);
+ fan_chip_set_rpm_target(CONFIG_FAN_CH_CPU, rpm);
ccprintf("Setting fan rpm target to %d\n", rpm);
@@ -277,7 +189,7 @@ static int hc_pwm_get_fan_target_rpm(struct host_cmd_handler_args *args)
{
struct ec_response_pwm_get_fan_rpm *r = args->response;
- r->rpm = fan_get_rpm_target();
+ r->rpm = fan_chip_get_rpm_target(CONFIG_FAN_CH_CPU);
args->response_size = sizeof(*r);
return EC_RES_SUCCESS;
@@ -291,8 +203,8 @@ static int hc_pwm_set_fan_target_rpm(struct host_cmd_handler_args *args)
const struct ec_params_pwm_set_fan_target_rpm *p = args->params;
fan_set_thermal_control_enabled(0);
- fan_set_rpm_mode(1);
- fan_set_rpm_target(p->rpm);
+ fan_chip_set_rpm_mode(CONFIG_FAN_CH_CPU, 1);
+ fan_chip_set_rpm_target(CONFIG_FAN_CH_CPU, p->rpm);
return EC_RES_SUCCESS;
}
@@ -346,11 +258,11 @@ static void pwm_fan_init(void)
system_get_jump_tag(PWMFAN_SYSJUMP_TAG, &version, &size);
if (prev && version == PWM_HOOK_VERSION && size == sizeof(*prev)) {
/* Restore previous state. */
- fan_set_enabled(prev->fan_en);
- fan_set_rpm_target(prev->fan_rpm);
+ fan_chip_set_enabled(CONFIG_FAN_CH_CPU, prev->fan_en);
+ fan_chip_set_rpm_target(CONFIG_FAN_CH_CPU, prev->fan_rpm);
} else {
/* Set initial fan speed to maximum */
- pwm_fan_set_percent_needed(100);
+ fan_chip_set_duty(CONFIG_FAN_CH_CPU, 100);
}
fan_set_thermal_control_enabled(1);
@@ -366,7 +278,7 @@ static void pwm_fan_second(void)
{
uint16_t *mapped = (uint16_t *)host_get_memmap(EC_MEMMAP_FAN);
- if (fan_is_stalled()) {
+ if (fan_chip_is_stalled(CONFIG_FAN_CH_CPU)) {
mapped[0] = EC_FAN_SPEED_STALLED;
/*
* Issue warning. As we have thermal shutdown
@@ -375,7 +287,7 @@ static void pwm_fan_second(void)
host_set_single_event(EC_HOST_EVENT_THERMAL);
cprintf(CC_PWM, "[%T Fan stalled!]\n");
} else {
- mapped[0] = fan_get_rpm_actual();
+ mapped[0] = fan_chip_get_rpm_actual(CONFIG_FAN_CH_CPU);
}
}
DECLARE_HOOK(HOOK_SECOND, pwm_fan_second, HOOK_PRIO_DEFAULT);
@@ -384,8 +296,8 @@ static void pwm_fan_preserve_state(void)
{
struct pwm_fan_state state;
- state.fan_en = fan_get_enabled();
- state.fan_rpm = fan_get_rpm_target();
+ state.fan_en = fan_chip_get_enabled(CONFIG_FAN_CH_CPU);
+ state.fan_rpm = fan_chip_get_rpm_target(CONFIG_FAN_CH_CPU);
system_add_jump_tag(PWMFAN_SYSJUMP_TAG, PWM_HOOK_VERSION,
sizeof(state), &state);
@@ -394,7 +306,7 @@ DECLARE_HOOK(HOOK_SYSJUMP, pwm_fan_preserve_state, HOOK_PRIO_DEFAULT);
static void pwm_fan_resume(void)
{
- fan_set_enabled(1);
+ fan_chip_set_enabled(CONFIG_FAN_CH_CPU, 1);
}
DECLARE_HOOK(HOOK_CHIPSET_RESUME, pwm_fan_resume, HOOK_PRIO_DEFAULT);
@@ -405,8 +317,8 @@ static void pwm_fan_S3_S5(void)
/* For now don't do anything with it. We'll have to turn it on again if
* we need active cooling during heavy battery charging or something.
*/
- fan_set_rpm_target(0);
- fan_set_enabled(0); /* crosbug.com/p/8097 */
+ fan_chip_set_rpm_target(CONFIG_FAN_CH_CPU, 0);
+ fan_chip_set_enabled(CONFIG_FAN_CH_CPU, 0); /* crosbug.com/p/8097 */
}
DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, pwm_fan_S3_S5, HOOK_PRIO_DEFAULT);
DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, pwm_fan_S3_S5, HOOK_PRIO_DEFAULT);
diff --git a/chip/lm4/fan_chip.c b/chip/lm4/fan_chip.c
new file mode 100644
index 0000000000..cef39b9b3d
--- /dev/null
+++ b/chip/lm4/fan_chip.c
@@ -0,0 +1,180 @@
+/* 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.
+ */
+
+/* LM4 fan control module. */
+
+#include "clock.h"
+#include "fan_chip.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "registers.h"
+#include "util.h"
+
+/* Maximum RPM for fan controller */
+#define MAX_RPM 0x1fff
+
+/* Maximum PWM for PWM controller */
+#define MAX_PWM 0x1ff
+
+/*
+ * Scaling factor for requested/actual RPM for CPU fan. We need this because
+ * the fan controller on Blizzard filters tach pulses that are less than 64
+ * 15625Hz ticks apart, which works out to ~7000rpm on an unscaled fan. By
+ * telling the controller we actually have twice as many edges per revolution,
+ * the controller can handle fans that actually go twice as fast. See
+ * crosbug.com/p/7718.
+ */
+#define RPM_SCALE 2
+
+
+void fan_chip_set_enabled(int ch, int enabled)
+{
+ if (enabled)
+ LM4_FAN_FANCTL |= (1 << ch);
+ else
+ LM4_FAN_FANCTL &= ~(1 << ch);
+}
+
+int fan_chip_get_enabled(int ch)
+{
+ return (LM4_FAN_FANCTL & (1 << ch)) ? 1 : 0;
+}
+
+void fan_chip_set_duty(int ch, int percent)
+{
+ int duty;
+
+ if (percent < 0)
+ percent = 0;
+ else if (percent > 100)
+ percent = 100;
+
+ duty = (MAX_PWM * percent + 50) / 100;
+
+ /* Always enable the channel */
+ fan_chip_set_enabled(ch, 1);
+
+ /* Set the duty cycle */
+ LM4_FAN_FANCMD(ch) = duty << 16;
+}
+
+int fan_chip_get_duty(enum pwm_channel ch)
+{
+ return ((LM4_FAN_FANCMD(ch) >> 16) * 100 + MAX_PWM / 2) / MAX_PWM;
+}
+
+int fan_chip_get_rpm_mode(int ch)
+{
+ return (LM4_FAN_FANCH(ch) & 0x0001) ? 0 : 1;
+}
+
+void fan_chip_set_rpm_mode(int ch, int rpm_mode)
+{
+ int was_enabled = fan_chip_get_enabled(ch);
+ int was_rpm = fan_chip_get_rpm_mode(ch);
+
+ if (!was_rpm && rpm_mode) {
+ /* Enable RPM control */
+ fan_chip_set_enabled(ch, 0);
+ LM4_FAN_FANCH(ch) &= ~0x0001;
+ fan_chip_set_enabled(ch, was_enabled);
+ } else if (was_rpm && !rpm_mode) {
+ /* Disable RPM mode */
+ fan_chip_set_enabled(ch, 0);
+ LM4_FAN_FANCH(ch) |= 0x0001;
+ fan_chip_set_enabled(ch, was_enabled);
+ }
+}
+
+int fan_chip_get_rpm_actual(int ch)
+{
+ return (LM4_FAN_FANCST(ch) & MAX_RPM) * RPM_SCALE;
+}
+
+int fan_chip_get_rpm_target(int ch)
+{
+ return (LM4_FAN_FANCMD(ch) & MAX_RPM) * RPM_SCALE;
+}
+
+void fan_chip_set_rpm_target(int ch, int rpm)
+{
+ /* Apply fan scaling */
+ if (rpm > 0)
+ rpm /= RPM_SCALE;
+
+ /* Treat out-of-range requests as requests for maximum fan speed */
+ if (rpm < 0 || rpm > MAX_RPM)
+ rpm = MAX_RPM;
+
+ LM4_FAN_FANCMD(ch) = rpm;
+}
+
+/*
+ * 0 = stopped
+ * 1 = changing
+ * 2 = locked
+ * 3 = unable to lock
+ */
+int fan_chip_get_status(int ch)
+{
+ return (LM4_FAN_FANSTS >> (2 * ch)) & 0x03;
+}
+
+/**
+ * Return non-zero if fan is enabled but stalled.
+ */
+int fan_chip_is_stalled(int ch)
+{
+ /* Must be enabled with non-zero target to stall */
+ if (!fan_chip_get_enabled(ch) || fan_chip_get_rpm_target(ch) == 0)
+ return 0;
+
+ /* Check for stall condition */
+ return (((LM4_FAN_FANSTS >> (2 * ch)) & 0x03) == 0) ? 1 : 0;
+}
+
+void fan_chip_channel_setup(int ch, unsigned int flags)
+{
+ if (flags & FAN_CHIP_USE_RPM_MODE) {
+ /*
+ * Configure automatic/feedback mode:
+ * 0x8000 = bit 15 = auto-restart
+ * 0x0000 = bit 14 = slow acceleration
+ * 0x0000 = bits 13:11 = no hysteresis
+ * 0x0000 = bits 10:8 = start period (2<<0) edges
+ * 0x0000 = bits 7:6 = no fast start
+ * 0x0020 = bits 5:4 = average 4 edges when
+ * calculating RPM
+ * 0x000c = bits 3:2 = 8 pulses per revolution
+ * (see note at top of file)
+ * 0x0000 = bit 0 = automatic control
+ */
+ LM4_FAN_FANCH(ch) = 0x802c;
+ } else {
+ /*
+ * Configure drive-only mode:
+ * 0x0000 = bit 15 = no auto-restart
+ * 0x0000 = bit 14 = slow acceleration
+ * 0x0000 = bits 13:11 = no hysteresis
+ * 0x0000 = bits 10:8 = start period (2<<0) edges
+ * 0x0000 = bits 7:6 = no fast start
+ * 0x0000 = bits 5:4 = no RPM averaging
+ * 0x0000 = bits 3:2 = 1 pulses per revolution
+ * 0x0001 = bit 0 = manual control
+ */
+ LM4_FAN_FANCH(ch) = 0x0001;
+ }
+}
+
+static void fan_chip_init(void)
+{
+ /* Enable the fan module and delay a few clocks */
+ clock_enable_peripheral(CGC_OFFSET_FAN, 0x1,
+ CGC_MODE_RUN | CGC_MODE_SLEEP);
+
+ /* Disable all fans */
+ LM4_FAN_FANCTL = 0;
+}
+DECLARE_HOOK(HOOK_INIT, fan_chip_init, HOOK_PRIO_INIT_PWM);
diff --git a/chip/lm4/fan_chip.h b/chip/lm4/fan_chip.h
new file mode 100644
index 0000000000..0ff92b1740
--- /dev/null
+++ b/chip/lm4/fan_chip.h
@@ -0,0 +1,27 @@
+/* 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.
+ */
+
+/* LM4-specific fan control module */
+
+#ifndef __CROS_EC_LM4_FAN_CHIP_H
+#define __CROS_EC_LM4_FAN_CHIP_H
+
+void fan_chip_set_enabled(int ch, int enabled);
+int fan_chip_get_enabled(int ch);
+void fan_chip_set_duty(int ch, int percent);
+int fan_chip_get_duty(enum pwm_channel ch);
+int fan_chip_get_rpm_mode(int ch);
+void fan_chip_set_rpm_mode(int ch, int rpm_mode);
+int fan_chip_get_rpm_actual(int ch);
+int fan_chip_get_rpm_target(int ch);
+void fan_chip_set_rpm_target(int ch, int rpm);
+int fan_chip_get_status(int ch);
+int fan_chip_is_stalled(int ch);
+
+/* Maintain target RPM using tach input */
+#define FAN_CHIP_USE_RPM_MODE (1 << 0)
+void fan_chip_channel_setup(int ch, unsigned int flags);
+
+#endif /* __CROS_EC_LM4_FAN_CHIP_H */
diff --git a/chip/lm4/pwm.c b/chip/lm4/pwm.c
index 6e52ebb369..943aa0210f 100644
--- a/chip/lm4/pwm.c
+++ b/chip/lm4/pwm.c
@@ -3,9 +3,13 @@
* found in the LICENSE file.
*/
-/* PWM control module for LM4 */
+/* PWM control module for LM4.
+ *
+ * On this chip, the PWM logic is implemented by the hardware FAN modules.
+ */
#include "clock.h"
+#include "fan_chip.h"
#include "gpio.h"
#include "hooks.h"
#include "pwm.h"
@@ -13,58 +17,39 @@
#include "registers.h"
#include "util.h"
-/* Maximum RPM for PWM controller */
-#define MAX_RPM 0x1fff
-
-/* Maximum PWM for PWM controller */
-#define MAX_PWM 0x1ff
-
-#define RPM_SCALE 2
-
void pwm_enable(enum pwm_channel ch, int enabled)
{
- const struct pwm_t *pwm = pwm_channels + ch;
- if (enabled)
- LM4_FAN_FANCTL |= (1 << pwm->channel);
- else
- LM4_FAN_FANCTL &= ~(1 << pwm->channel);
+ fan_chip_set_enabled(pwm_channels[ch].channel, enabled);
}
int pwm_get_enabled(enum pwm_channel ch)
{
- const struct pwm_t *pwm = pwm_channels + ch;
- return (LM4_FAN_FANCTL & (1 << pwm->channel)) ? 1 : 0;
+ return fan_chip_get_enabled(pwm_channels[ch].channel);
}
void pwm_set_duty(enum pwm_channel ch, int percent)
{
- const struct pwm_t *pwm = pwm_channels + ch;
- int duty;
-
if (percent < 0)
percent = 0;
else if (percent > 100)
percent = 100;
- if (pwm->flags & PWM_CONFIG_ACTIVE_LOW)
+ /* Assume the fan control is active high and invert it ourselves */
+ if (pwm_channels[ch].flags & PWM_CONFIG_ACTIVE_LOW)
percent = 100 - percent;
- duty = (MAX_PWM * percent + 50) / 100;
-
/* Always enable the channel */
pwm_enable(ch, 1);
/* Set the duty cycle */
- LM4_FAN_FANCMD(pwm->channel) = duty << 16;
+ fan_chip_set_duty(pwm_channels[ch].channel, percent);
}
int pwm_get_duty(enum pwm_channel ch)
{
- const struct pwm_t *pwm = pwm_channels + ch;
- int percent = ((LM4_FAN_FANCMD(pwm->channel) >> 16) * 100 + MAX_PWM / 2)
- / MAX_PWM;
+ int percent = fan_chip_get_duty(pwm_channels[ch].channel);
- if (pwm->flags & PWM_CONFIG_ACTIVE_LOW)
+ if (pwm_channels[ch].flags & PWM_CONFIG_ACTIVE_LOW)
percent = 100 - percent;
return percent;
@@ -73,47 +58,13 @@ int pwm_get_duty(enum pwm_channel ch)
static void pwm_init(void)
{
int i;
- const struct pwm_t *pwm;
-
- /* Enable the fan module and delay a few clocks */
- clock_enable_peripheral(CGC_OFFSET_FAN, 0x1,
- CGC_MODE_RUN | CGC_MODE_SLEEP);
-
- /* Disable all fans */
- LM4_FAN_FANCTL = 0;
- for (i = 0; i < PWM_CH_COUNT; ++i) {
- pwm = pwm_channels + i;
-
- if (pwm->flags & PWM_CONFIG_HAS_RPM_MODE) {
- /*
- * Configure PWM:
- * 0x8000 = bit 15 = auto-restart
- * 0x0000 = bit 14 = slow acceleration
- * 0x0000 = bits 13:11 = no hysteresis
- * 0x0000 = bits 10:8 = start period (2<<0) edges
- * 0x0000 = bits 7:6 = no fast start
- * 0x0020 = bits 5:4 = average 4 edges when
- * calculating RPM
- * 0x000c = bits 3:2 = 8 pulses per revolution
- * (see note at top of file)
- * 0x0000 = bit 0 = automatic control
- */
- LM4_FAN_FANCH(pwm->channel) = 0x802c;
- } else {
- /*
- * Configure keyboard backlight:
- * 0x0000 = bit 15 = no auto-restart
- * 0x0000 = bit 14 = slow acceleration
- * 0x0000 = bits 13:11 = no hysteresis
- * 0x0000 = bits 10:8 = start period (2<<0) edges
- * 0x0000 = bits 7:6 = no fast start
- * 0x0000 = bits 5:4 = no RPM averaging
- * 0x0000 = bits 3:2 = 1 pulses per revolution
- * 0x0001 = bit 0 = manual control
- */
- LM4_FAN_FANCH(pwm->channel) = 0x0001;
- }
- }
+ for (i = 0; i < PWM_CH_COUNT; ++i)
+ fan_chip_channel_setup(pwm_channels[i].channel,
+ (pwm_channels[i].flags &
+ PWM_CONFIG_HAS_RPM_MODE)
+ ? FAN_CHIP_USE_RPM_MODE : 0);
}
-DECLARE_HOOK(HOOK_INIT, pwm_init, HOOK_PRIO_INIT_PWM);
+
+/* The chip-specific fan module initializes before this. */
+DECLARE_HOOK(HOOK_INIT, pwm_init, HOOK_PRIO_DEFAULT);