]> git.proxmox.com Git - mirror_qemu.git/blame - hw/i2c/omap_i2c.c
qdev: Replace cannot_instantiate_with_device_add_yet with !user_creatable
[mirror_qemu.git] / hw / i2c / omap_i2c.c
CommitLineData
02645926
AZ
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 *
fad6cb1a 16 * You should have received a copy of the GNU General Public License along
8167ee88 17 * with this program; if not, see <http://www.gnu.org/licenses/>.
02645926 18 */
17b7f2db 19#include "qemu/osdep.h"
83c9f4ca 20#include "hw/hw.h"
0d09e41a
PB
21#include "hw/i2c/i2c.h"
22#include "hw/arm/omap.h"
83c9f4ca 23#include "hw/sysbus.h"
84a3a53c 24#include "qemu/error-report.h"
758aba7d 25#include "qapi/error.h"
02645926 26
60ecfcb3
AF
27#define TYPE_OMAP_I2C "omap_i2c"
28#define OMAP_I2C(obj) OBJECT_CHECK(OMAPI2CState, (obj), TYPE_OMAP_I2C)
54e17933
JR
29
30typedef struct OMAPI2CState {
60ecfcb3
AF
31 SysBusDevice parent_obj;
32
74878139 33 MemoryRegion iomem;
02645926
AZ
34 qemu_irq irq;
35 qemu_irq drq[2];
a5c82852 36 I2CBus *bus;
02645926 37
29885477 38 uint8_t revision;
54e17933
JR
39 void *iclk;
40 void *fclk;
41
02645926
AZ
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;
54e17933 55} OMAPI2CState;
02645926 56
29885477
AZ
57#define OMAP2_INTR_REV 0x34
58#define OMAP2_GC_REV 0x34
59
54e17933 60static void omap_i2c_interrupts_update(OMAPI2CState *s)
02645926
AZ
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
54e17933 69static void omap_i2c_fifo_run(OMAPI2CState *s)
02645926
AZ
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;
29885477 81 s->txlen = 0;
02645926
AZ
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 */
827df9f3
AZ
103 else
104 s->stat &= ~(1 << 4); /* XRDY */
02645926
AZ
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 */
827df9f3
AZ
116 else
117 s->stat &= ~(1 << 3); /* RRDY */
02645926
AZ
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;
29885477 124 s->txlen = 0;
02645926
AZ
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
54e17933 137static void omap_i2c_reset(DeviceState *dev)
02645926 138{
60ecfcb3
AF
139 OMAPI2CState *s = OMAP_I2C(dev);
140
02645926
AZ
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
a8170e5e 158static uint32_t omap_i2c_read(void *opaque, hwaddr addr)
02645926 159{
54e17933 160 OMAPI2CState *s = opaque;
cf965d24 161 int offset = addr & OMAP_MPUI_REG_MASK;
02645926
AZ
162 uint16_t ret;
163
164 switch (offset) {
165 case 0x00: /* I2C_REV */
29885477 166 return s->revision; /* REV */
02645926
AZ
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 */
29885477
AZ
175 if (s->revision >= OMAP2_INTR_REV)
176 break;
bd2a8884
SH
177 ret = ctz32(s->stat & s->mask);
178 if (ret != 32) {
179 s->stat ^= 1 << ret;
180 ret++;
181 } else {
182 ret = 0;
183 }
02645926
AZ
184 omap_i2c_interrupts_update(s);
185 return ret;
186
29885477
AZ
187 case 0x10: /* I2C_SYSS */
188 return (s->control >> 15) & 1; /* I2C_EN */
189
02645926
AZ
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;
3ffd710e
BS
212 } else {
213 /* XXX: remote access (qualifier) error - what's that? */
214 }
02645926 215 if (!s->rxlen) {
29885477 216 s->stat &= ~(1 << 3); /* RRDY */
02645926
AZ
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
29885477
AZ
228 case 0x20: /* I2C_SYSC */
229 return 0;
230
02645926
AZ
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
a8170e5e 261static void omap_i2c_write(void *opaque, hwaddr addr,
02645926
AZ
262 uint32_t value)
263{
54e17933 264 OMAPI2CState *s = opaque;
cf965d24 265 int offset = addr & OMAP_MPUI_REG_MASK;
02645926
AZ
266 int nack;
267
268 switch (offset) {
269 case 0x00: /* I2C_REV */
02645926 270 case 0x0c: /* I2C_IV */
29885477
AZ
271 case 0x10: /* I2C_SYSS */
272 OMAP_RO_REG(addr);
02645926
AZ
273 return;
274
275 case 0x04: /* I2C_IE */
29885477
AZ
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
827df9f3
AZ
285 /* RRDY and XRDY are reset by hardware. (in all versions???) */
286 s->stat &= ~(value & 0x27);
29885477 287 omap_i2c_interrupts_update(s);
02645926
AZ
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
29885477
AZ
323 case 0x20: /* I2C_SYSC */
324 if (s->revision < OMAP2_INTR_REV) {
325 OMAP_BAD_REG(addr);
326 return;
327 }
328
60ecfcb3
AF
329 if (value & 2) {
330 omap_i2c_reset(DEVICE(s));
331 }
29885477
AZ
332 break;
333
02645926 334 case 0x24: /* I2C_CON */
29885477 335 s->control = value & 0xcf87;
02645926 336 if (~value & (1 << 15)) { /* I2C_EN */
60ecfcb3
AF
337 if (s->revision < OMAP2_INTR_REV) {
338 omap_i2c_reset(DEVICE(s));
339 }
02645926
AZ
340 break;
341 }
29885477 342 if ((value & (1 << 15)) && !(value & (1 << 10))) { /* MST */
827df9f3
AZ
343 fprintf(stderr, "%s: I^2C slave mode not supported\n",
344 __FUNCTION__);
02645926
AZ
345 break;
346 }
29885477 347 if ((value & (1 << 15)) && value & (1 << 8)) { /* XA */
827df9f3
AZ
348 fprintf(stderr, "%s: 10-bit addressing mode not supported\n",
349 __FUNCTION__);
02645926
AZ
350 break;
351 }
29885477 352 if ((value & (1 << 15)) && value & (1 << 0)) { /* STT */
02645926
AZ
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 */
51fec3cc 357 s->fifo = 0;
02645926
AZ
358 if (nack)
359 s->control &= ~(1 << 1); /* STP */
29885477
AZ
360 else {
361 s->count_cur = s->count;
02645926 362 omap_i2c_fifo_run(s);
29885477 363 }
02645926
AZ
364 omap_i2c_interrupts_update(s);
365 }
366 break;
367
368 case 0x28: /* I2C_OA */
369 s->addr[0] = value & 0x3ff;
02645926
AZ
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 */
29885477
AZ
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 }
02645926 395 if (value & (1 << 15)) /* ST_EN */
827df9f3 396 fprintf(stderr, "%s: System Test not supported\n", __FUNCTION__);
02645926
AZ
397 break;
398
399 default:
400 OMAP_BAD_REG(addr);
401 return;
402 }
403}
404
a8170e5e 405static void omap_i2c_writeb(void *opaque, hwaddr addr,
29885477
AZ
406 uint32_t value)
407{
54e17933 408 OMAPI2CState *s = opaque;
29885477
AZ
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
74878139
BC
433static 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,
02645926
AZ
447};
448
758aba7d
XZ
449static 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
462static void omap_i2c_realize(DeviceState *dev, Error **errp)
02645926 463{
60ecfcb3 464 OMAPI2CState *s = OMAP_I2C(dev);
02645926 465
758aba7d
XZ
466 memory_region_init_io(&s->iomem, OBJECT(dev), &omap_i2c_ops, s, "omap.i2c",
467 (s->revision < OMAP2_INTR_REV) ? 0x800 : 0x1000);
468
54e17933 469 if (!s->fclk) {
758aba7d
XZ
470 error_setg(errp, "omap_i2c: fclk not connected");
471 return;
54e17933
JR
472 }
473 if (s->revision >= OMAP2_INTR_REV && !s->iclk) {
474 /* Note that OMAP1 doesn't have a separate interface clock */
758aba7d
XZ
475 error_setg(errp, "omap_i2c: iclk not connected");
476 return;
54e17933 477 }
02645926
AZ
478}
479
54e17933
JR
480static 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};
29885477 486
54e17933
JR
487static void omap_i2c_class_init(ObjectClass *klass, void *data)
488{
489 DeviceClass *dc = DEVICE_CLASS(klass);
758aba7d 490
54e17933
JR
491 dc->props = omap_i2c_properties;
492 dc->reset = omap_i2c_reset;
1b111dc1 493 /* Reason: pointer properties "iclk", "fclk" */
e90f2a8c 494 dc->user_creatable = false;
758aba7d 495 dc->realize = omap_i2c_realize;
54e17933 496}
29885477 497
8c43a6f0 498static const TypeInfo omap_i2c_info = {
60ecfcb3 499 .name = TYPE_OMAP_I2C,
54e17933
JR
500 .parent = TYPE_SYS_BUS_DEVICE,
501 .instance_size = sizeof(OMAPI2CState),
758aba7d 502 .instance_init = omap_i2c_init,
54e17933
JR
503 .class_init = omap_i2c_class_init,
504};
29885477 505
54e17933
JR
506static void omap_i2c_register_types(void)
507{
508 type_register_static(&omap_i2c_info);
29885477
AZ
509}
510
a5c82852 511I2CBus *omap_i2c_bus(DeviceState *omap_i2c)
02645926 512{
60ecfcb3 513 OMAPI2CState *s = OMAP_I2C(omap_i2c);
02645926
AZ
514 return s->bus;
515}
54e17933
JR
516
517type_init(omap_i2c_register_types)