blob: 960ae8c700f979ff3838576190991b3763bc3ec0 [file] [log] [blame]
Arthur Li7f5ea252020-06-01 12:56:31 -07001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2020
4 * Arthur Li, Cortina Access, arthur.li@cortina-access.com.
5 */
6
7#include <common.h>
8#include <i2c.h>
9#include <log.h>
10#include <asm/io.h>
11#include <dm.h>
12#include <mapmem.h>
13#include "i2c-cortina.h"
14
15static void set_speed(struct i2c_regs *regs, int i2c_spd)
16{
17 union ca_biw_cfg i2c_cfg;
18
19 i2c_cfg.wrd = readl(&regs->i2c_cfg);
20 i2c_cfg.bf.core_en = 0;
21 writel(i2c_cfg.wrd, &regs->i2c_cfg);
22
23 switch (i2c_spd) {
24 case IC_SPEED_MODE_FAST_PLUS:
25 i2c_cfg.bf.prer = CORTINA_PER_IO_FREQ /
26 (5 * I2C_SPEED_FAST_PLUS_RATE) - 1;
27 break;
28
29 case IC_SPEED_MODE_STANDARD:
30 i2c_cfg.bf.prer = CORTINA_PER_IO_FREQ /
31 (5 * I2C_SPEED_STANDARD_RATE) - 1;
32 break;
33
34 case IC_SPEED_MODE_FAST:
35 default:
36 i2c_cfg.bf.prer = CORTINA_PER_IO_FREQ /
37 (5 * I2C_SPEED_FAST_RATE) - 1;
38 break;
39 }
40
41 i2c_cfg.bf.core_en = 1;
42 writel(i2c_cfg.wrd, &regs->i2c_cfg);
43}
44
45static int ca_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
46{
47 struct ca_i2c *priv = dev_get_priv(bus);
48 int i2c_spd;
49
50 if (speed >= I2C_SPEED_FAST_PLUS_RATE) {
51 i2c_spd = IC_SPEED_MODE_FAST_PLUS;
52 priv->speed = I2C_SPEED_FAST_PLUS_RATE;
53 } else if (speed >= I2C_SPEED_FAST_RATE) {
54 i2c_spd = IC_SPEED_MODE_FAST;
55 priv->speed = I2C_SPEED_FAST_RATE;
56 } else {
57 i2c_spd = IC_SPEED_MODE_STANDARD;
58 priv->speed = I2C_SPEED_STANDARD_RATE;
59 }
60
61 set_speed(priv->regs, i2c_spd);
62
63 return 0;
64}
65
66static int ca_i2c_get_bus_speed(struct udevice *bus)
67{
68 struct ca_i2c *priv = dev_get_priv(bus);
69
70 return priv->speed;
71}
72
73static void ca_i2c_init(struct i2c_regs *regs)
74{
75 union ca_biw_cfg i2c_cfg;
76
77 i2c_cfg.wrd = readl(&regs->i2c_cfg);
78 i2c_cfg.bf.core_en = 0;
79 i2c_cfg.bf.biw_soft_reset = 1;
80 writel(i2c_cfg.wrd, &regs->i2c_cfg);
81 mdelay(10);
82 i2c_cfg.bf.biw_soft_reset = 0;
83 writel(i2c_cfg.wrd, &regs->i2c_cfg);
84
85 set_speed(regs, IC_SPEED_MODE_STANDARD);
86
87 i2c_cfg.wrd = readl(&regs->i2c_cfg);
88 i2c_cfg.bf.core_en = 1;
89 writel(i2c_cfg.wrd, &regs->i2c_cfg);
90}
91
92static int i2c_wait_complete(struct i2c_regs *regs)
93{
94 union ca_biw_ctrl i2c_ctrl;
95 unsigned long start_time_bb = get_timer(0);
96
97 i2c_ctrl.wrd = readl(&regs->i2c_ctrl);
98
99 while (i2c_ctrl.bf.biwdone == 0) {
100 i2c_ctrl.wrd = readl(&regs->i2c_ctrl);
101
102 if (get_timer(start_time_bb) >
103 (unsigned long)(I2C_BYTE_TO_BB)) {
104 printf("%s not done!!!\n", __func__);
105 return -ETIMEDOUT;
106 }
107 }
108
109 /* Clear done bit */
110 writel(i2c_ctrl.wrd, &regs->i2c_ctrl);
111
112 return 0;
113}
114
115static void i2c_setaddress(struct i2c_regs *regs, unsigned int i2c_addr,
116 int write_read)
117{
118 writel(i2c_addr | write_read, &regs->i2c_txr);
119
120 writel(BIW_CTRL_START | BIW_CTRL_WRITE,
121 &regs->i2c_ctrl);
122
123 i2c_wait_complete(regs);
124}
125
126static int i2c_wait_for_bus_busy(struct i2c_regs *regs)
127{
128 union ca_biw_ack i2c_ack;
129 unsigned long start_time_bb = get_timer(0);
130
131 i2c_ack.wrd = readl(&regs->i2c_ack);
132
133 while (i2c_ack.bf.biw_busy) {
134 i2c_ack.wrd = readl(&regs->i2c_ack);
135
136 if (get_timer(start_time_bb) >
137 (unsigned long)(I2C_BYTE_TO_BB)) {
138 printf("%s: timeout!\n", __func__);
139 return -ETIMEDOUT;
140 }
141 }
142
143 return 0;
144}
145
146static int i2c_xfer_init(struct i2c_regs *regs, uint8_t chip, uint addr,
147 int alen, int write_read)
148{
149 int addr_len = alen;
150
151 if (i2c_wait_for_bus_busy(regs))
152 return 1;
153
154 /* First cycle must write addr + offset */
155 chip = ((chip & 0x7F) << 1);
156 if (alen == 0 && write_read == I2C_CMD_RD)
157 i2c_setaddress(regs, chip, I2C_CMD_RD);
158 else
159 i2c_setaddress(regs, chip, I2C_CMD_WT);
160
161 while (alen) {
162 alen--;
163 writel(addr, &regs->i2c_txr);
164 if (write_read == I2C_CMD_RD)
165 writel(BIW_CTRL_WRITE | BIW_CTRL_STOP,
166 &regs->i2c_ctrl);
167 else
168 writel(BIW_CTRL_WRITE, &regs->i2c_ctrl);
169 i2c_wait_complete(regs);
170 }
171
172 /* Send address again with Read flag if it's read command */
173 if (write_read == I2C_CMD_RD && addr_len > 0)
174 i2c_setaddress(regs, chip, I2C_CMD_RD);
175
176 return 0;
177}
178
179static int i2c_xfer_finish(struct i2c_regs *regs)
180{
181 /* Dummy read makes bus free */
182 writel(BIW_CTRL_READ | BIW_CTRL_STOP, &regs->i2c_ctrl);
183 i2c_wait_complete(regs);
184
185 if (i2c_wait_for_bus_busy(regs)) {
186 printf("Timed out waiting for bus\n");
187 return -ETIMEDOUT;
188 }
189
190 return 0;
191}
192
193static int ca_i2c_read(struct i2c_regs *regs, uint8_t chip, uint addr,
194 int alen, uint8_t *buffer, int len)
195{
196 unsigned long start_time_rx;
197 int rc = 0;
198
199 rc = i2c_xfer_init(regs, chip, addr, alen, I2C_CMD_RD);
200 if (rc)
201 return rc;
202
203 start_time_rx = get_timer(0);
204 while (len) {
205 /* ACK_IN is ack value to send during read.
206 * ack high only on the very last byte!
207 */
208 if (len == 1)
209 writel(BIW_CTRL_READ | BIW_CTRL_ACK_IN | BIW_CTRL_STOP,
210 &regs->i2c_ctrl);
211 else
212 writel(BIW_CTRL_READ, &regs->i2c_ctrl);
213
214 rc = i2c_wait_complete(regs);
215 udelay(1);
216
217 if (rc == 0) {
218 *buffer++ =
219 (uchar) readl(&regs->i2c_rxr);
220 len--;
221 start_time_rx = get_timer(0);
222
223 } else if (get_timer(start_time_rx) > I2C_BYTE_TO) {
224 return -ETIMEDOUT;
225 }
226 }
227 i2c_xfer_finish(regs);
228 return rc;
229}
230
231static int ca_i2c_write(struct i2c_regs *regs, uint8_t chip, uint addr,
232 int alen, uint8_t *buffer, int len)
233{
234 int rc, nb = len;
235 unsigned long start_time_tx;
236
237 rc = i2c_xfer_init(regs, chip, addr, alen, I2C_CMD_WT);
238 if (rc)
239 return rc;
240
241 start_time_tx = get_timer(0);
242 while (len) {
243 writel(*buffer, &regs->i2c_txr);
244 if (len == 1)
245 writel(BIW_CTRL_WRITE | BIW_CTRL_STOP,
246 &regs->i2c_ctrl);
247 else
248 writel(BIW_CTRL_WRITE, &regs->i2c_ctrl);
249
250 rc = i2c_wait_complete(regs);
251
252 if (rc == 0) {
253 len--;
254 buffer++;
255 start_time_tx = get_timer(0);
256 } else if (get_timer(start_time_tx) > (nb * I2C_BYTE_TO)) {
257 return -ETIMEDOUT;
258 }
259 }
260
261 return 0;
262}
263
264static int ca_i2c_probe_chip(struct udevice *bus, uint chip_addr,
265 uint chip_flags)
266{
267 struct ca_i2c *priv = dev_get_priv(bus);
268 int ret;
269 u32 tmp;
270
271 /* Try to read the first location of the chip */
272 ret = ca_i2c_read(priv->regs, chip_addr, 0, 1, (uchar *)&tmp, 1);
273 if (ret)
274 ca_i2c_init(priv->regs);
275
276 return ret;
277}
278
279static int ca_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
280{
281 struct ca_i2c *priv = dev_get_priv(bus);
282 int ret;
283
284 debug("i2c_xfer: %d messages\n", nmsgs);
285 for (; nmsgs > 0; nmsgs--, msg++) {
286 debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
287 if (msg->flags & I2C_M_RD)
288 ret = ca_i2c_read(priv->regs, msg->addr, 0, 0,
289 msg->buf, msg->len);
290 else
291 ret = ca_i2c_write(priv->regs, msg->addr, 0, 0,
292 msg->buf, msg->len);
293
294 if (ret) {
295 printf("i2c_xfer: %s error\n",
296 msg->flags & I2C_M_RD ? "read" : "write");
297 return ret;
298 }
299 }
300
301 return 0;
302}
303
304static const struct dm_i2c_ops ca_i2c_ops = {
305 .xfer = ca_i2c_xfer,
306 .probe_chip = ca_i2c_probe_chip,
307 .set_bus_speed = ca_i2c_set_bus_speed,
308 .get_bus_speed = ca_i2c_get_bus_speed,
309};
310
311static const struct udevice_id ca_i2c_ids[] = {
312 { .compatible = "cortina,ca-i2c", },
313 { }
314};
315
316static int ca_i2c_probe(struct udevice *bus)
317{
318 struct ca_i2c *priv = dev_get_priv(bus);
319
320 ca_i2c_init(priv->regs);
321
322 return 0;
323}
324
Simon Glassd1998a92020-12-03 16:55:21 -0700325static int ca_i2c_of_to_plat(struct udevice *bus)
Arthur Li7f5ea252020-06-01 12:56:31 -0700326{
327 struct ca_i2c *priv = dev_get_priv(bus);
328
329 priv->regs = map_sysmem(dev_read_addr(bus), sizeof(struct i2c_regs));
330 if (!priv->regs) {
331 printf("I2C: base address is invalid\n");
332 return -EINVAL;
333 }
334
335 return 0;
336}
337
338U_BOOT_DRIVER(i2c_cortina) = {
339 .name = "i2c_cortina",
340 .id = UCLASS_I2C,
341 .of_match = ca_i2c_ids,
Simon Glassd1998a92020-12-03 16:55:21 -0700342 .of_to_plat = ca_i2c_of_to_plat,
Arthur Li7f5ea252020-06-01 12:56:31 -0700343 .probe = ca_i2c_probe,
Simon Glass41575d82020-12-03 16:55:17 -0700344 .priv_auto = sizeof(struct ca_i2c),
Arthur Li7f5ea252020-06-01 12:56:31 -0700345 .ops = &ca_i2c_ops,
346 .flags = DM_FLAG_PRE_RELOC,
347};