fix I2C slave addressing
[qemu] / hw / omap_i2c.c
1 /*
2  * TI OMAP on-chip I2C controller.  Only "new I2C" mode supported.
3  *
4  * Copyright (C) 2007 Andrzej Zaborowski  <balrog@zabor.org>
5  * Copyright (C) 2009 Nokia Corporation
6  *
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  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21 #include "hw.h"
22 #include "i2c.h"
23 #include "omap.h"
24
25 #define I2C_MAX_FIFO_SIZE (1 << 6)
26 #define I2C_FIFO_SIZE_MASK ((I2C_MAX_FIFO_SIZE) - 1)
27
28 struct omap_i2c_s {
29     qemu_irq irq;
30     qemu_irq drq[2];
31     i2c_bus *bus;
32
33     uint8_t revision;
34     uint16_t mask;
35     uint16_t stat;
36     uint16_t we;
37     uint16_t dma;
38     uint16_t count;
39     int count_cur;
40     uint16_t sysc;
41     uint16_t control;
42     uint16_t own_addr[4];
43     uint16_t slave_addr;
44     uint8_t sblock;
45     uint8_t divider;
46     uint16_t times[2];
47     uint16_t test;
48     int fifostart;
49     int fifolen;
50     int fifosize;
51     uint8_t fifo[I2C_MAX_FIFO_SIZE];
52 };
53
54 #define OMAP2_INTR_REV  0x34
55 #define OMAP2_GC_REV    0x34
56 #define OMAP3_INTR_REV  0x3c
57
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
64
65 static void omap_i2c_interrupts_update(struct omap_i2c_s *s)
66 {
67     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));
71     qemu_set_irq(s->irq, s->stat & s->mask);
72     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 */
76 }
77
78 static void omap_i2c_fifo_run(struct omap_i2c_s *s)
79 {
80     int ack = 1, i;
81
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;
90             s->fifolen = 0;
91         } else if ((s->control >> 9) & 1) {                     /* TRX */
92             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;
98             s->stat |= 1 << 4;                                  /* XRDY */
99         } else {
100             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;
104             s->stat |= 1 << 3;                                  /* RRDY */
105         }
106     } else {
107         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--;
114             }
115             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                 }
126             }
127             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]);
138             }
139             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 */
151         }
152         if (!s->count_cur) {
153             TRACE("no more data to transmit/receive");
154             if ((s->control >> 1) & 1) {   /* STP */
155                 i2c_end_transfer(s->bus);
156                 s->control &= ~0x0602;     /* MST | TRX | STP */
157                 s->count_cur = s->count;
158             } 
159         }
160     }
161
162     s->stat |= (!ack) << 1;                   /* NACK */
163     if (!ack)
164         s->control &= ~(1 << 1);          /* STP */
165     TRACE("finished, STAT = %04x, CNT = %d", s->stat, s->count_cur);
166 }
167
168 void 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;
175     s->we = 0;
176     s->sysc = 0;
177     s->fifolen = 0;
178     s->fifostart = 0;
179     s->control = 0;
180     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;
186     s->divider = 0;
187     s->times[0] = 0;
188     s->times[1] = 0;
189     s->test = 0;
190 }
191
192 static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr)
193 {
194     struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
195     int offset = addr & OMAP_MPUI_REG_MASK;
196     uint16_t ret;
197
198     switch (offset) {
199         case 0x00: /* I2C_REV */
200             TRACE("REV returns %04x", s->revision);
201             return s->revision;
202         case 0x04: /* I2C_IE */
203             TRACE("IE returns %04x", s->mask);
204             return s->mask;
205         case 0x08: /* I2C_STAT */
206             TRACE("STAT returns %04x", s->stat | (i2c_bus_busy(s->bus) << 12));
207             return s->stat | (i2c_bus_busy(s->bus) << 12);
208         case 0x0c: /* I2C_IV / I2C_WE */
209             if (s->revision >= OMAP3_INTR_REV)
210                 return s->we;
211             if (s->revision >= OMAP2_INTR_REV)
212                 break;
213             ret = ffs(s->stat & s->mask);
214             if (ret)
215                 s->stat ^= 1 << (ret - 1);
216             omap_i2c_interrupts_update(s);
217             return ret;
218         case 0x10: /* I2C_SYSS */
219             return (s->control >> 15) & 1; /* reset completed == I2C_EN */
220         case 0x14: /* I2C_BUF */
221             TRACE("BUF returns %04x", s->dma);
222             return s->dma;
223         case 0x18: /* I2C_CNT */
224             TRACE("CNT returns %04x", s->count_cur);
225             return s->count_cur; /* DCOUNT */
226         case 0x1c: /* I2C_DATA */
227             ret = 0;
228             if (s->fifolen) {
229                 if (s->revision < OMAP3_INTR_REV) {
230                     if (s->control & (1 << 14)) /* BE */
231                         ret = (((uint16_t)s->fifo[s->fifostart]) << 8) 
232                             | s->fifo[(s->fifostart + 1) & I2C_FIFO_SIZE_MASK];
233                     else
234                         ret = (((uint16_t)s->fifo[(s->fifostart + 1) & I2C_FIFO_SIZE_MASK]) << 8) 
235                             | s->fifo[s->fifostart];
236                     s->fifostart = (s->fifostart + 2) & I2C_FIFO_SIZE_MASK;
237                     if (s->fifolen == 1) {
238                         s->stat |= 1 << 15; /* SBD */
239                         s->fifolen = 0;
240                     } else
241                         s->fifolen -= 2;
242                     if (!s->fifolen) {
243                         s->stat &= ~(1 << 3); /* RRDY */
244                         s->stat |= 1 << 2;    /* ARDY */
245                     }
246                 } else {
247                     s->stat &= ~(1 << 7); /* AERR */
248                     ret = s->fifo[s->fifostart++];
249                     s->fifostart &= I2C_FIFO_SIZE_MASK;
250                     if (--s->fifolen) {
251                         if (s->fifolen <= ((s->dma >> 8) & 0x3f)) {
252                             s->stat &= ~(1 << 3); /* RRDY */
253                             s->stat |= 1 << 13;   /* RDR */
254                         }
255                     } else {
256                         s->stat &= ~((1 << 3) | (1 << 13)); /* RRDY | RDR */
257                         s->stat |= 1 << 2;                  /* ARDY */
258                     }
259                 }
260                 s->stat &= ~(1 << 11); /* ROVR */
261             } else if (s->revision >= OMAP3_INTR_REV)
262                 s->stat |= (1 << 7); /* AERR */
263             TRACE("DATA returns %04x", ret);
264             omap_i2c_fifo_run(s);
265             omap_i2c_interrupts_update(s);
266             return ret;
267         case 0x20: /* I2C_SYSC */
268             TRACE("SYSC returns %04x", s->sysc);
269             return s->sysc;
270         case 0x24: /* I2C_CON */
271             TRACE("CON returns %04x", s->control);
272             return s->control;
273         case 0x28: /* I2C_OA / I2C_OA0 */
274             return s->own_addr[0];
275         case 0x2c: /* I2C_SA */
276             return s->slave_addr;
277         case 0x30: /* I2C_PSC */
278             return s->divider;
279         case 0x34: /* I2C_SCLL */
280             return s->times[0];
281         case 0x38: /* I2C_SCLH */
282             return s->times[1];
283         case 0x3c: /* I2C_SYSTEST */
284             if (s->test & (1 << 15)) { /* ST_EN */
285                 s->test ^= 0xa;
286                 return s->test;
287             }
288             return s->test & ~0x300f;
289         case 0x40: /* I2C_BUFSTAT */
290             if (s->revision >= OMAP3_INTR_REV) {
291                 switch (s->fifosize) {
292                     case 8:  ret = 0x0000; break;
293                     case 16: ret = 0x4000; break;
294                     case 32: ret = 0x8000; break;
295                     case 64: ret = 0xc000; break;
296                     default: ret = 0x0000; break;
297                 }
298                 ret |= ((s->fifolen) & 0x3f) << 8;  /* RXSTAT */
299                 ret |= (s->count_cur) & 0x3f;       /* TXSTAT */
300                 TRACE("BUFSTAT returns %04x", ret);
301                 return ret;
302             }
303             break;
304         case 0x44: /* I2C_OA1 */
305         case 0x48: /* I2C_OA2 */
306         case 0x4c: /* I2C_OA3 */
307             if (s->revision >= OMAP3_INTR_REV)
308                 return s->own_addr[(addr >> 2) & 3];
309             break;
310         case 0x50: /* I2C_ACTOA */
311             if (s->revision >= OMAP3_INTR_REV)
312                 return 0; /* TODO: determine accessed slave own address */
313             break;
314         case 0x54: /* I2C_SBLOCK */
315             if (s->revision >= OMAP3_INTR_REV)
316                 return s->sblock;
317             break;
318         default:
319             break;
320     }
321
322     OMAP_BAD_REG(addr);
323     return 0;
324 }
325
326 static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
327                 uint32_t value)
328 {
329     struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
330     int offset = addr & OMAP_MPUI_REG_MASK;
331     int nack;
332
333     switch (offset) {
334         case 0x00: /* I2C_REV */
335         case 0x10: /* I2C_SYSS */
336         case 0x40: /* I2C_BUFSTAT */
337         case 0x50: /* I2C_ACTOA */
338             OMAP_RO_REG(addr);
339             break;
340         case 0x04: /* I2C_IE */
341             TRACE("IE = %04x", value);
342             if (s->revision >= OMAP3_INTR_REV)
343                 s->mask = value & 0x63ff;
344             else
345                 s->mask = value & (s->revision < OMAP2_GC_REV ? 0x1f : 0x3f);
346             omap_i2c_interrupts_update(s);
347             break;
348         case 0x08: /* I2C_STAT */
349             if (s->revision < OMAP2_INTR_REV)
350                 OMAP_RO_REG(addr);
351             else {
352                 TRACE("STAT = %04x", value);
353                 /* RRDY and XRDY are reset by hardware. (in all versions???) */
354                 s->stat &= ~(value & (s->revision < OMAP3_INTR_REV ? 0x27 : 0x63e7));
355                 omap_i2c_interrupts_update(s);
356             }
357             break;
358         case 0x0c: /* I2C_IV / I2C_WE */
359             if (s->revision < OMAP3_INTR_REV)
360                 OMAP_RO_REG(addr);
361             else
362                 s->we = value & 0x636f;
363             break;
364         case 0x14: /* I2C_BUF */
365             TRACE("BUF = %04x", value);
366             if (s->revision < OMAP3_INTR_REV)
367                 s->dma = value & 0x8080;
368             else {
369                 s->dma = value & 0xbfbf;
370                 if ((value & (1 << 14))    /* RXFIFO_CLR */
371                     || (value & (1 << 6))) /* TXFIFO_CLR */
372                     s->fifolen = 0;
373             }
374             if (value & (1 << 15))     /* RDMA_EN */
375                 s->mask &= ~(1 << 3);  /* RRDY_IE */
376             if (value & (1 << 7))      /* XDMA_EN */
377                 s->mask &= ~(1 << 4);  /* XRDY_IE */
378             break;
379         case 0x18: /* I2C_CNT */
380             TRACE("CNT = %04x", value);
381             s->count = value; /* DCOUNT */
382             break;
383         case 0x1c: /* I2C_DATA */
384             TRACE("DATA = %04x", value);
385             if (s->revision < OMAP3_INTR_REV) {
386                 if (s->fifolen > 2) {
387                     /* XXX: remote access (qualifier) error - what's that? */
388                     break;
389                 }
390                 if (s->control & (1 << 14)) { /* BE */
391                     s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
392                         (uint8_t)((value >> 8) & 0xff);
393                     s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
394                         (uint8_t)(value & 0xff);
395                 } else {
396                     s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
397                         (uint8_t)(value & 0xff);
398                     s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
399                         (uint8_t)((value >> 8) & 0xff);
400                 }
401             } else {
402                 if (s->fifolen < s->fifosize) {
403                     s->stat &= ~(1 << 7); /* AERR */
404                     s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
405                         (uint8_t)(value & 0xff);
406                 } else
407                     s->stat |= (1 << 7); /* AERR */
408             }
409             s->stat &= ~(1 << 10); /* XUDF */
410             omap_i2c_fifo_run(s);
411             omap_i2c_interrupts_update(s);
412             break;
413         case 0x20: /* I2C_SYSC */
414             if (s->revision < OMAP2_INTR_REV) {
415                 OMAP_BAD_REG(addr);
416                 break;
417             }
418             TRACE("SYSC = %04x", value);
419             if (value & 2)
420                 omap_i2c_reset(s);
421             else if (s->revision >= OMAP3_INTR_REV)
422                 s->sysc = value & 0x031d;
423             break;
424         case 0x24: /* I2C_CON */
425             TRACE("CON = %04x", value);
426             s->control = value & (s->revision < OMAP3_INTR_REV ? 0xcf87 : 0xbff3);
427             if (~value & (1 << 15)) { /* I2C_EN */
428                 if (s->revision < OMAP2_INTR_REV)
429                     omap_i2c_reset(s);
430                 break;
431             }
432             if (s->revision >= OMAP3_INTR_REV && ((value >> 12) & 3) > 1) { /* OPMODE */
433                 fprintf(stderr,
434                         "%s: only FS and HS modes are supported\n",
435                         __FUNCTION__);
436                 break;
437             }
438             if ((value & (1 << 10))) { /* MST */
439                 if (value & 1) { /* STT */
440                     nack = !!i2c_start_transfer(s->bus, s->slave_addr, /*SA*/
441                                                 (~value >> 9) & 1);    /*TRX*/
442                     s->stat |= nack << 1;        /* NACK */
443                     s->control &= ~(1 << 0);     /* STT */
444                     s->fifolen = 0;
445                     if (nack)
446                         s->control &= ~(1 << 1); /* STP */
447                     else {
448                         s->count_cur = s->count;
449                         omap_i2c_fifo_run(s);
450                     }
451                     omap_i2c_interrupts_update(s);
452                 } else if (value & 2) { /* STP, but not STT */
453                     i2c_end_transfer(s->bus);
454                     s->control &= ~0x0602;     /* MST | TRX | STP */
455                     s->count_cur = s->count;
456                 }
457             }
458             break;
459         case 0x28: /* I2C_OA / I2C_OA0 */
460             TRACE("OA0 = %04x", value);
461             s->own_addr[0] = value & (s->revision < OMAP3_INTR_REV 
462                                       ? 0x3ff : 0xe3ff);
463             /*i2c_set_slave_address(&s->slave[0], 
464                                   value & (s->revision >= OMAP3_INTR_REV 
465                                            && (s->control & 0x80) 
466                                            ? 0x3ff: 0x7f));*/
467             break;
468         case 0x2c: /* I2C_SA */
469             TRACE("SA = %04x", value);
470             s->slave_addr = value & 0x3ff;
471             break;
472         case 0x30: /* I2C_PSC */
473             s->divider = value;
474             break;
475         case 0x34: /* I2C_SCLL */
476             s->times[0] = value & (s->revision < OMAP3_INTR_REV 
477                                    ? 0xff : 0xffff);
478             break;
479         case 0x38: /* I2C_SCLH */
480             s->times[1] = value & (s->revision < OMAP3_INTR_REV
481                                    ? 0xff : 0xffff);
482             break;
483         case 0x3c: /* I2C_SYSTEST */
484             value &= s->revision < OMAP3_INTR_REV ? 0xf805 : 0xf815;
485             if ((value & (1 << 15))) { /* ST_EN */
486                 fprintf(stderr, "%s: System Test not supported\n",
487                         __FUNCTION__);
488                 s->test = (s->test & 0x0a) | value;
489             } else
490                 s->test = (s->test & 0x1f) | (value & 0xf800);
491             if (value & (1 << 11)) /* SBB */
492                 if (s->revision >= OMAP2_INTR_REV) {
493                     s->stat |= 0x3f;
494                     if (s->revision >= OMAP3_INTR_REV)
495                         s->stat |= 0x600;
496                     omap_i2c_interrupts_update(s);
497                 }
498             break;
499         case 0x44: /* I2C_OA1 */
500         case 0x48: /* I2C_OA2 */
501         case 0x4c: /* I2C_OA3 */
502             if (s->revision < OMAP3_INTR_REV)
503                 OMAP_BAD_REG(addr);
504             else {
505                 addr = (addr >> 2) & 3;
506                 TRACE("OA%d = %04x", (int)addr, value);
507                 s->own_addr[addr] = value & 0x3ff;
508                 /*i2c_set_slave_address(&s->slave[addr], 
509                                       value & ((s->control & (0x80 >> addr)) 
510                                                ? 0x3ff: 0x7f));*/
511             }
512             break;
513         case 0x54: /* I2C_SBLOCK */
514             if (s->revision < OMAP3_INTR_REV)
515                 OMAP_BAD_REG(addr);
516             else {
517                 s->sblock = value & 0x0f;
518             }
519             break;
520         default:
521             OMAP_BAD_REG(addr);
522             break;
523     }
524 }
525
526 static void omap_i2c_writeb(void *opaque, target_phys_addr_t addr,
527                 uint32_t value)
528 {
529     struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
530     int offset = addr & OMAP_MPUI_REG_MASK;
531
532     switch (offset) {
533         case 0x1c: /* I2C_DATA */
534             TRACE("DATA = %02x", value);
535             if (s->revision < OMAP3_INTR_REV && s->fifolen > 2) {
536                 /* XXX: remote access (qualifier) error - what's that? */
537                 break;
538             }
539             if (s->fifolen < s->fifosize) {
540                 s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
541                     (uint8_t)(value & 0xff);
542                 if (s->revision >= OMAP3_INTR_REV)
543                     s->stat &= ~(1 << 7); /* AERR */
544                 s->stat &= ~(1 << 10);    /* XUDF */
545                 omap_i2c_fifo_run(s);
546             } else if (s->revision >= OMAP3_INTR_REV)
547                 s->stat |= (1 << 7);      /* AERR */
548             omap_i2c_interrupts_update(s);
549             break;
550         default:
551             OMAP_BAD_REG(addr);
552             break;
553     }
554 }
555
556 static CPUReadMemoryFunc *omap_i2c_readfn[] = {
557     omap_badwidth_read16,
558     omap_i2c_read,
559     omap_badwidth_read16,
560 };
561
562 static CPUWriteMemoryFunc *omap_i2c_writefn[] = {
563     omap_i2c_writeb,    /* Only the last fifo write can be 8 bit.  */
564     omap_i2c_write,
565     omap_badwidth_write16,
566 };
567
568 static void omap_i2c_save_state(QEMUFile *f, void *opaque)
569 {
570     struct omap_i2c_s *s = (struct omap_i2c_s *)opaque;
571     
572     /* TODO: slave setup(s) */
573     qemu_put_be16(f, s->mask);
574     qemu_put_be16(f, s->stat);
575     qemu_put_be16(f, s->we);
576     qemu_put_be16(f, s->dma);
577     qemu_put_be16(f, s->count);
578     qemu_put_sbe32(f, s->count_cur);
579     qemu_put_be16(f, s->sysc);
580     qemu_put_be16(f, s->control);
581     qemu_put_be16(f, s->own_addr[0]);
582     qemu_put_be16(f, s->own_addr[1]);
583     qemu_put_be16(f, s->own_addr[2]);
584     qemu_put_be16(f, s->own_addr[3]);
585     qemu_put_be16(f, s->slave_addr);
586     qemu_put_byte(f, s->sblock);
587     qemu_put_byte(f, s->divider);
588     qemu_put_be16(f, s->times[0]);
589     qemu_put_be16(f, s->times[1]);
590     qemu_put_be16(f, s->test);
591     qemu_put_sbe32(f, s->fifostart);
592     qemu_put_sbe32(f, s->fifolen);
593     qemu_put_sbe32(f, s->fifosize);
594     qemu_put_buffer(f, s->fifo, sizeof(s->fifo));
595 }
596
597 static int omap_i2c_load_state(QEMUFile *f, void *opaque, int version_id)
598 {
599     struct omap_i2c_s *s = (struct omap_i2c_s *)opaque;
600     
601     if (version_id)
602         return -EINVAL;
603     
604     /* TODO: slave setup(s) */
605     s->mask = qemu_get_be16(f);
606     s->stat = qemu_get_be16(f);
607     s->we = qemu_get_be16(f);
608     s->dma = qemu_get_be16(f);
609     s->count = qemu_get_be16(f);
610     s->count_cur = qemu_get_sbe32(f);
611     s->sysc = qemu_get_be16(f);
612     s->control = qemu_get_be16(f);
613     s->own_addr[0] = qemu_get_be16(f);
614     s->own_addr[1] = qemu_get_be16(f);
615     s->own_addr[2] = qemu_get_be16(f);
616     s->own_addr[3] = qemu_get_be16(f);
617     s->slave_addr = qemu_get_be16(f);
618     s->sblock = qemu_get_byte(f);
619     s->divider = qemu_get_byte(f);
620     s->times[0] = qemu_get_be16(f);
621     s->times[1] = qemu_get_be16(f);
622     s->test = qemu_get_be16(f);
623     s->fifostart = qemu_get_sbe32(f);
624     s->fifolen = qemu_get_sbe32(f);
625     s->fifosize = qemu_get_sbe32(f);
626     qemu_get_buffer(f, s->fifo, sizeof(s->fifo));
627
628     omap_i2c_interrupts_update(s);
629     
630     return 0;
631 }
632
633 static struct omap_i2c_s *omap_i2c_common_init(uint8_t rev, int fifosize,
634                                                qemu_irq irq, qemu_irq *dma)
635 {
636     struct omap_i2c_s *s = (struct omap_i2c_s *)
637         qemu_mallocz(sizeof(struct omap_i2c_s));
638     
639     if (fifosize > I2C_MAX_FIFO_SIZE) {
640         fprintf(stderr, "%s: maximum FIFO size is %d (tried to use %d)\n",
641                 __FUNCTION__, I2C_MAX_FIFO_SIZE, fifosize);
642         exit(-1);
643     }
644     s->revision = rev;
645     s->irq = irq;
646     s->drq[0] = dma[0];
647     s->drq[1] = dma[1];
648     s->bus = i2c_init_bus(NULL, "i2c");
649     s->fifosize = fifosize;
650     omap_i2c_reset(s);
651     return s;
652 }
653
654 struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
655                 qemu_irq irq, qemu_irq *dma, omap_clk clk)
656 {
657     struct omap_i2c_s *s = omap_i2c_common_init(0x11, 4, irq, dma);
658
659     cpu_register_physical_memory(base, 0x800,
660                                  cpu_register_io_memory(0, omap_i2c_readfn,
661                                                         omap_i2c_writefn, s));
662     return s;
663 }
664
665 struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta,
666                 qemu_irq irq, qemu_irq *dma, omap_clk fclk, omap_clk iclk)
667 {
668     struct omap_i2c_s *s = omap_i2c_common_init(0x34, 4, irq, dma);
669
670     omap_l4_attach(ta, 0, l4_register_io_memory(0, omap_i2c_readfn,
671                                                 omap_i2c_writefn, s));
672     return s;
673 }
674
675 struct omap_i2c_s *omap3_i2c_init(struct omap_target_agent_s *ta,
676                                   qemu_irq irq, qemu_irq *dma,
677                                   omap_clk fclk, omap_clk iclk,
678                                   int fifosize)
679 {
680     struct omap_i2c_s *s;
681     
682     if (fifosize != 8 && fifosize != 16 && fifosize != 32 && fifosize != 64) {
683         fprintf(stderr, "%s: unsupported FIFO depth specified (%d)\n",
684                 __FUNCTION__, fifosize);
685         exit(-1);
686     }
687     s = omap_i2c_common_init(OMAP3_INTR_REV, fifosize, irq, dma);
688     
689     omap_l4_attach(ta, 0, l4_register_io_memory(0, omap_i2c_readfn,
690                                                 omap_i2c_writefn, s));
691     register_savevm("omap3_i2c", (ta->base >> 12) & 0xff, 0,
692                     omap_i2c_save_state, omap_i2c_load_state, s);
693     return s;
694 }
695
696 i2c_bus *omap_i2c_bus(struct omap_i2c_s *s)
697 {
698     return s->bus;
699 }