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