Skip to content

Commit 2d72d86

Browse files
JasonLin-RealTekjhedberg
authored andcommitted
serial: rts5912: implement power management
support uart wake up function Signed-off-by: Lin Yu-Cheng <[email protected]>
1 parent 3372459 commit 2d72d86

File tree

7 files changed

+187
-9
lines changed

7 files changed

+187
-9
lines changed

boards/realtek/rts5912_evb/rts5912_evb.dts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include <realtek/ec/rts5912.dtsi>
1010
#include <realtek/ec/rts5912-pinctrl.dtsi>
1111
#include <zephyr/dt-bindings/gpio/gpio.h>
12-
12+
#include <zephyr/dt-bindings/gpio/realtek-gpio.h>
1313
/ {
1414
model = "Realtek RTS5912 Evaluation Board";
1515
compatible = "realtek,rts5912-evb";
@@ -42,6 +42,7 @@
4242
status = "okay";
4343
pinctrl-0 = <&uart_rx_gpio113 &uart_tx_gpio114>;
4444
pinctrl-names = "default";
45+
rx-gpios = <RTS5912_GPIO113 GPIO_ACTIVE_HIGH>;
4546
};
4647

4748
&kbd {

drivers/clock_control/clock_control_rts5912_sccon.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ static int rts5912_periph_clock_control(const struct device *dev, clock_control_
5353
case RTS5912_SCCON_UART:
5454
if (on_off) {
5555
sys_reg->UARTCLK = BIT(clk_idx);
56+
sys_reg->UARTCLK |= SYSTEM_UARTCLK_SRC_Msk;
5657
} else {
5758
sys_reg->UARTCLK &= ~BIT(clk_idx);
5859
}

drivers/serial/Kconfig.realtek_rts5912

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ config UART_RTS5912
1414

1515
config UART_RTS5912_INIT_PRIORITY
1616
int "RTS5912 UART wrapper init priority"
17-
default 49
17+
default 51
1818
depends on UART_RTS5912
1919
help
2020
Initialization priority for Realtek RTS5912 UART wrapper driver.

drivers/serial/uart_realtek_rts5912.c

Lines changed: 167 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,110 @@
1313
#include <zephyr/drivers/gpio.h>
1414
#include <zephyr/drivers/clock_control.h>
1515
#include <zephyr/drivers/clock_control/clock_control_rts5912.h>
16+
#include <zephyr/drivers/serial/uart_ns16550.h>
1617
#include <zephyr/logging/log.h>
18+
#include <zephyr/pm/pm.h>
19+
#include <zephyr/pm/policy.h>
20+
#include <zephyr/pm/device.h>
21+
#include "zephyr/drivers/gpio/gpio_rts5912.h"
1722

1823
LOG_MODULE_REGISTER(uart_rts5912, CONFIG_UART_LOG_LEVEL);
1924

20-
BUILD_ASSERT(CONFIG_UART_RTS5912_INIT_PRIORITY < CONFIG_SERIAL_INIT_PRIORITY,
21-
"The uart_realtek_rts5912 driver must be initialized before the uart_ns16550 driver");
22-
2325
/* device config */
2426
struct uart_rts5912_device_config {
2527
const struct pinctrl_dev_config *pcfg;
2628
const struct device *clk_dev;
2729
struct rts5912_sccon_subsys sccon_cfg;
30+
struct gpio_dt_spec uart_rx_wakeup;
31+
const struct device *uart_dev;
2832
};
2933

3034
/** Device data structure */
3135
struct uart_rts5912_dev_data {
36+
#if defined(CONFIG_PM)
37+
struct pm_notifier pm_handles;
38+
uint32_t *rts5912_rx_wake_reg;
39+
uint32_t rx_wakeup_pin_num;
40+
#endif
3241
};
3342

43+
DT_INST_FOREACH_STATUS_OKAY(PINCTRL_DT_INST_DEFINE);
44+
#if defined(CONFIG_PM)
45+
#define REG_IIR 0x08 /* Interrupt ID reg. */
46+
#define REG_LSR 0x14 /* Line status reg. */
47+
#define REG_USR 0x7C /* UART status reg. (DW8250) */
48+
#define IIR_NIP 0x01 /* no interrupt pending */
49+
#define IIR_THRE 0x02 /* transmit holding register empty interrupt */
50+
#define IIR_RBRF 0x04 /* receiver buffer register full interrupt */
51+
#define IIR_LS 0x06 /* receiver line status interrupt */
52+
#define IIR_MASK 0x07 /* interrupt id bits mask */
53+
#define IIR_BUSY 0x07 /* iir busy mask */
54+
#define USR_BUSY_CHECK BIT(0)
55+
#define RTS5912_MAXIMUM_UART_POLLING_TIME_US (50 * USEC_PER_MSEC)
56+
static struct k_work_delayable rx_refresh_timeout_work;
57+
58+
static void uart_rts5912_rx_refresh_timeout(struct k_work *work)
59+
{
60+
ARG_UNUSED(work);
61+
62+
pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
63+
}
64+
/* Hook to count entry/exit */
65+
static void uart_rts5912_pm_state_entry(const struct device *dev, enum pm_state state)
66+
{
67+
const struct uart_rts5912_dev_data *const dev_data = dev->data;
68+
69+
switch (state) {
70+
case PM_STATE_SUSPEND_TO_IDLE:
71+
irq_enable(dev_data->rx_wakeup_pin_num);
72+
gpio_rts5912_set_wakeup_pin(dev_data->rx_wakeup_pin_num);
73+
break;
74+
default:
75+
break;
76+
}
77+
}
78+
/* Hook to count entry/exit */
79+
static void uart_rts5912_pm_state_exit(const struct device *dev, enum pm_state state)
80+
{
81+
const struct uart_rts5912_device_config *const dev_cfg = dev->config;
82+
const struct uart_rts5912_dev_data *const dev_data = dev->data;
83+
84+
switch (state) {
85+
case PM_STATE_SUSPEND_TO_IDLE:
86+
uint32_t interrupt_pin = gpio_rts5912_get_intr_pin(dev_data->rts5912_rx_wake_reg);
87+
88+
pinctrl_apply_state(dev_cfg->pcfg, PINCTRL_STATE_DEFAULT);
89+
if (IS_ENABLED(CONFIG_UART_CONSOLE_INPUT_EXPIRED) &&
90+
interrupt_pin == dev_cfg->uart_rx_wakeup.pin) {
91+
k_timeout_t delay = K_MSEC(CONFIG_UART_CONSOLE_INPUT_EXPIRED_TIMEOUT);
92+
93+
pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
94+
k_work_reschedule(&rx_refresh_timeout_work, delay);
95+
}
96+
NVIC_ClearPendingIRQ(dev_data->rx_wakeup_pin_num);
97+
irq_disable(dev_data->rx_wakeup_pin_num);
98+
break;
99+
default:
100+
break;
101+
}
102+
}
103+
104+
static void uart_rx_wait(const struct device *dev, void *user_data)
105+
{
106+
ARG_UNUSED(user_data);
107+
if (IS_ENABLED(CONFIG_UART_CONSOLE_INPUT_EXPIRED) && uart_irq_rx_ready(dev)) {
108+
k_timeout_t delay = K_MSEC(CONFIG_UART_CONSOLE_INPUT_EXPIRED_TIMEOUT);
109+
110+
pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
111+
k_work_reschedule(&rx_refresh_timeout_work, delay);
112+
}
113+
}
114+
#endif
115+
34116
static int rts5912_uart_init(const struct device *dev)
35117
{
36118
const struct uart_rts5912_device_config *const dev_cfg = dev->config;
119+
struct uart_rts5912_dev_data *const dev_data = dev->data;
37120
int rc;
38121

39122
if (!device_is_ready(dev_cfg->clk_dev)) {
@@ -50,11 +133,87 @@ static int rts5912_uart_init(const struct device *dev)
50133
return rc;
51134
}
52135

136+
#if defined(CONFIG_PM)
137+
const uint32_t uart_reg = uart_ns16550_get_port(dev_cfg->uart_dev);
138+
uint32_t wf_cycle_count = k_us_to_cyc_ceil32(RTS5912_MAXIMUM_UART_POLLING_TIME_US);
139+
uint32_t wf_start = k_cycle_get_32();
140+
uint32_t wf_now = wf_start;
141+
142+
/* For RTS5912 UART, if enable UART wake up function, it will
143+
* change GPIO pin from uart funciton to gpio function before WFI.
144+
* System need to ensure this register is cleared in every time doing init function.
145+
*/
146+
while (wf_cycle_count > (wf_now - wf_start)) {
147+
uint32_t iir = sys_read32(uart_reg + REG_IIR) & IIR_MASK;
148+
149+
if (iir == IIR_NIP) {
150+
break;
151+
}
152+
switch (iir) {
153+
case IIR_LS: /* Receiver line status */
154+
sys_read32(uart_reg + REG_LSR);
155+
break;
156+
case IIR_RBRF: /* Received data available*/
157+
sys_write32(sys_read32(uart_reg + REG_IIR) | IIR_THRE,
158+
(uart_reg + REG_IIR));
159+
break;
160+
case IIR_BUSY:
161+
while (wf_cycle_count > (wf_now - wf_start)) {
162+
uint32_t usr = sys_read32(uart_reg + REG_USR);
163+
164+
if ((usr & USR_BUSY_CHECK) == 0) {
165+
break;
166+
}
167+
wf_now = k_cycle_get_32();
168+
}
169+
break;
170+
}
171+
iir = sys_read32(uart_reg + REG_IIR) & IIR_MASK;
172+
if (iir == IIR_NIP) {
173+
break;
174+
}
175+
k_busy_wait(10);
176+
wf_now = k_cycle_get_32();
177+
}
178+
179+
if (wf_cycle_count <= (wf_now - wf_start)) {
180+
LOG_ERR("Uart reset iir reach timeout");
181+
return -EIO;
182+
}
183+
184+
k_work_init_delayable(&rx_refresh_timeout_work, uart_rts5912_rx_refresh_timeout);
185+
pm_notifier_register(&dev_data->pm_handles);
186+
uart_irq_callback_set(DEVICE_DT_GET(DT_CHOSEN(zephyr_console)), uart_rx_wait);
187+
dev_data->rx_wakeup_pin_num = gpio_rts5912_get_pin_num(&dev_cfg->uart_rx_wakeup);
188+
dev_data->rts5912_rx_wake_reg = gpio_rts5912_get_port_address(&dev_cfg->uart_rx_wakeup);
189+
#endif
190+
53191
return 0;
54192
}
55193

194+
#if defined(CONFIG_PM)
195+
#define UART_REALTEK_RTS5912_PM_HANDLES_DEFINE(n) \
196+
static void uart_rts5912_##n##_pm_entry(enum pm_state state) \
197+
{ \
198+
uart_rts5912_pm_state_entry(DEVICE_DT_INST_GET(n), state); \
199+
} \
200+
\
201+
static void uart_rts5912_##n##_pm_exit(enum pm_state state) \
202+
{ \
203+
uart_rts5912_pm_state_exit(DEVICE_DT_INST_GET(n), state); \
204+
}
205+
#define UART_REALTEK_RTS5912_PM_HANDLES_BIND(n) \
206+
.pm_handles = { \
207+
.state_entry = uart_rts5912_##n##_pm_entry, \
208+
.state_exit = uart_rts5912_##n##_pm_exit, \
209+
},
210+
#else
211+
#define UART_REALTEK_RTS5912_PM_HANDLES_DEFINE(n)
212+
#define UART_REALTEK_RTS5912_PM_HANDLES_BIND(n)
213+
#endif
214+
56215
#define UART_RTS5912_DEVICE_INIT(n) \
57-
PINCTRL_DT_INST_DEFINE(n); \
216+
UART_REALTEK_RTS5912_PM_HANDLES_DEFINE(n) \
58217
\
59218
static const struct uart_rts5912_device_config uart_rts5912_dev_cfg_##n = { \
60219
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
@@ -64,9 +223,12 @@ static int rts5912_uart_init(const struct device *dev)
64223
.clk_grp = DT_INST_CLOCKS_CELL_BY_NAME(n, uart##n, clk_grp), \
65224
.clk_idx = DT_INST_CLOCKS_CELL_BY_NAME(n, uart##n, clk_idx), \
66225
}, \
226+
.uart_rx_wakeup = GPIO_DT_SPEC_INST_GET(n, rx_gpios), \
227+
.uart_dev = DEVICE_DT_GET(DT_INST_PHANDLE(n, uart_dev)), \
67228
}; \
68229
\
69-
static struct uart_rts5912_dev_data uart_rts5912_dev_data_##n; \
230+
static struct uart_rts5912_dev_data uart_rts5912_dev_data_##n = { \
231+
UART_REALTEK_RTS5912_PM_HANDLES_BIND(n)}; \
70232
\
71233
DEVICE_DT_INST_DEFINE(n, &rts5912_uart_init, NULL, &uart_rts5912_dev_data_##n, \
72234
&uart_rts5912_dev_cfg_##n, PRE_KERNEL_1, \

dts/arm/realtek/ec/rts5912.dtsi

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@
275275
compatible = "ns16550";
276276
reg = <0x40010100 0x100>;
277277
reg-shift = <2>;
278-
clock-frequency = <25000000>;
278+
clock-frequency = <DT_FREQ_M(100)>;
279279
interrupts = <191 0>;
280280
status = "disabled";
281281
};
@@ -287,6 +287,7 @@
287287
clocks = <&sccon RTS5912_SCCON_UART UART0_CLKPWR>;
288288
clock-names = "uart0";
289289
status = "disabled";
290+
uart-dev = <&uart0>;
290291
};
291292

292293
pinctrl: pin-controller@40090000 {

dts/bindings/serial/realtek,rts5912-uart.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,16 @@ properties:
2222

2323
pinctrl-names:
2424
required: true
25+
26+
rx-gpios:
27+
description: |
28+
Select the wake up pin for uart rx,
29+
please check include/zephyr/dt-bindings/gpio/realtek-gpio.h
30+
For example:
31+
rx-gpios = <RTS5912_GPIO113 GPIO_ACTIVE_HIGH>;
32+
type: phandle-array
33+
34+
uart-dev:
35+
type: phandle
36+
description: |
37+
Get the device of the UART device

include/zephyr/drivers/gpio/gpio_rts5912.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ static ALWAYS_INLINE void gpio_rts5912_set_wakeup_pin(uint32_t pin_num)
3030

3131
int gpio_rts5912_get_pin_num(const struct gpio_dt_spec *gpio);
3232

33-
uint32_t gpio_rts5912_get_port_address(const struct gpio_dt_spec *gpio);
33+
uint32_t *gpio_rts5912_get_port_address(const struct gpio_dt_spec *gpio);
3434

3535
#ifdef __cplusplus
3636
}

0 commit comments

Comments
 (0)