From 961959fc5f2ba913a80af6e92ea493b373f90253 Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Tue, 22 Aug 2023 15:27:20 +0200 Subject: [PATCH] drivers: serial: Smartbond: add support DTR line wakeup This change allows to use DTR line driven from external serial port that when active (low) will prevent UART device from going to sleep. It will also wake up platform when DTR line becomes active. DTR line is often activated in serial port connected to host computer when operating system opens serial device like COMx for Windows or /dev/ttyACMx /dev/ttyUSBx for Linux based systems. DTR line (specified in device tree) will be used by WAKEUP and PDC controllers (via GPIO driver) to handle DTR line changes. Signed-off-by: Jerzy Kasenberg --- drivers/serial/uart_smartbond.c | 39 +++++++++++++++++++ .../serial/renesas,smartbond-uart.yaml | 12 ++++++ 2 files changed, 51 insertions(+) diff --git a/drivers/serial/uart_smartbond.c b/drivers/serial/uart_smartbond.c index 66ec3e108f6..8656ae8dc43 100644 --- a/drivers/serial/uart_smartbond.c +++ b/drivers/serial/uart_smartbond.c @@ -82,6 +82,7 @@ struct uart_smartbond_cfg { #if CONFIG_PM_DEVICE int rx_wake_timeout; struct gpio_dt_spec rx_wake_gpio; + struct gpio_dt_spec dtr_gpio; #endif }; @@ -94,6 +95,7 @@ struct uart_smartbond_runtime_cfg { enum uart_smartbond_pm_policy_state_flag { UART_SMARTBOND_PM_POLICY_STATE_RX_FLAG, + UART_SMARTBOND_PM_POLICY_STATE_DTR_FLAG, UART_SMARTBOND_PM_POLICY_STATE_FLAG_COUNT, }; @@ -108,6 +110,7 @@ struct uart_smartbond_data { uint8_t rx_enabled; uint8_t tx_enabled; #if CONFIG_PM_DEVICE + struct gpio_callback dtr_wake_cb; const struct uart_smartbond_cfg *config; struct gpio_callback rx_wake_cb; int rx_wake_timeout; @@ -328,6 +331,22 @@ static void uart_smartbond_wake_handler(const struct device *gpio, struct gpio_c } } +static void uart_smartbond_dtr_handler(const struct device *gpio, struct gpio_callback *cb, + uint32_t pins) +{ + struct uart_smartbond_data *data = CONTAINER_OF(cb, struct uart_smartbond_data, + dtr_wake_cb); + int pin = find_lsb_set(pins) - 1; + + if (gpio_pin_get(gpio, pin) == 1) { + uart_smartbond_pm_policy_state_lock_put(data, + UART_SMARTBOND_PM_POLICY_STATE_DTR_FLAG); + } else { + uart_smartbond_pm_policy_state_lock_get(data, + UART_SMARTBOND_PM_POLICY_STATE_DTR_FLAG); + } +} + #endif static int uart_smartbond_init(const struct device *dev) @@ -354,6 +373,22 @@ static int uart_smartbond_init(const struct device *dev) rx_wake_timeout = CONFIG_UART_CONSOLE_INPUT_EXPIRED_TIMEOUT; #endif } + /* If DTR pin is configured, use it for power management */ + if (config->dtr_gpio.port != NULL) { + gpio_init_callback(&data->dtr_wake_cb, uart_smartbond_dtr_handler, + BIT(config->dtr_gpio.pin)); + ret = gpio_add_callback(config->dtr_gpio.port, &data->dtr_wake_cb); + if (ret == 0) { + ret = gpio_pin_interrupt_configure_dt(&config->dtr_gpio, + GPIO_INT_MODE_EDGE | + GPIO_INT_TRIG_BOTH); + /* Check if DTR is already active (low), if so lock power state */ + if (gpio_pin_get(config->dtr_gpio.port, config->dtr_gpio.pin) == 0) { + uart_smartbond_pm_policy_state_lock_get(data, + UART_SMARTBOND_PM_POLICY_STATE_DTR_FLAG); + } + } + } if (rx_wake_timeout > 0 && config->rx_wake_gpio.port != NULL) { k_work_init_delayable(&data->rx_timeout_work, uart_smartbond_rx_refresh_timeout); @@ -688,9 +723,12 @@ static const struct uart_driver_api uart_smartbond_driver_api = { .rx_wake_timeout = (DT_INST_PROP_OR(n, rx_wake_timeout, 0)), #define UART_PM_WAKE_RX_PIN(n) \ .rx_wake_gpio = GPIO_DT_SPEC_INST_GET_OR(n, rx_wake_gpios, {0}), +#define UART_PM_WAKE_DTR_PIN(n) \ + .dtr_gpio = GPIO_DT_SPEC_INST_GET_OR(n, dtr_gpios, {0}), #else #define UART_PM_WAKE_RX_PIN(n) /* Not used */ #define UART_PM_WAKE_RX_TIMEOUT(n) /* Not used */ +#define UART_PM_WAKE_DTR_PIN(n) /* Not used */ #endif #define UART_SMARTBOND_DEVICE(id) \ @@ -702,6 +740,7 @@ static const struct uart_driver_api uart_smartbond_driver_api = { .hw_flow_control_supported = DT_INST_PROP(id, hw_flow_control_supported), \ UART_PM_WAKE_RX_TIMEOUT(id) \ UART_PM_WAKE_RX_PIN(id) \ + UART_PM_WAKE_DTR_PIN(id) \ }; \ static struct uart_smartbond_data uart_smartbond_##id##_data = { \ .current_config = { \ diff --git a/dts/bindings/serial/renesas,smartbond-uart.yaml b/dts/bindings/serial/renesas,smartbond-uart.yaml index 9eaf48974e8..428eb0ca76e 100644 --- a/dts/bindings/serial/renesas,smartbond-uart.yaml +++ b/dts/bindings/serial/renesas,smartbond-uart.yaml @@ -47,3 +47,15 @@ properties: type: int description: | Time to prevent UART entering sleep mode after receiving data (ms) + + dtr-gpios: + type: phandle-array + description: | + DTR pin specification. DTR pin when active tells that the driver that there + is active client on the other side of serial line. + The device driver does not use DTR for hardware flow control. + When device is connected to computer serial converter usually asserts DTR + line when serial port is opened and ready for communication. + This line can be used in Smartbond(tm) driver to detect remote client presence. + If client is not present the device can disable UART, allowing for + power system management to enter more efficient power levels.