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