xref: /netbsd-src/sys/arch/arm/rockchip/rk_i2c.c (revision aab4b3ba1f0fa03c6fd1a09c4869549953551d24)
1*aab4b3baSjmcneill /* $NetBSD: rk_i2c.c,v 1.12 2021/11/13 01:08:15 jmcneill Exp $ */
26fb98cc4Sjmcneill 
36fb98cc4Sjmcneill /*-
46fb98cc4Sjmcneill  * Copyright (c) 2018 Jared McNeill <jmcneill@invisible.ca>
56fb98cc4Sjmcneill  * All rights reserved.
66fb98cc4Sjmcneill  *
76fb98cc4Sjmcneill  * Redistribution and use in source and binary forms, with or without
86fb98cc4Sjmcneill  * modification, are permitted provided that the following conditions
96fb98cc4Sjmcneill  * are met:
106fb98cc4Sjmcneill  * 1. Redistributions of source code must retain the above copyright
116fb98cc4Sjmcneill  *    notice, this list of conditions and the following disclaimer.
126fb98cc4Sjmcneill  * 2. Redistributions in binary form must reproduce the above copyright
136fb98cc4Sjmcneill  *    notice, this list of conditions and the following disclaimer in the
146fb98cc4Sjmcneill  *    documentation and/or other materials provided with the distribution.
156fb98cc4Sjmcneill  *
166fb98cc4Sjmcneill  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
176fb98cc4Sjmcneill  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
186fb98cc4Sjmcneill  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
196fb98cc4Sjmcneill  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
206fb98cc4Sjmcneill  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
216fb98cc4Sjmcneill  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
226fb98cc4Sjmcneill  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
236fb98cc4Sjmcneill  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
246fb98cc4Sjmcneill  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
256fb98cc4Sjmcneill  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
266fb98cc4Sjmcneill  * POSSIBILITY OF SUCH DAMAGE.
276fb98cc4Sjmcneill  */
286fb98cc4Sjmcneill 
296fb98cc4Sjmcneill #include <sys/cdefs.h>
306fb98cc4Sjmcneill 
31*aab4b3baSjmcneill __KERNEL_RCSID(0, "$NetBSD: rk_i2c.c,v 1.12 2021/11/13 01:08:15 jmcneill Exp $");
326fb98cc4Sjmcneill 
336fb98cc4Sjmcneill #include <sys/param.h>
346fb98cc4Sjmcneill #include <sys/bus.h>
356fb98cc4Sjmcneill #include <sys/device.h>
366fb98cc4Sjmcneill #include <sys/intr.h>
376fb98cc4Sjmcneill #include <sys/systm.h>
386fb98cc4Sjmcneill #include <sys/time.h>
396fb98cc4Sjmcneill #include <sys/kmem.h>
406fb98cc4Sjmcneill 
416fb98cc4Sjmcneill #include <dev/i2c/i2cvar.h>
426fb98cc4Sjmcneill 
436fb98cc4Sjmcneill #include <dev/fdt/fdtvar.h>
446fb98cc4Sjmcneill 
456fb98cc4Sjmcneill #define	RKI2C_CON		0x000
466fb98cc4Sjmcneill #define	 RKI2C_CON_ACT2NAK	__BIT(6)
476fb98cc4Sjmcneill #define	 RKI2C_CON_ACK		__BIT(5)
486fb98cc4Sjmcneill #define	 RKI2C_CON_STOP		__BIT(4)
496fb98cc4Sjmcneill #define	 RKI2C_CON_START	__BIT(3)
506fb98cc4Sjmcneill #define	 RKI2C_CON_I2C_MODE	__BITS(2,1)
516fb98cc4Sjmcneill #define	  RKI2C_CON_I2C_MODE_TX		0
526fb98cc4Sjmcneill #define	  RKI2C_CON_I2C_MODE_RTX	1
536fb98cc4Sjmcneill #define	  RKI2C_CON_I2C_MODE_RX		2
546fb98cc4Sjmcneill #define	  RKI2C_CON_I2C_MODE_RRX	3
556fb98cc4Sjmcneill #define	 RKI2C_CON_I2C_EN	__BIT(0)
566fb98cc4Sjmcneill 
576fb98cc4Sjmcneill #define	RKI2C_CLKDIV		0x004
586fb98cc4Sjmcneill #define	 RKI2C_CLKDIV_CLKDIVH	__BITS(31,16)
596fb98cc4Sjmcneill #define	 RKI2C_CLKDIV_CLKDIVL	__BITS(15,0)
606fb98cc4Sjmcneill 
616fb98cc4Sjmcneill #define	RKI2C_MRXADDR		0x008
626fb98cc4Sjmcneill #define	 RKI2C_MRXADDR_ADDHVLD	__BIT(26)
636fb98cc4Sjmcneill #define	 RKI2C_MRXADDR_ADDMVLD	__BIT(25)
646fb98cc4Sjmcneill #define	 RKI2C_MRXADDR_ADDLVLD	__BIT(24)
656fb98cc4Sjmcneill #define	 RKI2C_MRXADDR_SADDR	__BITS(23,0)
666fb98cc4Sjmcneill 
676fb98cc4Sjmcneill #define	RKI2C_MRXRADDR		0x00c
686fb98cc4Sjmcneill #define	 RKI2C_MRXRADDR_ADDHVLD	__BIT(26)
696fb98cc4Sjmcneill #define	 RKI2C_MRXRADDR_ADDMVLD	__BIT(25)
706fb98cc4Sjmcneill #define	 RKI2C_MRXRADDR_ADDLVLD	__BIT(24)
716fb98cc4Sjmcneill #define	 RKI2C_MRXRADDR_SADDR	__BITS(23,0)
726fb98cc4Sjmcneill 
736fb98cc4Sjmcneill #define	RKI2C_MTXCNT		0x010
746fb98cc4Sjmcneill #define	 RKI2C_MTXCNT_MTXCNT	__BITS(5,0)
756fb98cc4Sjmcneill 
766fb98cc4Sjmcneill #define	RKI2C_MRXCNT		0x014
776fb98cc4Sjmcneill #define	 RKI2C_MRXCNT_MRXCNT	__BITS(5,0)
786fb98cc4Sjmcneill 
796fb98cc4Sjmcneill #define	RKI2C_IEN		0x018
806fb98cc4Sjmcneill #define	 RKI2C_IEN_NAKRCVIEN	__BIT(6)
816fb98cc4Sjmcneill #define	 RKI2C_IEN_STOPIEN	__BIT(5)
826fb98cc4Sjmcneill #define	 RKI2C_IEN_STARTIEN	__BIT(4)
836fb98cc4Sjmcneill #define	 RKI2C_IEN_MBRFIEN	__BIT(3)
846fb98cc4Sjmcneill #define	 RKI2C_IEN_MBTFIEN	__BIT(2)
856fb98cc4Sjmcneill #define	 RKI2C_IEN_BRFIEN	__BIT(1)
866fb98cc4Sjmcneill #define	 RKI2C_IEN_BTFIEN	__BIT(0)
876fb98cc4Sjmcneill 
886fb98cc4Sjmcneill #define	RKI2C_IPD		0x01c
896fb98cc4Sjmcneill #define	 RKI2C_IPD_NAKRCVIPD	__BIT(6)
906fb98cc4Sjmcneill #define	 RKI2C_IPD_STOPIPD	__BIT(5)
916fb98cc4Sjmcneill #define	 RKI2C_IPD_STARTIPD	__BIT(4)
926fb98cc4Sjmcneill #define	 RKI2C_IPD_MBRFIPD	__BIT(3)
936fb98cc4Sjmcneill #define	 RKI2C_IPD_MBTFIPD	__BIT(2)
946fb98cc4Sjmcneill #define	 RKI2C_IPD_BRFIPD	__BIT(1)
956fb98cc4Sjmcneill #define	 RKI2C_IPD_BTFIPD	__BIT(0)
966fb98cc4Sjmcneill 
976fb98cc4Sjmcneill #define	RKI2C_FCNT		0x020
986fb98cc4Sjmcneill #define	 RKI2C_FCNT_FCNT	__BITS(5,0)
996fb98cc4Sjmcneill 
1006fb98cc4Sjmcneill #define	RKI2C_TXDATA(n)		(0x100 + (n) * 4)
1016fb98cc4Sjmcneill #define	RKI2C_RXDATA(n)		(0x200 + (n) * 4)
1026fb98cc4Sjmcneill 
10301470923Sjmcneill /* Compat data flags */
10401470923Sjmcneill #define	RKI2C_HAS_PCLK		__BIT(0)
10501470923Sjmcneill 
1066e54367aSthorpej static const struct device_compatible_entry compat_data[] = {
10701470923Sjmcneill 	{ .compat = "rockchip,rk3288-i2c",	.value = 0 },
10801470923Sjmcneill 	{ .compat = "rockchip,rk3399-i2c",	.value = RKI2C_HAS_PCLK },
1096e54367aSthorpej 	DEVICE_COMPAT_EOL
1106fb98cc4Sjmcneill };
1116fb98cc4Sjmcneill 
1126fb98cc4Sjmcneill struct rk_i2c_softc {
1136fb98cc4Sjmcneill 	device_t		sc_dev;
1146fb98cc4Sjmcneill 	bus_space_tag_t		sc_bst;
1156fb98cc4Sjmcneill 	bus_space_handle_t	sc_bsh;
1166fb98cc4Sjmcneill 	struct clk		*sc_sclk;
1176fb98cc4Sjmcneill 	struct clk		*sc_pclk;
1186fb98cc4Sjmcneill 
1196fb98cc4Sjmcneill 	u_int			sc_clkfreq;
1206fb98cc4Sjmcneill 
1216fb98cc4Sjmcneill 	struct i2c_controller	sc_ic;
1226fb98cc4Sjmcneill };
1236fb98cc4Sjmcneill 
1246fb98cc4Sjmcneill #define	RD4(sc, reg)				\
1256fb98cc4Sjmcneill 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
1266fb98cc4Sjmcneill #define	WR4(sc, reg, val)			\
1276fb98cc4Sjmcneill 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
1286fb98cc4Sjmcneill 
1296fb98cc4Sjmcneill static void
rk_i2c_init(struct rk_i2c_softc * sc)1306fb98cc4Sjmcneill rk_i2c_init(struct rk_i2c_softc *sc)
1316fb98cc4Sjmcneill {
1326fb98cc4Sjmcneill 	int div, divl, divh;
1336fb98cc4Sjmcneill 	u_int rate;
1346fb98cc4Sjmcneill 
1356fb98cc4Sjmcneill 	/*
1366fb98cc4Sjmcneill 	 * SCL frequency is calculated by the following formula:
1376fb98cc4Sjmcneill 	 *
1386fb98cc4Sjmcneill 	 * SCL Divisor = 8 * (CLKDIVL + 1 + CLKDIVH + 1)
1396fb98cc4Sjmcneill 	 * SCL = PCLK / SCLK Divisor
1406fb98cc4Sjmcneill 	 */
1416fb98cc4Sjmcneill 
1421445d404Sjmcneill 	rate = clk_get_rate(sc->sc_sclk);
1436fb98cc4Sjmcneill 	div = howmany(rate, sc->sc_clkfreq * 8) - 2;
1446fb98cc4Sjmcneill 	if (div >= 0) {
1456fb98cc4Sjmcneill 		divl = div / 2;
1466fb98cc4Sjmcneill 		if (div % 2 == 0)
1476fb98cc4Sjmcneill 			divh = divl;
1486fb98cc4Sjmcneill 		else
1496fb98cc4Sjmcneill 			divh = howmany(div, 2);
1506fb98cc4Sjmcneill 	} else {
1516fb98cc4Sjmcneill 		divl = divh = 0;
1526fb98cc4Sjmcneill 	}
1536fb98cc4Sjmcneill 
1546fb98cc4Sjmcneill 	WR4(sc, RKI2C_CLKDIV,
1556fb98cc4Sjmcneill 	    __SHIFTIN(divh, RKI2C_CLKDIV_CLKDIVH) |
1566fb98cc4Sjmcneill 	    __SHIFTIN(divl, RKI2C_CLKDIV_CLKDIVL));
1576fb98cc4Sjmcneill 
1586fb98cc4Sjmcneill 	/*
1596fb98cc4Sjmcneill 	 * Disable the module until we are ready to use it.
1606fb98cc4Sjmcneill 	 */
1616fb98cc4Sjmcneill 	WR4(sc, RKI2C_CON, 0);
1626fb98cc4Sjmcneill 	WR4(sc, RKI2C_IEN, 0);
1636fb98cc4Sjmcneill 	WR4(sc, RKI2C_IPD, RD4(sc, RKI2C_IPD));
1646fb98cc4Sjmcneill }
1656fb98cc4Sjmcneill 
1666fb98cc4Sjmcneill static int
rk_i2c_wait(struct rk_i2c_softc * sc,uint32_t mask)1676fb98cc4Sjmcneill rk_i2c_wait(struct rk_i2c_softc *sc, uint32_t mask)
1686fb98cc4Sjmcneill {
1696fb98cc4Sjmcneill 	u_int timeo = 100000;
1706fb98cc4Sjmcneill 	uint32_t val;
1716fb98cc4Sjmcneill 
1726fb98cc4Sjmcneill 	const uint32_t ipdmask = mask | RKI2C_IPD_NAKRCVIPD;
1736fb98cc4Sjmcneill 	do {
1746fb98cc4Sjmcneill 		val = RD4(sc, RKI2C_IPD);
1756fb98cc4Sjmcneill 		if (val & ipdmask)
1766fb98cc4Sjmcneill 			break;
1776fb98cc4Sjmcneill 		delay(1);
1786fb98cc4Sjmcneill 	} while (--timeo > 0);
1796fb98cc4Sjmcneill 
1806fb98cc4Sjmcneill 	WR4(sc, RKI2C_IPD, val & ipdmask);
1816fb98cc4Sjmcneill 
1826fb98cc4Sjmcneill 	if ((val & RKI2C_IPD_NAKRCVIPD) != 0)
1836fb98cc4Sjmcneill 		return EIO;
1846fb98cc4Sjmcneill 	if ((val & mask) != 0)
1856fb98cc4Sjmcneill 		return 0;
1866fb98cc4Sjmcneill 
1876fb98cc4Sjmcneill 	return ETIMEDOUT;
1886fb98cc4Sjmcneill }
1896fb98cc4Sjmcneill 
1906fb98cc4Sjmcneill static int
rk_i2c_start(struct rk_i2c_softc * sc)1916fb98cc4Sjmcneill rk_i2c_start(struct rk_i2c_softc *sc)
1926fb98cc4Sjmcneill {
1936fb98cc4Sjmcneill 	uint32_t con;
1946fb98cc4Sjmcneill 	int error;
1956fb98cc4Sjmcneill 
1966fb98cc4Sjmcneill 	/* Send start */
1976fb98cc4Sjmcneill 	con = RD4(sc, RKI2C_CON);
1986fb98cc4Sjmcneill 	con |= RKI2C_CON_START;
1996fb98cc4Sjmcneill 	WR4(sc, RKI2C_CON, con);
2006fb98cc4Sjmcneill 
2016fb98cc4Sjmcneill 	if ((error = rk_i2c_wait(sc, RKI2C_IPD_STARTIPD)) != 0)
2026fb98cc4Sjmcneill 		return error;
2036fb98cc4Sjmcneill 
2046fb98cc4Sjmcneill 	con &= ~RKI2C_CON_START;
2056fb98cc4Sjmcneill 	WR4(sc, RKI2C_CON, con);
2066fb98cc4Sjmcneill 
2076fb98cc4Sjmcneill 	return 0;
2086fb98cc4Sjmcneill }
2096fb98cc4Sjmcneill 
2106fb98cc4Sjmcneill static int
rk_i2c_stop(struct rk_i2c_softc * sc)2116fb98cc4Sjmcneill rk_i2c_stop(struct rk_i2c_softc *sc)
2126fb98cc4Sjmcneill {
2136fb98cc4Sjmcneill 	uint32_t con;
2146fb98cc4Sjmcneill 	int error;
2156fb98cc4Sjmcneill 
2166fb98cc4Sjmcneill 	/* Send start */
2176fb98cc4Sjmcneill 	con = RD4(sc, RKI2C_CON);
2186fb98cc4Sjmcneill 	con |= RKI2C_CON_STOP;
2196fb98cc4Sjmcneill 	WR4(sc, RKI2C_CON, con);
2206fb98cc4Sjmcneill 
2216fb98cc4Sjmcneill 	if ((error = rk_i2c_wait(sc, RKI2C_IPD_STOPIPD)) != 0)
2226fb98cc4Sjmcneill 		return error;
2236fb98cc4Sjmcneill 
2246fb98cc4Sjmcneill 	con &= ~RKI2C_CON_STOP;
2256fb98cc4Sjmcneill 	WR4(sc, RKI2C_CON, con);
2266fb98cc4Sjmcneill 
2276fb98cc4Sjmcneill 	return 0;
2286fb98cc4Sjmcneill }
2296fb98cc4Sjmcneill 
2306fb98cc4Sjmcneill static int
rk_i2c_write(struct rk_i2c_softc * sc,i2c_addr_t addr,const uint8_t * cmd,size_t cmdlen,const uint8_t * buf,size_t buflen,int flags,bool send_start)231970ed7d1Stnn rk_i2c_write(struct rk_i2c_softc *sc, i2c_addr_t addr, const uint8_t *cmd,
232970ed7d1Stnn     size_t cmdlen, const uint8_t *buf, size_t buflen, int flags, bool send_start)
2336fb98cc4Sjmcneill {
2346fb98cc4Sjmcneill 	union {
2356fb98cc4Sjmcneill 		uint8_t data8[32];
2366fb98cc4Sjmcneill 		uint32_t data32[8];
2376fb98cc4Sjmcneill 	} txdata;
2386fb98cc4Sjmcneill 	uint32_t con;
2396fb98cc4Sjmcneill 	u_int mode;
2406fb98cc4Sjmcneill 	int error;
241970ed7d1Stnn 	size_t len;
2426fb98cc4Sjmcneill 
243970ed7d1Stnn 	len = cmdlen + buflen;
244970ed7d1Stnn 	if (len > 31)
2456fb98cc4Sjmcneill 		return EINVAL;
2466fb98cc4Sjmcneill 
2476fb98cc4Sjmcneill 	mode = RKI2C_CON_I2C_MODE_TX;
2486fb98cc4Sjmcneill 	con = RKI2C_CON_I2C_EN | __SHIFTIN(mode, RKI2C_CON_I2C_MODE);
2496fb98cc4Sjmcneill 	WR4(sc, RKI2C_CON, con);
2506fb98cc4Sjmcneill 
2516fb98cc4Sjmcneill 	if (send_start && (error = rk_i2c_start(sc)) != 0)
2526fb98cc4Sjmcneill 		return error;
2536fb98cc4Sjmcneill 
2546fb98cc4Sjmcneill 	/* Transmit data. Slave address goes in the lower 8 bits of TXDATA0 */
2556fb98cc4Sjmcneill 	txdata.data8[0] = addr << 1;
256970ed7d1Stnn 	memcpy(&txdata.data8[1], cmd, cmdlen);
257970ed7d1Stnn 	memcpy(&txdata.data8[1 + cmdlen], buf, buflen);
25861a4f876Sryo #if _BYTE_ORDER == _BIG_ENDIAN
25961a4f876Sryo 	for (int i = 0; i < howmany(len + 1, 4); i++)
26061a4f876Sryo 		LE32TOH(txdata.data32[i]);
26161a4f876Sryo #endif
2626fb98cc4Sjmcneill 	bus_space_write_region_4(sc->sc_bst, sc->sc_bsh, RKI2C_TXDATA(0),
263970ed7d1Stnn 	    txdata.data32, howmany(len + 1, 4));
264970ed7d1Stnn 	WR4(sc, RKI2C_MTXCNT, __SHIFTIN(len + 1, RKI2C_MTXCNT_MTXCNT));
2656fb98cc4Sjmcneill 
2666fb98cc4Sjmcneill 	if ((error = rk_i2c_wait(sc, RKI2C_IPD_MBTFIPD)) != 0)
2676fb98cc4Sjmcneill 		return error;
2686fb98cc4Sjmcneill 
2696fb98cc4Sjmcneill 	return 0;
2706fb98cc4Sjmcneill }
2716fb98cc4Sjmcneill 
2726fb98cc4Sjmcneill static int
rk_i2c_read(struct rk_i2c_softc * sc,i2c_addr_t addr,const uint8_t * cmd,size_t cmdlen,uint8_t * buf,size_t buflen,int flags,bool send_start,bool last_ack)2736fb98cc4Sjmcneill rk_i2c_read(struct rk_i2c_softc *sc, i2c_addr_t addr,
2746fb98cc4Sjmcneill     const uint8_t *cmd, size_t cmdlen, uint8_t *buf,
27503b6843eSjmcneill     size_t buflen, int flags, bool send_start, bool last_ack)
2766fb98cc4Sjmcneill {
2776fb98cc4Sjmcneill 	uint32_t rxdata[8];
2786fb98cc4Sjmcneill 	uint32_t con, mrxaddr, mrxraddr;
2796fb98cc4Sjmcneill 	u_int mode;
2806fb98cc4Sjmcneill 	int error, n;
2816fb98cc4Sjmcneill 
2826fb98cc4Sjmcneill 	if (buflen > 32)
2836fb98cc4Sjmcneill 		return EINVAL;
2846fb98cc4Sjmcneill 	if (cmdlen > 3)
2856fb98cc4Sjmcneill 		return EINVAL;
2866fb98cc4Sjmcneill 
28703b6843eSjmcneill 	mode = send_start ? RKI2C_CON_I2C_MODE_RTX : RKI2C_CON_I2C_MODE_RX;
28803b6843eSjmcneill 	con = RKI2C_CON_I2C_EN | __SHIFTIN(mode, RKI2C_CON_I2C_MODE);
2896fb98cc4Sjmcneill 	WR4(sc, RKI2C_CON, con);
2906fb98cc4Sjmcneill 
2916fb98cc4Sjmcneill 	if (send_start && (error = rk_i2c_start(sc)) != 0)
2926fb98cc4Sjmcneill 		return error;
2936fb98cc4Sjmcneill 
29403b6843eSjmcneill 	if (send_start) {
2956fb98cc4Sjmcneill 		mrxaddr = __SHIFTIN((addr << 1) | 1, RKI2C_MRXADDR_SADDR) |
2966fb98cc4Sjmcneill 		    RKI2C_MRXADDR_ADDLVLD;
2976fb98cc4Sjmcneill 		WR4(sc, RKI2C_MRXADDR, mrxaddr);
2986fb98cc4Sjmcneill 		for (n = 0, mrxraddr = 0; n < cmdlen; n++) {
2996fb98cc4Sjmcneill 			mrxraddr |= cmd[n] << (n * 8);
3006fb98cc4Sjmcneill 			mrxraddr |= (RKI2C_MRXRADDR_ADDLVLD << n);
3016fb98cc4Sjmcneill 		}
3026fb98cc4Sjmcneill 		WR4(sc, RKI2C_MRXRADDR, mrxraddr);
30303b6843eSjmcneill 	}
3046fb98cc4Sjmcneill 
30503b6843eSjmcneill 	if (last_ack) {
3066fb98cc4Sjmcneill 		con |= RKI2C_CON_ACK;
30703b6843eSjmcneill 	}
3086fb98cc4Sjmcneill 	WR4(sc, RKI2C_CON, con);
3096fb98cc4Sjmcneill 
3106fb98cc4Sjmcneill 	/* Receive data. Slave address goes in the lower 8 bits of MRXADDR */
3116fb98cc4Sjmcneill 	WR4(sc, RKI2C_MRXCNT, __SHIFTIN(buflen, RKI2C_MRXCNT_MRXCNT));
3126fb98cc4Sjmcneill 	if ((error = rk_i2c_wait(sc, RKI2C_IPD_MBRFIPD)) != 0)
3136fb98cc4Sjmcneill 		return error;
3146fb98cc4Sjmcneill 
31503b6843eSjmcneill #if 0
3166fb98cc4Sjmcneill 	bus_space_read_region_4(sc->sc_bst, sc->sc_bsh, RKI2C_RXDATA(0),
3176fb98cc4Sjmcneill 	    rxdata, howmany(buflen, 4));
31803b6843eSjmcneill #else
31903b6843eSjmcneill 	for (n = 0; n < roundup(buflen, 4); n += 4)
32003b6843eSjmcneill 		rxdata[n/4] = RD4(sc, RKI2C_RXDATA(n/4));
32103b6843eSjmcneill #endif
32203b6843eSjmcneill 
32361a4f876Sryo #if _BYTE_ORDER == _BIG_ENDIAN
32461a4f876Sryo 	for (int i = 0; i < howmany(buflen, 4); i++)
32561a4f876Sryo 		HTOLE32(rxdata[i]);
32661a4f876Sryo #endif
32761a4f876Sryo 
3286fb98cc4Sjmcneill 	memcpy(buf, rxdata, buflen);
3296fb98cc4Sjmcneill 
3306fb98cc4Sjmcneill 	return 0;
3316fb98cc4Sjmcneill }
3326fb98cc4Sjmcneill 
3336fb98cc4Sjmcneill static int
rk_i2c_exec(void * priv,i2c_op_t op,i2c_addr_t addr,const void * cmdbuf,size_t cmdlen,void * buf,size_t buflen,int flags)3346fb98cc4Sjmcneill rk_i2c_exec(void *priv, i2c_op_t op, i2c_addr_t addr,
3356fb98cc4Sjmcneill     const void *cmdbuf, size_t cmdlen, void *buf, size_t buflen, int flags)
3366fb98cc4Sjmcneill {
3376fb98cc4Sjmcneill 	struct rk_i2c_softc * const sc = priv;
3386fb98cc4Sjmcneill 	bool send_start = true;
3396fb98cc4Sjmcneill 	int error;
3406fb98cc4Sjmcneill 
3416fb98cc4Sjmcneill 	if (I2C_OP_READ_P(op)) {
34203b6843eSjmcneill 		uint8_t *databuf = buf;
34303b6843eSjmcneill 		while (buflen > 0) {
34403b6843eSjmcneill 			const size_t datalen = uimin(buflen, 32);
34503b6843eSjmcneill 			const bool last_ack = datalen == buflen;
34603b6843eSjmcneill 			error = rk_i2c_read(sc, addr, cmdbuf, cmdlen, databuf, datalen, flags, send_start, last_ack);
34703b6843eSjmcneill 			if (error != 0)
34803b6843eSjmcneill 				break;
34903b6843eSjmcneill 			databuf += datalen;
35003b6843eSjmcneill 			buflen -= datalen;
35103b6843eSjmcneill 			send_start = false;
35203b6843eSjmcneill 			cmdbuf = NULL;
35303b6843eSjmcneill 			cmdlen = 0;
35403b6843eSjmcneill 		}
3556fb98cc4Sjmcneill 	} else {
356970ed7d1Stnn 		error = rk_i2c_write(sc, addr, cmdbuf, cmdlen, buf, buflen, flags, send_start);
3576fb98cc4Sjmcneill 	}
3586fb98cc4Sjmcneill 
3596fb98cc4Sjmcneill 	if (error != 0 || I2C_OP_STOP_P(op))
3606fb98cc4Sjmcneill 		rk_i2c_stop(sc);
3616fb98cc4Sjmcneill 
3626fb98cc4Sjmcneill 	WR4(sc, RKI2C_CON, 0);
3636fb98cc4Sjmcneill 	WR4(sc, RKI2C_IPD, RD4(sc, RKI2C_IPD));
3646fb98cc4Sjmcneill 
3656fb98cc4Sjmcneill 	return error;
3666fb98cc4Sjmcneill }
3676fb98cc4Sjmcneill 
3686fb98cc4Sjmcneill static int
rk_i2c_match(device_t parent,cfdata_t cf,void * aux)3696fb98cc4Sjmcneill rk_i2c_match(device_t parent, cfdata_t cf, void *aux)
3706fb98cc4Sjmcneill {
3716fb98cc4Sjmcneill 	struct fdt_attach_args * const faa = aux;
3726fb98cc4Sjmcneill 
3736e54367aSthorpej 	return of_compatible_match(faa->faa_phandle, compat_data);
3746fb98cc4Sjmcneill }
3756fb98cc4Sjmcneill 
3766fb98cc4Sjmcneill static void
rk_i2c_attach(device_t parent,device_t self,void * aux)3776fb98cc4Sjmcneill rk_i2c_attach(device_t parent, device_t self, void *aux)
3786fb98cc4Sjmcneill {
3796fb98cc4Sjmcneill 	struct rk_i2c_softc * const sc = device_private(self);
3806fb98cc4Sjmcneill 	struct fdt_attach_args * const faa = aux;
3816fb98cc4Sjmcneill 	const int phandle = faa->faa_phandle;
3826fb98cc4Sjmcneill 	bus_addr_t addr;
3836fb98cc4Sjmcneill 	bus_size_t size;
38401470923Sjmcneill 	u_int flags;
3856fb98cc4Sjmcneill 
3866fb98cc4Sjmcneill 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
3876fb98cc4Sjmcneill 		aprint_error(": couldn't get registers\n");
3886fb98cc4Sjmcneill 		return;
3896fb98cc4Sjmcneill 	}
3906fb98cc4Sjmcneill 
39101470923Sjmcneill 	flags = of_compatible_lookup(phandle, compat_data)->value;
39201470923Sjmcneill 
3936fb98cc4Sjmcneill 	sc->sc_sclk = fdtbus_clock_get(phandle, "i2c");
3946fb98cc4Sjmcneill 	if (sc->sc_sclk == NULL || clk_enable(sc->sc_sclk) != 0) {
3956fb98cc4Sjmcneill 		aprint_error(": couldn't enable sclk\n");
3966fb98cc4Sjmcneill 		return;
3976fb98cc4Sjmcneill 	}
3986fb98cc4Sjmcneill 
39901470923Sjmcneill 	if (ISSET(flags, RKI2C_HAS_PCLK)) {
4006fb98cc4Sjmcneill 		sc->sc_pclk = fdtbus_clock_get(phandle, "pclk");
4016fb98cc4Sjmcneill 		if (sc->sc_pclk == NULL || clk_enable(sc->sc_pclk) != 0) {
4026fb98cc4Sjmcneill 			aprint_error(": couldn't enable pclk\n");
4036fb98cc4Sjmcneill 			return;
4046fb98cc4Sjmcneill 		}
40501470923Sjmcneill 	}
4066fb98cc4Sjmcneill 
4076fb98cc4Sjmcneill 	if (of_getprop_uint32(phandle, "clock-frequency", &sc->sc_clkfreq))
4086fb98cc4Sjmcneill 		sc->sc_clkfreq = 100000;
4096fb98cc4Sjmcneill 
4106fb98cc4Sjmcneill 	sc->sc_dev = self;
4116fb98cc4Sjmcneill 	sc->sc_bst = faa->faa_bst;
4126fb98cc4Sjmcneill 	if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
4136fb98cc4Sjmcneill 		aprint_error(": couldn't map registers\n");
4146fb98cc4Sjmcneill 		return;
4156fb98cc4Sjmcneill 	}
4166fb98cc4Sjmcneill 
4176fb98cc4Sjmcneill 	aprint_naive("\n");
4186fb98cc4Sjmcneill 	aprint_normal(": Rockchip I2C (%u Hz)\n", sc->sc_clkfreq);
4196fb98cc4Sjmcneill 
4200ca3d100Sjmcneill 	fdtbus_clock_assign(phandle);
4210ca3d100Sjmcneill 
4226fb98cc4Sjmcneill 	rk_i2c_init(sc);
4236fb98cc4Sjmcneill 
424601e1783Sthorpej 	iic_tag_init(&sc->sc_ic);
4256fb98cc4Sjmcneill 	sc->sc_ic.ic_cookie = sc;
4266fb98cc4Sjmcneill 	sc->sc_ic.ic_exec = rk_i2c_exec;
4276fb98cc4Sjmcneill 
42821b71bc0Sthorpej 	fdtbus_register_i2c_controller(&sc->sc_ic, phandle);
4296fb98cc4Sjmcneill 
4306fb98cc4Sjmcneill 	fdtbus_attach_i2cbus(self, phandle, &sc->sc_ic, iicbus_print);
4316fb98cc4Sjmcneill }
4326fb98cc4Sjmcneill 
4336fb98cc4Sjmcneill CFATTACH_DECL_NEW(rk_i2c, sizeof(struct rk_i2c_softc),
4346fb98cc4Sjmcneill     rk_i2c_match, rk_i2c_attach, NULL, NULL);
435