Refactor PWM module

This unifies the PWM module interface for LM4 and STM32. Now PWM
channels are defined in board.h/board.c. Instead of calling functions
named pwm_set_fan_duty(x), one can now use pwm_set_duty(PWM_CH_FAN, x),
which prevents additional functions added when we have a new PWM
channel.

BUG=chrome-os-partner:18343
TEST=Limit input current on Spring.
TEST=Check power LED in S0/S3/S5 on Snow.
TEST=Check keyboard backlight functionality on Link.
TEST=Check fan speed control/detecting on Link.
BRANCH=None

Change-Id: Ibac4d79f72e65c94776d503558a7592f7db859dc
Signed-off-by: Vic Yang <victoryang@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/64450
Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
Vic Yang
2013-08-05 11:17:35 +08:00
committed by chrome-internal-fetch
parent 99f06c39aa
commit 5d014fd2dd
37 changed files with 606 additions and 319 deletions

View File

@@ -40,6 +40,10 @@ enum adc_channel {
ADC_CH_COUNT
};
enum pwm_channel {
PWM_CH_COUNT
};
/* I2C ports */
#define I2C_PORT_LIGHTBAR 5 // port 5 / PA6:7 on link, but PG6:7 on badger
/* Number of I2C ports used */

View File

@@ -22,6 +22,7 @@
#include "peci.h"
#include "power_button.h"
#include "pwm.h"
#include "pwm_data.h"
#include "registers.h"
#include "switch.h"
#include "temp_sensor.h"
@@ -179,6 +180,13 @@ const struct adc_t adc_channels[] = {
};
BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
/* PWM channels */
const struct pwm_t pwm_channels[] = {
[PWM_CH_FAN] = {FAN_CH_CPU, PWM_CONFIG_HAS_RPM_MODE},
[PWM_CH_KBLIGHT] = {FAN_CH_KBLIGHT, 0},
};
BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT);
/* I2C ports */
const struct i2c_port_t i2c_ports[] = {
/* Note: battery and charger share a port. Only include it once in

View File

@@ -35,10 +35,11 @@
#define CONFIG_CHARGER_SENSE_RESISTOR_AC 10
/* External Charger maximum current. */
#define CONFIG_CHARGER_INPUT_CURRENT 5000
#define CONFIG_PWM_FAN
#define CONFIG_PWM_FAN_RPM_MIN 1000
#define CONFIG_PWM_FAN_RPM_MAX 5050
#define CONFIG_PWM_FAN_POWER_GOOD GPIO_PP5000_PGOOD
#define CONFIG_FAN
#define CONFIG_FAN_RPM_MIN 1000
#define CONFIG_FAN_RPM_MAX 5050
#define CONFIG_FAN_POWER_GOOD GPIO_PP5000_PGOOD
#define CONFIG_PWM
#define CONFIG_PWM_KBLIGHT
#define CONFIG_TEMP_SENSOR
#define CONFIG_UART_HOST 2
@@ -177,6 +178,7 @@ enum x86_signal {
/* Number of X86 signals */
X86_SIGNAL_COUNT
};
enum adc_channel {
/* EC internal die temperature in degrees K. */
ADC_CH_EC_TEMP = 0,
@@ -187,6 +189,14 @@ enum adc_channel {
ADC_CH_COUNT
};
enum pwm_channel {
PWM_CH_FAN,
PWM_CH_KBLIGHT,
/* Number of PWM channels */
PWM_CH_COUNT
};
enum temp_sensor_id {
/* HEY - need two I2C sensor values, and put PECI first */

View File

@@ -23,6 +23,8 @@
#include "lm4_adc.h"
#include "peci.h"
#include "power_button.h"
#include "pwm.h"
#include "pwm_data.h"
#include "registers.h"
#include "switch.h"
#include "temp_sensor.h"
@@ -182,6 +184,12 @@ const struct adc_t adc_channels[] = {
};
BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
/* PWM channels */
const struct pwm_t pwm_channels[] = {
[PWM_CH_FAN] = {FAN_CH_CPU, PWM_CONFIG_HAS_RPM_MODE},
};
BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT);
/* I2C ports */
const struct i2c_port_t i2c_ports[] = {
/* Note: battery and charger share a port. Only include it once in

View File

@@ -18,14 +18,15 @@
#define CONFIG_CHIPSET_X86
#define CONFIG_EXTPOWER_FALCO
#define CONFIG_EXTPOWER_GPIO
#define CONFIG_FAN
#define CONFIG_FAN_RPM_MIN 1000
#define CONFIG_FAN_RPM_MAX 5050
#define CONFIG_FAN_POWER_GOOD GPIO_PP5000_PGOOD
#define CONFIG_KEYBOARD_BOARD_CONFIG
#define CONFIG_KEYBOARD_PROTOCOL_8042
#define CONFIG_POWER_BUTTON
#define CONFIG_POWER_BUTTON_X86
#define CONFIG_PWM_FAN
#define CONFIG_PWM_FAN_RPM_MIN 1000
#define CONFIG_PWM_FAN_RPM_MAX 5050
#define CONFIG_PWM_FAN_POWER_GOOD GPIO_PP5000_PGOOD
#define CONFIG_PWM
#define CONFIG_TEMP_SENSOR
#define CONFIG_TEMP_SENSOR_G781
#define CONFIG_UART_HOST 2
@@ -177,6 +178,13 @@ enum adc_channel {
ADC_CH_COUNT
};
enum pwm_channel {
PWM_CH_FAN,
/* Number of PWM channels */
PWM_CH_COUNT
};
enum temp_sensor_id {
/* CPU die temperature via PECI */
TEMP_SENSOR_CPU_PECI = 0,

View File

@@ -14,6 +14,7 @@
#define CONFIG_KEYBOARD_PROTOCOL_MKBP
#define CONFIG_POWER_BUTTON
#undef CONFIG_WATCHDOG
#define CONFIG_PWM
#undef CONFIG_CONSOLE_HISTORY
#define CONFIG_CONSOLE_HISTORY 4
@@ -53,4 +54,10 @@ enum adc_channel {
ADC_CH_COUNT
};
enum pwm_channel {
PWM_CH_FAN,
PWM_CH_COUNT
};
#endif /* __BOARD_H */

View File

@@ -20,6 +20,7 @@
#include "peci.h"
#include "power_button.h"
#include "pwm.h"
#include "pwm_data.h"
#include "registers.h"
#include "switch.h"
#include "temp_sensor.h"
@@ -181,6 +182,13 @@ const struct adc_t adc_channels[] = {
};
BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
/* PWM channels */
const struct pwm_t pwm_channels[] = {
[PWM_CH_FAN] = {FAN_CH_CPU, PWM_CONFIG_HAS_RPM_MODE},
[PWM_CH_KBLIGHT] = {FAN_CH_KBLIGHT, 0},
};
BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT);
/* I2C ports */
const struct i2c_port_t i2c_ports[] = {
/* Note: battery and charger share a port. Only include it once in

View File

@@ -18,6 +18,10 @@
#define CONFIG_CHIPSET_IVYBRIDGE
#define CONFIG_CHIPSET_X86
#define CONFIG_EXTPOWER_GPIO
#define CONFIG_FAN
#define CONFIG_FAN_RPM_MIN 1500
#define CONFIG_FAN_RPM_MAX 9300
#define CONFIG_FAN_POWER_GOOD GPIO_PGOOD_5VALW
#define CONFIG_I2C_PASSTHRU_RESTRICTED
#define CONFIG_KEYBOARD_BOARD_CONFIG
#define CONFIG_KEYBOARD_PROTOCOL_8042
@@ -25,10 +29,7 @@
#define CONFIG_ONEWIRE
#define CONFIG_POWER_BUTTON
#define CONFIG_POWER_BUTTON_X86
#define CONFIG_PWM_FAN
#define CONFIG_PWM_FAN_RPM_MIN 1500
#define CONFIG_PWM_FAN_RPM_MAX 9300
#define CONFIG_PWM_FAN_POWER_GOOD GPIO_PGOOD_5VALW
#define CONFIG_PWM
#define CONFIG_PWM_KBLIGHT
#define CONFIG_TEMP_SENSOR
#define CONFIG_TEMP_SENSOR_TMP006
@@ -64,6 +65,14 @@ enum adc_channel {
ADC_CH_COUNT
};
enum pwm_channel {
PWM_CH_FAN,
PWM_CH_KBLIGHT,
/* Number of PWM channels */
PWM_CH_COUNT
};
/* Charger module */
#define CONFIG_CHARGER_SENSE_RESISTOR 10 /* Charge sense resistor, mOhm */
#define CONFIG_CHARGER_SENSE_RESISTOR_AC 20 /* Input sensor resistor, mOhm */

View File

@@ -20,6 +20,8 @@
#include "lm4_adc.h"
#include "peci.h"
#include "power_button.h"
#include "pwm.h"
#include "pwm_data.h"
#include "registers.h"
#include "switch.h"
#include "temp_sensor.h"
@@ -172,6 +174,12 @@ const struct adc_t adc_channels[] = {
};
BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
/* PWM channels */
const struct pwm_t pwm_channels[] = {
[PWM_CH_FAN] = {FAN_CH_CPU, PWM_CONFIG_HAS_RPM_MODE},
};
BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT);
/* I2C ports */
const struct i2c_port_t i2c_ports[] = {
/* Note: battery and charger share a port. Only include it once in

View File

@@ -19,15 +19,16 @@
#define CONFIG_CHIPSET_HASWELL
#define CONFIG_CHIPSET_X86
#define CONFIG_EXTPOWER_GPIO
#define CONFIG_FAN
#define CONFIG_FAN_EN_GPIO GPIO_PP5000_FAN_EN
#define CONFIG_FAN_RPM_MIN 1000
#define CONFIG_FAN_RPM_MAX 5050
#define CONFIG_FAN_POWER_GOOD GPIO_PP5000_PGOOD
#define CONFIG_KEYBOARD_BOARD_CONFIG
#define CONFIG_KEYBOARD_PROTOCOL_8042
#define CONFIG_POWER_BUTTON
#define CONFIG_POWER_BUTTON_X86
#define CONFIG_PWM_FAN
#define CONFIG_PWM_FAN_EN_GPIO GPIO_PP5000_FAN_EN
#define CONFIG_PWM_FAN_RPM_MIN 1000
#define CONFIG_PWM_FAN_RPM_MAX 5050
#define CONFIG_PWM_FAN_POWER_GOOD GPIO_PP5000_PGOOD
#define CONFIG_PWM
#define CONFIG_TEMP_SENSOR
#define CONFIG_TEMP_SENSOR_G781
#define CONFIG_UART_HOST 2
@@ -181,6 +182,13 @@ enum adc_channel {
ADC_CH_COUNT
};
enum pwm_channel {
PWM_CH_FAN,
/* Number of PWM channels */
PWM_CH_COUNT
};
enum temp_sensor_id {
/* CPU die temperature via PECI */
TEMP_SENSOR_CPU_PECI = 0,

View File

@@ -13,6 +13,8 @@
#include "keyboard_raw.h"
#include "lid_switch.h"
#include "pmu_tpschrome.h"
#include "pwm.h"
#include "pwm_data.h"
#include "registers.h"
#include "spi.h"
#include "task.h"
@@ -107,6 +109,13 @@ const struct i2c_port_t i2c_ports[] = {
};
BUILD_ASSERT(ARRAY_SIZE(i2c_ports) == I2C_PORTS_USED);
/* PWM channels */
const struct pwm_t pwm_channels[] = {
[PWM_CH_POWER_LED] = {STM32_TIM(2), STM32_TIM_CH(3),
PWM_CONFIG_ACTIVE_LOW, GPIO_LED_POWER_L},
};
BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT);
int pmu_board_init(void)
{
int ver, failure = 0;

View File

@@ -21,6 +21,7 @@
#define CONFIG_PMU_POWERINFO
#define CONFIG_PMU_TPS65090
#define CONFIG_SPI
#define CONFIG_PWM
#ifndef __ASSEMBLER__
@@ -120,6 +121,12 @@ enum gpio_signal {
GPIO_COUNT
};
enum pwm_channel {
PWM_CH_POWER_LED = 0,
/* Number of PWM channels */
PWM_CH_COUNT
};
#endif /* !__ASSEMBLER__ */
#endif /* __BOARD_H */

View File

@@ -13,6 +13,8 @@
#include "keyboard_raw.h"
#include "lid_switch.h"
#include "pmu_tpschrome.h"
#include "pwm.h"
#include "pwm_data.h"
#include "registers.h"
#include "spi.h"
#include "task.h"
@@ -107,6 +109,13 @@ const struct i2c_port_t i2c_ports[] = {
};
BUILD_ASSERT(ARRAY_SIZE(i2c_ports) == I2C_PORTS_USED);
/* PWM channels */
const struct pwm_t pwm_channels[] = {
[PWM_CH_POWER_LED] = {STM32_TIM(2), STM32_TIM_CH(3),
PWM_CONFIG_ACTIVE_LOW, GPIO_LED_POWER_L},
};
BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT);
int pmu_board_init(void)
{
int ver, failure = 0;

View File

@@ -21,6 +21,7 @@
#define CONFIG_PMU_HARD_RESET
#define CONFIG_PMU_TPS65090
#define CONFIG_SPI
#define CONFIG_PWM
#ifndef __ASSEMBLER__
@@ -116,6 +117,12 @@ enum gpio_signal {
GPIO_COUNT
};
enum pwm_channel {
PWM_CH_POWER_LED = 0,
/* Number of PWM channels */
PWM_CH_COUNT
};
#endif /* !__ASSEMBLER__ */
#endif /* __BOARD_H */

View File

@@ -20,6 +20,8 @@
#include "lm4_adc.h"
#include "peci.h"
#include "power_button.h"
#include "pwm.h"
#include "pwm_data.h"
#include "registers.h"
#include "switch.h"
#include "temp_sensor.h"
@@ -172,6 +174,12 @@ const struct adc_t adc_channels[] = {
};
BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
/* PWM channels */
const struct pwm_t pwm_channels[] = {
[PWM_CH_FAN] = {FAN_CH_CPU, PWM_CONFIG_HAS_RPM_MODE},
};
BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT);
/* I2C ports */
const struct i2c_port_t i2c_ports[] = {
/* Note: battery and charger share a port. Only include it once in

View File

@@ -19,15 +19,16 @@
#define CONFIG_CHIPSET_HASWELL
#define CONFIG_CHIPSET_X86
#define CONFIG_EXTPOWER_GPIO
#define CONFIG_FAN
#define CONFIG_FAN_RPM_MIN 1000
#define CONFIG_FAN_RPM_MAX 5050
#define CONFIG_FAN_POWER_GOOD GPIO_PP5000_PGOOD
#define CONFIG_KEYBOARD_BOARD_CONFIG
#define CONFIG_KEYBOARD_PROTOCOL_8042
#define CONFIG_LED_SLIPPY
#define CONFIG_POWER_BUTTON
#define CONFIG_POWER_BUTTON_X86
#define CONFIG_PWM_FAN
#define CONFIG_PWM_FAN_RPM_MIN 1000
#define CONFIG_PWM_FAN_RPM_MAX 5050
#define CONFIG_PWM_FAN_POWER_GOOD GPIO_PP5000_PGOOD
#define CONFIG_PWM
#define CONFIG_TEMP_SENSOR
#define CONFIG_TEMP_SENSOR_G781
#define CONFIG_UART_HOST 2
@@ -175,6 +176,13 @@ enum adc_channel {
ADC_CH_COUNT
};
enum pwm_channel {
PWM_CH_FAN,
/* Number of PWM channels */
PWM_CH_COUNT
};
enum temp_sensor_id {
/* CPU die temperature via PECI */
TEMP_SENSOR_CPU_PECI = 0,

View File

@@ -17,6 +17,8 @@
#include "lid_switch.h"
#include "pmu_tpschrome.h"
#include "power_led.h"
#include "pwm.h"
#include "pwm_data.h"
#include "registers.h"
#include "spi.h"
#include "task.h"
@@ -120,6 +122,13 @@ const struct i2c_port_t i2c_ports[] = {
};
BUILD_ASSERT(ARRAY_SIZE(i2c_ports) == I2C_PORTS_USED);
/* PWM channels */
const struct pwm_t pwm_channels[] = {
[PWM_CH_POWER_LED] = {STM32_TIM(2), STM32_TIM_CH(2),
PWM_CONFIG_ACTIVE_LOW, GPIO_LED_POWER_L},
};
BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT);
void board_config_pre_init(void)
{
uint32_t val;

View File

@@ -28,6 +28,7 @@
#define CONFIG_KEYBOARD_SUPPRESS_NOISE
#define CONFIG_PMU_HARD_RESET
#define CONFIG_PMU_TPS65090
#define CONFIG_PWM
/* use STOP mode when we have nothing to do */
#define CONFIG_LOW_POWER_IDLE
@@ -120,6 +121,12 @@ enum gpio_signal {
GPIO_COUNT
};
enum pwm_channel {
PWM_CH_POWER_LED = 0,
/* Number of PWM channels */
PWM_CH_COUNT
};
#endif /* !__ASSEMBLER__ */
#endif /* __BOARD_H */

View File

@@ -19,6 +19,8 @@
#include "keyboard_raw.h"
#include "lid_switch.h"
#include "pmu_tpschrome.h"
#include "pwm.h"
#include "pwm_data.h"
#include "registers.h"
#include "stm32_adc.h"
#include "timer.h"
@@ -129,6 +131,13 @@ const struct adc_t adc_channels[] = {
};
BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
/* PWM channels */
const struct pwm_t pwm_channels[] = {
[PWM_CH_ILIM] = {STM32_TIM(3), STM32_TIM_CH(1), 0,
GPIO_ILIM},
};
BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT);
/* I2C ports */
const struct i2c_port_t i2c_ports[] = {
{"host", I2C_PORT_HOST, 100},

View File

@@ -33,6 +33,7 @@
#define CONFIG_PMU_HARD_RESET
#define CONFIG_PMU_TPS65090
#define CONFIG_USB_SWITCH_TSU6721
#define CONFIG_PWM
#ifndef __ASSEMBLER__
@@ -41,6 +42,7 @@
enum module_id {
MODULE_I2C,
MODULE_UART,
MODULE_EXTPOWER_USB,
};
/* By default, enable all console messages except keyboard */
@@ -73,6 +75,13 @@ enum adc_channel {
ADC_CH_COUNT
};
/* PWM signal */
enum pwm_channel {
PWM_CH_ILIM = 0,
/* Number of PWM channels */
PWM_CH_COUNT
};
/* GPIO signal list */
enum gpio_signal {
/* Inputs with interrupt handlers are first for efficiency */

View File

@@ -19,7 +19,8 @@ chip-$(CONFIG_FLASH)+=flash.o
chip-$(CONFIG_I2C)+=i2c.o
chip-$(CONFIG_LPC)+=lpc.o
chip-$(CONFIG_PECI)+=peci.o
chip-$(CONFIG_PWM_FAN)+=pwm_fan.o
chip-$(CONFIG_PWM)+=pwm.o
chip-$(CONFIG_FAN)+=fan.o
chip-$(CONFIG_PWM_KBLIGHT)+=pwm_kblight.o
chip-$(CONFIG_SPI)+=spi.o
chip-$(CONFIG_WATCHDOG)+=watchdog.o

View File

@@ -12,6 +12,7 @@
#include "gpio.h"
#include "hooks.h"
#include "host_command.h"
#include "pwm.h"
#include "registers.h"
#include "system.h"
#include "task.h"
@@ -37,15 +38,12 @@
static int fan_get_enabled(void)
{
return (LM4_FAN_FANCTL & (1 << FAN_CH_CPU)) ? 1 : 0;
return pwm_get_enabled(PWM_CH_FAN);
}
static void fan_set_enabled(int enable)
{
if (enable)
LM4_FAN_FANCTL |= (1 << FAN_CH_CPU);
else
LM4_FAN_FANCTL &= ~(1 << FAN_CH_CPU);
pwm_enable(PWM_CH_FAN, enable);
#ifdef CONFIG_PWM_FAN_EN_GPIO
gpio_set_level(CONFIG_PWM_FAN_EN_GPIO, enable);
@@ -98,16 +96,6 @@ static void fan_set_rpm_target(int rpm)
LM4_FAN_FANCMD(FAN_CH_CPU) = rpm;
}
static int fan_get_duty_raw(void)
{
return (LM4_FAN_FANCMD(FAN_CH_CPU) >> 16) & MAX_PWM;
}
static void fan_set_duty_raw(int pwm)
{
LM4_FAN_FANCMD(FAN_CH_CPU) = pwm << 16;
}
static int fan_get_status(void)
{
return (LM4_FAN_FANSTS >> (2 * FAN_CH_CPU)) & 0x03;
@@ -158,22 +146,8 @@ void pwm_fan_set_percent_needed(int pct)
fan_set_rpm_target(rpm);
}
static int fan_get_duty_cycle(void)
{
return fan_get_duty_raw() * 100 / MAX_PWM;
}
static void fan_set_duty_cycle(int percent)
{
int pwm;
if (percent < 0)
percent = 0;
else if (percent > 100)
percent = 100;
pwm = (MAX_PWM * percent) / 100;
/* Move the fan to manual control */
fan_set_rpm_mode(0);
@@ -184,7 +158,12 @@ static void fan_set_duty_cycle(int percent)
fan_set_thermal_control_enabled(0);
/* Set the duty cycle */
fan_set_duty_raw(pwm);
pwm_set_duty(PWM_CH_FAN, percent);
}
static int fan_get_duty_cycle(void)
{
return pwm_get_duty(PWM_CH_FAN);
}
/*****************************************************************************/
@@ -360,30 +339,8 @@ static void pwm_fan_init(void)
int version, size;
int i;
/* Enable the fan module and delay a few clocks */
LM4_SYSTEM_RCGCFAN = 1;
clock_wait_cycles(3);
/* Configure GPIOs */
gpio_config_module(MODULE_PWM_FAN, 1);
/* Disable all fans */
LM4_FAN_FANCTL = 0;
/*
* Configure CPU fan:
* 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(FAN_CH_CPU) = 0x802c;
prev = (const struct pwm_fan_state *)
system_get_jump_tag(PWMFAN_SYSJUMP_TAG, &version, &size);
if (prev && version == PWM_HOOK_VERSION && size == sizeof(*prev)) {
@@ -402,7 +359,7 @@ static void pwm_fan_init(void)
for (i = 0; i < EC_FAN_SPEED_ENTRIES; i++)
mapped[i] = EC_FAN_SPEED_NOT_PRESENT;
}
DECLARE_HOOK(HOOK_INIT, pwm_fan_init, HOOK_PRIO_DEFAULT);
DECLARE_HOOK(HOOK_INIT, pwm_fan_init, HOOK_PRIO_DEFAULT + 1);
static void pwm_fan_second(void)
{
@@ -449,7 +406,6 @@ static void pwm_fan_S3_S5(void)
*/
fan_set_rpm_target(0);
fan_set_enabled(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);

View File

@@ -401,7 +401,7 @@ static void handle_acpi_write(int is_cmd)
* good enough and less code than defining a new
* console command interface just for ACPI read/write.
*/
result = pwm_get_keyboard_backlight();
result = pwm_get_duty(PWM_CH_KBLIGHT);
break;
#endif
default:
@@ -427,7 +427,7 @@ static void handle_acpi_write(int is_cmd)
* debug console.
*/
CPRINTF("\r[%T ACPI kblight %d]", data);
pwm_set_keyboard_backlight(data);
pwm_set_duty(PWM_CH_KBLIGHT, data);
break;
#endif
default:

112
chip/lm4/pwm.c Normal file
View File

@@ -0,0 +1,112 @@
/* 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.
*/
/* PWM control module for LM4 */
#include "clock.h"
#include "gpio.h"
#include "hooks.h"
#include "pwm.h"
#include "pwm_data.h"
#include "registers.h"
#include "thermal.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);
}
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;
}
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;
duty = (MAX_PWM * percent) / 100;
/* Always enable the channel */
pwm_enable(ch, 1);
/* Set the duty cycle */
LM4_FAN_FANCMD(pwm->channel) = duty << 16;
}
int pwm_get_duty(enum pwm_channel ch)
{
const struct pwm_t *pwm = pwm_channels + ch;
return (LM4_FAN_FANCMD(pwm->channel) >> 16) * 100 / MAX_PWM;
}
static void pwm_init(void)
{
int i;
const struct pwm_t *pwm;
/* Enable the fan module and delay a few clocks */
LM4_SYSTEM_RCGCFAN = 1;
clock_wait_cycles(3);
/* 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;
}
}
}
DECLARE_HOOK(HOOK_INIT, pwm_init, HOOK_PRIO_DEFAULT);

21
chip/lm4/pwm_data.h Normal file
View File

@@ -0,0 +1,21 @@
/* 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 PWM module for Chrome EC */
#ifndef __CROS_EC_LM4_PWM_H
#define __CROS_EC_LM4_PWM_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[];
#endif /* __CROS_EC_LM4_PWM_H */

View File

@@ -31,35 +31,6 @@ struct pwm_kbd_state {
uint8_t pad0, pad1; /* Pad to multiple of 4 bytes. */
};
void pwm_enable_keyboard_backlight(int enable)
{
if (enable)
LM4_FAN_FANCTL |= (1 << FAN_CH_KBLIGHT);
else
LM4_FAN_FANCTL &= ~(1 << FAN_CH_KBLIGHT);
}
int pwm_get_keyboard_backlight_enabled(void)
{
return (LM4_FAN_FANCTL & (1 << FAN_CH_KBLIGHT)) ? 1 : 0;
}
int pwm_get_keyboard_backlight(void)
{
return ((LM4_FAN_FANCMD(FAN_CH_KBLIGHT) >> 16) * 100 +
MAX_PWM / 2) / MAX_PWM;
}
void pwm_set_keyboard_backlight(int percent)
{
if (percent < 0)
percent = 0;
else if (percent > 100)
percent = 100;
LM4_FAN_FANCMD(FAN_CH_KBLIGHT) = ((percent * MAX_PWM + 50) / 100) << 16;
}
/*****************************************************************************/
/* Console commands */
@@ -70,10 +41,10 @@ static int command_kblight(int argc, char **argv)
int i = strtoi(argv[1], &e, 0);
if (*e)
return EC_ERROR_PARAM1;
pwm_set_keyboard_backlight(i);
pwm_set_duty(PWM_CH_KBLIGHT, i);
}
ccprintf("Keyboard backlight: %d%%\n", pwm_get_keyboard_backlight());
ccprintf("Keyboard backlight: %d%%\n", pwm_get_duty(PWM_CH_KBLIGHT));
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(kblight, command_kblight,
@@ -88,8 +59,8 @@ int pwm_command_get_keyboard_backlight(struct host_cmd_handler_args *args)
{
struct ec_response_pwm_get_keyboard_backlight *r = args->response;
r->percent = pwm_get_keyboard_backlight();
r->enabled = pwm_get_keyboard_backlight_enabled();
r->percent = pwm_get_duty(PWM_CH_KBLIGHT);
r->enabled = pwm_get_enabled(PWM_CH_KBLIGHT);
args->response_size = sizeof(*r);
return EC_RES_SUCCESS;
@@ -102,7 +73,7 @@ int pwm_command_set_keyboard_backlight(struct host_cmd_handler_args *args)
{
const struct ec_params_pwm_set_keyboard_backlight *p = args->params;
pwm_set_keyboard_backlight(p->percent);
pwm_set_duty(PWM_CH_KBLIGHT, p->percent);
return EC_RES_SUCCESS;
}
@@ -118,39 +89,19 @@ static void pwm_kblight_init(void)
const struct pwm_kbd_state *prev;
int version, size;
/* Enable the fan module and delay a few clocks */
LM4_SYSTEM_RCGCFAN = 1;
clock_wait_cycles(3);
/* Configure GPIOs */
/* Configure GPIO */
gpio_config_module(MODULE_PWM_KBLIGHT, 1);
/* Disable all fans */
LM4_FAN_FANCTL = 0;
/*
* Configure keyboard backlight:
* 0x0000 = 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
* 0x0000 = bits 5:4 = average 4 edges when calculating RPM
* 0x0000 = bits 3:2 = 4 pulses per revolution
* 0x0001 = bit 0 = manual control
*/
LM4_FAN_FANCH(FAN_CH_KBLIGHT) = 0x0001;
prev = (const struct pwm_kbd_state *)
system_get_jump_tag(PWMKBD_SYSJUMP_TAG, &version, &size);
if (prev && version == PWM_HOOK_VERSION && size == sizeof(*prev)) {
/* Restore previous state. */
pwm_enable_keyboard_backlight(prev->kblight_en);
pwm_set_keyboard_backlight(prev->kblight_percent);
pwm_enable(PWM_CH_KBLIGHT, prev->kblight_en);
pwm_set_duty(PWM_CH_KBLIGHT, prev->kblight_percent);
} else {
/* Enable keyboard backlight control, turned down */
pwm_set_keyboard_backlight(0);
pwm_enable_keyboard_backlight(1);
pwm_set_duty(PWM_CH_KBLIGHT, 0);
pwm_enable(PWM_CH_KBLIGHT, 1);
}
}
DECLARE_HOOK(HOOK_INIT, pwm_kblight_init, HOOK_PRIO_DEFAULT);
@@ -159,8 +110,8 @@ static void pwm_kblight_preserve_state(void)
{
struct pwm_kbd_state state;
state.kblight_en = pwm_get_keyboard_backlight_enabled();
state.kblight_percent = pwm_get_keyboard_backlight();
state.kblight_en = pwm_get_enabled(PWM_CH_KBLIGHT);
state.kblight_percent = pwm_get_duty(PWM_CH_KBLIGHT);
system_add_jump_tag(PWMKBD_SYSJUMP_TAG, PWM_HOOK_VERSION,
sizeof(state), &state);
@@ -169,18 +120,18 @@ DECLARE_HOOK(HOOK_SYSJUMP, pwm_kblight_preserve_state, HOOK_PRIO_DEFAULT);
static void pwm_kblight_suspend(void)
{
pwm_set_keyboard_backlight(0);
pwm_set_duty(PWM_CH_KBLIGHT, 0);
}
DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, pwm_kblight_suspend, HOOK_PRIO_DEFAULT);
static void pwm_kblight_shutdown(void)
{
pwm_set_keyboard_backlight(0);
pwm_set_duty(PWM_CH_KBLIGHT, 0);
}
DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, pwm_kblight_shutdown, HOOK_PRIO_DEFAULT);
static void pwm_kblight_lid_change(void)
{
pwm_enable_keyboard_backlight(lid_is_open());
pwm_enable(PWM_CH_KBLIGHT, lid_is_open());
}
DECLARE_HOOK(HOOK_LID_CHANGE, pwm_kblight_lid_change, HOOK_PRIO_DEFAULT);

View File

@@ -18,3 +18,4 @@ chip-$(HAS_TASK_KEYSCAN)+=keyboard_raw.o
chip-$(HAS_TASK_POWERLED)+=power_led.o
chip-$(CONFIG_FLASH)+=flash-$(CHIP_FAMILY).o
chip-$(CONFIG_ADC)+=adc.o
chip-$(CONFIG_PWM)+=pwm.o

View File

@@ -21,6 +21,8 @@
#include "hooks.h"
#include "hwtimer.h"
#include "power_led.h"
#include "pwm.h"
#include "pwm_data.h"
#include "registers.h"
#include "task.h"
#include "timer.h"
@@ -32,7 +34,6 @@
static enum powerled_state led_state = POWERLED_STATE_ON;
static int power_led_percent = 100;
static int using_pwm;
void powerled_set_state(enum powerled_state new_state)
{
@@ -45,77 +46,18 @@ static void power_led_set_duty(int percent)
{
ASSERT((percent >= 0) && (percent <= 100));
power_led_percent = percent;
/*
* Set the duty cycle. CCRx = percent * ARR / 100. Since we set
* ARR=100, this is just percent.
*/
#ifdef BOARD_snow
STM32_TIM_CCR2(TIM_POWER_LED) = percent;
#else
STM32_TIM_CCR3(TIM_POWER_LED) = percent;
#endif
pwm_set_duty(PWM_CH_POWER_LED, percent);
}
static void power_led_use_pwm(void)
{
/* Configure power LED GPIO for TIM2/PWM alternate function */
#ifdef BOARD_snow
/* PB3 = TIM2_CH2 */
uint32_t val = STM32_GPIO_CRL(GPIO_B) & ~0x0000f000;
val |= 0x00009000; /* alt. function (TIM2/PWM) */
STM32_GPIO_CRL(GPIO_B) = val;
#else
gpio_config_module(MODULE_POWER_LED, 1);
#endif
/* Enable timer */
__hw_timer_enable_clock(TIM_POWER_LED, 1);
/* Disable counter during setup */
STM32_TIM_CR1(TIM_POWER_LED) = 0x0000;
/*
* CPU clock / PSC determines how fast the counter operates.
* ARR determines the wave period, CCRn determines duty cycle.
* Thus, frequency = cpu_freq / PSC / ARR. so:
*
* frequency = cpu_freq / (cpu_freq/10000) / 100 = 100 Hz.
*/
STM32_TIM_PSC(TIM_POWER_LED) = clock_get_freq() / 10000;
STM32_TIM_ARR(TIM_POWER_LED) = 100;
pwm_enable(PWM_CH_POWER_LED, 1);
power_led_set_duty(100);
#ifdef BOARD_snow
/* CC2 configured as output, PWM mode 1, preload enable */
STM32_TIM_CCMR1(TIM_POWER_LED) = (6 << 12) | (1 << 11);
/* CC2 output enable, active low */
STM32_TIM_CCER(TIM_POWER_LED) = (1 << 4) | (1 << 5);
#else
/* CC3 configured as output, PWM mode 1, preload enable */
STM32_TIM_CCMR2(TIM_POWER_LED) = (6 << 4) | (1 << 3);
/* CC3 output enable, active low */
STM32_TIM_CCER(TIM_POWER_LED) = (1 << 8) | (1 << 9);
#endif
/* Generate update event to force loading of shadow registers */
STM32_TIM_EGR(TIM_POWER_LED) |= 1;
/* Enable auto-reload preload, start counting */
STM32_TIM_CR1(TIM_POWER_LED) |= (1 << 7) | (1 << 0);
using_pwm = 1;
}
static void power_led_manual_off(void)
{
/* Disable counter */
STM32_TIM_CR1(TIM_POWER_LED) &= ~0x1;
/* Disable timer clock */
__hw_timer_enable_clock(TIM_POWER_LED, 0);
pwm_enable(PWM_CH_POWER_LED, 0);
/*
* Reconfigure GPIO as a floating input. Alternatively we could
@@ -128,8 +70,6 @@ static void power_led_manual_off(void)
#else
gpio_config_module(MODULE_POWER_LED, 0);
#endif
using_pwm = 0;
}
/**
@@ -166,17 +106,6 @@ static int power_led_step(void)
return state_timeout;
}
/**
* Handle clock frequency change
*/
static void power_led_freq_change(void)
{
/* If we're using PWM, re-initialize to adjust timer divisor */
if (using_pwm)
power_led_use_pwm();
}
DECLARE_HOOK(HOOK_FREQ_CHANGE, power_led_freq_change, HOOK_PRIO_DEFAULT);
void power_led_task(void)
{
while (1) {
@@ -189,21 +118,18 @@ void power_led_task(void)
* duty duty cycle of 100%. This produces a softer
* brightness than setting the GPIO to solid ON.
*/
if (!using_pwm)
power_led_use_pwm();
power_led_use_pwm();
power_led_set_duty(100);
state_timeout = -1;
break;
case POWERLED_STATE_OFF:
/* Reconfigure GPIO to disable the LED */
if (using_pwm)
power_led_manual_off();
power_led_manual_off();
state_timeout = -1;
break;
case POWERLED_STATE_SUSPEND:
/* Drive using PWM with variable duty cycle */
if (!using_pwm)
power_led_use_pwm();
power_led_use_pwm();
state_timeout = power_led_step();
break;
default:
@@ -214,6 +140,7 @@ void power_led_task(void)
}
}
#define CONFIG_CMD_POWERLED
#ifdef CONFIG_CMD_POWERLED
static int command_powerled(int argc, char **argv)
{

154
chip/stm32/pwm.c Normal file
View File

@@ -0,0 +1,154 @@
/* 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.
*/
/* PWM control module for STM32 */
#include "clock.h"
#include "gpio.h"
#include "hooks.h"
#include "hwtimer.h"
#include "pwm.h"
#include "pwm_data.h"
#include "registers.h"
#include "util.h"
static int using_pwm[PWM_CH_COUNT];
void pwm_set_duty(enum pwm_channel ch, int percent)
{
const struct pwm_t *pwm = pwm_channels + ch;
timer_ctlr_t *tim = (timer_ctlr_t *)(pwm->tim.base);
ASSERT((percent >= 0) && (percent <= 100));
tim->ccr[pwm->channel] = percent;
}
int pwm_get_duty(enum pwm_channel ch)
{
const struct pwm_t *pwm = pwm_channels + ch;
timer_ctlr_t *tim = (timer_ctlr_t *)(pwm->tim.base);
return tim->ccr[pwm->channel];
}
static void pwm_configure(enum pwm_channel ch)
{
const struct pwm_t *pwm = pwm_channels + ch;
const struct gpio_info *gpio = gpio_list + pwm->pin;
timer_ctlr_t *tim = (timer_ctlr_t *)(pwm->tim.base);
volatile unsigned *ccmr = NULL;
#ifdef CHIP_FAMILY_stm32f
int mask = gpio->mask;
volatile uint32_t *gpio_cr = NULL;
uint32_t val;
#endif
if (using_pwm[ch])
return;
#ifdef CHIP_FAMILY_stm32f
if (mask < 0x100) {
gpio_cr = &STM32_GPIO_CRL(gpio->port);
} else {
gpio_cr = &STM32_GPIO_CRH(gpio->port);
mask >>= 8;
}
/* Expand mask from 8-bit to 32-bit */
mask = mask * mask;
mask = mask * mask;
/* Set alternate function */
val = *gpio_cr & ~(mask * 0xf);
val |= mask * 0x9;
*gpio_cr = val;
#else /* stm32l */
gpio_set_alternate_function(gpio->port, gpio->mask,
GPIO_ALT_TIM(pwm->tim.id));
#endif
/* Enable timer */
__hw_timer_enable_clock(pwm->tim.id, 1);
/* Disable counter during setup */
tim->cr1 = 0x0000;
/*
* CPU clock / PSC determines how fast the counter operates.
* ARR determines the wave period, CCRn determines duty cycle.
* Thus, frequency = cpu_freq / PSC / ARR. so:
*
* frequency = cpu_freq / (cpu_freq/10000) / 100 = 100 Hz.
*/
tim->psc = clock_get_freq() / 10000;
tim->arr = 100;
if (pwm->channel <= 2) /* Channel ID starts from 1 */
ccmr = &tim->ccmr1;
else
ccmr = &tim->ccmr2;
/* Output, PWM mode 1, preload enable */
if (pwm->channel & 0x1)
*ccmr = (6 << 4) | (1 << 3);
else
*ccmr = (6 << 12) | (1 << 11);
/* Output enable. Set active high/low. */
if (pwm->flags & PWM_CONFIG_ACTIVE_LOW)
tim->ccer = 3 << (pwm->channel * 4 - 4);
else
tim->ccer = 1 << (pwm->channel * 4 - 4);
/* Generate update event to force loading of shadow registers */
tim->egr |= 1;
/* Enable auto-reload preload, start counting */
tim->cr1 |= (1 << 7) | (1 << 0);
using_pwm[ch] = 1;
}
static void pwm_disable(enum pwm_channel ch)
{
const struct pwm_t *pwm = pwm_channels + ch;
timer_ctlr_t *tim = (timer_ctlr_t *)(pwm->tim.base);
if (using_pwm[ch] == 0)
return;
/* Disable counter */
tim->cr1 &= ~0x1;
/* Disable timer clock */
__hw_timer_enable_clock(pwm->tim.id, 0);
using_pwm[ch] = 0;
}
void pwm_enable(enum pwm_channel ch, int enabled)
{
if (enabled)
pwm_configure(ch);
else
pwm_disable(ch);
}
static void pwm_reconfigure(enum pwm_channel ch)
{
using_pwm[ch] = 0;
pwm_configure(ch);
}
/**
* Handle clock frequency change
*/
static void pwm_freq_change(void)
{
int i;
for (i = 0; i < PWM_CH_COUNT; ++i)
if (using_pwm[i])
pwm_reconfigure(i);
}
DECLARE_HOOK(HOOK_FREQ_CHANGE, pwm_freq_change, HOOK_PRIO_DEFAULT);

37
chip/stm32/pwm_data.h Normal file
View File

@@ -0,0 +1,37 @@
/* 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.
*/
/* STM32-specific PWM module for Chrome EC */
#ifndef __CROS_EC_STM32_PWM_H
#define __CROS_EC_STM32_PWM_H
/* Data structure to define PWM channels. */
struct pwm_t {
/*
* Timer powering the PWM channel. Must use STM32_TIM(x) to
* initialize
*/
struct {
int id;
uintptr_t base;
} tim;
/* Channel ID within the timer */
int channel;
/* PWM channel flags. See include/pwm.h */
uint32_t flags;
/* GPIO pin corresponding to the PWM channel */
enum gpio_signal pin;
};
extern const struct pwm_t pwm_channels[];
/* Macro to fill in both timer ID and register base */
#define STM32_TIM(x) {x, STM32_TIM_BASE(x)}
/* Plain ID mapping for readability */
#define STM32_TIM_CH(x) (x)
#endif /* __CROS_EC_STM32_PWM_H */

View File

@@ -145,8 +145,10 @@
#define STM32_TIM16_BASE 0x40014400 /* STM32F100 only */
#define STM32_TIM17_BASE 0x40014800 /* STM32F100 only */
#define STM32_TIM_BASE(n) CONCAT3(STM32_TIM, n, _BASE)
#define STM32_TIM_REG(n, offset) \
REG16(CONCAT3(STM32_TIM, n, _BASE) + (offset))
REG16(STM32_TIM_BASE(n) + (offset))
#define STM32_TIM_CR1(n) STM32_TIM_REG(n, 0x00)
#define STM32_TIM_CR2(n) STM32_TIM_REG(n, 0x04)
@@ -186,12 +188,8 @@ struct timer_ctlr {
unsigned psc;
unsigned arr;
unsigned reserved30;
unsigned ccr1;
unsigned ccr2;
unsigned ccr3;
unsigned ccr[5]; /* ccr[0] = reserved30 */
unsigned ccr4;
unsigned reserved44;
unsigned dcr;
unsigned dmar;
@@ -235,6 +233,7 @@ typedef volatile struct timer_ctlr timer_ctlr_t;
#define GPIO_ALT_TIM2 0x1
#define GPIO_ALT_TIM3_4 0x2
#define GPIO_ALT_TIM9_11 0x3
#define GPIO_ALT_TIM(x) (((x) > 5) ? 0x3 : ((x) / 3 + 1))
#define GPIO_ALT_I2C 0x4
#define GPIO_ALT_SPI 0x5
#define GPIO_ALT_USART 0x7

View File

@@ -54,7 +54,7 @@ common-$(CONFIG_ONEWIRE)+=onewire.o
common-$(CONFIG_POWER_BUTTON)+=power_button.o
common-$(CONFIG_POWER_BUTTON_X86)+=power_button_x86.o
common-$(CONFIG_PSTORE)+=pstore_commands.o
common-$(CONFIG_PWM_FAN)+=pwm_fan.o
common-$(CONFIG_FAN)+=pwm_fan.o
common-$(CONFIG_REGULATOR_IR357X)+=regulator_ir357x.o
common-$(CONFIG_SWITCH)+=switch.o
common-$(CONFIG_WIRELESS)+=wireless.o

View File

@@ -15,6 +15,7 @@
#include "host_command.h"
#include "keyboard_protocol.h"
#include "pmu_tpschrome.h"
#include "pwm.h"
#include "registers.h"
#include "smart_battery.h"
#include "stm32_adc.h"
@@ -181,56 +182,10 @@ static void set_video_power(int enabled)
static void ilim_use_gpio(void)
{
/* Disable counter */
STM32_TIM_CR1(3) &= ~0x1;
/* Disable TIM3 clock */
STM32_RCC_APB1ENR &= ~0x2;
/* Switch to GPIO */
pwm_enable(PWM_CH_ILIM, 0);
gpio_set_flags(GPIO_ILIM, GPIO_OUTPUT);
}
static void ilim_use_pwm(void)
{
uint32_t val;
/* Config alt. function (TIM3/PWM) */
val = STM32_GPIO_CRL(GPIO_B) & ~0x000f0000;
val |= 0x00090000;
STM32_GPIO_CRL(GPIO_B) = val;
/* Enable TIM3 clock */
STM32_RCC_APB1ENR |= 0x2;
/* Disable counter during setup */
STM32_TIM_CR1(3) = 0x0000;
/*
* CPU_CLOCK / (PSC + 1) determines how fast the counter operates.
* ARR determines the wave period, CCRn determines duty cycle.
* Thus, frequency = CPU_CLOCK / (PSC + 1) / ARR.
*
* Assuming 16MHz clock and ARR=100, PSC needed to achieve PWM_FREQUENCY
* is: PSC = CPU_CLOCK / PWM_FREQUENCY / ARR - 1
*/
STM32_TIM_PSC(3) = CPU_CLOCK / PWM_FREQUENCY / 100 - 1; /* pre-scaler */
STM32_TIM_ARR(3) = 100; /* auto-reload value */
STM32_TIM_CCR1(3) = 100; /* duty cycle */
/* CC1 configured as output, PWM mode 1, preload enable */
STM32_TIM_CCMR1(3) = (6 << 4) | (1 << 3);
/* CC1 output enable, active high */
STM32_TIM_CCER(3) = (1 << 0);
/* Generate update event to force loading of shadow registers */
STM32_TIM_EGR(3) |= 1;
/* Enable auto-reload preload, start counting */
STM32_TIM_CR1(3) |= (1 << 7) | (1 << 0);
}
/**
* Set ILIM pin control type.
*/
@@ -248,7 +203,7 @@ static void ilim_config(enum ilim_config config)
config == ILIM_CONFIG_MANUAL_ON ? 1 : 0);
break;
case ILIM_CONFIG_PWM:
ilim_use_pwm();
pwm_enable(PWM_CH_ILIM, 1);
break;
default:
break;
@@ -360,7 +315,7 @@ static void set_pwm_duty_cycle(int percent)
percent = 0;
if (percent > 100)
percent = 100;
STM32_TIM_CCR1(3) = (percent * STM32_TIM_ARR(3)) / 100;
pwm_set_duty(PWM_CH_ILIM, percent);
current_pwm_duty = percent;
}
@@ -936,7 +891,8 @@ static int command_ilim(int argc, char **argv)
else if (current_ilim_config == ILIM_CONFIG_MANUAL_OFF)
ccprintf("ILIM is GPIO low\n");
else
ccprintf("ILIM is PWM duty cycle %d%%\n", STM32_TIM_CCR1(3));
ccprintf("ILIM is PWM duty cycle %d%%\n",
pwm_get_duty(PWM_CH_ILIM));
return EC_SUCCESS;
}
@@ -957,7 +913,7 @@ static int command_batdebug(int argc, char **argv)
* 17000 / 1024);
ccprintf("IBAT = %d mA\n", pmu_adc_read(ADC_IBAT, 0)
* (1000 / R_BATTERY_MOHM) * 40 / 1024);
ccprintf("PWM = %d%%\n", STM32_TIM_CCR1(3));
ccprintf("PWM = %d%%\n", pwm_get_duty(PWM_CH_ILIM));
battery_current(&val);
ccprintf("Battery Current = %d mA\n", val);
battery_voltage(&val);

View File

@@ -295,8 +295,8 @@ static void get_battery_level(void)
* when ambient is bright), use max brightness for lightbar. If
* keyboard backlight is ON, use keyboard backlight brightness.
*/
if (pwm_get_keyboard_backlight_enabled()) {
pct = pwm_get_keyboard_backlight();
if (pwm_get_enabled(PWM_CH_KBLIGHT)) {
pct = pwm_get_duty(PWM_CH_KBLIGHT);
pct = (255 * pct) / 100; /* 00 - FF */
if (pct > st.p.bright_bl_on_max[st.battery_is_charging])
pct = st.p.bright_bl_on_max[st.battery_is_charging];

View File

@@ -6,7 +6,7 @@
#include "common.h"
#include "fan.h"
#ifndef CONFIG_PWM_FAN_RPM_CUSTOM
#ifndef CONFIG_FAN_RPM_CUSTOM
/* This is the default implementation. It's only called over [0,100].
* Convert the percentage to a target RPM. We can't simply scale all
* the way down to zero because most fans won't turn that slowly, so
@@ -19,8 +19,8 @@ int pwm_fan_percent_to_rpm(int pct)
if (!pct)
rpm = 0;
else
rpm = ((pct - 1) * CONFIG_PWM_FAN_RPM_MAX +
(100 - pct) * CONFIG_PWM_FAN_RPM_MIN) / 99;
rpm = ((pct - 1) * CONFIG_FAN_RPM_MAX +
(100 - pct) * CONFIG_FAN_RPM_MIN) / 99;
return rpm;
}

View File

@@ -282,6 +282,30 @@
*/
#undef CONFIG_EXTPOWER_USB
/*****************************************************************************/
/* Compile support for PWM control of cooling fans */
#undef CONFIG_FAN
/* Name of active high GPIO to control power to the cooling fan */
#undef CONFIG_FAN_EN_GPIO
/* Fan speeds corresponding to 1% and 100% cooling (0% == off). */
#undef CONFIG_FAN_RPM_MIN
#undef CONFIG_FAN_RPM_MAX
/* Alternately, define this to replace the default mapping with your own
* board-specific function in board.c:
*
* int pwm_fan_percent_to_rpm(int pct);
*
*/
#undef CONFIG_FAN_RPM_CUSTOM
/* If you define this, the "faninfo" console command will read the GPIO to
* display the state of the fan's power rail.
*/
#undef CONFIG_FAN_POWER_GOOD
/*****************************************************************************/
/* Flash configuration */
@@ -466,28 +490,8 @@
#undef CONFIG_PSTORE
/*****************************************************************************/
/* Compile support for PWM control of cooling fans */
#undef CONFIG_PWM_FAN
/* Name of active high GPIO to control power to the cooling fan */
#undef CONFIG_PWM_FAN_EN_GPIO
/* Fan speeds corresponding to 1% and 100% cooling (0% == off). */
#undef CONFIG_PWM_FAN_RPM_MIN
#undef CONFIG_PWM_FAN_RPM_MAX
/* Alternately, define this to replace the default mapping with your own
* board-specific function in board.c:
*
* int pwm_fan_percent_to_rpm(int pct);
*
*/
#undef CONFIG_PWM_FAN_RPM_CUSTOM
/* If you define this, the "faninfo" console command will read the GPIO to
* display the state of the fan's power rail.
*/
#undef CONFIG_PWM_FAN_POWER_GOOD
/* Compile support for PWM control */
#undef CONFIG_PWM
/*****************************************************************************/
/* Compile support for PWM output to keyboard backlight */

View File

@@ -7,28 +7,36 @@
#define __CROS_EC_PWM_H
/**
* Set the fan PWM duty cycle (0-100), disabling the automatic control.
* Enable/disable a PWM channel.
*/
void pwm_set_fan_duty(int percent);
void pwm_enable(enum pwm_channel ch, int enabled);
/**
* Enable/disable the keyboard backlight.
* Get PWM channel enabled status.
*/
void pwm_enable_keyboard_backlight(int enable);
int pwm_get_enabled(enum pwm_channel ch);
/**
* Get the keyboard backlight enable/disable status (1=enabled, 0=disabled).
* Set PWM channel duty cycle (0-100).
*/
int pwm_get_keyboard_backlight_enabled(void);
void pwm_set_duty(enum pwm_channel ch, int percent);
/**
* Get the keyboard backlight percentage (0=off, 100=max).
* Get PWM channel duty cycle.
*/
int pwm_get_keyboard_backlight(void);
int pwm_get_duty(enum pwm_channel ch);
/* Flags for PWM config table */
/**
* Set the keyboard backlight percentage (0=off, 100=max).
* PWM output signal is inverted, so 100% duty means always low
*/
void pwm_set_keyboard_backlight(int percent);
#define PWM_CONFIG_ACTIVE_LOW (1 << 0)
/**
* PWM channel has a fan controller with a tach input and can auto-adjust
* its duty cycle to produce a given fan RPM.
*/
#define PWM_CONFIG_HAS_RPM_MODE (1 << 1)
#endif /* __CROS_EC_PWM_H */