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