From b4cd531e2ceaf60d7c00dd01b9b13b0368d39ec4 Mon Sep 17 00:00:00 2001 From: Manimaran A Date: Wed, 31 May 2023 19:42:06 +0530 Subject: [PATCH] drivers: bbled: pwm: mchp: BBLED low power mode updated Updated the driver to support low power mode. Introduced "enable-low-power" flag in device tree to control(on/off) low power mode. If flag added in DTS, during sleep BBLED will switch off the LEDs. Otherwise BBLED will continue the configured blinking pattern on LEDs. Signed-off-by: Manimaran A --- drivers/pwm/pwm_mchp_xec_bbled.c | 77 +++++++++++++++++++- dts/bindings/pwm/microchip,xec-pwmbbled.yaml | 12 +++ 2 files changed, 85 insertions(+), 4 deletions(-) diff --git a/drivers/pwm/pwm_mchp_xec_bbled.c b/drivers/pwm/pwm_mchp_xec_bbled.c index 0b1083e0e31..63b673ca02e 100644 --- a/drivers/pwm/pwm_mchp_xec_bbled.c +++ b/drivers/pwm/pwm_mchp_xec_bbled.c @@ -18,6 +18,7 @@ #endif #include #include +#include #include @@ -104,6 +105,7 @@ LOG_MODULE_REGISTER(pwmbbled_mchp_xec, CONFIG_PWM_LOG_LEVEL); #define XEC_PWM_BBLED_CLKSEL_1 XEC_PWM_BBLED_CLKSEL_PCR_SLOW #define XEC_PWM_BBLED_CLKSEL_2 XEC_PWM_BBLED_CLKSEL_AHB_48M + struct bbled_regs { volatile uint32_t config; volatile uint32_t limits; @@ -118,12 +120,17 @@ struct bbled_regs { struct pwm_bbled_xec_config { struct bbled_regs * const regs; + const struct pinctrl_dev_config *pcfg; uint8_t girq; uint8_t girq_pos; uint8_t pcr_idx; uint8_t pcr_pos; uint8_t clk_sel; - const struct pinctrl_dev_config *pcfg; + bool enable_low_power_32K; +}; + +struct bbled_xec_data { + uint32_t config; }; /* Compute BBLED PWM delay factor to produce requested frequency. @@ -318,6 +325,63 @@ static int pwm_bbled_xec_get_cycles_per_sec(const struct device *dev, return 0; } + +#ifdef CONFIG_PM_DEVICE +static int pwm_bbled_xec_pm_action(const struct device *dev, enum pm_device_action action) +{ + const struct pwm_bbled_xec_config *const devcfg = dev->config; + struct bbled_regs * const regs = devcfg->regs; + struct bbled_xec_data * const data = dev->data; + int ret = 0; + + /* 32K core clock is not gated by PCR in sleep, so BBLED can blink the LED even + * in sleep, if it is configured to use 32K clock. If we want to control it + * we shall use flag "enable_low_power_32K". + * This flag dont have effect on 48M clock. Since it is gated by PCR in sleep, BBLED + * will not get clock during sleep. + */ + if ((!devcfg->enable_low_power_32K) && + (!(regs->config & BIT(XEC_PWM_BBLED_CFG_CLK_SRC_48M_POS)))) { + return ret; + } + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + ret = pinctrl_apply_state(devcfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret != 0) { + LOG_ERR("XEC BBLED pinctrl setup failed (%d)", ret); + } + + /* Turn on BBLED only if it is ON before sleep */ + if ((data->config & XEC_PWM_BBLED_CFG_MODE_MSK) != XEC_PWM_BBLED_CFG_MODE_OFF) { + + regs->config |= (data->config & XEC_PWM_BBLED_CFG_MODE_MSK); + regs->config |= BIT(XEC_PWM_BBLED_CFG_EN_UPDATE_POS); + + data->config = XEC_PWM_BBLED_CFG_MODE_OFF; + } + break; + case PM_DEVICE_ACTION_SUSPEND: + if ((regs->config & XEC_PWM_BBLED_CFG_MODE_MSK) != XEC_PWM_BBLED_CFG_MODE_OFF) { + /* Do copy first, then clear mode. */ + data->config = regs->config; + + regs->config &= ~(XEC_PWM_BBLED_CFG_MODE_MSK); + } + + ret = pinctrl_apply_state(devcfg->pcfg, PINCTRL_STATE_SLEEP); + /* pinctrl-1 does not exist. */ + if (ret == -ENOENT) { + ret = 0; + } + break; + default: + ret = -ENOTSUP; + } + return ret; +} +#endif /* CONFIG_PM_DEVICE */ + static const struct pwm_driver_api pwm_bbled_xec_driver_api = { .set_cycles = pwm_bbled_xec_set_cycles, .get_cycles_per_sec = pwm_bbled_xec_get_cycles_per_sec, @@ -355,19 +419,24 @@ static int pwm_bbled_xec_init(const struct device *dev) .girq_pos = (uint8_t)(DT_INST_PROP_BY_IDX(0, girqs, 1)), \ .pcr_idx = (uint8_t)DT_INST_PROP_BY_IDX(inst, pcrs, 0), \ .pcr_pos = (uint8_t)DT_INST_PROP_BY_IDX(inst, pcrs, 1), \ - .clk_sel = UTIL_CAT(XEC_PWM_BBLED_CLKSEL_, XEC_PWM_BBLED_CLKSEL(n)), \ + .clk_sel = UTIL_CAT(XEC_PWM_BBLED_CLKSEL_, XEC_PWM_BBLED_CLKSEL(inst)), \ + .enable_low_power_32K = DT_INST_PROP(inst, enable_low_power_32k),\ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ }; #define XEC_PWM_BBLED_DEVICE_INIT(index) \ \ + static struct bbled_xec_data bbled_xec_data_##index; \ + \ PINCTRL_DT_INST_DEFINE(index); \ \ XEC_PWM_BBLED_CONFIG(index); \ \ + PM_DEVICE_DT_INST_DEFINE(index, pwm_bbled_xec_pm_action); \ + \ DEVICE_DT_INST_DEFINE(index, &pwm_bbled_xec_init, \ - NULL, \ - NULL, \ + PM_DEVICE_DT_INST_GET(index), \ + &bbled_xec_data_##index, \ &pwm_bbled_xec_config_##index, POST_KERNEL, \ CONFIG_PWM_INIT_PRIORITY, \ &pwm_bbled_xec_driver_api); diff --git a/dts/bindings/pwm/microchip,xec-pwmbbled.yaml b/dts/bindings/pwm/microchip,xec-pwmbbled.yaml index 00d30921d56..6ee66fafcd9 100644 --- a/dts/bindings/pwm/microchip,xec-pwmbbled.yaml +++ b/dts/bindings/pwm/microchip,xec-pwmbbled.yaml @@ -46,6 +46,18 @@ properties: "#pwm-cells": const: 2 + enable-low-power-32k: + type: boolean + description: | + BBLED has two clock inputs. + - Main system clock (48MHz) + - 32KHz Core clock (32.768KHz) + When BBLED enter into Suspend state, 48MHz clock will be switched off by + PCR(Power, Clock and Reset) block. But 32KHz Core clock will be available to BBLED. + There may be a product requirement, either to blink (or) not blink LED in Suspend state. + Flag "enable-low-power-32k" shall be used along with 32KHz clock to blink (or) not blink + the LED in Suspend state. + pwm-cells: - channel - period