19be8a82cSStrahinja Jankovic /*
29be8a82cSStrahinja Jankovic * Allwinner I2C Bus Serial Interface Emulation
39be8a82cSStrahinja Jankovic *
49be8a82cSStrahinja Jankovic * Copyright (C) 2022 Strahinja Jankovic <strahinja.p.jankovic@gmail.com>
59be8a82cSStrahinja Jankovic *
69be8a82cSStrahinja Jankovic * This file is derived from IMX I2C controller,
79be8a82cSStrahinja Jankovic * by Jean-Christophe DUBOIS .
89be8a82cSStrahinja Jankovic *
99be8a82cSStrahinja Jankovic * This program is free software; you can redistribute it and/or modify it
109be8a82cSStrahinja Jankovic * under the terms of the GNU General Public License as published by the
119be8a82cSStrahinja Jankovic * Free Software Foundation; either version 2 of the License, or
129be8a82cSStrahinja Jankovic * (at your option) any later version.
139be8a82cSStrahinja Jankovic *
149be8a82cSStrahinja Jankovic * This program is distributed in the hope that it will be useful, but WITHOUT
159be8a82cSStrahinja Jankovic * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
169be8a82cSStrahinja Jankovic * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
179be8a82cSStrahinja Jankovic * for more details.
189be8a82cSStrahinja Jankovic *
199be8a82cSStrahinja Jankovic * You should have received a copy of the GNU General Public License along
209be8a82cSStrahinja Jankovic * with this program; if not, see <http://www.gnu.org/licenses/>.
219be8a82cSStrahinja Jankovic *
229be8a82cSStrahinja Jankovic * SPDX-License-Identifier: MIT
239be8a82cSStrahinja Jankovic */
249be8a82cSStrahinja Jankovic
259be8a82cSStrahinja Jankovic #include "qemu/osdep.h"
269be8a82cSStrahinja Jankovic #include "hw/i2c/allwinner-i2c.h"
279be8a82cSStrahinja Jankovic #include "hw/irq.h"
289be8a82cSStrahinja Jankovic #include "migration/vmstate.h"
299be8a82cSStrahinja Jankovic #include "hw/i2c/i2c.h"
309be8a82cSStrahinja Jankovic #include "qemu/log.h"
319be8a82cSStrahinja Jankovic #include "trace.h"
329be8a82cSStrahinja Jankovic #include "qemu/module.h"
339be8a82cSStrahinja Jankovic
349be8a82cSStrahinja Jankovic /* Allwinner I2C memory map */
359be8a82cSStrahinja Jankovic #define TWI_ADDR_REG 0x00 /* slave address register */
369be8a82cSStrahinja Jankovic #define TWI_XADDR_REG 0x04 /* extended slave address register */
379be8a82cSStrahinja Jankovic #define TWI_DATA_REG 0x08 /* data register */
389be8a82cSStrahinja Jankovic #define TWI_CNTR_REG 0x0c /* control register */
399be8a82cSStrahinja Jankovic #define TWI_STAT_REG 0x10 /* status register */
409be8a82cSStrahinja Jankovic #define TWI_CCR_REG 0x14 /* clock control register */
419be8a82cSStrahinja Jankovic #define TWI_SRST_REG 0x18 /* software reset register */
429be8a82cSStrahinja Jankovic #define TWI_EFR_REG 0x1c /* enhance feature register */
439be8a82cSStrahinja Jankovic #define TWI_LCR_REG 0x20 /* line control register */
449be8a82cSStrahinja Jankovic
459be8a82cSStrahinja Jankovic /* Used only in slave mode, do not set */
469be8a82cSStrahinja Jankovic #define TWI_ADDR_RESET 0
479be8a82cSStrahinja Jankovic #define TWI_XADDR_RESET 0
489be8a82cSStrahinja Jankovic
499be8a82cSStrahinja Jankovic /* Data register */
509be8a82cSStrahinja Jankovic #define TWI_DATA_MASK 0xFF
519be8a82cSStrahinja Jankovic #define TWI_DATA_RESET 0
529be8a82cSStrahinja Jankovic
539be8a82cSStrahinja Jankovic /* Control register */
549be8a82cSStrahinja Jankovic #define TWI_CNTR_INT_EN (1 << 7)
559be8a82cSStrahinja Jankovic #define TWI_CNTR_BUS_EN (1 << 6)
569be8a82cSStrahinja Jankovic #define TWI_CNTR_M_STA (1 << 5)
579be8a82cSStrahinja Jankovic #define TWI_CNTR_M_STP (1 << 4)
589be8a82cSStrahinja Jankovic #define TWI_CNTR_INT_FLAG (1 << 3)
599be8a82cSStrahinja Jankovic #define TWI_CNTR_A_ACK (1 << 2)
609be8a82cSStrahinja Jankovic #define TWI_CNTR_MASK 0xFC
619be8a82cSStrahinja Jankovic #define TWI_CNTR_RESET 0
629be8a82cSStrahinja Jankovic
639be8a82cSStrahinja Jankovic /* Status register */
649be8a82cSStrahinja Jankovic #define TWI_STAT_MASK 0xF8
659be8a82cSStrahinja Jankovic #define TWI_STAT_RESET 0xF8
669be8a82cSStrahinja Jankovic
679be8a82cSStrahinja Jankovic /* Clock register */
689be8a82cSStrahinja Jankovic #define TWI_CCR_CLK_M_MASK 0x78
699be8a82cSStrahinja Jankovic #define TWI_CCR_CLK_N_MASK 0x07
709be8a82cSStrahinja Jankovic #define TWI_CCR_MASK 0x7F
719be8a82cSStrahinja Jankovic #define TWI_CCR_RESET 0
729be8a82cSStrahinja Jankovic
739be8a82cSStrahinja Jankovic /* Soft reset */
749be8a82cSStrahinja Jankovic #define TWI_SRST_MASK 0x01
759be8a82cSStrahinja Jankovic #define TWI_SRST_RESET 0
769be8a82cSStrahinja Jankovic
779be8a82cSStrahinja Jankovic /* Enhance feature */
789be8a82cSStrahinja Jankovic #define TWI_EFR_MASK 0x03
799be8a82cSStrahinja Jankovic #define TWI_EFR_RESET 0
809be8a82cSStrahinja Jankovic
819be8a82cSStrahinja Jankovic /* Line control */
829be8a82cSStrahinja Jankovic #define TWI_LCR_SCL_STATE (1 << 5)
839be8a82cSStrahinja Jankovic #define TWI_LCR_SDA_STATE (1 << 4)
849be8a82cSStrahinja Jankovic #define TWI_LCR_SCL_CTL (1 << 3)
859be8a82cSStrahinja Jankovic #define TWI_LCR_SCL_CTL_EN (1 << 2)
869be8a82cSStrahinja Jankovic #define TWI_LCR_SDA_CTL (1 << 1)
879be8a82cSStrahinja Jankovic #define TWI_LCR_SDA_CTL_EN (1 << 0)
889be8a82cSStrahinja Jankovic #define TWI_LCR_MASK 0x3F
899be8a82cSStrahinja Jankovic #define TWI_LCR_RESET 0x3A
909be8a82cSStrahinja Jankovic
919be8a82cSStrahinja Jankovic /* Status value in STAT register is shifted by 3 bits */
929be8a82cSStrahinja Jankovic #define TWI_STAT_SHIFT 3
939be8a82cSStrahinja Jankovic #define STAT_FROM_STA(x) ((x) << TWI_STAT_SHIFT)
949be8a82cSStrahinja Jankovic #define STAT_TO_STA(x) ((x) >> TWI_STAT_SHIFT)
959be8a82cSStrahinja Jankovic
969be8a82cSStrahinja Jankovic enum {
979be8a82cSStrahinja Jankovic STAT_BUS_ERROR = 0,
989be8a82cSStrahinja Jankovic /* Master mode */
999be8a82cSStrahinja Jankovic STAT_M_STA_TX,
1009be8a82cSStrahinja Jankovic STAT_M_RSTA_TX,
1019be8a82cSStrahinja Jankovic STAT_M_ADDR_WR_ACK,
1029be8a82cSStrahinja Jankovic STAT_M_ADDR_WR_NACK,
1039be8a82cSStrahinja Jankovic STAT_M_DATA_TX_ACK,
1049be8a82cSStrahinja Jankovic STAT_M_DATA_TX_NACK,
1059be8a82cSStrahinja Jankovic STAT_M_ARB_LOST,
1069be8a82cSStrahinja Jankovic STAT_M_ADDR_RD_ACK,
1079be8a82cSStrahinja Jankovic STAT_M_ADDR_RD_NACK,
1089be8a82cSStrahinja Jankovic STAT_M_DATA_RX_ACK,
1099be8a82cSStrahinja Jankovic STAT_M_DATA_RX_NACK,
1109be8a82cSStrahinja Jankovic /* Slave mode */
1119be8a82cSStrahinja Jankovic STAT_S_ADDR_WR_ACK,
1129be8a82cSStrahinja Jankovic STAT_S_ARB_LOST_AW_ACK,
1139be8a82cSStrahinja Jankovic STAT_S_GCA_ACK,
1149be8a82cSStrahinja Jankovic STAT_S_ARB_LOST_GCA_ACK,
1159be8a82cSStrahinja Jankovic STAT_S_DATA_RX_SA_ACK,
1169be8a82cSStrahinja Jankovic STAT_S_DATA_RX_SA_NACK,
1179be8a82cSStrahinja Jankovic STAT_S_DATA_RX_GCA_ACK,
1189be8a82cSStrahinja Jankovic STAT_S_DATA_RX_GCA_NACK,
1199be8a82cSStrahinja Jankovic STAT_S_STP_RSTA,
1209be8a82cSStrahinja Jankovic STAT_S_ADDR_RD_ACK,
1219be8a82cSStrahinja Jankovic STAT_S_ARB_LOST_AR_ACK,
1229be8a82cSStrahinja Jankovic STAT_S_DATA_TX_ACK,
1239be8a82cSStrahinja Jankovic STAT_S_DATA_TX_NACK,
1249be8a82cSStrahinja Jankovic STAT_S_LB_TX_ACK,
1259be8a82cSStrahinja Jankovic /* Master mode, 10-bit */
1269be8a82cSStrahinja Jankovic STAT_M_2ND_ADDR_WR_ACK,
1279be8a82cSStrahinja Jankovic STAT_M_2ND_ADDR_WR_NACK,
1289be8a82cSStrahinja Jankovic /* Idle */
1299be8a82cSStrahinja Jankovic STAT_IDLE = 0x1f
1309be8a82cSStrahinja Jankovic } TWI_STAT_STA;
1319be8a82cSStrahinja Jankovic
allwinner_i2c_get_regname(unsigned offset)1329be8a82cSStrahinja Jankovic static const char *allwinner_i2c_get_regname(unsigned offset)
1339be8a82cSStrahinja Jankovic {
1349be8a82cSStrahinja Jankovic switch (offset) {
1359be8a82cSStrahinja Jankovic case TWI_ADDR_REG:
1369be8a82cSStrahinja Jankovic return "ADDR";
1379be8a82cSStrahinja Jankovic case TWI_XADDR_REG:
1389be8a82cSStrahinja Jankovic return "XADDR";
1399be8a82cSStrahinja Jankovic case TWI_DATA_REG:
1409be8a82cSStrahinja Jankovic return "DATA";
1419be8a82cSStrahinja Jankovic case TWI_CNTR_REG:
1429be8a82cSStrahinja Jankovic return "CNTR";
1439be8a82cSStrahinja Jankovic case TWI_STAT_REG:
1449be8a82cSStrahinja Jankovic return "STAT";
1459be8a82cSStrahinja Jankovic case TWI_CCR_REG:
1469be8a82cSStrahinja Jankovic return "CCR";
1479be8a82cSStrahinja Jankovic case TWI_SRST_REG:
1489be8a82cSStrahinja Jankovic return "SRST";
1499be8a82cSStrahinja Jankovic case TWI_EFR_REG:
1509be8a82cSStrahinja Jankovic return "EFR";
1519be8a82cSStrahinja Jankovic case TWI_LCR_REG:
1529be8a82cSStrahinja Jankovic return "LCR";
1539be8a82cSStrahinja Jankovic default:
1549be8a82cSStrahinja Jankovic return "[?]";
1559be8a82cSStrahinja Jankovic }
1569be8a82cSStrahinja Jankovic }
1579be8a82cSStrahinja Jankovic
allwinner_i2c_is_reset(AWI2CState * s)1589be8a82cSStrahinja Jankovic static inline bool allwinner_i2c_is_reset(AWI2CState *s)
1599be8a82cSStrahinja Jankovic {
1609be8a82cSStrahinja Jankovic return s->srst & TWI_SRST_MASK;
1619be8a82cSStrahinja Jankovic }
1629be8a82cSStrahinja Jankovic
allwinner_i2c_bus_is_enabled(AWI2CState * s)1639be8a82cSStrahinja Jankovic static inline bool allwinner_i2c_bus_is_enabled(AWI2CState *s)
1649be8a82cSStrahinja Jankovic {
1659be8a82cSStrahinja Jankovic return s->cntr & TWI_CNTR_BUS_EN;
1669be8a82cSStrahinja Jankovic }
1679be8a82cSStrahinja Jankovic
allwinner_i2c_interrupt_is_enabled(AWI2CState * s)1689be8a82cSStrahinja Jankovic static inline bool allwinner_i2c_interrupt_is_enabled(AWI2CState *s)
1699be8a82cSStrahinja Jankovic {
1709be8a82cSStrahinja Jankovic return s->cntr & TWI_CNTR_INT_EN;
1719be8a82cSStrahinja Jankovic }
1729be8a82cSStrahinja Jankovic
allwinner_i2c_reset_hold(Object * obj,ResetType type)173*ad80e367SPeter Maydell static void allwinner_i2c_reset_hold(Object *obj, ResetType type)
1749be8a82cSStrahinja Jankovic {
1759be8a82cSStrahinja Jankovic AWI2CState *s = AW_I2C(obj);
1769be8a82cSStrahinja Jankovic
1779be8a82cSStrahinja Jankovic if (STAT_TO_STA(s->stat) != STAT_IDLE) {
1789be8a82cSStrahinja Jankovic i2c_end_transfer(s->bus);
1799be8a82cSStrahinja Jankovic }
1809be8a82cSStrahinja Jankovic
1819be8a82cSStrahinja Jankovic s->addr = TWI_ADDR_RESET;
1829be8a82cSStrahinja Jankovic s->xaddr = TWI_XADDR_RESET;
1839be8a82cSStrahinja Jankovic s->data = TWI_DATA_RESET;
1849be8a82cSStrahinja Jankovic s->cntr = TWI_CNTR_RESET;
1859be8a82cSStrahinja Jankovic s->stat = TWI_STAT_RESET;
1869be8a82cSStrahinja Jankovic s->ccr = TWI_CCR_RESET;
1879be8a82cSStrahinja Jankovic s->srst = TWI_SRST_RESET;
1889be8a82cSStrahinja Jankovic s->efr = TWI_EFR_RESET;
1899be8a82cSStrahinja Jankovic s->lcr = TWI_LCR_RESET;
1909be8a82cSStrahinja Jankovic }
1919be8a82cSStrahinja Jankovic
allwinner_i2c_raise_interrupt(AWI2CState * s)1929be8a82cSStrahinja Jankovic static inline void allwinner_i2c_raise_interrupt(AWI2CState *s)
1939be8a82cSStrahinja Jankovic {
1949be8a82cSStrahinja Jankovic /*
1959be8a82cSStrahinja Jankovic * Raise an interrupt if the device is not reset and it is configured
1969be8a82cSStrahinja Jankovic * to generate some interrupts.
1979be8a82cSStrahinja Jankovic */
1989be8a82cSStrahinja Jankovic if (!allwinner_i2c_is_reset(s) && allwinner_i2c_bus_is_enabled(s)) {
1999be8a82cSStrahinja Jankovic if (STAT_TO_STA(s->stat) != STAT_IDLE) {
2009be8a82cSStrahinja Jankovic s->cntr |= TWI_CNTR_INT_FLAG;
2019be8a82cSStrahinja Jankovic if (allwinner_i2c_interrupt_is_enabled(s)) {
2029be8a82cSStrahinja Jankovic qemu_irq_raise(s->irq);
2039be8a82cSStrahinja Jankovic }
2049be8a82cSStrahinja Jankovic }
2059be8a82cSStrahinja Jankovic }
2069be8a82cSStrahinja Jankovic }
2079be8a82cSStrahinja Jankovic
allwinner_i2c_read(void * opaque,hwaddr offset,unsigned size)2089be8a82cSStrahinja Jankovic static uint64_t allwinner_i2c_read(void *opaque, hwaddr offset,
2099be8a82cSStrahinja Jankovic unsigned size)
2109be8a82cSStrahinja Jankovic {
2119be8a82cSStrahinja Jankovic uint16_t value;
2129be8a82cSStrahinja Jankovic AWI2CState *s = AW_I2C(opaque);
2139be8a82cSStrahinja Jankovic
2149be8a82cSStrahinja Jankovic switch (offset) {
2159be8a82cSStrahinja Jankovic case TWI_ADDR_REG:
2169be8a82cSStrahinja Jankovic value = s->addr;
2179be8a82cSStrahinja Jankovic break;
2189be8a82cSStrahinja Jankovic case TWI_XADDR_REG:
2199be8a82cSStrahinja Jankovic value = s->xaddr;
2209be8a82cSStrahinja Jankovic break;
2219be8a82cSStrahinja Jankovic case TWI_DATA_REG:
2229be8a82cSStrahinja Jankovic if ((STAT_TO_STA(s->stat) == STAT_M_ADDR_RD_ACK) ||
2239be8a82cSStrahinja Jankovic (STAT_TO_STA(s->stat) == STAT_M_DATA_RX_ACK) ||
2249be8a82cSStrahinja Jankovic (STAT_TO_STA(s->stat) == STAT_M_DATA_RX_NACK)) {
2259be8a82cSStrahinja Jankovic /* Get the next byte */
2269be8a82cSStrahinja Jankovic s->data = i2c_recv(s->bus);
2279be8a82cSStrahinja Jankovic
2289be8a82cSStrahinja Jankovic if (s->cntr & TWI_CNTR_A_ACK) {
2299be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_DATA_RX_ACK);
2309be8a82cSStrahinja Jankovic } else {
2319be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_DATA_RX_NACK);
2329be8a82cSStrahinja Jankovic }
2339be8a82cSStrahinja Jankovic allwinner_i2c_raise_interrupt(s);
2349be8a82cSStrahinja Jankovic }
2359be8a82cSStrahinja Jankovic value = s->data;
2369be8a82cSStrahinja Jankovic break;
2379be8a82cSStrahinja Jankovic case TWI_CNTR_REG:
2389be8a82cSStrahinja Jankovic value = s->cntr;
2399be8a82cSStrahinja Jankovic break;
2409be8a82cSStrahinja Jankovic case TWI_STAT_REG:
2419be8a82cSStrahinja Jankovic value = s->stat;
2429be8a82cSStrahinja Jankovic /*
2439be8a82cSStrahinja Jankovic * If polling when reading then change state to indicate data
2449be8a82cSStrahinja Jankovic * is available
2459be8a82cSStrahinja Jankovic */
2469be8a82cSStrahinja Jankovic if (STAT_TO_STA(s->stat) == STAT_M_ADDR_RD_ACK) {
2479be8a82cSStrahinja Jankovic if (s->cntr & TWI_CNTR_A_ACK) {
2489be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_DATA_RX_ACK);
2499be8a82cSStrahinja Jankovic } else {
2509be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_DATA_RX_NACK);
2519be8a82cSStrahinja Jankovic }
2529be8a82cSStrahinja Jankovic allwinner_i2c_raise_interrupt(s);
2539be8a82cSStrahinja Jankovic }
2549be8a82cSStrahinja Jankovic break;
2559be8a82cSStrahinja Jankovic case TWI_CCR_REG:
2569be8a82cSStrahinja Jankovic value = s->ccr;
2579be8a82cSStrahinja Jankovic break;
2589be8a82cSStrahinja Jankovic case TWI_SRST_REG:
2599be8a82cSStrahinja Jankovic value = s->srst;
2609be8a82cSStrahinja Jankovic break;
2619be8a82cSStrahinja Jankovic case TWI_EFR_REG:
2629be8a82cSStrahinja Jankovic value = s->efr;
2639be8a82cSStrahinja Jankovic break;
2649be8a82cSStrahinja Jankovic case TWI_LCR_REG:
2659be8a82cSStrahinja Jankovic value = s->lcr;
2669be8a82cSStrahinja Jankovic break;
2679be8a82cSStrahinja Jankovic default:
2689be8a82cSStrahinja Jankovic qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%"
2699be8a82cSStrahinja Jankovic HWADDR_PRIx "\n", TYPE_AW_I2C, __func__, offset);
2709be8a82cSStrahinja Jankovic value = 0;
2719be8a82cSStrahinja Jankovic break;
2729be8a82cSStrahinja Jankovic }
2739be8a82cSStrahinja Jankovic
2749be8a82cSStrahinja Jankovic trace_allwinner_i2c_read(allwinner_i2c_get_regname(offset), offset, value);
2759be8a82cSStrahinja Jankovic
2769be8a82cSStrahinja Jankovic return (uint64_t)value;
2779be8a82cSStrahinja Jankovic }
2789be8a82cSStrahinja Jankovic
allwinner_i2c_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)2799be8a82cSStrahinja Jankovic static void allwinner_i2c_write(void *opaque, hwaddr offset,
2809be8a82cSStrahinja Jankovic uint64_t value, unsigned size)
2819be8a82cSStrahinja Jankovic {
2829be8a82cSStrahinja Jankovic AWI2CState *s = AW_I2C(opaque);
2839be8a82cSStrahinja Jankovic
2849be8a82cSStrahinja Jankovic value &= 0xff;
2859be8a82cSStrahinja Jankovic
2869be8a82cSStrahinja Jankovic trace_allwinner_i2c_write(allwinner_i2c_get_regname(offset), offset, value);
2879be8a82cSStrahinja Jankovic
2889be8a82cSStrahinja Jankovic switch (offset) {
2899be8a82cSStrahinja Jankovic case TWI_ADDR_REG:
2909be8a82cSStrahinja Jankovic s->addr = (uint8_t)value;
2919be8a82cSStrahinja Jankovic break;
2929be8a82cSStrahinja Jankovic case TWI_XADDR_REG:
2939be8a82cSStrahinja Jankovic s->xaddr = (uint8_t)value;
2949be8a82cSStrahinja Jankovic break;
2959be8a82cSStrahinja Jankovic case TWI_DATA_REG:
2969be8a82cSStrahinja Jankovic /* If the device is in reset or not enabled, nothing to do */
2979be8a82cSStrahinja Jankovic if (allwinner_i2c_is_reset(s) || (!allwinner_i2c_bus_is_enabled(s))) {
2989be8a82cSStrahinja Jankovic break;
2999be8a82cSStrahinja Jankovic }
3009be8a82cSStrahinja Jankovic
3019be8a82cSStrahinja Jankovic s->data = value & TWI_DATA_MASK;
3029be8a82cSStrahinja Jankovic
3039be8a82cSStrahinja Jankovic switch (STAT_TO_STA(s->stat)) {
3049be8a82cSStrahinja Jankovic case STAT_M_STA_TX:
3059be8a82cSStrahinja Jankovic case STAT_M_RSTA_TX:
3069be8a82cSStrahinja Jankovic /* Send address */
3079be8a82cSStrahinja Jankovic if (i2c_start_transfer(s->bus, extract32(s->data, 1, 7),
3089be8a82cSStrahinja Jankovic extract32(s->data, 0, 1))) {
3099be8a82cSStrahinja Jankovic /* If non zero is returned, the address is not valid */
3109be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_ADDR_WR_NACK);
3119be8a82cSStrahinja Jankovic } else {
3129be8a82cSStrahinja Jankovic /* Determine if read of write */
3139be8a82cSStrahinja Jankovic if (extract32(s->data, 0, 1)) {
3149be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_ADDR_RD_ACK);
3159be8a82cSStrahinja Jankovic } else {
3169be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_ADDR_WR_ACK);
3179be8a82cSStrahinja Jankovic }
3189be8a82cSStrahinja Jankovic allwinner_i2c_raise_interrupt(s);
3199be8a82cSStrahinja Jankovic }
3209be8a82cSStrahinja Jankovic break;
3219be8a82cSStrahinja Jankovic case STAT_M_ADDR_WR_ACK:
3229be8a82cSStrahinja Jankovic case STAT_M_DATA_TX_ACK:
3239be8a82cSStrahinja Jankovic if (i2c_send(s->bus, s->data)) {
3249be8a82cSStrahinja Jankovic /* If the target return non zero then end the transfer */
3259be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_DATA_TX_NACK);
3269be8a82cSStrahinja Jankovic i2c_end_transfer(s->bus);
3279be8a82cSStrahinja Jankovic } else {
3289be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_DATA_TX_ACK);
3299be8a82cSStrahinja Jankovic allwinner_i2c_raise_interrupt(s);
3309be8a82cSStrahinja Jankovic }
3319be8a82cSStrahinja Jankovic break;
3329be8a82cSStrahinja Jankovic default:
3339be8a82cSStrahinja Jankovic break;
3349be8a82cSStrahinja Jankovic }
3359be8a82cSStrahinja Jankovic break;
3369be8a82cSStrahinja Jankovic case TWI_CNTR_REG:
3379be8a82cSStrahinja Jankovic if (!allwinner_i2c_is_reset(s)) {
3389be8a82cSStrahinja Jankovic /* Do something only if not in software reset */
3399be8a82cSStrahinja Jankovic s->cntr = value & TWI_CNTR_MASK;
3409be8a82cSStrahinja Jankovic
3419be8a82cSStrahinja Jankovic /* Check if start condition should be sent */
3429be8a82cSStrahinja Jankovic if (s->cntr & TWI_CNTR_M_STA) {
3439be8a82cSStrahinja Jankovic /* Update status */
3449be8a82cSStrahinja Jankovic if (STAT_TO_STA(s->stat) == STAT_IDLE) {
3459be8a82cSStrahinja Jankovic /* Send start condition */
3469be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_STA_TX);
3479be8a82cSStrahinja Jankovic } else {
3489be8a82cSStrahinja Jankovic /* Send repeated start condition */
3499be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_RSTA_TX);
3509be8a82cSStrahinja Jankovic }
3519be8a82cSStrahinja Jankovic /* Clear start condition */
3529be8a82cSStrahinja Jankovic s->cntr &= ~TWI_CNTR_M_STA;
3539be8a82cSStrahinja Jankovic }
3549be8a82cSStrahinja Jankovic if (s->cntr & TWI_CNTR_M_STP) {
3559be8a82cSStrahinja Jankovic /* Update status */
3569be8a82cSStrahinja Jankovic i2c_end_transfer(s->bus);
3579be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_IDLE);
3589be8a82cSStrahinja Jankovic s->cntr &= ~TWI_CNTR_M_STP;
3599be8a82cSStrahinja Jankovic }
3608461bfdcSqianfan Zhao
3618461bfdcSqianfan Zhao if (!s->irq_clear_inverted && !(s->cntr & TWI_CNTR_INT_FLAG)) {
3628461bfdcSqianfan Zhao /* Write 0 to clear this flag */
3638461bfdcSqianfan Zhao qemu_irq_lower(s->irq);
3648461bfdcSqianfan Zhao } else if (s->irq_clear_inverted && (s->cntr & TWI_CNTR_INT_FLAG)) {
3658461bfdcSqianfan Zhao /* Write 1 to clear this flag */
3668461bfdcSqianfan Zhao s->cntr &= ~TWI_CNTR_INT_FLAG;
3679be8a82cSStrahinja Jankovic qemu_irq_lower(s->irq);
3689be8a82cSStrahinja Jankovic }
3698461bfdcSqianfan Zhao
3709be8a82cSStrahinja Jankovic if ((s->cntr & TWI_CNTR_A_ACK) == 0) {
3719be8a82cSStrahinja Jankovic if (STAT_TO_STA(s->stat) == STAT_M_DATA_RX_ACK) {
3729be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_DATA_RX_NACK);
3739be8a82cSStrahinja Jankovic }
3749be8a82cSStrahinja Jankovic } else {
3759be8a82cSStrahinja Jankovic if (STAT_TO_STA(s->stat) == STAT_M_DATA_RX_NACK) {
3769be8a82cSStrahinja Jankovic s->stat = STAT_FROM_STA(STAT_M_DATA_RX_ACK);
3779be8a82cSStrahinja Jankovic }
3789be8a82cSStrahinja Jankovic }
3799be8a82cSStrahinja Jankovic allwinner_i2c_raise_interrupt(s);
3809be8a82cSStrahinja Jankovic
3819be8a82cSStrahinja Jankovic }
3829be8a82cSStrahinja Jankovic break;
3839be8a82cSStrahinja Jankovic case TWI_CCR_REG:
3849be8a82cSStrahinja Jankovic s->ccr = value & TWI_CCR_MASK;
3859be8a82cSStrahinja Jankovic break;
3869be8a82cSStrahinja Jankovic case TWI_SRST_REG:
3879be8a82cSStrahinja Jankovic if (((value & TWI_SRST_MASK) == 0) && (s->srst & TWI_SRST_MASK)) {
388ef6ab292SPeter Maydell device_cold_reset(DEVICE(s));
3899be8a82cSStrahinja Jankovic }
3909be8a82cSStrahinja Jankovic s->srst = value & TWI_SRST_MASK;
3919be8a82cSStrahinja Jankovic break;
3929be8a82cSStrahinja Jankovic case TWI_EFR_REG:
3939be8a82cSStrahinja Jankovic s->efr = value & TWI_EFR_MASK;
3949be8a82cSStrahinja Jankovic break;
3959be8a82cSStrahinja Jankovic case TWI_LCR_REG:
3969be8a82cSStrahinja Jankovic s->lcr = value & TWI_LCR_MASK;
3979be8a82cSStrahinja Jankovic break;
3989be8a82cSStrahinja Jankovic default:
3999be8a82cSStrahinja Jankovic qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%"
4009be8a82cSStrahinja Jankovic HWADDR_PRIx "\n", TYPE_AW_I2C, __func__, offset);
4019be8a82cSStrahinja Jankovic break;
4029be8a82cSStrahinja Jankovic }
4039be8a82cSStrahinja Jankovic }
4049be8a82cSStrahinja Jankovic
4059be8a82cSStrahinja Jankovic static const MemoryRegionOps allwinner_i2c_ops = {
4069be8a82cSStrahinja Jankovic .read = allwinner_i2c_read,
4079be8a82cSStrahinja Jankovic .write = allwinner_i2c_write,
4089be8a82cSStrahinja Jankovic .valid.min_access_size = 1,
4099be8a82cSStrahinja Jankovic .valid.max_access_size = 4,
4109be8a82cSStrahinja Jankovic .endianness = DEVICE_NATIVE_ENDIAN,
4119be8a82cSStrahinja Jankovic };
4129be8a82cSStrahinja Jankovic
4139be8a82cSStrahinja Jankovic static const VMStateDescription allwinner_i2c_vmstate = {
4149be8a82cSStrahinja Jankovic .name = TYPE_AW_I2C,
4159be8a82cSStrahinja Jankovic .version_id = 1,
4169be8a82cSStrahinja Jankovic .minimum_version_id = 1,
41701d9442aSRichard Henderson .fields = (const VMStateField[]) {
4189be8a82cSStrahinja Jankovic VMSTATE_UINT8(addr, AWI2CState),
4199be8a82cSStrahinja Jankovic VMSTATE_UINT8(xaddr, AWI2CState),
4209be8a82cSStrahinja Jankovic VMSTATE_UINT8(data, AWI2CState),
4219be8a82cSStrahinja Jankovic VMSTATE_UINT8(cntr, AWI2CState),
4229be8a82cSStrahinja Jankovic VMSTATE_UINT8(ccr, AWI2CState),
4239be8a82cSStrahinja Jankovic VMSTATE_UINT8(srst, AWI2CState),
4249be8a82cSStrahinja Jankovic VMSTATE_UINT8(efr, AWI2CState),
4259be8a82cSStrahinja Jankovic VMSTATE_UINT8(lcr, AWI2CState),
4269be8a82cSStrahinja Jankovic VMSTATE_END_OF_LIST()
4279be8a82cSStrahinja Jankovic }
4289be8a82cSStrahinja Jankovic };
4299be8a82cSStrahinja Jankovic
allwinner_i2c_realize(DeviceState * dev,Error ** errp)4309be8a82cSStrahinja Jankovic static void allwinner_i2c_realize(DeviceState *dev, Error **errp)
4319be8a82cSStrahinja Jankovic {
4329be8a82cSStrahinja Jankovic AWI2CState *s = AW_I2C(dev);
4339be8a82cSStrahinja Jankovic
4349be8a82cSStrahinja Jankovic memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_i2c_ops, s,
4359be8a82cSStrahinja Jankovic TYPE_AW_I2C, AW_I2C_MEM_SIZE);
4369be8a82cSStrahinja Jankovic sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
4379be8a82cSStrahinja Jankovic sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
4389be8a82cSStrahinja Jankovic s->bus = i2c_init_bus(dev, "i2c");
4399be8a82cSStrahinja Jankovic }
4409be8a82cSStrahinja Jankovic
allwinner_i2c_class_init(ObjectClass * klass,void * data)4419be8a82cSStrahinja Jankovic static void allwinner_i2c_class_init(ObjectClass *klass, void *data)
4429be8a82cSStrahinja Jankovic {
4439be8a82cSStrahinja Jankovic DeviceClass *dc = DEVICE_CLASS(klass);
4449be8a82cSStrahinja Jankovic ResettableClass *rc = RESETTABLE_CLASS(klass);
4459be8a82cSStrahinja Jankovic
4469be8a82cSStrahinja Jankovic rc->phases.hold = allwinner_i2c_reset_hold;
4479be8a82cSStrahinja Jankovic dc->vmsd = &allwinner_i2c_vmstate;
4489be8a82cSStrahinja Jankovic dc->realize = allwinner_i2c_realize;
4499be8a82cSStrahinja Jankovic dc->desc = "Allwinner I2C Controller";
4509be8a82cSStrahinja Jankovic }
4519be8a82cSStrahinja Jankovic
4529be8a82cSStrahinja Jankovic static const TypeInfo allwinner_i2c_type_info = {
4539be8a82cSStrahinja Jankovic .name = TYPE_AW_I2C,
4549be8a82cSStrahinja Jankovic .parent = TYPE_SYS_BUS_DEVICE,
4559be8a82cSStrahinja Jankovic .instance_size = sizeof(AWI2CState),
4569be8a82cSStrahinja Jankovic .class_init = allwinner_i2c_class_init,
4579be8a82cSStrahinja Jankovic };
4589be8a82cSStrahinja Jankovic
allwinner_i2c_sun6i_init(Object * obj)4598461bfdcSqianfan Zhao static void allwinner_i2c_sun6i_init(Object *obj)
4608461bfdcSqianfan Zhao {
4618461bfdcSqianfan Zhao AWI2CState *s = AW_I2C(obj);
4628461bfdcSqianfan Zhao
4638461bfdcSqianfan Zhao s->irq_clear_inverted = true;
4648461bfdcSqianfan Zhao }
4658461bfdcSqianfan Zhao
4668461bfdcSqianfan Zhao static const TypeInfo allwinner_i2c_sun6i_type_info = {
4678461bfdcSqianfan Zhao .name = TYPE_AW_I2C_SUN6I,
4686c50845aSPeter Maydell .parent = TYPE_AW_I2C,
4698461bfdcSqianfan Zhao .instance_init = allwinner_i2c_sun6i_init,
4708461bfdcSqianfan Zhao };
4718461bfdcSqianfan Zhao
allwinner_i2c_register_types(void)4729be8a82cSStrahinja Jankovic static void allwinner_i2c_register_types(void)
4739be8a82cSStrahinja Jankovic {
4749be8a82cSStrahinja Jankovic type_register_static(&allwinner_i2c_type_info);
4758461bfdcSqianfan Zhao type_register_static(&allwinner_i2c_sun6i_type_info);
4769be8a82cSStrahinja Jankovic }
4779be8a82cSStrahinja Jankovic
4789be8a82cSStrahinja Jankovic type_init(allwinner_i2c_register_types)
479