99827627c86134454411b6ca48de64da0c407345
[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_slave slave[4];
32     i2c_bus *bus;
33
34     uint8_t revision;
35     uint16_t mask;
36     uint16_t stat;
37     uint16_t we;
38     uint16_t dma;
39     uint16_t count;
40     int count_cur;
41     uint16_t sysc;
42     uint16_t control;
43     uint16_t own_addr[4];
44     uint16_t slave_addr;
45     uint8_t sblock;
46     uint8_t divider;
47     uint16_t times[2];
48     uint16_t test;
49     int fifostart;
50     int fifolen;
51     int fifosize;
52     uint8_t fifo[I2C_MAX_FIFO_SIZE];
53 };
54
55 #define OMAP2_INTR_REV  0x34
56 #define OMAP2_GC_REV    0x34
57 #define OMAP3_INTR_REV  0x3c
58
59 //#define I2C_DEBUG
60 #ifdef I2C_DEBUG
61 #define TRACE(fmt, ...) fprintf(stderr, "%s " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
62 #else
63 #define TRACE(...)
64 #endif
65
66 static void omap_i2c_interrupts_update(struct omap_i2c_s *s)
67 {
68     TRACE("IRQ=%04x,RDRQ=%d,XDRQ=%d", 
69           s->stat & s->mask,
70           ((s->dma >> 15 ) & 1) & ((s->stat >> 3) & 1),
71           ((s->dma >> 7 ) & 1 )& ((s->stat >> 4 ) & 1));
72     qemu_set_irq(s->irq, s->stat & s->mask);
73     if ((s->dma >> 15) & 1)                          /* RDMA_EN */
74         qemu_set_irq(s->drq[0], (s->stat >> 3) & 1); /* RRDY */
75     if ((s->dma >> 7) & 1)                           /* XDMA_EN */
76         qemu_set_irq(s->drq[1], (s->stat >> 4) & 1); /* XRDY */
77 }
78
79 /* These are only stubs now.  */
80 static void omap_i2c_event(i2c_slave *i2c, enum i2c_event event)
81 {
82     fprintf(stderr, "%s: I^2C slave mode not supported\n", __FUNCTION__);
83     
84     /* code below is broken, i2c_slave CANNOT be cast to omap_i2c_s! */
85      
86     //struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
87     // 
88     //if ((~s->control >> 15) & 1)                              /* I2C_EN */
89     //    return;
90     //
91     //switch (event) {
92     //    case I2C_START_SEND:
93     //    case I2C_START_RECV:
94     //        s->stat |= 1 << 9;                                        /* AAS */
95     //        break;
96     //    case I2C_FINISH:
97     //        s->stat |= 1 << 2;                                        /* ARDY */
98     //        break;
99     //    case I2C_NACK:
100     //        s->stat |= 1 << 1;                                        /* NACK */
101     //        break;
102     //    default:
103     //        break;
104     //}
105     //
106     //omap_i2c_interrupts_update(s);
107 }
108
109 static int omap_i2c_rx(i2c_slave *i2c)
110 {
111     fprintf(stderr, "%s: I^2C slave mode not supported\n", __FUNCTION__);
112     return 0;
113     
114     /* code below is broken, i2c_slave CANNOT be cast to omap_i2c_s! */
115     
116     //struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
117     //uint8_t ret = 0;
118     //
119     //if ((~s->control >> 15) & 1)                              /* I2C_EN */
120     //    return -1;
121     //
122     //if (s->rxlen < s->txlen)
123     //    ret = s->fifo[s->rxlen++];
124     //else
125     //    s->stat |= 1 << 10;                                   /* XUDF */
126     //s->stat |= 1 << 4;                                                /* XRDY */
127     //
128     //omap_i2c_interrupts_update(s);
129     //return ret;
130 }
131
132 static int omap_i2c_tx(i2c_slave *i2c, uint8_t data)
133 {
134     fprintf(stderr, "%s: I^2C slave mode not supported\n", __FUNCTION__);
135     return 1;
136     
137     /* code below is broken, i2c_slave CANNOT be cast to omap_i2c_s! */
138     
139     //struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
140     //
141     //if ((~s->control >> 15) & 1)                              /* I2C_EN */
142     //    return 1;
143     //
144     //if (s->txlen < s->fifosize)
145     //    s->fifo[s->txlen++] = data;
146     //else
147     //    s->stat |= 1 << 11;                                   /* ROVR */
148     //s->stat |= 1 << 3;                                                /* RRDY */
149     //
150     //omap_i2c_interrupts_update(s);
151     //return 1;
152 }
153
154 static void omap_i2c_fifo_run(struct omap_i2c_s *s)
155 {
156     int ack = 1, i;
157
158     if (!i2c_bus_busy(s->bus))
159         return;
160
161     if ((s->control >> 2) & 1) {                                /* RM */
162         if ((s->control >> 1) & 1) {                            /* STP */
163             i2c_end_transfer(s->bus);
164             s->control &= ~(1 << 1);                            /* STP */
165             s->count_cur = s->count;
166             s->fifolen = 0;
167         } else if ((s->control >> 9) & 1) {                     /* TRX */
168             while (ack && s->fifolen) {
169                 ack = (i2c_send(s->bus, s->fifo[s->fifostart++]) >= 0);
170                 s->fifostart &= I2C_FIFO_SIZE_MASK;
171                 s->fifolen--;
172             }
173             s->fifolen = 0;
174             s->stat |= 1 << 4;                                  /* XRDY */
175         } else {
176             for (i = 0; i < 4; i++)
177                 s->fifo[(s->fifostart + i) & I2C_FIFO_SIZE_MASK] =
178                     i2c_recv(s->bus);
179             s->fifolen = 4;
180             s->stat |= 1 << 3;                                  /* RRDY */
181         }
182     } else {
183         if ((s->control >> 9) & 1) {                /* TRX */
184             TRACE("master transmit, count_cur=%d, fifolen=%d",
185                   s->count_cur, s->fifolen);
186             for (; ack && s->count_cur && s->fifolen; s->count_cur--) {
187                 ack = (i2c_send(s->bus, s->fifo[s->fifostart++]) >= 0);
188                 s->fifostart &= I2C_FIFO_SIZE_MASK;
189                 s->fifolen--;
190             }
191             s->stat &= ~0x4410;                     /* XDR | XUDF | XRDY */
192             if (ack && s->count_cur) {              /* send more? */
193                 /* we know that FIFO is empty */
194                 if (s->revision < OMAP3_INTR_REV)
195                     s->stat |= 1 << 4;              /* XRDY */
196                 else {
197                     if (s->count_cur > (s->dma & 0x3f)) /* XTRSH */
198                         s->stat |= 1 << 4;          /* XRDY */
199                     else
200                         s->stat |= 1 << 14;         /* XDR */
201                 }
202             }
203             if (!s->count_cur)                      /* everything sent? */
204                 s->stat |= 1 << 2;                  /* ARDY */
205         } else {                                    /* !TRX */
206             TRACE("master receive");
207             for (; s->count_cur && s->fifolen < s->fifosize; s->count_cur--) {
208                 i = i2c_recv(s->bus);
209                 if (i < 0) break; /* stop receiving if nothing to receive */
210                 s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
211                     (uint8_t)(i & 0xff);
212                 TRACE("received fifo[%02x] = %02x", s->fifolen - 1,
213                       s->fifo[(s->fifostart + s->fifolen - 1) & I2C_FIFO_SIZE_MASK]);
214             }
215             s->stat &= ~((1 << 3) | (1 << 13));            /* RRDY | RDR */
216             if (s->fifolen) {
217                 if (s->revision < OMAP3_INTR_REV)
218                     s->stat |= 1 << 3;                     /* RRDY */
219                 else {
220                     if (s->fifolen > ((s->dma >> 8) & 0x3f)) /* RTRSH */
221                         s->stat |= 1 << 3;                 /* RRDY */
222                     else
223                         s->stat |= 1 << 13;                /* RDR */
224                 }
225             } else if (!s->count_cur && (s->control & 2))  /* STP */
226                 s->stat |= 1 << 2;                         /* ARDY */
227         }
228         if (!s->count_cur) {
229             TRACE("no more data to transmit/receive");
230             if ((s->control >> 1) & 1) {   /* STP */
231                 i2c_end_transfer(s->bus);
232                 s->control &= ~0x0602;     /* MST | TRX | STP */
233                 s->count_cur = s->count;
234             } 
235         }
236     }
237
238     s->stat |= (!ack) << 1;                   /* NACK */
239     if (!ack)
240         s->control &= ~(1 << 1);          /* STP */
241     TRACE("finished, STAT = %04x, CNT = %d", s->stat, s->count_cur);
242 }
243
244 void omap_i2c_reset(struct omap_i2c_s *s)
245 {
246     s->mask = 0;
247     s->stat = 0;
248     s->dma = 0;
249     s->count = 0;
250     s->count_cur = 0;
251     s->we = 0;
252     s->sysc = 0;
253     s->fifolen = 0;
254     s->fifostart = 0;
255     s->control = 0;
256     s->own_addr[0] = 0;
257     s->own_addr[1] = 0;
258     s->own_addr[2] = 0;
259     s->own_addr[3] = 0;
260     s->slave_addr = 0;
261     s->sblock = 0;
262     s->divider = 0;
263     s->times[0] = 0;
264     s->times[1] = 0;
265     s->test = 0;
266 }
267
268 static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr)
269 {
270     struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
271     int offset = addr & OMAP_MPUI_REG_MASK;
272     uint16_t ret;
273
274     switch (offset) {
275         case 0x00: /* I2C_REV */
276             TRACE("REV returns %04x", s->revision);
277             return s->revision;
278         case 0x04: /* I2C_IE */
279             TRACE("IE returns %04x", s->mask);
280             return s->mask;
281         case 0x08: /* I2C_STAT */
282             TRACE("STAT returns %04x", s->stat | (i2c_bus_busy(s->bus) << 12));
283             return s->stat | (i2c_bus_busy(s->bus) << 12);
284         case 0x0c: /* I2C_IV / I2C_WE */
285             if (s->revision >= OMAP3_INTR_REV)
286                 return s->we;
287             if (s->revision >= OMAP2_INTR_REV)
288                 break;
289             ret = ffs(s->stat & s->mask);
290             if (ret)
291                 s->stat ^= 1 << (ret - 1);
292             omap_i2c_interrupts_update(s);
293             return ret;
294         case 0x10: /* I2C_SYSS */
295             return (s->control >> 15) & 1; /* reset completed == I2C_EN */
296         case 0x14: /* I2C_BUF */
297             TRACE("BUF returns %04x", s->dma);
298             return s->dma;
299         case 0x18: /* I2C_CNT */
300             TRACE("CNT returns %04x", s->count_cur);
301             return s->count_cur; /* DCOUNT */
302         case 0x1c: /* I2C_DATA */
303             ret = 0;
304             if (s->fifolen) {
305                 if (s->revision < OMAP3_INTR_REV) {
306                     if (s->control & (1 << 14)) /* BE */
307                         ret = (((uint16_t)s->fifo[s->fifostart]) << 8) 
308                             | s->fifo[(s->fifostart + 1) & I2C_FIFO_SIZE_MASK];
309                     else
310                         ret = (((uint16_t)s->fifo[(s->fifostart + 1) & I2C_FIFO_SIZE_MASK]) << 8) 
311                             | s->fifo[s->fifostart];
312                     s->fifostart = (s->fifostart + 2) & I2C_FIFO_SIZE_MASK;
313                     if (s->fifolen == 1) {
314                         s->stat |= 1 << 15; /* SBD */
315                         s->fifolen = 0;
316                     } else
317                         s->fifolen -= 2;
318                     if (!s->fifolen) {
319                         s->stat &= ~(1 << 3); /* RRDY */
320                         s->stat |= 1 << 2;    /* ARDY */
321                     }
322                 } else {
323                     s->stat &= ~(1 << 7); /* AERR */
324                     ret = s->fifo[s->fifostart++];
325                     s->fifostart &= I2C_FIFO_SIZE_MASK;
326                     if (--s->fifolen) {
327                         if (s->fifolen < ((s->dma & 0x3f) >> 8)) {
328                             s->stat &= ~(1 << 3); /* RRDY */
329                             s->stat |= 1 << 13;   /* RDR */
330                         }
331                     } else {
332                         s->stat &= ~((1 << 3) | (1 << 13)); /* RRDY | RDR */
333                         s->stat |= 1 << 2;                  /* ARDY */
334                     }
335                 }
336                 s->stat &= ~(1 << 11); /* ROVR */
337             } else if (s->revision >= OMAP3_INTR_REV)
338                 s->stat |= (1 << 7); /* AERR */
339             TRACE("DATA returns %04x", ret);
340             omap_i2c_fifo_run(s);
341             omap_i2c_interrupts_update(s);
342             return ret;
343         case 0x20: /* I2C_SYSC */
344             TRACE("SYSC returns %04x", s->sysc);
345             return s->sysc;
346         case 0x24: /* I2C_CON */
347             TRACE("CON returns %04x", s->control);
348             return s->control;
349         case 0x28: /* I2C_OA / I2C_OA0 */
350             return s->own_addr[0];
351         case 0x2c: /* I2C_SA */
352             return s->slave_addr;
353         case 0x30: /* I2C_PSC */
354             return s->divider;
355         case 0x34: /* I2C_SCLL */
356             return s->times[0];
357         case 0x38: /* I2C_SCLH */
358             return s->times[1];
359         case 0x3c: /* I2C_SYSTEST */
360             if (s->test & (1 << 15)) { /* ST_EN */
361                 s->test ^= 0xa;
362                 return s->test;
363             }
364             return s->test & ~0x300f;
365         case 0x40: /* I2C_BUFSTAT */
366             if (s->revision >= OMAP3_INTR_REV) {
367                 switch (s->fifosize) {
368                     case 8:  ret = 0x0000; break;
369                     case 16: ret = 0x4000; break;
370                     case 32: ret = 0x8000; break;
371                     case 64: ret = 0xc000; break;
372                     default: ret = 0x0000; break;
373                 }
374                 ret |= ((s->fifolen) & 0x3f) << 8;  /* RXSTAT */
375                 ret |= (s->count_cur) & 0x3f;       /* TXSTAT */
376                 TRACE("BUFSTAT returns %04x", ret);
377                 return ret;
378             }
379             break;
380         case 0x44: /* I2C_OA1 */
381         case 0x48: /* I2C_OA2 */
382         case 0x4c: /* I2C_OA3 */
383             if (s->revision >= OMAP3_INTR_REV)
384                 return s->own_addr[(addr >> 2) & 3];
385             break;
386         case 0x50: /* I2C_ACTOA */
387             if (s->revision >= OMAP3_INTR_REV)
388                 return 0; /* TODO: determine accessed slave own address */
389             break;
390         case 0x54: /* I2C_SBLOCK */
391             if (s->revision >= OMAP3_INTR_REV)
392                 return s->sblock;
393             break;
394         default:
395             break;
396     }
397
398     OMAP_BAD_REG(addr);
399     return 0;
400 }
401
402 static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
403                 uint32_t value)
404 {
405     struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
406     int offset = addr & OMAP_MPUI_REG_MASK;
407     int nack;
408
409     switch (offset) {
410         case 0x00: /* I2C_REV */
411         case 0x10: /* I2C_SYSS */
412         case 0x40: /* I2C_BUFSTAT */
413         case 0x50: /* I2C_ACTOA */
414             OMAP_RO_REG(addr);
415             break;
416         case 0x04: /* I2C_IE */
417             TRACE("IE = %04x", value);
418             if (s->revision >= OMAP3_INTR_REV)
419                 s->mask = value & 0x63ff;
420             else
421                 s->mask = value & (s->revision < OMAP2_GC_REV ? 0x1f : 0x3f);
422             omap_i2c_interrupts_update(s);
423             break;
424         case 0x08: /* I2C_STAT */
425             if (s->revision < OMAP2_INTR_REV)
426                 OMAP_RO_REG(addr);
427             else {
428                 TRACE("STAT = %04x", value);
429                 /* RRDY and XRDY are reset by hardware. (in all versions???) */
430                 s->stat &= ~(value & (s->revision < OMAP3_INTR_REV ? 0x27 : 0x63e7));
431                 omap_i2c_interrupts_update(s);
432             }
433             break;
434         case 0x0c: /* I2C_IV / I2C_WE */
435             if (s->revision < OMAP3_INTR_REV)
436                 OMAP_RO_REG(addr);
437             else
438                 s->we = value & 0x636f;
439             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 */
560             value &= s->revision < OMAP3_INTR_REV ? 0xf805 : 0xf815;
561             if ((value & (1 << 15))) { /* ST_EN */
562                 fprintf(stderr, "%s: System Test not supported\n",
563                         __FUNCTION__);
564                 s->test = (s->test & 0x0a) | value;
565             } else
566                 s->test = (s->test & 0x1f) | (value & 0xf800);
567             if (value & (1 << 11)) /* SBB */
568                 if (s->revision >= OMAP2_INTR_REV) {
569                     s->stat |= 0x3f;
570                     if (s->revision >= OMAP3_INTR_REV)
571                         s->stat |= 0x600;
572                     omap_i2c_interrupts_update(s);
573                 }
574             break;
575         case 0x44: /* I2C_OA1 */
576         case 0x48: /* I2C_OA2 */
577         case 0x4c: /* I2C_OA3 */
578             if (s->revision < OMAP3_INTR_REV)
579                 OMAP_BAD_REG(addr);
580             else {
581                 addr = (addr >> 2) & 3;
582                 TRACE("OA%d = %04x", (int)addr, value);
583                 s->own_addr[addr] = value & 0x3ff;
584                 i2c_set_slave_address(&s->slave[addr], 
585                                       value & ((s->control & (0x80 >> addr)) 
586                                                ? 0x3ff: 0x7f));
587             }
588             break;
589         case 0x54: /* I2C_SBLOCK */
590             if (s->revision < OMAP3_INTR_REV)
591                 OMAP_BAD_REG(addr);
592             else {
593                 s->sblock = value & 0x0f;
594             }
595             break;
596         default:
597             OMAP_BAD_REG(addr);
598             break;
599     }
600 }
601
602 static void omap_i2c_writeb(void *opaque, target_phys_addr_t addr,
603                 uint32_t value)
604 {
605     struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
606     int offset = addr & OMAP_MPUI_REG_MASK;
607
608     switch (offset) {
609         case 0x1c: /* I2C_DATA */
610             TRACE("DATA = %02x", value);
611             if (s->revision < OMAP3_INTR_REV && s->fifolen > 2) {
612                 /* XXX: remote access (qualifier) error - what's that? */
613                 break;
614             }
615             if (s->fifolen < s->fifosize) {
616                 s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
617                     (uint8_t)(value & 0xff);
618                 if (s->revision >= OMAP3_INTR_REV)
619                     s->stat &= ~(1 << 7); /* AERR */
620                 s->stat &= ~(1 << 10);    /* XUDF */
621                 omap_i2c_fifo_run(s);
622             } else if (s->revision >= OMAP3_INTR_REV)
623                 s->stat |= (1 << 7);      /* AERR */
624             omap_i2c_interrupts_update(s);
625             break;
626         default:
627             OMAP_BAD_REG(addr);
628             break;
629     }
630 }
631
632 static CPUReadMemoryFunc *omap_i2c_readfn[] = {
633     omap_badwidth_read16,
634     omap_i2c_read,
635     omap_badwidth_read16,
636 };
637
638 static CPUWriteMemoryFunc *omap_i2c_writefn[] = {
639     omap_i2c_writeb,    /* Only the last fifo write can be 8 bit.  */
640     omap_i2c_write,
641     omap_badwidth_write16,
642 };
643
644 static void omap_i2c_save_state(QEMUFile *f, void *opaque)
645 {
646     struct omap_i2c_s *s = (struct omap_i2c_s *)opaque;
647     
648     /* TODO: slave setup(s) */
649     qemu_put_be16(f, s->mask);
650     qemu_put_be16(f, s->stat);
651     qemu_put_be16(f, s->we);
652     qemu_put_be16(f, s->dma);
653     qemu_put_be16(f, s->count);
654     qemu_put_sbe32(f, s->count_cur);
655     qemu_put_be16(f, s->sysc);
656     qemu_put_be16(f, s->control);
657     qemu_put_be16(f, s->own_addr[0]);
658     qemu_put_be16(f, s->own_addr[1]);
659     qemu_put_be16(f, s->own_addr[2]);
660     qemu_put_be16(f, s->own_addr[3]);
661     qemu_put_be16(f, s->slave_addr);
662     qemu_put_byte(f, s->sblock);
663     qemu_put_byte(f, s->divider);
664     qemu_put_be16(f, s->times[0]);
665     qemu_put_be16(f, s->times[1]);
666     qemu_put_be16(f, s->test);
667     qemu_put_sbe32(f, s->fifostart);
668     qemu_put_sbe32(f, s->fifolen);
669     qemu_put_sbe32(f, s->fifosize);
670     qemu_put_buffer(f, s->fifo, sizeof(s->fifo));
671 }
672
673 static int omap_i2c_load_state(QEMUFile *f, void *opaque, int version_id)
674 {
675     struct omap_i2c_s *s = (struct omap_i2c_s *)opaque;
676     
677     if (version_id)
678         return -EINVAL;
679     
680     /* TODO: slave setup(s) */
681     s->mask = qemu_get_be16(f);
682     s->stat = qemu_get_be16(f);
683     s->we = qemu_get_be16(f);
684     s->dma = qemu_get_be16(f);
685     s->count = qemu_get_be16(f);
686     s->count_cur = qemu_get_sbe32(f);
687     s->sysc = qemu_get_be16(f);
688     s->control = qemu_get_be16(f);
689     s->own_addr[0] = qemu_get_be16(f);
690     s->own_addr[1] = qemu_get_be16(f);
691     s->own_addr[2] = qemu_get_be16(f);
692     s->own_addr[3] = qemu_get_be16(f);
693     s->slave_addr = qemu_get_be16(f);
694     s->sblock = qemu_get_byte(f);
695     s->divider = qemu_get_byte(f);
696     s->times[0] = qemu_get_be16(f);
697     s->times[1] = qemu_get_be16(f);
698     s->test = qemu_get_be16(f);
699     s->fifostart = qemu_get_sbe32(f);
700     s->fifolen = qemu_get_sbe32(f);
701     s->fifosize = qemu_get_sbe32(f);
702     qemu_get_buffer(f, s->fifo, sizeof(s->fifo));
703
704     omap_i2c_interrupts_update(s);
705     
706     return 0;
707 }
708
709 static struct omap_i2c_s *omap_i2c_common_init(uint8_t rev, int fifosize,
710                                                qemu_irq irq, qemu_irq *dma)
711 {
712     struct omap_i2c_s *s = (struct omap_i2c_s *)
713         qemu_mallocz(sizeof(struct omap_i2c_s));
714     
715     if (fifosize > I2C_MAX_FIFO_SIZE) {
716         fprintf(stderr, "%s: maximum FIFO size is %d (tried to use %d)\n",
717                 __FUNCTION__, I2C_MAX_FIFO_SIZE, fifosize);
718         exit(-1);
719     }
720     s->revision = rev;
721     s->irq = irq;
722     s->drq[0] = dma[0];
723     s->drq[1] = dma[1];
724     s->slave[0].event = s->slave[1].event = s->slave[2].event =
725         s->slave[3].event = omap_i2c_event;
726     s->slave[0].recv = s->slave[1].recv = s->slave[2].recv =
727         s->slave[3].recv = omap_i2c_rx;
728     s->slave[0].send = s->slave[1].send = s->slave[2].send =
729         s->slave[3].send = omap_i2c_tx;
730     s->bus = i2c_init_bus();
731     s->fifosize = fifosize;
732     omap_i2c_reset(s);
733     return s;
734 }
735
736 struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
737                 qemu_irq irq, qemu_irq *dma, omap_clk clk)
738 {
739     struct omap_i2c_s *s = omap_i2c_common_init(0x11, 4, irq, dma);
740
741     cpu_register_physical_memory(base, 0x800,
742                                  cpu_register_io_memory(0, omap_i2c_readfn,
743                                                         omap_i2c_writefn, s));
744     return s;
745 }
746
747 struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta,
748                 qemu_irq irq, qemu_irq *dma, omap_clk fclk, omap_clk iclk)
749 {
750     struct omap_i2c_s *s = omap_i2c_common_init(0x34, 4, irq, dma);
751
752     omap_l4_attach(ta, 0, l4_register_io_memory(0, omap_i2c_readfn,
753                                                 omap_i2c_writefn, s));
754     return s;
755 }
756
757 struct omap_i2c_s *omap3_i2c_init(struct omap_target_agent_s *ta,
758                                   qemu_irq irq, qemu_irq *dma,
759                                   omap_clk fclk, omap_clk iclk,
760                                   int fifosize)
761 {
762     struct omap_i2c_s *s;
763     
764     if (fifosize != 8 && fifosize != 16 && fifosize != 32 && fifosize != 64) {
765         fprintf(stderr, "%s: unsupported FIFO depth specified (%d)\n",
766                 __FUNCTION__, fifosize);
767         exit(-1);
768     }
769     s = omap_i2c_common_init(OMAP3_INTR_REV, fifosize, irq, dma);
770     
771     omap_l4_attach(ta, 0, l4_register_io_memory(0, omap_i2c_readfn,
772                                                 omap_i2c_writefn, s));
773     register_savevm("omap3_i2c", (ta->base >> 12) & 0xff, 0,
774                     omap_i2c_save_state, omap_i2c_load_state, s);
775     return s;
776 }
777
778 i2c_bus *omap_i2c_bus(struct omap_i2c_s *s)
779 {
780     return s->bus;
781 }