mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-10 17:41:54 +00:00
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>
This commit is contained in:
164
chip/mchp/fan.c
Normal file
164
chip/mchp/fan.c
Normal file
@@ -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();
|
||||
}
|
||||
155
chip/mchp/pwm.c
Normal file
155
chip/mchp/pwm.c
Normal file
@@ -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);
|
||||
23
chip/mchp/pwm_chip.h
Normal file
23
chip/mchp/pwm_chip.h
Normal file
@@ -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 */
|
||||
Reference in New Issue
Block a user