diff options
author | Scott Worley <scott.worley@microchip.corp-partner.google.com> | 2017-12-21 14:13:47 -0500 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-12-28 14:50:31 -0800 |
commit | eb29ab7acdcb5b9d88794a3f5d36850f6e33a2a5 (patch) | |
tree | c6392eb68abbbf98be8470561ce809670f720dd8 /chip | |
parent | 0a6a7be572cf74af531f922ad84b767749e852a7 (diff) | |
download | chrome-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>
Diffstat (limited to 'chip')
-rw-r--r-- | chip/mchp/fan.c | 164 | ||||
-rw-r--r-- | chip/mchp/pwm.c | 155 | ||||
-rw-r--r-- | chip/mchp/pwm_chip.h | 23 |
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 */ |