Skip to content

Commit

Permalink
drivers: serial: Smartbond: add support DTR line wakeup
Browse files Browse the repository at this point in the history
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 <jerzy.kasenberg@codecoup.pl>
  • Loading branch information
kasjer authored and nashif committed May 12, 2024
1 parent f10b773 commit 961959f
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 0 deletions.
39 changes: 39 additions & 0 deletions drivers/serial/uart_smartbond.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
};

Expand All @@ -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,
};

Expand All @@ -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;
Expand Down Expand Up @@ -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)
Expand All @@ -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);
Expand Down Expand Up @@ -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) \
Expand All @@ -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 = { \
Expand Down
12 changes: 12 additions & 0 deletions dts/bindings/serial/renesas,smartbond-uart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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.

0 comments on commit 961959f

Please sign in to comment.