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