1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
|
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (C) Copyright 2022 - Analog Devices, Inc.
*
* Written and/or maintained by Timesys Corporation
*
* Converted to driver model by Nathan Barrett-Morrison
*
* Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
* Contact: Greg Malysa <greg.malysa@timesys.com>
*/
#include <clk.h>
#include <dm.h>
#include <i2c.h>
#include <mapmem.h>
#include <linux/io.h>
#define CLKLOW(x) ((x) & 0xFF) // Periods Clock Is Held Low
#define CLKHI(y) (((y) & 0xFF) << 0x8) // Periods Clock Is High
#define PRESCALE 0x007F // SCLKs Per Internal Time Reference (10MHz)
#define TWI_ENA 0x0080 // TWI Enable
#define SCCB 0x0200 // SCCB Compatibility Enable
#define SEN 0x0001 // Slave Enable
#define SADD_LEN 0x0002 // Slave Address Length
#define STDVAL 0x0004 // Slave Transmit Data Valid
#define TSC_NAK 0x0008 // NAK Generated At Conclusion Of Transfer
#define GEN 0x0010 // General Call Adrress Matching Enabled
#define SDIR 0x0001 // Slave Transfer Direction
#define GCALL 0x0002 // General Call Indicator
#define MEN 0x0001 // Master Mode Enable
#define MADD_LEN 0x0002 // Master Address Length
#define MDIR 0x0004 // Master Transmit Direction (RX/TX*)
#define FAST 0x0008 // Use Fast Mode Timing Specs
#define STOP 0x0010 // Issue Stop Condition
#define RSTART 0x0020 // Repeat Start or Stop* At End Of Transfer
#define DCNT 0x3FC0 // Data Bytes To Transfer
#define SDAOVR 0x4000 // Serial Data Override
#define SCLOVR 0x8000 // Serial Clock Override
#define MPROG 0x0001 // Master Transfer In Progress
#define LOSTARB 0x0002 // Lost Arbitration Indicator (Xfer Aborted)
#define ANAK 0x0004 // Address Not Acknowledged
#define DNAK 0x0008 // Data Not Acknowledged
#define BUFRDERR 0x0010 // Buffer Read Error
#define BUFWRERR 0x0020 // Buffer Write Error
#define SDASEN 0x0040 // Serial Data Sense
#define SCLSEN 0x0080 // Serial Clock Sense
#define BUSBUSY 0x0100 // Bus Busy Indicator
#define SINIT 0x0001 // Slave Transfer Initiated
#define SCOMP 0x0002 // Slave Transfer Complete
#define SERR 0x0004 // Slave Transfer Error
#define SOVF 0x0008 // Slave Overflow
#define MCOMP 0x0010 // Master Transfer Complete
#define MERR 0x0020 // Master Transfer Error
#define XMTSERV 0x0040 // Transmit FIFO Service
#define RCVSERV 0x0080 // Receive FIFO Service
#define XMTFLUSH 0x0001 // Transmit Buffer Flush
#define RCVFLUSH 0x0002 // Receive Buffer Flush
#define XMTINTLEN 0x0004 // Transmit Buffer Interrupt Length
#define RCVINTLEN 0x0008 // Receive Buffer Interrupt Length
#define XMTSTAT 0x0003 // Transmit FIFO Status
#define XMT_EMPTY 0x0000 // Transmit FIFO Empty
#define XMT_HALF 0x0001 // Transmit FIFO Has 1 Byte To Write
#define XMT_FULL 0x0003 // Transmit FIFO Full (2 Bytes To Write)
#define RCVSTAT 0x000C // Receive FIFO Status
#define RCV_EMPTY 0x0000 // Receive FIFO Empty
#define RCV_HALF 0x0004 // Receive FIFO Has 1 Byte To Read
#define RCV_FULL 0x000C // Receive FIFO Full (2 Bytes To Read)
/* Every register is 32bit aligned, but only 16bits in size */
#define ureg(name) u16 name; u16 __pad_##name
struct twi_regs {
ureg(clkdiv);
ureg(control);
ureg(slave_ctl);
ureg(slave_stat);
ureg(slave_addr);
ureg(master_ctl);
ureg(master_stat);
ureg(master_addr);
ureg(int_stat);
ureg(int_mask);
ureg(fifo_ctl);
ureg(fifo_stat);
u8 __pad[0x50];
ureg(xmt_data8);
ureg(xmt_data16);
ureg(rcv_data8);
ureg(rcv_data16);
};
#undef ureg
/*
* The way speed is changed into duty often results in integer truncation
* with 50% duty, so we'll force rounding up to the next duty by adding 1
* to the max. In practice this will get us a speed of something like
* 385 KHz. The other limit is easy to handle as it is only 8 bits.
*/
#define I2C_SPEED_MAX 400000
#define I2C_SPEED_TO_DUTY(speed) (5000000 / (speed))
#define I2C_DUTY_MAX (I2C_SPEED_TO_DUTY(I2C_SPEED_MAX) + 1)
#define I2C_DUTY_MIN 0xff /* 8 bit limited */
#define I2C_M_COMBO 0x4
#define I2C_M_STOP 0x2
#define I2C_M_READ 0x1
/*
* All transfers are described by this data structure
*/
struct adi_i2c_msg {
u8 flags;
u32 len; /* msg length */
u8 *buf; /* pointer to msg data */
u32 olen; /* addr length */
u8 *obuf; /* addr buffer */
};
struct adi_i2c_dev {
struct twi_regs __iomem *base;
u32 i2c_clk;
uint speed;
};
/* Allow msec timeout per ~byte transfer */
#define I2C_TIMEOUT 10
/**
* wait_for_completion - manage the actual i2c transfer
* @msg: the i2c msg
*/
static int wait_for_completion(struct twi_regs *twi, struct adi_i2c_msg *msg)
{
u16 int_stat;
ulong timebase = get_timer(0);
do {
int_stat = ioread16(&twi->int_stat);
if (int_stat & XMTSERV) {
iowrite16(XMTSERV, &twi->int_stat);
if (msg->olen) {
iowrite16(*(msg->obuf++), &twi->xmt_data8);
--msg->olen;
} else if (!(msg->flags & I2C_M_COMBO) && msg->len) {
iowrite16(*(msg->buf++), &twi->xmt_data8);
--msg->len;
} else {
if (msg->flags & I2C_M_COMBO)
setbits_16(&twi->master_ctl, RSTART | MDIR);
else
setbits_16(&twi->master_ctl, STOP);
}
}
if (int_stat & RCVSERV) {
iowrite16(RCVSERV, &twi->int_stat);
if (msg->len) {
*(msg->buf++) = ioread16(&twi->rcv_data8);
--msg->len;
} else if (msg->flags & I2C_M_STOP) {
setbits_16(&twi->master_ctl, STOP);
}
}
if (int_stat & MERR) {
pr_err("%s: master transmit terror: %d\n", __func__,
ioread16(&twi->master_stat));
iowrite16(MERR, &twi->int_stat);
return -EIO;
}
if (int_stat & MCOMP) {
iowrite16(MCOMP, &twi->int_stat);
if (msg->flags & I2C_M_COMBO && msg->len) {
u16 mlen = min(msg->len, 0xffu) << 6;
clrsetbits_16(&twi->master_ctl, RSTART, mlen | MEN | MDIR);
} else {
break;
}
}
/* If we were able to do something, reset timeout */
if (int_stat)
timebase = get_timer(0);
} while (get_timer(timebase) < I2C_TIMEOUT);
return 0;
}
static int i2c_transfer(struct twi_regs *twi, u8 chip, u8 *offset,
int olen, u8 *buffer, int len, u8 flags)
{
int ret;
u16 ctl;
struct adi_i2c_msg msg = {
.flags = flags | (len >= 0xff ? I2C_M_STOP : 0),
.buf = buffer,
.len = len,
.obuf = offset,
.olen = olen,
};
/* wait for things to settle */
while (ioread16(&twi->master_stat) & BUSBUSY)
if (!IS_ENABLED(CONFIG_SPL_BUILD) && ctrlc())
return -EINTR;
/* Set Transmit device address */
iowrite16(chip, &twi->master_addr);
/* Clear the FIFO before starting things */
iowrite16(XMTFLUSH | RCVFLUSH, &twi->fifo_ctl);
iowrite16(0, &twi->fifo_ctl);
/* Prime the pump */
if (msg.olen) {
len = (msg.flags & I2C_M_COMBO) ? msg.olen : msg.olen + len;
iowrite16(*(msg.obuf++), &twi->xmt_data8);
--msg.olen;
} else if (!(msg.flags & I2C_M_READ) && msg.len) {
iowrite16(*(msg.buf++), &twi->xmt_data8);
--msg.len;
}
/* clear int stat */
iowrite16(-1, &twi->master_stat);
iowrite16(-1, &twi->int_stat);
iowrite16(0, &twi->int_mask);
/* Master enable */
ctl = ioread16(&twi->master_ctl);
ctl = (ctl & FAST) | (min(len, 0xff) << 6) | MEN |
((msg.flags & I2C_M_READ) ? MDIR : 0);
iowrite16(ctl, &twi->master_ctl);
/* Process the rest */
ret = wait_for_completion(twi, &msg);
clrbits_16(&twi->master_ctl, MEN);
clrbits_16(&twi->control, TWI_ENA);
setbits_16(&twi->control, TWI_ENA);
return ret;
}
static int adi_i2c_read(struct twi_regs *twi, u8 chip,
u8 *offset, int olen, u8 *buffer, int len)
{
return i2c_transfer(twi, chip, offset, olen, buffer,
len, olen ? I2C_M_COMBO : I2C_M_READ);
}
static int adi_i2c_write(struct twi_regs *twi, u8 chip,
u8 *offset, int olen, u8 *buffer, int len)
{
return i2c_transfer(twi, chip, offset, olen, buffer, len, 0);
}
static int adi_i2c_set_bus_speed(struct udevice *bus, uint speed)
{
struct adi_i2c_dev *dev = dev_get_priv(bus);
struct twi_regs *twi = dev->base;
u16 clkdiv = I2C_SPEED_TO_DUTY(speed);
/* Set TWI interface clock */
if (clkdiv < I2C_DUTY_MAX || clkdiv > I2C_DUTY_MIN)
return -1;
clkdiv = (clkdiv << 8) | (clkdiv & 0xff);
iowrite16(clkdiv, &twi->clkdiv);
/* Don't turn it on */
iowrite16(speed > 100000 ? FAST : 0, &twi->master_ctl);
return 0;
}
static int adi_i2c_of_to_plat(struct udevice *bus)
{
struct adi_i2c_dev *dev = dev_get_priv(bus);
struct clk clock;
u32 ret;
dev->base = map_sysmem(dev_read_addr(bus), sizeof(struct twi_regs));
if (!dev->base)
return -ENOMEM;
dev->speed = dev_read_u32_default(bus, "clock-frequency",
I2C_SPEED_FAST_RATE);
ret = clk_get_by_name(bus, "i2c", &clock);
if (ret < 0)
printf("%s: Can't get I2C clk: %d\n", __func__, ret);
else
dev->i2c_clk = clk_get_rate(&clock);
return 0;
}
static int adi_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
u32 chip_flags)
{
struct adi_i2c_dev *dev = dev_get_priv(bus);
u8 byte;
return adi_i2c_read(dev->base, chip_addr, NULL, 0, &byte, 1);
}
static int adi_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
{
struct adi_i2c_dev *dev = dev_get_priv(bus);
struct i2c_msg *dmsg, *omsg, dummy;
memset(&dummy, 0, sizeof(struct i2c_msg));
/*
* We expect either two messages (one with an offset and one with the
* actual data) or one message (just data)
*/
if (nmsgs > 2 || nmsgs == 0) {
debug("%s: Only one or two messages are supported.", __func__);
return -EINVAL;
}
omsg = nmsgs == 1 ? &dummy : msg;
dmsg = nmsgs == 1 ? msg : msg + 1;
if (dmsg->flags & I2C_M_RD)
return adi_i2c_read(dev->base, dmsg->addr, omsg->buf, omsg->len,
dmsg->buf, dmsg->len);
else
return adi_i2c_write(dev->base, dmsg->addr, omsg->buf, omsg->len,
dmsg->buf, dmsg->len);
}
int adi_i2c_probe(struct udevice *bus)
{
struct adi_i2c_dev *dev = dev_get_priv(bus);
struct twi_regs *twi = dev->base;
u16 prescale = ((dev->i2c_clk / 1000 / 1000 + 5) / 10) & 0x7F;
/* Set TWI internal clock as 10MHz */
iowrite16(prescale, &twi->control);
/* Set TWI interface clock as specified */
adi_i2c_set_bus_speed(bus, dev->speed);
/* Enable it */
iowrite16(TWI_ENA | prescale, &twi->control);
return 0;
}
static const struct dm_i2c_ops adi_i2c_ops = {
.xfer = adi_i2c_xfer,
.probe_chip = adi_i2c_probe_chip,
.set_bus_speed = adi_i2c_set_bus_speed,
};
static const struct udevice_id adi_i2c_ids[] = {
{ .compatible = "adi-i2c", },
{ /* sentinel */ }
};
U_BOOT_DRIVER(i2c_adi) = {
.name = "i2c_adi",
.id = UCLASS_I2C,
.of_match = adi_i2c_ids,
.probe = adi_i2c_probe,
.of_to_plat = adi_i2c_of_to_plat,
.priv_auto = sizeof(struct adi_i2c_dev),
.ops = &adi_i2c_ops,
.flags = DM_FLAG_PRE_RELOC,
};
|