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_channel
8
9 /**
10 * @file
11 * @brief Nuvoton NPCX PS/2 driver
12 *
13 * This file contains the driver of PS/2 buses (channels) which provides the
14 * connection between Zephyr PS/2 API fucntions and NPCX PS/2 controller driver
15 * to support PS/2 transactions.
16 *
17 */
18
19 #include <drivers/clock_control.h>
20 #include <drivers/ps2.h>
21 #include <soc.h>
22
23 #include <logging/log.h>
24 LOG_MODULE_REGISTER(ps2_npcx_channel, CONFIG_PS2_LOG_LEVEL);
25
26 #include "ps2_npcx_controller.h"
27
28 /* Device config */
29 struct ps2_npcx_ch_config {
30 /* pinmux configuration */
31 const uint8_t alts_size;
32 const struct npcx_alt *alts_list;
33 /* Indicate the channel's number of the PS/2 channel device */
34 uint8_t channel_id;
35 const struct device *ps2_ctrl;
36 };
37
38 /* Driver convenience defines */
39 #define DRV_CONFIG(dev) ((const struct ps2_npcx_ch_config *)(dev)->config)
40
41 /* PS/2 api functions */
ps2_npcx_ch_configure(const struct device * dev,ps2_callback_t callback_isr)42 static int ps2_npcx_ch_configure(const struct device *dev,
43 ps2_callback_t callback_isr)
44 {
45 const struct ps2_npcx_ch_config *const config = DRV_CONFIG(dev);
46 int ret;
47
48 ret = ps2_npcx_ctrl_configure(config->ps2_ctrl, config->channel_id,
49 callback_isr);
50 if (ret != 0)
51 return ret;
52
53 return ps2_npcx_ctrl_enable_interface(config->ps2_ctrl,
54 config->channel_id, 1);
55 }
56
ps2_npcx_ch_write(const struct device * dev,uint8_t value)57 static int ps2_npcx_ch_write(const struct device *dev, uint8_t value)
58 {
59 const struct ps2_npcx_ch_config *const config = DRV_CONFIG(dev);
60
61 return ps2_npcx_ctrl_write(config->ps2_ctrl, config->channel_id, value);
62 }
63
ps2_npcx_ch_enable_interface(const struct device * dev)64 static int ps2_npcx_ch_enable_interface(const struct device *dev)
65 {
66 const struct ps2_npcx_ch_config *const config = DRV_CONFIG(dev);
67
68 return ps2_npcx_ctrl_enable_interface(config->ps2_ctrl,
69 config->channel_id, 1);
70 }
71
ps2_npcx_ch_inhibit_interface(const struct device * dev)72 static int ps2_npcx_ch_inhibit_interface(const struct device *dev)
73 {
74 const struct ps2_npcx_ch_config *const config = DRV_CONFIG(dev);
75
76 return ps2_npcx_ctrl_enable_interface(config->ps2_ctrl,
77 config->channel_id, 0);
78 }
79
80 /* PS/2 driver registration */
ps2_npcx_channel_init(const struct device * dev)81 static int ps2_npcx_channel_init(const struct device *dev)
82 {
83 const struct ps2_npcx_ch_config *const config = DRV_CONFIG(dev);
84
85 if (!device_is_ready(config->ps2_ctrl)) {
86 LOG_ERR("%s device not ready", config->ps2_ctrl->name);
87 return -ENODEV;
88 }
89
90 /* Configure pin-mux for PS/2 device */
91 npcx_pinctrl_mux_configure(config->alts_list, config->alts_size, 1);
92
93 return 0;
94 }
95
96 static const struct ps2_driver_api ps2_channel_npcx_driver_api = {
97 .config = ps2_npcx_ch_configure,
98 .read = NULL,
99 .write = ps2_npcx_ch_write,
100 .disable_callback = ps2_npcx_ch_inhibit_interface,
101 .enable_callback = ps2_npcx_ch_enable_interface,
102 };
103
104 /* PS/2 channel initialization macro functions */
105 #define NPCX_PS2_CHANNEL_INIT(inst) \
106 \
107 static const struct npcx_alt ps2_channel_alts##inst[] = \
108 NPCX_DT_ALT_ITEMS_LIST(inst); \
109 \
110 static const struct ps2_npcx_ch_config ps2_npcx_ch_cfg_##inst = { \
111 .channel_id = DT_INST_PROP(inst, channel), \
112 .alts_size = ARRAY_SIZE(ps2_channel_alts##inst), \
113 .alts_list = ps2_channel_alts##inst, \
114 .ps2_ctrl = DEVICE_DT_GET(DT_PARENT(DT_DRV_INST(inst))), \
115 }; \
116 \
117 DEVICE_DT_INST_DEFINE(inst, ps2_npcx_channel_init, NULL, NULL, \
118 &ps2_npcx_ch_cfg_##inst, POST_KERNEL, \
119 CONFIG_PS2_CHANNEL_INIT_PRIORITY, \
120 &ps2_channel_npcx_driver_api);
121
122 DT_INST_FOREACH_STATUS_OKAY(NPCX_PS2_CHANNEL_INIT)
123
124 /* PS/2 channel driver must be initialized after PS/2 controller driver */
125 BUILD_ASSERT(CONFIG_PS2_CHANNEL_INIT_PRIORITY > CONFIG_PS2_INIT_PRIORITY);
126