Statistics
| Branch: | Revision:

root / hw / omap_i2c.c @ 0dad6c35

History | View | Annotate | Download (13.2 kB)

1
/*
2
 * TI OMAP on-chip I2C controller.  Only "new I2C" mode supported.
3
 *
4
 * Copyright (C) 2007 Andrzej Zaborowski  <balrog@zabor.org>
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
}