Statistics
| Branch: | Revision:

root / hw / omap_i2c.c @ 02e2da45

History | View | Annotate | Download (13 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, write to the Free Software Foundation, Inc.,
18
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
 */
20
#include "hw.h"
21
#include "i2c.h"
22
#include "omap.h"
23

    
24
struct omap_i2c_s {
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
        if (!s->rxlen) {
197
            s->stat &= ~(1 << 3);                                /* RRDY */
198
            if (((s->control >> 10) & 1) &&                        /* MST */
199
                            ((~s->control >> 9) & 1)) {                /* TRX */
200
                s->stat |= 1 << 2;                                /* ARDY */
201
                s->control &= ~(1 << 10);                        /* MST */
202
            }
203
        }
204
        s->stat &= ~(1 << 11);                                        /* ROVR */
205
        omap_i2c_fifo_run(s);
206
        omap_i2c_interrupts_update(s);
207
        return ret;
208

    
209
    case 0x20:        /* I2C_SYSC */
210
        return 0;
211

    
212
    case 0x24:        /* I2C_CON */
213
        return s->control;
214

    
215
    case 0x28:        /* I2C_OA */
216
        return s->addr[0];
217

    
218
    case 0x2c:        /* I2C_SA */
219
        return s->addr[1];
220

    
221
    case 0x30:        /* I2C_PSC */
222
        return s->divider;
223

    
224
    case 0x34:        /* I2C_SCLL */
225
        return s->times[0];
226

    
227
    case 0x38:        /* I2C_SCLH */
228
        return s->times[1];
229

    
230
    case 0x3c:        /* I2C_SYSTEST */
231
        if (s->test & (1 << 15)) {                                /* ST_EN */
232
            s->test ^= 0xa;
233
            return s->test;
234
        } else
235
            return s->test & ~0x300f;
236
    }
237

    
238
    OMAP_BAD_REG(addr);
239
    return 0;
240
}
241

    
242
static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
243
                uint32_t value)
244
{
245
    struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
246
    int offset = addr & OMAP_MPUI_REG_MASK;
247
    int nack;
248

    
249
    switch (offset) {
250
    case 0x00:        /* I2C_REV */
251
    case 0x0c:        /* I2C_IV */
252
    case 0x10:        /* I2C_SYSS */
253
        OMAP_RO_REG(addr);
254
        return;
255

    
256
    case 0x04:        /* I2C_IE */
257
        s->mask = value & (s->revision < OMAP2_GC_REV ? 0x1f : 0x3f);
258
        break;
259

    
260
    case 0x08:        /* I2C_STAT */
261
        if (s->revision < OMAP2_INTR_REV) {
262
            OMAP_RO_REG(addr);
263
            return;
264
        }
265

    
266
        /* RRDY and XRDY are reset by hardware. (in all versions???) */
267
        s->stat &= ~(value & 0x27);
268
        omap_i2c_interrupts_update(s);
269
        break;
270

    
271
    case 0x14:        /* I2C_BUF */
272
        s->dma = value & 0x8080;
273
        if (value & (1 << 15))                                        /* RDMA_EN */
274
            s->mask &= ~(1 << 3);                                /* RRDY_IE */
275
        if (value & (1 << 7))                                        /* XDMA_EN */
276
            s->mask &= ~(1 << 4);                                /* XRDY_IE */
277
        break;
278

    
279
    case 0x18:        /* I2C_CNT */
280
        s->count = value;                                        /* DCOUNT */
281
        break;
282

    
283
    case 0x1c:        /* I2C_DATA */
284
        if (s->txlen > 2) {
285
            /* XXX: remote access (qualifier) error - what's that?  */
286
            break;
287
        }
288
        s->fifo <<= 16;
289
        s->txlen += 2;
290
        if (s->control & (1 << 14)) {                                /* BE */
291
            s->fifo |= ((value >> 8) & 0xff) << 8;
292
            s->fifo |= ((value >> 0) & 0xff) << 0;
293
        } else {
294
            s->fifo |= ((value >> 0) & 0xff) << 8;
295
            s->fifo |= ((value >> 8) & 0xff) << 0;
296
        }
297
        s->stat &= ~(1 << 10);                                        /* XUDF */
298
        if (s->txlen > 2)
299
            s->stat &= ~(1 << 4);                                /* XRDY */
300
        omap_i2c_fifo_run(s);
301
        omap_i2c_interrupts_update(s);
302
        break;
303

    
304
    case 0x20:        /* I2C_SYSC */
305
        if (s->revision < OMAP2_INTR_REV) {
306
            OMAP_BAD_REG(addr);
307
            return;
308
        }
309

    
310
        if (value & 2)
311
            omap_i2c_reset(s);
312
        break;
313

    
314
    case 0x24:        /* I2C_CON */
315
        s->control = value & 0xcf87;
316
        if (~value & (1 << 15)) {                                /* I2C_EN */
317
            if (s->revision < OMAP2_INTR_REV)
318
                omap_i2c_reset(s);
319
            break;
320
        }
321
        if ((value & (1 << 15)) && !(value & (1 << 10))) {        /* MST */
322
            fprintf(stderr, "%s: I^2C slave mode not supported\n",
323
                            __FUNCTION__);
324
            break;
325
        }
326
        if ((value & (1 << 15)) && value & (1 << 8)) {                /* XA */
327
            fprintf(stderr, "%s: 10-bit addressing mode not supported\n",
328
                            __FUNCTION__);
329
            break;
330
        }
331
        if ((value & (1 << 15)) && value & (1 << 0)) {                /* STT */
332
            nack = !!i2c_start_transfer(s->bus, s->addr[1],        /* SA */
333
                            (~value >> 9) & 1);                        /* TRX */
334
            s->stat |= nack << 1;                                /* NACK */
335
            s->control &= ~(1 << 0);                                /* STT */
336
            s->fifo = 0;
337
            if (nack)
338
                s->control &= ~(1 << 1);                        /* STP */
339
            else {
340
                s->count_cur = s->count;
341
                omap_i2c_fifo_run(s);
342
            }
343
            omap_i2c_interrupts_update(s);
344
        }
345
        break;
346

    
347
    case 0x28:        /* I2C_OA */
348
        s->addr[0] = value & 0x3ff;
349
        break;
350

    
351
    case 0x2c:        /* I2C_SA */
352
        s->addr[1] = value & 0x3ff;
353
        break;
354

    
355
    case 0x30:        /* I2C_PSC */
356
        s->divider = value;
357
        break;
358

    
359
    case 0x34:        /* I2C_SCLL */
360
        s->times[0] = value;
361
        break;
362

    
363
    case 0x38:        /* I2C_SCLH */
364
        s->times[1] = value;
365
        break;
366

    
367
    case 0x3c:        /* I2C_SYSTEST */
368
        s->test = value & 0xf80f;
369
        if (value & (1 << 11))                                        /* SBB */
370
            if (s->revision >= OMAP2_INTR_REV) {
371
                s->stat |= 0x3f;
372
                omap_i2c_interrupts_update(s);
373
            }
374
        if (value & (1 << 15))                                        /* ST_EN */
375
            fprintf(stderr, "%s: System Test not supported\n", __FUNCTION__);
376
        break;
377

    
378
    default:
379
        OMAP_BAD_REG(addr);
380
        return;
381
    }
382
}
383

    
384
static void omap_i2c_writeb(void *opaque, target_phys_addr_t addr,
385
                uint32_t value)
386
{
387
    struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
388
    int offset = addr & OMAP_MPUI_REG_MASK;
389

    
390
    switch (offset) {
391
    case 0x1c:        /* I2C_DATA */
392
        if (s->txlen > 2) {
393
            /* XXX: remote access (qualifier) error - what's that?  */
394
            break;
395
        }
396
        s->fifo <<= 8;
397
        s->txlen += 1;
398
        s->fifo |= value & 0xff;
399
        s->stat &= ~(1 << 10);                                        /* XUDF */
400
        if (s->txlen > 2)
401
            s->stat &= ~(1 << 4);                                /* XRDY */
402
        omap_i2c_fifo_run(s);
403
        omap_i2c_interrupts_update(s);
404
        break;
405

    
406
    default:
407
        OMAP_BAD_REG(addr);
408
        return;
409
    }
410
}
411

    
412
static CPUReadMemoryFunc *omap_i2c_readfn[] = {
413
    omap_badwidth_read16,
414
    omap_i2c_read,
415
    omap_badwidth_read16,
416
};
417

    
418
static CPUWriteMemoryFunc *omap_i2c_writefn[] = {
419
    omap_i2c_writeb,        /* Only the last fifo write can be 8 bit.  */
420
    omap_i2c_write,
421
    omap_badwidth_write16,
422
};
423

    
424
struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
425
                qemu_irq irq, qemu_irq *dma, omap_clk clk)
426
{
427
    int iomemtype;
428
    struct omap_i2c_s *s = (struct omap_i2c_s *)
429
            qemu_mallocz(sizeof(struct omap_i2c_s));
430

    
431
    /* TODO: set a value greater or equal to real hardware */
432
    s->revision = 0x11;
433
    s->irq = irq;
434
    s->drq[0] = dma[0];
435
    s->drq[1] = dma[1];
436
    s->bus = i2c_init_bus(NULL, "i2c");
437
    omap_i2c_reset(s);
438

    
439
    iomemtype = cpu_register_io_memory(0, omap_i2c_readfn,
440
                    omap_i2c_writefn, s);
441
    cpu_register_physical_memory(base, 0x800, iomemtype);
442

    
443
    return s;
444
}
445

    
446
struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta,
447
                qemu_irq irq, qemu_irq *dma, omap_clk fclk, omap_clk iclk)
448
{
449
    int iomemtype;
450
    struct omap_i2c_s *s = (struct omap_i2c_s *)
451
            qemu_mallocz(sizeof(struct omap_i2c_s));
452

    
453
    s->revision = 0x34;
454
    s->irq = irq;
455
    s->drq[0] = dma[0];
456
    s->drq[1] = dma[1];
457
    s->bus = i2c_init_bus(NULL, "i2c");
458
    omap_i2c_reset(s);
459

    
460
    iomemtype = l4_register_io_memory(0, omap_i2c_readfn,
461
                    omap_i2c_writefn, s);
462
    omap_l4_attach(ta, 0, iomemtype);
463

    
464
    return s;
465
}
466

    
467
i2c_bus *omap_i2c_bus(struct omap_i2c_s *s)
468
{
469
    return s->bus;
470
}