1 /*
2  * Copyright (c) 2019 Intel Corporation
3  * Copyright (c) 2022 Microchip Technology Inc.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #define DT_DRV_COMPAT microchip_xec_ps2
9 
10 #include <cmsis_core.h>
11 #include <errno.h>
12 #include <zephyr/device.h>
13 #include <zephyr/kernel.h>
14 #ifdef CONFIG_SOC_SERIES_MEC172X
15 #include <zephyr/drivers/clock_control/mchp_xec_clock_control.h>
16 #include <zephyr/drivers/interrupt_controller/intc_mchp_xec_ecia.h>
17 #endif
18 #include <zephyr/drivers/pinctrl.h>
19 #ifdef CONFIG_PM_DEVICE
20 #include <zephyr/pm/device.h>
21 #include <zephyr/pm/policy.h>
22 #endif
23 #include <zephyr/drivers/ps2.h>
24 #include <soc.h>
25 #include <zephyr/logging/log.h>
26 #include <zephyr/irq.h>
27 #include <zephyr/drivers/gpio.h>
28 
29 #define LOG_LEVEL CONFIG_PS2_LOG_LEVEL
30 LOG_MODULE_REGISTER(ps2_mchp_xec);
31 
32 /* in 50us units */
33 #define PS2_TIMEOUT 10000
34 
35 struct ps2_xec_config {
36 	struct ps2_regs * const regs;
37 	int isr_nvic;
38 	uint8_t girq_id;
39 	uint8_t girq_bit;
40 	uint8_t girq_id_wk;
41 	uint8_t girq_bit_wk;
42 	uint8_t pcr_idx;
43 	uint8_t pcr_pos;
44 	void (*irq_config_func)(void);
45 	const struct pinctrl_dev_config *pcfg;
46 #ifdef CONFIG_PM_DEVICE
47 	struct gpio_dt_spec wakerx_gpio;
48 	bool wakeup_source;
49 #endif
50 };
51 
52 
53 struct ps2_xec_data {
54 	ps2_callback_t callback_isr;
55 	struct k_sem tx_lock;
56 };
57 
58 
59 #ifdef CONFIG_SOC_SERIES_MEC172X
ps2_xec_slp_en_clr(const struct device * dev)60 static inline void ps2_xec_slp_en_clr(const struct device *dev)
61 {
62 	const struct ps2_xec_config * const cfg = dev->config;
63 
64 	z_mchp_xec_pcr_periph_sleep(cfg->pcr_idx, cfg->pcr_pos, 0);
65 }
66 
ps2_xec_girq_clr(uint8_t girq_idx,uint8_t girq_posn)67 static inline void ps2_xec_girq_clr(uint8_t girq_idx, uint8_t girq_posn)
68 {
69 	mchp_soc_ecia_girq_src_clr(girq_idx, girq_posn);
70 }
71 
ps2_xec_girq_en(uint8_t girq_idx,uint8_t girq_posn)72 static inline void ps2_xec_girq_en(uint8_t girq_idx, uint8_t girq_posn)
73 {
74 	mchp_xec_ecia_girq_src_en(girq_idx, girq_posn);
75 }
76 
ps2_xec_girq_dis(uint8_t girq_idx,uint8_t girq_posn)77 static inline void ps2_xec_girq_dis(uint8_t girq_idx, uint8_t girq_posn)
78 {
79 	mchp_xec_ecia_girq_src_dis(girq_idx, girq_posn);
80 }
81 #else
ps2_xec_slp_en_clr(const struct device * dev)82 static inline void ps2_xec_slp_en_clr(const struct device *dev)
83 {
84 	const struct ps2_xec_config * const cfg = dev->config;
85 
86 	if (cfg->pcr_pos == MCHP_PCR3_PS2_0_POS) {
87 		mchp_pcr_periph_slp_ctrl(PCR_PS2_0, 0);
88 	} else {
89 		mchp_pcr_periph_slp_ctrl(PCR_PS2_1, 0);
90 	}
91 }
92 
ps2_xec_girq_clr(uint8_t girq_idx,uint8_t girq_posn)93 static inline void ps2_xec_girq_clr(uint8_t girq_idx, uint8_t girq_posn)
94 {
95 	MCHP_GIRQ_SRC(girq_idx) = BIT(girq_posn);
96 }
97 
ps2_xec_girq_en(uint8_t girq_idx,uint8_t girq_posn)98 static inline void ps2_xec_girq_en(uint8_t girq_idx, uint8_t girq_posn)
99 {
100 	MCHP_GIRQ_ENSET(girq_idx) = BIT(girq_posn);
101 }
102 
ps2_xec_girq_dis(uint8_t girq_idx,uint8_t girq_posn)103 static inline void ps2_xec_girq_dis(uint8_t girq_idx, uint8_t girq_posn)
104 {
105 	MCHP_GIRQ_ENCLR(girq_idx) = MCHP_KBC_IBF_GIRQ;
106 }
107 #endif /* CONFIG_SOC_SERIES_MEC172X */
108 
ps2_xec_configure(const struct device * dev,ps2_callback_t callback_isr)109 static int ps2_xec_configure(const struct device *dev,
110 			     ps2_callback_t callback_isr)
111 {
112 	const struct ps2_xec_config * const config = dev->config;
113 	struct ps2_xec_data * const data = dev->data;
114 	struct ps2_regs * const regs = config->regs;
115 
116 	uint8_t  __attribute__((unused)) temp;
117 
118 	if (!callback_isr) {
119 		return -EINVAL;
120 	}
121 
122 	data->callback_isr = callback_isr;
123 
124 	/* In case the self test for a PS2 device already finished and
125 	 * set the SOURCE bit to 1 we clear it before enabling the
126 	 * interrupts. Instances must be allocated before the BAT
127 	 * (Basic Assurance Test) or the host may time out.
128 	 */
129 	temp = regs->TRX_BUFF;
130 	regs->STATUS = MCHP_PS2_STATUS_RW1C_MASK;
131 	/* clear next higher level */
132 	ps2_xec_girq_clr(config->girq_id, config->girq_bit);
133 
134 	/* Enable FSM and init instance in rx mode*/
135 	regs->CTRL = MCHP_PS2_CTRL_EN_POS;
136 
137 	/* We enable the interrupts in the EC aggregator so that the
138 	 * result  can be forwarded to the ARM NVIC
139 	 */
140 	ps2_xec_girq_en(config->girq_id, config->girq_bit);
141 
142 	k_sem_give(&data->tx_lock);
143 
144 	return 0;
145 }
146 
147 
ps2_xec_write(const struct device * dev,uint8_t value)148 static int ps2_xec_write(const struct device *dev, uint8_t value)
149 {
150 	const struct ps2_xec_config * const config = dev->config;
151 	struct ps2_xec_data * const data = dev->data;
152 	struct ps2_regs * const regs = config->regs;
153 	int i = 0;
154 
155 	uint8_t  __attribute__((unused)) temp;
156 
157 	if (k_sem_take(&data->tx_lock, K_NO_WAIT)) {
158 		return -EACCES;
159 	}
160 	/* Allow the PS2 controller to complete a RX transaction. This
161 	 * is because the channel may be actively receiving data.
162 	 * In addition, it is necessary to wait for a previous TX
163 	 * transaction to complete. The PS2 block has a single
164 	 * FSM.
165 	 */
166 	while (((regs->STATUS &
167 		(MCHP_PS2_STATUS_RX_BUSY | MCHP_PS2_STATUS_TX_IDLE))
168 		!= MCHP_PS2_STATUS_TX_IDLE) && (i < PS2_TIMEOUT)) {
169 		k_busy_wait(50);
170 		i++;
171 	}
172 
173 	if (unlikely(i == PS2_TIMEOUT)) {
174 		LOG_DBG("PS2 write timed out");
175 		return -ETIMEDOUT;
176 	}
177 #ifdef CONFIG_PM_DEVICE
178 	pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
179 #endif
180 	/* Inhibit ps2 controller and clear status register */
181 	regs->CTRL = 0x00;
182 
183 	/* Read to clear data ready bit in the status register*/
184 	temp = regs->TRX_BUFF;
185 	k_sleep(K_MSEC(1));
186 	regs->STATUS = MCHP_PS2_STATUS_RW1C_MASK;
187 
188 	/* Switch the interface to TX mode and enable state machine */
189 	regs->CTRL = MCHP_PS2_CTRL_TR_TX | MCHP_PS2_CTRL_EN;
190 
191 	/* Write value to TX/RX register */
192 	regs->TRX_BUFF = value;
193 
194 	k_sem_give(&data->tx_lock);
195 
196 	return 0;
197 }
198 
ps2_xec_inhibit_interface(const struct device * dev)199 static int ps2_xec_inhibit_interface(const struct device *dev)
200 {
201 	const struct ps2_xec_config * const config = dev->config;
202 	struct ps2_xec_data * const data = dev->data;
203 	struct ps2_regs * const regs = config->regs;
204 
205 	if (k_sem_take(&data->tx_lock, K_MSEC(10)) != 0) {
206 		return -EACCES;
207 	}
208 
209 	regs->CTRL = 0x00;
210 	regs->STATUS = MCHP_PS2_STATUS_RW1C_MASK;
211 	ps2_xec_girq_clr(config->girq_id, config->girq_bit);
212 	NVIC_ClearPendingIRQ(config->isr_nvic);
213 
214 	k_sem_give(&data->tx_lock);
215 
216 	return 0;
217 }
218 
ps2_xec_enable_interface(const struct device * dev)219 static int ps2_xec_enable_interface(const struct device *dev)
220 {
221 	const struct ps2_xec_config * const config = dev->config;
222 	struct ps2_xec_data * const data = dev->data;
223 	struct ps2_regs * const regs = config->regs;
224 
225 	ps2_xec_girq_clr(config->girq_id, config->girq_bit);
226 	regs->CTRL = MCHP_PS2_CTRL_EN;
227 
228 	k_sem_give(&data->tx_lock);
229 
230 	return 0;
231 }
232 
233 #ifdef CONFIG_PM_DEVICE
ps2_xec_pm_action(const struct device * dev,enum pm_device_action action)234 static int ps2_xec_pm_action(const struct device *dev, enum pm_device_action action)
235 {
236 	const struct ps2_xec_config *const devcfg = dev->config;
237 	struct ps2_regs * const regs = devcfg->regs;
238 	int ret = 0;
239 
240 	switch (action) {
241 	case PM_DEVICE_ACTION_RESUME:
242 		if (devcfg->wakeup_source) {
243 			/* Disable PS2 wake interrupt
244 			 * Disable interrupt on PS2DAT pin
245 			 */
246 			if (devcfg->wakerx_gpio.port != NULL) {
247 				ret = gpio_pin_interrupt_configure_dt(
248 						&devcfg->wakerx_gpio,
249 						GPIO_INT_DISABLE);
250 				if (ret < 0) {
251 					LOG_ERR("Fail to disable PS2 wake interrupt (ret %d)", ret);
252 					return ret;
253 				}
254 			}
255 			ps2_xec_girq_dis(devcfg->girq_id_wk, devcfg->girq_bit_wk);
256 			ps2_xec_girq_clr(devcfg->girq_id_wk, devcfg->girq_bit_wk);
257 		} else {
258 			ret = pinctrl_apply_state(devcfg->pcfg, PINCTRL_STATE_DEFAULT);
259 			regs->CTRL |= MCHP_PS2_CTRL_EN;
260 		}
261 	break;
262 	case PM_DEVICE_ACTION_SUSPEND:
263 		if (devcfg->wakeup_source) {
264 			/* Enable PS2 wake interrupt
265 			 * Configure Falling Edge Trigger interrupt on PS2DAT pin
266 			 */
267 			ps2_xec_girq_clr(devcfg->girq_id_wk, devcfg->girq_bit_wk);
268 			ps2_xec_girq_en(devcfg->girq_id_wk, devcfg->girq_bit_wk);
269 			if (devcfg->wakerx_gpio.port != NULL) {
270 				ret = gpio_pin_interrupt_configure_dt(
271 					&devcfg->wakerx_gpio,
272 					GPIO_INT_MODE_EDGE | GPIO_INT_TRIG_LOW);
273 				if (ret < 0) {
274 					LOG_ERR("Fail to enable PS2 wake interrupt(ret %d)", ret);
275 					return ret;
276 				}
277 			}
278 		} else {
279 			regs->CTRL &= ~MCHP_PS2_CTRL_EN;
280 			/* If application does not want to turn off PS2 pins it will
281 			 * not define pinctrl-1 for this node.
282 			 */
283 			ret = pinctrl_apply_state(devcfg->pcfg, PINCTRL_STATE_SLEEP);
284 			if (ret == -ENOENT) { /* pinctrl-1 does not exist.  */
285 				ret = 0;
286 			}
287 		}
288 	break;
289 	default:
290 		ret = -ENOTSUP;
291 	}
292 
293 	return ret;
294 }
295 #endif /* CONFIG_PM_DEVICE */
296 
ps2_xec_isr(const struct device * dev)297 static void ps2_xec_isr(const struct device *dev)
298 {
299 	const struct ps2_xec_config * const config = dev->config;
300 	struct ps2_xec_data * const data = dev->data;
301 	struct ps2_regs * const regs = config->regs;
302 	uint32_t status;
303 
304 	/* Read and clear status */
305 	status = regs->STATUS;
306 
307 	/* clear next higher level the GIRQ */
308 	ps2_xec_girq_clr(config->girq_id, config->girq_bit);
309 
310 	if (status & MCHP_PS2_STATUS_RXD_RDY) {
311 #ifdef CONFIG_PM_DEVICE
312 		pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
313 #endif
314 		regs->CTRL = 0x00;
315 		if (data->callback_isr) {
316 			data->callback_isr(dev, regs->TRX_BUFF);
317 		}
318 #ifdef CONFIG_PM_DEVICE
319 		pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
320 #endif
321 	} else if (status &
322 		    (MCHP_PS2_STATUS_TX_TMOUT | MCHP_PS2_STATUS_TX_ST_TMOUT)) {
323 		/* Clear sticky bits and go to read mode */
324 		regs->STATUS = MCHP_PS2_STATUS_RW1C_MASK;
325 		LOG_ERR("TX time out: %0x", status);
326 #ifdef CONFIG_PM_DEVICE
327 		pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
328 #endif
329 	} else if (status &
330 			(MCHP_PS2_STATUS_RX_TMOUT | MCHP_PS2_STATUS_PE | MCHP_PS2_STATUS_FE)) {
331 		/* catch and clear rx error if any */
332 		regs->STATUS = MCHP_PS2_STATUS_RW1C_MASK;
333 	} else if (status & MCHP_PS2_STATUS_TX_IDLE) {
334 		/* Transfer completed, release the lock to enter low per mode */
335 #ifdef CONFIG_PM_DEVICE
336 		pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
337 #endif
338 	}
339 
340 	/* The control register reverts to RX automatically after
341 	 * transmitting the data
342 	 */
343 	regs->CTRL = MCHP_PS2_CTRL_EN;
344 }
345 
346 static const struct ps2_driver_api ps2_xec_driver_api = {
347 	.config = ps2_xec_configure,
348 	.read = NULL,
349 	.write = ps2_xec_write,
350 	.disable_callback = ps2_xec_inhibit_interface,
351 	.enable_callback = ps2_xec_enable_interface,
352 };
353 
ps2_xec_init(const struct device * dev)354 static int ps2_xec_init(const struct device *dev)
355 {
356 	const struct ps2_xec_config * const cfg = dev->config;
357 	struct ps2_xec_data * const data = dev->data;
358 	int ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
359 	if (ret != 0) {
360 		LOG_ERR("XEC PS2 pinctrl init failed (%d)", ret);
361 		return ret;
362 	}
363 
364 	ps2_xec_slp_en_clr(dev);
365 
366 	k_sem_init(&data->tx_lock, 0, 1);
367 
368 	cfg->irq_config_func();
369 
370 	return 0;
371 }
372 
373 /* To enable wakeup on the PS2, the DTS needs to have two entries defined
374  * in the corresponding PS2 node in the DTS specifying it as a wake source
375  * and specifying the PS2DAT GPIO; example as below
376  *
377  *	wakerx-gpios = <MCHP_GPIO_DECODE_115 GPIO_ACTIVE_HIGH>
378  *	wakeup-source;
379  */
380 #ifdef CONFIG_PM_DEVICE
381 #define XEC_PS2_PM_WAKEUP(n)						\
382 		.wakeup_source = (uint8_t)DT_INST_PROP_OR(n, wakeup_source, 0),	\
383 		.wakerx_gpio = GPIO_DT_SPEC_INST_GET_OR(n, wakerx_gpios, {0}),
384 #else
385 #define XEC_PS2_PM_WAKEUP(index) /* Not used */
386 #endif
387 
388 #define XEC_PS2_PINCTRL_CFG(inst) PINCTRL_DT_INST_DEFINE(inst)
389 #define XEC_PS2_CONFIG(inst)							\
390 	static const struct ps2_xec_config ps2_xec_config_##inst = {		\
391 		.regs = (struct ps2_regs * const)(DT_INST_REG_ADDR(inst)),	\
392 		.isr_nvic = DT_INST_IRQN(inst),					\
393 		.girq_id = (uint8_t)(DT_INST_PROP_BY_IDX(inst, girqs, 0)),	\
394 		.girq_bit = (uint8_t)(DT_INST_PROP_BY_IDX(inst, girqs, 1)),	\
395 		.girq_id_wk = (uint8_t)(DT_INST_PROP_BY_IDX(inst, girqs, 2)),	\
396 		.girq_bit_wk = (uint8_t)(DT_INST_PROP_BY_IDX(inst, girqs, 3)),	\
397 		.pcr_idx = (uint8_t)(DT_INST_PROP_BY_IDX(inst, pcrs, 0)),	\
398 		.pcr_pos = (uint8_t)(DT_INST_PROP_BY_IDX(inst, pcrs, 1)),	\
399 		.irq_config_func = ps2_xec_irq_config_func_##inst,		\
400 		.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst),			\
401 		XEC_PS2_PM_WAKEUP(inst)						\
402 	}
403 
404 #define PS2_XEC_DEVICE(i)						\
405 									\
406 	static void ps2_xec_irq_config_func_##i(void)			\
407 	{								\
408 		IRQ_CONNECT(DT_INST_IRQN(i),				\
409 			    DT_INST_IRQ(i, priority),			\
410 			    ps2_xec_isr,				\
411 			    DEVICE_DT_INST_GET(i), 0);			\
412 		irq_enable(DT_INST_IRQN(i));				\
413 	}								\
414 									\
415 	static struct ps2_xec_data ps2_xec_port_data_##i;		\
416 									\
417 	XEC_PS2_PINCTRL_CFG(i);						\
418 									\
419 	XEC_PS2_CONFIG(i);						\
420 									\
421 	PM_DEVICE_DT_INST_DEFINE(i, ps2_xec_pm_action);		\
422 									\
423 	DEVICE_DT_INST_DEFINE(i, &ps2_xec_init,				\
424 		PM_DEVICE_DT_INST_GET(i),				\
425 		&ps2_xec_port_data_##i, &ps2_xec_config_##i,		\
426 		POST_KERNEL, CONFIG_PS2_INIT_PRIORITY,			\
427 		&ps2_xec_driver_api);
428 
429 DT_INST_FOREACH_STATUS_OKAY(PS2_XEC_DEVICE)
430