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