tree: drop last paragraph of GPL copyright header
[coreboot.git] / src / soc / samsung / exynos5250 / i2c.c
blob97db093119b814e56b7668ce51e04652d26df9dc
1 /*
2 * This file is part of the coreboot project.
4 * (C) Copyright 2002
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.
17 #include <arch/io.h>
18 #include <assert.h>
19 #include <console/console.h>
20 #include <delay.h>
21 #include <device/i2c.h>
22 #include <soc/clk.h>
23 #include <soc/i2c.h>
24 #include <soc/periph.h>
26 struct __attribute__ ((packed)) i2c_regs
28 uint8_t con;
29 uint8_t _1[3];
30 uint8_t stat;
31 uint8_t _2[3];
32 uint8_t add;
33 uint8_t _3[3];
34 uint8_t ds;
35 uint8_t _4[3];
36 uint8_t lc;
37 uint8_t _5[3];
40 struct s3c24x0_i2c_bus {
41 int bus_num;
42 struct i2c_regs *regs;
43 enum periph_id periph_id;
46 enum {
47 I2cConIntPending = 0x1 << 4,
48 I2cConIntEn = 0x1 << 5,
49 I2cConAckGen = 0x1 << 7
52 enum {
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[] = {
70 .bus_num = 0,
71 .regs = (void *)0x12c60000,
72 .periph_id = PERIPH_ID_I2C0,
75 .bus_num = 1,
76 .regs = (void *)0x12c70000,
77 .periph_id = PERIPH_ID_I2C1,
80 .bus_num = 2,
81 .regs = (void *)0x12c80000,
82 .periph_id = PERIPH_ID_I2C2,
85 .bus_num = 3,
86 .regs = (void *)0x12c90000,
87 .periph_id = PERIPH_ID_I2C3,
90 .bus_num = 4,
91 .regs = (void *)0x12ca0000,
92 .periph_id = PERIPH_ID_I2C4,
95 .bus_num = 5,
96 .regs = (void *)0x12cb0000,
97 .periph_id = PERIPH_ID_I2C5,
100 .bus_num = 6,
101 .regs = (void *)0x12cc0000,
102 .periph_id = PERIPH_ID_I2C6,
105 .bus_num = 7,
106 .regs = (void *)0x12cd0000,
107 .periph_id = PERIPH_ID_I2C7,
114 static int i2c_int_pending(struct i2c_regs *regs)
116 return read8(&regs->con) & I2cConIntPending;
119 static void i2c_clear_int(struct i2c_regs *regs)
121 write8(&regs->con, read8(&regs->con) & ~I2cConIntPending);
124 static void i2c_ack_enable(struct i2c_regs *regs)
126 write8(&regs->con, read8(&regs->con) | I2cConAckGen);
129 static void i2c_ack_disable(struct i2c_regs *regs)
131 write8(&regs->con, read8(&regs->con) & ~I2cConAckGen);
134 static int i2c_got_ack(struct i2c_regs *regs)
136 return !(read8(&regs->stat) & I2cStatAck);
139 static int i2c_wait_for_idle(struct i2c_regs *regs)
141 int timeout = 1000 * 100; // 1s.
142 while (timeout--) {
143 if (!(read8(&regs->stat) & I2cStatBusy))
144 return 0;
145 udelay(10);
147 printk(BIOS_ERR, "I2C timeout waiting for idle.\n");
148 return 1;
151 static int i2c_wait_for_int(struct i2c_regs *regs)
153 int timeout = 1000 * 100; // 1s.
154 while (timeout--) {
155 if (i2c_int_pending(regs))
156 return 0;
157 udelay(10);
159 printk(BIOS_ERR, "I2C timeout waiting for I2C interrupt.\n");
160 return 1;
166 static int i2c_send_stop(struct i2c_regs *regs)
168 uint8_t mode = read8(&regs->stat) & (I2cStatModeMask);
169 write8(&regs->stat, mode | I2cStatEnable);
170 i2c_clear_int(regs);
171 return i2c_wait_for_idle(regs);
174 static int i2c_send_start(struct i2c_regs *regs, int read, int chip)
176 write8(&regs->ds, chip << 1);
177 uint8_t mode = read ? I2cStatMasterRecv : I2cStatMasterXmit;
178 write8(&regs->stat, mode | I2cStatStartStop | I2cStatEnable);
179 i2c_clear_int(regs);
181 if (i2c_wait_for_int(regs))
182 return 1;
184 if (!i2c_got_ack(regs)) {
185 // Nobody home, but they may just be asleep.
186 return 1;
189 return 0;
192 static int i2c_xmit_buf(struct i2c_regs *regs, uint8_t *data, int len)
194 ASSERT(len);
196 i2c_ack_enable(regs);
198 int i;
199 for (i = 0; i < len; i++) {
200 write8(&regs->ds, data[i]);
202 i2c_clear_int(regs);
203 if (i2c_wait_for_int(regs))
204 return 1;
206 if (!i2c_got_ack(regs)) {
207 printk(BIOS_INFO, "I2c nacked.\n");
208 return 1;
212 return 0;
215 static int i2c_recv_buf(struct i2c_regs *regs, uint8_t *data, int len)
217 ASSERT(len);
219 i2c_ack_enable(regs);
221 int i;
222 for (i = 0; i < len; i++) {
223 if (i == len - 1)
224 i2c_ack_disable(regs);
226 i2c_clear_int(regs);
227 if (i2c_wait_for_int(regs))
228 return 1;
230 data[i] = read8(&regs->ds);
233 return 0;
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;
240 int res = 0;
242 if (!regs || i2c_wait_for_idle(regs))
243 return 1;
245 write8(&regs->stat, I2cStatMasterXmit | I2cStatEnable);
247 int i;
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);
252 if (res)
253 break;
254 if (seg->read)
255 res = i2c_recv_buf(regs, seg->buf, seg->len);
256 else
257 res = i2c_xmit_buf(regs, seg->buf, seg->len);
258 if (res)
259 break;
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;
270 unsigned long val;
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 */
276 pres = 512;
278 div = 0;
280 while ((freq / pres / (div + 1)) > speed)
281 div++;
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);