15ca8e326SPierre-Luc Drouin /*-
25ca8e326SPierre-Luc Drouin  * SPDX-License-Identifier: BSD-2-Clause
35ca8e326SPierre-Luc Drouin  *
45ca8e326SPierre-Luc Drouin  * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
55ca8e326SPierre-Luc Drouin  * Copyright (c) 2024 Pierre-Luc Drouin <pldrouin@pldrouin.net>
65ca8e326SPierre-Luc Drouin  *
75ca8e326SPierre-Luc Drouin  * Redistribution and use in source and binary forms, with or without
85ca8e326SPierre-Luc Drouin  * modification, are permitted provided that the following conditions
95ca8e326SPierre-Luc Drouin  * are met:
105ca8e326SPierre-Luc Drouin  * 1. Redistributions of source code must retain the above copyright
115ca8e326SPierre-Luc Drouin  *    notice, this list of conditions and the following disclaimer.
125ca8e326SPierre-Luc Drouin  * 2. Redistributions in binary form must reproduce the above copyright
135ca8e326SPierre-Luc Drouin  *    notice, this list of conditions and the following disclaimer in the
145ca8e326SPierre-Luc Drouin  *    documentation and/or other materials provided with the distribution.
155ca8e326SPierre-Luc Drouin  *
165ca8e326SPierre-Luc Drouin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
175ca8e326SPierre-Luc Drouin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
185ca8e326SPierre-Luc Drouin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
195ca8e326SPierre-Luc Drouin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
205ca8e326SPierre-Luc Drouin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
215ca8e326SPierre-Luc Drouin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
225ca8e326SPierre-Luc Drouin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
235ca8e326SPierre-Luc Drouin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
245ca8e326SPierre-Luc Drouin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
255ca8e326SPierre-Luc Drouin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
265ca8e326SPierre-Luc Drouin  * SUCH DAMAGE.
275ca8e326SPierre-Luc Drouin  */
285ca8e326SPierre-Luc Drouin 
295ca8e326SPierre-Luc Drouin /*
305ca8e326SPierre-Luc Drouin  * Vybrid Family Inter-Integrated Circuit (I2C)
31*44847114SPierre-Luc Drouin  * Originally based on Chapter 48, Vybrid Reference Manual, Rev. 5, 07/2013
32*44847114SPierre-Luc Drouin  * Currently based on Chapter 21, LX2160A Reference Manual, Rev. 1, 10/2021
335ca8e326SPierre-Luc Drouin  *
345ca8e326SPierre-Luc Drouin  * The current implementation is based on the original driver by Ruslan Bukin,
355ca8e326SPierre-Luc Drouin  * later modified by Dawid Górecki, and split into FDT and ACPI drivers by Val
365ca8e326SPierre-Luc Drouin  * Packett.
375ca8e326SPierre-Luc Drouin  */
385ca8e326SPierre-Luc Drouin 
395ca8e326SPierre-Luc Drouin #include <sys/types.h>
405ca8e326SPierre-Luc Drouin #include <sys/mutex.h>
415ca8e326SPierre-Luc Drouin #include <sys/param.h>
425ca8e326SPierre-Luc Drouin #include <sys/systm.h>
435ca8e326SPierre-Luc Drouin #include <sys/bus.h>
445ca8e326SPierre-Luc Drouin #include <sys/kernel.h>
455ca8e326SPierre-Luc Drouin #include <sys/module.h>
465ca8e326SPierre-Luc Drouin #include <sys/malloc.h>
475ca8e326SPierre-Luc Drouin #include <sys/rman.h>
485ca8e326SPierre-Luc Drouin #include <sys/timeet.h>
495ca8e326SPierre-Luc Drouin #include <sys/timetc.h>
505ca8e326SPierre-Luc Drouin 
515ca8e326SPierre-Luc Drouin #include <dev/iicbus/iiconf.h>
525ca8e326SPierre-Luc Drouin #include <dev/iicbus/iicbus.h>
535ca8e326SPierre-Luc Drouin 
545ca8e326SPierre-Luc Drouin #include "iicbus_if.h"
555ca8e326SPierre-Luc Drouin 
565ca8e326SPierre-Luc Drouin #include <machine/bus.h>
575ca8e326SPierre-Luc Drouin #include <machine/cpu.h>
585ca8e326SPierre-Luc Drouin #include <machine/intr.h>
595ca8e326SPierre-Luc Drouin 
605ca8e326SPierre-Luc Drouin #include <dev/iicbus/controller/vybrid/vf_i2c.h>
615ca8e326SPierre-Luc Drouin 
625ca8e326SPierre-Luc Drouin #define	I2C_IBAD	0x0	/* I2C Bus Address Register */
635ca8e326SPierre-Luc Drouin #define	I2C_IBFD	0x1	/* I2C Bus Frequency Divider Register */
645ca8e326SPierre-Luc Drouin #define	I2C_IBCR	0x2	/* I2C Bus Control Register */
655ca8e326SPierre-Luc Drouin #define	 IBCR_MDIS		(1 << 7) /* Module disable. */
665ca8e326SPierre-Luc Drouin #define	 IBCR_IBIE		(1 << 6) /* I-Bus Interrupt Enable. */
675ca8e326SPierre-Luc Drouin #define	 IBCR_MSSL		(1 << 5) /* Master/Slave mode select. */
685ca8e326SPierre-Luc Drouin #define	 IBCR_TXRX		(1 << 4) /* Transmit/Receive mode select. */
695ca8e326SPierre-Luc Drouin #define	 IBCR_NOACK		(1 << 3) /* Data Acknowledge disable. */
705ca8e326SPierre-Luc Drouin #define	 IBCR_RSTA		(1 << 2) /* Repeat Start. */
715ca8e326SPierre-Luc Drouin #define	 IBCR_DMAEN		(1 << 1) /* DMA Enable. */
725ca8e326SPierre-Luc Drouin #define	I2C_IBSR	0x3	/* I2C Bus Status Register */
735ca8e326SPierre-Luc Drouin #define	 IBSR_TCF		(1 << 7) /* Transfer complete. */
745ca8e326SPierre-Luc Drouin #define	 IBSR_IAAS		(1 << 6) /* Addressed as a slave. */
755ca8e326SPierre-Luc Drouin #define	 IBSR_IBB		(1 << 5) /* Bus busy. */
765ca8e326SPierre-Luc Drouin #define	 IBSR_IBAL		(1 << 4) /* Arbitration Lost. */
775ca8e326SPierre-Luc Drouin #define	 IBSR_SRW		(1 << 2) /* Slave Read/Write. */
785ca8e326SPierre-Luc Drouin #define	 IBSR_IBIF		(1 << 1) /* I-Bus Interrupt Flag. */
795ca8e326SPierre-Luc Drouin #define	 IBSR_RXAK		(1 << 0) /* Received Acknowledge. */
805ca8e326SPierre-Luc Drouin #define	I2C_IBDR	0x4	/* I2C Bus Data I/O Register */
815ca8e326SPierre-Luc Drouin #define	I2C_IBIC	0x5	/* I2C Bus Interrupt Config Register */
825ca8e326SPierre-Luc Drouin #define	 IBIC_BIIE		(1 << 7) /* Bus Idle Interrupt Enable bit. */
835ca8e326SPierre-Luc Drouin #define	I2C_IBDBG	0x6	/* I2C Bus Debug Register */
845ca8e326SPierre-Luc Drouin 
855ca8e326SPierre-Luc Drouin #define DIV_REG_UNSET	0xFF
865ca8e326SPierre-Luc Drouin 
875ca8e326SPierre-Luc Drouin #define	READ1(_sc, _reg) bus_space_read_1(_sc->bst, _sc->bsh, _reg)
885ca8e326SPierre-Luc Drouin #define	WRITE1(_sc, _reg, _val)	bus_space_write_1(_sc->bst,\
895ca8e326SPierre-Luc Drouin 		_sc->bsh, _reg, _val)
905ca8e326SPierre-Luc Drouin 
915ca8e326SPierre-Luc Drouin #ifdef DEBUG
925ca8e326SPierre-Luc Drouin #define vf_i2c_dbg(_sc, fmt, args...) \
935ca8e326SPierre-Luc Drouin 	device_printf((_sc)->dev, fmt, ##args)
945ca8e326SPierre-Luc Drouin #ifdef DEBUG2
955ca8e326SPierre-Luc Drouin #undef WRITE1
965ca8e326SPierre-Luc Drouin #define WRITE1(_sc, _reg, _val) ({\
975ca8e326SPierre-Luc Drouin 		vf_i2c_dbg(_sc, "WRITE1 REG 0x%02X VAL 0x%02X\n",_reg,_val);\
985ca8e326SPierre-Luc Drouin 		bus_space_write_1(_sc->bst, _sc->bsh, _reg, _val);\
995ca8e326SPierre-Luc Drouin 		})
1005ca8e326SPierre-Luc Drouin #undef READ1
1015ca8e326SPierre-Luc Drouin #define READ1(_sc, _reg) ({\
1025ca8e326SPierre-Luc Drouin 		uint32_t ret=bus_space_read_1(_sc->bst, _sc->bsh, _reg);\
1035ca8e326SPierre-Luc Drouin 		vf_i2c_dbg(_sc, "READ1 REG 0x%02X RETURNS 0x%02X\n",_reg,ret);\
1045ca8e326SPierre-Luc Drouin 		ret;\
1055ca8e326SPierre-Luc Drouin 		})
1065ca8e326SPierre-Luc Drouin #endif
1075ca8e326SPierre-Luc Drouin #else
1085ca8e326SPierre-Luc Drouin #define vf_i2c_dbg(_sc, fmt, args...)
1095ca8e326SPierre-Luc Drouin #endif
1105ca8e326SPierre-Luc Drouin 
1115ca8e326SPierre-Luc Drouin static int i2c_repeated_start(device_t, u_char, int);
1125ca8e326SPierre-Luc Drouin static int i2c_start(device_t, u_char, int);
1135ca8e326SPierre-Luc Drouin static int i2c_stop(device_t);
1145ca8e326SPierre-Luc Drouin static int i2c_reset(device_t, u_char, u_char, u_char *);
1155ca8e326SPierre-Luc Drouin static int i2c_read(device_t, char *, int, int *, int, int);
1165ca8e326SPierre-Luc Drouin static int i2c_write(device_t, const char *, int, int *, int);
1175ca8e326SPierre-Luc Drouin 
1185ca8e326SPierre-Luc Drouin struct i2c_div_type {
1195ca8e326SPierre-Luc Drouin 	uint32_t reg_val;
1205ca8e326SPierre-Luc Drouin 	uint32_t div;
1215ca8e326SPierre-Luc Drouin };
1225ca8e326SPierre-Luc Drouin 
1235ca8e326SPierre-Luc Drouin static struct resource_spec i2c_spec[] = {
1245ca8e326SPierre-Luc Drouin 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
1255ca8e326SPierre-Luc Drouin 	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
1265ca8e326SPierre-Luc Drouin 	{ -1, 0 }
1275ca8e326SPierre-Luc Drouin };
1285ca8e326SPierre-Luc Drouin 
1295ca8e326SPierre-Luc Drouin static struct i2c_div_type vf610_div_table[] = {
1305ca8e326SPierre-Luc Drouin 	{ 0x00, 20 }, { 0x01, 22 }, { 0x02, 24 }, { 0x03, 26 },
1315ca8e326SPierre-Luc Drouin 	{ 0x04, 28 }, { 0x05, 30 }, { 0x09, 32 }, { 0x06, 34 },
1325ca8e326SPierre-Luc Drouin 	{ 0x0A, 36 }, { 0x0B, 40 }, { 0x0C, 44 }, { 0x0D, 48 },
1335ca8e326SPierre-Luc Drouin 	{ 0x0E, 56 }, { 0x12, 64 }, { 0x13, 72 }, { 0x14, 80 },
1345ca8e326SPierre-Luc Drouin 	{ 0x15, 88 }, { 0x19, 96 }, { 0x16, 104 }, { 0x1A, 112 },
1355ca8e326SPierre-Luc Drouin 	{ 0x17, 128 }, { 0x1D, 160 }, { 0x1E, 192 }, { 0x22, 224 },
1365ca8e326SPierre-Luc Drouin 	{ 0x1F, 240 }, { 0x23, 256 }, { 0x24, 288 }, { 0x25, 320 },
1375ca8e326SPierre-Luc Drouin 	{ 0x26, 384 }, { 0x2A, 448 }, { 0x27, 480 }, { 0x2B, 512 },
1385ca8e326SPierre-Luc Drouin 	{ 0x2C, 576 }, { 0x2D, 640 }, { 0x2E, 768 }, { 0x32, 896 },
1395ca8e326SPierre-Luc Drouin 	{ 0x2F, 960 }, { 0x33, 1024 }, { 0x34, 1152 }, { 0x35, 1280 },
1405ca8e326SPierre-Luc Drouin 	{ 0x36, 1536 }, { 0x3A, 1792 }, { 0x37, 1920 }, { 0x3B, 2048 },
1415ca8e326SPierre-Luc Drouin 	{ 0x3C, 2304 }, { 0x3D, 2560 }, { 0x3E, 3072 }, { 0x3F, 3840 },
1425ca8e326SPierre-Luc Drouin 	{ 0x3F, 3840 }, { 0x7B, 4096 }, { 0x7D, 5120 }, { 0x7E, 6144 },
1435ca8e326SPierre-Luc Drouin };
1445ca8e326SPierre-Luc Drouin 
1455ca8e326SPierre-Luc Drouin int
vf_i2c_attach_common(device_t dev)1465ca8e326SPierre-Luc Drouin vf_i2c_attach_common(device_t dev)
1475ca8e326SPierre-Luc Drouin {
1485ca8e326SPierre-Luc Drouin 	struct vf_i2c_softc *sc;
1495ca8e326SPierre-Luc Drouin 	int error;
1505ca8e326SPierre-Luc Drouin 
1515ca8e326SPierre-Luc Drouin 	sc = device_get_softc(dev);
1525ca8e326SPierre-Luc Drouin 
1535ca8e326SPierre-Luc Drouin 	vf_i2c_dbg(sc, "i2c attach common\n");
1545ca8e326SPierre-Luc Drouin 
1555ca8e326SPierre-Luc Drouin 	mtx_init(&sc->mutex, device_get_nameunit(dev), "I2C", MTX_DEF);
1565ca8e326SPierre-Luc Drouin 
1575ca8e326SPierre-Luc Drouin 	error = bus_alloc_resources(dev, i2c_spec, sc->res);
1585ca8e326SPierre-Luc Drouin 	if (error != 0) {
1595ca8e326SPierre-Luc Drouin 		mtx_destroy(&sc->mutex);
1605ca8e326SPierre-Luc Drouin 		device_printf(dev, "could not allocate resources\n");
1615ca8e326SPierre-Luc Drouin 		return (ENXIO);
1625ca8e326SPierre-Luc Drouin 	}
1635ca8e326SPierre-Luc Drouin 
1645ca8e326SPierre-Luc Drouin 	/* Memory interface */
1655ca8e326SPierre-Luc Drouin 	sc->bst = rman_get_bustag(sc->res[0]);
1665ca8e326SPierre-Luc Drouin 	sc->bsh = rman_get_bushandle(sc->res[0]);
1675ca8e326SPierre-Luc Drouin 
1685ca8e326SPierre-Luc Drouin 	mtx_lock(&sc->mutex);
1695ca8e326SPierre-Luc Drouin 
1705ca8e326SPierre-Luc Drouin 	WRITE1(sc, I2C_IBIC, IBIC_BIIE);
1715ca8e326SPierre-Luc Drouin 
1725ca8e326SPierre-Luc Drouin 	if (sc->freq == 0) {
1735ca8e326SPierre-Luc Drouin 		uint8_t div_reg;
1745ca8e326SPierre-Luc Drouin 
1755ca8e326SPierre-Luc Drouin 		div_reg = READ1(sc, I2C_IBFD);
1765ca8e326SPierre-Luc Drouin 
1775ca8e326SPierre-Luc Drouin 		if (div_reg != 0x00) {
1785ca8e326SPierre-Luc Drouin 			sc->freq = UINT32_MAX;
1795ca8e326SPierre-Luc Drouin 			device_printf(dev, "Using existing bus frequency divider register value (0x%02X).\n", div_reg);
1805ca8e326SPierre-Luc Drouin 		} else {
1815ca8e326SPierre-Luc Drouin 			device_printf(dev, "Bus frequency divider value appears unset, defaulting to low I2C bus speed.\n");
1825ca8e326SPierre-Luc Drouin 		}
1835ca8e326SPierre-Luc Drouin 	}
1845ca8e326SPierre-Luc Drouin 
1855ca8e326SPierre-Luc Drouin 	mtx_unlock(&sc->mutex);
1865ca8e326SPierre-Luc Drouin 
1875ca8e326SPierre-Luc Drouin 	sc->iicbus = device_add_child(dev, "iicbus", -1);
188*44847114SPierre-Luc Drouin 
1895ca8e326SPierre-Luc Drouin 	if (sc->iicbus == NULL) {
1905ca8e326SPierre-Luc Drouin 		device_printf(dev, "could not add iicbus child");
1915ca8e326SPierre-Luc Drouin 		mtx_destroy(&sc->mutex);
1925ca8e326SPierre-Luc Drouin 		bus_release_resources(dev, i2c_spec, sc->res);
1935ca8e326SPierre-Luc Drouin 		return (ENXIO);
1945ca8e326SPierre-Luc Drouin 	}
1955ca8e326SPierre-Luc Drouin 
1965ca8e326SPierre-Luc Drouin 	bus_generic_attach(dev);
1975ca8e326SPierre-Luc Drouin 
1985ca8e326SPierre-Luc Drouin 	return (0);
1995ca8e326SPierre-Luc Drouin }
2005ca8e326SPierre-Luc Drouin 
2015ca8e326SPierre-Luc Drouin static int
i2c_detach(device_t dev)2025ca8e326SPierre-Luc Drouin i2c_detach(device_t dev)
2035ca8e326SPierre-Luc Drouin {
2045ca8e326SPierre-Luc Drouin 	struct vf_i2c_softc *sc;
2055ca8e326SPierre-Luc Drouin 	int error = 0;
2065ca8e326SPierre-Luc Drouin 
2075ca8e326SPierre-Luc Drouin 	sc = device_get_softc(dev);
2085ca8e326SPierre-Luc Drouin 	vf_i2c_dbg(sc, "i2c detach\n");
2095ca8e326SPierre-Luc Drouin 
2105ca8e326SPierre-Luc Drouin 	mtx_lock(&sc->mutex);
2115ca8e326SPierre-Luc Drouin 
2125ca8e326SPierre-Luc Drouin 	if (sc->freq == 0) {
2135ca8e326SPierre-Luc Drouin 		vf_i2c_dbg(sc, "Writing 0x00 to clock divider register\n");
2145ca8e326SPierre-Luc Drouin 		WRITE1(sc, I2C_IBFD, 0x00);
2155ca8e326SPierre-Luc Drouin 	}
2165ca8e326SPierre-Luc Drouin 
2175ca8e326SPierre-Luc Drouin 	error = bus_generic_detach(dev);
2185ca8e326SPierre-Luc Drouin 	if (error != 0) {
2195ca8e326SPierre-Luc Drouin 		device_printf(dev, "cannot detach child devices.\n");
2205ca8e326SPierre-Luc Drouin 		return (error);
2215ca8e326SPierre-Luc Drouin 	}
2225ca8e326SPierre-Luc Drouin 
2235ca8e326SPierre-Luc Drouin 	error = device_delete_child(dev, sc->iicbus);
2245ca8e326SPierre-Luc Drouin 	if (error != 0) {
2255ca8e326SPierre-Luc Drouin 		device_printf(dev, "could not delete iicbus child.\n");
2265ca8e326SPierre-Luc Drouin 		return (error);
2275ca8e326SPierre-Luc Drouin 	}
2285ca8e326SPierre-Luc Drouin 
2295ca8e326SPierre-Luc Drouin 	bus_release_resources(dev, i2c_spec, sc->res);
2305ca8e326SPierre-Luc Drouin 
2315ca8e326SPierre-Luc Drouin 	mtx_unlock(&sc->mutex);
2325ca8e326SPierre-Luc Drouin 
2335ca8e326SPierre-Luc Drouin 	mtx_destroy(&sc->mutex);
2345ca8e326SPierre-Luc Drouin 
2355ca8e326SPierre-Luc Drouin 	return (0);
2365ca8e326SPierre-Luc Drouin }
2375ca8e326SPierre-Luc Drouin 
2385ca8e326SPierre-Luc Drouin /* Wait for free bus */
2395ca8e326SPierre-Luc Drouin static int
wait_for_nibb(struct vf_i2c_softc * sc)2405ca8e326SPierre-Luc Drouin wait_for_nibb(struct vf_i2c_softc *sc)
2415ca8e326SPierre-Luc Drouin {
2425ca8e326SPierre-Luc Drouin 	int retry;
2435ca8e326SPierre-Luc Drouin 
2445ca8e326SPierre-Luc Drouin 	retry = 1000;
2455ca8e326SPierre-Luc Drouin 	while (retry --) {
2465ca8e326SPierre-Luc Drouin 		if ((READ1(sc, I2C_IBSR) & IBSR_IBB) == 0)
2475ca8e326SPierre-Luc Drouin 			return (IIC_NOERR);
2485ca8e326SPierre-Luc Drouin 		DELAY(10);
2495ca8e326SPierre-Luc Drouin 	}
2505ca8e326SPierre-Luc Drouin 
2515ca8e326SPierre-Luc Drouin 	return (IIC_ETIMEOUT);
2525ca8e326SPierre-Luc Drouin }
2535ca8e326SPierre-Luc Drouin 
2545ca8e326SPierre-Luc Drouin /* Wait for transfer complete+interrupt flag */
2555ca8e326SPierre-Luc Drouin static int
wait_for_icf(struct vf_i2c_softc * sc)2565ca8e326SPierre-Luc Drouin wait_for_icf(struct vf_i2c_softc *sc)
2575ca8e326SPierre-Luc Drouin {
2585ca8e326SPierre-Luc Drouin 	int retry;
259*44847114SPierre-Luc Drouin 	uint8_t ibsr;
260*44847114SPierre-Luc Drouin 
261*44847114SPierre-Luc Drouin 	vf_i2c_dbg(sc, "i2c wait for transfer complete + interrupt flag\n");
2625ca8e326SPierre-Luc Drouin 
2635ca8e326SPierre-Luc Drouin 	retry = 1000;
2645ca8e326SPierre-Luc Drouin 	while (retry --) {
265*44847114SPierre-Luc Drouin 		ibsr = READ1(sc, I2C_IBSR);
266*44847114SPierre-Luc Drouin 
267*44847114SPierre-Luc Drouin 		if (ibsr & IBSR_IBIF) {
2685ca8e326SPierre-Luc Drouin 			WRITE1(sc, I2C_IBSR, IBSR_IBIF);
269*44847114SPierre-Luc Drouin 
270*44847114SPierre-Luc Drouin 			if (ibsr & IBSR_IBAL) {
271*44847114SPierre-Luc Drouin 				WRITE1(sc, I2C_IBSR, IBSR_IBAL);
272*44847114SPierre-Luc Drouin 				return (IIC_EBUSBSY);
2735ca8e326SPierre-Luc Drouin 			}
274*44847114SPierre-Luc Drouin 
275*44847114SPierre-Luc Drouin 			if (ibsr & IBSR_TCF)
276*44847114SPierre-Luc Drouin 				return (IIC_NOERR);
2775ca8e326SPierre-Luc Drouin 		}
2785ca8e326SPierre-Luc Drouin 		DELAY(10);
2795ca8e326SPierre-Luc Drouin 	}
2805ca8e326SPierre-Luc Drouin 
2815ca8e326SPierre-Luc Drouin 	return (IIC_ETIMEOUT);
2825ca8e326SPierre-Luc Drouin }
2835ca8e326SPierre-Luc Drouin /* Get ACK bit from last write */
2845ca8e326SPierre-Luc Drouin static bool
tx_acked(struct vf_i2c_softc * sc)2855ca8e326SPierre-Luc Drouin tx_acked(struct vf_i2c_softc *sc)
2865ca8e326SPierre-Luc Drouin {
2875ca8e326SPierre-Luc Drouin 	vf_i2c_dbg(sc, "i2c get ACK bit from last write\n");
2885ca8e326SPierre-Luc Drouin 
2895ca8e326SPierre-Luc Drouin 	return (READ1(sc, I2C_IBSR) & IBSR_RXAK) ? false : true;
2905ca8e326SPierre-Luc Drouin 
2915ca8e326SPierre-Luc Drouin }
2925ca8e326SPierre-Luc Drouin 
2935ca8e326SPierre-Luc Drouin static int
i2c_repeated_start(device_t dev,u_char slave,int timeout)2945ca8e326SPierre-Luc Drouin i2c_repeated_start(device_t dev, u_char slave, int timeout)
2955ca8e326SPierre-Luc Drouin {
2965ca8e326SPierre-Luc Drouin 	struct vf_i2c_softc *sc;
2975ca8e326SPierre-Luc Drouin 	int error;
2985ca8e326SPierre-Luc Drouin 	int reg;
2995ca8e326SPierre-Luc Drouin 
3005ca8e326SPierre-Luc Drouin 	sc = device_get_softc(dev);
3015ca8e326SPierre-Luc Drouin 
3025ca8e326SPierre-Luc Drouin 	vf_i2c_dbg(sc, "i2c repeated start\n");
3035ca8e326SPierre-Luc Drouin 
3045ca8e326SPierre-Luc Drouin 	mtx_lock(&sc->mutex);
3055ca8e326SPierre-Luc Drouin 
3065ca8e326SPierre-Luc Drouin 	if ((READ1(sc, I2C_IBSR) & IBSR_IBB) == 0) {
307*44847114SPierre-Luc Drouin 		vf_i2c_dbg(sc, "cant i2c repeat start: bus is no longer busy\n");
3085ca8e326SPierre-Luc Drouin 		mtx_unlock(&sc->mutex);
3095ca8e326SPierre-Luc Drouin 		return (IIC_EBUSERR);
3105ca8e326SPierre-Luc Drouin 	}
3115ca8e326SPierre-Luc Drouin 
3125ca8e326SPierre-Luc Drouin 	reg = READ1(sc, I2C_IBCR);
3135ca8e326SPierre-Luc Drouin 	reg |= (IBCR_RSTA | IBCR_IBIE);
3145ca8e326SPierre-Luc Drouin 	WRITE1(sc, I2C_IBCR, reg);
3155ca8e326SPierre-Luc Drouin 
3165ca8e326SPierre-Luc Drouin 	/* Write target address - LSB is R/W bit */
3175ca8e326SPierre-Luc Drouin 	WRITE1(sc, I2C_IBDR, slave);
3185ca8e326SPierre-Luc Drouin 
319*44847114SPierre-Luc Drouin 	error = wait_for_icf(sc);
3205ca8e326SPierre-Luc Drouin 
3215ca8e326SPierre-Luc Drouin 	if (!tx_acked(sc)) {
322*44847114SPierre-Luc Drouin 		mtx_unlock(&sc->mutex);
323*44847114SPierre-Luc Drouin 		vf_i2c_dbg(sc, "cant i2c repeat start: missing ACK after slave address\n");
3245ca8e326SPierre-Luc Drouin 		return (IIC_ENOACK);
3255ca8e326SPierre-Luc Drouin 	}
3265ca8e326SPierre-Luc Drouin 
3275ca8e326SPierre-Luc Drouin 	mtx_unlock(&sc->mutex);
3285ca8e326SPierre-Luc Drouin 
3295ca8e326SPierre-Luc Drouin 	if (error != 0)
3305ca8e326SPierre-Luc Drouin 		return (error);
3315ca8e326SPierre-Luc Drouin 
3325ca8e326SPierre-Luc Drouin 	return (IIC_NOERR);
3335ca8e326SPierre-Luc Drouin }
3345ca8e326SPierre-Luc Drouin 
3355ca8e326SPierre-Luc Drouin static int
i2c_start(device_t dev,u_char slave,int timeout)3365ca8e326SPierre-Luc Drouin i2c_start(device_t dev, u_char slave, int timeout)
3375ca8e326SPierre-Luc Drouin {
3385ca8e326SPierre-Luc Drouin 	struct vf_i2c_softc *sc;
3395ca8e326SPierre-Luc Drouin 	int error;
3405ca8e326SPierre-Luc Drouin 	int reg;
3415ca8e326SPierre-Luc Drouin 
3425ca8e326SPierre-Luc Drouin 	sc = device_get_softc(dev);
3435ca8e326SPierre-Luc Drouin 
3445ca8e326SPierre-Luc Drouin 	vf_i2c_dbg(sc, "i2c start\n");
3455ca8e326SPierre-Luc Drouin 
3465ca8e326SPierre-Luc Drouin 	mtx_lock(&sc->mutex);
3475ca8e326SPierre-Luc Drouin 
348*44847114SPierre-Luc Drouin 	error = wait_for_nibb(sc);
3495ca8e326SPierre-Luc Drouin 
350*44847114SPierre-Luc Drouin 	/* Reset controller if bus is still busy. */
351*44847114SPierre-Luc Drouin 	if (error == IIC_ETIMEOUT) {
352*44847114SPierre-Luc Drouin 		WRITE1(sc, I2C_IBCR, IBCR_MDIS);
353*44847114SPierre-Luc Drouin 		DELAY(1000);
354*44847114SPierre-Luc Drouin 		WRITE1(sc, I2C_IBCR, IBCR_NOACK);
355*44847114SPierre-Luc Drouin 		error = wait_for_nibb(sc);
356*44847114SPierre-Luc Drouin 	}
357*44847114SPierre-Luc Drouin 
358*44847114SPierre-Luc Drouin 	if (error != 0) {
3595ca8e326SPierre-Luc Drouin 		mtx_unlock(&sc->mutex);
360*44847114SPierre-Luc Drouin 		vf_i2c_dbg(sc, "cant i2c start: %i\n", error);
361*44847114SPierre-Luc Drouin 		return (error);
3625ca8e326SPierre-Luc Drouin 	}
3635ca8e326SPierre-Luc Drouin 
3645ca8e326SPierre-Luc Drouin 	/* Set start condition */
365*44847114SPierre-Luc Drouin 	reg = (IBCR_MSSL | IBCR_NOACK | IBCR_IBIE | IBCR_TXRX);
3665ca8e326SPierre-Luc Drouin 	WRITE1(sc, I2C_IBCR, reg);
3675ca8e326SPierre-Luc Drouin 
368*44847114SPierre-Luc Drouin 	WRITE1(sc, I2C_IBSR, IBSR_IBIF);
3695ca8e326SPierre-Luc Drouin 
3705ca8e326SPierre-Luc Drouin 	/* Write target address - LSB is R/W bit */
3715ca8e326SPierre-Luc Drouin 	WRITE1(sc, I2C_IBDR, slave);
3725ca8e326SPierre-Luc Drouin 
373*44847114SPierre-Luc Drouin 	error = wait_for_icf(sc);
3745ca8e326SPierre-Luc Drouin 	if (error != 0) {
3755ca8e326SPierre-Luc Drouin 		mtx_unlock(&sc->mutex);
3765ca8e326SPierre-Luc Drouin 		vf_i2c_dbg(sc, "cant i2c start: iif error\n");
3775ca8e326SPierre-Luc Drouin 		return (error);
3785ca8e326SPierre-Luc Drouin 	}
3795ca8e326SPierre-Luc Drouin 	mtx_unlock(&sc->mutex);
3805ca8e326SPierre-Luc Drouin 
3815ca8e326SPierre-Luc Drouin 	if (!tx_acked(sc)) {
382*44847114SPierre-Luc Drouin 		vf_i2c_dbg(sc, "cant i2c start: missing ACK after slave address\n");
3835ca8e326SPierre-Luc Drouin 		return (IIC_ENOACK);
3845ca8e326SPierre-Luc Drouin 	}
3855ca8e326SPierre-Luc Drouin 
3865ca8e326SPierre-Luc Drouin 	return (IIC_NOERR);
3875ca8e326SPierre-Luc Drouin }
3885ca8e326SPierre-Luc Drouin 
3895ca8e326SPierre-Luc Drouin static int
i2c_stop(device_t dev)3905ca8e326SPierre-Luc Drouin i2c_stop(device_t dev)
3915ca8e326SPierre-Luc Drouin {
3925ca8e326SPierre-Luc Drouin 	struct vf_i2c_softc *sc;
3935ca8e326SPierre-Luc Drouin 
3945ca8e326SPierre-Luc Drouin 	sc = device_get_softc(dev);
3955ca8e326SPierre-Luc Drouin 
3965ca8e326SPierre-Luc Drouin 	vf_i2c_dbg(sc, "i2c stop\n");
3975ca8e326SPierre-Luc Drouin 
3985ca8e326SPierre-Luc Drouin 	mtx_lock(&sc->mutex);
3995ca8e326SPierre-Luc Drouin 
400*44847114SPierre-Luc Drouin 	if ((READ1(sc, I2C_IBCR) & IBCR_MSSL) != 0)
4015ca8e326SPierre-Luc Drouin 		WRITE1(sc, I2C_IBCR, IBCR_NOACK | IBCR_IBIE);
4025ca8e326SPierre-Luc Drouin 
4035ca8e326SPierre-Luc Drouin 	mtx_unlock(&sc->mutex);
4045ca8e326SPierre-Luc Drouin 
4055ca8e326SPierre-Luc Drouin 	return (IIC_NOERR);
4065ca8e326SPierre-Luc Drouin }
4075ca8e326SPierre-Luc Drouin 
4085ca8e326SPierre-Luc Drouin static uint8_t
i2c_get_div_val(device_t dev)4095ca8e326SPierre-Luc Drouin i2c_get_div_val(device_t dev)
4105ca8e326SPierre-Luc Drouin {
4115ca8e326SPierre-Luc Drouin 	struct vf_i2c_softc *sc;
4125ca8e326SPierre-Luc Drouin 	uint8_t div_reg = DIV_REG_UNSET;
4135ca8e326SPierre-Luc Drouin 
4145ca8e326SPierre-Luc Drouin 	sc = device_get_softc(dev);
4155ca8e326SPierre-Luc Drouin 
4165ca8e326SPierre-Luc Drouin 	if (sc->freq == UINT32_MAX)
4175ca8e326SPierre-Luc Drouin 		return div_reg;
4185ca8e326SPierre-Luc Drouin #ifndef FDT
4195ca8e326SPierre-Luc Drouin 	div_reg = vf610_div_table[nitems(vf610_div_table) - 1].reg_val;
4205ca8e326SPierre-Luc Drouin #else
4215ca8e326SPierre-Luc Drouin 	if (sc->hwtype == HW_MVF600)
4225ca8e326SPierre-Luc Drouin 		div_reg = MVF600_DIV_REG;
4235ca8e326SPierre-Luc Drouin 	else if (sc->freq == 0)
4245ca8e326SPierre-Luc Drouin 		div_reg = vf610_div_table[nitems(vf610_div_table) - 1].reg_val;
4255ca8e326SPierre-Luc Drouin 	else {
4265ca8e326SPierre-Luc Drouin 		uint64_t clk_freq;
4275ca8e326SPierre-Luc Drouin 		int error, i;
4285ca8e326SPierre-Luc Drouin 
4295ca8e326SPierre-Luc Drouin 		error = clk_get_freq(sc->clock, &clk_freq);
4305ca8e326SPierre-Luc Drouin 		if (error != 0) {
4315ca8e326SPierre-Luc Drouin 			device_printf(dev, "Could not get parent clock frequency. "
4325ca8e326SPierre-Luc Drouin 					"Using default divider.\n");
4335ca8e326SPierre-Luc Drouin 			div_reg = vf610_div_table[nitems(vf610_div_table) - 1].reg_val;
4345ca8e326SPierre-Luc Drouin 		} else {
4355ca8e326SPierre-Luc Drouin 
4365ca8e326SPierre-Luc Drouin 			for (i = 0; i < nitems(vf610_div_table) - 1; i++)
4375ca8e326SPierre-Luc Drouin 				if ((clk_freq / vf610_div_table[i].div) <= sc->freq)
4385ca8e326SPierre-Luc Drouin 					break;
4395ca8e326SPierre-Luc Drouin 			div_reg = vf610_div_table[i].reg_val;
4405ca8e326SPierre-Luc Drouin 		}
4415ca8e326SPierre-Luc Drouin 	}
4425ca8e326SPierre-Luc Drouin #endif
4435ca8e326SPierre-Luc Drouin 	vf_i2c_dbg(sc, "Writing 0x%02X to clock divider register\n", div_reg);
4445ca8e326SPierre-Luc Drouin 	return div_reg;
4455ca8e326SPierre-Luc Drouin }
4465ca8e326SPierre-Luc Drouin 
4475ca8e326SPierre-Luc Drouin static int
i2c_reset(device_t dev,u_char speed,u_char addr,u_char * oldadr)4485ca8e326SPierre-Luc Drouin i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldadr)
4495ca8e326SPierre-Luc Drouin {
4505ca8e326SPierre-Luc Drouin 	struct vf_i2c_softc *sc;
4515ca8e326SPierre-Luc Drouin 	uint8_t div_reg;
4525ca8e326SPierre-Luc Drouin 
4535ca8e326SPierre-Luc Drouin 	sc = device_get_softc(dev);
4545ca8e326SPierre-Luc Drouin 	div_reg = i2c_get_div_val(dev);
4555ca8e326SPierre-Luc Drouin 	vf_i2c_dbg(sc, "i2c reset\n");
4565ca8e326SPierre-Luc Drouin 
4575ca8e326SPierre-Luc Drouin 	mtx_lock(&sc->mutex);
4585ca8e326SPierre-Luc Drouin 	WRITE1(sc, I2C_IBCR, IBCR_MDIS);
4595ca8e326SPierre-Luc Drouin 
4605ca8e326SPierre-Luc Drouin 	if(div_reg != DIV_REG_UNSET)
4615ca8e326SPierre-Luc Drouin 		WRITE1(sc, I2C_IBFD, div_reg);
4625ca8e326SPierre-Luc Drouin 
4635ca8e326SPierre-Luc Drouin 	WRITE1(sc, I2C_IBCR, 0x0); /* Enable i2c */
4645ca8e326SPierre-Luc Drouin 
4655ca8e326SPierre-Luc Drouin 	mtx_unlock(&sc->mutex);
4665ca8e326SPierre-Luc Drouin 
4675ca8e326SPierre-Luc Drouin 	return (IIC_NOERR);
4685ca8e326SPierre-Luc Drouin }
4695ca8e326SPierre-Luc Drouin 
4705ca8e326SPierre-Luc Drouin static int
i2c_read(device_t dev,char * buf,int len,int * read,int last,int delay)4715ca8e326SPierre-Luc Drouin i2c_read(device_t dev, char *buf, int len, int *read, int last, int delay)
4725ca8e326SPierre-Luc Drouin {
4735ca8e326SPierre-Luc Drouin 	struct vf_i2c_softc *sc;
4745ca8e326SPierre-Luc Drouin 	int error;
4755ca8e326SPierre-Luc Drouin 
4765ca8e326SPierre-Luc Drouin 	sc = device_get_softc(dev);
4775ca8e326SPierre-Luc Drouin 
4785ca8e326SPierre-Luc Drouin 	vf_i2c_dbg(sc, "i2c read\n");
4795ca8e326SPierre-Luc Drouin 
4805ca8e326SPierre-Luc Drouin 	*read = 0;
4815ca8e326SPierre-Luc Drouin 
4825ca8e326SPierre-Luc Drouin 	mtx_lock(&sc->mutex);
4835ca8e326SPierre-Luc Drouin 
4845ca8e326SPierre-Luc Drouin 	if (len) {
4855ca8e326SPierre-Luc Drouin 		if (len == 1)
486*44847114SPierre-Luc Drouin 			WRITE1(sc, I2C_IBCR, IBCR_IBIE | IBCR_MSSL | IBCR_NOACK);
4875ca8e326SPierre-Luc Drouin 		else
4885ca8e326SPierre-Luc Drouin 			WRITE1(sc, I2C_IBCR, IBCR_IBIE | IBCR_MSSL);
4895ca8e326SPierre-Luc Drouin 
4905ca8e326SPierre-Luc Drouin 		/* dummy read */
4915ca8e326SPierre-Luc Drouin 		READ1(sc, I2C_IBDR);
4925ca8e326SPierre-Luc Drouin 
4935ca8e326SPierre-Luc Drouin 		while (*read < len) {
4945ca8e326SPierre-Luc Drouin 			error = wait_for_icf(sc);
4955ca8e326SPierre-Luc Drouin 			if (error != 0) {
4965ca8e326SPierre-Luc Drouin 				mtx_unlock(&sc->mutex);
4975ca8e326SPierre-Luc Drouin 				return (error);
4985ca8e326SPierre-Luc Drouin 			}
4995ca8e326SPierre-Luc Drouin 
500*44847114SPierre-Luc Drouin 			if (last) {
501*44847114SPierre-Luc Drouin 				if (*read == len - 2) {
5025ca8e326SPierre-Luc Drouin 					/* NO ACK on last byte */
503*44847114SPierre-Luc Drouin 					WRITE1(sc, I2C_IBCR, IBCR_IBIE | IBCR_MSSL | IBCR_NOACK);
5045ca8e326SPierre-Luc Drouin 
505*44847114SPierre-Luc Drouin 				} else if (*read == len - 1) {
5065ca8e326SPierre-Luc Drouin 					/* Transfer done, remove master bit */
5075ca8e326SPierre-Luc Drouin 					WRITE1(sc, I2C_IBCR, IBCR_IBIE | IBCR_NOACK);
5085ca8e326SPierre-Luc Drouin 				}
509*44847114SPierre-Luc Drouin 			}
5105ca8e326SPierre-Luc Drouin 
5115ca8e326SPierre-Luc Drouin 			*buf++ = READ1(sc, I2C_IBDR);
5125ca8e326SPierre-Luc Drouin 			(*read)++;
5135ca8e326SPierre-Luc Drouin 		}
514*44847114SPierre-Luc Drouin 	}
5155ca8e326SPierre-Luc Drouin 	mtx_unlock(&sc->mutex);
5165ca8e326SPierre-Luc Drouin 
5175ca8e326SPierre-Luc Drouin 	return (IIC_NOERR);
5185ca8e326SPierre-Luc Drouin }
5195ca8e326SPierre-Luc Drouin 
5205ca8e326SPierre-Luc Drouin static int
i2c_write(device_t dev,const char * buf,int len,int * sent,int timeout)5215ca8e326SPierre-Luc Drouin i2c_write(device_t dev, const char *buf, int len, int *sent, int timeout)
5225ca8e326SPierre-Luc Drouin {
5235ca8e326SPierre-Luc Drouin 	struct vf_i2c_softc *sc;
5245ca8e326SPierre-Luc Drouin 	int error;
5255ca8e326SPierre-Luc Drouin 
5265ca8e326SPierre-Luc Drouin 	sc = device_get_softc(dev);
5275ca8e326SPierre-Luc Drouin 
5285ca8e326SPierre-Luc Drouin 	vf_i2c_dbg(sc, "i2c write\n");
5295ca8e326SPierre-Luc Drouin 
5305ca8e326SPierre-Luc Drouin 	*sent = 0;
5315ca8e326SPierre-Luc Drouin 
5325ca8e326SPierre-Luc Drouin 	mtx_lock(&sc->mutex);
5335ca8e326SPierre-Luc Drouin 	while (*sent < len) {
5345ca8e326SPierre-Luc Drouin 		WRITE1(sc, I2C_IBDR, *buf++);
5355ca8e326SPierre-Luc Drouin 
536*44847114SPierre-Luc Drouin 		error = wait_for_icf(sc);
5375ca8e326SPierre-Luc Drouin 		if (error != 0) {
5385ca8e326SPierre-Luc Drouin 			mtx_unlock(&sc->mutex);
5395ca8e326SPierre-Luc Drouin 			return (error);
5405ca8e326SPierre-Luc Drouin 		}
5415ca8e326SPierre-Luc Drouin 
5425ca8e326SPierre-Luc Drouin 		if (!tx_acked(sc) && (*sent  = (len - 2)) ){
5435ca8e326SPierre-Luc Drouin 			mtx_unlock(&sc->mutex);
5445ca8e326SPierre-Luc Drouin 			vf_i2c_dbg(sc, "no ACK on %d write\n", *sent);
5455ca8e326SPierre-Luc Drouin 			return (IIC_ENOACK);
5465ca8e326SPierre-Luc Drouin 		}
5475ca8e326SPierre-Luc Drouin 
5485ca8e326SPierre-Luc Drouin 		(*sent)++;
5495ca8e326SPierre-Luc Drouin 	}
5505ca8e326SPierre-Luc Drouin 	mtx_unlock(&sc->mutex);
5515ca8e326SPierre-Luc Drouin 	return (IIC_NOERR);
5525ca8e326SPierre-Luc Drouin }
5535ca8e326SPierre-Luc Drouin 
5545ca8e326SPierre-Luc Drouin static device_method_t i2c_methods[] = {
5555ca8e326SPierre-Luc Drouin 	/* Device interface */
5565ca8e326SPierre-Luc Drouin 	DEVMETHOD(device_detach,		i2c_detach),
5575ca8e326SPierre-Luc Drouin 
5585ca8e326SPierre-Luc Drouin 	/* Device interface */
5595ca8e326SPierre-Luc Drouin 	DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
5605ca8e326SPierre-Luc Drouin 	DEVMETHOD(bus_teardown_intr,		bus_generic_teardown_intr),
5615ca8e326SPierre-Luc Drouin 	DEVMETHOD(bus_alloc_resource,		bus_generic_alloc_resource),
5625ca8e326SPierre-Luc Drouin 	DEVMETHOD(bus_release_resource,		bus_generic_release_resource),
5635ca8e326SPierre-Luc Drouin 	DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
5645ca8e326SPierre-Luc Drouin 	DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
5655ca8e326SPierre-Luc Drouin 	DEVMETHOD(bus_adjust_resource,		bus_generic_adjust_resource),
5665ca8e326SPierre-Luc Drouin 
5675ca8e326SPierre-Luc Drouin 	/* iicbus interface */
5685ca8e326SPierre-Luc Drouin 	DEVMETHOD(iicbus_callback,		iicbus_null_callback),
5695ca8e326SPierre-Luc Drouin 	DEVMETHOD(iicbus_repeated_start,	i2c_repeated_start),
5705ca8e326SPierre-Luc Drouin 	DEVMETHOD(iicbus_start,			i2c_start),
5715ca8e326SPierre-Luc Drouin 	DEVMETHOD(iicbus_stop,			i2c_stop),
5725ca8e326SPierre-Luc Drouin 	DEVMETHOD(iicbus_reset,			i2c_reset),
5735ca8e326SPierre-Luc Drouin 	DEVMETHOD(iicbus_read,			i2c_read),
5745ca8e326SPierre-Luc Drouin 	DEVMETHOD(iicbus_write,			i2c_write),
5755ca8e326SPierre-Luc Drouin 	DEVMETHOD(iicbus_transfer,		iicbus_transfer_gen),
5765ca8e326SPierre-Luc Drouin 	DEVMETHOD_END
5775ca8e326SPierre-Luc Drouin };
5785ca8e326SPierre-Luc Drouin 
5795ca8e326SPierre-Luc Drouin driver_t vf_i2c_driver = {
5805ca8e326SPierre-Luc Drouin 	"i2c",
5815ca8e326SPierre-Luc Drouin 	i2c_methods,
5825ca8e326SPierre-Luc Drouin 	sizeof(struct vf_i2c_softc),
5835ca8e326SPierre-Luc Drouin };
584