From 1dee6d6f7c4beec6aeedf84ac9bf299aad9c0c2b Mon Sep 17 00:00:00 2001 From: Lin Yu-Cheng Date: Thu, 7 Aug 2025 13:50:48 +0800 Subject: [PATCH] driver: espi: implement espi PM function 1. add cs pin as espi driver wake up reference 2. removed the unnecessary update of the cached date 3. removed the unnecessary busy wait in notify funciton Signed-off-by: Lin Yu-Cheng --- drivers/espi/espi_realtek_rts5912.c | 100 +++++++++++++------- dts/arm/realtek/ec/rts5912.dtsi | 2 + dts/bindings/espi/realtek,rts5912-espi.yaml | 9 ++ 3 files changed, 75 insertions(+), 36 deletions(-) diff --git a/drivers/espi/espi_realtek_rts5912.c b/drivers/espi/espi_realtek_rts5912.c index 3c4a7a1e840d3..c418894b09c64 100644 --- a/drivers/espi/espi_realtek_rts5912.c +++ b/drivers/espi/espi_realtek_rts5912.c @@ -23,6 +23,14 @@ LOG_MODULE_REGISTER(espi, CONFIG_ESPI_LOG_LEVEL); #include "reg/reg_kbc.h" #include "reg/reg_port80.h" +#ifdef CONFIG_PM +#include "reg/reg_gpio.h" +#include +#include +#include "reg/reg_system.h" +#include "zephyr/drivers/gpio/gpio_rts5912.h" +#endif + BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "support only one espi compatible node"); struct espi_rts5912_config { @@ -56,6 +64,9 @@ struct espi_rts5912_config { volatile struct port80_reg *const port80_reg; uint32_t port80_clk_grp; uint32_t port80_clk_idx; +#endif +#ifdef CONFIG_PM + struct gpio_dt_spec cs_pin; #endif const struct device *clk_dev; const struct pinctrl_dev_config *pcfg; @@ -1197,7 +1208,6 @@ static void notify_host_warning(const struct device *dev, enum espi_vwire_signal uint8_t status = 0; espi_rts5912_receive_vwire(dev, signal, &status); - k_busy_wait(200); switch (signal) { case ESPI_VWIRE_SIGNAL_SUS_WARN: @@ -1394,8 +1404,6 @@ static int espi_rts5912_send_vwire(const struct device *dev, enum espi_vwire_sig static int espi_rts5912_receive_vwire(const struct device *dev, enum espi_vwire_signal signal, uint8_t *level) { - const struct espi_rts5912_config *const espi_config = dev->config; - volatile struct espi_reg *const espi_reg = espi_config->espi_reg; uint8_t vw_idx, lev_msk, valid_msk; uint8_t vw_data; @@ -1412,9 +1420,6 @@ static int espi_rts5912_receive_vwire(const struct device *dev, enum espi_vwire_ vw_data = espi_vw_ch_cached_data.idx2; break; case VW_CH_IDX3: - if (espi_vw_ch_cached_data.idx3 != espi_reg->EVIDX3) { - espi_vw_ch_cached_data.idx3 = espi_reg->EVIDX3; - } vw_data = espi_vw_ch_cached_data.idx3; break; case VW_CH_IDX4: @@ -1427,60 +1432,33 @@ static int espi_rts5912_receive_vwire(const struct device *dev, enum espi_vwire_ vw_data = espi_vw_tx_cached_data.idx6; break; case VW_CH_IDX7: - if (espi_vw_ch_cached_data.idx7 != espi_reg->EVIDX7) { - espi_vw_ch_cached_data.idx7 = espi_reg->EVIDX7; - } vw_data = espi_vw_ch_cached_data.idx7; break; case VW_CH_IDX40: vw_data = espi_vw_tx_cached_data.idx40; break; case VW_CH_IDX41: - if (espi_vw_ch_cached_data.idx41 != espi_reg->EVIDX41) { - espi_vw_ch_cached_data.idx41 = espi_reg->EVIDX41; - } vw_data = espi_vw_ch_cached_data.idx41; break; case VW_CH_IDX42: - if (espi_vw_ch_cached_data.idx42 != espi_reg->EVIDX42) { - espi_vw_ch_cached_data.idx42 = espi_reg->EVIDX42; - } vw_data = espi_vw_ch_cached_data.idx42; break; case VW_CH_IDX43: - if (espi_vw_ch_cached_data.idx43 != espi_reg->EVIDX43) { - espi_vw_ch_cached_data.idx43 = espi_reg->EVIDX43; - } vw_data = espi_vw_ch_cached_data.idx43; break; case VW_CH_IDX44: - if (espi_vw_ch_cached_data.idx44 != espi_reg->EVIDX44) { - espi_vw_ch_cached_data.idx44 = espi_reg->EVIDX44; - } vw_data = espi_vw_ch_cached_data.idx44; break; case VW_CH_IDX47: - if (espi_vw_ch_cached_data.idx47 != espi_reg->EVIDX47) { - espi_vw_ch_cached_data.idx47 = espi_reg->EVIDX47; - } vw_data = espi_vw_ch_cached_data.idx47; break; case VW_CH_IDX4A: - if (espi_vw_ch_cached_data.idx4a != espi_reg->EVIDX4A) { - espi_vw_ch_cached_data.idx4a = espi_reg->EVIDX4A; - } vw_data = espi_vw_ch_cached_data.idx4a; break; case VW_CH_IDX51: - if (espi_vw_ch_cached_data.idx51 != espi_reg->EVIDX51) { - espi_vw_ch_cached_data.idx51 = espi_reg->EVIDX51; - } vw_data = espi_vw_ch_cached_data.idx51; break; case VW_CH_IDX61: - if (espi_vw_ch_cached_data.idx61 != espi_reg->EVIDX61) { - espi_vw_ch_cached_data.idx61 = espi_reg->EVIDX61; - } vw_data = espi_vw_ch_cached_data.idx61; break; default: @@ -2293,7 +2271,18 @@ static void espi_bus_reset_setup(const struct device *dev) DEVICE_DT_GET(DT_DRV_INST(0)), 0); irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), bus_rst, irq)); } +#ifdef CONFIG_PM +void espi_cs_low_isr(const struct device *port, struct gpio_callback *cb, gpio_port_pins_t pins) +{ + gpio_flags_t cs_pin_config; + gpio_pin_get_config(port, pins, &cs_pin_config); + if (cs_pin_config & GPIO_INT_ENABLE) { + gpio_pin_interrupt_configure(port, (find_msb_set(pins) - 1), + GPIO_INT_MODE_DISABLED); + } +} +#endif static int espi_rts5912_init(const struct device *dev) { const struct espi_rts5912_config *const espi_config = dev->config; @@ -2393,13 +2382,44 @@ static int espi_rts5912_init(const struct device *dev) goto exit; } #endif - +#ifdef CONFIG_PM + static struct gpio_callback cb; + uint32_t cs_irq_nun = gpio_rts5912_get_pin_num(&espi_config->cs_pin); + + NVIC_ClearPendingIRQ(cs_irq_nun); + gpio_init_callback(&cb, espi_cs_low_isr, BIT(espi_config->cs_pin.pin)); + gpio_add_callback(espi_config->cs_pin.port, &cb); + irq_enable(cs_irq_nun); +#endif exit: return rc; } +#ifdef CONFIG_PM +static inline int espi_rts5912_pm_action(const struct device *dev, enum pm_device_action action) +{ + const struct espi_rts5912_config *const espi_config = dev->config; + SYSTEM_Type *sys_reg = RTS5912_SCCON_REG_BASE; -PINCTRL_DT_INST_DEFINE(0); + switch (action) { + case PM_DEVICE_ACTION_RESUME: + sys_reg->SLPCTRL &= ~SYSTEM_SLPCTRL_GPIOWKEN_Msk; + gpio_pin_interrupt_configure_dt(&espi_config->cs_pin, GPIO_INT_MODE_DISABLED); + break; + case PM_DEVICE_ACTION_SUSPEND: + sys_reg->SLPCTRL |= SYSTEM_SLPCTRL_GPIOWKEN_Msk; + gpio_pin_interrupt_configure_dt(&espi_config->cs_pin, + GPIO_INT_MODE_EDGE | GPIO_INT_TRIG_LOW); + break; + default: + return -ENOTSUP; + } + return 0; +} +PM_DEVICE_DT_INST_DEFINE(0, espi_rts5912_pm_action); +#endif + +PINCTRL_DT_INST_DEFINE(0); static struct espi_rts5912_data espi_rts5912_data_0; static const struct espi_rts5912_config espi_rts5912_config = { @@ -2434,10 +2454,18 @@ static const struct espi_rts5912_config espi_rts5912_config = { .port80_reg = (volatile struct port80_reg *const)DT_INST_REG_ADDR_BY_NAME(0, port80), .port80_clk_grp = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), port80, clk_grp), .port80_clk_idx = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), port80, clk_idx), +#endif +#ifdef CONFIG_PM + .cs_pin = GPIO_DT_SPEC_INST_GET(0, cs_gpios), #endif .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(0)), .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), }; - +#ifdef CONFIG_PM +DEVICE_DT_INST_DEFINE(0, &espi_rts5912_init, PM_DEVICE_DT_INST_GET(0), &espi_rts5912_data_0, + &espi_rts5912_config, PRE_KERNEL_2, CONFIG_ESPI_INIT_PRIORITY, + &espi_rts5912_driver_api); +#else DEVICE_DT_INST_DEFINE(0, &espi_rts5912_init, NULL, &espi_rts5912_data_0, &espi_rts5912_config, PRE_KERNEL_2, CONFIG_ESPI_INIT_PRIORITY, &espi_rts5912_driver_api); +#endif diff --git a/dts/arm/realtek/ec/rts5912.dtsi b/dts/arm/realtek/ec/rts5912.dtsi index 13daf81625df3..f1a517d79ff97 100644 --- a/dts/arm/realtek/ec/rts5912.dtsi +++ b/dts/arm/realtek/ec/rts5912.dtsi @@ -13,6 +13,7 @@ #include #include #include +#include / { cpus { @@ -167,6 +168,7 @@ espi0: espi0@400b1000 { compatible = "realtek,rts5912-espi"; + cs-gpios = ; status = "disabled"; reg = <0x400b1000 0x200 /* espi target */ diff --git a/dts/bindings/espi/realtek,rts5912-espi.yaml b/dts/bindings/espi/realtek,rts5912-espi.yaml index 18198cdfbc868..76044596710a8 100644 --- a/dts/bindings/espi/realtek,rts5912-espi.yaml +++ b/dts/bindings/espi/realtek,rts5912-espi.yaml @@ -17,3 +17,12 @@ properties: pinctrl-names: required: true + + cs-gpios: + description: | + select the cs pin to support the espi wakeup + and it is required when CONFIG_PM is enabled. + please check include/zephyr/dt-bindings/gpio/realtek-gpio.h + For example: + cs-gpios = ; + type: phandle-array