diff options
author | Mulin Chao <mlchao@nuvoton.com> | 2015-09-19 08:59:29 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2015-09-29 21:11:41 -0700 |
commit | 7e7dd8cd1aa232e2790ddfe09bffbe908f3d0230 (patch) | |
tree | 5aa2e13b38519396e04b5ca679ccaac071dab50b /chip/npcx/pwm.c | |
parent | dbef9a6fed88c78795a5060dead823978394cf6f (diff) | |
download | chrome-ec-7e7dd8cd1aa232e2790ddfe09bffbe908f3d0230.tar.gz |
nuc: Simplify adc/pwm/fan drivers and related structures in boards
Modified drivers:
1. register.h: Add marco field operation funcs for muti-bits field of register.
2. adc.c/fan.c/pwm.c: Simplify field operations by marco funcs.
3. adc.c: Add support for ADC_CH3/4
4. pwm.c: Add PWM_CONFIG_DSLEEP_CLK flag
6. fan.c: Support multi-fans mechanism
BUG=chrome-os-partner:34346
TEST=make buildall -j; test nuvoton IC specific drivers
BRANCH=none
Change-Id: Iaaeb6c4ae8d55b4245a1cefb9c20feae4c0fdec2
Reviewed-on: https://chromium-review.googlesource.com/300673
Commit-Ready: Mulin Chao <mlchao@nuvoton.com>
Tested-by: Mulin Chao <mlchao@nuvoton.com>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Diffstat (limited to 'chip/npcx/pwm.c')
-rw-r--r-- | chip/npcx/pwm.c | 193 |
1 files changed, 78 insertions, 115 deletions
diff --git a/chip/npcx/pwm.c b/chip/npcx/pwm.c index 4a8ba4dace..d89ff365c3 100644 --- a/chip/npcx/pwm.c +++ b/chip/npcx/pwm.c @@ -30,7 +30,7 @@ enum npcx_pwm_source_clock { NPCX_PWM_CLOCK_APB2_LFCLK = 0, NPCX_PWM_CLOCK_FX = 1, NPCX_PWM_CLOCK_FR = 2, - NPCX_PWM_CLOCK_RESERVED = 0x3, + NPCX_PWM_CLOCK_RESERVED = 3, NPCX_PWM_CLOCK_UNDEF = 0xFF }; @@ -43,53 +43,53 @@ enum npcx_pwm_heartbeat_mode { NPCX_PWM_HBM_UNDEF = 0xFF }; -/* Global variables */ -static int pwm_init_ch; +/* Default duty cycle resolution */ +#define DUTY_CYCLE_RESOLUTION 100 /** - * Preset PWM operation clock. + * Set PWM operation clock. * - * @param none - * @return none - * @notes changed when initial or HOOK_FREQ_CHANGE command + * @param ch operation channel + * @param freq desired PWM frequency + * @param res resolution for duty cycle + * @notes changed when initialization */ -void pwm_freq_changed(void) +void pwm_set_freq(enum pwm_channel ch, uint32_t freq, uint32_t res) { + int mdl = pwm_channels[ch].channel; uint32_t prescaler_divider = 0; + uint32_t clock; /* Disable PWM for module configuration */ - pwm_enable(pwm_init_ch, 0); - - if (pwm_init_ch == PWM_CH_FAN) { - /* - * Using PWM Frequency and Resolution we calculate - * prescaler for input clock - */ -#ifdef NPCX_PWM_INPUT_LFCLK - prescaler_divider = (uint32_t)(32768 / - (pwm_channels[pwm_init_ch].freq) - /(pwm_channels[pwm_init_ch].cycle_pulses)); -#else - prescaler_divider = (uint32_t)( - clock_get_apb2_freq() / pwm_channels[pwm_init_ch].freq - / (pwm_channels[pwm_init_ch].cycle_pulses)); -#endif - } else { - prescaler_divider = (uint32_t)( - clock_get_apb2_freq() / pwm_channels[pwm_init_ch].freq - / (pwm_channels[pwm_init_ch].cycle_pulses)); - } - /* Set clock prescalre divider to ADC module*/ + pwm_enable(ch, 0); + + /* Get PWM clock frequency */ + if (pwm_channels[ch].flags & PWM_CONFIG_DSLEEP_CLK) + clock = INT_32K_CLOCK; + else + clock = clock_get_apb2_freq(); + + /* + * Using PWM Frequency and Resolution we calculate + * prescaler for input clock + */ + prescaler_divider = ((clock / freq)/res); + + /* Set clock prescaler divider to PWM module*/ if (prescaler_divider >= 1) prescaler_divider = prescaler_divider - 1; if (prescaler_divider > 0xFFFF) prescaler_divider = 0xFFFF; /* Configure computed prescaler and resolution */ - NPCX_PRSC(pwm_channels[pwm_init_ch].channel) = - (uint16_t)prescaler_divider; + NPCX_PRSC(mdl) = (uint16_t)prescaler_divider - 1; + + /* Set PWM cycle time */ + NPCX_CTR(mdl) = res - 1; + + /* Set the duty cycle to 0% since DCR > CTR */ + NPCX_DCR(mdl) = res; } -DECLARE_HOOK(HOOK_FREQ_CHANGE, pwm_freq_changed, HOOK_PRIO_DEFAULT); /** * Set PWM enabled. @@ -100,12 +100,9 @@ DECLARE_HOOK(HOOK_FREQ_CHANGE, pwm_freq_changed, HOOK_PRIO_DEFAULT); */ void pwm_enable(enum pwm_channel ch, int enabled) { + int mdl = pwm_channels[ch].channel; /* Start or close PWM module */ - if (enabled) - SET_BIT(NPCX_PWMCTL(pwm_channels[ch].channel), NPCX_PWMCTL_PWR); - else - CLEAR_BIT(NPCX_PWMCTL(pwm_channels[ch].channel), - NPCX_PWMCTL_PWR); + UPDATE_BIT(NPCX_PWMCTL(mdl), NPCX_PWMCTL_PWR, enabled); } /** @@ -116,8 +113,8 @@ void pwm_enable(enum pwm_channel ch, int enabled) */ int pwm_get_enabled(enum pwm_channel ch) { - return IS_BIT_SET(NPCX_PWMCTL(pwm_channels[ch].channel), - NPCX_PWMCTL_PWR); + int mdl = pwm_channels[ch].channel; + return IS_BIT_SET(NPCX_PWMCTL(mdl), NPCX_PWMCTL_PWR); } /** @@ -129,37 +126,38 @@ int pwm_get_enabled(enum pwm_channel ch) */ void pwm_set_duty(enum pwm_channel ch, int percent) { - uint32_t resolution = 0; - uint16_t duty_cycle = 0; - - CPRINTS("pwm0=%d", percent); - /* Assume the fan control is active high and invert it ourselves */ - if (pwm_channels[ch].flags & PWM_CONFIG_ACTIVE_LOW) - SET_BIT(NPCX_PWMCTL(pwm_channels[ch].channel), - NPCX_PWMCTL_INVP); - else - CLEAR_BIT(NPCX_PWMCTL(pwm_channels[ch].channel), - NPCX_PWMCTL_INVP); + int mdl = pwm_channels[ch].channel; + uint32_t dc_res = 0; + uint16_t dc_cnt = 0; + /* Checking duty value first */ if (percent < 0) percent = 0; else if (percent > 100) percent = 100; - CPRINTS("pwm1duty=%d", percent); + CPRINTS("pwm%d, set duty=%d", mdl, percent); - resolution = NPCX_CTR(pwm_channels[ch].channel) + 1; - duty_cycle = percent*resolution/100; + /* Assume the fan control is active high and invert it ourselves */ + UPDATE_BIT(NPCX_PWMCTL(mdl), NPCX_PWMCTL_INVP, + (pwm_channels[ch].flags & PWM_CONFIG_ACTIVE_LOW)); + + dc_res = NPCX_CTR(mdl) + 1; + dc_cnt = (percent*dc_res)/100; CPRINTS("freq=0x%x", pwm_channels[ch].freq); - CPRINTS("resolution=%d", resolution); - CPRINTS("duty_cycle=%d", duty_cycle); - if (percent*resolution > (duty_cycle*100)) - duty_cycle += 1; + CPRINTS("duty_cycle_res=%d", dc_res); + CPRINTS("duty_cycle_cnt=%d", dc_cnt); + + /* Set the duty cycle */ - if (duty_cycle > 0) { - NPCX_DCR(pwm_channels[ch].channel) = (duty_cycle - 1); + if (percent > 0) { + if (percent == 100) + NPCX_DCR(mdl) = NPCX_CTR(mdl); + else + NPCX_DCR(mdl) = (dc_cnt - 1); pwm_enable(ch, 1); } else { - NPCX_DCR(pwm_channels[ch].channel) = resolution; + /* Output low since DCR > CTR */ + NPCX_DCR(mdl) = NPCX_CTR(mdl) + 1; pwm_enable(ch, 0); } } @@ -172,74 +170,45 @@ void pwm_set_duty(enum pwm_channel ch, int percent) */ int pwm_get_duty(enum pwm_channel ch) { + int mdl = pwm_channels[ch].channel; /* Return percent */ - if ((0 == pwm_get_enabled(ch)) || (NPCX_DCR(pwm_channels[ch].channel) - > NPCX_CTR(pwm_channels[ch].channel))) + if ((!pwm_get_enabled(ch)) || (NPCX_DCR(mdl) > NPCX_CTR(mdl))) return 0; else - return (((NPCX_DCR(pwm_channels[ch].channel) + 1) * 100) - / (NPCX_CTR(pwm_channels[ch].channel) + 1)); + return ((NPCX_DCR(mdl) + 1) * 100) / (NPCX_CTR(mdl) + 1); } /** * PWM configuration. * - * @param ch operation channel + * @param ch operation channel * @return none */ void pwm_config(enum pwm_channel ch) { - pwm_init_ch = ch; - - /* Configure pins from GPIOs to PWM */ - if (ch == PWM_CH_FAN) - gpio_config_module(MODULE_PWM_FAN, 1); - else - gpio_config_module(MODULE_PWM_KBLIGHT, 1); + int mdl = pwm_channels[ch].channel; /* Disable PWM for module configuration */ - pwm_enable(ch, 0); + pwm_enable(mdl, 0); - /* Set PWM heartbeat mode is no heartbeat*/ - NPCX_PWMCTL(pwm_channels[ch].channel) = - (NPCX_PWMCTL(pwm_channels[ch].channel) - & (~(((1<<2)-1) << NPCX_PWMCTL_HB_DC_CTL))) - | (NPCX_PWM_HBM_NORMAL << NPCX_PWMCTL_HB_DC_CTL); + /* Set PWM heartbeat mode is no heartbeat */ + SET_FIELD(NPCX_PWMCTL(mdl), NPCX_PWMCTL_HB_DC_CTL_FIELD, + NPCX_PWM_HBM_NORMAL); - /* Set PWM operation frequence */ - pwm_freq_changed(); + /* Select default CLK or LFCLK clock input to PWM module */ + SET_FIELD(NPCX_PWMCTLEX(mdl), NPCX_PWMCTLEX_FCK_SEL_FIELD, + NPCX_PWM_CLOCK_APB2_LFCLK); - /* Set PWM cycle time */ - NPCX_CTR(pwm_channels[ch].channel) = - (pwm_channels[ch].cycle_pulses - 1); + /* Set PWM polarity normal first */ + CLEAR_BIT(NPCX_PWMCTL(mdl), NPCX_PWMCTL_INVP); - /* Set the duty cycle */ - NPCX_DCR(pwm_channels[ch].channel) = pwm_channels[ch].cycle_pulses; + /* Select PWM clock source */ + UPDATE_BIT(NPCX_PWMCTL(mdl), NPCX_PWMCTL_CKSEL, + (pwm_channels[ch].flags & PWM_CONFIG_DSLEEP_CLK)); - /* Set PWM polarity is normal*/ - CLEAR_BIT(NPCX_PWMCTL(pwm_channels[ch].channel), NPCX_PWMCTL_INVP); + /* Set PWM operation frequency */ + pwm_set_freq(ch, pwm_channels[ch].freq, DUTY_CYCLE_RESOLUTION); - /* Select default CLK or LFCLK clock input to PWM module */ - NPCX_PWMCTLEX(pwm_channels[ch].channel) = - (NPCX_PWMCTLEX(pwm_channels[ch].channel) - & (~(((1<<2)-1)<<NPCX_PWMCTLEX_FCK_SEL))) - | (NPCX_PWM_CLOCK_APB2_LFCLK<<NPCX_PWMCTLEX_FCK_SEL); - - if (ch == PWM_CH_FAN) { -#ifdef NPCX_PWM_INPUT_LFCLK - /* Select default LFCLK clock input to PWM module */ - SET_BIT(NPCX_PWMCTL(pwm_channels[ch].channel), - NPCX_PWMCTL_CKSEL); -#else - /* Select default core clock input to PWM module */ - CLEAR_BIT(NPCX_PWMCTL(pwm_channels[ch].channel), - NPCX_PWMCTL_CKSEL); -#endif - } else { - /* Select default core clock input to PWM module */ - CLEAR_BIT(NPCX_PWMCTL(pwm_channels[ch].channel), - NPCX_PWMCTL_CKSEL); - } } /** @@ -252,14 +221,8 @@ static void pwm_init(void) { int i; -#ifdef CONFIG_PWM_DSLEEP /* Enable the PWM module and delay a few clocks */ clock_enable_peripheral(CGC_OFFSET_PWM, CGC_PWM_MASK, CGC_MODE_ALL); -#else - /* Enable the PWM module and delay a few clocks */ - clock_enable_peripheral(CGC_OFFSET_PWM, CGC_PWM_MASK, - CGC_MODE_RUN | CGC_MODE_SLEEP); -#endif for (i = 0; i < PWM_CH_COUNT; i++) pwm_config(i); |