153ed424eSPaolo Bonzini /*
253ed424eSPaolo Bonzini * TI OMAP on-chip I2C controller. Only "new I2C" mode supported.
353ed424eSPaolo Bonzini *
453ed424eSPaolo Bonzini * Copyright (C) 2007 Andrzej Zaborowski <balrog@zabor.org>
553ed424eSPaolo Bonzini *
653ed424eSPaolo Bonzini * This program is free software; you can redistribute it and/or
753ed424eSPaolo Bonzini * modify it under the terms of the GNU General Public License as
853ed424eSPaolo Bonzini * published by the Free Software Foundation; either version 2 of
953ed424eSPaolo Bonzini * the License, or (at your option) any later version.
1053ed424eSPaolo Bonzini *
1153ed424eSPaolo Bonzini * This program is distributed in the hope that it will be useful,
1253ed424eSPaolo Bonzini * but WITHOUT ANY WARRANTY; without even the implied warranty of
1353ed424eSPaolo Bonzini * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1453ed424eSPaolo Bonzini * GNU General Public License for more details.
1553ed424eSPaolo Bonzini *
1653ed424eSPaolo Bonzini * You should have received a copy of the GNU General Public License along
1753ed424eSPaolo Bonzini * with this program; if not, see <http://www.gnu.org/licenses/>.
1853ed424eSPaolo Bonzini */
190b8fa32fSMarkus Armbruster
2017b7f2dbSPeter Maydell #include "qemu/osdep.h"
218d2774f0SPhilippe Mathieu-Daudé #include "qemu/log.h"
220b8fa32fSMarkus Armbruster #include "qemu/module.h"
2353ed424eSPaolo Bonzini #include "hw/i2c/i2c.h"
2464552b6bSMarkus Armbruster #include "hw/irq.h"
25a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
2653ed424eSPaolo Bonzini #include "hw/arm/omap.h"
2753ed424eSPaolo Bonzini #include "hw/sysbus.h"
2884a3a53cSMarkus Armbruster #include "qemu/error-report.h"
29758aba7dSxiaoqiang zhao #include "qapi/error.h"
3053ed424eSPaolo Bonzini
310fd20c53SMarc-André Lureau struct OMAPI2CState {
3260ecfcb3SAndreas Färber SysBusDevice parent_obj;
3360ecfcb3SAndreas Färber
3453ed424eSPaolo Bonzini MemoryRegion iomem;
3553ed424eSPaolo Bonzini qemu_irq irq;
3653ed424eSPaolo Bonzini qemu_irq drq[2];
37a5c82852SAndreas Färber I2CBus *bus;
3853ed424eSPaolo Bonzini
3953ed424eSPaolo Bonzini uint8_t revision;
4053ed424eSPaolo Bonzini void *iclk;
4153ed424eSPaolo Bonzini void *fclk;
4253ed424eSPaolo Bonzini
4353ed424eSPaolo Bonzini uint8_t mask;
4453ed424eSPaolo Bonzini uint16_t stat;
4553ed424eSPaolo Bonzini uint16_t dma;
4653ed424eSPaolo Bonzini uint16_t count;
4753ed424eSPaolo Bonzini int count_cur;
4853ed424eSPaolo Bonzini uint32_t fifo;
4953ed424eSPaolo Bonzini int rxlen;
5053ed424eSPaolo Bonzini int txlen;
5153ed424eSPaolo Bonzini uint16_t control;
5253ed424eSPaolo Bonzini uint16_t addr[2];
5353ed424eSPaolo Bonzini uint8_t divider;
5453ed424eSPaolo Bonzini uint8_t times[2];
5553ed424eSPaolo Bonzini uint16_t test;
560fd20c53SMarc-André Lureau };
5753ed424eSPaolo Bonzini
5853ed424eSPaolo Bonzini #define OMAP2_INTR_REV 0x34
5953ed424eSPaolo Bonzini #define OMAP2_GC_REV 0x34
6053ed424eSPaolo Bonzini
omap_i2c_interrupts_update(OMAPI2CState * s)6153ed424eSPaolo Bonzini static void omap_i2c_interrupts_update(OMAPI2CState *s)
6253ed424eSPaolo Bonzini {
6353ed424eSPaolo Bonzini qemu_set_irq(s->irq, s->stat & s->mask);
6453ed424eSPaolo Bonzini if ((s->dma >> 15) & 1) /* RDMA_EN */
6553ed424eSPaolo Bonzini qemu_set_irq(s->drq[0], (s->stat >> 3) & 1); /* RRDY */
6653ed424eSPaolo Bonzini if ((s->dma >> 7) & 1) /* XDMA_EN */
6753ed424eSPaolo Bonzini qemu_set_irq(s->drq[1], (s->stat >> 4) & 1); /* XRDY */
6853ed424eSPaolo Bonzini }
6953ed424eSPaolo Bonzini
omap_i2c_fifo_run(OMAPI2CState * s)7053ed424eSPaolo Bonzini static void omap_i2c_fifo_run(OMAPI2CState *s)
7153ed424eSPaolo Bonzini {
7253ed424eSPaolo Bonzini int ack = 1;
7353ed424eSPaolo Bonzini
7453ed424eSPaolo Bonzini if (!i2c_bus_busy(s->bus))
7553ed424eSPaolo Bonzini return;
7653ed424eSPaolo Bonzini
7753ed424eSPaolo Bonzini if ((s->control >> 2) & 1) { /* RM */
7853ed424eSPaolo Bonzini if ((s->control >> 1) & 1) { /* STP */
7953ed424eSPaolo Bonzini i2c_end_transfer(s->bus);
8053ed424eSPaolo Bonzini s->control &= ~(1 << 1); /* STP */
8153ed424eSPaolo Bonzini s->count_cur = s->count;
8253ed424eSPaolo Bonzini s->txlen = 0;
8353ed424eSPaolo Bonzini } else if ((s->control >> 9) & 1) { /* TRX */
8453ed424eSPaolo Bonzini while (ack && s->txlen)
8553ed424eSPaolo Bonzini ack = (i2c_send(s->bus,
8653ed424eSPaolo Bonzini (s->fifo >> ((-- s->txlen) << 3)) &
8753ed424eSPaolo Bonzini 0xff) >= 0);
8853ed424eSPaolo Bonzini s->stat |= 1 << 4; /* XRDY */
8953ed424eSPaolo Bonzini } else {
9053ed424eSPaolo Bonzini while (s->rxlen < 4)
9153ed424eSPaolo Bonzini s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
9253ed424eSPaolo Bonzini s->stat |= 1 << 3; /* RRDY */
9353ed424eSPaolo Bonzini }
9453ed424eSPaolo Bonzini } else {
9553ed424eSPaolo Bonzini if ((s->control >> 9) & 1) { /* TRX */
9653ed424eSPaolo Bonzini while (ack && s->count_cur && s->txlen) {
9753ed424eSPaolo Bonzini ack = (i2c_send(s->bus,
9853ed424eSPaolo Bonzini (s->fifo >> ((-- s->txlen) << 3)) &
9953ed424eSPaolo Bonzini 0xff) >= 0);
10053ed424eSPaolo Bonzini s->count_cur --;
10153ed424eSPaolo Bonzini }
10253ed424eSPaolo Bonzini if (ack && s->count_cur)
10353ed424eSPaolo Bonzini s->stat |= 1 << 4; /* XRDY */
10453ed424eSPaolo Bonzini else
10553ed424eSPaolo Bonzini s->stat &= ~(1 << 4); /* XRDY */
10653ed424eSPaolo Bonzini if (!s->count_cur) {
10753ed424eSPaolo Bonzini s->stat |= 1 << 2; /* ARDY */
10853ed424eSPaolo Bonzini s->control &= ~(1 << 10); /* MST */
10953ed424eSPaolo Bonzini }
11053ed424eSPaolo Bonzini } else {
11153ed424eSPaolo Bonzini while (s->count_cur && s->rxlen < 4) {
11253ed424eSPaolo Bonzini s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
11353ed424eSPaolo Bonzini s->count_cur --;
11453ed424eSPaolo Bonzini }
11553ed424eSPaolo Bonzini if (s->rxlen)
11653ed424eSPaolo Bonzini s->stat |= 1 << 3; /* RRDY */
11753ed424eSPaolo Bonzini else
11853ed424eSPaolo Bonzini s->stat &= ~(1 << 3); /* RRDY */
11953ed424eSPaolo Bonzini }
12053ed424eSPaolo Bonzini if (!s->count_cur) {
12153ed424eSPaolo Bonzini if ((s->control >> 1) & 1) { /* STP */
12253ed424eSPaolo Bonzini i2c_end_transfer(s->bus);
12353ed424eSPaolo Bonzini s->control &= ~(1 << 1); /* STP */
12453ed424eSPaolo Bonzini s->count_cur = s->count;
12553ed424eSPaolo Bonzini s->txlen = 0;
12653ed424eSPaolo Bonzini } else {
12753ed424eSPaolo Bonzini s->stat |= 1 << 2; /* ARDY */
12853ed424eSPaolo Bonzini s->control &= ~(1 << 10); /* MST */
12953ed424eSPaolo Bonzini }
13053ed424eSPaolo Bonzini }
13153ed424eSPaolo Bonzini }
13253ed424eSPaolo Bonzini
13353ed424eSPaolo Bonzini s->stat |= (!ack) << 1; /* NACK */
13453ed424eSPaolo Bonzini if (!ack)
13553ed424eSPaolo Bonzini s->control &= ~(1 << 1); /* STP */
13653ed424eSPaolo Bonzini }
13753ed424eSPaolo Bonzini
omap_i2c_reset(DeviceState * dev)13853ed424eSPaolo Bonzini static void omap_i2c_reset(DeviceState *dev)
13953ed424eSPaolo Bonzini {
14060ecfcb3SAndreas Färber OMAPI2CState *s = OMAP_I2C(dev);
14160ecfcb3SAndreas Färber
14253ed424eSPaolo Bonzini s->mask = 0;
14353ed424eSPaolo Bonzini s->stat = 0;
14453ed424eSPaolo Bonzini s->dma = 0;
14553ed424eSPaolo Bonzini s->count = 0;
14653ed424eSPaolo Bonzini s->count_cur = 0;
14753ed424eSPaolo Bonzini s->fifo = 0;
14853ed424eSPaolo Bonzini s->rxlen = 0;
14953ed424eSPaolo Bonzini s->txlen = 0;
15053ed424eSPaolo Bonzini s->control = 0;
15153ed424eSPaolo Bonzini s->addr[0] = 0;
15253ed424eSPaolo Bonzini s->addr[1] = 0;
15353ed424eSPaolo Bonzini s->divider = 0;
15453ed424eSPaolo Bonzini s->times[0] = 0;
15553ed424eSPaolo Bonzini s->times[1] = 0;
15653ed424eSPaolo Bonzini s->test = 0;
15753ed424eSPaolo Bonzini }
15853ed424eSPaolo Bonzini
omap_i2c_read(void * opaque,hwaddr addr)15953ed424eSPaolo Bonzini static uint32_t omap_i2c_read(void *opaque, hwaddr addr)
16053ed424eSPaolo Bonzini {
16153ed424eSPaolo Bonzini OMAPI2CState *s = opaque;
16253ed424eSPaolo Bonzini int offset = addr & OMAP_MPUI_REG_MASK;
16353ed424eSPaolo Bonzini uint16_t ret;
16453ed424eSPaolo Bonzini
16553ed424eSPaolo Bonzini switch (offset) {
16653ed424eSPaolo Bonzini case 0x00: /* I2C_REV */
16753ed424eSPaolo Bonzini return s->revision; /* REV */
16853ed424eSPaolo Bonzini
16953ed424eSPaolo Bonzini case 0x04: /* I2C_IE */
17053ed424eSPaolo Bonzini return s->mask;
17153ed424eSPaolo Bonzini
17253ed424eSPaolo Bonzini case 0x08: /* I2C_STAT */
17353ed424eSPaolo Bonzini return s->stat | (i2c_bus_busy(s->bus) << 12);
17453ed424eSPaolo Bonzini
17553ed424eSPaolo Bonzini case 0x0c: /* I2C_IV */
17653ed424eSPaolo Bonzini if (s->revision >= OMAP2_INTR_REV)
17753ed424eSPaolo Bonzini break;
178bd2a8884SStefan Hajnoczi ret = ctz32(s->stat & s->mask);
179bd2a8884SStefan Hajnoczi if (ret != 32) {
180bd2a8884SStefan Hajnoczi s->stat ^= 1 << ret;
181bd2a8884SStefan Hajnoczi ret++;
182bd2a8884SStefan Hajnoczi } else {
183bd2a8884SStefan Hajnoczi ret = 0;
184bd2a8884SStefan Hajnoczi }
18553ed424eSPaolo Bonzini omap_i2c_interrupts_update(s);
18653ed424eSPaolo Bonzini return ret;
18753ed424eSPaolo Bonzini
18853ed424eSPaolo Bonzini case 0x10: /* I2C_SYSS */
18953ed424eSPaolo Bonzini return (s->control >> 15) & 1; /* I2C_EN */
19053ed424eSPaolo Bonzini
19153ed424eSPaolo Bonzini case 0x14: /* I2C_BUF */
19253ed424eSPaolo Bonzini return s->dma;
19353ed424eSPaolo Bonzini
19453ed424eSPaolo Bonzini case 0x18: /* I2C_CNT */
19553ed424eSPaolo Bonzini return s->count_cur; /* DCOUNT */
19653ed424eSPaolo Bonzini
19753ed424eSPaolo Bonzini case 0x1c: /* I2C_DATA */
19853ed424eSPaolo Bonzini ret = 0;
19953ed424eSPaolo Bonzini if (s->control & (1 << 14)) { /* BE */
20053ed424eSPaolo Bonzini ret |= ((s->fifo >> 0) & 0xff) << 8;
20153ed424eSPaolo Bonzini ret |= ((s->fifo >> 8) & 0xff) << 0;
20253ed424eSPaolo Bonzini } else {
20353ed424eSPaolo Bonzini ret |= ((s->fifo >> 8) & 0xff) << 8;
20453ed424eSPaolo Bonzini ret |= ((s->fifo >> 0) & 0xff) << 0;
20553ed424eSPaolo Bonzini }
20653ed424eSPaolo Bonzini if (s->rxlen == 1) {
20753ed424eSPaolo Bonzini s->stat |= 1 << 15; /* SBD */
20853ed424eSPaolo Bonzini s->rxlen = 0;
20953ed424eSPaolo Bonzini } else if (s->rxlen > 1) {
21053ed424eSPaolo Bonzini if (s->rxlen > 2)
21153ed424eSPaolo Bonzini s->fifo >>= 16;
21253ed424eSPaolo Bonzini s->rxlen -= 2;
21353ed424eSPaolo Bonzini } else {
21453ed424eSPaolo Bonzini /* XXX: remote access (qualifier) error - what's that? */
21553ed424eSPaolo Bonzini }
21653ed424eSPaolo Bonzini if (!s->rxlen) {
21753ed424eSPaolo Bonzini s->stat &= ~(1 << 3); /* RRDY */
21853ed424eSPaolo Bonzini if (((s->control >> 10) & 1) && /* MST */
21953ed424eSPaolo Bonzini ((~s->control >> 9) & 1)) { /* TRX */
22053ed424eSPaolo Bonzini s->stat |= 1 << 2; /* ARDY */
22153ed424eSPaolo Bonzini s->control &= ~(1 << 10); /* MST */
22253ed424eSPaolo Bonzini }
22353ed424eSPaolo Bonzini }
22453ed424eSPaolo Bonzini s->stat &= ~(1 << 11); /* ROVR */
22553ed424eSPaolo Bonzini omap_i2c_fifo_run(s);
22653ed424eSPaolo Bonzini omap_i2c_interrupts_update(s);
22753ed424eSPaolo Bonzini return ret;
22853ed424eSPaolo Bonzini
22953ed424eSPaolo Bonzini case 0x20: /* I2C_SYSC */
23053ed424eSPaolo Bonzini return 0;
23153ed424eSPaolo Bonzini
23253ed424eSPaolo Bonzini case 0x24: /* I2C_CON */
23353ed424eSPaolo Bonzini return s->control;
23453ed424eSPaolo Bonzini
23553ed424eSPaolo Bonzini case 0x28: /* I2C_OA */
23653ed424eSPaolo Bonzini return s->addr[0];
23753ed424eSPaolo Bonzini
23853ed424eSPaolo Bonzini case 0x2c: /* I2C_SA */
23953ed424eSPaolo Bonzini return s->addr[1];
24053ed424eSPaolo Bonzini
24153ed424eSPaolo Bonzini case 0x30: /* I2C_PSC */
24253ed424eSPaolo Bonzini return s->divider;
24353ed424eSPaolo Bonzini
24453ed424eSPaolo Bonzini case 0x34: /* I2C_SCLL */
24553ed424eSPaolo Bonzini return s->times[0];
24653ed424eSPaolo Bonzini
24753ed424eSPaolo Bonzini case 0x38: /* I2C_SCLH */
24853ed424eSPaolo Bonzini return s->times[1];
24953ed424eSPaolo Bonzini
25053ed424eSPaolo Bonzini case 0x3c: /* I2C_SYSTEST */
25153ed424eSPaolo Bonzini if (s->test & (1 << 15)) { /* ST_EN */
25253ed424eSPaolo Bonzini s->test ^= 0xa;
25353ed424eSPaolo Bonzini return s->test;
25453ed424eSPaolo Bonzini } else
25553ed424eSPaolo Bonzini return s->test & ~0x300f;
25653ed424eSPaolo Bonzini }
25753ed424eSPaolo Bonzini
25853ed424eSPaolo Bonzini OMAP_BAD_REG(addr);
25953ed424eSPaolo Bonzini return 0;
26053ed424eSPaolo Bonzini }
26153ed424eSPaolo Bonzini
omap_i2c_write(void * opaque,hwaddr addr,uint32_t value)26253ed424eSPaolo Bonzini static void omap_i2c_write(void *opaque, hwaddr addr,
26353ed424eSPaolo Bonzini uint32_t value)
26453ed424eSPaolo Bonzini {
26553ed424eSPaolo Bonzini OMAPI2CState *s = opaque;
26653ed424eSPaolo Bonzini int offset = addr & OMAP_MPUI_REG_MASK;
26753ed424eSPaolo Bonzini int nack;
26853ed424eSPaolo Bonzini
26953ed424eSPaolo Bonzini switch (offset) {
27053ed424eSPaolo Bonzini case 0x00: /* I2C_REV */
27153ed424eSPaolo Bonzini case 0x0c: /* I2C_IV */
27253ed424eSPaolo Bonzini case 0x10: /* I2C_SYSS */
27353ed424eSPaolo Bonzini OMAP_RO_REG(addr);
27453ed424eSPaolo Bonzini return;
27553ed424eSPaolo Bonzini
27653ed424eSPaolo Bonzini case 0x04: /* I2C_IE */
27753ed424eSPaolo Bonzini s->mask = value & (s->revision < OMAP2_GC_REV ? 0x1f : 0x3f);
27853ed424eSPaolo Bonzini break;
27953ed424eSPaolo Bonzini
28053ed424eSPaolo Bonzini case 0x08: /* I2C_STAT */
28153ed424eSPaolo Bonzini if (s->revision < OMAP2_INTR_REV) {
28253ed424eSPaolo Bonzini OMAP_RO_REG(addr);
28353ed424eSPaolo Bonzini return;
28453ed424eSPaolo Bonzini }
28553ed424eSPaolo Bonzini
28653ed424eSPaolo Bonzini /* RRDY and XRDY are reset by hardware. (in all versions???) */
28753ed424eSPaolo Bonzini s->stat &= ~(value & 0x27);
28853ed424eSPaolo Bonzini omap_i2c_interrupts_update(s);
28953ed424eSPaolo Bonzini break;
29053ed424eSPaolo Bonzini
29153ed424eSPaolo Bonzini case 0x14: /* I2C_BUF */
29253ed424eSPaolo Bonzini s->dma = value & 0x8080;
29353ed424eSPaolo Bonzini if (value & (1 << 15)) /* RDMA_EN */
29453ed424eSPaolo Bonzini s->mask &= ~(1 << 3); /* RRDY_IE */
29553ed424eSPaolo Bonzini if (value & (1 << 7)) /* XDMA_EN */
29653ed424eSPaolo Bonzini s->mask &= ~(1 << 4); /* XRDY_IE */
29753ed424eSPaolo Bonzini break;
29853ed424eSPaolo Bonzini
29953ed424eSPaolo Bonzini case 0x18: /* I2C_CNT */
30053ed424eSPaolo Bonzini s->count = value; /* DCOUNT */
30153ed424eSPaolo Bonzini break;
30253ed424eSPaolo Bonzini
30353ed424eSPaolo Bonzini case 0x1c: /* I2C_DATA */
30453ed424eSPaolo Bonzini if (s->txlen > 2) {
30553ed424eSPaolo Bonzini /* XXX: remote access (qualifier) error - what's that? */
30653ed424eSPaolo Bonzini break;
30753ed424eSPaolo Bonzini }
30853ed424eSPaolo Bonzini s->fifo <<= 16;
30953ed424eSPaolo Bonzini s->txlen += 2;
31053ed424eSPaolo Bonzini if (s->control & (1 << 14)) { /* BE */
31153ed424eSPaolo Bonzini s->fifo |= ((value >> 8) & 0xff) << 8;
31253ed424eSPaolo Bonzini s->fifo |= ((value >> 0) & 0xff) << 0;
31353ed424eSPaolo Bonzini } else {
31453ed424eSPaolo Bonzini s->fifo |= ((value >> 0) & 0xff) << 8;
31553ed424eSPaolo Bonzini s->fifo |= ((value >> 8) & 0xff) << 0;
31653ed424eSPaolo Bonzini }
31753ed424eSPaolo Bonzini s->stat &= ~(1 << 10); /* XUDF */
31853ed424eSPaolo Bonzini if (s->txlen > 2)
31953ed424eSPaolo Bonzini s->stat &= ~(1 << 4); /* XRDY */
32053ed424eSPaolo Bonzini omap_i2c_fifo_run(s);
32153ed424eSPaolo Bonzini omap_i2c_interrupts_update(s);
32253ed424eSPaolo Bonzini break;
32353ed424eSPaolo Bonzini
32453ed424eSPaolo Bonzini case 0x20: /* I2C_SYSC */
32553ed424eSPaolo Bonzini if (s->revision < OMAP2_INTR_REV) {
32653ed424eSPaolo Bonzini OMAP_BAD_REG(addr);
32753ed424eSPaolo Bonzini return;
32853ed424eSPaolo Bonzini }
32953ed424eSPaolo Bonzini
33060ecfcb3SAndreas Färber if (value & 2) {
33160ecfcb3SAndreas Färber omap_i2c_reset(DEVICE(s));
33260ecfcb3SAndreas Färber }
33353ed424eSPaolo Bonzini break;
33453ed424eSPaolo Bonzini
33553ed424eSPaolo Bonzini case 0x24: /* I2C_CON */
33653ed424eSPaolo Bonzini s->control = value & 0xcf87;
33753ed424eSPaolo Bonzini if (~value & (1 << 15)) { /* I2C_EN */
33860ecfcb3SAndreas Färber if (s->revision < OMAP2_INTR_REV) {
33960ecfcb3SAndreas Färber omap_i2c_reset(DEVICE(s));
34060ecfcb3SAndreas Färber }
34153ed424eSPaolo Bonzini break;
34253ed424eSPaolo Bonzini }
34353ed424eSPaolo Bonzini if ((value & (1 << 15)) && !(value & (1 << 10))) { /* MST */
3448d2774f0SPhilippe Mathieu-Daudé qemu_log_mask(LOG_UNIMP, "%s: I^2C slave mode not supported\n",
345a89f364aSAlistair Francis __func__);
34653ed424eSPaolo Bonzini break;
34753ed424eSPaolo Bonzini }
34853ed424eSPaolo Bonzini if ((value & (1 << 15)) && value & (1 << 8)) { /* XA */
3498d2774f0SPhilippe Mathieu-Daudé qemu_log_mask(LOG_UNIMP,
3508d2774f0SPhilippe Mathieu-Daudé "%s: 10-bit addressing mode not supported\n",
351a89f364aSAlistair Francis __func__);
35253ed424eSPaolo Bonzini break;
35353ed424eSPaolo Bonzini }
35453ed424eSPaolo Bonzini if ((value & (1 << 15)) && value & (1 << 0)) { /* STT */
35553ed424eSPaolo Bonzini nack = !!i2c_start_transfer(s->bus, s->addr[1], /* SA */
35653ed424eSPaolo Bonzini (~value >> 9) & 1); /* TRX */
35753ed424eSPaolo Bonzini s->stat |= nack << 1; /* NACK */
35853ed424eSPaolo Bonzini s->control &= ~(1 << 0); /* STT */
35953ed424eSPaolo Bonzini s->fifo = 0;
36053ed424eSPaolo Bonzini if (nack)
36153ed424eSPaolo Bonzini s->control &= ~(1 << 1); /* STP */
36253ed424eSPaolo Bonzini else {
36353ed424eSPaolo Bonzini s->count_cur = s->count;
36453ed424eSPaolo Bonzini omap_i2c_fifo_run(s);
36553ed424eSPaolo Bonzini }
36653ed424eSPaolo Bonzini omap_i2c_interrupts_update(s);
36753ed424eSPaolo Bonzini }
36853ed424eSPaolo Bonzini break;
36953ed424eSPaolo Bonzini
37053ed424eSPaolo Bonzini case 0x28: /* I2C_OA */
37153ed424eSPaolo Bonzini s->addr[0] = value & 0x3ff;
37253ed424eSPaolo Bonzini break;
37353ed424eSPaolo Bonzini
37453ed424eSPaolo Bonzini case 0x2c: /* I2C_SA */
37553ed424eSPaolo Bonzini s->addr[1] = value & 0x3ff;
37653ed424eSPaolo Bonzini break;
37753ed424eSPaolo Bonzini
37853ed424eSPaolo Bonzini case 0x30: /* I2C_PSC */
37953ed424eSPaolo Bonzini s->divider = value;
38053ed424eSPaolo Bonzini break;
38153ed424eSPaolo Bonzini
38253ed424eSPaolo Bonzini case 0x34: /* I2C_SCLL */
38353ed424eSPaolo Bonzini s->times[0] = value;
38453ed424eSPaolo Bonzini break;
38553ed424eSPaolo Bonzini
38653ed424eSPaolo Bonzini case 0x38: /* I2C_SCLH */
38753ed424eSPaolo Bonzini s->times[1] = value;
38853ed424eSPaolo Bonzini break;
38953ed424eSPaolo Bonzini
39053ed424eSPaolo Bonzini case 0x3c: /* I2C_SYSTEST */
39153ed424eSPaolo Bonzini s->test = value & 0xf80f;
39253ed424eSPaolo Bonzini if (value & (1 << 11)) /* SBB */
39353ed424eSPaolo Bonzini if (s->revision >= OMAP2_INTR_REV) {
39453ed424eSPaolo Bonzini s->stat |= 0x3f;
39553ed424eSPaolo Bonzini omap_i2c_interrupts_update(s);
39653ed424eSPaolo Bonzini }
3978d2774f0SPhilippe Mathieu-Daudé if (value & (1 << 15)) { /* ST_EN */
3988d2774f0SPhilippe Mathieu-Daudé qemu_log_mask(LOG_UNIMP,
3998d2774f0SPhilippe Mathieu-Daudé "%s: System Test not supported\n", __func__);
4008d2774f0SPhilippe Mathieu-Daudé }
40153ed424eSPaolo Bonzini break;
40253ed424eSPaolo Bonzini
40353ed424eSPaolo Bonzini default:
40453ed424eSPaolo Bonzini OMAP_BAD_REG(addr);
40553ed424eSPaolo Bonzini return;
40653ed424eSPaolo Bonzini }
40753ed424eSPaolo Bonzini }
40853ed424eSPaolo Bonzini
omap_i2c_writeb(void * opaque,hwaddr addr,uint32_t value)40953ed424eSPaolo Bonzini static void omap_i2c_writeb(void *opaque, hwaddr addr,
41053ed424eSPaolo Bonzini uint32_t value)
41153ed424eSPaolo Bonzini {
41253ed424eSPaolo Bonzini OMAPI2CState *s = opaque;
41353ed424eSPaolo Bonzini int offset = addr & OMAP_MPUI_REG_MASK;
41453ed424eSPaolo Bonzini
41553ed424eSPaolo Bonzini switch (offset) {
41653ed424eSPaolo Bonzini case 0x1c: /* I2C_DATA */
41753ed424eSPaolo Bonzini if (s->txlen > 2) {
41853ed424eSPaolo Bonzini /* XXX: remote access (qualifier) error - what's that? */
41953ed424eSPaolo Bonzini break;
42053ed424eSPaolo Bonzini }
42153ed424eSPaolo Bonzini s->fifo <<= 8;
42253ed424eSPaolo Bonzini s->txlen += 1;
42353ed424eSPaolo Bonzini s->fifo |= value & 0xff;
42453ed424eSPaolo Bonzini s->stat &= ~(1 << 10); /* XUDF */
42553ed424eSPaolo Bonzini if (s->txlen > 2)
42653ed424eSPaolo Bonzini s->stat &= ~(1 << 4); /* XRDY */
42753ed424eSPaolo Bonzini omap_i2c_fifo_run(s);
42853ed424eSPaolo Bonzini omap_i2c_interrupts_update(s);
42953ed424eSPaolo Bonzini break;
43053ed424eSPaolo Bonzini
43153ed424eSPaolo Bonzini default:
43253ed424eSPaolo Bonzini OMAP_BAD_REG(addr);
43353ed424eSPaolo Bonzini return;
43453ed424eSPaolo Bonzini }
43553ed424eSPaolo Bonzini }
43653ed424eSPaolo Bonzini
omap_i2c_readfn(void * opaque,hwaddr addr,unsigned size)43728dc207fSPeter Maydell static uint64_t omap_i2c_readfn(void *opaque, hwaddr addr,
43828dc207fSPeter Maydell unsigned size)
43928dc207fSPeter Maydell {
44028dc207fSPeter Maydell switch (size) {
44128dc207fSPeter Maydell case 2:
44228dc207fSPeter Maydell return omap_i2c_read(opaque, addr);
44328dc207fSPeter Maydell default:
44428dc207fSPeter Maydell return omap_badwidth_read16(opaque, addr);
44528dc207fSPeter Maydell }
44628dc207fSPeter Maydell }
44728dc207fSPeter Maydell
omap_i2c_writefn(void * opaque,hwaddr addr,uint64_t value,unsigned size)44828dc207fSPeter Maydell static void omap_i2c_writefn(void *opaque, hwaddr addr,
44928dc207fSPeter Maydell uint64_t value, unsigned size)
45028dc207fSPeter Maydell {
45128dc207fSPeter Maydell switch (size) {
45228dc207fSPeter Maydell case 1:
45328dc207fSPeter Maydell /* Only the last fifo write can be 8 bit. */
45428dc207fSPeter Maydell omap_i2c_writeb(opaque, addr, value);
45528dc207fSPeter Maydell break;
45628dc207fSPeter Maydell case 2:
45728dc207fSPeter Maydell omap_i2c_write(opaque, addr, value);
45828dc207fSPeter Maydell break;
45928dc207fSPeter Maydell default:
46028dc207fSPeter Maydell omap_badwidth_write16(opaque, addr, value);
46128dc207fSPeter Maydell break;
46228dc207fSPeter Maydell }
46328dc207fSPeter Maydell }
46428dc207fSPeter Maydell
46553ed424eSPaolo Bonzini static const MemoryRegionOps omap_i2c_ops = {
46628dc207fSPeter Maydell .read = omap_i2c_readfn,
46728dc207fSPeter Maydell .write = omap_i2c_writefn,
46828dc207fSPeter Maydell .valid.min_access_size = 1,
46928dc207fSPeter Maydell .valid.max_access_size = 4,
47053ed424eSPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
47153ed424eSPaolo Bonzini };
47253ed424eSPaolo Bonzini
omap_i2c_init(Object * obj)473758aba7dSxiaoqiang zhao static void omap_i2c_init(Object *obj)
47453ed424eSPaolo Bonzini {
475758aba7dSxiaoqiang zhao DeviceState *dev = DEVICE(obj);
476758aba7dSxiaoqiang zhao OMAPI2CState *s = OMAP_I2C(obj);
477758aba7dSxiaoqiang zhao SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
47884a3a53cSMarkus Armbruster
47960ecfcb3SAndreas Färber sysbus_init_irq(sbd, &s->irq);
48060ecfcb3SAndreas Färber sysbus_init_irq(sbd, &s->drq[0]);
48160ecfcb3SAndreas Färber sysbus_init_irq(sbd, &s->drq[1]);
48260ecfcb3SAndreas Färber sysbus_init_mmio(sbd, &s->iomem);
48360ecfcb3SAndreas Färber s->bus = i2c_init_bus(dev, NULL);
484758aba7dSxiaoqiang zhao }
485758aba7dSxiaoqiang zhao
omap_i2c_realize(DeviceState * dev,Error ** errp)486758aba7dSxiaoqiang zhao static void omap_i2c_realize(DeviceState *dev, Error **errp)
487758aba7dSxiaoqiang zhao {
488758aba7dSxiaoqiang zhao OMAPI2CState *s = OMAP_I2C(dev);
489758aba7dSxiaoqiang zhao
490758aba7dSxiaoqiang zhao memory_region_init_io(&s->iomem, OBJECT(dev), &omap_i2c_ops, s, "omap.i2c",
491758aba7dSxiaoqiang zhao (s->revision < OMAP2_INTR_REV) ? 0x800 : 0x1000);
492758aba7dSxiaoqiang zhao
493758aba7dSxiaoqiang zhao if (!s->fclk) {
494758aba7dSxiaoqiang zhao error_setg(errp, "omap_i2c: fclk not connected");
495758aba7dSxiaoqiang zhao return;
496758aba7dSxiaoqiang zhao }
497758aba7dSxiaoqiang zhao if (s->revision >= OMAP2_INTR_REV && !s->iclk) {
498758aba7dSxiaoqiang zhao /* Note that OMAP1 doesn't have a separate interface clock */
499758aba7dSxiaoqiang zhao error_setg(errp, "omap_i2c: iclk not connected");
500758aba7dSxiaoqiang zhao return;
501758aba7dSxiaoqiang zhao }
50253ed424eSPaolo Bonzini }
50353ed424eSPaolo Bonzini
omap_i2c_set_iclk(OMAPI2CState * i2c,omap_clk clk)5040fd20c53SMarc-André Lureau void omap_i2c_set_iclk(OMAPI2CState *i2c, omap_clk clk)
5050fd20c53SMarc-André Lureau {
5060fd20c53SMarc-André Lureau i2c->iclk = clk;
5070fd20c53SMarc-André Lureau }
5080fd20c53SMarc-André Lureau
omap_i2c_set_fclk(OMAPI2CState * i2c,omap_clk clk)5090fd20c53SMarc-André Lureau void omap_i2c_set_fclk(OMAPI2CState *i2c, omap_clk clk)
5100fd20c53SMarc-André Lureau {
5110fd20c53SMarc-André Lureau i2c->fclk = clk;
5120fd20c53SMarc-André Lureau }
5130fd20c53SMarc-André Lureau
51453ed424eSPaolo Bonzini static Property omap_i2c_properties[] = {
51553ed424eSPaolo Bonzini DEFINE_PROP_UINT8("revision", OMAPI2CState, revision, 0),
51653ed424eSPaolo Bonzini DEFINE_PROP_END_OF_LIST(),
51753ed424eSPaolo Bonzini };
51853ed424eSPaolo Bonzini
omap_i2c_class_init(ObjectClass * klass,void * data)51953ed424eSPaolo Bonzini static void omap_i2c_class_init(ObjectClass *klass, void *data)
52053ed424eSPaolo Bonzini {
52153ed424eSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
522758aba7dSxiaoqiang zhao
5234f67d30bSMarc-André Lureau device_class_set_props(dc, omap_i2c_properties);
524*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, omap_i2c_reset);
5251b111dc1SMarkus Armbruster /* Reason: pointer properties "iclk", "fclk" */
526e90f2a8cSEduardo Habkost dc->user_creatable = false;
527758aba7dSxiaoqiang zhao dc->realize = omap_i2c_realize;
52853ed424eSPaolo Bonzini }
52953ed424eSPaolo Bonzini
53053ed424eSPaolo Bonzini static const TypeInfo omap_i2c_info = {
53160ecfcb3SAndreas Färber .name = TYPE_OMAP_I2C,
53253ed424eSPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE,
53353ed424eSPaolo Bonzini .instance_size = sizeof(OMAPI2CState),
534758aba7dSxiaoqiang zhao .instance_init = omap_i2c_init,
53553ed424eSPaolo Bonzini .class_init = omap_i2c_class_init,
53653ed424eSPaolo Bonzini };
53753ed424eSPaolo Bonzini
omap_i2c_register_types(void)53853ed424eSPaolo Bonzini static void omap_i2c_register_types(void)
53953ed424eSPaolo Bonzini {
54053ed424eSPaolo Bonzini type_register_static(&omap_i2c_info);
54153ed424eSPaolo Bonzini }
54253ed424eSPaolo Bonzini
omap_i2c_bus(DeviceState * omap_i2c)543a5c82852SAndreas Färber I2CBus *omap_i2c_bus(DeviceState *omap_i2c)
54453ed424eSPaolo Bonzini {
54560ecfcb3SAndreas Färber OMAPI2CState *s = OMAP_I2C(omap_i2c);
54653ed424eSPaolo Bonzini return s->bus;
54753ed424eSPaolo Bonzini }
54853ed424eSPaolo Bonzini
54953ed424eSPaolo Bonzini type_init(omap_i2c_register_types)
550