summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Worley <scott.worley@microchip.corp-partner.google.com>2017-12-21 14:13:47 -0500
committerchrome-bot <chrome-bot@chromium.org>2017-12-28 14:50:31 -0800
commiteb29ab7acdcb5b9d88794a3f5d36850f6e33a2a5 (patch)
treec6392eb68abbbf98be8470561ce809670f720dd8
parent0a6a7be572cf74af531f922ad84b767749e852a7 (diff)
downloadchrome-ec-eb29ab7acdcb5b9d88794a3f5d36850f6e33a2a5.tar.gz
ec_chip_mchp: Add PWM and fan files
Add Microchip MEC17xx family PWM and fan source files for review BRANCH=none BUG= TEST=Review only. Change-Id: I91439ab999a4662d690b58b0fbbb887f643b3673 Signed-off-by: Scott Worley <scott.worley@microchip.corp-partner.google.com>
-rw-r--r--chip/mchp/fan.c164
-rw-r--r--chip/mchp/pwm.c155
-rw-r--r--chip/mchp/pwm_chip.h23
3 files changed, 342 insertions, 0 deletions
diff --git a/chip/mchp/fan.c b/chip/mchp/fan.c
new file mode 100644
index 0000000000..6f89f06673
--- /dev/null
+++ b/chip/mchp/fan.c
@@ -0,0 +1,164 @@
+/* Copyright 2017 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.
+ */
+
+/* MCHP MEC fan control module. */
+
+/* This assumes 2-pole fan. For each rotation, 5 edges are measured. */
+
+#include "fan.h"
+#include "registers.h"
+#include "util.h"
+#include "tfdp_chip.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 */
+ MCHP_FAN_STATUS(0) = 0x23;
+}
+
+void fan_set_enabled(int ch, int enabled)
+{
+ if (in_rpm_mode) {
+ if (enabled)
+ fan_set_rpm_target(ch, rpm_setting);
+ else
+ MCHP_FAN_TARGET(0) = FAN_OFF_TACH;
+ } else {
+ if (enabled)
+ fan_set_duty(ch, duty_setting);
+ else
+ MCHP_FAN_SETTING(0) = 0;
+ }
+ clear_status();
+}
+
+int fan_get_enabled(int ch)
+{
+ if (in_rpm_mode)
+ return (MCHP_FAN_TARGET(0) & 0xff00) != 0xff00;
+ else
+ return !!MCHP_FAN_SETTING(0);
+}
+
+void fan_set_duty(int ch, int percent)
+{
+ if (percent < 0)
+ percent = 0;
+ else if (percent > 100)
+ percent = 100;
+
+ duty_setting = percent;
+ MCHP_FAN_SETTING(0) = percent * 255 / 100;
+ clear_status();
+}
+
+int fan_get_duty(int ch)
+{
+ return duty_setting;
+}
+
+int fan_get_rpm_mode(int ch)
+{
+ return !!(MCHP_FAN_CFG1(0) & (1 << 7));
+}
+
+void fan_set_rpm_mode(int ch, int rpm_mode)
+{
+ if (rpm_mode)
+ MCHP_FAN_CFG1(0) |= 1 << 7;
+ else
+ MCHP_FAN_CFG1(0) &= ~(1 << 7);
+ clear_status();
+}
+
+int fan_get_rpm_actual(int ch)
+{
+ if ((MCHP_FAN_READING(0) >> 8) == 0xff)
+ return 0;
+ else
+ return TACH_TO_RPM(MCHP_FAN_READING(0) >> 3);
+}
+
+int fan_get_rpm_target(int ch)
+{
+ return rpm_setting;
+}
+
+void fan_set_rpm_target(int ch, int rpm)
+{
+ rpm_setting = rpm;
+ MCHP_FAN_TARGET(0) = RPM_TO_TACH(rpm) << 3;
+ clear_status();
+}
+
+enum fan_status fan_get_status(int ch)
+{
+ uint8_t sts = MCHP_FAN_STATUS(0);
+
+ 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 = MCHP_FAN_STATUS(0);
+
+ if (fan_get_rpm_actual(ch)) {
+ MCHP_FAN_STATUS(0) = 0x1;
+ return 0;
+ }
+ return sts & 0x1;
+}
+
+void fan_channel_setup(int ch, unsigned int flags)
+{
+ /* Clear PCR sleep enable for RPM2FAN0 */
+ MCHP_PCR_SLP_DIS_DEV(MCHP_PCR_RPMPWM0);
+
+ /*
+ * 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)
+ MCHP_FAN_CFG1(0) = 0xab;
+ else
+ MCHP_FAN_CFG1(0) = 0x2b;
+ MCHP_FAN_CFG2(0) = 0x1a;
+ clear_status();
+}
diff --git a/chip/mchp/pwm.c b/chip/mchp/pwm.c
new file mode 100644
index 0000000000..54200c7890
--- /dev/null
+++ b/chip/mchp/pwm.c
@@ -0,0 +1,155 @@
+/* Copyright 2017 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.
+ */
+
+/* PWM control module for MCHP MEC family */
+
+#include "common.h"
+#include "console.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "pwm.h"
+#include "pwm_chip.h"
+#include "registers.h"
+#include "util.h"
+#include "tfdp_chip.h"
+
+#define CPUTS(outstr) cputs(CC_PWM, outstr)
+#define CPRINTS(format, args...) cprints(CC_PWM, format, ## args)
+
+/*
+ * PWMs that must remain active in low-power idle -
+ * PWM 0,1-8 are b[4,20:27] of MCHP_PCR_SLP_EN1
+ * PWM 9 is b[31] of MCHP_PCR_SLP_EN3
+ * PWM 10 - 11 are b[0:1] of MCHP_PCR_SLP_EN4
+ * store 32-bit word with
+ * b[0:1] = PWM 10-11
+ * b[4,20:27] = PWM 0, 1-8
+ * b[31] = PWM 9
+ */
+static uint32_t pwm_keep_awake_mask;
+
+const uint8_t pwm_slp_bitpos[12] = {
+ 4, 20, 21, 22, 23, 24, 25, 26, 27, 31, 0, 1
+};
+
+static uint32_t pwm_get_sleep_mask(int id)
+{
+ uint32_t bitpos = 32;
+
+ if (id < 12)
+ bitpos = (uint32_t)pwm_slp_bitpos[id];
+
+ return (1ul << bitpos);
+}
+
+
+void pwm_enable(enum pwm_channel ch, int enabled)
+{
+ int id = pwm_channels[ch].channel;
+ uint32_t pwm_slp_mask;
+
+ pwm_slp_mask = pwm_get_sleep_mask(id);
+
+ if (enabled) {
+ MCHP_PWM_CFG(id) |= 0x1;
+ if (pwm_channels[ch].flags & PWM_CONFIG_DSLEEP)
+ pwm_keep_awake_mask |= pwm_slp_mask;
+ } else {
+ MCHP_PWM_CFG(id) &= ~0x1;
+ pwm_keep_awake_mask &= ~pwm_slp_mask;
+ }
+}
+
+int pwm_get_enabled(enum pwm_channel ch)
+{
+ return MCHP_PWM_CFG(pwm_channels[ch].channel) & 0x1;
+}
+
+void pwm_set_duty(enum pwm_channel ch, int percent)
+{
+ int id = pwm_channels[ch].channel;
+
+ if (percent < 0)
+ percent = 0;
+ else if (percent > 100)
+ percent = 100;
+
+ MCHP_PWM_ON(id) = percent;
+ MCHP_PWM_OFF(id) = 100 - percent;
+}
+
+int pwm_get_duty(enum pwm_channel ch)
+{
+ return MCHP_PWM_ON(pwm_channels[ch].channel);
+}
+
+void pwm_keep_awake(void)
+{
+ if (pwm_keep_awake_mask) {
+ /* b[4,20:27] */
+ MCHP_PCR_SLP_EN1 &= ~(pwm_keep_awake_mask &
+ (MCHP_PCR_SLP_EN1_PWM_ALL));
+ /* b[31] */
+ MCHP_PCR_SLP_EN3 &= ~(pwm_keep_awake_mask &
+ (MCHP_PCR_SLP_EN3_PWM_ALL));
+ /* b[1:0] */
+ MCHP_PCR_SLP_EN4 &= ~(pwm_keep_awake_mask &
+ (MCHP_PCR_SLP_EN4_PWM_ALL));
+ } else {
+ MCHP_PCR_SLOW_CLK_CTL &= 0xFFFFFC00;
+ }
+}
+
+
+static void pwm_configure(int ch, int active_low, int clock_low)
+{
+ /*
+ * clock_low=0 selects the 48MHz Ring Oscillator source
+ * clock_low=1 selects the 100kHz_Clk source
+ */
+ MCHP_PWM_CFG(ch) = (15 << 3) | /* Pre-divider = 16 */
+ (active_low ? (1 << 2) : 0) |
+ (clock_low ? (1 << 1) : 0);
+}
+
+static const uint16_t pwm_pcr[MCHP_PWM_ID_MAX] = {
+ MCHP_PCR_PWM0,
+ MCHP_PCR_PWM1,
+ MCHP_PCR_PWM2,
+ MCHP_PCR_PWM3,
+ MCHP_PCR_PWM4,
+ MCHP_PCR_PWM5,
+ MCHP_PCR_PWM6,
+ MCHP_PCR_PWM7,
+ MCHP_PCR_PWM8,
+ MCHP_PCR_PWM9,
+ MCHP_PCR_PWM10,
+ MCHP_PCR_PWM11,
+};
+
+static void pwm_slp_en(int pwm_id, int sleep_en)
+{
+ if ((pwm_id < 0) || (pwm_id > MCHP_PWM_ID_MAX))
+ return;
+
+ if (sleep_en)
+ MCHP_PCR_SLP_EN_DEV(pwm_pcr[pwm_id]);
+ else
+ MCHP_PCR_SLP_DIS_DEV(pwm_pcr[pwm_id]);
+}
+
+static void pwm_init(void)
+{
+ int i;
+
+ for (i = 0; i < PWM_CH_COUNT; ++i) {
+ pwm_slp_en(pwm_channels[i].channel, 0);
+ pwm_configure(pwm_channels[i].channel,
+ pwm_channels[i].flags & PWM_CONFIG_ACTIVE_LOW,
+ pwm_channels[i].flags & PWM_CONFIG_ALT_CLOCK);
+ pwm_set_duty(i, 0);
+ }
+}
+DECLARE_HOOK(HOOK_INIT, pwm_init, HOOK_PRIO_DEFAULT);
diff --git a/chip/mchp/pwm_chip.h b/chip/mchp/pwm_chip.h
new file mode 100644
index 0000000000..85ff484f86
--- /dev/null
+++ b/chip/mchp/pwm_chip.h
@@ -0,0 +1,23 @@
+/* Copyright 2017 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.
+ */
+
+/* MEC1701H-specific PWM module for Chrome EC */
+#ifndef __CROS_EC_PWM_CHIP_H
+#define __CROS_EC_PWM_CHIP_H
+
+/* Data structure to define PWM channels. */
+struct pwm_t {
+ /* PWM Channel ID */
+ int channel;
+
+ /* PWM channel flags. See include/pwm.h */
+ uint32_t flags;
+};
+
+extern const struct pwm_t pwm_channels[];
+
+void pwm_keep_awake(void);
+
+#endif /* __CROS_EC_PWM_CHIP_H */