/** * Get PWM duty cycle. * * @param ch operation channel * @return duty cycle percent */ int pwm_get_duty(enum pwm_channel ch) { int mdl = pwm_channels[ch].channel; /* Return percent */ if ((!pwm_get_enabled(ch)) || (NPCX_DCR(mdl) > NPCX_CTR(mdl))) return 0; else return ((NPCX_DCR(mdl) + 1) * 100) / (NPCX_CTR(mdl) + 1); }
/** * PWM configuration. * * @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); /* Disable PWM for module configuration */ pwm_enable(ch, 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 operation frequence */ pwm_freq_changed(); /* Set PWM cycle time */ NPCX_CTR(pwm_channels[ch].channel) = (pwm_channels[ch].cycle_pulses - 1); /* Set the duty cycle */ NPCX_DCR(pwm_channels[ch].channel) = 0; /* Set PWM polarity is normal*/ CLEAR_BIT(NPCX_PWMCTL(pwm_channels[ch].channel), NPCX_PWMCTL_INVP); /* Set PWM open drain output is push-pull type*/ CLEAR_BIT(NPCX_PWMCTL(pwm_channels[ch].channel), NPCX_PWMCTLEX_OD_OUT); /* 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 CONFIG_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); } }
/** * Get PWM duty cycle. * * @param ch operation channel * @return duty cycle percent */ int pwm_get_duty(enum pwm_channel ch) { /* Return percent */ if (0 == pwm_get_enabled(ch)) return 0; else return (((NPCX_DCR(pwm_channels[ch].channel) + 1) * 100) / (NPCX_CTR(pwm_channels[ch].channel) + 1)); }
/** * Set PWM duty cycle. * * @param ch operation channel * @param percent duty cycle percent * @return none */ void pwm_set_duty(enum pwm_channel ch, int percent) { 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("pwm%d, set duty=%d", mdl, percent); /* 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("duty_cycle_res=%d", dc_res); CPRINTS("duty_cycle_cnt=%d", dc_cnt); /* Set the duty cycle */ if (percent > 0) { if (percent == 100) NPCX_DCR(mdl) = NPCX_CTR(mdl); else NPCX_DCR(mdl) = (dc_cnt - 1); pwm_enable(ch, 1); } else { /* Output low since DCR > CTR */ NPCX_DCR(mdl) = NPCX_CTR(mdl) + 1; pwm_enable(ch, 0); } }
/** * Set PWM duty cycle. * * @param ch operation channel * @param percent duty cycle percent * @return none */ 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); if (percent < 0) percent = 0; /* (Benson_TBD_14) if 100% make mft cannot get TCRB, * it will need to change to 99% */ else if (percent > 100) percent = 100; CPRINTS("pwm1duty=%d", percent); resolution = NPCX_CTR(pwm_channels[ch].channel) + 1; duty_cycle = percent*resolution/100; CPRINTS("freq=0x%x", pwm_channels[ch].freq); CPRINTS("resolution=%d", resolution); CPRINTS("duty_cycle=%d", duty_cycle); /* Set the duty cycle */ /* (Benson_TBD_14) Always enable the fan channel or not */ if (percent) { NPCX_DCR(pwm_channels[ch].channel) = (duty_cycle - 1); pwm_enable(ch, 1); } else { NPCX_DCR(pwm_channels[ch].channel) = 0; pwm_enable(ch, 0); } }
/** * Set PWM operation clock. * * @param ch operation channel * @param freq desired PWM frequency * @param res resolution for duty cycle * @notes changed when initialization */ 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(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(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; }