drivers/wifi: Remove unnecessary data structure copy
[coreboot2.git] / src / soc / samsung / exynos5250 / i2c.c
blob5ce4c7d8146ef48b8af4cd22cb12e9838276c73b
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <device/mmio.h>
4 #include <assert.h>
5 #include <console/console.h>
6 #include <delay.h>
7 #include <device/i2c_simple.h>
8 #include <soc/clk.h>
9 #include <soc/i2c.h>
10 #include <soc/periph.h>
11 #include <timer.h>
13 #define I2C_TIMEOUT_US (1000 * USECS_PER_MSEC)
15 struct __packed i2c_regs
17 uint8_t con;
18 uint8_t _1[3];
19 uint8_t stat;
20 uint8_t _2[3];
21 uint8_t add;
22 uint8_t _3[3];
23 uint8_t ds;
24 uint8_t _4[3];
25 uint8_t lc;
26 uint8_t _5[3];
29 struct s3c24x0_i2c_bus {
30 int bus_num;
31 struct i2c_regs *regs;
32 enum periph_id periph_id;
35 enum {
36 I2cConIntPending = 0x1 << 4,
37 I2cConIntEn = 0x1 << 5,
38 I2cConAckGen = 0x1 << 7
41 enum {
42 I2cStatAck = 0x1 << 0,
43 I2cStatAddrZero = 0x1 << 1,
44 I2cStatAddrSlave = 0x1 << 2,
45 I2cStatArb = 0x1 << 3,
46 I2cStatEnable = 0x1 << 4,
47 I2cStatStartStop = 0x1 << 5,
48 I2cStatBusy = 0x1 << 5,
50 I2cStatModeMask = 0x3 << 6,
51 I2cStatSlaveRecv = 0x0 << 6,
52 I2cStatSlaveXmit = 0x1 << 6,
53 I2cStatMasterRecv = 0x2 << 6,
54 I2cStatMasterXmit = 0x3 << 6
57 static struct s3c24x0_i2c_bus i2c_busses[] = {
59 .bus_num = 0,
60 .regs = (void *)0x12c60000,
61 .periph_id = PERIPH_ID_I2C0,
64 .bus_num = 1,
65 .regs = (void *)0x12c70000,
66 .periph_id = PERIPH_ID_I2C1,
69 .bus_num = 2,
70 .regs = (void *)0x12c80000,
71 .periph_id = PERIPH_ID_I2C2,
74 .bus_num = 3,
75 .regs = (void *)0x12c90000,
76 .periph_id = PERIPH_ID_I2C3,
79 .bus_num = 4,
80 .regs = (void *)0x12ca0000,
81 .periph_id = PERIPH_ID_I2C4,
84 .bus_num = 5,
85 .regs = (void *)0x12cb0000,
86 .periph_id = PERIPH_ID_I2C5,
89 .bus_num = 6,
90 .regs = (void *)0x12cc0000,
91 .periph_id = PERIPH_ID_I2C6,
94 .bus_num = 7,
95 .regs = (void *)0x12cd0000,
96 .periph_id = PERIPH_ID_I2C7,
100 static int i2c_int_pending(struct i2c_regs *regs)
102 return read8(&regs->con) & I2cConIntPending;
105 static void i2c_clear_int(struct i2c_regs *regs)
107 write8(&regs->con, read8(&regs->con) & ~I2cConIntPending);
110 static void i2c_ack_enable(struct i2c_regs *regs)
112 write8(&regs->con, read8(&regs->con) | I2cConAckGen);
115 static void i2c_ack_disable(struct i2c_regs *regs)
117 write8(&regs->con, read8(&regs->con) & ~I2cConAckGen);
120 static int i2c_got_ack(struct i2c_regs *regs)
122 return !(read8(&regs->stat) & I2cStatAck);
125 static int i2c_wait_for_idle(struct i2c_regs *regs, int timeout_us)
127 int timeout = DIV_ROUND_UP(timeout_us, 10);
128 while (timeout--) {
129 if (!(read8(&regs->stat) & I2cStatBusy))
130 return 0;
131 udelay(10);
133 printk(BIOS_ERR, "I2C timeout waiting for idle.\n");
134 return 1;
137 static int i2c_wait_for_int(struct i2c_regs *regs, int timeout_us)
139 int timeout = DIV_ROUND_UP(timeout_us, 10);
140 while (timeout--) {
141 if (i2c_int_pending(regs))
142 return 0;
143 udelay(10);
145 printk(BIOS_ERR, "I2C timeout waiting for I2C interrupt.\n");
146 return 1;
149 static int i2c_send_stop(struct i2c_regs *regs)
151 uint8_t mode = read8(&regs->stat) & (I2cStatModeMask);
152 write8(&regs->stat, mode | I2cStatEnable);
153 i2c_clear_int(regs);
154 return i2c_wait_for_idle(regs, I2C_TIMEOUT_US);
157 static int i2c_send_start(struct i2c_regs *regs, int read, int chip)
159 write8(&regs->ds, chip << 1);
160 uint8_t mode = read ? I2cStatMasterRecv : I2cStatMasterXmit;
161 write8(&regs->stat, mode | I2cStatStartStop | I2cStatEnable);
162 i2c_clear_int(regs);
164 if (i2c_wait_for_int(regs, I2C_TIMEOUT_US))
165 return 1;
167 if (!i2c_got_ack(regs)) {
168 // Nobody home, but they may just be asleep.
169 return 1;
172 return 0;
175 static int i2c_xmit_buf(struct i2c_regs *regs, uint8_t *data, int len)
177 ASSERT(len);
179 i2c_ack_enable(regs);
181 int i;
182 for (i = 0; i < len; i++) {
183 write8(&regs->ds, data[i]);
185 i2c_clear_int(regs);
186 if (i2c_wait_for_int(regs, CONFIG_I2C_TRANSFER_TIMEOUT_US))
187 return 1;
189 if (!i2c_got_ack(regs)) {
190 printk(BIOS_INFO, "I2c nacked.\n");
191 return 1;
195 return 0;
198 static int i2c_recv_buf(struct i2c_regs *regs, uint8_t *data, int len)
200 ASSERT(len);
202 i2c_ack_enable(regs);
204 int i;
205 for (i = 0; i < len; i++) {
206 if (i == len - 1)
207 i2c_ack_disable(regs);
209 i2c_clear_int(regs);
210 if (i2c_wait_for_int(regs, CONFIG_I2C_TRANSFER_TIMEOUT_US))
211 return 1;
213 data[i] = read8(&regs->ds);
216 return 0;
219 int platform_i2c_transfer(unsigned int bus, struct i2c_msg *segments,
220 int seg_count)
222 struct s3c24x0_i2c_bus *i2c = &i2c_busses[bus];
223 struct i2c_regs *regs = i2c->regs;
224 int res = 0;
226 if (!regs || i2c_wait_for_idle(regs, I2C_TIMEOUT_US))
227 return 1;
229 write8(&regs->stat, I2cStatMasterXmit | I2cStatEnable);
231 int i;
232 for (i = 0; i < seg_count; i++) {
233 struct i2c_msg *seg = &segments[i];
235 res = i2c_send_start(regs, seg->flags & I2C_M_RD, seg->slave);
236 if (res)
237 break;
238 if (seg->flags & I2C_M_RD)
239 res = i2c_recv_buf(regs, seg->buf, seg->len);
240 else
241 res = i2c_xmit_buf(regs, seg->buf, seg->len);
242 if (res)
243 break;
246 return i2c_send_stop(regs) || res;
249 void i2c_init(unsigned int bus, int speed, int slaveadd)
251 struct s3c24x0_i2c_bus *i2c = &i2c_busses[bus];
253 unsigned long freq, pres = 16, div;
254 unsigned long val;
256 freq = clock_get_periph_rate(i2c->periph_id);
257 // Calculate prescaler and divisor values.
258 if ((freq / pres / (16 + 1)) > speed)
259 /* set prescaler to 512 */
260 pres = 512;
262 div = 0;
264 while ((freq / pres / (div + 1)) > speed)
265 div++;
267 // Set prescaler, divisor according to freq, also set ACKGEN, IRQ.
268 val = (div & 0x0f) | 0xa0 | ((pres == 512) ? 0x40 : 0);
269 write32(&i2c->regs->con, val);
271 // Init to SLAVE RECEIVE mode and clear I2CADDn.
272 write32(&i2c->regs->stat, 0);
273 write32(&i2c->regs->add, slaveadd);
274 // program Master Transmit (and implicit STOP).
275 write32(&i2c->regs->stat, I2cStatMasterXmit | I2cStatEnable);