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