2 * This file is part of the coreboot project.
5 * David Mueller, ELSOFT AG, d.mueller@elsoft.ch
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
19 #include <console/console.h>
21 #include <device/i2c.h>
24 #include <soc/periph.h>
26 struct __attribute__ ((packed
)) i2c_regs
40 struct s3c24x0_i2c_bus
{
42 struct i2c_regs
*regs
;
43 enum periph_id periph_id
;
47 I2cConIntPending
= 0x1 << 4,
48 I2cConIntEn
= 0x1 << 5,
49 I2cConAckGen
= 0x1 << 7
53 I2cStatAck
= 0x1 << 0,
54 I2cStatAddrZero
= 0x1 << 1,
55 I2cStatAddrSlave
= 0x1 << 2,
56 I2cStatArb
= 0x1 << 3,
57 I2cStatEnable
= 0x1 << 4,
58 I2cStatStartStop
= 0x1 << 5,
59 I2cStatBusy
= 0x1 << 5,
61 I2cStatModeMask
= 0x3 << 6,
62 I2cStatSlaveRecv
= 0x0 << 6,
63 I2cStatSlaveXmit
= 0x1 << 6,
64 I2cStatMasterRecv
= 0x2 << 6,
65 I2cStatMasterXmit
= 0x3 << 6
68 static struct s3c24x0_i2c_bus i2c_busses
[] = {
71 .regs
= (void *)0x12c60000,
72 .periph_id
= PERIPH_ID_I2C0
,
76 .regs
= (void *)0x12c70000,
77 .periph_id
= PERIPH_ID_I2C1
,
81 .regs
= (void *)0x12c80000,
82 .periph_id
= PERIPH_ID_I2C2
,
86 .regs
= (void *)0x12c90000,
87 .periph_id
= PERIPH_ID_I2C3
,
91 .regs
= (void *)0x12ca0000,
92 .periph_id
= PERIPH_ID_I2C4
,
96 .regs
= (void *)0x12cb0000,
97 .periph_id
= PERIPH_ID_I2C5
,
101 .regs
= (void *)0x12cc0000,
102 .periph_id
= PERIPH_ID_I2C6
,
106 .regs
= (void *)0x12cd0000,
107 .periph_id
= PERIPH_ID_I2C7
,
114 static int i2c_int_pending(struct i2c_regs
*regs
)
116 return read8(®s
->con
) & I2cConIntPending
;
119 static void i2c_clear_int(struct i2c_regs
*regs
)
121 write8(®s
->con
, read8(®s
->con
) & ~I2cConIntPending
);
124 static void i2c_ack_enable(struct i2c_regs
*regs
)
126 write8(®s
->con
, read8(®s
->con
) | I2cConAckGen
);
129 static void i2c_ack_disable(struct i2c_regs
*regs
)
131 write8(®s
->con
, read8(®s
->con
) & ~I2cConAckGen
);
134 static int i2c_got_ack(struct i2c_regs
*regs
)
136 return !(read8(®s
->stat
) & I2cStatAck
);
139 static int i2c_wait_for_idle(struct i2c_regs
*regs
)
141 int timeout
= 1000 * 100; // 1s.
143 if (!(read8(®s
->stat
) & I2cStatBusy
))
147 printk(BIOS_ERR
, "I2C timeout waiting for idle.\n");
151 static int i2c_wait_for_int(struct i2c_regs
*regs
)
153 int timeout
= 1000 * 100; // 1s.
155 if (i2c_int_pending(regs
))
159 printk(BIOS_ERR
, "I2C timeout waiting for I2C interrupt.\n");
166 static int i2c_send_stop(struct i2c_regs
*regs
)
168 uint8_t mode
= read8(®s
->stat
) & (I2cStatModeMask
);
169 write8(®s
->stat
, mode
| I2cStatEnable
);
171 return i2c_wait_for_idle(regs
);
174 static int i2c_send_start(struct i2c_regs
*regs
, int read
, int chip
)
176 write8(®s
->ds
, chip
<< 1);
177 uint8_t mode
= read
? I2cStatMasterRecv
: I2cStatMasterXmit
;
178 write8(®s
->stat
, mode
| I2cStatStartStop
| I2cStatEnable
);
181 if (i2c_wait_for_int(regs
))
184 if (!i2c_got_ack(regs
)) {
185 // Nobody home, but they may just be asleep.
192 static int i2c_xmit_buf(struct i2c_regs
*regs
, uint8_t *data
, int len
)
196 i2c_ack_enable(regs
);
199 for (i
= 0; i
< len
; i
++) {
200 write8(®s
->ds
, data
[i
]);
203 if (i2c_wait_for_int(regs
))
206 if (!i2c_got_ack(regs
)) {
207 printk(BIOS_INFO
, "I2c nacked.\n");
215 static int i2c_recv_buf(struct i2c_regs
*regs
, uint8_t *data
, int len
)
219 i2c_ack_enable(regs
);
222 for (i
= 0; i
< len
; i
++) {
224 i2c_ack_disable(regs
);
227 if (i2c_wait_for_int(regs
))
230 data
[i
] = read8(®s
->ds
);
236 int platform_i2c_transfer(unsigned bus
, struct i2c_seg
*segments
, int seg_count
)
238 struct s3c24x0_i2c_bus
*i2c
= &i2c_busses
[bus
];
239 struct i2c_regs
*regs
= i2c
->regs
;
242 if (!regs
|| i2c_wait_for_idle(regs
))
245 write8(®s
->stat
, I2cStatMasterXmit
| I2cStatEnable
);
248 for (i
= 0; i
< seg_count
; i
++) {
249 struct i2c_seg
*seg
= &segments
[i
];
251 res
= i2c_send_start(regs
, seg
->read
, seg
->chip
);
255 res
= i2c_recv_buf(regs
, seg
->buf
, seg
->len
);
257 res
= i2c_xmit_buf(regs
, seg
->buf
, seg
->len
);
262 return i2c_send_stop(regs
) || res
;
265 void i2c_init(unsigned bus
, int speed
, int slaveadd
)
267 struct s3c24x0_i2c_bus
*i2c
= &i2c_busses
[bus
];
269 unsigned long freq
, pres
= 16, div
;
272 freq
= clock_get_periph_rate(i2c
->periph_id
);
273 // Calculate prescaler and divisor values.
274 if ((freq
/ pres
/ (16 + 1)) > speed
)
275 /* set prescaler to 512 */
280 while ((freq
/ pres
/ (div
+ 1)) > speed
)
283 // Set prescaler, divisor according to freq, also set ACKGEN, IRQ.
284 val
= (div
& 0x0f) | 0xa0 | ((pres
== 512) ? 0x40 : 0);
285 write32(&i2c
->regs
->con
, val
);
287 // Init to SLAVE RECEIVE mode and clear I2CADDn.
288 write32(&i2c
->regs
->stat
, 0);
289 write32(&i2c
->regs
->add
, slaveadd
);
290 // program Master Transmit (and implicit STOP).
291 write32(&i2c
->regs
->stat
, I2cStatMasterXmit
| I2cStatEnable
);