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