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