]> Git Repo - qemu.git/blob - hw/i2c/omap_i2c.c
Merge remote-tracking branch 'filippov/tags/20130729-xtensa' into staging
[qemu.git] / hw / i2c / omap_i2c.c
1 /*
2  * TI OMAP on-chip I2C controller.  Only "new I2C" mode supported.
3  *
4  * Copyright (C) 2007 Andrzej Zaborowski  <[email protected]>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19 #include "hw/hw.h"
20 #include "hw/i2c/i2c.h"
21 #include "hw/arm/omap.h"
22 #include "hw/sysbus.h"
23
24 #define TYPE_OMAP_I2C "omap_i2c"
25 #define OMAP_I2C(obj) OBJECT_CHECK(OMAPI2CState, (obj), TYPE_OMAP_I2C)
26
27 typedef struct OMAPI2CState {
28     SysBusDevice parent_obj;
29
30     MemoryRegion iomem;
31     qemu_irq irq;
32     qemu_irq drq[2];
33     i2c_bus *bus;
34
35     uint8_t revision;
36     void *iclk;
37     void *fclk;
38
39     uint8_t mask;
40     uint16_t stat;
41     uint16_t dma;
42     uint16_t count;
43     int count_cur;
44     uint32_t fifo;
45     int rxlen;
46     int txlen;
47     uint16_t control;
48     uint16_t addr[2];
49     uint8_t divider;
50     uint8_t times[2];
51     uint16_t test;
52 } OMAPI2CState;
53
54 #define OMAP2_INTR_REV  0x34
55 #define OMAP2_GC_REV    0x34
56
57 static void omap_i2c_interrupts_update(OMAPI2CState *s)
58 {
59     qemu_set_irq(s->irq, s->stat & s->mask);
60     if ((s->dma >> 15) & 1)                                     /* RDMA_EN */
61         qemu_set_irq(s->drq[0], (s->stat >> 3) & 1);            /* RRDY */
62     if ((s->dma >> 7) & 1)                                      /* XDMA_EN */
63         qemu_set_irq(s->drq[1], (s->stat >> 4) & 1);            /* XRDY */
64 }
65
66 static void omap_i2c_fifo_run(OMAPI2CState *s)
67 {
68     int ack = 1;
69
70     if (!i2c_bus_busy(s->bus))
71         return;
72
73     if ((s->control >> 2) & 1) {                                /* RM */
74         if ((s->control >> 1) & 1) {                            /* STP */
75             i2c_end_transfer(s->bus);
76             s->control &= ~(1 << 1);                            /* STP */
77             s->count_cur = s->count;
78             s->txlen = 0;
79         } else if ((s->control >> 9) & 1) {                     /* TRX */
80             while (ack && s->txlen)
81                 ack = (i2c_send(s->bus,
82                                         (s->fifo >> ((-- s->txlen) << 3)) &
83                                         0xff) >= 0);
84             s->stat |= 1 << 4;                                  /* XRDY */
85         } else {
86             while (s->rxlen < 4)
87                 s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
88             s->stat |= 1 << 3;                                  /* RRDY */
89         }
90     } else {
91         if ((s->control >> 9) & 1) {                            /* TRX */
92             while (ack && s->count_cur && s->txlen) {
93                 ack = (i2c_send(s->bus,
94                                         (s->fifo >> ((-- s->txlen) << 3)) &
95                                         0xff) >= 0);
96                 s->count_cur --;
97             }
98             if (ack && s->count_cur)
99                 s->stat |= 1 << 4;                              /* XRDY */
100             else
101                 s->stat &= ~(1 << 4);                           /* XRDY */
102             if (!s->count_cur) {
103                 s->stat |= 1 << 2;                              /* ARDY */
104                 s->control &= ~(1 << 10);                       /* MST */
105             }
106         } else {
107             while (s->count_cur && s->rxlen < 4) {
108                 s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
109                 s->count_cur --;
110             }
111             if (s->rxlen)
112                 s->stat |= 1 << 3;                              /* RRDY */
113             else
114                 s->stat &= ~(1 << 3);                           /* RRDY */
115         }
116         if (!s->count_cur) {
117             if ((s->control >> 1) & 1) {                        /* STP */
118                 i2c_end_transfer(s->bus);
119                 s->control &= ~(1 << 1);                        /* STP */
120                 s->count_cur = s->count;
121                 s->txlen = 0;
122             } else {
123                 s->stat |= 1 << 2;                              /* ARDY */
124                 s->control &= ~(1 << 10);                       /* MST */
125             }
126         }
127     }
128
129     s->stat |= (!ack) << 1;                                     /* NACK */
130     if (!ack)
131         s->control &= ~(1 << 1);                                /* STP */
132 }
133
134 static void omap_i2c_reset(DeviceState *dev)
135 {
136     OMAPI2CState *s = OMAP_I2C(dev);
137
138     s->mask = 0;
139     s->stat = 0;
140     s->dma = 0;
141     s->count = 0;
142     s->count_cur = 0;
143     s->fifo = 0;
144     s->rxlen = 0;
145     s->txlen = 0;
146     s->control = 0;
147     s->addr[0] = 0;
148     s->addr[1] = 0;
149     s->divider = 0;
150     s->times[0] = 0;
151     s->times[1] = 0;
152     s->test = 0;
153 }
154
155 static uint32_t omap_i2c_read(void *opaque, hwaddr addr)
156 {
157     OMAPI2CState *s = opaque;
158     int offset = addr & OMAP_MPUI_REG_MASK;
159     uint16_t ret;
160
161     switch (offset) {
162     case 0x00:  /* I2C_REV */
163         return s->revision;                                     /* REV */
164
165     case 0x04:  /* I2C_IE */
166         return s->mask;
167
168     case 0x08:  /* I2C_STAT */
169         return s->stat | (i2c_bus_busy(s->bus) << 12);
170
171     case 0x0c:  /* I2C_IV */
172         if (s->revision >= OMAP2_INTR_REV)
173             break;
174         ret = ffs(s->stat & s->mask);
175         if (ret)
176             s->stat ^= 1 << (ret - 1);
177         omap_i2c_interrupts_update(s);
178         return ret;
179
180     case 0x10:  /* I2C_SYSS */
181         return (s->control >> 15) & 1;                          /* I2C_EN */
182
183     case 0x14:  /* I2C_BUF */
184         return s->dma;
185
186     case 0x18:  /* I2C_CNT */
187         return s->count_cur;                                    /* DCOUNT */
188
189     case 0x1c:  /* I2C_DATA */
190         ret = 0;
191         if (s->control & (1 << 14)) {                           /* BE */
192             ret |= ((s->fifo >> 0) & 0xff) << 8;
193             ret |= ((s->fifo >> 8) & 0xff) << 0;
194         } else {
195             ret |= ((s->fifo >> 8) & 0xff) << 8;
196             ret |= ((s->fifo >> 0) & 0xff) << 0;
197         }
198         if (s->rxlen == 1) {
199             s->stat |= 1 << 15;                                 /* SBD */
200             s->rxlen = 0;
201         } else if (s->rxlen > 1) {
202             if (s->rxlen > 2)
203                 s->fifo >>= 16;
204             s->rxlen -= 2;
205         } else {
206             /* XXX: remote access (qualifier) error - what's that?  */
207         }
208         if (!s->rxlen) {
209             s->stat &= ~(1 << 3);                               /* RRDY */
210             if (((s->control >> 10) & 1) &&                     /* MST */
211                             ((~s->control >> 9) & 1)) {         /* TRX */
212                 s->stat |= 1 << 2;                              /* ARDY */
213                 s->control &= ~(1 << 10);                       /* MST */
214             }
215         }
216         s->stat &= ~(1 << 11);                                  /* ROVR */
217         omap_i2c_fifo_run(s);
218         omap_i2c_interrupts_update(s);
219         return ret;
220
221     case 0x20:  /* I2C_SYSC */
222         return 0;
223
224     case 0x24:  /* I2C_CON */
225         return s->control;
226
227     case 0x28:  /* I2C_OA */
228         return s->addr[0];
229
230     case 0x2c:  /* I2C_SA */
231         return s->addr[1];
232
233     case 0x30:  /* I2C_PSC */
234         return s->divider;
235
236     case 0x34:  /* I2C_SCLL */
237         return s->times[0];
238
239     case 0x38:  /* I2C_SCLH */
240         return s->times[1];
241
242     case 0x3c:  /* I2C_SYSTEST */
243         if (s->test & (1 << 15)) {                              /* ST_EN */
244             s->test ^= 0xa;
245             return s->test;
246         } else
247             return s->test & ~0x300f;
248     }
249
250     OMAP_BAD_REG(addr);
251     return 0;
252 }
253
254 static void omap_i2c_write(void *opaque, hwaddr addr,
255                 uint32_t value)
256 {
257     OMAPI2CState *s = opaque;
258     int offset = addr & OMAP_MPUI_REG_MASK;
259     int nack;
260
261     switch (offset) {
262     case 0x00:  /* I2C_REV */
263     case 0x0c:  /* I2C_IV */
264     case 0x10:  /* I2C_SYSS */
265         OMAP_RO_REG(addr);
266         return;
267
268     case 0x04:  /* I2C_IE */
269         s->mask = value & (s->revision < OMAP2_GC_REV ? 0x1f : 0x3f);
270         break;
271
272     case 0x08:  /* I2C_STAT */
273         if (s->revision < OMAP2_INTR_REV) {
274             OMAP_RO_REG(addr);
275             return;
276         }
277
278         /* RRDY and XRDY are reset by hardware. (in all versions???) */
279         s->stat &= ~(value & 0x27);
280         omap_i2c_interrupts_update(s);
281         break;
282
283     case 0x14:  /* I2C_BUF */
284         s->dma = value & 0x8080;
285         if (value & (1 << 15))                                  /* RDMA_EN */
286             s->mask &= ~(1 << 3);                               /* RRDY_IE */
287         if (value & (1 << 7))                                   /* XDMA_EN */
288             s->mask &= ~(1 << 4);                               /* XRDY_IE */
289         break;
290
291     case 0x18:  /* I2C_CNT */
292         s->count = value;                                       /* DCOUNT */
293         break;
294
295     case 0x1c:  /* I2C_DATA */
296         if (s->txlen > 2) {
297             /* XXX: remote access (qualifier) error - what's that?  */
298             break;
299         }
300         s->fifo <<= 16;
301         s->txlen += 2;
302         if (s->control & (1 << 14)) {                           /* BE */
303             s->fifo |= ((value >> 8) & 0xff) << 8;
304             s->fifo |= ((value >> 0) & 0xff) << 0;
305         } else {
306             s->fifo |= ((value >> 0) & 0xff) << 8;
307             s->fifo |= ((value >> 8) & 0xff) << 0;
308         }
309         s->stat &= ~(1 << 10);                                  /* XUDF */
310         if (s->txlen > 2)
311             s->stat &= ~(1 << 4);                               /* XRDY */
312         omap_i2c_fifo_run(s);
313         omap_i2c_interrupts_update(s);
314         break;
315
316     case 0x20:  /* I2C_SYSC */
317         if (s->revision < OMAP2_INTR_REV) {
318             OMAP_BAD_REG(addr);
319             return;
320         }
321
322         if (value & 2) {
323             omap_i2c_reset(DEVICE(s));
324         }
325         break;
326
327     case 0x24:  /* I2C_CON */
328         s->control = value & 0xcf87;
329         if (~value & (1 << 15)) {                               /* I2C_EN */
330             if (s->revision < OMAP2_INTR_REV) {
331                 omap_i2c_reset(DEVICE(s));
332             }
333             break;
334         }
335         if ((value & (1 << 15)) && !(value & (1 << 10))) {      /* MST */
336             fprintf(stderr, "%s: I^2C slave mode not supported\n",
337                             __FUNCTION__);
338             break;
339         }
340         if ((value & (1 << 15)) && value & (1 << 8)) {          /* XA */
341             fprintf(stderr, "%s: 10-bit addressing mode not supported\n",
342                             __FUNCTION__);
343             break;
344         }
345         if ((value & (1 << 15)) && value & (1 << 0)) {          /* STT */
346             nack = !!i2c_start_transfer(s->bus, s->addr[1],     /* SA */
347                             (~value >> 9) & 1);                 /* TRX */
348             s->stat |= nack << 1;                               /* NACK */
349             s->control &= ~(1 << 0);                            /* STT */
350             s->fifo = 0;
351             if (nack)
352                 s->control &= ~(1 << 1);                        /* STP */
353             else {
354                 s->count_cur = s->count;
355                 omap_i2c_fifo_run(s);
356             }
357             omap_i2c_interrupts_update(s);
358         }
359         break;
360
361     case 0x28:  /* I2C_OA */
362         s->addr[0] = value & 0x3ff;
363         break;
364
365     case 0x2c:  /* I2C_SA */
366         s->addr[1] = value & 0x3ff;
367         break;
368
369     case 0x30:  /* I2C_PSC */
370         s->divider = value;
371         break;
372
373     case 0x34:  /* I2C_SCLL */
374         s->times[0] = value;
375         break;
376
377     case 0x38:  /* I2C_SCLH */
378         s->times[1] = value;
379         break;
380
381     case 0x3c:  /* I2C_SYSTEST */
382         s->test = value & 0xf80f;
383         if (value & (1 << 11))                                  /* SBB */
384             if (s->revision >= OMAP2_INTR_REV) {
385                 s->stat |= 0x3f;
386                 omap_i2c_interrupts_update(s);
387             }
388         if (value & (1 << 15))                                  /* ST_EN */
389             fprintf(stderr, "%s: System Test not supported\n", __FUNCTION__);
390         break;
391
392     default:
393         OMAP_BAD_REG(addr);
394         return;
395     }
396 }
397
398 static void omap_i2c_writeb(void *opaque, hwaddr addr,
399                 uint32_t value)
400 {
401     OMAPI2CState *s = opaque;
402     int offset = addr & OMAP_MPUI_REG_MASK;
403
404     switch (offset) {
405     case 0x1c:  /* I2C_DATA */
406         if (s->txlen > 2) {
407             /* XXX: remote access (qualifier) error - what's that?  */
408             break;
409         }
410         s->fifo <<= 8;
411         s->txlen += 1;
412         s->fifo |= value & 0xff;
413         s->stat &= ~(1 << 10);                                  /* XUDF */
414         if (s->txlen > 2)
415             s->stat &= ~(1 << 4);                               /* XRDY */
416         omap_i2c_fifo_run(s);
417         omap_i2c_interrupts_update(s);
418         break;
419
420     default:
421         OMAP_BAD_REG(addr);
422         return;
423     }
424 }
425
426 static const MemoryRegionOps omap_i2c_ops = {
427     .old_mmio = {
428         .read = {
429             omap_badwidth_read16,
430             omap_i2c_read,
431             omap_badwidth_read16,
432         },
433         .write = {
434             omap_i2c_writeb, /* Only the last fifo write can be 8 bit.  */
435             omap_i2c_write,
436             omap_badwidth_write16,
437         },
438     },
439     .endianness = DEVICE_NATIVE_ENDIAN,
440 };
441
442 static int omap_i2c_init(SysBusDevice *sbd)
443 {
444     DeviceState *dev = DEVICE(sbd);
445     OMAPI2CState *s = OMAP_I2C(dev);
446
447     if (!s->fclk) {
448         hw_error("omap_i2c: fclk not connected\n");
449     }
450     if (s->revision >= OMAP2_INTR_REV && !s->iclk) {
451         /* Note that OMAP1 doesn't have a separate interface clock */
452         hw_error("omap_i2c: iclk not connected\n");
453     }
454     sysbus_init_irq(sbd, &s->irq);
455     sysbus_init_irq(sbd, &s->drq[0]);
456     sysbus_init_irq(sbd, &s->drq[1]);
457     memory_region_init_io(&s->iomem, OBJECT(s), &omap_i2c_ops, s, "omap.i2c",
458                           (s->revision < OMAP2_INTR_REV) ? 0x800 : 0x1000);
459     sysbus_init_mmio(sbd, &s->iomem);
460     s->bus = i2c_init_bus(dev, NULL);
461     return 0;
462 }
463
464 static Property omap_i2c_properties[] = {
465     DEFINE_PROP_UINT8("revision", OMAPI2CState, revision, 0),
466     DEFINE_PROP_PTR("iclk", OMAPI2CState, iclk),
467     DEFINE_PROP_PTR("fclk", OMAPI2CState, fclk),
468     DEFINE_PROP_END_OF_LIST(),
469 };
470
471 static void omap_i2c_class_init(ObjectClass *klass, void *data)
472 {
473     DeviceClass *dc = DEVICE_CLASS(klass);
474     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
475     k->init = omap_i2c_init;
476     dc->props = omap_i2c_properties;
477     dc->reset = omap_i2c_reset;
478 }
479
480 static const TypeInfo omap_i2c_info = {
481     .name = TYPE_OMAP_I2C,
482     .parent = TYPE_SYS_BUS_DEVICE,
483     .instance_size = sizeof(OMAPI2CState),
484     .class_init = omap_i2c_class_init,
485 };
486
487 static void omap_i2c_register_types(void)
488 {
489     type_register_static(&omap_i2c_info);
490 }
491
492 i2c_bus *omap_i2c_bus(DeviceState *omap_i2c)
493 {
494     OMAPI2CState *s = OMAP_I2C(omap_i2c);
495     return s->bus;
496 }
497
498 type_init(omap_i2c_register_types)
This page took 0.065029 seconds and 4 git commands to generate.