diff --git a/board/npcx_evb/board.c b/board/npcx_evb/board.c index 3e438bb6b0..e5b70d7f7d 100644 --- a/board/npcx_evb/board.c +++ b/board/npcx_evb/board.c @@ -36,43 +36,17 @@ /******************************************************************************/ /* ADC channels. Must be in the exactly same order as in enum adc_channel. */ const struct adc_t adc_channels[] = { - [ADC_CH_0] = {"ADC0", NPCX_ADC_INPUT_CH0, ADC_MAX_VOLT, - ADC_READ_MAX+1, 0}, - [ADC_CH_1] = {"ADC1", NPCX_ADC_INPUT_CH1, ADC_MAX_VOLT, - ADC_READ_MAX+1, 0}, - [ADC_CH_2] = {"ADC2", NPCX_ADC_INPUT_CH2, ADC_MAX_VOLT, - ADC_READ_MAX+1, 0}, + [ADC_CH_0] = {"ADC0", NPCX_ADC_CH0, ADC_MAX_VOLT, ADC_READ_MAX+1, 0}, + [ADC_CH_1] = {"ADC1", NPCX_ADC_CH1, ADC_MAX_VOLT, ADC_READ_MAX+1, 0}, + [ADC_CH_2] = {"ADC2", NPCX_ADC_CH2, ADC_MAX_VOLT, ADC_READ_MAX+1, 0}, }; BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT); /******************************************************************************/ /* PWM channels. Must be in the exactly same order as in enum pwm_channel. */ const struct pwm_t pwm_channels[] = { - [PWM_CH_FAN] = { - .channel = 0, - /* - * flags can reverse the PWM output signal according to - * the board design - */ - .flags = PWM_CONFIG_ACTIVE_LOW, - /* - * freq_operation = freq_input / prescaler_divider - * freq_output = freq_operation / cycle_pulses - * and freq_output <= freq_mft - */ - .freq = 34, - /* - * cycle_pulses = (cycle_pulses * freq_output) * - * RPM_EDGES * RPM_SCALE * 60 / poles / rpm_min - */ - .cycle_pulses = 480, - }, - [PWM_CH_KBLIGHT] = { - .channel = 1, - .flags = 0, - .freq = 10000, - .cycle_pulses = 100, - }, + [PWM_CH_FAN] = { 0, PWM_CONFIG_ACTIVE_LOW | PWM_CONFIG_DSLEEP_CLK, 100}, + [PWM_CH_KBLIGHT] = { 1, 0, 10000 }, }; BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT); @@ -84,7 +58,7 @@ const struct fan_t fans[] = { .rpm_min = 1020, .rpm_start = 1020, .rpm_max = 8190, - .ch = 0,/* Use PWM/MFT to control fan */ + .ch = 0,/* Use MFT id to control fan */ .pgood_gpio = GPIO_PGOOD_FAN, .enable_gpio = -1, }, @@ -94,16 +68,7 @@ BUILD_ASSERT(ARRAY_SIZE(fans) == FAN_CH_COUNT); /******************************************************************************/ /* MFT channels. These are logically separate from mft_channels. */ const struct mft_t mft_channels[] = { - [MFT_CH_0] = { - .module = NPCX_MFT_MODULE_1, - .port = NPCX_MFT_MODULE_PORT_TA, - .default_count = 0xFFFF, -#ifdef NPCX_MFT_INPUT_LFCLK - .freq = 32768, -#else - .freq = 2000000, -#endif - }, + [MFT_CH_0] = { NPCX_MFT_MODULE_1, 0xFFFF, TCKC_LFCLK, PWM_CH_FAN}, }; BUILD_ASSERT(ARRAY_SIZE(mft_channels) == MFT_CH_COUNT); diff --git a/board/npcx_evb/board.h b/board/npcx_evb/board.h index fd0ff65e75..316ca3ede7 100644 --- a/board/npcx_evb/board.h +++ b/board/npcx_evb/board.h @@ -10,7 +10,6 @@ /* Optional modules */ #define CONFIG_ADC -#define CONFIG_PECI #define CONFIG_PWM #define CONFIG_SPI #define CONFIG_LPC /* Used in Intel-based platform for host interface */ @@ -41,8 +40,6 @@ #define CONFIG_FANS 1 /* Optional feature - used by nuvoton */ -#define NPCX_PWM_INPUT_LFCLK /* PWM use LFCLK for input clock */ -#define NPCX_MFT_INPUT_LFCLK /* MFT use LFCLK for input clock */ #define NPCX_UART_MODULE2 0 /* 0:GPIO10/11 1:GPIO64/65 as UART */ #define NPCX_JTAG_MODULE2 0 /* 0:GPIO21/17/16/20 1:GPIOD5/E2/D4/E5 as JTAG*/ #define NPCX_TACH_SEL2 0 /* 0:GPIO40/A4 1:GPIO93/D3 as TACH */ diff --git a/board/npcx_evb/gpio.inc b/board/npcx_evb/gpio.inc index 7c7ae2f10d..027855620b 100644 --- a/board/npcx_evb/gpio.inc +++ b/board/npcx_evb/gpio.inc @@ -62,9 +62,12 @@ ALTERNATE(PIN_MASK(4, 0x38), 1, MODULE_ADC, 0) /* ADC ALTERNATE(PIN_MASK(A, 0x0A), 1, MODULE_SPI, 0) /* SPIP_MOSI/SPIP_SCLK GPIOA3/A1 */ ALTERNATE(PIN_MASK(9, 0x20), 1, MODULE_SPI, 0) /* SPIP_MISO GPIO95 */ ALTERNATE(PIN_MASK(C, 0x04), 3, MODULE_PWM_KBLIGHT, 0) /* PWM1 for PWM/KBLIGHT Test GPIOC2 */ +/* Alternative functionality for FANS */ +#ifdef CONFIG_FANS ALTERNATE(PIN_MASK(C, 0x08), 7, MODULE_PWM_FAN, 0) /* PWM0 for PWM/FAN Test GPIOC3 */ #if NPCX_TACH_SEL2 ALTERNATE(PIN_MASK(9, 0x08), 3, MODULE_PWM_FAN, 0) /* MFT-1/TA1_TACH1 for FAN GPIO93 */ #else ALTERNATE(PIN_MASK(4, 0x01), 3, MODULE_PWM_FAN, 0) /* MFT-1/TA1_TACH1 for FAN Test GPIO40 */ #endif +#endif diff --git a/board/npcx_evb_arm/board.c b/board/npcx_evb_arm/board.c index 6661ff6e11..037e3d82e5 100644 --- a/board/npcx_evb_arm/board.c +++ b/board/npcx_evb_arm/board.c @@ -36,43 +36,17 @@ /******************************************************************************/ /* ADC channels. Must be in the exactly same order as in enum adc_channel. */ const struct adc_t adc_channels[] = { - [ADC_CH_0] = {"ADC0", NPCX_ADC_INPUT_CH0, ADC_MAX_VOLT, - ADC_READ_MAX+1, 0}, - [ADC_CH_1] = {"ADC1", NPCX_ADC_INPUT_CH1, ADC_MAX_VOLT, - ADC_READ_MAX+1, 0}, - [ADC_CH_2] = {"ADC2", NPCX_ADC_INPUT_CH2, ADC_MAX_VOLT, - ADC_READ_MAX+1, 0}, + [ADC_CH_0] = {"ADC0", NPCX_ADC_CH0, ADC_MAX_VOLT, ADC_READ_MAX+1, 0}, + [ADC_CH_1] = {"ADC1", NPCX_ADC_CH1, ADC_MAX_VOLT, ADC_READ_MAX+1, 0}, + [ADC_CH_2] = {"ADC2", NPCX_ADC_CH2, ADC_MAX_VOLT, ADC_READ_MAX+1, 0}, }; BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT); /******************************************************************************/ /* PWM channels. Must be in the exactly same order as in enum pwm_channel. */ const struct pwm_t pwm_channels[] = { - [PWM_CH_FAN] = { - .channel = 0, - /* - * flags can reverse the PWM output signal according to - * the board design - */ - .flags = PWM_CONFIG_ACTIVE_LOW, - /* - * freq_operation = freq_input / prescaler_divider - * freq_output = freq_operation / cycle_pulses - * and freq_output <= freq_mft - */ - .freq = 34, - /* - * cycle_pulses = (cycle_pulses * freq_output) * - * RPM_EDGES * RPM_SCALE * 60 / poles / rpm_min - */ - .cycle_pulses = 480, - }, - [PWM_CH_KBLIGHT] = { - .channel = 1, - .flags = 0, - .freq = 10000, - .cycle_pulses = 100, - }, + [PWM_CH_FAN] = { 0, PWM_CONFIG_ACTIVE_LOW | PWM_CONFIG_DSLEEP_CLK, 100}, + [PWM_CH_KBLIGHT] = { 1, 0, 10000 }, }; BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT); @@ -84,7 +58,7 @@ const struct fan_t fans[] = { .rpm_min = 1020, .rpm_start = 1020, .rpm_max = 8190, - .ch = 0,/* Use PWM/MFT to control fan */ + .ch = 0,/* Use MFT id to control fan */ .pgood_gpio = GPIO_PGOOD_FAN, .enable_gpio = -1, }, @@ -94,16 +68,7 @@ BUILD_ASSERT(ARRAY_SIZE(fans) == FAN_CH_COUNT); /******************************************************************************/ /* MFT channels. These are logically separate from mft_channels. */ const struct mft_t mft_channels[] = { - [MFT_CH_0] = { - .module = NPCX_MFT_MODULE_1, - .port = NPCX_MFT_MODULE_PORT_TA, - .default_count = 0xFFFF, -#ifdef NPCX_MFT_INPUT_LFCLK - .freq = 32768, -#else - .freq = 2000000, -#endif - }, + [MFT_CH_0] = { NPCX_MFT_MODULE_1, 0xFFFF, TCKC_LFCLK, PWM_CH_FAN}, }; BUILD_ASSERT(ARRAY_SIZE(mft_channels) == MFT_CH_COUNT); diff --git a/board/npcx_evb_arm/board.h b/board/npcx_evb_arm/board.h index 1a8c85ea93..b455f40473 100644 --- a/board/npcx_evb_arm/board.h +++ b/board/npcx_evb_arm/board.h @@ -37,13 +37,12 @@ #define CONFIG_FANS 1 /* Optional feature - used by nuvoton */ -#define NPCX_PWM_INPUT_LFCLK /* PWM use LFCLK for input clock */ -#define NPCX_MFT_INPUT_LFCLK /* MFT use LFCLK for input clock */ #define NPCX_UART_MODULE2 0 /* 0:GPIO10/11 1:GPIO64/65 as UART */ #define NPCX_JTAG_MODULE2 0 /* 0:GPIO21/17/16/20 1:GPIOD5/E2/D4/E5 as JTAG*/ #define NPCX_TACH_SEL2 0 /* 0:GPIO40/A4 1:GPIO93/D3 as TACH */ /* Optional for testing */ +#undef CONFIG_PECI #undef CONFIG_PSTORE #undef CONFIG_LOW_POWER_IDLE /* Deep Sleep Support */ diff --git a/board/npcx_evb_arm/gpio.inc b/board/npcx_evb_arm/gpio.inc index 18d50564ff..1d1667ba06 100644 --- a/board/npcx_evb_arm/gpio.inc +++ b/board/npcx_evb_arm/gpio.inc @@ -20,7 +20,7 @@ GPIO_INT(LID_OPEN, PIN(3, 3), GPIO_PULL_DOWN | GPIO_INT_BOTH, lid_interr GPIO(ENTERING_RW, PIN(3, 6), GPIO_OUT_LOW) /* Indicate when EC is entering RW code */ GPIO(PCH_WAKE_L, PIN(5, 0), GPIO_OUT_HIGH) /* Wake signal output to PCH */ /* For testing keyboard mkbp */ -GPIO(EC_INT_L, PIN(7, 4), GPIO_ODR_HIGH) /* Interrupt pin for keyboard mkbp */ +GPIO(EC_INT_L, PIN(7, 4), GPIO_ODR_HIGH) /* Interrupt pin for keyboard mkbp */ /* Used for module testing */ GPIO(PGOOD_FAN, PIN(C, 7), GPIO_PULL_UP | GPIO_INPUT) /* Power Good for FAN test */ @@ -63,9 +63,12 @@ ALTERNATE(PIN_MASK(4, 0x38), 1, MODULE_ADC, 0) /* ADC ALTERNATE(PIN_MASK(A, 0x0A), 1, MODULE_SPI, 0) /* SPIP_MOSI/SPIP_SCLK GPIOA3/A1 */ ALTERNATE(PIN_MASK(9, 0x20), 1, MODULE_SPI, 0) /* SPIP_MISO GPIO95 */ ALTERNATE(PIN_MASK(C, 0x04), 3, MODULE_PWM_KBLIGHT, 0) /* PWM1 for PWM/KBLIGHT Test GPIOC2 */ +/* Alternative functionality for FANS */ +#ifdef CONFIG_FANS ALTERNATE(PIN_MASK(C, 0x08), 7, MODULE_PWM_FAN, 0) /* PWM0 for PWM/FAN Test GPIOC3 */ #if NPCX_TACH_SEL2 ALTERNATE(PIN_MASK(9, 0x08), 3, MODULE_PWM_FAN, 0) /* MFT-1/TA1_TACH1 for FAN GPIO93 */ #else ALTERNATE(PIN_MASK(4, 0x01), 3, MODULE_PWM_FAN, 0) /* MFT-1/TA1_TACH1 for FAN Test GPIO40 */ #endif +#endif diff --git a/chip/npcx/adc.c b/chip/npcx/adc.c index 9d498be555..ba80162f45 100644 --- a/chip/npcx/adc.c +++ b/chip/npcx/adc.c @@ -33,13 +33,6 @@ enum npcx_adc_conversion_mode { ADC_SCAN_CONVERSION_MODE = 1 }; -/* ADC repetitive mode */ -enum npcx_adc_repetitive_mode { - ADC_ONE_SHOT_CONVERSION_TYPE = 0, - ADC_REPETITIVE_CONVERSION_TYPE = 1 -}; - - /* Global variables */ static task_id_t task_waiting; @@ -62,8 +55,7 @@ void adc_freq_changed(void) prescaler_divider = 0x3F; /* Set Core Clock Division Factor in order to obtain the ADC clock */ - NPCX_ATCTL = (NPCX_ATCTL & (~(((1<<6)-1)<>NPCX_CHNDAT_CHDAT) & ((1<<10)-1); + return GET_FIELD(NPCX_CHNDAT(input_ch), NPCX_CHNDAT_CHDAT_FIELD); } /** @@ -94,16 +86,14 @@ static int start_single_and_wait(enum npcx_adc_input_channel input_ch task_waiting = task_get_current(); /* Set ADC conversion code to SW conversion mode */ - NPCX_ADCCNF = (NPCX_ADCCNF & (~(((1<<2)-1)<input_ch, ADC_TIMEOUT_US)) { if ((adc->input_ch == - ((NPCX_ASCADD>>NPCX_ASCADD_SADDR)&((1<<5)-1))) + GET_FIELD(NPCX_ASCADD, NPCX_ASCADD_SADDR_FIELD)) && (IS_BIT_SET(NPCX_CHNDAT(adc->input_ch), NPCX_CHNDAT_NEW))) { value = get_channel_data(adc->input_ch) * @@ -223,8 +213,9 @@ static void adc_init(void) adc_freq_changed(); /* Set regular speed */ - NPCX_ATCTL = (NPCX_ATCTL & (~(((1<<3)-1)< 0) ? (TACH_TO_RPM(ch, tacho)) : 0; } /** - * Preset fan operation clock. + * Set fan prescaler based on apb1 clock * * @param none * @return none * @notes changed when initial or HOOK_FREQ_CHANGE command */ -#ifndef NPCX_MFT_INPUT_LFCLK -void mft_freq_changed(void) +void mft_set_apb1_prescaler(int ch) { - uint16_t prescaler_divider = 0; - int mft_ch = fan_op_ch(fan_init_ch, NPCX_FAN_OP_MFT); + int mdl = mft_channels[ch].module; + uint16_t prescaler_divider = 0; /* Set clock prescaler divider to MFT module*/ prescaler_divider = (uint16_t)(clock_get_apb1_freq() - /mft_channels[mft_ch].freq); + / fan_status[ch].mft_freq); if (prescaler_divider >= 1) prescaler_divider = prescaler_divider - 1; if (prescaler_divider > 0xFF) prescaler_divider = 0xFF; - NPCX_TPRSC(mft_channels[mft_ch].module) = (uint8_t)prescaler_divider; + NPCX_TPRSC(mdl) = (uint8_t) prescaler_divider; } -DECLARE_HOOK(HOOK_FREQ_CHANGE, mft_freq_changed, HOOK_PRIO_DEFAULT); -#endif /** * Fan configuration. @@ -227,116 +165,88 @@ DECLARE_HOOK(HOOK_FREQ_CHANGE, mft_freq_changed, HOOK_PRIO_DEFAULT); */ static void fan_config(int ch, int enable_mft_read_rpm) { - int pwm_ch = fan_op_ch(ch, NPCX_FAN_OP_PWM); - int mft_ch = fan_op_ch(ch, NPCX_FAN_OP_MFT); - - fan_init_ch = ch; - pwm_config(pwm_ch); + int mdl = mft_channels[ch].module; + int pwm_id = mft_channels[ch].pwm_id; + enum npcx_mft_clk_src clk_src = mft_channels[ch].clk_src; + volatile struct fan_status_t *p_status = fan_status + ch; /* Configure pins from GPIOs to FAN */ gpio_config_module(MODULE_PWM_FAN, 1); - if (enable_mft_read_rpm) { - /* Set mode 5 to MFT module*/ - NPCX_TMCTRL(mft_channels[mft_ch].module) = - (NPCX_TMCTRL(mft_channels[mft_ch].module) - & (~(((1<<3)-1)<mft_freq = INT_32K_CLOCK; + else if (clk_src == TCKC_PRESCALE_APB1_CLK) + p_status->mft_freq = clock_get_apb1_freq(); + else + p_status->mft_freq = 0; + + /* Set mode 5 to MFT module*/ + SET_FIELD(NPCX_TMCTRL(mdl), NPCX_TMCTRL_MDSEL_FIELD, + NPCX_MFT_MDSEL_5); + + /* Set MFT operation frequency */ + if (clk_src == TCKC_PRESCALE_APB1_CLK) + mft_set_apb1_prescaler(ch); + + /* Set the low power mode or not. */ + UPDATE_BIT(NPCX_TCKC(mdl), NPCX_TCKC_LOW_PWR, + clk_src == TCKC_LFCLK); + + /* Set the default count-down timer. */ + NPCX_TCNT1(mdl) = mft_channels[ch].default_count; + NPCX_TCRA(mdl) = mft_channels[ch].default_count; + + /* Set the edge polarity to rising. */ + SET_BIT(NPCX_TMCTRL(mdl), NPCX_TMCTRL_TAEDG); + /* Enable capture TCNT1 into TCRA and preset TCNT1. */ + SET_BIT(NPCX_TMCTRL(mdl), NPCX_TMCTRL_TAEN); + /* Enable input debounce logic into TA. */ + SET_BIT(NPCX_TCFG(mdl), NPCX_TCFG_TADBEN); + + /* Set the no clock to TCNT1. */ + SET_FIELD(NPCX_TCKC(mdl), NPCX_TCKC_C1CSEL_FIELD, + TCKC_NOCLK); + /* Set timer wake-up enable */ + SET_BIT(NPCX_TWUEN(mdl), NPCX_TWUEN_TAWEN); + SET_BIT(NPCX_TWUEN(mdl), NPCX_TWUEN_TCWEN); -#ifndef NPCX_MFT_INPUT_LFCLK - /* Set MFT operation frequence */ - mft_freq_changed(); - /* Set the active power mode. */ - CLEAR_BIT(NPCX_TCKC(mft_channels[mft_ch].module), - NPCX_TCKC_LOW_PWR); -#else - /* Set the low power mode. */ - SET_BIT(NPCX_TCKC(mft_channels[mft_ch].module), - NPCX_TCKC_LOW_PWR); -#endif - if (NPCX_MFT_MODULE_PORT_TB == mft_channels[mft_ch].port) { - /* Set the default count-down timer. */ - NPCX_TCNT2(mft_channels[mft_ch].module) = - mft_channels[mft_ch].default_count; - NPCX_TCRB(mft_channels[mft_ch].module) = - mft_channels[mft_ch].default_count; - /* Set the edge polarity to rising. */ - SET_BIT(NPCX_TMCTRL(mft_channels[mft_ch].module), - NPCX_TMCTRL_TBEDG); - /* Enable capture TCNT2 into TCRB and preset TCNT2. */ - SET_BIT(NPCX_TMCTRL(mft_channels[mft_ch].module), - NPCX_TMCTRL_TBEN); - /* Enable input debounce logic into TB. */ - SET_BIT(NPCX_TCFG(mft_channels[mft_ch].module), - NPCX_TCFG_TBDBEN); - /* Set the no clock to TCNT2. */ - NPCX_TCKC(mft_channels[mft_ch].module) = - (NPCX_TCKC(mft_channels[mft_ch].module) - & (~(((1<<3)-1)<cur_state = TACHO_IN_IDLE; } /** - * Set fan enabled. + * Get percentage of duty cycle from rpm * * @param ch operation channel - * @param enabled enabled flag + * @param rpm target rpm * @return none */ -void fan_set_enabled(int ch, int enabled) +int fan_rpm_to_percent(int ch, int rpm) { - int pwm_ch = fan_op_ch(ch, NPCX_FAN_OP_PWM); + int pct, max, min; - pwm_enable(pwm_ch, enabled); + if (!rpm) { + pct = 0; + } else { + min = fans[ch].rpm_min; + max = fans[ch].rpm_max; + pct = (99*rpm + max - 100*min) / (max-min); + } + + return pct; } -/** - * Check fan enabled. - * - * @param ch operation channel - * @return enabled or not - */ -int fan_get_enabled(int ch) -{ - int pwm_ch = fan_op_ch(ch, NPCX_FAN_OP_PWM); - - return pwm_get_enabled(pwm_ch); -} +/*****************************************************************************/ +/* IC specific low-level driver */ /** * Set fan duty cycle. @@ -347,12 +257,15 @@ int fan_get_enabled(int ch) */ void fan_set_duty(int ch, int percent) { - int pwm_ch = fan_op_ch(ch, NPCX_FAN_OP_PWM); + int pwm_id = mft_channels[ch].pwm_id; CPRINTS("set duty percent=%d", percent); + /* Set the duty cycle of PWM */ + pwm_set_duty(pwm_id, percent); - /* Set the duty cycle */ - pwm_set_duty(pwm_ch, percent); + /* Start measurement again */ + if (percent != 0 && fan_status[ch].cur_state == TACHO_UNDERFLOW) + fan_status[ch].cur_state = TACHO_IN_IDLE; } /** @@ -363,12 +276,11 @@ void fan_set_duty(int ch, int percent) */ int fan_get_duty(int ch) { - int pwm_ch = fan_op_ch(ch, NPCX_FAN_OP_PWM); + int pwm_id = mft_channels[ch].pwm_id; /* Return percent */ - return pwm_get_duty(pwm_ch); + return pwm_get_duty(pwm_id); } - /** * Check fan is rpm operation mode. * @@ -403,59 +315,44 @@ void fan_set_rpm_mode(int ch, int rpm_mode) */ int fan_get_rpm_actual(int ch) { - int mft_ch = fan_op_ch(ch, NPCX_FAN_OP_MFT); - uint8_t capture_pnd = NPCX_TECTRL_TBPND, - underflow_pnd = NPCX_TECTRL_TDPND; - uint8_t capture_clr = NPCX_TECLR_TBCLR, - underflow_clr = NPCX_TECLR_TDCLR; + int mdl = mft_channels[ch].module; + volatile struct fan_status_t *p_status = fan_status + ch; - /* Init pending/clear flag bit */ - if (NPCX_MFT_MODULE_PORT_TA == mft_channels[mft_ch].port) { - capture_pnd = NPCX_TECTRL_TAPND; - underflow_pnd = NPCX_TECTRL_TCPND; - capture_clr = NPCX_TECLR_TACLR; - underflow_clr = NPCX_TECLR_TCCLR; - } - /* Start measure and return previous value when fan is working*/ + /* Start measure and return previous value when fan is working */ if ((fan_get_enabled(ch)) && (fan_get_duty(ch))) { - if ((tacho_status.cur_state == TACHO_IN_IDLE) - || (pre_duty != fan_get_duty(ch))) { + if (p_status->cur_state == TACHO_IN_IDLE) { CPRINTS("mft_startmeasure"); - if ((0 == rpm_actual) || (-1 == rpm_actual)) - rpm_actual = fans[ch].rpm_min; + if (p_status->rpm_actual <= 0) + p_status->rpm_actual = fans[ch].rpm_min; /* Clear all pending flags */ - NPCX_TECLR(mft_channels[mft_ch].module) = - NPCX_TECTRL(mft_channels[mft_ch].module); + NPCX_TECLR(mdl) = NPCX_TECTRL(mdl); /* Start from first edge state */ - tacho_status.cur_state = TACHO_WAIT_FOR_1_EDGE; + p_status->cur_state = TACHO_WAIT_FOR_1_EDGE; /* Start measure */ - mft_startmeasure(ch); + mft_start_measure(ch); } /* Check whether MFT underflow flag is occurred */ - else if (IS_BIT_SET(NPCX_TECTRL(mft_channels[mft_ch].module), - underflow_pnd)) { + else if (IS_BIT_SET(NPCX_TECTRL(mdl), NPCX_TECTRL_TCPND)) { /* Measurement is active - stop the measurement */ - mft_stopmeasure(fan_init_ch); + mft_stop_measure(ch); /* Need to avoid underflow state happen */ - rpm_actual = 0; + p_status->rpm_actual = 0; /* * Flag TDPND means mft underflow happen, * but let MFT still can re-measure actual rpm * when user change pwm/fan duty during * TACHO_UNDERFLOW state. */ - tacho_status.cur_state = TACHO_UNDERFLOW; + p_status->cur_state = TACHO_UNDERFLOW; CPRINTS("TACHO_UNDERFLOW"); /* Clear pending flags */ - SET_BIT(NPCX_TECLR(mft_channels[mft_ch].module), - underflow_clr); + SET_BIT(NPCX_TECLR(mdl), NPCX_TECLR_TCCLR); } /* Check whether MFT signal detection flag is occurred */ - else if (IS_BIT_SET(NPCX_TECTRL(mft_channels[mft_ch].module), - capture_pnd)) { + else if (IS_BIT_SET(NPCX_TECTRL(mdl), NPCX_TECTRL_TAPND)) { /* Start of tacho cycle is detected */ - switch (tacho_status.cur_state) { + switch (p_status->cur_state) { case TACHO_WAIT_FOR_1_EDGE: CPRINTS("TACHO_WAIT_FOR_1_EDGE"); /* @@ -463,44 +360,61 @@ int fan_get_rpm_actual(int ch) * and wait for the second tacho cycle * (second edge) */ - tacho_status.cur_state = TACHO_WAIT_FOR_2_EDGE; + p_status->cur_state = TACHO_WAIT_FOR_2_EDGE; /* Send previous rpm before complete measure */ break; case TACHO_WAIT_FOR_2_EDGE: - /* Complete measure tach and get actual tach */ - mft_finalmeasure(fan_init_ch); + /* Complete measure tacho and get actual rpm */ + p_status->rpm_actual = mft_final_measure(ch); /* Stop the measurement */ - mft_stopmeasure(ch); - /* Transfer actual tach to actual rpm */ - rpm_actual = (tacho_status.edge_interval > 0) ? - (TACH_TO_RPM(mft_ch, - tacho_status.edge_interval)) : 0; + mft_stop_measure(ch); + /* Back to Idle mode*/ - tacho_status.cur_state = TACHO_IN_IDLE; + p_status->cur_state = TACHO_IN_IDLE; CPRINTS("TACHO_WAIT_FOR_2_EDGE"); - CPRINTS("edge_interval=%x", - tacho_status.edge_interval); - CPRINTS("rpm_actual=%d", rpm_actual); + CPRINTS("rpm_actual=%d", p_status->rpm_actual); break; default: break; } /* Clear pending flags */ - SET_BIT(NPCX_TECLR(mft_channels[mft_ch].module), - capture_clr); + SET_BIT(NPCX_TECLR(mdl), NPCX_TECLR_TACLR); } } else { CPRINTS("preset rpm"); /* Send preset rpm before fan is working */ if (fan_get_enabled(ch)) - rpm_actual = fans[ch].rpm_min; + p_status->rpm_actual = fans[ch].rpm_min; else - rpm_actual = 0; + p_status->rpm_actual = 0; - tacho_status.cur_state = TACHO_IN_IDLE; + p_status->cur_state = TACHO_IN_IDLE; } - pre_duty = fan_get_duty(ch); - return rpm_actual; + return p_status->rpm_actual; +} + +/** + * Check fan enabled. + * + * @param ch operation channel + * @return enabled or not + */ +int fan_get_enabled(int ch) +{ + int pwm_id = mft_channels[ch].pwm_id; + return pwm_get_enabled(pwm_id); +} +/** + * Set fan enabled. + * + * @param ch operation channel + * @param enabled enabled flag + * @return none + */ +void fan_set_enabled(int ch, int enabled) +{ + int pwm_id = mft_channels[ch].pwm_id; + pwm_enable(pwm_id, enabled); } /** @@ -511,7 +425,7 @@ int fan_get_rpm_actual(int ch) */ int fan_get_rpm_target(int ch) { - return rpm_target; + return fan_status[ch].rpm_target; } /** @@ -523,23 +437,18 @@ int fan_get_rpm_target(int ch) */ void fan_set_rpm_target(int ch, int rpm) { - uint32_t percent = 0; - int pwm_ch = fan_op_ch(ch, NPCX_FAN_OP_PWM); + int percent = 0; - rpm_target = rpm; - /* Transfer rpm to tach then calculate percentage */ - percent = (RPM_TO_TACH(pwm_ch, rpm_target)*100) - /(pwm_channels[pwm_ch].cycle_pulses); + fan_status[ch].rpm_target = rpm; + /* Transfer rpm to percentage of duty cycle */ + percent = fan_rpm_to_percent(ch, rpm); if (percent < 0) percent = 0; else if (percent > 100) percent = 100; - /* RPM is inverse ratio to tach and percentage */ - percent = 100 - percent; - - pwm_set_duty(pwm_ch, percent); + fan_set_duty(ch, percent); } /** @@ -604,13 +513,7 @@ void fan_channel_setup(int ch, unsigned int flags) */ static void fan_init(void) { -#ifdef CONFIG_PWM_DSLEEP /* Enable the fan module and delay a few clocks */ clock_enable_peripheral(CGC_OFFSET_FAN, CGC_FAN_MASK, CGC_MODE_ALL); -#else - /* Enable the fan module and delay a few clocks */ - clock_enable_peripheral(CGC_OFFSET_FAN, CGC_FAN_MASK, - CGC_MODE_RUN | CGC_MODE_SLEEP); -#endif } DECLARE_HOOK(HOOK_INIT, fan_init, HOOK_PRIO_INIT_PWM); diff --git a/chip/npcx/fan_chip.h b/chip/npcx/fan_chip.h index 02c86bc9d4..3280cd1920 100644 --- a/chip/npcx/fan_chip.h +++ b/chip/npcx/fan_chip.h @@ -10,51 +10,30 @@ /* MFT module select */ enum npcx_mft_module { - NPCX_MFT_MODULE_1 = 0, - NPCX_MFT_MODULE_2 = 0, - NPCX_MFT_MODULE_3 = 0, + NPCX_MFT_MODULE_1, + NPCX_MFT_MODULE_2, + NPCX_MFT_MODULE_3, /* Number of MFT modules */ NPCX_MFT_MODULE_COUNT }; -/* MFT module port */ -enum npcx_mft_module_port { - NPCX_MFT_MODULE_PORT_TA, - NPCX_MFT_MODULE_PORT_TB, - /* Number of MFT module ports */ - NPCX_MFT_MODULE_PORT_COUNT +/* MFT clock source */ +enum npcx_mft_clk_src { + TCKC_NOCLK = 0, + TCKC_PRESCALE_APB1_CLK = 1, + TCKC_LFCLK = 5, }; /* Data structure to define MFT channels. */ struct mft_t { /* MFT module ID */ enum npcx_mft_module module; - /* MFT port */ - enum npcx_mft_module_port port; /* MFT TCNT default count */ uint32_t default_count; - /* MFT freq */ - uint32_t freq; -}; - -/* Tacho measurement state */ -enum tacho_measure_state { - /* Tacho init state */ - TACHO_IN_IDLE = 0, - /* Tacho first edge state */ - TACHO_WAIT_FOR_1_EDGE, - /* Tacho second edge state */ - TACHO_WAIT_FOR_2_EDGE, - /* Tacho underflow state */ - TACHO_UNDERFLOW -}; - -/* Tacho status data structure */ -struct tacho_status_t { - /* Current state of the measurement */ - enum tacho_measure_state cur_state; - /* Pulse counter value between edge1 and edge2 */ - uint32_t edge_interval; + /* MFT clock source */ + enum npcx_mft_clk_src clk_src; + /* PWM id */ + int pwm_id; }; extern const struct mft_t mft_channels[]; 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); + pwm_enable(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*/ + /* 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 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) = pwm_channels[ch].cycle_pulses; - - /* Set PWM polarity is normal*/ - CLEAR_BIT(NPCX_PWMCTL(pwm_channels[ch].channel), NPCX_PWMCTL_INVP); + /* Set PWM heartbeat mode is no heartbeat */ + SET_FIELD(NPCX_PWMCTL(mdl), NPCX_PWMCTL_HB_DC_CTL_FIELD, + NPCX_PWM_HBM_NORMAL); /* 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)<> bit) & (0x1)) @@ -20,6 +21,21 @@ SET_BIT(reg, bit); \ else \ CLEAR_BIT(reg, bit); } +/* Field functions */ +#define GET_POS_FIELD(pos, size) pos +#define GET_SIZE_FIELD(pos, size) size +#define FIELD_POS(field) GET_POS_##field +#define FIELD_SIZE(field) GET_SIZE_##field +/* Read field functions */ +#define GET_FIELD(reg, field) \ + _GET_FIELD_(reg, FIELD_POS(field), FIELD_SIZE(field)) +#define _GET_FIELD_(reg, f_pos, f_size) (((reg)>>(f_pos)) & ((1<<(f_size))-1)) +/* Write field functions */ +#define SET_FIELD(reg, field, value) \ + _SET_FIELD_(reg, FIELD_POS(field), FIELD_SIZE(field), value) +#define _SET_FIELD_(reg, f_pos, f_size, value) \ + ((reg) = ((reg) & (~(((1 << (f_size))-1) << (f_pos)))) \ + | ((value) << (f_pos))) /******************************************************************************/ /* @@ -1008,17 +1024,17 @@ enum PM_CHANNEL_T { #define NPCX_MEAST REG16(NPCX_ADC_BASE_ADDR + 0x026) /* ADC register fields */ -#define NPCX_ATCTL_SCLKDIV 0 -#define NPCX_ATCTL_DLY 8 -#define NPCX_ASCADD_SADDR 0 +#define NPCX_ATCTL_SCLKDIV_FIELD FIELD(0, 6) +#define NPCX_ATCTL_DLY_FIELD FIELD(8, 3) +#define NPCX_ASCADD_SADDR_FIELD FIELD(0, 5) #define NPCX_ADCSTS_EOCEV 0 -#define NPCX_ADCCNF_ADCMD 1 +#define NPCX_ADCCNF_ADCMD_FIELD FIELD(1, 2) #define NPCX_ADCCNF_ADCRPTC 3 #define NPCX_ADCCNF_INTECEN 6 #define NPCX_ADCCNF_START 4 #define NPCX_ADCCNF_ADCEN 0 #define NPCX_ADCCNF_STOP 11 -#define NPCX_CHNDAT_CHDAT 0 +#define NPCX_CHNDAT_CHDAT_FIELD FIELD(0, 10) #define NPCX_CHNDAT_NEW 15 /******************************************************************************/ /* SPI Register */ @@ -1076,9 +1092,9 @@ enum PM_CHANNEL_T { /* PWM register fields */ #define NPCX_PWMCTL_INVP 0 #define NPCX_PWMCTL_CKSEL 1 -#define NPCX_PWMCTL_HB_DC_CTL 2 +#define NPCX_PWMCTL_HB_DC_CTL_FIELD FIELD(2, 2) #define NPCX_PWMCTL_PWR 7 -#define NPCX_PWMCTLEX_FCK_SEL 4 +#define NPCX_PWMCTLEX_FCK_SEL_FIELD FIELD(4, 2) #define NPCX_PWMCTLEX_OD_OUT 7 /******************************************************************************/ /* MFT Registers */ @@ -1096,11 +1112,11 @@ enum PM_CHANNEL_T { #define NPCX_TCFG(n) REG8(NPCX_MFT_BASE_ADDR(n) + 0x01C) /* MFT register fields */ -#define NPCX_TMCTRL_MDSEL 0 +#define NPCX_TMCTRL_MDSEL_FIELD FIELD(0, 3) #define NPCX_TCKC_LOW_PWR 7 #define NPCX_TCKC_PLS_ACC_CLK 6 -#define NPCX_TCKC_C1CSEL 0 -#define NPCX_TCKC_C2CSEL 3 +#define NPCX_TCKC_C1CSEL_FIELD FIELD(0, 3) +#define NPCX_TCKC_C2CSEL_FIELD FIELD(3, 3) #define NPCX_TMCTRL_TAEN 5 #define NPCX_TMCTRL_TBEN 6 #define NPCX_TMCTRL_TAEDG 3