Statistics
| Branch: | Revision:

root / hw / omap_i2c.c @ cf965d24

History | View | Annotate | Download (11.8 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
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
19
 * MA 02111-1307 USA
20
 */
21
#include "vl.h"
22

    
23
struct omap_i2c_s {
24
    target_phys_addr_t base;
25
    qemu_irq irq;
26
    qemu_irq drq[2];
27
    i2c_slave slave;
28
    i2c_bus *bus;
29

    
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
static void omap_i2c_interrupts_update(struct omap_i2c_s *s)
46
{
47
    qemu_set_irq(s->irq, s->stat & s->mask);
48
    if ((s->dma >> 15) & 1)                                        /* RDMA_EN */
49
        qemu_set_irq(s->drq[0], (s->stat >> 3) & 1);                /* RRDY */
50
    if ((s->dma >> 7) & 1)                                        /* XDMA_EN */
51
        qemu_set_irq(s->drq[1], (s->stat >> 4) & 1);                /* XRDY */
52
}
53

    
54
/* These are only stubs now.  */
55
static void omap_i2c_event(i2c_slave *i2c, enum i2c_event event)
56
{
57
    struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
58

    
59
    if ((~s->control >> 15) & 1)                                /* I2C_EN */
60
        return;
61

    
62
    switch (event) {
63
    case I2C_START_SEND:
64
    case I2C_START_RECV:
65
        s->stat |= 1 << 9;                                        /* AAS */
66
        break;
67
    case I2C_FINISH:
68
        s->stat |= 1 << 2;                                        /* ARDY */
69
        break;
70
    case I2C_NACK:
71
        s->stat |= 1 << 1;                                        /* NACK */
72
        break;
73
    }
74

    
75
    omap_i2c_interrupts_update(s);
76
}
77

    
78
static int omap_i2c_rx(i2c_slave *i2c)
79
{
80
    struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
81
    uint8_t ret = 0;
82

    
83
    if ((~s->control >> 15) & 1)                                /* I2C_EN */
84
        return -1;
85

    
86
    if (s->txlen)
87
        ret = s->fifo >> ((-- s->txlen) << 3) & 0xff;
88
    else
89
        s->stat |= 1 << 10;                                        /* XUDF */
90
    s->stat |= 1 << 4;                                                /* XRDY */
91

    
92
    omap_i2c_interrupts_update(s);
93
    return ret;
94
}
95

    
96
static int omap_i2c_tx(i2c_slave *i2c, uint8_t data)
97
{
98
    struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
99

    
100
    if ((~s->control >> 15) & 1)                                /* I2C_EN */
101
        return 1;
102

    
103
    if (s->rxlen < 4)
104
        s->fifo |= data << ((s->rxlen ++) << 3);
105
    else
106
        s->stat |= 1 << 11;                                        /* ROVR */
107
    s->stat |= 1 << 3;                                                /* RRDY */
108

    
109
    omap_i2c_interrupts_update(s);
110
    return 1;
111
}
112

    
113
static void omap_i2c_fifo_run(struct omap_i2c_s *s)
114
{
115
    int ack = 1;
116

    
117
    if (!i2c_bus_busy(s->bus))
118
        return;
119

    
120
    if ((s->control >> 2) & 1) {                                /* RM */
121
        if ((s->control >> 1) & 1) {                                /* STP */
122
            i2c_end_transfer(s->bus);
123
            s->control &= ~(1 << 1);                                /* STP */
124
            s->count_cur = s->count;
125
        } else if ((s->control >> 9) & 1) {                        /* TRX */
126
            while (ack && s->txlen)
127
                ack = (i2c_send(s->bus,
128
                                        (s->fifo >> ((-- s->txlen) << 3)) &
129
                                        0xff) >= 0);
130
            s->stat |= 1 << 4;                                        /* XRDY */
131
        } else {
132
            while (s->rxlen < 4)
133
                s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
134
            s->stat |= 1 << 3;                                        /* RRDY */
135
        }
136
    } else {
137
        if ((s->control >> 9) & 1) {                                /* TRX */
138
            while (ack && s->count_cur && s->txlen) {
139
                ack = (i2c_send(s->bus,
140
                                        (s->fifo >> ((-- s->txlen) << 3)) &
141
                                        0xff) >= 0);
142
                s->count_cur --;
143
            }
144
            if (ack && s->count_cur)
145
                s->stat |= 1 << 4;                                /* XRDY */
146
            if (!s->count_cur) {
147
                s->stat |= 1 << 2;                                /* ARDY */
148
                s->control &= ~(1 << 10);                        /* MST */
149
            }
150
        } else {
151
            while (s->count_cur && s->rxlen < 4) {
152
                s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
153
                s->count_cur --;
154
            }
155
            if (s->rxlen)
156
                s->stat |= 1 << 3;                                /* RRDY */
157
        }
158
        if (!s->count_cur) {
159
            if ((s->control >> 1) & 1) {                        /* STP */
160
                i2c_end_transfer(s->bus);
161
                s->control &= ~(1 << 1);                        /* STP */
162
                s->count_cur = s->count;
163
            } else {
164
                s->stat |= 1 << 2;                                /* ARDY */
165
                s->control &= ~(1 << 10);                        /* MST */
166
            }
167
        }
168
    }
169

    
170
    s->stat |= (!ack) << 1;                                        /* NACK */
171
    if (!ack)
172
        s->control &= ~(1 << 1);                                /* STP */
173
}
174

    
175
void omap_i2c_reset(struct omap_i2c_s *s)
176
{
177
    s->mask = 0;
178
    s->stat = 0;
179
    s->dma = 0;
180
    s->count = 0;
181
    s->count_cur = 0;
182
    s->fifo = 0;
183
    s->rxlen = 0;
184
    s->txlen = 0;
185
    s->control = 0;
186
    s->addr[0] = 0;
187
    s->addr[1] = 0;
188
    s->divider = 0;
189
    s->times[0] = 0;
190
    s->times[1] = 0;
191
    s->test = 0;
192
}
193

    
194
static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr)
195
{
196
    struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
197
    int offset = addr & OMAP_MPUI_REG_MASK;
198
    uint16_t ret;
199

    
200
    switch (offset) {
201
    case 0x00:        /* I2C_REV */
202
        /* TODO: set a value greater or equal to real hardware */
203
        return 0x11;                                                /* REV */
204

    
205
    case 0x04:        /* I2C_IE */
206
        return s->mask;
207

    
208
    case 0x08:        /* I2C_STAT */
209
        return s->stat | (i2c_bus_busy(s->bus) << 12);
210

    
211
    case 0x0c:        /* I2C_IV */
212
        ret = ffs(s->stat & s->mask);
213
        if (ret)
214
            s->stat ^= 1 << (ret - 1);
215
        omap_i2c_interrupts_update(s);
216
        return ret;
217

    
218
    case 0x14:        /* I2C_BUF */
219
        return s->dma;
220

    
221
    case 0x18:        /* I2C_CNT */
222
        return s->count_cur;                                        /* DCOUNT */
223

    
224
    case 0x1c:        /* I2C_DATA */
225
        ret = 0;
226
        if (s->control & (1 << 14)) {                                /* BE */
227
            ret |= ((s->fifo >> 0) & 0xff) << 8;
228
            ret |= ((s->fifo >> 8) & 0xff) << 0;
229
        } else {
230
            ret |= ((s->fifo >> 8) & 0xff) << 8;
231
            ret |= ((s->fifo >> 0) & 0xff) << 0;
232
        }
233
        if (s->rxlen == 1) {
234
            s->stat |= 1 << 15;                                        /* SBD */
235
            s->rxlen = 0;
236
        } else if (s->rxlen > 1) {
237
            if (s->rxlen > 2)
238
                s->fifo >>= 16;
239
            s->rxlen -= 2;
240
        } else
241
            /* XXX: remote access (qualifier) error - what's that?  */;
242
        if (!s->rxlen) {
243
            s->stat |= ~(1 << 3);                                /* RRDY */
244
            if (((s->control >> 10) & 1) &&                        /* MST */
245
                            ((~s->control >> 9) & 1)) {                /* TRX */
246
                s->stat |= 1 << 2;                                /* ARDY */
247
                s->control &= ~(1 << 10);                        /* MST */
248
            }
249
        }
250
        s->stat &= ~(1 << 11);                                        /* ROVR */
251
        omap_i2c_fifo_run(s);
252
        omap_i2c_interrupts_update(s);
253
        return ret;
254

    
255
    case 0x24:        /* I2C_CON */
256
        return s->control;
257

    
258
    case 0x28:        /* I2C_OA */
259
        return s->addr[0];
260

    
261
    case 0x2c:        /* I2C_SA */
262
        return s->addr[1];
263

    
264
    case 0x30:        /* I2C_PSC */
265
        return s->divider;
266

    
267
    case 0x34:        /* I2C_SCLL */
268
        return s->times[0];
269

    
270
    case 0x38:        /* I2C_SCLH */
271
        return s->times[1];
272

    
273
    case 0x3c:        /* I2C_SYSTEST */
274
        if (s->test & (1 << 15)) {                                /* ST_EN */
275
            s->test ^= 0xa;
276
            return s->test;
277
        } else
278
            return s->test & ~0x300f;
279
    }
280

    
281
    OMAP_BAD_REG(addr);
282
    return 0;
283
}
284

    
285
static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
286
                uint32_t value)
287
{
288
    struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
289
    int offset = addr & OMAP_MPUI_REG_MASK;
290
    int nack;
291

    
292
    switch (offset) {
293
    case 0x00:        /* I2C_REV */
294
    case 0x08:        /* I2C_STAT */
295
    case 0x0c:        /* I2C_IV */
296
        OMAP_BAD_REG(addr);
297
        return;
298

    
299
    case 0x04:        /* I2C_IE */
300
        s->mask = value & 0x1f;
301
        break;
302

    
303
    case 0x14:        /* I2C_BUF */
304
        s->dma = value & 0x8080;
305
        if (value & (1 << 15))                                        /* RDMA_EN */
306
            s->mask &= ~(1 << 3);                                /* RRDY_IE */
307
        if (value & (1 << 7))                                        /* XDMA_EN */
308
            s->mask &= ~(1 << 4);                                /* XRDY_IE */
309
        break;
310

    
311
    case 0x18:        /* I2C_CNT */
312
        s->count = value;                                        /* DCOUNT */
313
        break;
314

    
315
    case 0x1c:        /* I2C_DATA */
316
        if (s->txlen > 2) {
317
            /* XXX: remote access (qualifier) error - what's that?  */
318
            break;
319
        }
320
        s->fifo <<= 16;
321
        s->txlen += 2;
322
        if (s->control & (1 << 14)) {                                /* BE */
323
            s->fifo |= ((value >> 8) & 0xff) << 8;
324
            s->fifo |= ((value >> 0) & 0xff) << 0;
325
        } else {
326
            s->fifo |= ((value >> 0) & 0xff) << 8;
327
            s->fifo |= ((value >> 8) & 0xff) << 0;
328
        }
329
        s->stat &= ~(1 << 10);                                        /* XUDF */
330
        if (s->txlen > 2)
331
            s->stat &= ~(1 << 4);                                /* XRDY */
332
        omap_i2c_fifo_run(s);
333
        omap_i2c_interrupts_update(s);
334
        break;
335

    
336
    case 0x24:        /* I2C_CON */
337
        s->control = value & 0xcf07;
338
        if (~value & (1 << 15)) {                                /* I2C_EN */
339
            omap_i2c_reset(s);
340
            break;
341
        }
342
        if (~value & (1 << 10)) {                                /* MST */
343
            printf("%s: I^2C slave mode not supported\n", __FUNCTION__);
344
            break;
345
        }
346
        if (value & (1 << 9)) {                                        /* XA */
347
            printf("%s: 10-bit addressing mode not supported\n", __FUNCTION__);
348
            break;
349
        }
350
        if (value & (1 << 0)) {                                        /* STT */
351
            nack = !!i2c_start_transfer(s->bus, s->addr[1],        /* SA */
352
                            (~value >> 9) & 1);                        /* TRX */
353
            s->stat |= nack << 1;                                /* NACK */
354
            s->control &= ~(1 << 0);                                /* STT */
355
            if (nack)
356
                s->control &= ~(1 << 1);                        /* STP */
357
            else
358
                omap_i2c_fifo_run(s);
359
            omap_i2c_interrupts_update(s);
360
        }
361
        break;
362

    
363
    case 0x28:        /* I2C_OA */
364
        s->addr[0] = value & 0x3ff;
365
        i2c_set_slave_address(&s->slave, value & 0x7f);
366
        break;
367

    
368
    case 0x2c:        /* I2C_SA */
369
        s->addr[1] = value & 0x3ff;
370
        break;
371

    
372
    case 0x30:        /* I2C_PSC */
373
        s->divider = value;
374
        break;
375

    
376
    case 0x34:        /* I2C_SCLL */
377
        s->times[0] = value;
378
        break;
379

    
380
    case 0x38:        /* I2C_SCLH */
381
        s->times[1] = value;
382
        break;
383

    
384
    case 0x3c:        /* I2C_SYSTEST */
385
        s->test = value & 0xf00f;
386
        if (value & (1 << 15))                                        /* ST_EN */
387
            printf("%s: System Test not supported\n", __FUNCTION__);
388
        break;
389

    
390
    default:
391
        OMAP_BAD_REG(addr);
392
        return;
393
    }
394
}
395

    
396
static CPUReadMemoryFunc *omap_i2c_readfn[] = {
397
    omap_badwidth_read16,
398
    omap_i2c_read,
399
    omap_badwidth_read16,
400
};
401

    
402
static CPUWriteMemoryFunc *omap_i2c_writefn[] = {
403
    omap_badwidth_write16,
404
    omap_i2c_write,
405
    omap_i2c_write,        /* TODO: Only the last fifo write can be 8 bit.  */
406
};
407

    
408
struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
409
                qemu_irq irq, qemu_irq *dma, omap_clk clk)
410
{
411
    int iomemtype;
412
    struct omap_i2c_s *s = (struct omap_i2c_s *)
413
            qemu_mallocz(sizeof(struct omap_i2c_s));
414

    
415
    s->base = base;
416
    s->irq = irq;
417
    s->drq[0] = dma[0];
418
    s->drq[1] = dma[1];
419
    s->slave.event = omap_i2c_event;
420
    s->slave.recv = omap_i2c_rx;
421
    s->slave.send = omap_i2c_tx;
422
    s->bus = i2c_init_bus();
423
    omap_i2c_reset(s);
424

    
425
    iomemtype = cpu_register_io_memory(0, omap_i2c_readfn,
426
                    omap_i2c_writefn, s);
427
    cpu_register_physical_memory(s->base, 0x800, iomemtype);
428

    
429
    return s;
430
}
431

    
432
i2c_bus *omap_i2c_bus(struct omap_i2c_s *s)
433
{
434
    return s->bus;
435
}