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