blob: b0b0bb270cf511baaaa46f4dee3ad29fd9feb9b8 [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"
Riku Voipio2ddfea92011-01-17 16:50:40 +000023#include "sysbus.h"
balrog02645922007-11-03 12:50:46 +000024
Riku Voipioffdea892011-01-17 16:50:36 +000025#define I2C_MAX_FIFO_SIZE (1 << 6)
26#define I2C_FIFO_SIZE_MASK ((I2C_MAX_FIFO_SIZE) - 1)
27
Riku Voipio2ddfea92011-01-17 16:50:40 +000028typedef struct omap_i2c_bus_s {
29 i2c_bus *bus;
balrog02645922007-11-03 12:50:46 +000030 qemu_irq irq;
31 qemu_irq drq[2];
balrog02645922007-11-03 12:50:46 +000032
balrog29885472008-02-10 17:02:23 +000033 uint8_t revision;
Riku Voipio2ddfea92011-01-17 16:50:40 +000034 int fifosize;
35 char *id;
36
Riku Voipioffdea892011-01-17 16:50:36 +000037 uint16_t mask;
balrog02645922007-11-03 12:50:46 +000038 uint16_t stat;
Riku Voipioffdea892011-01-17 16:50:36 +000039 uint16_t we;
balrog02645922007-11-03 12:50:46 +000040 uint16_t dma;
41 uint16_t count;
42 int count_cur;
Riku Voipioffdea892011-01-17 16:50:36 +000043 uint16_t sysc;
balrog02645922007-11-03 12:50:46 +000044 uint16_t control;
Riku Voipioffdea892011-01-17 16:50:36 +000045 uint16_t own_addr[4];
46 uint16_t slave_addr;
47 uint8_t sblock;
balrog02645922007-11-03 12:50:46 +000048 uint8_t divider;
Riku Voipioffdea892011-01-17 16:50:36 +000049 uint16_t times[2];
balrog02645922007-11-03 12:50:46 +000050 uint16_t test;
Riku Voipioffdea892011-01-17 16:50:36 +000051 int fifostart;
52 int fifolen;
Riku Voipioffdea892011-01-17 16:50:36 +000053 uint8_t fifo[I2C_MAX_FIFO_SIZE];
Riku Voipio2ddfea92011-01-17 16:50:40 +000054} OMAPI2CBusState;
balrog02645922007-11-03 12:50:46 +000055
Riku Voipio2ddfea92011-01-17 16:50:40 +000056typedef struct omap_i2c_s {
57 SysBusDevice busdev;
Juha Riihimäki76018002011-01-17 16:50:41 +000058 int32_t mpu_model;
Riku Voipio2ddfea92011-01-17 16:50:40 +000059 int buscount;
60 OMAPI2CBusState *bus;
61} OMAPI2CState;
62
63/* I2C controller revision register values */
64#define OMAP1_INTR_REV 0x11
Riku Voipio7f3d8482011-01-17 16:50:36 +000065#define OMAP2_INTR_REV 0x34
Riku Voipio7f3d8482011-01-17 16:50:36 +000066#define OMAP3_INTR_REV 0x3c
67#define OMAP3630_INTR_REV 0x40
Riku Voipioffdea892011-01-17 16:50:36 +000068
69//#define I2C_DEBUG
70#ifdef I2C_DEBUG
Riku Voipio2ddfea92011-01-17 16:50:40 +000071#define TRACE(fmt, ...) \
72 fprintf(stderr, "%s " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
Riku Voipioffdea892011-01-17 16:50:36 +000073#else
74#define TRACE(...)
75#endif
balrog29885472008-02-10 17:02:23 +000076
Riku Voipio2ddfea92011-01-17 16:50:40 +000077static void omap_i2c_interrupts_update(OMAPI2CBusState *s)
balrog02645922007-11-03 12:50:46 +000078{
Riku Voipioffdea892011-01-17 16:50:36 +000079 TRACE("IRQ=%04x,RDRQ=%d,XDRQ=%d",
80 s->stat & s->mask,
81 ((s->dma >> 15 ) & 1) & ((s->stat >> 3) & 1),
82 ((s->dma >> 7 ) & 1 )& ((s->stat >> 4 ) & 1));
balrog02645922007-11-03 12:50:46 +000083 qemu_set_irq(s->irq, s->stat & s->mask);
Riku Voipioffdea892011-01-17 16:50:36 +000084 if ((s->dma >> 15) & 1) /* RDMA_EN */
85 qemu_set_irq(s->drq[0], (s->stat >> 3) & 1); /* RRDY */
86 if ((s->dma >> 7) & 1) /* XDMA_EN */
87 qemu_set_irq(s->drq[1], (s->stat >> 4) & 1); /* XRDY */
balrog02645922007-11-03 12:50:46 +000088}
89
Riku Voipio2ddfea92011-01-17 16:50:40 +000090static void omap_i2c_fifo_run(OMAPI2CBusState *s)
balrog02645922007-11-03 12:50:46 +000091{
Riku Voipioffdea892011-01-17 16:50:36 +000092 int ack = 1, i;
balrog02645922007-11-03 12:50:46 +000093
94 if (!i2c_bus_busy(s->bus))
95 return;
96
97 if ((s->control >> 2) & 1) { /* RM */
98 if ((s->control >> 1) & 1) { /* STP */
99 i2c_end_transfer(s->bus);
100 s->control &= ~(1 << 1); /* STP */
101 s->count_cur = s->count;
Riku Voipioffdea892011-01-17 16:50:36 +0000102 s->fifolen = 0;
balrog02645922007-11-03 12:50:46 +0000103 } else if ((s->control >> 9) & 1) { /* TRX */
Riku Voipioffdea892011-01-17 16:50:36 +0000104 while (ack && s->fifolen) {
105 ack = (i2c_send(s->bus, s->fifo[s->fifostart++]) >= 0);
106 s->fifostart &= I2C_FIFO_SIZE_MASK;
107 s->fifolen--;
108 }
109 s->fifolen = 0;
balrog02645922007-11-03 12:50:46 +0000110 s->stat |= 1 << 4; /* XRDY */
111 } else {
Riku Voipioffdea892011-01-17 16:50:36 +0000112 for (i = 0; i < 4; i++)
113 s->fifo[(s->fifostart + i) & I2C_FIFO_SIZE_MASK] =
114 i2c_recv(s->bus);
115 s->fifolen = 4;
balrog02645922007-11-03 12:50:46 +0000116 s->stat |= 1 << 3; /* RRDY */
117 }
118 } else {
Riku Voipioffdea892011-01-17 16:50:36 +0000119 if ((s->control >> 9) & 1) { /* TRX */
120 TRACE("master transmit, count_cur=%d, fifolen=%d",
121 s->count_cur, s->fifolen);
122 for (; ack && s->count_cur && s->fifolen; s->count_cur--) {
123 ack = (i2c_send(s->bus, s->fifo[s->fifostart++]) >= 0);
124 s->fifostart &= I2C_FIFO_SIZE_MASK;
125 s->fifolen--;
balrog02645922007-11-03 12:50:46 +0000126 }
Riku Voipioffdea892011-01-17 16:50:36 +0000127 s->stat &= ~0x4410; /* XDR | XUDF | XRDY */
128 if (ack && s->count_cur) { /* send more? */
129 /* we know that FIFO is empty */
130 if (s->revision < OMAP3_INTR_REV)
131 s->stat |= 1 << 4; /* XRDY */
132 else {
133 if (s->count_cur > (s->dma & 0x3f)) /* XTRSH */
134 s->stat |= 1 << 4; /* XRDY */
135 else
136 s->stat |= 1 << 14; /* XDR */
137 }
balrog02645922007-11-03 12:50:46 +0000138 }
Riku Voipioffdea892011-01-17 16:50:36 +0000139 if (!s->count_cur) /* everything sent? */
140 s->stat |= 1 << 2; /* ARDY */
141 } else { /* !TRX */
142 TRACE("master receive");
143 for (; s->count_cur && s->fifolen < s->fifosize; s->count_cur--) {
144 i = i2c_recv(s->bus);
145 if (i < 0) break; /* stop receiving if nothing to receive */
146 s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
147 (uint8_t)(i & 0xff);
148 TRACE("received fifo[%02x] = %02x", s->fifolen - 1,
Riku Voipio2ddfea92011-01-17 16:50:40 +0000149 s->fifo[(s->fifostart + s->fifolen - 1)
150 & I2C_FIFO_SIZE_MASK]);
balrog02645922007-11-03 12:50:46 +0000151 }
Riku Voipioffdea892011-01-17 16:50:36 +0000152 s->stat &= ~((1 << 3) | (1 << 13)); /* RRDY | RDR */
153 if (s->fifolen) {
154 if (s->revision < OMAP3_INTR_REV)
155 s->stat |= 1 << 3; /* RRDY */
156 else {
157 if (s->fifolen > ((s->dma >> 8) & 0x3f)) /* RTRSH */
158 s->stat |= 1 << 3; /* RRDY */
159 else
160 s->stat |= 1 << 13; /* RDR */
161 }
162 } else if (!s->count_cur && (s->control & 2)) /* STP */
163 s->stat |= 1 << 2; /* ARDY */
balrog02645922007-11-03 12:50:46 +0000164 }
165 if (!s->count_cur) {
Riku Voipioffdea892011-01-17 16:50:36 +0000166 TRACE("no more data to transmit/receive");
Matt Waddel57ff4f52011-01-17 16:50:36 +0000167 i2c_end_transfer(s->bus);
Riku Voipioffdea892011-01-17 16:50:36 +0000168 if ((s->control >> 1) & 1) { /* STP */
Riku Voipioffdea892011-01-17 16:50:36 +0000169 s->control &= ~0x0602; /* MST | TRX | STP */
balrog02645922007-11-03 12:50:46 +0000170 s->count_cur = s->count;
Riku Voipioffdea892011-01-17 16:50:36 +0000171 }
balrog02645922007-11-03 12:50:46 +0000172 }
173 }
174
Riku Voipioffdea892011-01-17 16:50:36 +0000175 s->stat |= (!ack) << 1; /* NACK */
balrog02645922007-11-03 12:50:46 +0000176 if (!ack)
Riku Voipioffdea892011-01-17 16:50:36 +0000177 s->control &= ~(1 << 1); /* STP */
178 TRACE("finished, STAT = %04x, CNT = %d", s->stat, s->count_cur);
balrog02645922007-11-03 12:50:46 +0000179}
180
Riku Voipio2ddfea92011-01-17 16:50:40 +0000181static void omap_i2c_bus_reset(OMAPI2CBusState *s)
balrog02645922007-11-03 12:50:46 +0000182{
183 s->mask = 0;
184 s->stat = 0;
185 s->dma = 0;
186 s->count = 0;
187 s->count_cur = 0;
Riku Voipioffdea892011-01-17 16:50:36 +0000188 s->we = 0;
189 s->sysc = 0;
190 s->fifolen = 0;
191 s->fifostart = 0;
balrog02645922007-11-03 12:50:46 +0000192 s->control = 0;
Riku Voipioffdea892011-01-17 16:50:36 +0000193 s->own_addr[0] = 0;
194 s->own_addr[1] = 0;
195 s->own_addr[2] = 0;
196 s->own_addr[3] = 0;
197 s->slave_addr = 0;
198 s->sblock = 0;
balrog02645922007-11-03 12:50:46 +0000199 s->divider = 0;
200 s->times[0] = 0;
201 s->times[1] = 0;
202 s->test = 0;
Riku Voipioffdea892011-01-17 16:50:36 +0000203
204 i2c_end_transfer(s->bus);
balrog02645922007-11-03 12:50:46 +0000205}
206
Anthony Liguoric227f092009-10-01 16:12:16 -0500207static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr)
balrog02645922007-11-03 12:50:46 +0000208{
Riku Voipio2ddfea92011-01-17 16:50:40 +0000209 OMAPI2CBusState *s = opaque;
balrogcf965d22007-11-04 12:19:22 +0000210 int offset = addr & OMAP_MPUI_REG_MASK;
balrog02645922007-11-03 12:50:46 +0000211 uint16_t ret;
212
213 switch (offset) {
Riku Voipioffdea892011-01-17 16:50:36 +0000214 case 0x00: /* I2C_REV */
215 TRACE("REV returns %04x", s->revision);
216 return s->revision;
217 case 0x04: /* I2C_IE */
218 TRACE("IE returns %04x", s->mask);
219 return s->mask;
220 case 0x08: /* I2C_STAT */
Riku Voipiod356bd12011-01-17 16:50:36 +0000221 ret = s->stat | (i2c_bus_busy(s->bus) << 12 );
Riku Voipio2ddfea92011-01-17 16:50:40 +0000222 if (s->revision >= OMAP3_INTR_REV
223 && (s->stat & 0x4010)) { /* XRDY or XDR */
Riku Voipiod356bd12011-01-17 16:50:36 +0000224 s->stat |= 1 << 10; /* XUDF as required by errata 1.153 */
Riku Voipio2ddfea92011-01-17 16:50:40 +0000225 }
Riku Voipiod356bd12011-01-17 16:50:36 +0000226 TRACE("STAT returns %04x", ret);
227 return ret;
Riku Voipioffdea892011-01-17 16:50:36 +0000228 case 0x0c: /* I2C_IV / I2C_WE */
229 if (s->revision >= OMAP3_INTR_REV)
230 return s->we;
231 if (s->revision >= OMAP2_INTR_REV)
232 break;
233 ret = ffs(s->stat & s->mask);
234 if (ret)
235 s->stat ^= 1 << (ret - 1);
236 omap_i2c_interrupts_update(s);
237 return ret;
238 case 0x10: /* I2C_SYSS */
239 return (s->control >> 15) & 1; /* reset completed == I2C_EN */
240 case 0x14: /* I2C_BUF */
241 TRACE("BUF returns %04x", s->dma);
242 return s->dma;
243 case 0x18: /* I2C_CNT */
244 TRACE("CNT returns %04x", s->count_cur);
245 return s->count_cur; /* DCOUNT */
246 case 0x1c: /* I2C_DATA */
247 ret = 0;
248 if (s->fifolen) {
249 if (s->revision < OMAP3_INTR_REV) {
250 if (s->control & (1 << 14)) /* BE */
Riku Voipio2ddfea92011-01-17 16:50:40 +0000251 ret = (((uint16_t)s->fifo[s->fifostart]) << 8)
Riku Voipioffdea892011-01-17 16:50:36 +0000252 | s->fifo[(s->fifostart + 1) & I2C_FIFO_SIZE_MASK];
253 else
Riku Voipio2ddfea92011-01-17 16:50:40 +0000254 ret = (((uint16_t)s->fifo[(s->fifostart + 1)
255 & I2C_FIFO_SIZE_MASK]) << 8)
Riku Voipioffdea892011-01-17 16:50:36 +0000256 | s->fifo[s->fifostart];
257 s->fifostart = (s->fifostart + 2) & I2C_FIFO_SIZE_MASK;
258 if (s->fifolen == 1) {
259 s->stat |= 1 << 15; /* SBD */
260 s->fifolen = 0;
261 } else
262 s->fifolen -= 2;
263 if (!s->fifolen) {
264 s->stat &= ~(1 << 3); /* RRDY */
265 s->stat |= 1 << 2; /* ARDY */
266 }
267 } else {
268 s->stat &= ~(1 << 7); /* AERR */
269 ret = s->fifo[s->fifostart++];
270 s->fifostart &= I2C_FIFO_SIZE_MASK;
271 if (--s->fifolen) {
272 if (s->fifolen <= ((s->dma >> 8) & 0x3f)) {
273 s->stat &= ~(1 << 3); /* RRDY */
274 s->stat |= 1 << 13; /* RDR */
275 }
276 } else {
277 s->stat &= ~((1 << 3) | (1 << 13)); /* RRDY | RDR */
278 s->stat |= 1 << 2; /* ARDY */
279 }
280 }
281 s->stat &= ~(1 << 11); /* ROVR */
282 } else if (s->revision >= OMAP3_INTR_REV)
283 s->stat |= (1 << 7); /* AERR */
284 TRACE("DATA returns %04x", ret);
285 omap_i2c_fifo_run(s);
286 omap_i2c_interrupts_update(s);
287 return ret;
288 case 0x20: /* I2C_SYSC */
289 TRACE("SYSC returns %04x", s->sysc);
290 return s->sysc;
291 case 0x24: /* I2C_CON */
292 TRACE("CON returns %04x", s->control);
293 return s->control;
294 case 0x28: /* I2C_OA / I2C_OA0 */
295 return s->own_addr[0];
296 case 0x2c: /* I2C_SA */
297 return s->slave_addr;
298 case 0x30: /* I2C_PSC */
299 return s->divider;
300 case 0x34: /* I2C_SCLL */
301 return s->times[0];
302 case 0x38: /* I2C_SCLH */
303 return s->times[1];
304 case 0x3c: /* I2C_SYSTEST */
305 if (s->test & (1 << 15)) { /* ST_EN */
306 s->test ^= 0xa;
307 return s->test;
balrog02645922007-11-03 12:50:46 +0000308 }
balrog02645922007-11-03 12:50:46 +0000309 return s->test & ~0x300f;
Riku Voipioffdea892011-01-17 16:50:36 +0000310 case 0x40: /* I2C_BUFSTAT */
311 if (s->revision >= OMAP3_INTR_REV) {
312 switch (s->fifosize) {
313 case 8: ret = 0x0000; break;
314 case 16: ret = 0x4000; break;
315 case 32: ret = 0x8000; break;
316 case 64: ret = 0xc000; break;
317 default: ret = 0x0000; break;
318 }
319 ret |= ((s->fifolen) & 0x3f) << 8; /* RXSTAT */
320 ret |= (s->count_cur) & 0x3f; /* TXSTAT */
321 TRACE("BUFSTAT returns %04x", ret);
322 return ret;
323 }
324 break;
325 case 0x44: /* I2C_OA1 */
326 case 0x48: /* I2C_OA2 */
327 case 0x4c: /* I2C_OA3 */
328 if (s->revision >= OMAP3_INTR_REV)
329 return s->own_addr[(addr >> 2) & 3];
330 break;
331 case 0x50: /* I2C_ACTOA */
332 if (s->revision >= OMAP3_INTR_REV)
333 return 0; /* TODO: determine accessed slave own address */
334 break;
335 case 0x54: /* I2C_SBLOCK */
336 if (s->revision >= OMAP3_INTR_REV)
337 return s->sblock;
338 break;
339 default:
340 break;
balrog02645922007-11-03 12:50:46 +0000341 }
342
343 OMAP_BAD_REG(addr);
344 return 0;
345}
346
Matt Waddel715cc6d2011-01-17 16:50:36 +0000347static uint32_t omap_i2c_readb(void *opaque, target_phys_addr_t addr)
348{
Riku Voipio2ddfea92011-01-17 16:50:40 +0000349 OMAPI2CBusState *s = opaque;
Matt Waddel715cc6d2011-01-17 16:50:36 +0000350 int offset = addr & OMAP_MPUI_REG_MASK;
351 uint8_t ret;
352
353 switch (offset) {
354 case 0x1c: /* I2C_DATA */
355 ret = 0;
356 if (s->fifolen) {
357 if (s->revision < OMAP3_INTR_REV) {
358 if (s->control & (1 << 14)) /* BE */
359 ret = (((uint8_t)s->fifo[s->fifostart]) << 8)
360 | s->fifo[(s->fifostart + 1) & I2C_FIFO_SIZE_MASK];
361 else
Riku Voipio2ddfea92011-01-17 16:50:40 +0000362 ret = (((uint8_t)s->fifo[(s->fifostart + 1)
363 & I2C_FIFO_SIZE_MASK]) << 8)
Matt Waddel715cc6d2011-01-17 16:50:36 +0000364 | s->fifo[s->fifostart];
365 s->fifostart = (s->fifostart + 2) & I2C_FIFO_SIZE_MASK;
366 if (s->fifolen == 1) {
367 s->stat |= 1 << 15; /* SBD */
368 s->fifolen = 0;
369 } else
370 s->fifolen -= 2;
371 if (!s->fifolen) {
372 s->stat &= ~(1 << 3); /* RRDY */
373 s->stat |= 1 << 2; /* ARDY */
374 }
375 } else {
376 s->stat &= ~(1 << 7); /* AERR */
377 ret = (uint8_t)s->fifo[s->fifostart++];
378 s->fifostart &= I2C_FIFO_SIZE_MASK;
379 if (--s->fifolen) {
380 if (s->fifolen <= ((s->dma >> 8) & 0x3f)) {
381 s->stat &= ~(1 << 3); /* RRDY */
382 s->stat |= 1 << 13; /* RDR */
383 }
384 } else {
385 s->stat &= ~((1 << 3) | (1 << 13)); /* RRDY | RDR */
386 s->stat |= 1 << 2; /* ARDY */
387 }
388 }
389 s->stat &= ~(1 << 11); /* ROVR */
390 } else if (s->revision >= OMAP3_INTR_REV)
391 s->stat |= (1 << 7); /* AERR */
392 TRACE("DATA returns %04x", ret);
393 omap_i2c_fifo_run(s);
394 omap_i2c_interrupts_update(s);
395 return ret;
396 default:
397 break;
398 }
399
400 OMAP_BAD_REG(addr);
401 return 0;
402}
403
Anthony Liguoric227f092009-10-01 16:12:16 -0500404static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
Riku Voipio2ddfea92011-01-17 16:50:40 +0000405 uint32_t value)
balrog02645922007-11-03 12:50:46 +0000406{
Riku Voipio2ddfea92011-01-17 16:50:40 +0000407 OMAPI2CBusState *s = opaque;
balrogcf965d22007-11-04 12:19:22 +0000408 int offset = addr & OMAP_MPUI_REG_MASK;
balrog02645922007-11-03 12:50:46 +0000409 int nack;
410
411 switch (offset) {
Riku Voipioffdea892011-01-17 16:50:36 +0000412 case 0x00: /* I2C_REV */
413 case 0x10: /* I2C_SYSS */
414 case 0x40: /* I2C_BUFSTAT */
415 case 0x50: /* I2C_ACTOA */
balrog29885472008-02-10 17:02:23 +0000416 OMAP_RO_REG(addr);
balrog02645922007-11-03 12:50:46 +0000417 break;
Riku Voipioffdea892011-01-17 16:50:36 +0000418 case 0x04: /* I2C_IE */
419 TRACE("IE = %04x", value);
Riku Voipio2ddfea92011-01-17 16:50:40 +0000420 if (s->revision < OMAP2_INTR_REV) {
Riku Voipio7f3d8482011-01-17 16:50:36 +0000421 s->mask = value & 0x1f;
422 } else if (s->revision < OMAP3_INTR_REV) {
423 s->mask = value & 0x3f;
424 } else if (s->revision == OMAP3_INTR_REV) {
Riku Voipioffdea892011-01-17 16:50:36 +0000425 s->mask = value & 0x63ff;
Riku Voipio7f3d8482011-01-17 16:50:36 +0000426 } else { /* omap3630 */
427 s->mask = value & 0x6fff;
428 }
balrog02645922007-11-03 12:50:46 +0000429 omap_i2c_interrupts_update(s);
Riku Voipioffdea892011-01-17 16:50:36 +0000430 break;
431 case 0x08: /* I2C_STAT */
Riku Voipio7f3d8482011-01-17 16:50:36 +0000432 if (s->revision < OMAP2_INTR_REV) {
Riku Voipioffdea892011-01-17 16:50:36 +0000433 OMAP_RO_REG(addr);
Riku Voipio7f3d8482011-01-17 16:50:36 +0000434 } else {
Riku Voipioffdea892011-01-17 16:50:36 +0000435 TRACE("STAT = %04x", value);
436 /* RRDY and XRDY are reset by hardware. (in all versions???) */
Riku Voipio7f3d8482011-01-17 16:50:36 +0000437 if (s->revision < OMAP3_INTR_REV) {
438 value &= 0x27;
439 } else if (s->revision == OMAP3_INTR_REV) {
440 value &= 0x63e7;
441 } else { /* omap3630 */
442 value &= 0x6ee7;
443 }
444 s->stat &= ~value;
balrog29885472008-02-10 17:02:23 +0000445 omap_i2c_interrupts_update(s);
446 }
Riku Voipioffdea892011-01-17 16:50:36 +0000447 break;
448 case 0x0c: /* I2C_IV / I2C_WE */
Riku Voipio7f3d8482011-01-17 16:50:36 +0000449 if (s->revision < OMAP3_INTR_REV) {
Riku Voipioffdea892011-01-17 16:50:36 +0000450 OMAP_RO_REG(addr);
Riku Voipio7f3d8482011-01-17 16:50:36 +0000451 } else if (s->revision == OMAP3_INTR_REV) {
Riku Voipioffdea892011-01-17 16:50:36 +0000452 s->we = value & 0x636f;
Riku Voipio7f3d8482011-01-17 16:50:36 +0000453 } else { /* omap3630 */
454 s->we = value & 0x6f6f;
455 }
Riku Voipioffdea892011-01-17 16:50:36 +0000456 break;
457 case 0x14: /* I2C_BUF */
458 TRACE("BUF = %04x", value);
459 if (s->revision < OMAP3_INTR_REV)
460 s->dma = value & 0x8080;
461 else {
462 s->dma = value & 0xbfbf;
463 if ((value & (1 << 14)) /* RXFIFO_CLR */
464 || (value & (1 << 6))) /* TXFIFO_CLR */
465 s->fifolen = 0;
466 }
467 if (value & (1 << 15)) /* RDMA_EN */
468 s->mask &= ~(1 << 3); /* RRDY_IE */
469 if (value & (1 << 7)) /* XDMA_EN */
470 s->mask &= ~(1 << 4); /* XRDY_IE */
471 break;
472 case 0x18: /* I2C_CNT */
473 TRACE("CNT = %04x", value);
474 s->count = value; /* DCOUNT */
475 break;
476 case 0x1c: /* I2C_DATA */
477 TRACE("DATA = %04x", value);
478 if (s->revision < OMAP3_INTR_REV) {
479 if (s->fifolen > 2) {
480 /* XXX: remote access (qualifier) error - what's that? */
481 break;
482 }
483 if (s->control & (1 << 14)) { /* BE */
Riku Voipio2ddfea92011-01-17 16:50:40 +0000484 s->fifo[(s->fifostart + s->fifolen++)
485 & I2C_FIFO_SIZE_MASK] =
Riku Voipioffdea892011-01-17 16:50:36 +0000486 (uint8_t)((value >> 8) & 0xff);
Riku Voipio2ddfea92011-01-17 16:50:40 +0000487 s->fifo[(s->fifostart + s->fifolen++)
488 & I2C_FIFO_SIZE_MASK] =
Riku Voipioffdea892011-01-17 16:50:36 +0000489 (uint8_t)(value & 0xff);
490 } else {
Riku Voipio2ddfea92011-01-17 16:50:40 +0000491 s->fifo[(s->fifostart + s->fifolen++)
492 & I2C_FIFO_SIZE_MASK] =
Riku Voipioffdea892011-01-17 16:50:36 +0000493 (uint8_t)(value & 0xff);
Riku Voipio2ddfea92011-01-17 16:50:40 +0000494 s->fifo[(s->fifostart + s->fifolen++)
495 & I2C_FIFO_SIZE_MASK] =
Riku Voipioffdea892011-01-17 16:50:36 +0000496 (uint8_t)((value >> 8) & 0xff);
497 }
498 } else {
499 if (s->fifolen < s->fifosize) {
500 s->stat &= ~(1 << 7); /* AERR */
Riku Voipio2ddfea92011-01-17 16:50:40 +0000501 s->fifo[(s->fifostart + s->fifolen++)
502 & I2C_FIFO_SIZE_MASK] =
Riku Voipioffdea892011-01-17 16:50:36 +0000503 (uint8_t)(value & 0xff);
504 } else
505 s->stat |= (1 << 7); /* AERR */
506 }
507 s->stat &= ~(1 << 10); /* XUDF */
508 omap_i2c_fifo_run(s);
509 omap_i2c_interrupts_update(s);
510 break;
511 case 0x20: /* I2C_SYSC */
512 if (s->revision < OMAP2_INTR_REV) {
513 OMAP_BAD_REG(addr);
514 break;
515 }
516 TRACE("SYSC = %04x", value);
517 if (value & 2)
Riku Voipio2ddfea92011-01-17 16:50:40 +0000518 omap_i2c_bus_reset(s);
Riku Voipioffdea892011-01-17 16:50:36 +0000519 else if (s->revision >= OMAP3_INTR_REV)
520 s->sysc = value & 0x031d;
521 break;
522 case 0x24: /* I2C_CON */
523 TRACE("CON = %04x", value);
Riku Voipio2ddfea92011-01-17 16:50:40 +0000524 s->control = value & (s->revision < OMAP3_INTR_REV
525 ? 0xcf87 : 0xbff3);
Riku Voipioffdea892011-01-17 16:50:36 +0000526 if (~value & (1 << 15)) { /* I2C_EN */
527 if (s->revision < OMAP2_INTR_REV)
Riku Voipio2ddfea92011-01-17 16:50:40 +0000528 omap_i2c_bus_reset(s);
Riku Voipioffdea892011-01-17 16:50:36 +0000529 break;
530 }
Riku Voipio2ddfea92011-01-17 16:50:40 +0000531 if (s->revision >= OMAP3_INTR_REV &&
532 ((value >> 12) & 3) > 1) { /* OPMODE */
Riku Voipioffdea892011-01-17 16:50:36 +0000533 fprintf(stderr,
534 "%s: only FS and HS modes are supported\n",
535 __FUNCTION__);
536 break;
537 }
538 if ((value & (1 << 10))) { /* MST */
539 if (value & 1) { /* STT */
540 nack = !!i2c_start_transfer(s->bus, s->slave_addr, /*SA*/
541 (~value >> 9) & 1); /*TRX*/
542 s->stat |= nack << 1; /* NACK */
543 s->control &= ~(1 << 0); /* STT */
544 s->fifolen = 0;
545 if (nack)
546 s->control &= ~(1 << 1); /* STP */
547 else {
548 s->count_cur = s->count;
549 omap_i2c_fifo_run(s);
550 }
551 omap_i2c_interrupts_update(s);
552 } else if (value & 2) { /* STP, but not STT */
553 i2c_end_transfer(s->bus);
554 s->control &= ~0x0602; /* MST | TRX | STP */
555 s->count_cur = s->count;
556 }
557 }
558 break;
559 case 0x28: /* I2C_OA / I2C_OA0 */
560 TRACE("OA0 = %04x", value);
561 s->own_addr[0] = value & (s->revision < OMAP3_INTR_REV
562 ? 0x3ff : 0xe3ff);
563 /*i2c_set_slave_address(&s->slave[0],
564 value & (s->revision >= OMAP3_INTR_REV
565 && (s->control & 0x80)
566 ? 0x3ff: 0x7f));*/
567 break;
568 case 0x2c: /* I2C_SA */
569 TRACE("SA = %04x", value);
570 s->slave_addr = value & 0x3ff;
571 break;
572 case 0x30: /* I2C_PSC */
573 s->divider = value;
574 break;
575 case 0x34: /* I2C_SCLL */
576 s->times[0] = value & (s->revision < OMAP3_INTR_REV
577 ? 0xff : 0xffff);
578 break;
579 case 0x38: /* I2C_SCLH */
580 s->times[1] = value & (s->revision < OMAP3_INTR_REV
581 ? 0xff : 0xffff);
582 break;
583 case 0x3c: /* I2C_SYSTEST */
Riku Voipio7f3d8482011-01-17 16:50:36 +0000584 if (s->revision < OMAP3_INTR_REV) {
585 value &= 0xf805;
586 } else if (s->revision == OMAP3_INTR_REV) {
587 value &= 0xf815;
588 } else { /* omap3630 */
589 value = (value & 0xf835) | 0x1c00;
590 }
Riku Voipioffdea892011-01-17 16:50:36 +0000591 if ((value & (1 << 15))) { /* ST_EN */
592 fprintf(stderr, "%s: System Test not supported\n",
593 __FUNCTION__);
594 s->test = (s->test & 0x0a) | value;
Riku Voipio7f3d8482011-01-17 16:50:36 +0000595 } else {
596 value &= ~0xff;
597 s->test = (s->test & 0x1f) | value;
598 }
599 if (value & (1 << 11)) { /* SBB */
Riku Voipioffdea892011-01-17 16:50:36 +0000600 if (s->revision >= OMAP2_INTR_REV) {
601 s->stat |= 0x3f;
Riku Voipio7f3d8482011-01-17 16:50:36 +0000602 if (s->revision >= OMAP3_INTR_REV) {
603 s->stat |= 0x6300;
604 if (s->revision > OMAP3_INTR_REV) {
605 s->stat |= 0x0c00;
606 }
607 }
Riku Voipioffdea892011-01-17 16:50:36 +0000608 omap_i2c_interrupts_update(s);
609 }
Riku Voipio7f3d8482011-01-17 16:50:36 +0000610 }
Riku Voipioffdea892011-01-17 16:50:36 +0000611 break;
612 case 0x44: /* I2C_OA1 */
613 case 0x48: /* I2C_OA2 */
614 case 0x4c: /* I2C_OA3 */
Riku Voipio7f3d8482011-01-17 16:50:36 +0000615 if (s->revision < OMAP3_INTR_REV) {
Riku Voipioffdea892011-01-17 16:50:36 +0000616 OMAP_BAD_REG(addr);
Riku Voipio7f3d8482011-01-17 16:50:36 +0000617 } else {
Riku Voipioffdea892011-01-17 16:50:36 +0000618 addr = (addr >> 2) & 3;
619 TRACE("OA%d = %04x", (int)addr, value);
620 s->own_addr[addr] = value & 0x3ff;
621 /*i2c_set_slave_address(&s->slave[addr],
622 value & ((s->control & (0x80 >> addr))
623 ? 0x3ff: 0x7f));*/
624 }
625 break;
626 case 0x54: /* I2C_SBLOCK */
627 if (s->revision < OMAP3_INTR_REV)
628 OMAP_BAD_REG(addr);
629 else {
630 s->sblock = value & 0x0f;
631 }
632 break;
633 default:
634 OMAP_BAD_REG(addr);
635 break;
balrog02645922007-11-03 12:50:46 +0000636 }
637}
638
Anthony Liguoric227f092009-10-01 16:12:16 -0500639static void omap_i2c_writeb(void *opaque, target_phys_addr_t addr,
Riku Voipio2ddfea92011-01-17 16:50:40 +0000640 uint32_t value)
balrog29885472008-02-10 17:02:23 +0000641{
Riku Voipio2ddfea92011-01-17 16:50:40 +0000642 OMAPI2CBusState *s = opaque;
balrog29885472008-02-10 17:02:23 +0000643 int offset = addr & OMAP_MPUI_REG_MASK;
644
645 switch (offset) {
Riku Voipioffdea892011-01-17 16:50:36 +0000646 case 0x1c: /* I2C_DATA */
647 TRACE("DATA = %02x", value);
648 if (s->revision < OMAP3_INTR_REV && s->fifolen > 2) {
649 /* XXX: remote access (qualifier) error - what's that? */
650 break;
651 }
652 if (s->fifolen < s->fifosize) {
653 s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
654 (uint8_t)(value & 0xff);
655 if (s->revision >= OMAP3_INTR_REV)
656 s->stat &= ~(1 << 7); /* AERR */
657 s->stat &= ~(1 << 10); /* XUDF */
658 omap_i2c_fifo_run(s);
659 } else if (s->revision >= OMAP3_INTR_REV)
660 s->stat |= (1 << 7); /* AERR */
661 omap_i2c_interrupts_update(s);
balrog29885472008-02-10 17:02:23 +0000662 break;
Riku Voipioffdea892011-01-17 16:50:36 +0000663 default:
664 OMAP_BAD_REG(addr);
665 break;
balrog29885472008-02-10 17:02:23 +0000666 }
667}
668
Blue Swirld60efc62009-08-25 18:29:31 +0000669static CPUReadMemoryFunc * const omap_i2c_readfn[] = {
Matt Waddel715cc6d2011-01-17 16:50:36 +0000670 omap_i2c_readb,
balrog02645922007-11-03 12:50:46 +0000671 omap_i2c_read,
Peter Maydellabbd52c2011-08-12 11:45:26 +0000672 omap_i2c_read,
balrog02645922007-11-03 12:50:46 +0000673};
674
Blue Swirld60efc62009-08-25 18:29:31 +0000675static CPUWriteMemoryFunc * const omap_i2c_writefn[] = {
balrog29885472008-02-10 17:02:23 +0000676 omap_i2c_writeb, /* Only the last fifo write can be 8 bit. */
balrog02645922007-11-03 12:50:46 +0000677 omap_i2c_write,
Peter Maydellabbd52c2011-08-12 11:45:26 +0000678 omap_i2c_write,
balrog02645922007-11-03 12:50:46 +0000679};
680
Riku Voipio2ddfea92011-01-17 16:50:40 +0000681static int omap_i2c_bus_post_load(void *opaque, int version_id)
balrog02645922007-11-03 12:50:46 +0000682{
Riku Voipio2ddfea92011-01-17 16:50:40 +0000683 OMAPI2CBusState *s = opaque;
Riku Voipioffdea892011-01-17 16:50:36 +0000684 omap_i2c_interrupts_update(s);
Riku Voipioffdea892011-01-17 16:50:36 +0000685 return 0;
686}
687
Riku Voipio2ddfea92011-01-17 16:50:40 +0000688static const VMStateDescription vmstate_omap_i2c_bus = {
689 .name = "omap_i2c",
690 .version_id = 1,
691 .minimum_version_id = 1,
692 .minimum_version_id_old = 1,
693 .post_load = omap_i2c_bus_post_load,
694 .fields = (VMStateField[]) {
695 VMSTATE_UINT16(mask, OMAPI2CBusState),
696 VMSTATE_UINT16(stat, OMAPI2CBusState),
697 VMSTATE_UINT16(we, OMAPI2CBusState),
698 VMSTATE_UINT16(dma, OMAPI2CBusState),
699 VMSTATE_UINT16(count, OMAPI2CBusState),
700 VMSTATE_INT32(count_cur, OMAPI2CBusState),
701 VMSTATE_UINT16(sysc, OMAPI2CBusState),
702 VMSTATE_UINT16(control, OMAPI2CBusState),
703 VMSTATE_UINT16_ARRAY(own_addr, OMAPI2CBusState, 4),
704 VMSTATE_UINT16(slave_addr, OMAPI2CBusState),
705 VMSTATE_UINT8(sblock, OMAPI2CBusState),
706 VMSTATE_UINT8(divider, OMAPI2CBusState),
707 VMSTATE_UINT16_ARRAY(times, OMAPI2CBusState, 2),
708 VMSTATE_UINT16(test, OMAPI2CBusState),
709 VMSTATE_INT32(fifostart, OMAPI2CBusState),
710 VMSTATE_INT32(fifolen, OMAPI2CBusState),
711 VMSTATE_INT32(fifosize, OMAPI2CBusState),
712 VMSTATE_UINT8_ARRAY(fifo, OMAPI2CBusState, I2C_MAX_FIFO_SIZE),
713 VMSTATE_END_OF_LIST()
Riku Voipioffdea892011-01-17 16:50:36 +0000714 }
Riku Voipio2ddfea92011-01-17 16:50:40 +0000715};
balrog02645922007-11-03 12:50:46 +0000716
Riku Voipio2ddfea92011-01-17 16:50:40 +0000717static int omap_i2c_init(SysBusDevice *dev)
Riku Voipioffdea892011-01-17 16:50:36 +0000718{
Riku Voipio2ddfea92011-01-17 16:50:40 +0000719 int i;
Juha Riihimäki76018002011-01-17 16:50:41 +0000720 uint8_t rev;
Riku Voipio2ddfea92011-01-17 16:50:40 +0000721 OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState, dev);
Juha Riihimäki76018002011-01-17 16:50:41 +0000722 if (s->mpu_model < omap2410) {
723 rev = OMAP1_INTR_REV;
Riku Voipio2ddfea92011-01-17 16:50:40 +0000724 s->buscount = 1;
Juha Riihimäki76018002011-01-17 16:50:41 +0000725 } else if (s->mpu_model < omap3430) {
726 rev = OMAP2_INTR_REV;
Riku Voipio2ddfea92011-01-17 16:50:40 +0000727 s->buscount = 2;
728 } else {
729 s->buscount = 3;
Juha Riihimäki76018002011-01-17 16:50:41 +0000730 if (s->mpu_model < omap3630) {
731 rev = OMAP3_INTR_REV;
732 } else {
733 rev = OMAP3630_INTR_REV;
734 }
Riku Voipioffdea892011-01-17 16:50:36 +0000735 }
Peter Maydelld0c64242011-08-25 19:01:45 +0000736 s->bus = g_new0(OMAPI2CBusState, s->buscount);
Riku Voipio2ddfea92011-01-17 16:50:40 +0000737 for (i = 0; i < s->buscount; i++) {
Juha Riihimäki76018002011-01-17 16:50:41 +0000738 s->bus[i].revision = rev;
739 if (rev < OMAP3_INTR_REV) {
Riku Voipio2ddfea92011-01-17 16:50:40 +0000740 s->bus[i].fifosize = 4;
741 } else {
742 s->bus[i].fifosize = (i < 2) ? 8 : 64;
743 }
744 sysbus_init_irq(dev, &s->bus[i].irq);
745 sysbus_init_irq(dev, &s->bus[i].drq[0]);
746 sysbus_init_irq(dev, &s->bus[i].drq[1]);
Juha Riihimäki76018002011-01-17 16:50:41 +0000747 sysbus_init_mmio(dev, (rev < OMAP2_INTR_REV) ? 0x800 : 0x1000,
Riku Voipio2ddfea92011-01-17 16:50:40 +0000748 cpu_register_io_memory(omap_i2c_readfn,
749 omap_i2c_writefn, &s->bus[i],
750 DEVICE_NATIVE_ENDIAN));
751 s->bus[i].bus = i2c_init_bus(&dev->qdev, NULL);
752 vmstate_register(&dev->qdev, i, &vmstate_omap_i2c_bus, &s->bus[i]);
753 }
754 return 0;
balrog29885472008-02-10 17:02:23 +0000755}
756
Riku Voipio2ddfea92011-01-17 16:50:40 +0000757static void omap_i2c_reset(DeviceState *dev)
balrog02645922007-11-03 12:50:46 +0000758{
Riku Voipio2ddfea92011-01-17 16:50:40 +0000759 OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState, sysbus_from_qdev(dev));
760 int i;
761 for (i = 0; i < s->buscount; i++) {
762 omap_i2c_bus_reset(&s->bus[i]);
763 }
balrog02645922007-11-03 12:50:46 +0000764}
Riku Voipio2ddfea92011-01-17 16:50:40 +0000765
766static SysBusDeviceInfo omap_i2c_info = {
767 .init = omap_i2c_init,
768 .qdev.name = "omap_i2c",
769 .qdev.size = sizeof(OMAPI2CState),
770 .qdev.reset = omap_i2c_reset,
771 .qdev.props = (Property[]) {
Juha Riihimäki76018002011-01-17 16:50:41 +0000772 DEFINE_PROP_INT32("mpu_model", OMAPI2CState, mpu_model, 0),
Riku Voipio2ddfea92011-01-17 16:50:40 +0000773 DEFINE_PROP_END_OF_LIST()
774 }
775};
776
777static void omap_i2c_register_devices(void)
778{
779 sysbus_register_withprop(&omap_i2c_info);
780}
781
Riku Voipio2ddfea92011-01-17 16:50:40 +0000782i2c_bus *omap_i2c_bus(DeviceState *omap_i2c, int n)
783{
784 OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState, sysbus_from_qdev(omap_i2c));
785 if (n >= s->buscount) {
786 hw_error("%s: requested bus %d (maximum allowed bus number is %d)\n",
787 __FUNCTION__, n, s->buscount - 1);
788 }
789 return s->bus[n].bus;
790}
791
792device_init(omap_i2c_register_devices)