xref: /qemu/hw/i2c/omap_i2c.c (revision e3d08143)
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