1 /*
2 * Copyright (c) 2018 SiFive Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT sifive_i2c0
8
9 #define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
10 #include <zephyr/logging/log.h>
11 LOG_MODULE_REGISTER(i2c_sifive);
12
13 #include <zephyr/device.h>
14 #include <zephyr/drivers/i2c.h>
15 #include <soc.h>
16 #include <zephyr/sys/sys_io.h>
17
18 #include "i2c-priv.h"
19
20 /* Macros */
21
22 #define I2C_REG(config, reg) ((mem_addr_t) ((config)->base + reg))
23 #define IS_SET(config, reg, value) (sys_read8(I2C_REG(config, reg)) & (value))
24
25 /* Register Offsets */
26
27 #define REG_PRESCALE_LOW 0x00
28 #define REG_PRESCALE_HIGH 0x04
29
30 #define REG_CONTROL 0x08
31
32 /* Transmit on write, receive on read */
33 #define REG_TRANSMIT 0x0c
34 #define REG_RECEIVE 0x0c
35
36 /* Command on write, status on read */
37 #define REG_COMMAND 0x10
38 #define REG_STATUS 0x10
39
40 /* Values */
41
42 #define SF_CONTROL_EN (1 << 7)
43 #define SF_CONTROL_IE (1 << 6)
44
45 #define SF_TX_WRITE (0 << 0)
46 #define SF_TX_READ (1 << 0)
47
48 #define SF_CMD_START (1 << 7)
49 #define SF_CMD_STOP (1 << 6)
50 #define SF_CMD_READ (1 << 5)
51 #define SF_CMD_WRITE (1 << 4)
52 #define SF_CMD_ACK (1 << 3)
53 #define SF_CMD_IACK (1 << 0)
54
55 #define SF_STATUS_RXACK (1 << 7)
56 #define SF_STATUS_BUSY (1 << 6)
57 #define SF_STATUS_AL (1 << 5)
58 #define SF_STATUS_TIP (1 << 1)
59 #define SF_STATUS_IP (1 << 0)
60
61 /* Structure declarations */
62
63 struct i2c_sifive_cfg {
64 uint32_t base;
65 uint32_t f_sys;
66 uint32_t f_bus;
67 };
68
69 /* Helper functions */
70
i2c_sifive_busy(const struct device * dev)71 static inline bool i2c_sifive_busy(const struct device *dev)
72 {
73 const struct i2c_sifive_cfg *config = dev->config;
74
75 return IS_SET(config, REG_STATUS, SF_STATUS_TIP);
76 }
77
i2c_sifive_send_addr(const struct device * dev,uint16_t addr,uint16_t rw_flag)78 static int i2c_sifive_send_addr(const struct device *dev,
79 uint16_t addr,
80 uint16_t rw_flag)
81 {
82 const struct i2c_sifive_cfg *config = dev->config;
83 uint8_t command = 0U;
84
85 /* Wait for a previous transfer to complete */
86 while (i2c_sifive_busy(dev)) {
87 }
88
89 /* Set transmit register to address with read/write flag */
90 sys_write8((addr | rw_flag), I2C_REG(config, REG_TRANSMIT));
91
92 /* Addresses are always written */
93 command = SF_CMD_WRITE | SF_CMD_START;
94
95 /* Write the command register to start the transfer */
96 sys_write8(command, I2C_REG(config, REG_COMMAND));
97
98 while (i2c_sifive_busy(dev)) {
99 }
100
101 if (IS_SET(config, REG_STATUS, SF_STATUS_RXACK)) {
102 LOG_ERR("I2C Rx failed to acknowledge\n");
103 return -EIO;
104 }
105
106 return 0;
107 }
108
i2c_sifive_write_msg(const struct device * dev,struct i2c_msg * msg,uint16_t addr)109 static int i2c_sifive_write_msg(const struct device *dev,
110 struct i2c_msg *msg,
111 uint16_t addr)
112 {
113 const struct i2c_sifive_cfg *config = dev->config;
114 int rc = 0;
115 uint8_t command = 0U;
116
117 rc = i2c_sifive_send_addr(dev, addr, SF_TX_WRITE);
118 if (rc != 0) {
119 LOG_ERR("I2C failed to write message\n");
120 return rc;
121 }
122
123 for (uint32_t i = 0; i < msg->len; i++) {
124 /* Wait for a previous transfer */
125 while (i2c_sifive_busy(dev)) {
126 }
127
128 /* Put data in transmit reg */
129 sys_write8((msg->buf)[i], I2C_REG(config, REG_TRANSMIT));
130
131 /* Generate command byte */
132 command = SF_CMD_WRITE;
133
134 /* On the last byte of the message */
135 if (i == (msg->len - 1)) {
136 /* If the stop bit is requested, set it */
137 if (msg->flags & I2C_MSG_STOP) {
138 command |= SF_CMD_STOP;
139 }
140 }
141
142 /* Write command reg */
143 sys_write8(command, I2C_REG(config, REG_COMMAND));
144
145 /* Wait for a previous transfer */
146 while (i2c_sifive_busy(dev)) {
147 }
148
149 if (IS_SET(config, REG_STATUS, SF_STATUS_RXACK)) {
150 LOG_ERR("I2C Rx failed to acknowledge\n");
151 return -EIO;
152 }
153 }
154
155 return 0;
156 }
157
i2c_sifive_read_msg(const struct device * dev,struct i2c_msg * msg,uint16_t addr)158 static int i2c_sifive_read_msg(const struct device *dev,
159 struct i2c_msg *msg,
160 uint16_t addr)
161 {
162 const struct i2c_sifive_cfg *config = dev->config;
163 uint8_t command = 0U;
164
165 i2c_sifive_send_addr(dev, addr, SF_TX_READ);
166
167 while (i2c_sifive_busy(dev)) {
168 }
169
170 for (int i = 0; i < msg->len; i++) {
171 /* Generate command byte */
172 command = SF_CMD_READ;
173
174 /* On the last byte of the message */
175 if (i == (msg->len - 1)) {
176 /* Set NACK to end read */
177 command |= SF_CMD_ACK;
178
179 /* If the stop bit is requested, set it */
180 if (msg->flags & I2C_MSG_STOP) {
181 command |= SF_CMD_STOP;
182 }
183 }
184
185 /* Write command reg */
186 sys_write8(command, I2C_REG(config, REG_COMMAND));
187
188 /* Wait for the read to complete */
189 while (i2c_sifive_busy(dev)) {
190 }
191
192 /* Store the received byte */
193 (msg->buf)[i] = sys_read8(I2C_REG(config, REG_RECEIVE));
194 }
195
196 return 0;
197 }
198
199 /* API Functions */
200
i2c_sifive_configure(const struct device * dev,uint32_t dev_config)201 static int i2c_sifive_configure(const struct device *dev, uint32_t dev_config)
202 {
203 const struct i2c_sifive_cfg *config = NULL;
204 uint32_t i2c_speed = 0U;
205 uint16_t prescale = 0U;
206
207 /* Check for NULL pointers */
208 if (dev == NULL) {
209 LOG_ERR("Device handle is NULL");
210 return -EINVAL;
211 }
212 config = dev->config;
213 if (config == NULL) {
214 LOG_ERR("Device config is NULL");
215 return -EINVAL;
216 }
217
218 /* Disable the I2C peripheral */
219 sys_write8(0, I2C_REG(config, REG_CONTROL));
220
221 /* Configure bus frequency */
222 switch (I2C_SPEED_GET(dev_config)) {
223 case I2C_SPEED_STANDARD:
224 i2c_speed = 100000U; /* 100 KHz */
225 break;
226 case I2C_SPEED_FAST:
227 i2c_speed = 400000U; /* 400 KHz */
228 break;
229 case I2C_SPEED_FAST_PLUS:
230 case I2C_SPEED_HIGH:
231 case I2C_SPEED_ULTRA:
232 default:
233 LOG_ERR("Unsupported I2C speed requested");
234 return -ENOTSUP;
235 }
236
237 /* Calculate prescale value */
238 prescale = (config->f_sys / (i2c_speed * 5U)) - 1;
239
240 /* Configure peripheral with calculated prescale */
241 sys_write8((uint8_t) (0xFF & prescale), I2C_REG(config, REG_PRESCALE_LOW));
242 sys_write8((uint8_t) (0xFF & (prescale >> 8)),
243 I2C_REG(config, REG_PRESCALE_HIGH));
244
245 /* Support I2C Master mode only */
246 if (!(dev_config & I2C_MODE_CONTROLLER)) {
247 LOG_ERR("I2C only supports operation as master");
248 return -ENOTSUP;
249 }
250
251 /*
252 * Driver does not support 10-bit addressing. This can be added
253 * in the future when needed.
254 */
255 if (dev_config & I2C_ADDR_10_BITS) {
256 LOG_ERR("I2C driver does not support 10-bit addresses");
257 return -ENOTSUP;
258 }
259
260 /* Enable the I2C peripheral */
261 sys_write8(SF_CONTROL_EN, I2C_REG(config, REG_CONTROL));
262
263 return 0;
264 }
265
i2c_sifive_transfer(const struct device * dev,struct i2c_msg * msgs,uint8_t num_msgs,uint16_t addr)266 static int i2c_sifive_transfer(const struct device *dev,
267 struct i2c_msg *msgs,
268 uint8_t num_msgs,
269 uint16_t addr)
270 {
271 int rc = 0;
272
273 /* Check for NULL pointers */
274 if (dev == NULL) {
275 LOG_ERR("Device handle is NULL");
276 return -EINVAL;
277 }
278 if (dev->config == NULL) {
279 LOG_ERR("Device config is NULL");
280 return -EINVAL;
281 }
282 if (msgs == NULL) {
283 return -EINVAL;
284 }
285
286 for (int i = 0; i < num_msgs; i++) {
287 if (msgs[i].flags & I2C_MSG_READ) {
288 rc = i2c_sifive_read_msg(dev, &(msgs[i]), addr);
289 } else {
290 rc = i2c_sifive_write_msg(dev, &(msgs[i]), addr);
291 }
292
293 if (rc != 0) {
294 LOG_ERR("I2C failed to transfer messages\n");
295 return rc;
296 }
297 }
298
299 return 0;
300 };
301
i2c_sifive_init(const struct device * dev)302 static int i2c_sifive_init(const struct device *dev)
303 {
304 const struct i2c_sifive_cfg *config = dev->config;
305 uint32_t dev_config = 0U;
306 int rc = 0;
307
308 dev_config = (I2C_MODE_CONTROLLER | i2c_map_dt_bitrate(config->f_bus));
309
310 rc = i2c_sifive_configure(dev, dev_config);
311 if (rc != 0) {
312 LOG_ERR("Failed to configure I2C on init");
313 return rc;
314 }
315
316 return 0;
317 }
318
319
320 static const struct i2c_driver_api i2c_sifive_api = {
321 .configure = i2c_sifive_configure,
322 .transfer = i2c_sifive_transfer,
323 };
324
325 /* Device instantiation */
326
327 #define I2C_SIFIVE_INIT(n) \
328 static struct i2c_sifive_cfg i2c_sifive_cfg_##n = { \
329 .base = DT_INST_REG_ADDR(n), \
330 .f_sys = SIFIVE_PERIPHERAL_CLOCK_FREQUENCY, \
331 .f_bus = DT_INST_PROP(n, clock_frequency), \
332 }; \
333 I2C_DEVICE_DT_INST_DEFINE(n, \
334 i2c_sifive_init, \
335 NULL, \
336 NULL, \
337 &i2c_sifive_cfg_##n, \
338 POST_KERNEL, \
339 CONFIG_I2C_INIT_PRIORITY, \
340 &i2c_sifive_api);
341
342 DT_INST_FOREACH_STATUS_OKAY(I2C_SIFIVE_INIT)
343