xref: /freebsd/sys/dev/iicbus/controller/rockchip/rk_i2c.c (revision b196276c20b577b364372f1aa1a646b9ce34bf5c)
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
rk_i2c_get_clkdiv(struct rk_i2c_softc * sc,uint32_t speed)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
rk_i2c_reset(device_t dev,u_char speed,u_char addr,u_char * oldaddr)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
rk_i2c_fill_tx(struct rk_i2c_softc * sc)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
rk_i2c_drain_rx(struct rk_i2c_softc * sc)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
rk_i2c_send_stop(struct rk_i2c_softc * sc)2803c2b2a28SEmmanuel Vadot rk_i2c_send_stop(struct rk_i2c_softc *sc)
2813c2b2a28SEmmanuel Vadot {
2823c2b2a28SEmmanuel Vadot 	uint32_t reg;
2833c2b2a28SEmmanuel Vadot 
2840deaf4beSAndriy 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);
2920deaf4beSAndriy Gapon 	} else {
2930deaf4beSAndriy Gapon 		/*
2940deaf4beSAndriy Gapon 		 * Do not actually set stop bit, set up conditions to
2950deaf4beSAndriy Gapon 		 * emulate repeated start by clearing all state.
2960deaf4beSAndriy Gapon 		 */
2970deaf4beSAndriy Gapon 		sc->state = STATE_IDLE;
2980deaf4beSAndriy Gapon 		sc->transfer_done = 1;
2990deaf4beSAndriy Gapon 
3000deaf4beSAndriy Gapon 		reg = RK_I2C_READ(sc, RK_I2C_CON);
3010deaf4beSAndriy Gapon 		reg &= ~RK_I2C_CON_CTRL_MASK;
3020deaf4beSAndriy Gapon 		RK_I2C_WRITE(sc, RK_I2C_CON, reg);
3030deaf4beSAndriy Gapon 	}
3043c2b2a28SEmmanuel Vadot }
3053c2b2a28SEmmanuel Vadot 
3063c2b2a28SEmmanuel Vadot static void
rk_i2c_intr_locked(struct rk_i2c_softc * sc)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 
3660deaf4beSAndriy Gapon 		if (sc->cnt == sc->msg->len) {
3673c2b2a28SEmmanuel Vadot 			rk_i2c_send_stop(sc);
3680deaf4beSAndriy 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);
3930deaf4beSAndriy Gapon 		} else {
3943c2b2a28SEmmanuel Vadot 			rk_i2c_send_stop(sc);
3953c2b2a28SEmmanuel Vadot 		}
3960deaf4beSAndriy 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
rk_i2c_intr(void * arg)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
rk_i2c_start_xfer(struct rk_i2c_softc * sc,struct iic_msg * msg,boolean_t last)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
rk_i2c_transfer(device_t dev,struct iic_msg * msgs,uint32_t nmsgs)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) &&
528a743e280SAndriy Gapon 		    (msgs[i + 1].flags & IIC_M_RD) == 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
rk_i2c_probe(device_t dev)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
rk_i2c_attach(device_t dev)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 
6615b56413dSWarner Losh 	sc->iicbus = device_add_child(dev, "iicbus", DEVICE_UNIT_ANY);
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 
668*18250ec6SJohn Baldwin 	bus_attach_children(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
rk_i2c_detach(device_t dev)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->sclk != NULL)
6903c2b2a28SEmmanuel Vadot 		clk_release(sc->sclk);
6913c2b2a28SEmmanuel Vadot 	if (sc->pclk != NULL)
6923c2b2a28SEmmanuel Vadot 		clk_release(sc->pclk);
6933c2b2a28SEmmanuel Vadot 
6943c2b2a28SEmmanuel Vadot 	if (sc->intrhand != NULL)
6953c2b2a28SEmmanuel Vadot 		bus_teardown_intr(sc->dev, sc->res[1], sc->intrhand);
6963c2b2a28SEmmanuel Vadot 
6973c2b2a28SEmmanuel Vadot 	bus_release_resources(dev, rk_i2c_spec, sc->res);
6983c2b2a28SEmmanuel Vadot 
6993c2b2a28SEmmanuel Vadot 	mtx_destroy(&sc->mtx);
7003c2b2a28SEmmanuel Vadot 
7013c2b2a28SEmmanuel Vadot 	return (0);
7023c2b2a28SEmmanuel Vadot }
7033c2b2a28SEmmanuel Vadot 
7043c2b2a28SEmmanuel Vadot static phandle_t
rk_i2c_get_node(device_t bus,device_t dev)7053c2b2a28SEmmanuel Vadot rk_i2c_get_node(device_t bus, device_t dev)
7063c2b2a28SEmmanuel Vadot {
7073c2b2a28SEmmanuel Vadot 
7083c2b2a28SEmmanuel Vadot 	return ofw_bus_get_node(bus);
7093c2b2a28SEmmanuel Vadot }
7103c2b2a28SEmmanuel Vadot 
7113c2b2a28SEmmanuel Vadot static device_method_t rk_i2c_methods[] = {
7123c2b2a28SEmmanuel Vadot 	DEVMETHOD(device_probe,		rk_i2c_probe),
7133c2b2a28SEmmanuel Vadot 	DEVMETHOD(device_attach,	rk_i2c_attach),
7143c2b2a28SEmmanuel Vadot 	DEVMETHOD(device_detach,	rk_i2c_detach),
7153c2b2a28SEmmanuel Vadot 
7163c2b2a28SEmmanuel Vadot 	/* OFW methods */
7173c2b2a28SEmmanuel Vadot 	DEVMETHOD(ofw_bus_get_node,		rk_i2c_get_node),
7183c2b2a28SEmmanuel Vadot 
7193c2b2a28SEmmanuel Vadot 	DEVMETHOD(iicbus_callback,	iicbus_null_callback),
7203c2b2a28SEmmanuel Vadot 	DEVMETHOD(iicbus_reset,		rk_i2c_reset),
7213c2b2a28SEmmanuel Vadot 	DEVMETHOD(iicbus_transfer,	rk_i2c_transfer),
7223c2b2a28SEmmanuel Vadot 
7233c2b2a28SEmmanuel Vadot 	DEVMETHOD_END
7243c2b2a28SEmmanuel Vadot };
7253c2b2a28SEmmanuel Vadot 
7263c2b2a28SEmmanuel Vadot static driver_t rk_i2c_driver = {
7273c2b2a28SEmmanuel Vadot 	"rk_i2c",
7283c2b2a28SEmmanuel Vadot 	rk_i2c_methods,
7293c2b2a28SEmmanuel Vadot 	sizeof(struct rk_i2c_softc),
7303c2b2a28SEmmanuel Vadot };
7313c2b2a28SEmmanuel Vadot 
7323c2b2a28SEmmanuel Vadot EARLY_DRIVER_MODULE(rk_i2c, simplebus, rk_i2c_driver, 0, 0,
7333c2b2a28SEmmanuel Vadot     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
7343c2b2a28SEmmanuel Vadot EARLY_DRIVER_MODULE(ofw_iicbus, rk_i2c, ofw_iicbus_driver,
7353c2b2a28SEmmanuel Vadot     0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
7363c2b2a28SEmmanuel Vadot MODULE_DEPEND(rk_i2c, iicbus, 1, 1, 1);
7373c2b2a28SEmmanuel Vadot MODULE_VERSION(rk_i2c, 1);
738