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 42*be82b3a0SEmmanuel 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 2843c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_STOPIEN); 2853c2b2a28SEmmanuel Vadot 2863c2b2a28SEmmanuel Vadot sc->state = STATE_STOP; 2873c2b2a28SEmmanuel Vadot 2883c2b2a28SEmmanuel Vadot reg = RK_I2C_READ(sc, RK_I2C_CON); 2893c2b2a28SEmmanuel Vadot reg |= RK_I2C_CON_STOP; 2903c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_CON, reg); 2913c2b2a28SEmmanuel Vadot } 2923c2b2a28SEmmanuel Vadot 2933c2b2a28SEmmanuel Vadot static void 2943c2b2a28SEmmanuel Vadot rk_i2c_intr_locked(struct rk_i2c_softc *sc) 2953c2b2a28SEmmanuel Vadot { 2963c2b2a28SEmmanuel Vadot uint32_t reg; 2973c2b2a28SEmmanuel Vadot int transfer_len; 2983c2b2a28SEmmanuel Vadot 2993c2b2a28SEmmanuel Vadot sc->ipd = RK_I2C_READ(sc, RK_I2C_IPD); 3003c2b2a28SEmmanuel Vadot 3013c2b2a28SEmmanuel Vadot /* Something to handle? */ 3023c2b2a28SEmmanuel Vadot if ((sc->ipd & RK_I2C_IPD_ALL) == 0) 3033c2b2a28SEmmanuel Vadot return; 3043c2b2a28SEmmanuel Vadot 3053c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_IPD, sc->ipd); 3063c2b2a28SEmmanuel Vadot sc->ipd &= RK_I2C_IPD_ALL; 3073c2b2a28SEmmanuel Vadot 3083c2b2a28SEmmanuel Vadot if (sc->ipd & RK_I2C_IPD_NAKRCVIPD) { 3093c2b2a28SEmmanuel Vadot /* NACK received */ 3103c2b2a28SEmmanuel Vadot sc->ipd &= ~RK_I2C_IPD_NAKRCVIPD; 3113c2b2a28SEmmanuel Vadot sc->nak_recv = true; 3123c2b2a28SEmmanuel Vadot /* XXXX last byte !!!, signal error !!! */ 3133c2b2a28SEmmanuel Vadot sc->transfer_done = true; 3143c2b2a28SEmmanuel Vadot sc->state = STATE_IDLE; 3153c2b2a28SEmmanuel Vadot goto err; 3163c2b2a28SEmmanuel Vadot } 3173c2b2a28SEmmanuel Vadot 3183c2b2a28SEmmanuel Vadot switch (sc->state) { 3193c2b2a28SEmmanuel Vadot case STATE_START: 3203c2b2a28SEmmanuel Vadot /* Disable start bit */ 3213c2b2a28SEmmanuel Vadot reg = RK_I2C_READ(sc, RK_I2C_CON); 3223c2b2a28SEmmanuel Vadot reg &= ~RK_I2C_CON_START; 3233c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_CON, reg); 3243c2b2a28SEmmanuel Vadot 3253c2b2a28SEmmanuel Vadot if (sc->mode == RK_I2C_CON_MODE_RRX || 3263c2b2a28SEmmanuel Vadot sc->mode == RK_I2C_CON_MODE_RX) { 3273c2b2a28SEmmanuel Vadot sc->state = STATE_READ; 3283c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_MBRFIEN | 3293c2b2a28SEmmanuel Vadot RK_I2C_IEN_NAKRCVIEN); 3303c2b2a28SEmmanuel Vadot 3313c2b2a28SEmmanuel Vadot if ((sc->msg->len - sc->cnt) > 32) 3323c2b2a28SEmmanuel Vadot transfer_len = 32; 3333c2b2a28SEmmanuel Vadot else { 3343c2b2a28SEmmanuel Vadot transfer_len = sc->msg->len - sc->cnt; 3353c2b2a28SEmmanuel Vadot reg = RK_I2C_READ(sc, RK_I2C_CON); 3363c2b2a28SEmmanuel Vadot reg |= RK_I2C_CON_LASTACK; 3373c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_CON, reg); 3383c2b2a28SEmmanuel Vadot } 3393c2b2a28SEmmanuel Vadot 3403c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_MRXCNT, transfer_len); 3413c2b2a28SEmmanuel Vadot } else { 3423c2b2a28SEmmanuel Vadot sc->state = STATE_WRITE; 3433c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_MBTFIEN | 3443c2b2a28SEmmanuel Vadot RK_I2C_IEN_NAKRCVIEN); 3453c2b2a28SEmmanuel Vadot 3463c2b2a28SEmmanuel Vadot transfer_len = rk_i2c_fill_tx(sc); 3473c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_MTXCNT, transfer_len); 3483c2b2a28SEmmanuel Vadot } 3493c2b2a28SEmmanuel Vadot break; 3503c2b2a28SEmmanuel Vadot case STATE_READ: 3513c2b2a28SEmmanuel Vadot rk_i2c_drain_rx(sc); 3523c2b2a28SEmmanuel Vadot 3533c2b2a28SEmmanuel Vadot if (sc->cnt == sc->msg->len) 3543c2b2a28SEmmanuel Vadot rk_i2c_send_stop(sc); 3553c2b2a28SEmmanuel Vadot else { 3563c2b2a28SEmmanuel Vadot sc->mode = RK_I2C_CON_MODE_RX; 3573c2b2a28SEmmanuel Vadot reg = RK_I2C_READ(sc, RK_I2C_CON) & \ 3583c2b2a28SEmmanuel Vadot ~RK_I2C_CON_CTRL_MASK; 3593c2b2a28SEmmanuel Vadot reg |= sc->mode << RK_I2C_CON_MODE_SHIFT; 3603c2b2a28SEmmanuel Vadot reg |= RK_I2C_CON_EN; 3613c2b2a28SEmmanuel Vadot 3623c2b2a28SEmmanuel Vadot if ((sc->msg->len - sc->cnt) > 32) 3633c2b2a28SEmmanuel Vadot transfer_len = 32; 3643c2b2a28SEmmanuel Vadot else { 3653c2b2a28SEmmanuel Vadot transfer_len = sc->msg->len - sc->cnt; 3663c2b2a28SEmmanuel Vadot reg |= RK_I2C_CON_LASTACK; 3673c2b2a28SEmmanuel Vadot } 3683c2b2a28SEmmanuel Vadot 3693c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_CON, reg); 3703c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_MRXCNT, transfer_len); 3713c2b2a28SEmmanuel Vadot } 3723c2b2a28SEmmanuel Vadot 3733c2b2a28SEmmanuel Vadot break; 3743c2b2a28SEmmanuel Vadot case STATE_WRITE: 3753c2b2a28SEmmanuel Vadot if (sc->cnt < sc->msg->len) { 3763c2b2a28SEmmanuel Vadot /* Keep writing. */ 3773c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_MBTFIEN | 3783c2b2a28SEmmanuel Vadot RK_I2C_IEN_NAKRCVIEN); 3793c2b2a28SEmmanuel Vadot transfer_len = rk_i2c_fill_tx(sc); 3803c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_MTXCNT, transfer_len); 3813c2b2a28SEmmanuel Vadot break; 3823c2b2a28SEmmanuel Vadot } else if (!(sc->msg->flags & IIC_M_NOSTOP)) { 3833c2b2a28SEmmanuel Vadot rk_i2c_send_stop(sc); 3843c2b2a28SEmmanuel Vadot break; 3853c2b2a28SEmmanuel Vadot } 3863c2b2a28SEmmanuel Vadot /* passthru */ 3873c2b2a28SEmmanuel Vadot case STATE_STOP: 3883c2b2a28SEmmanuel Vadot /* Disable stop bit */ 3893c2b2a28SEmmanuel Vadot reg = RK_I2C_READ(sc, RK_I2C_CON); 3903c2b2a28SEmmanuel Vadot reg &= ~RK_I2C_CON_STOP; 3913c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_CON, reg); 3923c2b2a28SEmmanuel Vadot 3933c2b2a28SEmmanuel Vadot sc->transfer_done = 1; 3943c2b2a28SEmmanuel Vadot sc->state = STATE_IDLE; 3953c2b2a28SEmmanuel Vadot break; 3963c2b2a28SEmmanuel Vadot case STATE_IDLE: 3973c2b2a28SEmmanuel Vadot break; 3983c2b2a28SEmmanuel Vadot } 3993c2b2a28SEmmanuel Vadot 4003c2b2a28SEmmanuel Vadot err: 4013c2b2a28SEmmanuel Vadot wakeup(sc); 4023c2b2a28SEmmanuel Vadot } 4033c2b2a28SEmmanuel Vadot 4043c2b2a28SEmmanuel Vadot static void 4053c2b2a28SEmmanuel Vadot rk_i2c_intr(void *arg) 4063c2b2a28SEmmanuel Vadot { 4073c2b2a28SEmmanuel Vadot struct rk_i2c_softc *sc; 4083c2b2a28SEmmanuel Vadot 4093c2b2a28SEmmanuel Vadot sc = (struct rk_i2c_softc *)arg; 4103c2b2a28SEmmanuel Vadot 4113c2b2a28SEmmanuel Vadot RK_I2C_LOCK(sc); 4123c2b2a28SEmmanuel Vadot rk_i2c_intr_locked(sc); 4133c2b2a28SEmmanuel Vadot RK_I2C_UNLOCK(sc); 4143c2b2a28SEmmanuel Vadot } 4153c2b2a28SEmmanuel Vadot 4163c2b2a28SEmmanuel Vadot static void 4173c2b2a28SEmmanuel Vadot rk_i2c_start_xfer(struct rk_i2c_softc *sc, struct iic_msg *msg, boolean_t last) 4183c2b2a28SEmmanuel Vadot { 4193c2b2a28SEmmanuel Vadot uint32_t reg; 4203c2b2a28SEmmanuel Vadot uint8_t len; 4213c2b2a28SEmmanuel Vadot 4223c2b2a28SEmmanuel Vadot sc->transfer_done = false; 4233c2b2a28SEmmanuel Vadot sc->nak_recv = false; 4243c2b2a28SEmmanuel Vadot sc->tx_slave_addr = false; 4253c2b2a28SEmmanuel Vadot sc->cnt = 0; 4263c2b2a28SEmmanuel Vadot sc->state = STATE_IDLE; 4273c2b2a28SEmmanuel Vadot sc->msg = msg; 4283c2b2a28SEmmanuel Vadot 4293c2b2a28SEmmanuel Vadot reg = RK_I2C_READ(sc, RK_I2C_CON) & ~RK_I2C_CON_CTRL_MASK; 4303c2b2a28SEmmanuel Vadot if (!(sc->msg->flags & IIC_M_NOSTART)) { 4313c2b2a28SEmmanuel Vadot /* Stadard message */ 4323c2b2a28SEmmanuel Vadot if (sc->mode == RK_I2C_CON_MODE_TX) { 4333c2b2a28SEmmanuel Vadot sc->tx_slave_addr = true; 4343c2b2a28SEmmanuel Vadot } 4353c2b2a28SEmmanuel Vadot sc->state = STATE_START; 4363c2b2a28SEmmanuel Vadot reg |= RK_I2C_CON_START; 4373c2b2a28SEmmanuel Vadot 4383c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_STARTIEN); 4393c2b2a28SEmmanuel Vadot } else { 4403c2b2a28SEmmanuel Vadot /* Continuation message */ 4413c2b2a28SEmmanuel Vadot if (sc->mode == RK_I2C_CON_MODE_RX) { 4423c2b2a28SEmmanuel Vadot sc->state = STATE_READ; 4433c2b2a28SEmmanuel Vadot if (last) 4443c2b2a28SEmmanuel Vadot reg |= RK_I2C_CON_LASTACK; 4453c2b2a28SEmmanuel Vadot 4463c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_MRXCNT, sc->msg->len); 4473c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_MBRFIEN | 4483c2b2a28SEmmanuel Vadot RK_I2C_IEN_NAKRCVIEN); 4493c2b2a28SEmmanuel Vadot } else { 4503c2b2a28SEmmanuel Vadot sc->state = STATE_WRITE; 4513c2b2a28SEmmanuel Vadot len = rk_i2c_fill_tx(sc); 4523c2b2a28SEmmanuel Vadot 4533c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_MTXCNT, len); 4543c2b2a28SEmmanuel Vadot 4553c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_MBTFIEN | 4563c2b2a28SEmmanuel Vadot RK_I2C_IEN_NAKRCVIEN); 4573c2b2a28SEmmanuel Vadot } 4583c2b2a28SEmmanuel Vadot } 4593c2b2a28SEmmanuel Vadot reg |= RK_I2C_CON_NAKSTOP; 4603c2b2a28SEmmanuel Vadot reg |= sc->mode << RK_I2C_CON_MODE_SHIFT; 4613c2b2a28SEmmanuel Vadot reg |= RK_I2C_CON_EN; 4623c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_CON, reg); 4633c2b2a28SEmmanuel Vadot } 4643c2b2a28SEmmanuel Vadot 4653c2b2a28SEmmanuel Vadot static int 4663c2b2a28SEmmanuel Vadot rk_i2c_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) 4673c2b2a28SEmmanuel Vadot { 4683c2b2a28SEmmanuel Vadot struct rk_i2c_softc *sc; 4693c2b2a28SEmmanuel Vadot uint32_t reg; 4703c2b2a28SEmmanuel Vadot bool last_msg; 4713c2b2a28SEmmanuel Vadot int i, j, timeout, err; 4723c2b2a28SEmmanuel Vadot 4733c2b2a28SEmmanuel Vadot sc = device_get_softc(dev); 4743c2b2a28SEmmanuel Vadot 4753c2b2a28SEmmanuel Vadot RK_I2C_LOCK(sc); 4763c2b2a28SEmmanuel Vadot 4773c2b2a28SEmmanuel Vadot while (sc->busy) 4783c2b2a28SEmmanuel Vadot mtx_sleep(sc, &sc->mtx, 0, "i2cbuswait", 0); 4793c2b2a28SEmmanuel Vadot sc->busy = 1; 4803c2b2a28SEmmanuel Vadot 4813c2b2a28SEmmanuel Vadot /* Disable the module and interrupts */ 4823c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_CON, 0); 4833c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_IEN, 0); 4843c2b2a28SEmmanuel Vadot 4853c2b2a28SEmmanuel Vadot /* Clean stale interrupts */ 4863c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_IPD, RK_I2C_IPD_ALL); 4873c2b2a28SEmmanuel Vadot 4883c2b2a28SEmmanuel Vadot err = 0; 4893c2b2a28SEmmanuel Vadot for (i = 0; i < nmsgs; i++) { 4903c2b2a28SEmmanuel Vadot /* Validate parameters. */ 4913c2b2a28SEmmanuel Vadot if (msgs == NULL || msgs[i].buf == NULL || 4923c2b2a28SEmmanuel Vadot msgs[i].len == 0) { 4933c2b2a28SEmmanuel Vadot err = IIC_ENOTSUPP; 4943c2b2a28SEmmanuel Vadot break; 4953c2b2a28SEmmanuel Vadot } 4963c2b2a28SEmmanuel Vadot /* 4973c2b2a28SEmmanuel Vadot * If next message have NOSTART flag, then they both 4983c2b2a28SEmmanuel Vadot * should be same type (read/write) and same address. 4993c2b2a28SEmmanuel Vadot */ 5003c2b2a28SEmmanuel Vadot if (i < nmsgs - 1) { 5013c2b2a28SEmmanuel Vadot if ((msgs[i + 1].flags & IIC_M_NOSTART) && 5023c2b2a28SEmmanuel Vadot ((msgs[i].flags & IIC_M_RD) != 5033c2b2a28SEmmanuel Vadot (msgs[i + 1].flags & IIC_M_RD) || 5043c2b2a28SEmmanuel Vadot (msgs[i].slave != msgs[i + 1].slave))) { 5053c2b2a28SEmmanuel Vadot err = IIC_ENOTSUPP; 5063c2b2a28SEmmanuel Vadot break; 5073c2b2a28SEmmanuel Vadot } 5083c2b2a28SEmmanuel Vadot } 5093c2b2a28SEmmanuel Vadot /* 5103c2b2a28SEmmanuel Vadot * Detect simple register read case. 5113c2b2a28SEmmanuel Vadot * The first message should be IIC_M_WR | IIC_M_NOSTOP, 5123c2b2a28SEmmanuel Vadot * next pure IIC_M_RD (no other flags allowed). Both 5133c2b2a28SEmmanuel Vadot * messages should have same slave address. 5143c2b2a28SEmmanuel Vadot */ 5153c2b2a28SEmmanuel Vadot 5163c2b2a28SEmmanuel Vadot if (nmsgs - i >= 2 && msgs[i].len < 4 && 5173c2b2a28SEmmanuel Vadot msgs[i].flags == (IIC_M_WR | IIC_M_NOSTOP) && 5183c2b2a28SEmmanuel Vadot msgs[i + 1].flags == IIC_M_RD && 5193c2b2a28SEmmanuel Vadot (msgs[i].slave & ~LSB) == (msgs[i + 1].slave & ~LSB)) { 5203c2b2a28SEmmanuel Vadot sc->mode = RK_I2C_CON_MODE_RRX; 5213c2b2a28SEmmanuel Vadot 5223c2b2a28SEmmanuel Vadot /* Write slave address */ 5233c2b2a28SEmmanuel Vadot reg = msgs[i].slave & ~LSB; 5243c2b2a28SEmmanuel Vadot reg |= RK_I2C_MRXADDR_VALID(0); 5253c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_MRXADDR, reg); 5263c2b2a28SEmmanuel Vadot 5273c2b2a28SEmmanuel Vadot /* Write slave register address */ 5283c2b2a28SEmmanuel Vadot reg = 0; 5293c2b2a28SEmmanuel Vadot for (j = 0; j < msgs[i].len ; j++) { 5303c2b2a28SEmmanuel Vadot reg |= (uint32_t)msgs[i].buf[j] << (j * 8); 5313c2b2a28SEmmanuel Vadot reg |= RK_I2C_MRXADDR_VALID(j); 5323c2b2a28SEmmanuel Vadot } 5333c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_MRXRADDR, reg); 5343c2b2a28SEmmanuel Vadot 5353c2b2a28SEmmanuel Vadot i++; 5363c2b2a28SEmmanuel Vadot } else { 5373c2b2a28SEmmanuel Vadot if (msgs[i].flags & IIC_M_RD) { 5383c2b2a28SEmmanuel Vadot if (msgs[i].flags & IIC_M_NOSTART) { 5393c2b2a28SEmmanuel Vadot sc->mode = RK_I2C_CON_MODE_RX; 5403c2b2a28SEmmanuel Vadot } else { 5413c2b2a28SEmmanuel Vadot sc->mode = RK_I2C_CON_MODE_RRX; 5423c2b2a28SEmmanuel Vadot reg = msgs[i].slave & ~LSB; 5433c2b2a28SEmmanuel Vadot reg |= RK_I2C_MRXADDR_VALID(0); 5443c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_MRXADDR, reg); 5453c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_MRXRADDR, 0); 5463c2b2a28SEmmanuel Vadot } 5473c2b2a28SEmmanuel Vadot } else { 5483c2b2a28SEmmanuel Vadot sc->mode = RK_I2C_CON_MODE_TX; 5493c2b2a28SEmmanuel Vadot } 5503c2b2a28SEmmanuel Vadot } 5513c2b2a28SEmmanuel Vadot /* last message ? */ 5523c2b2a28SEmmanuel Vadot last_msg = (i >= nmsgs - 1) || 5533c2b2a28SEmmanuel Vadot !(msgs[i + 1].flags & IIC_M_NOSTART); 5543c2b2a28SEmmanuel Vadot rk_i2c_start_xfer(sc, msgs + i, last_msg); 5553c2b2a28SEmmanuel Vadot 5563c2b2a28SEmmanuel Vadot if (cold) { 5573c2b2a28SEmmanuel Vadot for(timeout = 10000; timeout > 0; timeout--) { 5583c2b2a28SEmmanuel Vadot rk_i2c_intr_locked(sc); 5593c2b2a28SEmmanuel Vadot if (sc->transfer_done) 5603c2b2a28SEmmanuel Vadot break; 5613c2b2a28SEmmanuel Vadot DELAY(1000); 5623c2b2a28SEmmanuel Vadot } 5633c2b2a28SEmmanuel Vadot if (timeout <= 0) 5643c2b2a28SEmmanuel Vadot err = IIC_ETIMEOUT; 5653c2b2a28SEmmanuel Vadot } else { 5663c2b2a28SEmmanuel Vadot while (err == 0 && !sc->transfer_done) { 5673c2b2a28SEmmanuel Vadot err = msleep(sc, &sc->mtx, PZERO, "rk_i2c", 5683c2b2a28SEmmanuel Vadot 10 * hz); 5693c2b2a28SEmmanuel Vadot } 5703c2b2a28SEmmanuel Vadot } 5713c2b2a28SEmmanuel Vadot } 5723c2b2a28SEmmanuel Vadot 5733c2b2a28SEmmanuel Vadot /* Disable the module and interrupts */ 5743c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_CON, 0); 5753c2b2a28SEmmanuel Vadot RK_I2C_WRITE(sc, RK_I2C_IEN, 0); 5763c2b2a28SEmmanuel Vadot 5773c2b2a28SEmmanuel Vadot sc->busy = 0; 5783c2b2a28SEmmanuel Vadot 5793c2b2a28SEmmanuel Vadot if (sc->nak_recv) 5803c2b2a28SEmmanuel Vadot err = IIC_ENOACK; 5813c2b2a28SEmmanuel Vadot 5823c2b2a28SEmmanuel Vadot RK_I2C_UNLOCK(sc); 5833c2b2a28SEmmanuel Vadot return (err); 5843c2b2a28SEmmanuel Vadot } 5853c2b2a28SEmmanuel Vadot 5863c2b2a28SEmmanuel Vadot static int 5873c2b2a28SEmmanuel Vadot rk_i2c_probe(device_t dev) 5883c2b2a28SEmmanuel Vadot { 5893c2b2a28SEmmanuel Vadot 5903c2b2a28SEmmanuel Vadot if (!ofw_bus_status_okay(dev)) 5913c2b2a28SEmmanuel Vadot return (ENXIO); 5923c2b2a28SEmmanuel Vadot if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 5933c2b2a28SEmmanuel Vadot return (ENXIO); 5943c2b2a28SEmmanuel Vadot 5953c2b2a28SEmmanuel Vadot device_set_desc(dev, "RockChip I2C"); 5963c2b2a28SEmmanuel Vadot return (BUS_PROBE_DEFAULT); 5973c2b2a28SEmmanuel Vadot } 5983c2b2a28SEmmanuel Vadot 5993c2b2a28SEmmanuel Vadot static int 6003c2b2a28SEmmanuel Vadot rk_i2c_attach(device_t dev) 6013c2b2a28SEmmanuel Vadot { 6023c2b2a28SEmmanuel Vadot struct rk_i2c_softc *sc; 6033c2b2a28SEmmanuel Vadot int error; 6043c2b2a28SEmmanuel Vadot 6053c2b2a28SEmmanuel Vadot sc = device_get_softc(dev); 6063c2b2a28SEmmanuel Vadot sc->dev = dev; 6073c2b2a28SEmmanuel Vadot 6083c2b2a28SEmmanuel Vadot mtx_init(&sc->mtx, device_get_nameunit(dev), "rk_i2c", MTX_DEF); 6093c2b2a28SEmmanuel Vadot 6103c2b2a28SEmmanuel Vadot if (bus_alloc_resources(dev, rk_i2c_spec, sc->res) != 0) { 6113c2b2a28SEmmanuel Vadot device_printf(dev, "cannot allocate resources for device\n"); 6123c2b2a28SEmmanuel Vadot error = ENXIO; 6133c2b2a28SEmmanuel Vadot goto fail; 6143c2b2a28SEmmanuel Vadot } 6153c2b2a28SEmmanuel Vadot 6163c2b2a28SEmmanuel Vadot if (bus_setup_intr(dev, sc->res[1], 6173c2b2a28SEmmanuel Vadot INTR_TYPE_MISC | INTR_MPSAFE, NULL, rk_i2c_intr, sc, 6183c2b2a28SEmmanuel Vadot &sc->intrhand)) { 6193c2b2a28SEmmanuel Vadot bus_release_resources(dev, rk_i2c_spec, sc->res); 6203c2b2a28SEmmanuel Vadot device_printf(dev, "cannot setup interrupt handler\n"); 6213c2b2a28SEmmanuel Vadot return (ENXIO); 6223c2b2a28SEmmanuel Vadot } 6233c2b2a28SEmmanuel Vadot 6243c2b2a28SEmmanuel Vadot clk_set_assigned(dev, ofw_bus_get_node(dev)); 6253c2b2a28SEmmanuel Vadot 6263c2b2a28SEmmanuel Vadot /* Activate the module clocks. */ 6273c2b2a28SEmmanuel Vadot error = clk_get_by_ofw_name(dev, 0, "i2c", &sc->sclk); 6283c2b2a28SEmmanuel Vadot if (error != 0) { 6293c2b2a28SEmmanuel Vadot device_printf(dev, "cannot get i2c clock\n"); 6303c2b2a28SEmmanuel Vadot goto fail; 6313c2b2a28SEmmanuel Vadot } 6323c2b2a28SEmmanuel Vadot error = clk_enable(sc->sclk); 6333c2b2a28SEmmanuel Vadot if (error != 0) { 6343c2b2a28SEmmanuel Vadot device_printf(dev, "cannot enable i2c clock\n"); 6353c2b2a28SEmmanuel Vadot goto fail; 6363c2b2a28SEmmanuel Vadot } 6373c2b2a28SEmmanuel Vadot /* pclk clock is optional. */ 6383c2b2a28SEmmanuel Vadot error = clk_get_by_ofw_name(dev, 0, "pclk", &sc->pclk); 6393c2b2a28SEmmanuel Vadot if (error != 0 && error != ENOENT) { 6403c2b2a28SEmmanuel Vadot device_printf(dev, "cannot get pclk clock\n"); 6413c2b2a28SEmmanuel Vadot goto fail; 6423c2b2a28SEmmanuel Vadot } 6433c2b2a28SEmmanuel Vadot if (sc->pclk != NULL) { 6443c2b2a28SEmmanuel Vadot error = clk_enable(sc->pclk); 6453c2b2a28SEmmanuel Vadot if (error != 0) { 6463c2b2a28SEmmanuel Vadot device_printf(dev, "cannot enable pclk clock\n"); 6473c2b2a28SEmmanuel Vadot goto fail; 6483c2b2a28SEmmanuel Vadot } 6493c2b2a28SEmmanuel Vadot } 6503c2b2a28SEmmanuel Vadot 6513c2b2a28SEmmanuel Vadot sc->iicbus = device_add_child(dev, "iicbus", -1); 6523c2b2a28SEmmanuel Vadot if (sc->iicbus == NULL) { 6533c2b2a28SEmmanuel Vadot device_printf(dev, "cannot add iicbus child device\n"); 6543c2b2a28SEmmanuel Vadot error = ENXIO; 6553c2b2a28SEmmanuel Vadot goto fail; 6563c2b2a28SEmmanuel Vadot } 6573c2b2a28SEmmanuel Vadot 6583c2b2a28SEmmanuel Vadot bus_generic_attach(dev); 6593c2b2a28SEmmanuel Vadot 6603c2b2a28SEmmanuel Vadot return (0); 6613c2b2a28SEmmanuel Vadot 6623c2b2a28SEmmanuel Vadot fail: 6633c2b2a28SEmmanuel Vadot if (rk_i2c_detach(dev) != 0) 6643c2b2a28SEmmanuel Vadot device_printf(dev, "Failed to detach\n"); 6653c2b2a28SEmmanuel Vadot return (error); 6663c2b2a28SEmmanuel Vadot } 6673c2b2a28SEmmanuel Vadot 6683c2b2a28SEmmanuel Vadot static int 6693c2b2a28SEmmanuel Vadot rk_i2c_detach(device_t dev) 6703c2b2a28SEmmanuel Vadot { 6713c2b2a28SEmmanuel Vadot struct rk_i2c_softc *sc; 6723c2b2a28SEmmanuel Vadot int error; 6733c2b2a28SEmmanuel Vadot 6743c2b2a28SEmmanuel Vadot sc = device_get_softc(dev); 6753c2b2a28SEmmanuel Vadot 6763c2b2a28SEmmanuel Vadot if ((error = bus_generic_detach(dev)) != 0) 6773c2b2a28SEmmanuel Vadot return (error); 6783c2b2a28SEmmanuel Vadot 6793c2b2a28SEmmanuel Vadot if (sc->iicbus != NULL) 6803c2b2a28SEmmanuel Vadot if ((error = device_delete_child(dev, sc->iicbus)) != 0) 6813c2b2a28SEmmanuel Vadot return (error); 6823c2b2a28SEmmanuel Vadot 6833c2b2a28SEmmanuel Vadot if (sc->sclk != NULL) 6843c2b2a28SEmmanuel Vadot clk_release(sc->sclk); 6853c2b2a28SEmmanuel Vadot if (sc->pclk != NULL) 6863c2b2a28SEmmanuel Vadot clk_release(sc->pclk); 6873c2b2a28SEmmanuel Vadot 6883c2b2a28SEmmanuel Vadot if (sc->intrhand != NULL) 6893c2b2a28SEmmanuel Vadot bus_teardown_intr(sc->dev, sc->res[1], sc->intrhand); 6903c2b2a28SEmmanuel Vadot 6913c2b2a28SEmmanuel Vadot bus_release_resources(dev, rk_i2c_spec, sc->res); 6923c2b2a28SEmmanuel Vadot 6933c2b2a28SEmmanuel Vadot mtx_destroy(&sc->mtx); 6943c2b2a28SEmmanuel Vadot 6953c2b2a28SEmmanuel Vadot return (0); 6963c2b2a28SEmmanuel Vadot } 6973c2b2a28SEmmanuel Vadot 6983c2b2a28SEmmanuel Vadot static phandle_t 6993c2b2a28SEmmanuel Vadot rk_i2c_get_node(device_t bus, device_t dev) 7003c2b2a28SEmmanuel Vadot { 7013c2b2a28SEmmanuel Vadot 7023c2b2a28SEmmanuel Vadot return ofw_bus_get_node(bus); 7033c2b2a28SEmmanuel Vadot } 7043c2b2a28SEmmanuel Vadot 7053c2b2a28SEmmanuel Vadot static device_method_t rk_i2c_methods[] = { 7063c2b2a28SEmmanuel Vadot DEVMETHOD(device_probe, rk_i2c_probe), 7073c2b2a28SEmmanuel Vadot DEVMETHOD(device_attach, rk_i2c_attach), 7083c2b2a28SEmmanuel Vadot DEVMETHOD(device_detach, rk_i2c_detach), 7093c2b2a28SEmmanuel Vadot 7103c2b2a28SEmmanuel Vadot /* OFW methods */ 7113c2b2a28SEmmanuel Vadot DEVMETHOD(ofw_bus_get_node, rk_i2c_get_node), 7123c2b2a28SEmmanuel Vadot 7133c2b2a28SEmmanuel Vadot DEVMETHOD(iicbus_callback, iicbus_null_callback), 7143c2b2a28SEmmanuel Vadot DEVMETHOD(iicbus_reset, rk_i2c_reset), 7153c2b2a28SEmmanuel Vadot DEVMETHOD(iicbus_transfer, rk_i2c_transfer), 7163c2b2a28SEmmanuel Vadot 7173c2b2a28SEmmanuel Vadot DEVMETHOD_END 7183c2b2a28SEmmanuel Vadot }; 7193c2b2a28SEmmanuel Vadot 7203c2b2a28SEmmanuel Vadot static driver_t rk_i2c_driver = { 7213c2b2a28SEmmanuel Vadot "rk_i2c", 7223c2b2a28SEmmanuel Vadot rk_i2c_methods, 7233c2b2a28SEmmanuel Vadot sizeof(struct rk_i2c_softc), 7243c2b2a28SEmmanuel Vadot }; 7253c2b2a28SEmmanuel Vadot 7263c2b2a28SEmmanuel Vadot EARLY_DRIVER_MODULE(rk_i2c, simplebus, rk_i2c_driver, 0, 0, 7273c2b2a28SEmmanuel Vadot BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE); 7283c2b2a28SEmmanuel Vadot EARLY_DRIVER_MODULE(ofw_iicbus, rk_i2c, ofw_iicbus_driver, 7293c2b2a28SEmmanuel Vadot 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE); 7303c2b2a28SEmmanuel Vadot MODULE_DEPEND(rk_i2c, iicbus, 1, 1, 1); 7313c2b2a28SEmmanuel Vadot MODULE_VERSION(rk_i2c, 1); 732