1 /*
2  * Copyright (c) 2020 Nuvoton Technology Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nuvoton_npcx_i2c_port
8 
9 /**
10  * @file
11  * @brief Nuvoton NPCX smb/i2c port driver
12  *
13  * This file contains the driver of SMBus/I2C buses (ports) which provides
14  * pin-muxing for each i2c io-pads. In order to support "SMBus Multi-Bus"
15  * feature, please refer the diagram below, the driver also provides connection
16  * between Zephyr i2c api functions and i2c controller driver which provides
17  * full support for SMBus/I2C transactions.
18  *
19  *                           Port SEL
20  *                             |
21  *                           |\|
22  *           SCL_N Port 0----| \     +--------------+
23  *           SDA_N Port 0----|  |----|   SMB/I2C    |
24  *                           |  |----| Controller N |
25  *           SCL_N Port 1----|  |    +--------------+
26  *           SDA_N Port 1----| /
27  *                           |/
28  *
29  */
30 
31 #include <assert.h>
32 #include <zephyr/drivers/clock_control.h>
33 #include <zephyr/drivers/i2c.h>
34 #include <zephyr/drivers/pinctrl.h>
35 #include <zephyr/dt-bindings/i2c/i2c.h>
36 #include <soc.h>
37 
38 #include <zephyr/logging/log.h>
39 LOG_MODULE_REGISTER(i2c_npcx_port, CONFIG_I2C_LOG_LEVEL);
40 
41 #include "i2c_npcx_controller.h"
42 #include "i2c-priv.h"
43 
44 /* Device config */
45 struct i2c_npcx_port_config {
46 	uint32_t bitrate;
47 	uint8_t port;
48 	const struct device *i2c_ctrl;
49 	/* pinmux configuration */
50 	const struct pinctrl_dev_config *pcfg;
51 };
52 
53 /* I2C api functions */
i2c_npcx_port_configure(const struct device * dev,uint32_t dev_config)54 static int i2c_npcx_port_configure(const struct device *dev,
55 							uint32_t dev_config)
56 {
57 	const struct i2c_npcx_port_config *const config = dev->config;
58 
59 	if (config->i2c_ctrl == NULL) {
60 		LOG_ERR("Cannot find i2c controller on port%02x!",
61 								config->port);
62 		return -EIO;
63 	}
64 
65 	if (!(dev_config & I2C_MODE_CONTROLLER)) {
66 		return -ENOTSUP;
67 	}
68 
69 	if (dev_config & I2C_ADDR_10_BITS) {
70 		return -ENOTSUP;
71 	}
72 
73 	/* Configure i2c controller */
74 	return npcx_i2c_ctrl_configure(config->i2c_ctrl, dev_config);
75 }
76 
i2c_npcx_port_get_config(const struct device * dev,uint32_t * dev_config)77 static int i2c_npcx_port_get_config(const struct device *dev, uint32_t *dev_config)
78 {
79 	const struct i2c_npcx_port_config *const config = dev->config;
80 	uint32_t speed;
81 	int ret;
82 
83 	if (config->i2c_ctrl == NULL) {
84 		LOG_ERR("Cannot find i2c controller on port%02x!", config->port);
85 		return -EIO;
86 	}
87 
88 	ret = npcx_i2c_ctrl_get_speed(config->i2c_ctrl, &speed);
89 	if (!ret) {
90 		*dev_config = (I2C_MODE_CONTROLLER | speed);
91 	}
92 
93 	return ret;
94 }
95 
i2c_npcx_port_transfer(const struct device * dev,struct i2c_msg * msgs,uint8_t num_msgs,uint16_t addr)96 static int i2c_npcx_port_transfer(const struct device *dev,
97 		struct i2c_msg *msgs, uint8_t num_msgs, uint16_t addr)
98 {
99 	const struct i2c_npcx_port_config *const config = dev->config;
100 	int ret = 0;
101 	int idx_ctrl = (config->port & 0xF0) >> 4;
102 	int idx_port = (config->port & 0x0F);
103 
104 	if (config->i2c_ctrl == NULL) {
105 		LOG_ERR("Cannot find i2c controller on port%02x!",
106 								config->port);
107 		return -EIO;
108 	}
109 
110 	/* Lock mutex of i2c/smb controller */
111 	npcx_i2c_ctrl_mutex_lock(config->i2c_ctrl);
112 
113 	/* Switch correct port for i2c controller first */
114 	npcx_pinctrl_i2c_port_sel(idx_ctrl, idx_port);
115 
116 	/* Start transaction with i2c controller */
117 	ret = npcx_i2c_ctrl_transfer(config->i2c_ctrl, msgs, num_msgs, addr,
118 								config->port);
119 
120 	/* Unlock mutex of i2c/smb controller */
121 	npcx_i2c_ctrl_mutex_unlock(config->i2c_ctrl);
122 
123 	return ret;
124 }
i2c_npcx_port_recover_bus(const struct device * dev)125 static int i2c_npcx_port_recover_bus(const struct device *dev)
126 {
127 	const struct i2c_npcx_port_config *const config = dev->config;
128 	int ret;
129 
130 	if (config->i2c_ctrl == NULL) {
131 		LOG_ERR("Cannot find i2c controller on port%02x!", config->port);
132 		return -EIO;
133 	}
134 
135 	/* Lock mutex of i2c/smb controller */
136 	npcx_i2c_ctrl_mutex_lock(config->i2c_ctrl);
137 
138 	ret = npcx_i2c_ctrl_recover_bus(config->i2c_ctrl);
139 
140 	/* Unlock mutex of i2c/smb controller */
141 	npcx_i2c_ctrl_mutex_unlock(config->i2c_ctrl);
142 
143 	return ret;
144 }
145 
146 #ifdef CONFIG_I2C_TARGET
i2c_npcx_target_register(const struct device * dev,struct i2c_target_config * target_cfg)147 static int i2c_npcx_target_register(const struct device *dev,
148 				  struct i2c_target_config *target_cfg)
149 {
150 	const struct i2c_npcx_port_config *const config = dev->config;
151 
152 	if (!target_cfg) {
153 		return -EINVAL;
154 	}
155 
156 	if (config->i2c_ctrl == NULL) {
157 		LOG_ERR("Cannot find i2c controller on port%02x!", config->port);
158 		return -EIO;
159 	}
160 
161 	return npcx_i2c_ctrl_target_register(config->i2c_ctrl, target_cfg, config->port);
162 }
163 
i2c_npcx_target_unregister(const struct device * dev,struct i2c_target_config * target_cfg)164 static int i2c_npcx_target_unregister(const struct device *dev,
165 				     struct i2c_target_config *target_cfg)
166 {
167 	const struct i2c_npcx_port_config *const config = dev->config;
168 
169 	if (config->i2c_ctrl == NULL) {
170 		LOG_ERR("Cannot find i2c controller on port%02x!", config->port);
171 		return -EIO;
172 	}
173 
174 	return npcx_i2c_ctrl_target_unregister(config->i2c_ctrl, target_cfg);
175 }
176 #endif
177 
178 /* I2C driver registration */
i2c_npcx_port_init(const struct device * dev)179 static int i2c_npcx_port_init(const struct device *dev)
180 {
181 	const struct i2c_npcx_port_config *const config = dev->config;
182 	uint32_t i2c_config;
183 	int ret;
184 
185 	/* Configure pin-mux for I2C device */
186 	ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
187 	if (ret < 0) {
188 		LOG_ERR("I2C pinctrl setup failed (%d)", ret);
189 		return ret;
190 	}
191 
192 
193 	/* Setup initial i2c configuration */
194 	i2c_config = (I2C_MODE_CONTROLLER | i2c_map_dt_bitrate(config->bitrate));
195 	ret = i2c_npcx_port_configure(dev, i2c_config);
196 	if (ret != 0) {
197 		return ret;
198 	}
199 
200 	return 0;
201 }
202 
203 static DEVICE_API(i2c, i2c_port_npcx_driver_api) = {
204 	.configure = i2c_npcx_port_configure,
205 	.get_config = i2c_npcx_port_get_config,
206 	.transfer = i2c_npcx_port_transfer,
207 	.recover_bus = i2c_npcx_port_recover_bus,
208 #ifdef CONFIG_I2C_TARGET
209 	.target_register = i2c_npcx_target_register,
210 	.target_unregister = i2c_npcx_target_unregister,
211 #endif
212 #ifdef CONFIG_I2C_RTIO
213 	.iodev_submit = i2c_iodev_submit_fallback,
214 #endif
215 };
216 
217 /* I2C port init macro functions */
218 #define NPCX_I2C_PORT_INIT(inst)                                               \
219 	PINCTRL_DT_INST_DEFINE(inst);					       \
220 									       \
221 	static const struct i2c_npcx_port_config i2c_npcx_port_cfg_##inst = {  \
222 		.port = DT_INST_PROP(inst, port),                              \
223 		.bitrate = DT_INST_PROP(inst, clock_frequency),                \
224 		.i2c_ctrl = DEVICE_DT_GET(DT_INST_PHANDLE(inst, controller)),  \
225 		.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst),                  \
226 	};                                                                     \
227 									       \
228 	I2C_DEVICE_DT_INST_DEFINE(inst,                                        \
229 			    i2c_npcx_port_init,                                \
230 			    NULL, NULL,                                        \
231 			    &i2c_npcx_port_cfg_##inst,                         \
232 			    PRE_KERNEL_1, CONFIG_I2C_NPCX_PORT_INIT_PRIORITY,  \
233 			    &i2c_port_npcx_driver_api);
234 
235 DT_INST_FOREACH_STATUS_OKAY(NPCX_I2C_PORT_INIT)
236