From 47e62276a2d611ff6b8ebdb06e5abb654f033aa3 Mon Sep 17 00:00:00 2001 From: patrick Date: Tue, 24 Jul 2018 16:11:33 +0000 Subject: [PATCH] The I2C controller on the Allwinner hardware is actually a modified Marvell controller. The difference is essentially register offsets and a clock divider calculation based on a power of two. Also this particular hardware needs a delay after sending a stop and before reading the status register since apparently the data doesn't propagate fast enough. This makes sxitwi(4) work on the Marvell Armada 38x. ok kettenis@ --- sys/dev/fdt/sxitwi.c | 66 +++++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/sys/dev/fdt/sxitwi.c b/sys/dev/fdt/sxitwi.c index e97234896e3..83887fac50a 100644 --- a/sys/dev/fdt/sxitwi.c +++ b/sys/dev/fdt/sxitwi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sxitwi.c,v 1.7 2018/01/06 11:23:14 kettenis Exp $ */ +/* $OpenBSD: sxitwi.c,v 1.8 2018/07/24 16:11:33 patrick Exp $ */ /* $NetBSD: gttwsi_core.c,v 1.2 2014/11/23 13:37:27 jmcneill Exp $ */ /* * Copyright (c) 2008 Eiji Kawauchi. @@ -82,17 +82,14 @@ #include #include -#define TWI_CCR_REG 0x14 -#define TWI_CCR_CLK_M (0x0f << 3) -#define TWI_CCR_CLK_N (0x07 << 0) - -#define TWSI_SLAVEADDR 0x00 -#define TWSI_EXTEND_SLAVEADDR 0x04 -#define TWSI_DATA 0x08 -#define TWSI_CONTROL 0x0c -#define TWSI_STATUS 0x10 -#define TWSI_BAUDRATE 0x14 -#define TWSI_SOFTRESET 0x18 +#define TWSI_SLAVEADDR 0 +#define TWSI_EXTEND_SLAVEADDR 1 +#define TWSI_DATA 2 +#define TWSI_CONTROL 3 +#define TWSI_STATUS 4 +#define TWSI_CLOCK 5 +#define TWSI_SOFTRESET 6 +#define TWSI_NREG 7 #define SLAVEADDR_GCE_MASK 0x01 #define SLAVEADDR_SADDR_MASK 0xfe @@ -138,6 +135,8 @@ struct sxitwi_softc { struct i2c_controller sc_ic; struct rwlock sc_buslock; void *sc_ih; + uint8_t sc_regs[TWSI_NREG]; + int sc_delay; }; void sxitwi_attach(struct device *, struct device *, void *); @@ -171,7 +170,8 @@ sxitwi_match(struct device *parent, void *match, void *aux) return (OF_is_compatible(faa->fa_node, "allwinner,sun4i-a10-i2c") || OF_is_compatible(faa->fa_node, "allwinner,sun6i-a31-i2c") || - OF_is_compatible(faa->fa_node, "allwinner,sun7i-a20-i2c")); + OF_is_compatible(faa->fa_node, "allwinner,sun7i-a20-i2c") || + OF_is_compatible(faa->fa_node, "marvell,mv78230-a0-i2c")); } void @@ -181,13 +181,34 @@ sxitwi_attach(struct device *parent, struct device *self, void *aux) struct fdt_attach_args *faa = aux; struct i2cbus_attach_args iba; uint32_t freq, parent_freq; - uint32_t m, n; + uint32_t m, n, nbase; if (faa->fa_nreg < 1) { printf(": no registers\n"); return; } + nbase = 1; + sc->sc_regs[TWSI_SLAVEADDR] = 0x00; + sc->sc_regs[TWSI_EXTEND_SLAVEADDR] = 0x04; + sc->sc_regs[TWSI_DATA] = 0x08; + sc->sc_regs[TWSI_CONTROL] = 0x0c; + sc->sc_regs[TWSI_STATUS] = 0x10; + sc->sc_regs[TWSI_CLOCK] = 0x14; + sc->sc_regs[TWSI_SOFTRESET] = 0x18; + + if (OF_is_compatible(faa->fa_node, "marvell,mv78230-a0-i2c")) { + nbase = 2; + sc->sc_delay = 1; + sc->sc_regs[TWSI_SLAVEADDR] = 0x00; + sc->sc_regs[TWSI_EXTEND_SLAVEADDR] = 0x10; + sc->sc_regs[TWSI_DATA] = 0x04; + sc->sc_regs[TWSI_CONTROL] = 0x08; + sc->sc_regs[TWSI_STATUS] = 0x0c; + sc->sc_regs[TWSI_CLOCK] = 0x0c; + sc->sc_regs[TWSI_SOFTRESET] = 0x1c; + } + /* * Calculate clock dividers up front such that we can bail out * early if the desired clock rate can't be obtained. Make @@ -200,9 +221,9 @@ sxitwi_attach(struct device *parent, struct device *self, void *aux) return; } n = 0, m = 0; - while ((freq * (1 << n) * 16 * 10) < parent_freq) + while ((freq * (nbase << n) * 16 * 10) < parent_freq) n++; - while ((freq * (1 << n) * (m + 1) * 10) < parent_freq) + while ((freq * (nbase << n) * (m + 1) * 10) < parent_freq) m++; if (n > 8 || m > 16) { printf(": clock frequency too high\n"); @@ -246,7 +267,7 @@ sxitwi_attach(struct device *parent, struct device *self, void *aux) reset_deassert_all(faa->fa_node); /* Set clock rate. */ - sxitwi_write_4(sc, TWI_CCR_REG, (m << 3) | (n << 0)); + sxitwi_write_4(sc, TWSI_CLOCK, (m << 3) | (n << 0)); /* Put the controller into Soft Reset. */ sxitwi_write_4(sc, TWSI_SOFTRESET, SOFTRESET_VAL); @@ -304,13 +325,15 @@ sxitwi_bus_scan(struct device *self, struct i2cbus_attach_args *iba, void *arg) u_int sxitwi_read_4(struct sxitwi_softc *sc, u_int reg) { - return bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg); + KASSERT(reg < TWSI_NREG); + return bus_space_read_4(sc->sc_iot, sc->sc_ioh, sc->sc_regs[reg]); } void sxitwi_write_4(struct sxitwi_softc *sc, u_int reg, u_int val) { - bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg, val); + KASSERT(reg < TWSI_NREG); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, sc->sc_regs[reg], val); } int @@ -376,6 +399,8 @@ sxitwi_send_stop(void *v, int flags) * START condition until the bus is free. */ sxitwi_write_4(sc, TWSI_CONTROL, CONTROL_STOP | sc->sc_twsien_iflg); + if (sc->sc_delay) + delay(5); return 0; } @@ -471,6 +496,9 @@ sxitwi_wait(struct sxitwi_softc *sc, u_int control, u_int expect, int flags) if (timo == 0) return ETIMEDOUT; + if (sc->sc_delay) + delay(5); + status = sxitwi_read_4(sc, TWSI_STATUS); if (status != expect) return EIO; -- 2.20.1