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