1 /*
2 * Copyright (c) 2021 ITE Corporation. All Rights Reserved.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT ite_it8xxx2_uart
8
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/gpio.h>
11 #include <zephyr/drivers/pinctrl.h>
12 #include <zephyr/drivers/uart.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/pm/device.h>
15 #include <zephyr/pm/policy.h>
16 #include <soc.h>
17
18 #include <zephyr/logging/log.h>
19 LOG_MODULE_REGISTER(uart_ite_it8xxx2, CONFIG_UART_LOG_LEVEL);
20
21 #if defined(CONFIG_PM_DEVICE) && defined(CONFIG_UART_CONSOLE_INPUT_EXPIRED)
22 static struct uart_it8xxx2_data *uart_console_data;
23 #endif
24
25 struct uart_it8xxx2_config {
26 uint8_t port;
27 /* GPIO cells */
28 struct gpio_dt_spec gpio_wui;
29 /* UART handle */
30 const struct device *uart_dev;
31 /* UART alternate configuration */
32 const struct pinctrl_dev_config *pcfg;
33 };
34
35 struct uart_it8xxx2_data {
36 #ifdef CONFIG_UART_CONSOLE_INPUT_EXPIRED
37 struct k_work_delayable rx_refresh_timeout_work;
38 #endif
39 };
40
41 enum uart_port_num {
42 UART1 = 1,
43 UART2,
44 };
45
46 #ifdef CONFIG_PM_DEVICE
uart1_wui_isr(const struct device * gpio,struct gpio_callback * cb,uint32_t pins)47 void uart1_wui_isr(const struct device *gpio, struct gpio_callback *cb,
48 uint32_t pins)
49 {
50 /* Disable interrupts on UART1 RX pin to avoid repeated interrupts. */
51 (void)gpio_pin_interrupt_configure(gpio, (find_msb_set(pins) - 1),
52 GPIO_INT_DISABLE);
53
54 /* Refresh console expired time if got UART Rx wake-up event */
55 #ifdef CONFIG_UART_CONSOLE_INPUT_EXPIRED
56 k_timeout_t delay = K_MSEC(CONFIG_UART_CONSOLE_INPUT_EXPIRED_TIMEOUT);
57
58 /*
59 * The pm state of it8xxx2 chip only supports standby, so here we
60 * can directly set the constraint for standby.
61 */
62 pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
63 k_work_reschedule(&uart_console_data->rx_refresh_timeout_work, delay);
64 #endif
65 }
66
uart2_wui_isr(const struct device * gpio,struct gpio_callback * cb,uint32_t pins)67 void uart2_wui_isr(const struct device *gpio, struct gpio_callback *cb,
68 uint32_t pins)
69 {
70 /* Disable interrupts on UART2 RX pin to avoid repeated interrupts. */
71 (void)gpio_pin_interrupt_configure(gpio, (find_msb_set(pins) - 1),
72 GPIO_INT_DISABLE);
73
74 /* Refresh console expired time if got UART Rx wake-up event */
75 #ifdef CONFIG_UART_CONSOLE_INPUT_EXPIRED
76 k_timeout_t delay = K_MSEC(CONFIG_UART_CONSOLE_INPUT_EXPIRED_TIMEOUT);
77
78 /*
79 * The pm state of it8xxx2 chip only supports standby, so here we
80 * can directly set the constraint for standby.
81 */
82 pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
83 k_work_reschedule(&uart_console_data->rx_refresh_timeout_work, delay);
84 #endif
85 }
86
uart_it8xxx2_pm_action(const struct device * dev,enum pm_device_action action)87 static inline int uart_it8xxx2_pm_action(const struct device *dev,
88 enum pm_device_action action)
89 {
90 const struct uart_it8xxx2_config *const config = dev->config;
91 int ret = 0;
92
93 switch (action) {
94 /* Next device power state is in active. */
95 case PM_DEVICE_ACTION_RESUME:
96 /* Nothing to do. */
97 break;
98 /* Next device power state is deep doze mode */
99 case PM_DEVICE_ACTION_SUSPEND:
100 /* Enable UART WUI */
101 ret = gpio_pin_interrupt_configure_dt(&config->gpio_wui,
102 GPIO_INT_MODE_EDGE | GPIO_INT_TRIG_LOW);
103 if (ret < 0) {
104 LOG_ERR("Failed to configure UART%d WUI (ret %d)",
105 config->port, ret);
106 return ret;
107 }
108
109 break;
110 default:
111 return -ENOTSUP;
112 }
113
114 return 0;
115 }
116
117 #ifdef CONFIG_UART_CONSOLE_INPUT_EXPIRED
uart_it8xxx2_rx_refresh_timeout(struct k_work * work)118 static void uart_it8xxx2_rx_refresh_timeout(struct k_work *work)
119 {
120 ARG_UNUSED(work);
121
122 pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
123 }
124 #endif
125 #endif /* CONFIG_PM_DEVICE */
126
127
uart_it8xxx2_init(const struct device * dev)128 static int uart_it8xxx2_init(const struct device *dev)
129 {
130 const struct uart_it8xxx2_config *const config = dev->config;
131 int status;
132
133 /* Set the pin to UART alternate function. */
134 status = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
135 if (status < 0) {
136 LOG_ERR("Failed to configure UART pins");
137 return status;
138 }
139
140 #ifdef CONFIG_PM_DEVICE
141 const struct device *uart_console_dev =
142 DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
143 int ret = 0;
144
145 /*
146 * If the UART is used as a console device, we need to configure
147 * UART Rx interrupt as wakeup source and initialize a delayable
148 * work for console expired time.
149 */
150 if (config->uart_dev == uart_console_dev) {
151 #ifdef CONFIG_UART_CONSOLE_INPUT_EXPIRED
152 uart_console_data = dev->data;
153 k_work_init_delayable(&uart_console_data->rx_refresh_timeout_work,
154 uart_it8xxx2_rx_refresh_timeout);
155 #endif
156 /*
157 * When the system enters deep doze, all clocks are gated only the
158 * 32.768k clock is active. We need to wakeup EC by configuring
159 * UART Rx interrupt as a wakeup source. When the interrupt of UART
160 * Rx falling, EC will be woken.
161 */
162 if (config->port == UART1) {
163 static struct gpio_callback uart1_wui_cb;
164
165 gpio_init_callback(&uart1_wui_cb, uart1_wui_isr,
166 BIT(config->gpio_wui.pin));
167
168 ret = gpio_add_callback(config->gpio_wui.port, &uart1_wui_cb);
169 } else if (config->port == UART2) {
170 static struct gpio_callback uart2_wui_cb;
171
172 gpio_init_callback(&uart2_wui_cb, uart2_wui_isr,
173 BIT(config->gpio_wui.pin));
174
175 ret = gpio_add_callback(config->gpio_wui.port, &uart2_wui_cb);
176 }
177
178 if (ret < 0) {
179 LOG_ERR("Failed to add UART%d callback (err %d)",
180 config->port, ret);
181 return ret;
182 }
183 }
184 #endif /* CONFIG_PM_DEVICE */
185
186 return 0;
187 }
188
189 #define UART_ITE_IT8XXX2_INIT(inst) \
190 PINCTRL_DT_INST_DEFINE(inst); \
191 static const struct uart_it8xxx2_config uart_it8xxx2_cfg_##inst = { \
192 .port = DT_INST_PROP(inst, port_num), \
193 .gpio_wui = GPIO_DT_SPEC_INST_GET(inst, gpios), \
194 .uart_dev = DEVICE_DT_GET(DT_INST_PHANDLE(inst, uart_dev)), \
195 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
196 }; \
197 \
198 static struct uart_it8xxx2_data uart_it8xxx2_data_##inst; \
199 \
200 PM_DEVICE_DT_INST_DEFINE(inst, uart_it8xxx2_pm_action); \
201 DEVICE_DT_INST_DEFINE(inst, &uart_it8xxx2_init, \
202 PM_DEVICE_DT_INST_GET(inst), \
203 &uart_it8xxx2_data_##inst, \
204 &uart_it8xxx2_cfg_##inst, \
205 PRE_KERNEL_1, \
206 CONFIG_UART_ITE_IT8XXX2_INIT_PRIORITY, \
207 NULL);
208
209 DT_INST_FOREACH_STATUS_OKAY(UART_ITE_IT8XXX2_INIT)
210