13c2b2a28SEmmanuel Vadot /*- 23c2b2a28SEmmanuel Vadot * SPDX-License-Identifier: BSD-2-Clause 33c2b2a28SEmmanuel Vadot * 43c2b2a28SEmmanuel Vadot * Copyright (c) 2018 Emmanuel Vadot <manu@FreeBSD.org> 53c2b2a28SEmmanuel Vadot * 63c2b2a28SEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 73c2b2a28SEmmanuel Vadot * modification, are permitted provided that the following conditions 83c2b2a28SEmmanuel Vadot * are met: 93c2b2a28SEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 103c2b2a28SEmmanuel Vadot * notice, this list of conditions and the following disclaimer. 113c2b2a28SEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 123c2b2a28SEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the 133c2b2a28SEmmanuel Vadot * documentation and/or other materials provided with the distribution. 143c2b2a28SEmmanuel Vadot * 153c2b2a28SEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 163c2b2a28SEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 173c2b2a28SEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 183c2b2a28SEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 193c2b2a28SEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 203c2b2a28SEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 213c2b2a28SEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 223c2b2a28SEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 233c2b2a28SEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 243c2b2a28SEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 253c2b2a28SEmmanuel Vadot * SUCH DAMAGE. 263c2b2a28SEmmanuel Vadot */ 273c2b2a28SEmmanuel Vadot 283c2b2a28SEmmanuel Vadot #include <sys/param.h> 293c2b2a28SEmmanuel Vadot #include <sys/bus.h> 303c2b2a28SEmmanuel Vadot #include <sys/kernel.h> 313c2b2a28SEmmanuel Vadot #include <sys/module.h> 323c2b2a28SEmmanuel Vadot #include <sys/mutex.h> 333c2b2a28SEmmanuel Vadot #include <sys/rman.h> 343c2b2a28SEmmanuel Vadot #include <machine/bus.h> 353c2b2a28SEmmanuel Vadot 363c2b2a28SEmmanuel Vadot #include <dev/ofw/ofw_bus.h> 373c2b2a28SEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h> 383c2b2a28SEmmanuel Vadot 393c2b2a28SEmmanuel Vadot #include <dev/iicbus/iiconf.h> 403c2b2a28SEmmanuel Vadot #include <dev/iicbus/iicbus.h> 413c2b2a28SEmmanuel Vadot 42be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h> 433c2b2a28SEmmanuel Vadot 443c2b2a28SEmmanuel Vadot #include "iicbus_if.h" 453c2b2a28SEmmanuel Vadot 463c2b2a28SEmmanuel Vadot #define RK_I2C_CON 0x00 473c2b2a28SEmmanuel Vadot #define RK_I2C_CON_EN (1 << 0) 483c2b2a28SEmmanuel Vadot #define RK_I2C_CON_MODE_SHIFT 1 493c2b2a28SEmmanuel Vadot #define RK_I2C_CON_MODE_TX 0 503c2b2a28SEmmanuel Vadot #define RK_I2C_CON_MODE_RRX 1 513c2b2a28SEmmanuel Vadot #define RK_I2C_CON_MODE_RX 2 523c2b2a28SEmmanuel Vadot #define RK_I2C_CON_MODE_RTX 3 533c2b2a28SEmmanuel Vadot #define RK_I2C_CON_MODE_MASK 0x6 543c2b2a28SEmmanuel Vadot #define RK_I2C_CON_START (1 << 3) 553c2b2a28SEmmanuel Vadot #define RK_I2C_CON_STOP (1 << 4) 563c2b2a28SEmmanuel Vadot #define RK_I2C_CON_LASTACK (1 << 5) 573c2b2a28SEmmanuel Vadot #define RK_I2C_CON_NAKSTOP (1 << 6) 583c2b2a28SEmmanuel Vadot #define RK_I2C_CON_CTRL_MASK 0xFF 593c2b2a28SEmmanuel Vadot 603c2b2a28SEmmanuel Vadot #define RK_I2C_CLKDIV 0x04 613c2b2a28SEmmanuel Vadot #define RK_I2C_CLKDIVL_MASK 0xFFFF 623c2b2a28SEmmanuel Vadot #define RK_I2C_CLKDIVL_SHIFT 0 633c2b2a28SEmmanuel Vadot #define RK_I2C_CLKDIVH_MASK 0xFFFF0000 643c2b2a28SEmmanuel Vadot #define RK_I2C_CLKDIVH_SHIFT 16 653c2b2a28SEmmanuel Vadot #define RK_I2C_CLKDIV_MUL 8 663c2b2a28SEmmanuel Vadot 673c2b2a28SEmmanuel Vadot #define RK_I2C_MRXADDR 0x08 683c2b2a28SEmmanuel Vadot #define RK_I2C_MRXADDR_SADDR_MASK 0xFFFFFF 693c2b2a28SEmmanuel Vadot #define RK_I2C_MRXADDR_VALID(x) (1 << (24 + x)) 703c2b2a28SEmmanuel Vadot 713c2b2a28SEmmanuel Vadot #define RK_I2C_MRXRADDR 0x0C 723c2b2a28SEmmanuel Vadot #define RK_I2C_MRXRADDR_SRADDR_MASK 0xFFFFFF 733c2b2a28SEmmanuel Vadot #define RK_I2C_MRXRADDR_VALID(x) (1 << (24 + x)) 743c2b2a28SEmmanuel Vadot 753c2b2a28SEmmanuel Vadot #define RK_I2C_MTXCNT 0x10 763c2b2a28SEmmanuel Vadot #define RK_I2C_MTXCNT_MASK 0x3F 773c2b2a28SEmmanuel Vadot 783c2b2a28SEmmanuel Vadot #define RK_I2C_MRXCNT 0x14 793c2b2a28SEmmanuel Vadot #define RK_I2C_MRXCNT_MASK 0x3F 803c2b2a28SEmmanuel Vadot 813c2b2a28SEmmanuel Vadot #define RK_I2C_IEN 0x18 823c2b2a28SEmmanuel Vadot #define RK_I2C_IEN_BTFIEN (1 << 0) 833c2b2a28SEmmanuel Vadot #define RK_I2C_IEN_BRFIEN (1 << 1) 843c2b2a28SEmmanuel Vadot #define RK_I2C_IEN_MBTFIEN (1 << 2) 853c2b2a28SEmmanuel Vadot #define RK_I2C_IEN_MBRFIEN (1 << 3) 863c2b2a28SEmmanuel Vadot #define RK_I2C_IEN_STARTIEN (1 << 4) 873c2b2a28SEmmanuel Vadot #define RK_I2C_IEN_STOPIEN (1 << 5) 883c2b2a28SEmmanuel Vadot #define RK_I2C_IEN_NAKRCVIEN (1 << 6) 893c2b2a28SEmmanuel Vadot #define RK_I2C_IEN_ALL (RK_I2C_IEN_MBTFIEN | RK_I2C_IEN_MBRFIEN | \ 903c2b2a28SEmmanuel Vadot RK_I2C_IEN_STARTIEN | RK_I2C_IEN_STOPIEN | RK_I2C_IEN_NAKRCVIEN) 913c2b2a28SEmmanuel Vadot 923c2b2a28SEmmanuel Vadot #define RK_I2C_IPD 0x1C 933c2b2a28SEmmanuel Vadot #define RK_I2C_IPD_BTFIPD (1 << 0) 943c2b2a28SEmmanuel Vadot #define RK_I2C_IPD_BRFIPD (1 << 1) 953c2b2a28SEmmanuel Vadot #define RK_I2C_IPD_MBTFIPD (1 << 2) 963c2b2a28SEmmanuel Vadot #define RK_I2C_IPD_MBRFIPD (1 << 3) 973c2b2a28SEmmanuel Vadot #define RK_I2C_IPD_STARTIPD (1 << 4) 983c2b2a28SEmmanuel Vadot #define RK_I2C_IPD_STOPIPD (1 << 5) 993c2b2a28SEmmanuel Vadot #define RK_I2C_IPD_NAKRCVIPD (1 << 6) 1003c2b2a28SEmmanuel Vadot #define RK_I2C_IPD_ALL (RK_I2C_IPD_MBTFIPD | RK_I2C_IPD_MBRFIPD | \ 1013c2b2a28SEmmanuel Vadot RK_I2C_IPD_STARTIPD | RK_I2C_IPD_STOPIPD | RK_I2C_IPD_NAKRCVIPD) 1023c2b2a28SEmmanuel Vadot 1033c2b2a28SEmmanuel Vadot #define RK_I2C_FNCT 0x20 1043c2b2a28SEmmanuel Vadot #define RK_I2C_FNCT_MASK 0x3F 1053c2b2a28SEmmanuel Vadot 1063c2b2a28SEmmanuel Vadot #define RK_I2C_TXDATA_BASE 0x100 1073c2b2a28SEmmanuel Vadot 1083c2b2a28SEmmanuel Vadot #define RK_I2C_RXDATA_BASE 0x200 1093c2b2a28SEmmanuel Vadot 1103c2b2a28SEmmanuel Vadot /* 8 data registers, 4 bytes each. */ 1113c2b2a28SEmmanuel Vadot #define RK_I2C_MAX_RXTX_LEN 32 1123c2b2a28SEmmanuel Vadot 1133c2b2a28SEmmanuel Vadot enum rk_i2c_state { 1143c2b2a28SEmmanuel Vadot STATE_IDLE = 0, 1153c2b2a28SEmmanuel Vadot STATE_START, 1163c2b2a28SEmmanuel Vadot STATE_READ, 1173c2b2a28SEmmanuel Vadot STATE_WRITE, 1183c2b2a28SEmmanuel Vadot STATE_STOP 1193c2b2a28SEmmanuel Vadot }; 1203c2b2a28SEmmanuel Vadot 1213c2b2a28SEmmanuel Vadot struct rk_i2c_softc { 1223c2b2a28SEmmanuel Vadot device_t dev; 1233c2b2a28SEmmanuel Vadot struct resource *res[2]; 1243c2b2a28SEmmanuel Vadot struct mtx mtx; 1253c2b2a28SEmmanuel Vadot clk_t sclk; 1263c2b2a28SEmmanuel Vadot clk_t pclk; 1273c2b2a28SEmmanuel Vadot int busy; 1283c2b2a28SEmmanuel Vadot void * intrhand; 1293c2b2a28SEmmanuel Vadot uint32_t intr; 1303c2b2a28SEmmanuel Vadot uint32_t ipd; 1313c2b2a28SEmmanuel Vadot struct iic_msg *msg; 1323c2b2a28SEmmanuel Vadot size_t cnt; 1333c2b2a28SEmmanuel Vadot bool transfer_done; 1343c2b2a28SEmmanuel Vadot bool nak_recv; 1353c2b2a28SEmmanuel Vadot bool tx_slave_addr; 1363c2b2a28SEmmanuel Vadot uint8_t mode; 1373c2b2a28SEmmanuel Vadot uint8_t state; 1383c2b2a28SEmmanuel Vadot 1393c2b2a28SEmmanuel Vadot device_t iicbus; 1403c2b2a28SEmmanuel Vadot }; 1413c2b2a28SEmmanuel Vadot 1423c2b2a28SEmmanuel Vadot static struct ofw_compat_data compat_data[] = { 1433c2b2a28SEmmanuel Vadot {"rockchip,rk3288-i2c", 1}, 1443c2b2a28SEmmanuel Vadot {"rockchip,rk3328-i2c", 1}, 1453c2b2a28SEmmanuel Vadot {"rockchip,rk3399-i2c", 1}, 1463c2b2a28SEmmanuel Vadot {NULL, 0} 1473c2b2a28SEmmanuel Vadot }; 1483c2b2a28SEmmanuel Vadot 1493c2b2a28SEmmanuel Vadot static struct resource_spec rk_i2c_spec[] = { 1503c2b2a28SEmmanuel Vadot { SYS_RES_MEMORY, 0, RF_ACTIVE }, 1513c2b2a28SEmmanuel Vadot { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE }, 1523c2b2a28SEmmanuel Vadot { -1, 0 } 1533c2b2a28SEmmanuel Vadot }; 1543c2b2a28SEmmanuel Vadot 1553c2b2a28SEmmanuel Vadot static int rk_i2c_probe(device_t dev); 1563c2b2a28SEmmanuel Vadot static int rk_i2c_attach(device_t dev); 1573c2b2a28SEmmanuel Vadot static int rk_i2c_detach(device_t dev); 1583c2b2a28SEmmanuel Vadot 1593c2b2a28SEmmanuel Vadot #define RK_I2C_LOCK(sc) mtx_lock(&(sc)->mtx) 1603c2b2a28SEmmanuel Vadot #define RK_I2C_UNLOCK(sc) mtx_unlock(&(sc)->mtx) 1613c2b2a28SEmmanuel Vadot #define RK_I2C_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mtx, MA_OWNED) 1623c2b2a28SEmmanuel Vadot #define RK_I2C_READ(sc, reg) bus_read_4((sc)->res[0], (reg)) 1633c2b2a28SEmmanuel Vadot #define RK_I2C_WRITE(sc, reg, val) bus_write_4((sc)->res[0], (reg), (val)) 1643c2b2a28SEmmanuel Vadot 1653c2b2a28SEmmanuel Vadot static uint32_t 1663c2b2a28SEmmanuel Vadot rk_i2c_get_clkdiv(struct rk_i2c_softc *sc, uint32_t speed) 1673c2b2a28SEmmanuel Vadot { 1683c2b2a28SEmmanuel Vadot uint64_t sclk_freq; 1693c2b2a28SEmmanuel Vadot uint32_t clkdiv; 1703c2b2a28SEmmanuel Vadot int err; 1713c2b2a28SEmmanuel Vadot 1723c2b2a28SEmmanuel Vadot err = clk_get_freq(sc->sclk, &sclk_freq); 1733c2b2a28SEmmanuel Vadot if (err != 0) 1743c2b2a28SEmmanuel Vadot return (err); 1753c2b2a28SEmmanuel Vadot 1763c2b2a28SEmmanuel Vadot clkdiv = (sclk_freq / speed / RK_I2C_CLKDIV_MUL / 2) - 1; 1773c2b2a28SEmmanuel Vadot clkdiv &= RK_I2C_CLKDIVL_MASK; 1783c2b2a28SEmmanuel Vadot 1793c2b2a28SEmmanuel Vadot clkdiv = clkdiv << RK_I2C_CLKDIVH_SHIFT | clkdiv; 1803c2b2a28SEmmanuel Vadot 1813c2b2a28SEmmanuel Vadot return (clkdiv); 1823c2b2a28SEmmanuel Vadot } 1833c2b2a28SEmmanuel Vadot 1843c2b2a28SEmmanuel Vadot static int 1853c2b2a28SEmmanuel Vadot rk_i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 1863c2b2a28SEmmanuel Vadot { 1873c2b2a28SEmmanuel Vadot struct rk_i2c_softc *sc; 1883c2b2a28SEmmanuel Vadot uint32_t clkdiv; 1893c2b2a28SEmmanuel Vadot u_int busfreq; 1903c2b2a28SEmmanuel Vadot 1913c2b2a28SEmmanuel Vadot sc = device_get_softc(dev); 1923c2b2a28SEmmanuel Vadot 1933c2b2a28SEmmanuel Vadot busfreq = IICBUS_GET_FREQUENCY(sc->iicbus, speed); 1943c2b2a28SEmmanuel Vadot 1953c2b2a28SEmmanuel Vadot clkdiv = rk_i2c_get_clkdiv(sc, busfreq); 1963c2b2a28SEmmanuel Vadot 1973c2b2a28SEmmanuel Vadot RK_I2C_LOCK(sc); 1983c2b2a28SEmmanuel Vadot 1993c2b2a28SEmmanuel Vadot /* Set the clock divider */ 2003c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_CLKDIV, clkdiv); 2013c2b2a28SEmmanuel Vadot 2023c2b2a28SEmmanuel Vadot /* Disable the module */ 2033c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_CON, 0); 2043c2b2a28SEmmanuel Vadot 2053c2b2a28SEmmanuel Vadot RK_I2C_UNLOCK(sc); 2063c2b2a28SEmmanuel Vadot 2073c2b2a28SEmmanuel Vadot return (0); 2083c2b2a28SEmmanuel Vadot } 2093c2b2a28SEmmanuel Vadot 2103c2b2a28SEmmanuel Vadot static uint8_t 2113c2b2a28SEmmanuel Vadot rk_i2c_fill_tx(struct rk_i2c_softc *sc) 2123c2b2a28SEmmanuel Vadot { 2133c2b2a28SEmmanuel Vadot uint32_t buf32; 2143c2b2a28SEmmanuel Vadot uint8_t buf; 2153c2b2a28SEmmanuel Vadot int i, j, len; 2163c2b2a28SEmmanuel Vadot 2173c2b2a28SEmmanuel Vadot len = sc->msg->len - sc->cnt; 2183c2b2a28SEmmanuel Vadot if (sc->tx_slave_addr) { 2193c2b2a28SEmmanuel Vadot KASSERT(sc->cnt == 0, ("tx_slave_addr in the middle of data")); 2203c2b2a28SEmmanuel Vadot len++; 2213c2b2a28SEmmanuel Vadot } 2223c2b2a28SEmmanuel Vadot 2233c2b2a28SEmmanuel Vadot if (len > RK_I2C_MAX_RXTX_LEN) 2243c2b2a28SEmmanuel Vadot len = RK_I2C_MAX_RXTX_LEN; 2253c2b2a28SEmmanuel Vadot 2263c2b2a28SEmmanuel Vadot for (i = 0; i < len; ) { 2273c2b2a28SEmmanuel Vadot buf32 = 0; 2283c2b2a28SEmmanuel Vadot 2293c2b2a28SEmmanuel Vadot /* Process next 4 bytes or whatever remains. */ 2303c2b2a28SEmmanuel Vadot for (j = 0; j < MIN(len - i, 4); j++) { 2313c2b2a28SEmmanuel Vadot /* Fill the addr if needed */ 2323c2b2a28SEmmanuel Vadot if (sc->tx_slave_addr) { 2333c2b2a28SEmmanuel Vadot buf = sc->msg->slave; 2343c2b2a28SEmmanuel Vadot sc->tx_slave_addr = false; 2353c2b2a28SEmmanuel Vadot } else { 2363c2b2a28SEmmanuel Vadot KASSERT(sc->cnt < sc->msg->len, 2373c2b2a28SEmmanuel Vadot ("%s: data buffer overrun", __func__)); 2383c2b2a28SEmmanuel Vadot buf = sc->msg->buf[sc->cnt]; 2393c2b2a28SEmmanuel Vadot sc->cnt++; 2403c2b2a28SEmmanuel Vadot } 2413c2b2a28SEmmanuel Vadot buf32 |= (uint32_t)buf << (j * 8); 2423c2b2a28SEmmanuel Vadot } 2433c2b2a28SEmmanuel Vadot 2443c2b2a28SEmmanuel Vadot KASSERT(i % 4 == 0, ("%s: misaligned write offset", __func__)); 2453c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_TXDATA_BASE + i, buf32); 2463c2b2a28SEmmanuel Vadot 2473c2b2a28SEmmanuel Vadot i += j; 2483c2b2a28SEmmanuel Vadot } 2493c2b2a28SEmmanuel Vadot 2503c2b2a28SEmmanuel Vadot return (len); 2513c2b2a28SEmmanuel Vadot } 2523c2b2a28SEmmanuel Vadot 2533c2b2a28SEmmanuel Vadot static void 2543c2b2a28SEmmanuel Vadot rk_i2c_drain_rx(struct rk_i2c_softc *sc) 2553c2b2a28SEmmanuel Vadot { 2563c2b2a28SEmmanuel Vadot uint32_t buf32 = 0; 2573c2b2a28SEmmanuel Vadot uint8_t buf8; 2583c2b2a28SEmmanuel Vadot int len; 2593c2b2a28SEmmanuel Vadot int i; 2603c2b2a28SEmmanuel Vadot 2613c2b2a28SEmmanuel Vadot if (sc->msg == NULL) { 2623c2b2a28SEmmanuel Vadot device_printf(sc->dev, "No current iic msg\n"); 2633c2b2a28SEmmanuel Vadot return; 2643c2b2a28SEmmanuel Vadot } 2653c2b2a28SEmmanuel Vadot 2663c2b2a28SEmmanuel Vadot len = sc->msg->len - sc->cnt; 2673c2b2a28SEmmanuel Vadot if (len > RK_I2C_MAX_RXTX_LEN) 2683c2b2a28SEmmanuel Vadot len = RK_I2C_MAX_RXTX_LEN; 2693c2b2a28SEmmanuel Vadot 2703c2b2a28SEmmanuel Vadot for (i = 0; i < len; i++) { 2713c2b2a28SEmmanuel Vadot if (i % 4 == 0) 2723c2b2a28SEmmanuel Vadot buf32 = RK_I2C_READ(sc, RK_I2C_RXDATA_BASE + i); 2733c2b2a28SEmmanuel Vadot 2743c2b2a28SEmmanuel Vadot buf8 = (buf32 >> ((i % 4) * 8)) & 0xFF; 2753c2b2a28SEmmanuel Vadot sc->msg->buf[sc->cnt++] = buf8; 2763c2b2a28SEmmanuel Vadot } 2773c2b2a28SEmmanuel Vadot } 2783c2b2a28SEmmanuel Vadot 2793c2b2a28SEmmanuel Vadot static void 2803c2b2a28SEmmanuel Vadot rk_i2c_send_stop(struct rk_i2c_softc *sc) 2813c2b2a28SEmmanuel Vadot { 2823c2b2a28SEmmanuel Vadot uint32_t reg; 2833c2b2a28SEmmanuel Vadot 284*0deaf4beSAndriy Gapon if (!(sc->msg->flags & IIC_M_NOSTOP)) { 2853c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_STOPIEN); 2863c2b2a28SEmmanuel Vadot 2873c2b2a28SEmmanuel Vadot sc->state = STATE_STOP; 2883c2b2a28SEmmanuel Vadot 2893c2b2a28SEmmanuel Vadot reg = RK_I2C_READ(sc, RK_I2C_CON); 2903c2b2a28SEmmanuel Vadot reg |= RK_I2C_CON_STOP; 2913c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_CON, reg); 292*0deaf4beSAndriy Gapon } else { 293*0deaf4beSAndriy Gapon /* 294*0deaf4beSAndriy Gapon * Do not actually set stop bit, set up conditions to 295*0deaf4beSAndriy Gapon * emulate repeated start by clearing all state. 296*0deaf4beSAndriy Gapon */ 297*0deaf4beSAndriy Gapon sc->state = STATE_IDLE; 298*0deaf4beSAndriy Gapon sc->transfer_done = 1; 299*0deaf4beSAndriy Gapon 300*0deaf4beSAndriy Gapon reg = RK_I2C_READ(sc, RK_I2C_CON); 301*0deaf4beSAndriy Gapon reg &= ~RK_I2C_CON_CTRL_MASK; 302*0deaf4beSAndriy Gapon RK_I2C_WRITE(sc, RK_I2C_CON, reg); 303*0deaf4beSAndriy Gapon } 3043c2b2a28SEmmanuel Vadot } 3053c2b2a28SEmmanuel Vadot 3063c2b2a28SEmmanuel Vadot static void 3073c2b2a28SEmmanuel Vadot rk_i2c_intr_locked(struct rk_i2c_softc *sc) 3083c2b2a28SEmmanuel Vadot { 3093c2b2a28SEmmanuel Vadot uint32_t reg; 3103c2b2a28SEmmanuel Vadot int transfer_len; 3113c2b2a28SEmmanuel Vadot 3123c2b2a28SEmmanuel Vadot sc->ipd = RK_I2C_READ(sc, RK_I2C_IPD); 3133c2b2a28SEmmanuel Vadot 3143c2b2a28SEmmanuel Vadot /* Something to handle? */ 3153c2b2a28SEmmanuel Vadot if ((sc->ipd & RK_I2C_IPD_ALL) == 0) 3163c2b2a28SEmmanuel Vadot return; 3173c2b2a28SEmmanuel Vadot 3183c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_IPD, sc->ipd); 3193c2b2a28SEmmanuel Vadot sc->ipd &= RK_I2C_IPD_ALL; 3203c2b2a28SEmmanuel Vadot 3213c2b2a28SEmmanuel Vadot if (sc->ipd & RK_I2C_IPD_NAKRCVIPD) { 3223c2b2a28SEmmanuel Vadot /* NACK received */ 3233c2b2a28SEmmanuel Vadot sc->ipd &= ~RK_I2C_IPD_NAKRCVIPD; 3243c2b2a28SEmmanuel Vadot sc->nak_recv = true; 3253c2b2a28SEmmanuel Vadot /* XXXX last byte !!!, signal error !!! */ 3263c2b2a28SEmmanuel Vadot sc->transfer_done = true; 3273c2b2a28SEmmanuel Vadot sc->state = STATE_IDLE; 3283c2b2a28SEmmanuel Vadot goto err; 3293c2b2a28SEmmanuel Vadot } 3303c2b2a28SEmmanuel Vadot 3313c2b2a28SEmmanuel Vadot switch (sc->state) { 3323c2b2a28SEmmanuel Vadot case STATE_START: 3333c2b2a28SEmmanuel Vadot /* Disable start bit */ 3343c2b2a28SEmmanuel Vadot reg = RK_I2C_READ(sc, RK_I2C_CON); 3353c2b2a28SEmmanuel Vadot reg &= ~RK_I2C_CON_START; 3363c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_CON, reg); 3373c2b2a28SEmmanuel Vadot 3383c2b2a28SEmmanuel Vadot if (sc->mode == RK_I2C_CON_MODE_RRX || 3393c2b2a28SEmmanuel Vadot sc->mode == RK_I2C_CON_MODE_RX) { 3403c2b2a28SEmmanuel Vadot sc->state = STATE_READ; 3413c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_MBRFIEN | 3423c2b2a28SEmmanuel Vadot RK_I2C_IEN_NAKRCVIEN); 3433c2b2a28SEmmanuel Vadot 3443c2b2a28SEmmanuel Vadot if ((sc->msg->len - sc->cnt) > 32) 3453c2b2a28SEmmanuel Vadot transfer_len = 32; 3463c2b2a28SEmmanuel Vadot else { 3473c2b2a28SEmmanuel Vadot transfer_len = sc->msg->len - sc->cnt; 3483c2b2a28SEmmanuel Vadot reg = RK_I2C_READ(sc, RK_I2C_CON); 3493c2b2a28SEmmanuel Vadot reg |= RK_I2C_CON_LASTACK; 3503c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_CON, reg); 3513c2b2a28SEmmanuel Vadot } 3523c2b2a28SEmmanuel Vadot 3533c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_MRXCNT, transfer_len); 3543c2b2a28SEmmanuel Vadot } else { 3553c2b2a28SEmmanuel Vadot sc->state = STATE_WRITE; 3563c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_MBTFIEN | 3573c2b2a28SEmmanuel Vadot RK_I2C_IEN_NAKRCVIEN); 3583c2b2a28SEmmanuel Vadot 3593c2b2a28SEmmanuel Vadot transfer_len = rk_i2c_fill_tx(sc); 3603c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_MTXCNT, transfer_len); 3613c2b2a28SEmmanuel Vadot } 3623c2b2a28SEmmanuel Vadot break; 3633c2b2a28SEmmanuel Vadot case STATE_READ: 3643c2b2a28SEmmanuel Vadot rk_i2c_drain_rx(sc); 3653c2b2a28SEmmanuel Vadot 366*0deaf4beSAndriy Gapon if (sc->cnt == sc->msg->len) { 3673c2b2a28SEmmanuel Vadot rk_i2c_send_stop(sc); 368*0deaf4beSAndriy Gapon } else { 3693c2b2a28SEmmanuel Vadot sc->mode = RK_I2C_CON_MODE_RX; 3703c2b2a28SEmmanuel Vadot reg = RK_I2C_READ(sc, RK_I2C_CON) & \ 3713c2b2a28SEmmanuel Vadot ~RK_I2C_CON_CTRL_MASK; 3723c2b2a28SEmmanuel Vadot reg |= sc->mode << RK_I2C_CON_MODE_SHIFT; 3733c2b2a28SEmmanuel Vadot reg |= RK_I2C_CON_EN; 3743c2b2a28SEmmanuel Vadot 3753c2b2a28SEmmanuel Vadot if ((sc->msg->len - sc->cnt) > 32) 3763c2b2a28SEmmanuel Vadot transfer_len = 32; 3773c2b2a28SEmmanuel Vadot else { 3783c2b2a28SEmmanuel Vadot transfer_len = sc->msg->len - sc->cnt; 3793c2b2a28SEmmanuel Vadot reg |= RK_I2C_CON_LASTACK; 3803c2b2a28SEmmanuel Vadot } 3813c2b2a28SEmmanuel Vadot 3823c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_CON, reg); 3833c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_MRXCNT, transfer_len); 3843c2b2a28SEmmanuel Vadot } 3853c2b2a28SEmmanuel Vadot break; 3863c2b2a28SEmmanuel Vadot case STATE_WRITE: 3873c2b2a28SEmmanuel Vadot if (sc->cnt < sc->msg->len) { 3883c2b2a28SEmmanuel Vadot /* Keep writing. */ 3893c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_MBTFIEN | 3903c2b2a28SEmmanuel Vadot RK_I2C_IEN_NAKRCVIEN); 3913c2b2a28SEmmanuel Vadot transfer_len = rk_i2c_fill_tx(sc); 3923c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_MTXCNT, transfer_len); 393*0deaf4beSAndriy Gapon } else { 3943c2b2a28SEmmanuel Vadot rk_i2c_send_stop(sc); 3953c2b2a28SEmmanuel Vadot } 396*0deaf4beSAndriy Gapon break; 3973c2b2a28SEmmanuel Vadot case STATE_STOP: 3983c2b2a28SEmmanuel Vadot /* Disable stop bit */ 3993c2b2a28SEmmanuel Vadot reg = RK_I2C_READ(sc, RK_I2C_CON); 4003c2b2a28SEmmanuel Vadot reg &= ~RK_I2C_CON_STOP; 4013c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_CON, reg); 4023c2b2a28SEmmanuel Vadot 4033c2b2a28SEmmanuel Vadot sc->transfer_done = 1; 4043c2b2a28SEmmanuel Vadot sc->state = STATE_IDLE; 4053c2b2a28SEmmanuel Vadot break; 4063c2b2a28SEmmanuel Vadot case STATE_IDLE: 4073c2b2a28SEmmanuel Vadot break; 4083c2b2a28SEmmanuel Vadot } 4093c2b2a28SEmmanuel Vadot 4103c2b2a28SEmmanuel Vadot err: 4113c2b2a28SEmmanuel Vadot wakeup(sc); 4123c2b2a28SEmmanuel Vadot } 4133c2b2a28SEmmanuel Vadot 4143c2b2a28SEmmanuel Vadot static void 4153c2b2a28SEmmanuel Vadot rk_i2c_intr(void *arg) 4163c2b2a28SEmmanuel Vadot { 4173c2b2a28SEmmanuel Vadot struct rk_i2c_softc *sc; 4183c2b2a28SEmmanuel Vadot 4193c2b2a28SEmmanuel Vadot sc = (struct rk_i2c_softc *)arg; 4203c2b2a28SEmmanuel Vadot 4213c2b2a28SEmmanuel Vadot RK_I2C_LOCK(sc); 4223c2b2a28SEmmanuel Vadot rk_i2c_intr_locked(sc); 4233c2b2a28SEmmanuel Vadot RK_I2C_UNLOCK(sc); 4243c2b2a28SEmmanuel Vadot } 4253c2b2a28SEmmanuel Vadot 4263c2b2a28SEmmanuel Vadot static void 4273c2b2a28SEmmanuel Vadot rk_i2c_start_xfer(struct rk_i2c_softc *sc, struct iic_msg *msg, boolean_t last) 4283c2b2a28SEmmanuel Vadot { 4293c2b2a28SEmmanuel Vadot uint32_t reg; 4303c2b2a28SEmmanuel Vadot uint8_t len; 4313c2b2a28SEmmanuel Vadot 4323c2b2a28SEmmanuel Vadot sc->transfer_done = false; 4333c2b2a28SEmmanuel Vadot sc->nak_recv = false; 4343c2b2a28SEmmanuel Vadot sc->tx_slave_addr = false; 4353c2b2a28SEmmanuel Vadot sc->cnt = 0; 4363c2b2a28SEmmanuel Vadot sc->state = STATE_IDLE; 4373c2b2a28SEmmanuel Vadot sc->msg = msg; 4383c2b2a28SEmmanuel Vadot 4393c2b2a28SEmmanuel Vadot reg = RK_I2C_READ(sc, RK_I2C_CON) & ~RK_I2C_CON_CTRL_MASK; 4403c2b2a28SEmmanuel Vadot if (!(sc->msg->flags & IIC_M_NOSTART)) { 4413c2b2a28SEmmanuel Vadot /* Stadard message */ 4423c2b2a28SEmmanuel Vadot if (sc->mode == RK_I2C_CON_MODE_TX) { 4433c2b2a28SEmmanuel Vadot sc->tx_slave_addr = true; 4443c2b2a28SEmmanuel Vadot } 4453c2b2a28SEmmanuel Vadot sc->state = STATE_START; 4463c2b2a28SEmmanuel Vadot reg |= RK_I2C_CON_START; 4473c2b2a28SEmmanuel Vadot 4483c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_STARTIEN); 4493c2b2a28SEmmanuel Vadot } else { 4503c2b2a28SEmmanuel Vadot /* Continuation message */ 4513c2b2a28SEmmanuel Vadot if (sc->mode == RK_I2C_CON_MODE_RX) { 4523c2b2a28SEmmanuel Vadot sc->state = STATE_READ; 4533c2b2a28SEmmanuel Vadot if (last) 4543c2b2a28SEmmanuel Vadot reg |= RK_I2C_CON_LASTACK; 4553c2b2a28SEmmanuel Vadot 4563c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_MRXCNT, sc->msg->len); 4573c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_MBRFIEN | 4583c2b2a28SEmmanuel Vadot RK_I2C_IEN_NAKRCVIEN); 4593c2b2a28SEmmanuel Vadot } else { 4603c2b2a28SEmmanuel Vadot sc->state = STATE_WRITE; 4613c2b2a28SEmmanuel Vadot len = rk_i2c_fill_tx(sc); 4623c2b2a28SEmmanuel Vadot 4633c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_MTXCNT, len); 4643c2b2a28SEmmanuel Vadot 4653c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_MBTFIEN | 4663c2b2a28SEmmanuel Vadot RK_I2C_IEN_NAKRCVIEN); 4673c2b2a28SEmmanuel Vadot } 4683c2b2a28SEmmanuel Vadot } 4693c2b2a28SEmmanuel Vadot reg |= RK_I2C_CON_NAKSTOP; 4703c2b2a28SEmmanuel Vadot reg |= sc->mode << RK_I2C_CON_MODE_SHIFT; 4713c2b2a28SEmmanuel Vadot reg |= RK_I2C_CON_EN; 4723c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_CON, reg); 4733c2b2a28SEmmanuel Vadot } 4743c2b2a28SEmmanuel Vadot 4753c2b2a28SEmmanuel Vadot static int 4763c2b2a28SEmmanuel Vadot rk_i2c_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) 4773c2b2a28SEmmanuel Vadot { 4783c2b2a28SEmmanuel Vadot struct rk_i2c_softc *sc; 4793c2b2a28SEmmanuel Vadot uint32_t reg; 4803c2b2a28SEmmanuel Vadot bool last_msg; 4813c2b2a28SEmmanuel Vadot int i, j, timeout, err; 4823c2b2a28SEmmanuel Vadot 4833c2b2a28SEmmanuel Vadot sc = device_get_softc(dev); 4843c2b2a28SEmmanuel Vadot 4853c2b2a28SEmmanuel Vadot RK_I2C_LOCK(sc); 4863c2b2a28SEmmanuel Vadot 4873c2b2a28SEmmanuel Vadot while (sc->busy) 4883c2b2a28SEmmanuel Vadot mtx_sleep(sc, &sc->mtx, 0, "i2cbuswait", 0); 4893c2b2a28SEmmanuel Vadot sc->busy = 1; 4903c2b2a28SEmmanuel Vadot 4913c2b2a28SEmmanuel Vadot /* Disable the module and interrupts */ 4923c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_CON, 0); 4933c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_IEN, 0); 4943c2b2a28SEmmanuel Vadot 4953c2b2a28SEmmanuel Vadot /* Clean stale interrupts */ 4963c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_IPD, RK_I2C_IPD_ALL); 4973c2b2a28SEmmanuel Vadot 4983c2b2a28SEmmanuel Vadot err = 0; 4993c2b2a28SEmmanuel Vadot for (i = 0; i < nmsgs; i++) { 5003c2b2a28SEmmanuel Vadot /* Validate parameters. */ 5013c2b2a28SEmmanuel Vadot if (msgs == NULL || msgs[i].buf == NULL || 5023c2b2a28SEmmanuel Vadot msgs[i].len == 0) { 5033c2b2a28SEmmanuel Vadot err = IIC_ENOTSUPP; 5043c2b2a28SEmmanuel Vadot break; 5053c2b2a28SEmmanuel Vadot } 5063c2b2a28SEmmanuel Vadot /* 5073c2b2a28SEmmanuel Vadot * If next message have NOSTART flag, then they both 5083c2b2a28SEmmanuel Vadot * should be same type (read/write) and same address. 5093c2b2a28SEmmanuel Vadot */ 5103c2b2a28SEmmanuel Vadot if (i < nmsgs - 1) { 5113c2b2a28SEmmanuel Vadot if ((msgs[i + 1].flags & IIC_M_NOSTART) && 5123c2b2a28SEmmanuel Vadot ((msgs[i].flags & IIC_M_RD) != 5133c2b2a28SEmmanuel Vadot (msgs[i + 1].flags & IIC_M_RD) || 5143c2b2a28SEmmanuel Vadot (msgs[i].slave != msgs[i + 1].slave))) { 5153c2b2a28SEmmanuel Vadot err = IIC_ENOTSUPP; 5163c2b2a28SEmmanuel Vadot break; 5173c2b2a28SEmmanuel Vadot } 5183c2b2a28SEmmanuel Vadot } 5193c2b2a28SEmmanuel Vadot /* 5203c2b2a28SEmmanuel Vadot * Detect simple register read case. 5213c2b2a28SEmmanuel Vadot * The first message should be IIC_M_WR | IIC_M_NOSTOP, 5223c2b2a28SEmmanuel Vadot * next pure IIC_M_RD (no other flags allowed). Both 5233c2b2a28SEmmanuel Vadot * messages should have same slave address. 5243c2b2a28SEmmanuel Vadot */ 5253c2b2a28SEmmanuel Vadot 5263c2b2a28SEmmanuel Vadot if (nmsgs - i >= 2 && msgs[i].len < 4 && 5273c2b2a28SEmmanuel Vadot msgs[i].flags == (IIC_M_WR | IIC_M_NOSTOP) && 5283c2b2a28SEmmanuel Vadot msgs[i + 1].flags == IIC_M_RD && 5293c2b2a28SEmmanuel Vadot (msgs[i].slave & ~LSB) == (msgs[i + 1].slave & ~LSB)) { 5303c2b2a28SEmmanuel Vadot sc->mode = RK_I2C_CON_MODE_RRX; 5313c2b2a28SEmmanuel Vadot 5323c2b2a28SEmmanuel Vadot /* Write slave address */ 5333c2b2a28SEmmanuel Vadot reg = msgs[i].slave & ~LSB; 5343c2b2a28SEmmanuel Vadot reg |= RK_I2C_MRXADDR_VALID(0); 5353c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_MRXADDR, reg); 5363c2b2a28SEmmanuel Vadot 5373c2b2a28SEmmanuel Vadot /* Write slave register address */ 5383c2b2a28SEmmanuel Vadot reg = 0; 5393c2b2a28SEmmanuel Vadot for (j = 0; j < msgs[i].len ; j++) { 5403c2b2a28SEmmanuel Vadot reg |= (uint32_t)msgs[i].buf[j] << (j * 8); 5413c2b2a28SEmmanuel Vadot reg |= RK_I2C_MRXADDR_VALID(j); 5423c2b2a28SEmmanuel Vadot } 5433c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_MRXRADDR, reg); 5443c2b2a28SEmmanuel Vadot 5453c2b2a28SEmmanuel Vadot i++; 5463c2b2a28SEmmanuel Vadot } else { 5473c2b2a28SEmmanuel Vadot if (msgs[i].flags & IIC_M_RD) { 5483c2b2a28SEmmanuel Vadot if (msgs[i].flags & IIC_M_NOSTART) { 5493c2b2a28SEmmanuel Vadot sc->mode = RK_I2C_CON_MODE_RX; 5503c2b2a28SEmmanuel Vadot } else { 5513c2b2a28SEmmanuel Vadot sc->mode = RK_I2C_CON_MODE_RRX; 5523c2b2a28SEmmanuel Vadot reg = msgs[i].slave & ~LSB; 5533c2b2a28SEmmanuel Vadot reg |= RK_I2C_MRXADDR_VALID(0); 5543c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_MRXADDR, reg); 5553c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_MRXRADDR, 0); 5563c2b2a28SEmmanuel Vadot } 5573c2b2a28SEmmanuel Vadot } else { 5583c2b2a28SEmmanuel Vadot sc->mode = RK_I2C_CON_MODE_TX; 5593c2b2a28SEmmanuel Vadot } 5603c2b2a28SEmmanuel Vadot } 5613c2b2a28SEmmanuel Vadot /* last message ? */ 5623c2b2a28SEmmanuel Vadot last_msg = (i >= nmsgs - 1) || 5633c2b2a28SEmmanuel Vadot !(msgs[i + 1].flags & IIC_M_NOSTART); 5643c2b2a28SEmmanuel Vadot rk_i2c_start_xfer(sc, msgs + i, last_msg); 5653c2b2a28SEmmanuel Vadot 5663c2b2a28SEmmanuel Vadot if (cold) { 5673c2b2a28SEmmanuel Vadot for(timeout = 10000; timeout > 0; timeout--) { 5683c2b2a28SEmmanuel Vadot rk_i2c_intr_locked(sc); 5693c2b2a28SEmmanuel Vadot if (sc->transfer_done) 5703c2b2a28SEmmanuel Vadot break; 5713c2b2a28SEmmanuel Vadot DELAY(1000); 5723c2b2a28SEmmanuel Vadot } 5733c2b2a28SEmmanuel Vadot if (timeout <= 0) 5743c2b2a28SEmmanuel Vadot err = IIC_ETIMEOUT; 5753c2b2a28SEmmanuel Vadot } else { 5763c2b2a28SEmmanuel Vadot while (err == 0 && !sc->transfer_done) { 5773c2b2a28SEmmanuel Vadot err = msleep(sc, &sc->mtx, PZERO, "rk_i2c", 5783c2b2a28SEmmanuel Vadot 10 * hz); 5793c2b2a28SEmmanuel Vadot } 5803c2b2a28SEmmanuel Vadot } 5813c2b2a28SEmmanuel Vadot } 5823c2b2a28SEmmanuel Vadot 5833c2b2a28SEmmanuel Vadot /* Disable the module and interrupts */ 5843c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_CON, 0); 5853c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_IEN, 0); 5863c2b2a28SEmmanuel Vadot 5873c2b2a28SEmmanuel Vadot sc->busy = 0; 5883c2b2a28SEmmanuel Vadot 5893c2b2a28SEmmanuel Vadot if (sc->nak_recv) 5903c2b2a28SEmmanuel Vadot err = IIC_ENOACK; 5913c2b2a28SEmmanuel Vadot 5923c2b2a28SEmmanuel Vadot RK_I2C_UNLOCK(sc); 5933c2b2a28SEmmanuel Vadot return (err); 5943c2b2a28SEmmanuel Vadot } 5953c2b2a28SEmmanuel Vadot 5963c2b2a28SEmmanuel Vadot static int 5973c2b2a28SEmmanuel Vadot rk_i2c_probe(device_t dev) 5983c2b2a28SEmmanuel Vadot { 5993c2b2a28SEmmanuel Vadot 6003c2b2a28SEmmanuel Vadot if (!ofw_bus_status_okay(dev)) 6013c2b2a28SEmmanuel Vadot return (ENXIO); 6023c2b2a28SEmmanuel Vadot if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 6033c2b2a28SEmmanuel Vadot return (ENXIO); 6043c2b2a28SEmmanuel Vadot 6053c2b2a28SEmmanuel Vadot device_set_desc(dev, "RockChip I2C"); 6063c2b2a28SEmmanuel Vadot return (BUS_PROBE_DEFAULT); 6073c2b2a28SEmmanuel Vadot } 6083c2b2a28SEmmanuel Vadot 6093c2b2a28SEmmanuel Vadot static int 6103c2b2a28SEmmanuel Vadot rk_i2c_attach(device_t dev) 6113c2b2a28SEmmanuel Vadot { 6123c2b2a28SEmmanuel Vadot struct rk_i2c_softc *sc; 6133c2b2a28SEmmanuel Vadot int error; 6143c2b2a28SEmmanuel Vadot 6153c2b2a28SEmmanuel Vadot sc = device_get_softc(dev); 6163c2b2a28SEmmanuel Vadot sc->dev = dev; 6173c2b2a28SEmmanuel Vadot 6183c2b2a28SEmmanuel Vadot mtx_init(&sc->mtx, device_get_nameunit(dev), "rk_i2c", MTX_DEF); 6193c2b2a28SEmmanuel Vadot 6203c2b2a28SEmmanuel Vadot if (bus_alloc_resources(dev, rk_i2c_spec, sc->res) != 0) { 6213c2b2a28SEmmanuel Vadot device_printf(dev, "cannot allocate resources for device\n"); 6223c2b2a28SEmmanuel Vadot error = ENXIO; 6233c2b2a28SEmmanuel Vadot goto fail; 6243c2b2a28SEmmanuel Vadot } 6253c2b2a28SEmmanuel Vadot 6263c2b2a28SEmmanuel Vadot if (bus_setup_intr(dev, sc->res[1], 6273c2b2a28SEmmanuel Vadot INTR_TYPE_MISC | INTR_MPSAFE, NULL, rk_i2c_intr, sc, 6283c2b2a28SEmmanuel Vadot &sc->intrhand)) { 6293c2b2a28SEmmanuel Vadot bus_release_resources(dev, rk_i2c_spec, sc->res); 6303c2b2a28SEmmanuel Vadot device_printf(dev, "cannot setup interrupt handler\n"); 6313c2b2a28SEmmanuel Vadot return (ENXIO); 6323c2b2a28SEmmanuel Vadot } 6333c2b2a28SEmmanuel Vadot 6343c2b2a28SEmmanuel Vadot clk_set_assigned(dev, ofw_bus_get_node(dev)); 6353c2b2a28SEmmanuel Vadot 6363c2b2a28SEmmanuel Vadot /* Activate the module clocks. */ 6373c2b2a28SEmmanuel Vadot error = clk_get_by_ofw_name(dev, 0, "i2c", &sc->sclk); 6383c2b2a28SEmmanuel Vadot if (error != 0) { 6393c2b2a28SEmmanuel Vadot device_printf(dev, "cannot get i2c clock\n"); 6403c2b2a28SEmmanuel Vadot goto fail; 6413c2b2a28SEmmanuel Vadot } 6423c2b2a28SEmmanuel Vadot error = clk_enable(sc->sclk); 6433c2b2a28SEmmanuel Vadot if (error != 0) { 6443c2b2a28SEmmanuel Vadot device_printf(dev, "cannot enable i2c clock\n"); 6453c2b2a28SEmmanuel Vadot goto fail; 6463c2b2a28SEmmanuel Vadot } 6473c2b2a28SEmmanuel Vadot /* pclk clock is optional. */ 6483c2b2a28SEmmanuel Vadot error = clk_get_by_ofw_name(dev, 0, "pclk", &sc->pclk); 6493c2b2a28SEmmanuel Vadot if (error != 0 && error != ENOENT) { 6503c2b2a28SEmmanuel Vadot device_printf(dev, "cannot get pclk clock\n"); 6513c2b2a28SEmmanuel Vadot goto fail; 6523c2b2a28SEmmanuel Vadot } 6533c2b2a28SEmmanuel Vadot if (sc->pclk != NULL) { 6543c2b2a28SEmmanuel Vadot error = clk_enable(sc->pclk); 6553c2b2a28SEmmanuel Vadot if (error != 0) { 6563c2b2a28SEmmanuel Vadot device_printf(dev, "cannot enable pclk clock\n"); 6573c2b2a28SEmmanuel Vadot goto fail; 6583c2b2a28SEmmanuel Vadot } 6593c2b2a28SEmmanuel Vadot } 6603c2b2a28SEmmanuel Vadot 6613c2b2a28SEmmanuel Vadot sc->iicbus = device_add_child(dev, "iicbus", -1); 6623c2b2a28SEmmanuel Vadot if (sc->iicbus == NULL) { 6633c2b2a28SEmmanuel Vadot device_printf(dev, "cannot add iicbus child device\n"); 6643c2b2a28SEmmanuel Vadot error = ENXIO; 6653c2b2a28SEmmanuel Vadot goto fail; 6663c2b2a28SEmmanuel Vadot } 6673c2b2a28SEmmanuel Vadot 6683c2b2a28SEmmanuel Vadot bus_generic_attach(dev); 6693c2b2a28SEmmanuel Vadot 6703c2b2a28SEmmanuel Vadot return (0); 6713c2b2a28SEmmanuel Vadot 6723c2b2a28SEmmanuel Vadot fail: 6733c2b2a28SEmmanuel Vadot if (rk_i2c_detach(dev) != 0) 6743c2b2a28SEmmanuel Vadot device_printf(dev, "Failed to detach\n"); 6753c2b2a28SEmmanuel Vadot return (error); 6763c2b2a28SEmmanuel Vadot } 6773c2b2a28SEmmanuel Vadot 6783c2b2a28SEmmanuel Vadot static int 6793c2b2a28SEmmanuel Vadot rk_i2c_detach(device_t dev) 6803c2b2a28SEmmanuel Vadot { 6813c2b2a28SEmmanuel Vadot struct rk_i2c_softc *sc; 6823c2b2a28SEmmanuel Vadot int error; 6833c2b2a28SEmmanuel Vadot 6843c2b2a28SEmmanuel Vadot sc = device_get_softc(dev); 6853c2b2a28SEmmanuel Vadot 6863c2b2a28SEmmanuel Vadot if ((error = bus_generic_detach(dev)) != 0) 6873c2b2a28SEmmanuel Vadot return (error); 6883c2b2a28SEmmanuel Vadot 6893c2b2a28SEmmanuel Vadot if (sc->iicbus != NULL) 6903c2b2a28SEmmanuel Vadot if ((error = device_delete_child(dev, sc->iicbus)) != 0) 6913c2b2a28SEmmanuel Vadot return (error); 6923c2b2a28SEmmanuel Vadot 6933c2b2a28SEmmanuel Vadot if (sc->sclk != NULL) 6943c2b2a28SEmmanuel Vadot clk_release(sc->sclk); 6953c2b2a28SEmmanuel Vadot if (sc->pclk != NULL) 6963c2b2a28SEmmanuel Vadot clk_release(sc->pclk); 6973c2b2a28SEmmanuel Vadot 6983c2b2a28SEmmanuel Vadot if (sc->intrhand != NULL) 6993c2b2a28SEmmanuel Vadot bus_teardown_intr(sc->dev, sc->res[1], sc->intrhand); 7003c2b2a28SEmmanuel Vadot 7013c2b2a28SEmmanuel Vadot bus_release_resources(dev, rk_i2c_spec, sc->res); 7023c2b2a28SEmmanuel Vadot 7033c2b2a28SEmmanuel Vadot mtx_destroy(&sc->mtx); 7043c2b2a28SEmmanuel Vadot 7053c2b2a28SEmmanuel Vadot return (0); 7063c2b2a28SEmmanuel Vadot } 7073c2b2a28SEmmanuel Vadot 7083c2b2a28SEmmanuel Vadot static phandle_t 7093c2b2a28SEmmanuel Vadot rk_i2c_get_node(device_t bus, device_t dev) 7103c2b2a28SEmmanuel Vadot { 7113c2b2a28SEmmanuel Vadot 7123c2b2a28SEmmanuel Vadot return ofw_bus_get_node(bus); 7133c2b2a28SEmmanuel Vadot } 7143c2b2a28SEmmanuel Vadot 7153c2b2a28SEmmanuel Vadot static device_method_t rk_i2c_methods[] = { 7163c2b2a28SEmmanuel Vadot DEVMETHOD(device_probe, rk_i2c_probe), 7173c2b2a28SEmmanuel Vadot DEVMETHOD(device_attach, rk_i2c_attach), 7183c2b2a28SEmmanuel Vadot DEVMETHOD(device_detach, rk_i2c_detach), 7193c2b2a28SEmmanuel Vadot 7203c2b2a28SEmmanuel Vadot /* OFW methods */ 7213c2b2a28SEmmanuel Vadot DEVMETHOD(ofw_bus_get_node, rk_i2c_get_node), 7223c2b2a28SEmmanuel Vadot 7233c2b2a28SEmmanuel Vadot DEVMETHOD(iicbus_callback, iicbus_null_callback), 7243c2b2a28SEmmanuel Vadot DEVMETHOD(iicbus_reset, rk_i2c_reset), 7253c2b2a28SEmmanuel Vadot DEVMETHOD(iicbus_transfer, rk_i2c_transfer), 7263c2b2a28SEmmanuel Vadot 7273c2b2a28SEmmanuel Vadot DEVMETHOD_END 7283c2b2a28SEmmanuel Vadot }; 7293c2b2a28SEmmanuel Vadot 7303c2b2a28SEmmanuel Vadot static driver_t rk_i2c_driver = { 7313c2b2a28SEmmanuel Vadot "rk_i2c", 7323c2b2a28SEmmanuel Vadot rk_i2c_methods, 7333c2b2a28SEmmanuel Vadot sizeof(struct rk_i2c_softc), 7343c2b2a28SEmmanuel Vadot }; 7353c2b2a28SEmmanuel Vadot 7363c2b2a28SEmmanuel Vadot EARLY_DRIVER_MODULE(rk_i2c, simplebus, rk_i2c_driver, 0, 0, 7373c2b2a28SEmmanuel Vadot BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE); 7383c2b2a28SEmmanuel Vadot EARLY_DRIVER_MODULE(ofw_iicbus, rk_i2c, ofw_iicbus_driver, 7393c2b2a28SEmmanuel Vadot 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE); 7403c2b2a28SEmmanuel Vadot MODULE_DEPEND(rk_i2c, iicbus, 1, 1, 1); 7413c2b2a28SEmmanuel Vadot MODULE_VERSION(rk_i2c, 1); 742