1 /*
2  * Copyright (c) 2021 Nuvoton Technology Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nuvoton_npcx_ps2_ctrl
8 
9 /**
10  * @file
11  * @brief Nuvoton NPCX PS/2 module (controller) driver
12  *
13  * This file contains the driver of PS/2 module (controller) which provides a
14  * hardware accelerator mechanism to handle both incoming and outgoing data.
15  * The hardware accelerator mechanism is shared by four PS/2 channels.
16  */
17 
18 #include <zephyr/kernel.h>
19 #include <zephyr/drivers/clock_control.h>
20 #include <zephyr/drivers/ps2.h>
21 #include <zephyr/dt-bindings/clock/npcx_clock.h>
22 
23 #include <zephyr/logging/log.h>
24 #include <zephyr/irq.h>
25 LOG_MODULE_REGISTER(ps2_npcx_ctrl, CONFIG_PS2_LOG_LEVEL);
26 
27 #define NPCX_PS2_CH_COUNT 4
28 
29 /*
30  * Set WDAT3-0 and clear CLK3-0 in the PSOSIG register to
31  * reset the shift mechanism.
32  */
33 #define NPCX_PS2_SHIFT_MECH_RESET (uint8_t)~NPCX_PSOSIG_CLK_MASK_ALL
34 
35 /* in 50us units */
36 #define PS2_RETRY_COUNT 10000
37 
38 /*
39  * The max duration of a PS/2 clock is about 100 micro-seconds.
40  * A PS/2 transaction needs 11 clock cycles. It will take about 1.1 ms for a
41  * complete transaction.
42  */
43 #define PS2_TRANSACTION_TIMEOUT K_MSEC(2)
44 
45 /* Device config */
46 struct ps2_npcx_ctrl_config {
47 	uintptr_t base;
48 	struct npcx_clk_cfg clk_cfg;
49 };
50 
51 /* Driver data */
52 struct ps2_npcx_ctrl_data {
53 	/*
54 	 * Bit mask to record the enabled PS/2 channels.
55 	 * Only bit[7] and bit[5:3] are used
56 	 * (i.e. the bit position of CLK3-0 in the PS2_PSOSIG register)
57 	 */
58 	uint8_t channel_enabled_mask;
59 	/* The mutex of the PS/2 controller */
60 	struct k_sem lock;
61 	/* The semaphore to synchronize the Tx transaction */
62 	struct k_sem tx_sync_sem;
63 	/*
64 	 * The callback function to handle the data received from PS/2 device
65 	 */
66 	ps2_callback_t callback_isr[NPCX_PS2_CH_COUNT];
67 };
68 
69 /* Driver convenience defines */
70 #define HAL_PS2_INSTANCE(dev)                                                                      \
71 	((struct ps2_reg *)((const struct ps2_npcx_ctrl_config *)(dev)->config)->base)
72 
ps2_npcx_ctrl_get_ch_clk_mask(uint8_t channel_id)73 static uint8_t ps2_npcx_ctrl_get_ch_clk_mask(uint8_t channel_id)
74 {
75 	return BIT(NPCX_PSOSIG_CLK(channel_id));
76 }
77 
ps2_npcx_ctrl_configure(const struct device * dev,uint8_t channel_id,ps2_callback_t callback_isr)78 int ps2_npcx_ctrl_configure(const struct device *dev, uint8_t channel_id,
79 			    ps2_callback_t callback_isr)
80 {
81 	struct ps2_npcx_ctrl_data *const data = dev->data;
82 
83 	if (channel_id >= NPCX_PS2_CH_COUNT) {
84 		LOG_ERR("unexpected channel ID: %d", channel_id);
85 		return -EINVAL;
86 	}
87 
88 	if (callback_isr == NULL) {
89 		return -EINVAL;
90 	}
91 
92 	k_sem_take(&data->lock, K_FOREVER);
93 	data->callback_isr[channel_id] = callback_isr;
94 	k_sem_give(&data->lock);
95 
96 	return 0;
97 }
98 
ps2_npcx_ctrl_enable_interface(const struct device * dev,uint8_t channel_id,bool enable)99 int ps2_npcx_ctrl_enable_interface(const struct device *dev, uint8_t channel_id,
100 				   bool enable)
101 {
102 	struct ps2_npcx_ctrl_data *const data = dev->data;
103 	struct ps2_reg *const inst = HAL_PS2_INSTANCE(dev);
104 	uint8_t ch_clk_mask;
105 
106 	k_sem_take(&data->lock, K_FOREVER);
107 	/*
108 	 * Disable the interrupt during changing the enabled channel mask to
109 	 * prevent from preemption.
110 	 */
111 	irq_disable(DT_INST_IRQN(0));
112 
113 	if (channel_id >= NPCX_PS2_CH_COUNT) {
114 		LOG_ERR("unexpected channel ID: %d", channel_id);
115 		irq_enable(DT_INST_IRQN(0));
116 		k_sem_give(&data->lock);
117 		return -EINVAL;
118 	}
119 
120 	ch_clk_mask = ps2_npcx_ctrl_get_ch_clk_mask(channel_id);
121 	if (enable) {
122 		data->channel_enabled_mask |= ch_clk_mask;
123 		/* Enable the relevant channel clock */
124 		inst->PSOSIG |= ch_clk_mask;
125 	} else {
126 		data->channel_enabled_mask &= ~ch_clk_mask;
127 		/* Disable the relevant channel clock */
128 		inst->PSOSIG &= ~ch_clk_mask;
129 	}
130 
131 	irq_enable(DT_INST_IRQN(0));
132 	k_sem_give(&data->lock);
133 
134 	return 0;
135 }
136 
ps2_npcx_ctrl_bus_busy(const struct device * dev)137 static int ps2_npcx_ctrl_bus_busy(const struct device *dev)
138 {
139 	struct ps2_reg *const inst = HAL_PS2_INSTANCE(dev);
140 
141 	/*
142 	 * The driver pulls the CLK for non-active channels to low when Start
143 	 * bit is detected and pull the CLK of the active channel low after
144 	 * Stop bit detected. The EOT bit is set when Stop bit is detected,
145 	 * but both SOT and EOT are cleared when all CLKs are pull low
146 	 * (due to Shift Mechanism is reset)
147 	 */
148 	return (IS_BIT_SET(inst->PSTAT, NPCX_PSTAT_SOT) ||
149 		IS_BIT_SET(inst->PSTAT, NPCX_PSTAT_EOT)) ?
150 		       -EBUSY :
151 		       0;
152 }
153 
ps2_npcx_ctrl_write(const struct device * dev,uint8_t channel_id,uint8_t value)154 int ps2_npcx_ctrl_write(const struct device *dev, uint8_t channel_id,
155 			uint8_t value)
156 {
157 	struct ps2_npcx_ctrl_data *const data = dev->data;
158 	struct ps2_reg *const inst = HAL_PS2_INSTANCE(dev);
159 	int i = 0;
160 
161 	if (channel_id >= NPCX_PS2_CH_COUNT) {
162 		LOG_ERR("unexpected channel ID: %d", channel_id);
163 		return -EINVAL;
164 	}
165 
166 	if (!(ps2_npcx_ctrl_get_ch_clk_mask(channel_id) &
167 	      data->channel_enabled_mask)) {
168 		LOG_ERR("channel %d is not enabled", channel_id);
169 		return -EINVAL;
170 	}
171 
172 	k_sem_take(&data->lock, K_FOREVER);
173 
174 	while (ps2_npcx_ctrl_bus_busy(dev) && (i < PS2_RETRY_COUNT)) {
175 		k_busy_wait(50);
176 		i++;
177 	}
178 
179 	if (unlikely(i == PS2_RETRY_COUNT)) {
180 		LOG_ERR("PS2 write attempt timed out");
181 		goto timeout_invalid;
182 	}
183 
184 	/* Set PS/2 in transmit mode */
185 	inst->PSCON |= BIT(NPCX_PSCON_XMT);
186 	/* Enable Start Of Transaction interrupt */
187 	inst->PSIEN |= BIT(NPCX_PSIEN_SOTIE);
188 
189 	/* Reset the shift mechanism */
190 	inst->PSOSIG = NPCX_PS2_SHIFT_MECH_RESET;
191 	/* Inhibit communication should last at least 100 micro-seconds */
192 	k_busy_wait(100);
193 
194 	/* Write the data to be transmitted */
195 	inst->PSDAT = value;
196 	/* Apply the Request-to-send */
197 	inst->PSOSIG &= ~BIT(NPCX_PSOSIG_WDAT(channel_id));
198 	inst->PSOSIG |= ps2_npcx_ctrl_get_ch_clk_mask(channel_id);
199 	if (k_sem_take(&data->tx_sync_sem, PS2_TRANSACTION_TIMEOUT) != 0) {
200 		irq_disable(DT_INST_IRQN(0));
201 		LOG_ERR("PS/2 Tx timeout");
202 		/* Reset the shift mechanism */
203 		inst->PSOSIG = NPCX_PS2_SHIFT_MECH_RESET;
204 		/* Change the PS/2 module to receive mode */
205 		inst->PSCON &= ~BIT(NPCX_PSCON_XMT);
206 		/*
207 		 * Restore the channel back to enable according to
208 		 * channel_enabled_mask.
209 		 */
210 		inst->PSOSIG |= data->channel_enabled_mask;
211 		irq_enable(DT_INST_IRQN(0));
212 		goto timeout_invalid;
213 	}
214 
215 	k_sem_give(&data->lock);
216 	return 0;
217 
218 timeout_invalid:
219 	k_sem_give(&data->lock);
220 	return -ETIMEDOUT;
221 }
222 
ps2_npcx_ctrl_is_rx_error(const struct device * dev)223 static int ps2_npcx_ctrl_is_rx_error(const struct device *dev)
224 {
225 	struct ps2_reg *const inst = HAL_PS2_INSTANCE(dev);
226 	uint8_t status;
227 
228 	status = inst->PSTAT & (BIT(NPCX_PSTAT_PERR) | BIT(NPCX_PSTAT_RFERR));
229 	if (status) {
230 		if (status & BIT(NPCX_PSTAT_PERR)) {
231 			LOG_ERR("RX parity error");
232 		}
233 		if (status & BIT(NPCX_PSTAT_RFERR)) {
234 			LOG_ERR("RX Frame error");
235 		}
236 		return -EIO;
237 	}
238 
239 	return 0;
240 }
241 
ps2_npcx_ctrl_isr(const struct device * dev)242 static void ps2_npcx_ctrl_isr(const struct device *dev)
243 {
244 	uint8_t active_ch, mask;
245 	struct ps2_reg *const inst = HAL_PS2_INSTANCE(dev);
246 	struct ps2_npcx_ctrl_data *const data = dev->data;
247 
248 	/*
249 	 * ACH = 1 : Channel 0
250 	 * ACH = 2 : Channel 1
251 	 * ACH = 4 : Channel 2
252 	 * ACH = 5 : Channel 3
253 	 */
254 	active_ch = GET_FIELD(inst->PSTAT, NPCX_PSTAT_ACH);
255 	active_ch = active_ch > 2 ? (active_ch - 2) : (active_ch - 1);
256 	LOG_DBG("ACH: %d\n", active_ch);
257 
258 	/*
259 	 * Inhibit PS/2 transaction of the other non-active channels by
260 	 * pulling down the clock signal
261 	 */
262 	mask = ~NPCX_PSOSIG_CLK_MASK_ALL | BIT(NPCX_PSOSIG_CLK(active_ch));
263 	inst->PSOSIG &= mask;
264 
265 	/* PS/2 Start of Transaction */
266 	if (IS_BIT_SET(inst->PSTAT, NPCX_PSTAT_SOT) &&
267 	    IS_BIT_SET(inst->PSIEN, NPCX_PSIEN_SOTIE)) {
268 		/*
269 		 * Once set, SOT is not cleared until the shift mechanism
270 		 * is reset. Therefore, SOTIE should be cleared on the
271 		 * first occurrence of an SOT interrupt.
272 		 */
273 		inst->PSIEN &= ~BIT(NPCX_PSIEN_SOTIE);
274 		LOG_DBG("SOT");
275 		/* PS/2 End of Transaction */
276 	} else if (IS_BIT_SET(inst->PSTAT, NPCX_PSTAT_EOT)) {
277 		inst->PSIEN &= ~BIT(NPCX_PSIEN_EOTIE);
278 
279 		/*
280 		 * Clear the CLK of active channel to reset
281 		 * the shift mechanism
282 		 */
283 		inst->PSOSIG &= ~BIT(NPCX_PSOSIG_CLK(active_ch));
284 
285 		/* Tx is done */
286 		if (IS_BIT_SET(inst->PSCON, NPCX_PSCON_XMT)) {
287 			/* Change the PS/2 module to receive mode */
288 			inst->PSCON &= ~BIT(NPCX_PSCON_XMT);
289 			k_sem_give(&data->tx_sync_sem);
290 		} else {
291 			if (ps2_npcx_ctrl_is_rx_error(dev) == 0) {
292 				ps2_callback_t callback;
293 				uint8_t data_in = inst->PSDAT;
294 
295 				LOG_DBG("Recv:0x%02x", data_in);
296 				callback = data->callback_isr[active_ch];
297 				if (callback != NULL) {
298 					callback(dev, data_in);
299 				}
300 			}
301 		}
302 
303 		/* Restore the enabled channel */
304 		inst->PSOSIG |= data->channel_enabled_mask;
305 		/*
306 		 * Re-enable the Start Of Transaction interrupt when
307 		 * the shift mechanism is reset
308 		 */
309 		inst->PSIEN |= BIT(NPCX_PSIEN_SOTIE);
310 		inst->PSIEN |= BIT(NPCX_PSIEN_EOTIE);
311 		LOG_DBG("EOT");
312 	}
313 }
314 
315 /* PS/2 driver registration */
316 static int ps2_npcx_ctrl_init(const struct device *dev);
317 
318 static struct ps2_npcx_ctrl_data ps2_npcx_ctrl_data_0;
319 
320 static const struct ps2_npcx_ctrl_config ps2_npcx_ctrl_config_0 = {
321 	.base = DT_INST_REG_ADDR(0),
322 	.clk_cfg = NPCX_DT_CLK_CFG_ITEM(0),
323 };
324 
325 DEVICE_DT_INST_DEFINE(0, &ps2_npcx_ctrl_init, NULL, &ps2_npcx_ctrl_data_0,
326 		      &ps2_npcx_ctrl_config_0, POST_KERNEL,
327 		      CONFIG_PS2_INIT_PRIORITY, NULL);
328 
ps2_npcx_ctrl_init(const struct device * dev)329 static int ps2_npcx_ctrl_init(const struct device *dev)
330 {
331 	const struct ps2_npcx_ctrl_config *const config = dev->config;
332 	struct ps2_npcx_ctrl_data *const data = dev->data;
333 	struct ps2_reg *const inst = HAL_PS2_INSTANCE(dev);
334 	const struct device *const clk_dev = DEVICE_DT_GET(NPCX_CLK_CTRL_NODE);
335 	int ret;
336 
337 	if (!device_is_ready(clk_dev)) {
338 		LOG_ERR("%s device not ready", clk_dev->name);
339 		return -ENODEV;
340 	}
341 
342 	/* Turn on PS/2 controller device clock */
343 	ret = clock_control_on(clk_dev,
344 			       (clock_control_subsys_t)&config->clk_cfg);
345 	if (ret < 0) {
346 		LOG_ERR("Turn on PS/2 clock fail %d", ret);
347 		return ret;
348 	}
349 
350 	/* Disable shift mechanism and configure PS/2 to received mode. */
351 	inst->PSCON = 0x0;
352 	/* Set WDAT3-0 and clear CLK3-0 before enabling shift mechanism */
353 	inst->PSOSIG = NPCX_PS2_SHIFT_MECH_RESET;
354 	/*
355 	 * PS/2 interrupt enable register
356 	 * [0] - : SOTIE   = 1: Start Of Transaction Interrupt Enable
357 	 * [1] - : EOTIE   = 1: End Of Transaction Interrupt Enable
358 	 * [4] - : WUE     = 1: Wake-Up Enable
359 	 * [7] - : CLK_SEL = 1: Select Free-Run clock as the basic clock
360 	 *                   0: Select APB1 clock as the basic clock
361 	 */
362 	inst->PSIEN = BIT(NPCX_PSIEN_SOTIE) | BIT(NPCX_PSIEN_EOTIE) |
363 		      BIT(NPCX_PSIEN_PS2_WUE);
364 	if (config->clk_cfg.bus == NPCX_CLOCK_BUS_FREERUN) {
365 		inst->PSIEN |= BIT(NPCX_PSIEN_PS2_CLK_SEL);
366 	}
367 	/* Enable weak internal pull-up */
368 	inst->PSCON |= BIT(NPCX_PSCON_WPUED);
369 	/* Enable shift mechanism */
370 	inst->PSCON |= BIT(NPCX_PSCON_EN);
371 
372 	k_sem_init(&data->lock, 1, 1);
373 	k_sem_init(&data->tx_sync_sem, 0, 1);
374 
375 	IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority),
376 		    ps2_npcx_ctrl_isr, DEVICE_DT_INST_GET(0), 0);
377 
378 	irq_enable(DT_INST_IRQN(0));
379 
380 	return 0;
381 }
382