From 5f3bba54e8e51a92a692dfdbf0b094f877fd5d31 Mon Sep 17 00:00:00 2001 From: Ruibin Chang Date: Wed, 19 Jan 2022 13:39:36 +0800 Subject: [PATCH] ITE drivers/pwm: support tests/drivers/pwm/pwm_api Add pwm-0 to support tests/drivers/pwm/pwm_api. Solve tests code runtime error on it8xxx2_evb: 1.If the pwm channel target frequency is < 1, then we will return an error code. 2.If the target_freq is <= 324Hz, we will configure that this pwm channel need to output in EC power saving mode. In test_pwm_cycle() case, the period is 64000, then the target_freq is 8000000 / 64000 = 125Hz and <= 324Hz, so we will switch the prescaler clock source from 8MHz to 32.768kHz. Then the target_freq is 32768 / 64000 = 0.512Hz and < 1Hz, this will return an error code. In order to get the same target_freq, we always return PWM_FREQ in pwm_it8xxx2_get_cycles_per_sec(). Signed-off-by: Ruibin Chang --- boards/riscv/it8xxx2_evb/it8xxx2_evb.dts | 1 + drivers/pwm/pwm_ite_it8xxx2.c | 45 ++++++++++++++++++------ 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts b/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts index 739ac703a43..7fbcaab5310 100644 --- a/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts +++ b/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts @@ -33,6 +33,7 @@ led0 = &led0; kscan0 = &kscan0; watchdog0 = &twd0; + pwm-0 = &pwm0; }; leds { diff --git a/drivers/pwm/pwm_ite_it8xxx2.c b/drivers/pwm/pwm_ite_it8xxx2.c index 26159d61759..c60658b0011 100644 --- a/drivers/pwm/pwm_ite_it8xxx2.c +++ b/drivers/pwm/pwm_ite_it8xxx2.c @@ -69,17 +69,27 @@ static void pwm_enable(const struct device *dev, int enabled) static int pwm_it8xxx2_get_cycles_per_sec(const struct device *dev, uint32_t pwm, uint64_t *cycles) { - const struct pwm_it8xxx2_cfg *config = dev->config; - struct pwm_it8xxx2_regs *const inst = config->base; - int prs_sel = config->prs_sel; - ARG_UNUSED(pwm); - /* Get clock source cycles per second that output to prescaler */ - if ((inst->PCFSR) & BIT(prs_sel)) - *cycles = (uint64_t) PWM_FREQ; - else - *cycles = (uint64_t) 32768; + /* + * There are three ways to call pwm_it8xxx2_pin_set() from pwm api: + * 1) pwm_pin_set_usec() -> pwm_pin_set_cycles() -> pwm_it8xxx2_pin_set() + * target_freq = pwm_clk_src / period_cycles + * = cycles / (period * cycles / USEC_PER_SEC) + * = USEC_PER_SEC / period + * 2) pwm_pin_set_nsec() -> pwm_pin_set_cycles() -> pwm_it8xxx2_pin_set() + * target_freq = pwm_clk_src / period_cycles + * = cycles / (period * cycles / NSEC_PER_SEC) + * = NSEC_PER_SEC / period + * 3) pwm_pin_set_cycles() -> pwm_it8xxx2_pin_set() + * target_freq = pwm_clk_src / period_cycles + * = cycles / period + * + * If we need to pwm output in EC power saving mode, then we will switch + * the prescaler clock source (cycles) from 8MHz to 32.768kHz. In order + * to get the same target_freq in the 3) case, we always return PWM_FREQ. + */ + *cycles = (uint64_t) PWM_FREQ; return 0; } @@ -120,6 +130,21 @@ static int pwm_it8xxx2_pin_set(const struct device *dev, pwm_it8xxx2_get_cycles_per_sec(dev, pwm, &pwm_clk_src); target_freq = ((uint32_t) pwm_clk_src) / period_cycles; + + /* + * Support PWM output frequency: + * 1) 8MHz clock source: 1Hz <= target_freq <= 79207Hz + * 2) 32.768KHz clock source: 1Hz <= target_freq <= 324Hz + * NOTE: PWM output signal maximum supported frequency comes from + * [8MHz or 32.768KHz] / 1 / (PWM_CTRX_MIN + 1). + * PWM output signal minimum supported frequency comes from + * [8MHz or 32.768KHz] / 65536 / 256, the minimum integer is 1. + */ + if (target_freq < 1) { + LOG_ERR("PWM output frequency is < 1 !"); + return -EINVAL; + } + deviation = (target_freq / 100) + 1; /* @@ -128,8 +153,6 @@ static int pwm_it8xxx2_pin_set(const struct device *dev, * So if we still need pwm output in mode, then we should set frequency * <=324Hz in board dts. Now change prescaler clock source from 8MHz to * 32.768KHz to support pwm output in mode. - * NOTE: PWM output signal maximum supported frequency 324Hz comes from - * 32768 / (PWM_CTRX_MIN + 1). */ if ((target_freq <= 324) && (inst->PCFSR & BIT(prs_sel))) { inst->PCFSR &= ~BIT(prs_sel);