blob: 2f4a38f0db98a7bc6244e801296a5624d7e45c43 [file] [log] [blame]
balrog02645922007-11-03 12:50:46 +00001/*
2 * TI OMAP on-chip I2C controller. Only "new I2C" mode supported.
3 *
4 * Copyright (C) 2007 Andrzej Zaborowski <balrog@zabor.org>
Riku Voipioffdea892011-01-17 16:50:36 +00005 * Copyright (C) 2009 Nokia Corporation
balrog02645922007-11-03 12:50:46 +00006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
aurel32fad6cb12009-01-04 22:05:52 +000017 * You should have received a copy of the GNU General Public License along
Blue Swirl8167ee82009-07-16 20:47:01 +000018 * with this program; if not, see <http://www.gnu.org/licenses/>.
balrog02645922007-11-03 12:50:46 +000019 */
pbrook87ecb682007-11-17 17:14:51 +000020#include "hw.h"
21#include "i2c.h"
22#include "omap.h"
balrog02645922007-11-03 12:50:46 +000023
Riku Voipioffdea892011-01-17 16:50:36 +000024#define I2C_MAX_FIFO_SIZE (1 << 6)
25#define I2C_FIFO_SIZE_MASK ((I2C_MAX_FIFO_SIZE) - 1)
26
balrog02645922007-11-03 12:50:46 +000027struct omap_i2c_s {
balrog02645922007-11-03 12:50:46 +000028 qemu_irq irq;
29 qemu_irq drq[2];
balrog02645922007-11-03 12:50:46 +000030 i2c_bus *bus;
31
balrog29885472008-02-10 17:02:23 +000032 uint8_t revision;
Riku Voipioffdea892011-01-17 16:50:36 +000033 uint16_t mask;
balrog02645922007-11-03 12:50:46 +000034 uint16_t stat;
Riku Voipioffdea892011-01-17 16:50:36 +000035 uint16_t we;
balrog02645922007-11-03 12:50:46 +000036 uint16_t dma;
37 uint16_t count;
38 int count_cur;
Riku Voipioffdea892011-01-17 16:50:36 +000039 uint16_t sysc;
balrog02645922007-11-03 12:50:46 +000040 uint16_t control;
Riku Voipioffdea892011-01-17 16:50:36 +000041 uint16_t own_addr[4];
42 uint16_t slave_addr;
43 uint8_t sblock;
balrog02645922007-11-03 12:50:46 +000044 uint8_t divider;
Riku Voipioffdea892011-01-17 16:50:36 +000045 uint16_t times[2];
balrog02645922007-11-03 12:50:46 +000046 uint16_t test;
Riku Voipioffdea892011-01-17 16:50:36 +000047 int fifostart;
48 int fifolen;
49 int fifosize;
50 uint8_t fifo[I2C_MAX_FIFO_SIZE];
balrog02645922007-11-03 12:50:46 +000051};
52
Riku Voipio7f3d8482011-01-17 16:50:36 +000053#define OMAP2_INTR_REV 0x34
54#define OMAP2_GC_REV 0x34
55#define OMAP3_INTR_REV 0x3c
56#define OMAP3630_INTR_REV 0x40
Riku Voipioffdea892011-01-17 16:50:36 +000057
58//#define I2C_DEBUG
59#ifdef I2C_DEBUG
60#define TRACE(fmt, ...) fprintf(stderr, "%s " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
61#else
62#define TRACE(...)
63#endif
balrog29885472008-02-10 17:02:23 +000064
balrog02645922007-11-03 12:50:46 +000065static void omap_i2c_interrupts_update(struct omap_i2c_s *s)
66{
Riku Voipioffdea892011-01-17 16:50:36 +000067 TRACE("IRQ=%04x,RDRQ=%d,XDRQ=%d",
68 s->stat & s->mask,
69 ((s->dma >> 15 ) & 1) & ((s->stat >> 3) & 1),
70 ((s->dma >> 7 ) & 1 )& ((s->stat >> 4 ) & 1));
balrog02645922007-11-03 12:50:46 +000071 qemu_set_irq(s->irq, s->stat & s->mask);
Riku Voipioffdea892011-01-17 16:50:36 +000072 if ((s->dma >> 15) & 1) /* RDMA_EN */
73 qemu_set_irq(s->drq[0], (s->stat >> 3) & 1); /* RRDY */
74 if ((s->dma >> 7) & 1) /* XDMA_EN */
75 qemu_set_irq(s->drq[1], (s->stat >> 4) & 1); /* XRDY */
balrog02645922007-11-03 12:50:46 +000076}
77
balrog02645922007-11-03 12:50:46 +000078static void omap_i2c_fifo_run(struct omap_i2c_s *s)
79{
Riku Voipioffdea892011-01-17 16:50:36 +000080 int ack = 1, i;
balrog02645922007-11-03 12:50:46 +000081
82 if (!i2c_bus_busy(s->bus))
83 return;
84
85 if ((s->control >> 2) & 1) { /* RM */
86 if ((s->control >> 1) & 1) { /* STP */
87 i2c_end_transfer(s->bus);
88 s->control &= ~(1 << 1); /* STP */
89 s->count_cur = s->count;
Riku Voipioffdea892011-01-17 16:50:36 +000090 s->fifolen = 0;
balrog02645922007-11-03 12:50:46 +000091 } else if ((s->control >> 9) & 1) { /* TRX */
Riku Voipioffdea892011-01-17 16:50:36 +000092 while (ack && s->fifolen) {
93 ack = (i2c_send(s->bus, s->fifo[s->fifostart++]) >= 0);
94 s->fifostart &= I2C_FIFO_SIZE_MASK;
95 s->fifolen--;
96 }
97 s->fifolen = 0;
balrog02645922007-11-03 12:50:46 +000098 s->stat |= 1 << 4; /* XRDY */
99 } else {
Riku Voipioffdea892011-01-17 16:50:36 +0000100 for (i = 0; i < 4; i++)
101 s->fifo[(s->fifostart + i) & I2C_FIFO_SIZE_MASK] =
102 i2c_recv(s->bus);
103 s->fifolen = 4;
balrog02645922007-11-03 12:50:46 +0000104 s->stat |= 1 << 3; /* RRDY */
105 }
106 } else {
Riku Voipioffdea892011-01-17 16:50:36 +0000107 if ((s->control >> 9) & 1) { /* TRX */
108 TRACE("master transmit, count_cur=%d, fifolen=%d",
109 s->count_cur, s->fifolen);
110 for (; ack && s->count_cur && s->fifolen; s->count_cur--) {
111 ack = (i2c_send(s->bus, s->fifo[s->fifostart++]) >= 0);
112 s->fifostart &= I2C_FIFO_SIZE_MASK;
113 s->fifolen--;
balrog02645922007-11-03 12:50:46 +0000114 }
Riku Voipioffdea892011-01-17 16:50:36 +0000115 s->stat &= ~0x4410; /* XDR | XUDF | XRDY */
116 if (ack && s->count_cur) { /* send more? */
117 /* we know that FIFO is empty */
118 if (s->revision < OMAP3_INTR_REV)
119 s->stat |= 1 << 4; /* XRDY */
120 else {
121 if (s->count_cur > (s->dma & 0x3f)) /* XTRSH */
122 s->stat |= 1 << 4; /* XRDY */
123 else
124 s->stat |= 1 << 14; /* XDR */
125 }
balrog02645922007-11-03 12:50:46 +0000126 }
Riku Voipioffdea892011-01-17 16:50:36 +0000127 if (!s->count_cur) /* everything sent? */
128 s->stat |= 1 << 2; /* ARDY */
129 } else { /* !TRX */
130 TRACE("master receive");
131 for (; s->count_cur && s->fifolen < s->fifosize; s->count_cur--) {
132 i = i2c_recv(s->bus);
133 if (i < 0) break; /* stop receiving if nothing to receive */
134 s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
135 (uint8_t)(i & 0xff);
136 TRACE("received fifo[%02x] = %02x", s->fifolen - 1,
137 s->fifo[(s->fifostart + s->fifolen - 1) & I2C_FIFO_SIZE_MASK]);
balrog02645922007-11-03 12:50:46 +0000138 }
Riku Voipioffdea892011-01-17 16:50:36 +0000139 s->stat &= ~((1 << 3) | (1 << 13)); /* RRDY | RDR */
140 if (s->fifolen) {
141 if (s->revision < OMAP3_INTR_REV)
142 s->stat |= 1 << 3; /* RRDY */
143 else {
144 if (s->fifolen > ((s->dma >> 8) & 0x3f)) /* RTRSH */
145 s->stat |= 1 << 3; /* RRDY */
146 else
147 s->stat |= 1 << 13; /* RDR */
148 }
149 } else if (!s->count_cur && (s->control & 2)) /* STP */
150 s->stat |= 1 << 2; /* ARDY */
balrog02645922007-11-03 12:50:46 +0000151 }
152 if (!s->count_cur) {
Riku Voipioffdea892011-01-17 16:50:36 +0000153 TRACE("no more data to transmit/receive");
Matt Waddel57ff4f52011-01-17 16:50:36 +0000154 i2c_end_transfer(s->bus);
Riku Voipioffdea892011-01-17 16:50:36 +0000155 if ((s->control >> 1) & 1) { /* STP */
Riku Voipioffdea892011-01-17 16:50:36 +0000156 s->control &= ~0x0602; /* MST | TRX | STP */
balrog02645922007-11-03 12:50:46 +0000157 s->count_cur = s->count;
Riku Voipioffdea892011-01-17 16:50:36 +0000158 }
balrog02645922007-11-03 12:50:46 +0000159 }
160 }
161
Riku Voipioffdea892011-01-17 16:50:36 +0000162 s->stat |= (!ack) << 1; /* NACK */
balrog02645922007-11-03 12:50:46 +0000163 if (!ack)
Riku Voipioffdea892011-01-17 16:50:36 +0000164 s->control &= ~(1 << 1); /* STP */
165 TRACE("finished, STAT = %04x, CNT = %d", s->stat, s->count_cur);
balrog02645922007-11-03 12:50:46 +0000166}
167
168void omap_i2c_reset(struct omap_i2c_s *s)
169{
170 s->mask = 0;
171 s->stat = 0;
172 s->dma = 0;
173 s->count = 0;
174 s->count_cur = 0;
Riku Voipioffdea892011-01-17 16:50:36 +0000175 s->we = 0;
176 s->sysc = 0;
177 s->fifolen = 0;
178 s->fifostart = 0;
balrog02645922007-11-03 12:50:46 +0000179 s->control = 0;
Riku Voipioffdea892011-01-17 16:50:36 +0000180 s->own_addr[0] = 0;
181 s->own_addr[1] = 0;
182 s->own_addr[2] = 0;
183 s->own_addr[3] = 0;
184 s->slave_addr = 0;
185 s->sblock = 0;
balrog02645922007-11-03 12:50:46 +0000186 s->divider = 0;
187 s->times[0] = 0;
188 s->times[1] = 0;
189 s->test = 0;
Riku Voipioffdea892011-01-17 16:50:36 +0000190
191 i2c_end_transfer(s->bus);
balrog02645922007-11-03 12:50:46 +0000192}
193
Anthony Liguoric227f092009-10-01 16:12:16 -0500194static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr)
balrog02645922007-11-03 12:50:46 +0000195{
196 struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
balrogcf965d22007-11-04 12:19:22 +0000197 int offset = addr & OMAP_MPUI_REG_MASK;
balrog02645922007-11-03 12:50:46 +0000198 uint16_t ret;
199
200 switch (offset) {
Riku Voipioffdea892011-01-17 16:50:36 +0000201 case 0x00: /* I2C_REV */
202 TRACE("REV returns %04x", s->revision);
203 return s->revision;
204 case 0x04: /* I2C_IE */
205 TRACE("IE returns %04x", s->mask);
206 return s->mask;
207 case 0x08: /* I2C_STAT */
Riku Voipiod356bd12011-01-17 16:50:36 +0000208 ret = s->stat | (i2c_bus_busy(s->bus) << 12 );
209 if (s->revision >= OMAP3_INTR_REV && (s->stat & 0x4010)) /* XRDY or XDR */
210 s->stat |= 1 << 10; /* XUDF as required by errata 1.153 */
211 TRACE("STAT returns %04x", ret);
212 return ret;
Riku Voipioffdea892011-01-17 16:50:36 +0000213 case 0x0c: /* I2C_IV / I2C_WE */
214 if (s->revision >= OMAP3_INTR_REV)
215 return s->we;
216 if (s->revision >= OMAP2_INTR_REV)
217 break;
218 ret = ffs(s->stat & s->mask);
219 if (ret)
220 s->stat ^= 1 << (ret - 1);
221 omap_i2c_interrupts_update(s);
222 return ret;
223 case 0x10: /* I2C_SYSS */
224 return (s->control >> 15) & 1; /* reset completed == I2C_EN */
225 case 0x14: /* I2C_BUF */
226 TRACE("BUF returns %04x", s->dma);
227 return s->dma;
228 case 0x18: /* I2C_CNT */
229 TRACE("CNT returns %04x", s->count_cur);
230 return s->count_cur; /* DCOUNT */
231 case 0x1c: /* I2C_DATA */
232 ret = 0;
233 if (s->fifolen) {
234 if (s->revision < OMAP3_INTR_REV) {
235 if (s->control & (1 << 14)) /* BE */
236 ret = (((uint16_t)s->fifo[s->fifostart]) << 8)
237 | s->fifo[(s->fifostart + 1) & I2C_FIFO_SIZE_MASK];
238 else
239 ret = (((uint16_t)s->fifo[(s->fifostart + 1) & I2C_FIFO_SIZE_MASK]) << 8)
240 | s->fifo[s->fifostart];
241 s->fifostart = (s->fifostart + 2) & I2C_FIFO_SIZE_MASK;
242 if (s->fifolen == 1) {
243 s->stat |= 1 << 15; /* SBD */
244 s->fifolen = 0;
245 } else
246 s->fifolen -= 2;
247 if (!s->fifolen) {
248 s->stat &= ~(1 << 3); /* RRDY */
249 s->stat |= 1 << 2; /* ARDY */
250 }
251 } else {
252 s->stat &= ~(1 << 7); /* AERR */
253 ret = s->fifo[s->fifostart++];
254 s->fifostart &= I2C_FIFO_SIZE_MASK;
255 if (--s->fifolen) {
256 if (s->fifolen <= ((s->dma >> 8) & 0x3f)) {
257 s->stat &= ~(1 << 3); /* RRDY */
258 s->stat |= 1 << 13; /* RDR */
259 }
260 } else {
261 s->stat &= ~((1 << 3) | (1 << 13)); /* RRDY | RDR */
262 s->stat |= 1 << 2; /* ARDY */
263 }
264 }
265 s->stat &= ~(1 << 11); /* ROVR */
266 } else if (s->revision >= OMAP3_INTR_REV)
267 s->stat |= (1 << 7); /* AERR */
268 TRACE("DATA returns %04x", ret);
269 omap_i2c_fifo_run(s);
270 omap_i2c_interrupts_update(s);
271 return ret;
272 case 0x20: /* I2C_SYSC */
273 TRACE("SYSC returns %04x", s->sysc);
274 return s->sysc;
275 case 0x24: /* I2C_CON */
276 TRACE("CON returns %04x", s->control);
277 return s->control;
278 case 0x28: /* I2C_OA / I2C_OA0 */
279 return s->own_addr[0];
280 case 0x2c: /* I2C_SA */
281 return s->slave_addr;
282 case 0x30: /* I2C_PSC */
283 return s->divider;
284 case 0x34: /* I2C_SCLL */
285 return s->times[0];
286 case 0x38: /* I2C_SCLH */
287 return s->times[1];
288 case 0x3c: /* I2C_SYSTEST */
289 if (s->test & (1 << 15)) { /* ST_EN */
290 s->test ^= 0xa;
291 return s->test;
balrog02645922007-11-03 12:50:46 +0000292 }
balrog02645922007-11-03 12:50:46 +0000293 return s->test & ~0x300f;
Riku Voipioffdea892011-01-17 16:50:36 +0000294 case 0x40: /* I2C_BUFSTAT */
295 if (s->revision >= OMAP3_INTR_REV) {
296 switch (s->fifosize) {
297 case 8: ret = 0x0000; break;
298 case 16: ret = 0x4000; break;
299 case 32: ret = 0x8000; break;
300 case 64: ret = 0xc000; break;
301 default: ret = 0x0000; break;
302 }
303 ret |= ((s->fifolen) & 0x3f) << 8; /* RXSTAT */
304 ret |= (s->count_cur) & 0x3f; /* TXSTAT */
305 TRACE("BUFSTAT returns %04x", ret);
306 return ret;
307 }
308 break;
309 case 0x44: /* I2C_OA1 */
310 case 0x48: /* I2C_OA2 */
311 case 0x4c: /* I2C_OA3 */
312 if (s->revision >= OMAP3_INTR_REV)
313 return s->own_addr[(addr >> 2) & 3];
314 break;
315 case 0x50: /* I2C_ACTOA */
316 if (s->revision >= OMAP3_INTR_REV)
317 return 0; /* TODO: determine accessed slave own address */
318 break;
319 case 0x54: /* I2C_SBLOCK */
320 if (s->revision >= OMAP3_INTR_REV)
321 return s->sblock;
322 break;
323 default:
324 break;
balrog02645922007-11-03 12:50:46 +0000325 }
326
327 OMAP_BAD_REG(addr);
328 return 0;
329}
330
Matt Waddel715cc6d2011-01-17 16:50:36 +0000331static uint32_t omap_i2c_readb(void *opaque, target_phys_addr_t addr)
332{
333 struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
334 int offset = addr & OMAP_MPUI_REG_MASK;
335 uint8_t ret;
336
337 switch (offset) {
338 case 0x1c: /* I2C_DATA */
339 ret = 0;
340 if (s->fifolen) {
341 if (s->revision < OMAP3_INTR_REV) {
342 if (s->control & (1 << 14)) /* BE */
343 ret = (((uint8_t)s->fifo[s->fifostart]) << 8)
344 | s->fifo[(s->fifostart + 1) & I2C_FIFO_SIZE_MASK];
345 else
346 ret = (((uint8_t)s->fifo[(s->fifostart + 1) & I2C_FIFO_SIZE_MASK]) << 8)
347 | s->fifo[s->fifostart];
348 s->fifostart = (s->fifostart + 2) & I2C_FIFO_SIZE_MASK;
349 if (s->fifolen == 1) {
350 s->stat |= 1 << 15; /* SBD */
351 s->fifolen = 0;
352 } else
353 s->fifolen -= 2;
354 if (!s->fifolen) {
355 s->stat &= ~(1 << 3); /* RRDY */
356 s->stat |= 1 << 2; /* ARDY */
357 }
358 } else {
359 s->stat &= ~(1 << 7); /* AERR */
360 ret = (uint8_t)s->fifo[s->fifostart++];
361 s->fifostart &= I2C_FIFO_SIZE_MASK;
362 if (--s->fifolen) {
363 if (s->fifolen <= ((s->dma >> 8) & 0x3f)) {
364 s->stat &= ~(1 << 3); /* RRDY */
365 s->stat |= 1 << 13; /* RDR */
366 }
367 } else {
368 s->stat &= ~((1 << 3) | (1 << 13)); /* RRDY | RDR */
369 s->stat |= 1 << 2; /* ARDY */
370 }
371 }
372 s->stat &= ~(1 << 11); /* ROVR */
373 } else if (s->revision >= OMAP3_INTR_REV)
374 s->stat |= (1 << 7); /* AERR */
375 TRACE("DATA returns %04x", ret);
376 omap_i2c_fifo_run(s);
377 omap_i2c_interrupts_update(s);
378 return ret;
379 default:
380 break;
381 }
382
383 OMAP_BAD_REG(addr);
384 return 0;
385}
386
Anthony Liguoric227f092009-10-01 16:12:16 -0500387static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
balrog02645922007-11-03 12:50:46 +0000388 uint32_t value)
389{
390 struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
balrogcf965d22007-11-04 12:19:22 +0000391 int offset = addr & OMAP_MPUI_REG_MASK;
balrog02645922007-11-03 12:50:46 +0000392 int nack;
393
394 switch (offset) {
Riku Voipioffdea892011-01-17 16:50:36 +0000395 case 0x00: /* I2C_REV */
396 case 0x10: /* I2C_SYSS */
397 case 0x40: /* I2C_BUFSTAT */
398 case 0x50: /* I2C_ACTOA */
balrog29885472008-02-10 17:02:23 +0000399 OMAP_RO_REG(addr);
balrog02645922007-11-03 12:50:46 +0000400 break;
Riku Voipioffdea892011-01-17 16:50:36 +0000401 case 0x04: /* I2C_IE */
402 TRACE("IE = %04x", value);
Riku Voipio7f3d8482011-01-17 16:50:36 +0000403 if (s->revision < OMAP2_GC_REV) {
404 s->mask = value & 0x1f;
405 } else if (s->revision < OMAP3_INTR_REV) {
406 s->mask = value & 0x3f;
407 } else if (s->revision == OMAP3_INTR_REV) {
Riku Voipioffdea892011-01-17 16:50:36 +0000408 s->mask = value & 0x63ff;
Riku Voipio7f3d8482011-01-17 16:50:36 +0000409 } else { /* omap3630 */
410 s->mask = value & 0x6fff;
411 }
balrog02645922007-11-03 12:50:46 +0000412 omap_i2c_interrupts_update(s);
Riku Voipioffdea892011-01-17 16:50:36 +0000413 break;
414 case 0x08: /* I2C_STAT */
Riku Voipio7f3d8482011-01-17 16:50:36 +0000415 if (s->revision < OMAP2_INTR_REV) {
Riku Voipioffdea892011-01-17 16:50:36 +0000416 OMAP_RO_REG(addr);
Riku Voipio7f3d8482011-01-17 16:50:36 +0000417 } else {
Riku Voipioffdea892011-01-17 16:50:36 +0000418 TRACE("STAT = %04x", value);
419 /* RRDY and XRDY are reset by hardware. (in all versions???) */
Riku Voipio7f3d8482011-01-17 16:50:36 +0000420 if (s->revision < OMAP3_INTR_REV) {
421 value &= 0x27;
422 } else if (s->revision == OMAP3_INTR_REV) {
423 value &= 0x63e7;
424 } else { /* omap3630 */
425 value &= 0x6ee7;
426 }
427 s->stat &= ~value;
balrog29885472008-02-10 17:02:23 +0000428 omap_i2c_interrupts_update(s);
429 }
Riku Voipioffdea892011-01-17 16:50:36 +0000430 break;
431 case 0x0c: /* I2C_IV / I2C_WE */
Riku Voipio7f3d8482011-01-17 16:50:36 +0000432 if (s->revision < OMAP3_INTR_REV) {
Riku Voipioffdea892011-01-17 16:50:36 +0000433 OMAP_RO_REG(addr);
Riku Voipio7f3d8482011-01-17 16:50:36 +0000434 } else if (s->revision == OMAP3_INTR_REV) {
Riku Voipioffdea892011-01-17 16:50:36 +0000435 s->we = value & 0x636f;
Riku Voipio7f3d8482011-01-17 16:50:36 +0000436 } else { /* omap3630 */
437 s->we = value & 0x6f6f;
438 }
Riku Voipioffdea892011-01-17 16:50:36 +0000439 break;
440 case 0x14: /* I2C_BUF */
441 TRACE("BUF = %04x", value);
442 if (s->revision < OMAP3_INTR_REV)
443 s->dma = value & 0x8080;
444 else {
445 s->dma = value & 0xbfbf;
446 if ((value & (1 << 14)) /* RXFIFO_CLR */
447 || (value & (1 << 6))) /* TXFIFO_CLR */
448 s->fifolen = 0;
449 }
450 if (value & (1 << 15)) /* RDMA_EN */
451 s->mask &= ~(1 << 3); /* RRDY_IE */
452 if (value & (1 << 7)) /* XDMA_EN */
453 s->mask &= ~(1 << 4); /* XRDY_IE */
454 break;
455 case 0x18: /* I2C_CNT */
456 TRACE("CNT = %04x", value);
457 s->count = value; /* DCOUNT */
458 break;
459 case 0x1c: /* I2C_DATA */
460 TRACE("DATA = %04x", value);
461 if (s->revision < OMAP3_INTR_REV) {
462 if (s->fifolen > 2) {
463 /* XXX: remote access (qualifier) error - what's that? */
464 break;
465 }
466 if (s->control & (1 << 14)) { /* BE */
467 s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
468 (uint8_t)((value >> 8) & 0xff);
469 s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
470 (uint8_t)(value & 0xff);
471 } else {
472 s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
473 (uint8_t)(value & 0xff);
474 s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
475 (uint8_t)((value >> 8) & 0xff);
476 }
477 } else {
478 if (s->fifolen < s->fifosize) {
479 s->stat &= ~(1 << 7); /* AERR */
480 s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
481 (uint8_t)(value & 0xff);
482 } else
483 s->stat |= (1 << 7); /* AERR */
484 }
485 s->stat &= ~(1 << 10); /* XUDF */
486 omap_i2c_fifo_run(s);
487 omap_i2c_interrupts_update(s);
488 break;
489 case 0x20: /* I2C_SYSC */
490 if (s->revision < OMAP2_INTR_REV) {
491 OMAP_BAD_REG(addr);
492 break;
493 }
494 TRACE("SYSC = %04x", value);
495 if (value & 2)
496 omap_i2c_reset(s);
497 else if (s->revision >= OMAP3_INTR_REV)
498 s->sysc = value & 0x031d;
499 break;
500 case 0x24: /* I2C_CON */
501 TRACE("CON = %04x", value);
502 s->control = value & (s->revision < OMAP3_INTR_REV ? 0xcf87 : 0xbff3);
503 if (~value & (1 << 15)) { /* I2C_EN */
504 if (s->revision < OMAP2_INTR_REV)
505 omap_i2c_reset(s);
506 break;
507 }
508 if (s->revision >= OMAP3_INTR_REV && ((value >> 12) & 3) > 1) { /* OPMODE */
509 fprintf(stderr,
510 "%s: only FS and HS modes are supported\n",
511 __FUNCTION__);
512 break;
513 }
514 if ((value & (1 << 10))) { /* MST */
515 if (value & 1) { /* STT */
516 nack = !!i2c_start_transfer(s->bus, s->slave_addr, /*SA*/
517 (~value >> 9) & 1); /*TRX*/
518 s->stat |= nack << 1; /* NACK */
519 s->control &= ~(1 << 0); /* STT */
520 s->fifolen = 0;
521 if (nack)
522 s->control &= ~(1 << 1); /* STP */
523 else {
524 s->count_cur = s->count;
525 omap_i2c_fifo_run(s);
526 }
527 omap_i2c_interrupts_update(s);
528 } else if (value & 2) { /* STP, but not STT */
529 i2c_end_transfer(s->bus);
530 s->control &= ~0x0602; /* MST | TRX | STP */
531 s->count_cur = s->count;
532 }
533 }
534 break;
535 case 0x28: /* I2C_OA / I2C_OA0 */
536 TRACE("OA0 = %04x", value);
537 s->own_addr[0] = value & (s->revision < OMAP3_INTR_REV
538 ? 0x3ff : 0xe3ff);
539 /*i2c_set_slave_address(&s->slave[0],
540 value & (s->revision >= OMAP3_INTR_REV
541 && (s->control & 0x80)
542 ? 0x3ff: 0x7f));*/
543 break;
544 case 0x2c: /* I2C_SA */
545 TRACE("SA = %04x", value);
546 s->slave_addr = value & 0x3ff;
547 break;
548 case 0x30: /* I2C_PSC */
549 s->divider = value;
550 break;
551 case 0x34: /* I2C_SCLL */
552 s->times[0] = value & (s->revision < OMAP3_INTR_REV
553 ? 0xff : 0xffff);
554 break;
555 case 0x38: /* I2C_SCLH */
556 s->times[1] = value & (s->revision < OMAP3_INTR_REV
557 ? 0xff : 0xffff);
558 break;
559 case 0x3c: /* I2C_SYSTEST */
Riku Voipio7f3d8482011-01-17 16:50:36 +0000560 if (s->revision < OMAP3_INTR_REV) {
561 value &= 0xf805;
562 } else if (s->revision == OMAP3_INTR_REV) {
563 value &= 0xf815;
564 } else { /* omap3630 */
565 value = (value & 0xf835) | 0x1c00;
566 }
Riku Voipioffdea892011-01-17 16:50:36 +0000567 if ((value & (1 << 15))) { /* ST_EN */
568 fprintf(stderr, "%s: System Test not supported\n",
569 __FUNCTION__);
570 s->test = (s->test & 0x0a) | value;
Riku Voipio7f3d8482011-01-17 16:50:36 +0000571 } else {
572 value &= ~0xff;
573 s->test = (s->test & 0x1f) | value;
574 }
575 if (value & (1 << 11)) { /* SBB */
Riku Voipioffdea892011-01-17 16:50:36 +0000576 if (s->revision >= OMAP2_INTR_REV) {
577 s->stat |= 0x3f;
Riku Voipio7f3d8482011-01-17 16:50:36 +0000578 if (s->revision >= OMAP3_INTR_REV) {
579 s->stat |= 0x6300;
580 if (s->revision > OMAP3_INTR_REV) {
581 s->stat |= 0x0c00;
582 }
583 }
Riku Voipioffdea892011-01-17 16:50:36 +0000584 omap_i2c_interrupts_update(s);
585 }
Riku Voipio7f3d8482011-01-17 16:50:36 +0000586 }
Riku Voipioffdea892011-01-17 16:50:36 +0000587 break;
588 case 0x44: /* I2C_OA1 */
589 case 0x48: /* I2C_OA2 */
590 case 0x4c: /* I2C_OA3 */
Riku Voipio7f3d8482011-01-17 16:50:36 +0000591 if (s->revision < OMAP3_INTR_REV) {
Riku Voipioffdea892011-01-17 16:50:36 +0000592 OMAP_BAD_REG(addr);
Riku Voipio7f3d8482011-01-17 16:50:36 +0000593 } else {
Riku Voipioffdea892011-01-17 16:50:36 +0000594 addr = (addr >> 2) & 3;
595 TRACE("OA%d = %04x", (int)addr, value);
596 s->own_addr[addr] = value & 0x3ff;
597 /*i2c_set_slave_address(&s->slave[addr],
598 value & ((s->control & (0x80 >> addr))
599 ? 0x3ff: 0x7f));*/
600 }
601 break;
602 case 0x54: /* I2C_SBLOCK */
603 if (s->revision < OMAP3_INTR_REV)
604 OMAP_BAD_REG(addr);
605 else {
606 s->sblock = value & 0x0f;
607 }
608 break;
609 default:
610 OMAP_BAD_REG(addr);
611 break;
balrog02645922007-11-03 12:50:46 +0000612 }
613}
614
Anthony Liguoric227f092009-10-01 16:12:16 -0500615static void omap_i2c_writeb(void *opaque, target_phys_addr_t addr,
balrog29885472008-02-10 17:02:23 +0000616 uint32_t value)
617{
618 struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
619 int offset = addr & OMAP_MPUI_REG_MASK;
620
621 switch (offset) {
Riku Voipioffdea892011-01-17 16:50:36 +0000622 case 0x1c: /* I2C_DATA */
623 TRACE("DATA = %02x", value);
624 if (s->revision < OMAP3_INTR_REV && s->fifolen > 2) {
625 /* XXX: remote access (qualifier) error - what's that? */
626 break;
627 }
628 if (s->fifolen < s->fifosize) {
629 s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
630 (uint8_t)(value & 0xff);
631 if (s->revision >= OMAP3_INTR_REV)
632 s->stat &= ~(1 << 7); /* AERR */
633 s->stat &= ~(1 << 10); /* XUDF */
634 omap_i2c_fifo_run(s);
635 } else if (s->revision >= OMAP3_INTR_REV)
636 s->stat |= (1 << 7); /* AERR */
637 omap_i2c_interrupts_update(s);
balrog29885472008-02-10 17:02:23 +0000638 break;
Riku Voipioffdea892011-01-17 16:50:36 +0000639 default:
640 OMAP_BAD_REG(addr);
641 break;
balrog29885472008-02-10 17:02:23 +0000642 }
643}
644
Blue Swirld60efc62009-08-25 18:29:31 +0000645static CPUReadMemoryFunc * const omap_i2c_readfn[] = {
Matt Waddel715cc6d2011-01-17 16:50:36 +0000646 omap_i2c_readb,
balrog02645922007-11-03 12:50:46 +0000647 omap_i2c_read,
648 omap_badwidth_read16,
649};
650
Blue Swirld60efc62009-08-25 18:29:31 +0000651static CPUWriteMemoryFunc * const omap_i2c_writefn[] = {
balrog29885472008-02-10 17:02:23 +0000652 omap_i2c_writeb, /* Only the last fifo write can be 8 bit. */
balrog02645922007-11-03 12:50:46 +0000653 omap_i2c_write,
balrog29885472008-02-10 17:02:23 +0000654 omap_badwidth_write16,
balrog02645922007-11-03 12:50:46 +0000655};
656
Riku Voipioffdea892011-01-17 16:50:36 +0000657static void omap_i2c_save_state(QEMUFile *f, void *opaque)
balrog02645922007-11-03 12:50:46 +0000658{
Riku Voipioffdea892011-01-17 16:50:36 +0000659 struct omap_i2c_s *s = (struct omap_i2c_s *)opaque;
660
661 /* TODO: slave setup(s) */
662 qemu_put_be16(f, s->mask);
663 qemu_put_be16(f, s->stat);
664 qemu_put_be16(f, s->we);
665 qemu_put_be16(f, s->dma);
666 qemu_put_be16(f, s->count);
667 qemu_put_sbe32(f, s->count_cur);
668 qemu_put_be16(f, s->sysc);
669 qemu_put_be16(f, s->control);
670 qemu_put_be16(f, s->own_addr[0]);
671 qemu_put_be16(f, s->own_addr[1]);
672 qemu_put_be16(f, s->own_addr[2]);
673 qemu_put_be16(f, s->own_addr[3]);
674 qemu_put_be16(f, s->slave_addr);
675 qemu_put_byte(f, s->sblock);
676 qemu_put_byte(f, s->divider);
677 qemu_put_be16(f, s->times[0]);
678 qemu_put_be16(f, s->times[1]);
679 qemu_put_be16(f, s->test);
680 qemu_put_sbe32(f, s->fifostart);
681 qemu_put_sbe32(f, s->fifolen);
682 qemu_put_sbe32(f, s->fifosize);
683 qemu_put_buffer(f, s->fifo, sizeof(s->fifo));
684}
balrog02645922007-11-03 12:50:46 +0000685
Riku Voipioffdea892011-01-17 16:50:36 +0000686static int omap_i2c_load_state(QEMUFile *f, void *opaque, int version_id)
687{
688 struct omap_i2c_s *s = (struct omap_i2c_s *)opaque;
689
690 if (version_id)
691 return -EINVAL;
692
693 /* TODO: slave setup(s) */
694 s->mask = qemu_get_be16(f);
695 s->stat = qemu_get_be16(f);
696 s->we = qemu_get_be16(f);
697 s->dma = qemu_get_be16(f);
698 s->count = qemu_get_be16(f);
699 s->count_cur = qemu_get_sbe32(f);
700 s->sysc = qemu_get_be16(f);
701 s->control = qemu_get_be16(f);
702 s->own_addr[0] = qemu_get_be16(f);
703 s->own_addr[1] = qemu_get_be16(f);
704 s->own_addr[2] = qemu_get_be16(f);
705 s->own_addr[3] = qemu_get_be16(f);
706 s->slave_addr = qemu_get_be16(f);
707 s->sblock = qemu_get_byte(f);
708 s->divider = qemu_get_byte(f);
709 s->times[0] = qemu_get_be16(f);
710 s->times[1] = qemu_get_be16(f);
711 s->test = qemu_get_be16(f);
712 s->fifostart = qemu_get_sbe32(f);
713 s->fifolen = qemu_get_sbe32(f);
714 s->fifosize = qemu_get_sbe32(f);
715 qemu_get_buffer(f, s->fifo, sizeof(s->fifo));
716
717 omap_i2c_interrupts_update(s);
718
719 return 0;
720}
721
722static struct omap_i2c_s *omap_i2c_common_init(uint8_t rev, int fifosize,
723 qemu_irq irq, qemu_irq *dma)
724{
725 struct omap_i2c_s *s = (struct omap_i2c_s *)
726 qemu_mallocz(sizeof(struct omap_i2c_s));
727
728 if (fifosize > I2C_MAX_FIFO_SIZE) {
729 fprintf(stderr, "%s: maximum FIFO size is %d (tried to use %d)\n",
730 __FUNCTION__, I2C_MAX_FIFO_SIZE, fifosize);
731 exit(-1);
732 }
733 s->revision = rev;
balrog02645922007-11-03 12:50:46 +0000734 s->irq = irq;
735 s->drq[0] = dma[0];
736 s->drq[1] = dma[1];
Paul Brook02e2da42009-05-23 00:05:19 +0100737 s->bus = i2c_init_bus(NULL, "i2c");
Riku Voipioffdea892011-01-17 16:50:36 +0000738 s->fifosize = fifosize;
balrog02645922007-11-03 12:50:46 +0000739 omap_i2c_reset(s);
Riku Voipioffdea892011-01-17 16:50:36 +0000740 return s;
741}
balrog02645922007-11-03 12:50:46 +0000742
Riku Voipioffdea892011-01-17 16:50:36 +0000743struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
744 qemu_irq irq, qemu_irq *dma, omap_clk clk)
745{
746 struct omap_i2c_s *s = omap_i2c_common_init(0x11, 4, irq, dma);
balrog02645922007-11-03 12:50:46 +0000747
Riku Voipioffdea892011-01-17 16:50:36 +0000748 cpu_register_physical_memory(base, 0x800,
749 cpu_register_io_memory(omap_i2c_readfn,
750 omap_i2c_writefn, s,
751 DEVICE_NATIVE_ENDIAN));
balrog02645922007-11-03 12:50:46 +0000752 return s;
753}
754
balrog29885472008-02-10 17:02:23 +0000755struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta,
756 qemu_irq irq, qemu_irq *dma, omap_clk fclk, omap_clk iclk)
757{
Riku Voipio7f3d8482011-01-17 16:50:36 +0000758 struct omap_i2c_s *s = omap_i2c_common_init(OMAP2_GC_REV, 4, irq, dma);
balrog29885472008-02-10 17:02:23 +0000759
Riku Voipioffdea892011-01-17 16:50:36 +0000760 omap_l4_attach(ta, 0, l4_register_io_memory(omap_i2c_readfn,
761 omap_i2c_writefn, s));
762 return s;
763}
balrog29885472008-02-10 17:02:23 +0000764
Riku Voipioffdea892011-01-17 16:50:36 +0000765struct omap_i2c_s *omap3_i2c_init(struct omap_target_agent_s *ta,
Riku Voipio7f3d8482011-01-17 16:50:36 +0000766 struct omap_mpu_state_s *mpu,
Riku Voipioffdea892011-01-17 16:50:36 +0000767 qemu_irq irq, qemu_irq *dma,
768 omap_clk fclk, omap_clk iclk,
769 int fifosize)
770{
771 struct omap_i2c_s *s;
772
773 if (fifosize != 8 && fifosize != 16 && fifosize != 32 && fifosize != 64) {
774 fprintf(stderr, "%s: unsupported FIFO depth specified (%d)\n",
775 __FUNCTION__, fifosize);
776 exit(-1);
777 }
Riku Voipio7f3d8482011-01-17 16:50:36 +0000778 s = omap_i2c_common_init(cpu_is_omap3630(mpu)
779 ? OMAP3630_INTR_REV : OMAP3_INTR_REV,
780 fifosize, irq, dma);
Riku Voipioffdea892011-01-17 16:50:36 +0000781
782 omap_l4_attach(ta, 0, l4_register_io_memory(omap_i2c_readfn,
783 omap_i2c_writefn, s));
784 register_savevm("omap3_i2c", (ta->base >> 12) & 0xff, 0,
785 omap_i2c_save_state, omap_i2c_load_state, s);
balrog29885472008-02-10 17:02:23 +0000786 return s;
787}
788
balrog02645922007-11-03 12:50:46 +0000789i2c_bus *omap_i2c_bus(struct omap_i2c_s *s)
790{
791 return s->bus;
792}