Hi, revived the diff below, i2c tested via pmic's shutdown(), for working "shutdown -p now" operation. there was only two i2c's w/"status: 'okay'" in the FDT, so not all of them do attach.
related part of dmesg: com0: console sxitwi0 at simplebus0 iic0 at sxitwi0 axppmic0 at iic0 addr 0x34: AXP209, ACIN sxitwi1 at simplebus0 iic1 at sxitwi1 dwge0 at simplebus0 Comments? -Artturi diff --git a/sys/arch/armv7/conf/GENERIC b/sys/arch/armv7/conf/GENERIC index af71a6c4835..d8762ba394c 100644 --- a/sys/arch/armv7/conf/GENERIC +++ b/sys/arch/armv7/conf/GENERIC @@ -99,6 +99,8 @@ ehci* at fdt? # EHCI (shim) usb* at ehci? #flags 0x1 #ohci* at sunxi? #usb* at ohci? +sxitwi* at fdt? # Two-Wire Serial Interface +iic* at sxitwi? # I2C bus # ARM Versatile Express sysreg* at fdt? @@ -148,6 +150,7 @@ mvxhci* at fdt? usb* at mvxhci? mvahci* at fdt? +axppmic* at iic? # axp209 pmic crosec* at iic? wskbd* at crosec? mux 1 pcfrtc* at iic? diff --git a/sys/arch/armv7/conf/RAMDISK b/sys/arch/armv7/conf/RAMDISK index 56e64893df6..0c5f8aa4e1f 100644 --- a/sys/arch/armv7/conf/RAMDISK +++ b/sys/arch/armv7/conf/RAMDISK @@ -99,6 +99,8 @@ ehci* at fdt? # EHCI (shim) usb* at ehci? #flags 0x1 #ohci* at sunxi? #usb* at ohci? +sxitwi* at fdt? # Two-Wire Serial Interface +iic* at sxitwi? # I2C bus # ARM Versatile Express sysreg* at fdt? @@ -145,6 +147,7 @@ mvxhci* at fdt? usb* at mvxhci? mvahci* at fdt? +axppmic* at iic? # axp209 pmic crosec* at iic? wskbd* at crosec? mux 1 pcfrtc* at iic? diff --git a/sys/dev/fdt/axp20x.c b/sys/dev/fdt/axp20x.c new file mode 100644 index 00000000000..833038f0eff --- /dev/null +++ b/sys/dev/fdt/axp20x.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2014,2016 Artturi Alm + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/sensors.h> + +#include <dev/i2c/i2cvar.h> + +#include <machine/bus.h> +#include <machine/fdt.h> + +#include <dev/ofw/openfirm.h> +#include <dev/ofw/fdt.h> + +#include <armv7/armv7/armv7_machdep.h> /* needed for powerdownfn */ + +/* Power Status Register / Input power status */ +#define AXP209_PSR 0x00 +#define AXP209_PSR_ACIN (1 << 7) /* ACIN Exists */ +#define AXP209_PSR_VBUS (1 << 5) /* VBUS Exists */ + +/* Shutdown settings, battery detection, and CHGLED Pin control */ +#define AXP209_SDR 0x32 +#define AXP209_SDR_SHUTDOWN (1 << 7) /* Shutdown Control */ + +#define DNAME(sc) ((sc)->sc_dev.dv_xname) + +struct axp20x_softc { + struct device sc_dev; + i2c_tag_t sc_i2c; + i2c_addr_t sc_addr; +}; + +int axp20x_match(struct device *, void *, void *); +void axp20x_attach(struct device *, struct device *, void *); + +int axp20x_readb(u_char, u_char *); +int axp20x_writeb(u_char, u_char); +u_int axp20x_get_acin(void); +void axp20x_shutdown(void); + +struct cfattach axppmic_ca = { + sizeof(struct axp20x_softc), axp20x_match, axp20x_attach +}; + +struct cfdriver axppmic_cd = { + NULL, "axppmic", DV_DULL +}; + +int +axp20x_match(struct device *parent, void *cf, void *arg) +{ + struct i2c_attach_args *ia = arg; + int node = *(int *)ia->ia_cookie; + + if (OF_is_compatible(node, "x-powers,axp209")) + return 1; + if (strcmp(ia->ia_name, "x-powers,axp209") == 0) + return 1; + return 0; +} + +void +axp20x_attach(struct device *parent, struct device *self, void *args) +{ + struct axp20x_softc *sc = (struct axp20x_softc *)self; + struct i2c_attach_args *ia = args; + uint8_t psr; + + sc->sc_i2c = ia->ia_tag; + sc->sc_addr = ia->ia_addr; + + axp20x_readb(AXP209_PSR, &psr); + printf(": AXP209,"); + if (!(psr & (AXP209_PSR_ACIN | AXP209_PSR_VBUS))) + printf(" BAT"); + else { + if (psr & AXP209_PSR_ACIN) + printf(" ACIN"); + if (psr & AXP209_PSR_VBUS) + printf(" VBUS"); + } + printf("\n"); + + powerdownfn = axp20x_shutdown; +} + +int +axp20x_readb(u_char reg, u_char *val) +{ + struct axp20x_softc *sc = axppmic_cd.cd_devs[0]; + int flags = I2C_F_POLL; + int ret; + + if (sc == NULL) + return 1; + + iic_acquire_bus(sc->sc_i2c, flags); + ret = iic_smbus_read_byte(sc->sc_i2c, sc->sc_addr, reg, val, flags); + iic_release_bus(sc->sc_i2c, flags); + return ret; + +} + +int +axp20x_writeb(u_char reg, u_char data) +{ + struct axp20x_softc *sc = axppmic_cd.cd_devs[0]; + int flags = I2C_F_POLL; + int ret; + + if (sc == NULL) + return 1; + + iic_acquire_bus(sc->sc_i2c, flags); + ret = iic_smbus_write_byte(sc->sc_i2c, sc->sc_addr, reg, data, flags); + iic_release_bus(sc->sc_i2c, flags); + return ret; +} + +/* + * XXX this will detect power from usb-otg port as ACin on cubieboard, + * but as only user is the on-board ahci driver, this will likely be + * enough to protect against trying to spin-up on battery atleast. + */ +u_int +axp20x_get_acin(void) +{ + u_char psr; + if (axp20x_readb(AXP209_PSR, &psr)) + psr = 0; + if (psr & AXP209_PSR_ACIN) + return 1; + return 0; +} + +void +axp20x_shutdown(void) +{ + /* XXX + * if (!i2c_initialized) sxitwi_init(); ? + * or bring back bitbanging gpio 'soft'i2c.. + */ + axp20x_writeb(AXP209_SDR, AXP209_SDR_SHUTDOWN); +} diff --git a/sys/dev/fdt/files.fdt b/sys/dev/fdt/files.fdt index 9e2f64cbdaa..07e9b9025fd 100644 --- a/sys/dev/fdt/files.fdt +++ b/sys/dev/fdt/files.fdt @@ -23,6 +23,15 @@ device sximmc: sdmmcbus attach sximmc at fdt file dev/fdt/sximmc.c sximmc +device sxitwi: i2cbus +attach sxitwi at fdt +file dev/fdt/sxitwi.c sxitwi +file dev/fdt/gttwsi_core.c sxitwi + +device axppmic +attach axppmic at i2c +file dev/fdt/axp20x.c axppmic + device bcmdog attach bcmdog at fdt file dev/fdt/bcm2835_dog.c bcmdog diff --git a/sys/dev/fdt/gttwsi_core.c b/sys/dev/fdt/gttwsi_core.c new file mode 100644 index 00000000000..2f6f09c3464 --- /dev/null +++ b/sys/dev/fdt/gttwsi_core.c @@ -0,0 +1,430 @@ +/* $NetBSD: gttwsi_core.c,v 1.2 2014/11/23 13:37:27 jmcneill Exp $ */ +/* + * Copyright (c) 2008 Eiji Kawauchi. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Eiji Kawauchi. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 2005 Brocade Communcations, inc. + * All rights reserved. + * + * Written by Matt Thomas for Brocade Communcations, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Brocade Communications, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY BROCADE COMMUNICATIONS, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL EITHER BROCADE COMMUNICATIONS, INC. BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Marvell Two-Wire Serial Interface (aka I2C) master driver + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/rwlock.h> + +#define _I2C_PRIVATE +#include <dev/i2c/i2cvar.h> + +#include <machine/bus.h> + +#include <dev/fdt/gttwsivar.h> + +#define GTTWSI_SIZE 0x100 + +#define GTTWSI_ALLWINNER +#if defined(GTTWSI_ALLWINNER) +#define TWSI_SLAVEADDR 0x00 +#define TWSI_EXTEND_SLAVEADDR 0x04 +#define TWSI_DATA 0x08 +#define TWSI_CONTROL 0x0c +#define TWSI_STATUS 0x10 +#define TWSI_BAUDRATE 0x14 +#define TWSI_SOFTRESET 0x18 +#else +#define TWSI_SLAVEADDR 0x00 +#define TWSI_EXTEND_SLAVEADDR 0x10 +#define TWSI_DATA 0x04 +#define TWSI_CONTROL 0x08 +#define TWSI_STATUS 0x0c /* for read */ +#define TWSI_BAUDRATE 0x0c /* for write */ +#define TWSI_SOFTRESET 0x1c +#endif + +#define SLAVEADDR_GCE_MASK 0x01 +#define SLAVEADDR_SADDR_MASK 0xfe + +#define EXTEND_SLAVEADDR_MASK 0xff + +#define DATA_MASK 0xff + +#define CONTROL_ACK (1 << 2) +#define CONTROL_IFLG (1 << 3) +#define CONTROL_STOP (1 << 4) +#define CONTROL_START (1 << 5) +#define CONTROL_TWSIEN (1 << 6) +#define CONTROL_INTEN (1 << 7) + +#define STAT_BE 0x00 /* Bus Error */ +#define STAT_SCT 0x08 /* Start condition transmitted */ +#define STAT_RSCT 0x10 /* Repeated start condition transmitted */ +#define STAT_AWBT_AR 0x18 /* Address + write bit transd, ack recvd */ +#define STAT_AWBT_ANR 0x20 /* Address + write bit transd, ack not recvd */ +#define STAT_MTDB_AR 0x28 /* Master transd data byte, ack recvd */ +#define STAT_MTDB_ANR 0x30 /* Master transd data byte, ack not recvd */ +#define STAT_MLADADT 0x38 /* Master lost arbitr during addr or data tx */ +#define STAT_ARBT_AR 0x40 /* Address + read bit transd, ack recvd */ +#define STAT_ARBT_ANR 0x48 /* Address + read bit transd, ack not recvd */ +#define STAT_MRRD_AT 0x50 /* Master received read data, ack transd */ +#define STAT_MRRD_ANT 0x58 /* Master received read data, ack not transd */ +#define STAT_SAWBT_AR 0xd0 /* Second addr + write bit transd, ack recvd */ +#define STAT_SAWBT_ANR 0xd8 /* S addr + write bit transd, ack not recvd */ +#define STAT_SARBT_AR 0xe0 /* Second addr + read bit transd, ack recvd */ +#define STAT_SARBT_ANR 0xe8 /* S addr + read bit transd, ack not recvd */ +#define STAT_NRS 0xf8 /* No relevant status */ + +#define SOFTRESET_VAL 0 /* reset value */ + +#define TWSI_RETRY_COUNT 1000 /* retry loop count */ +#define TWSI_RETRY_DELAY 1 /* retry delay */ +#define TWSI_STAT_DELAY 1 /* poll status delay */ +#define TWSI_READ_DELAY 2 /* read delay */ +#define TWSI_WRITE_DELAY 2 /* write delay */ + + +/*efine TWSI_DEBUG +#ifdef TWSI_DEBUG +/* + * conditional debugging + */ +#define CD_INIT 0x00000001 /* init */ +#define CD_ERR 0x00000002 /* errors */ +#define CD_TIMO 0x00000004 /* timeout */ +#define CD_INFO 0x00000004 /* timeout */ +#define CD_DBG 0x00000010 /* just dbg */ +#define CD_SPAM 0x00000020 /* verbose boot */ +#define CD_ALL 0xffffffff + +int gttwsi_debug = 0 /*| CD_INIT | CD_DBG | CD_SPAM | CD_ALL*/; + +#define DPRINTF(flg, stmt) \ +do { \ + if (gttwsi_debug & (flg)) \ + printf stmt; \ +} while (0) +#else +#define DPRINTF(flg, stmt) do { } while (0) +#endif /* TWSI_DEBUG */ + +#define DNAME(sc) ((sc)->sc_dev.dv_xname) + +int gttwsi_acquire_bus(void *, int); +void gttwsi_release_bus(void *, int); +int gttwsi_send_start(void *v, int flags); +int gttwsi_send_stop(void *v, int flags); +int gttwsi_initiate_xfer(void *v, i2c_addr_t addr, int flags); +int gttwsi_read_byte(void *v, uint8_t *valp, int flags); +int gttwsi_write_byte(void *v, uint8_t val, int flags); + +int gttwsi_wait(struct gttwsi_softc *, uint32_t, uint32_t, int); + +inline u_int +gttwsi_read_4(struct gttwsi_softc *sc, u_int reg) +{ + u_int val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg); + + DPRINTF(CD_SPAM, ("I2C:R:%02x:%02x\n", reg, val)); +#if !defined(TWSI_DEBUG) + delay(TWSI_READ_DELAY); +#endif + + return val; +} + +inline void +gttwsi_write_4(struct gttwsi_softc *sc, u_int reg, u_int val) +{ + bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg, val); + + DPRINTF(CD_SPAM, ("I2C:W:%02x:%02x\n", reg, val)); +#if !defined(TWSI_DEBUG) + delay(TWSI_WRITE_DELAY); +#endif + + return; +} + +void +gttwsi_attach_subr(struct device *self, bus_space_tag_t iot, + bus_space_handle_t ioh, int node) +{ + struct gttwsi_softc * const sc = (struct gttwsi_softc *)self; + + sc->sc_iot = iot; + sc->sc_ioh = ioh; + sc->sc_node = node; + + rw_init(&sc->sc_buslock, sc->sc_dev.dv_xname); + + sc->sc_started = 0; + sc->sc_ic.ic_cookie = sc; + sc->sc_ic.ic_acquire_bus = gttwsi_acquire_bus; + sc->sc_ic.ic_release_bus = gttwsi_release_bus; + sc->sc_ic.ic_exec = NULL; + sc->sc_ic.ic_send_start = gttwsi_send_start; + sc->sc_ic.ic_send_stop = gttwsi_send_stop; + sc->sc_ic.ic_initiate_xfer = gttwsi_initiate_xfer; + sc->sc_ic.ic_read_byte = gttwsi_read_byte; + sc->sc_ic.ic_write_byte = gttwsi_write_byte; + + /* + * Put the controller into Soft Reset. + */ + + gttwsi_write_4(sc, TWSI_SOFTRESET, SOFTRESET_VAL); + + printf("\n"); +} + +void +gttwsi_config_children(struct device *self) +{ + struct gttwsi_softc * const sc = (struct gttwsi_softc *)self; + struct i2cbus_attach_args iba; + + memset(&iba, 0, sizeof(iba)); + iba.iba_name = "iic"; + iba.iba_tag = &sc->sc_ic; + + (void)config_found(&sc->sc_dev, &iba, iicbus_print); +} + +int +gttwsi_intr(void *arg) +{ + struct gttwsi_softc *sc = arg; + u_int val; + + val = gttwsi_read_4(sc, TWSI_CONTROL); + if (val & CONTROL_IFLG) { + gttwsi_write_4(sc, TWSI_CONTROL, val & ~CONTROL_INTEN); + wakeup(&sc->sc_dev); + return 1; + } + return 0; +} + +int +gttwsi_acquire_bus(void *arg, int flags) +{ + struct gttwsi_softc *sc = arg; + + if (flags & I2C_F_POLL) + return 0; + + return rw_enter(&sc->sc_buslock, RW_WRITE); +} + +void +gttwsi_release_bus(void *arg, int flags) +{ + struct gttwsi_softc *sc = arg; + + if (flags & I2C_F_POLL) + return; + + rw_exit(&sc->sc_buslock); +} + +int +gttwsi_send_start(void *v, int flags) +{ + struct gttwsi_softc *sc = v; + int expect; + + if (sc->sc_started) + expect = STAT_RSCT; + else + expect = STAT_SCT; + sc->sc_started = 1; + return gttwsi_wait(sc, CONTROL_START, expect, flags); +} + +int +gttwsi_send_stop(void *v, int flags) +{ + struct gttwsi_softc *sc = v; + int retry = TWSI_RETRY_COUNT; + u_int control; + + sc->sc_started = 0; + + /* Interrupt is not generated for STAT_NRS. */ + control = CONTROL_STOP | CONTROL_TWSIEN; + gttwsi_write_4(sc, TWSI_CONTROL, control); + while (--retry > 0) { + if (gttwsi_read_4(sc, TWSI_STATUS) == STAT_NRS) + return 0; + delay(TWSI_STAT_DELAY); + } + + DPRINTF(CD_ERR, ("%s: send STOP failed\n", DNAME(sc))); + + return -1; +} + +int +gttwsi_initiate_xfer(void *v, i2c_addr_t addr, int flags) +{ + struct gttwsi_softc *sc = v; + u_int data, expect; + int error, read; + + gttwsi_send_start(v, flags); + + read = (flags & I2C_F_READ) != 0; + if (read) + expect = STAT_ARBT_AR; + else + expect = STAT_AWBT_AR; + + /* + * First byte contains whether this xfer is a read or write. + */ + data = read; + if (addr > 0x7f) { + /* + * If this is a 10bit request, the first address byte is + * 0b11110<b9><b8><r/w>. + */ + data |= 0xf0 | ((addr & 0x300) >> 7); + gttwsi_write_4(sc, TWSI_DATA, data); + error = gttwsi_wait(sc, 0, expect, flags); + if (error) + return error; + /* + * The first address byte has been sent, now to send + * the second one. + */ + if (read) + expect = STAT_SARBT_AR; + else + expect = STAT_SAWBT_AR; + data = (uint8_t)addr; + } else + data |= (addr << 1); + + gttwsi_write_4(sc, TWSI_DATA, data); + return gttwsi_wait(sc, 0, expect, flags); +} + +int +gttwsi_read_byte(void *v, uint8_t *valp, int flags) +{ + struct gttwsi_softc *sc = v; + int error; + + if (flags & I2C_F_LAST) + error = gttwsi_wait(sc, 0, STAT_MRRD_ANT, flags); + else + error = gttwsi_wait(sc, CONTROL_ACK, STAT_MRRD_AT, flags); + if (!error) + *valp = gttwsi_read_4(sc, TWSI_DATA); + if ((flags & (I2C_F_LAST | I2C_F_STOP)) == (I2C_F_LAST | I2C_F_STOP)) + error = gttwsi_send_stop(sc, flags); + return error; +} + +int +gttwsi_write_byte(void *v, uint8_t val, int flags) +{ + struct gttwsi_softc *sc = v; + int error; + + gttwsi_write_4(sc, TWSI_DATA, val); + error = gttwsi_wait(sc, 0, STAT_MTDB_AR, flags); + if (flags & I2C_F_STOP) + gttwsi_send_stop(sc, flags); + return error; +} + +int +gttwsi_wait(struct gttwsi_softc *sc, u_int control, u_int expect, int flags) +{ + u_int status; + int timo, error = 0; + + delay(5); + if (!(flags & I2C_F_POLL)) + control |= CONTROL_INTEN; + gttwsi_write_4(sc, TWSI_CONTROL, control | CONTROL_TWSIEN); + + timo = 0; + do { + control = gttwsi_read_4(sc, TWSI_CONTROL); + if (control & CONTROL_IFLG) + break; + if (flags & I2C_F_POLL) + delay(TWSI_RETRY_DELAY); + else { + error = tsleep(&sc->sc_dev, PWAIT, "gttwsi", 100); + if (error) + return error; + } + } while (++timo < 1000000); + + status = gttwsi_read_4(sc, TWSI_STATUS); + if (status != expect) { + DPRINTF(CD_ERR, ("%s: status %#x expected %#x\n", + DNAME(sc), status, expect)); + return EIO; + } + return error; +} diff --git a/sys/dev/fdt/gttwsivar.h b/sys/dev/fdt/gttwsivar.h new file mode 100644 index 00000000000..c5edf3a8548 --- /dev/null +++ b/sys/dev/fdt/gttwsivar.h @@ -0,0 +1,91 @@ +/* $NetBSD: gttwsivar.h,v 1.2 2014/11/23 13:37:27 jmcneill Exp $ */ +/* + * Copyright (c) 2008 Eiji Kawauchi. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Eiji Kawauchi. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 2005 Brocade Communcations, inc. + * All rights reserved. + * + * Written by Matt Thomas for Brocade Communcations, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Brocade Communications, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY BROCADE COMMUNICATIONS, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL EITHER BROCADE COMMUNICATIONS, INC. BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DEV_MARVELL_GTTWSIVAR_H_ +#define _DEV_MARVELL_GTTWSIVAR_H_ + +/* + * Marvell Two-Wire Serial Interface (aka I2C) master driver + */ +#include <sys/device.h> +#include <sys/rwlock.h> + +#include <dev/i2c/i2cvar.h> +#include <machine/bus.h> + +struct gttwsi_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + int sc_node; + u_int sc_started; + struct i2c_controller sc_ic; + struct rwlock sc_buslock; +}; + +void gttwsi_attach_subr(struct device *, bus_space_tag_t, + bus_space_handle_t, int); +void gttwsi_config_children(struct device *); + +int gttwsi_intr(void *); + +#endif /* _DEV_MARVELL_GTTSWI_VAR_H_ */ diff --git a/sys/dev/fdt/sxitwi.c b/sys/dev/fdt/sxitwi.c new file mode 100644 index 00000000000..665c7201045 --- /dev/null +++ b/sys/dev/fdt/sxitwi.c @@ -0,0 +1,170 @@ +/* $NetBSD: awin_twi.c,v 1.7 2015/12/26 16:54:41 macallan Exp $ */ +/* + * Copyright (c) 2013 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matt Thomas of 3am Software Foundry. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/device.h> +#include <sys/systm.h> + +#define _I2C_PRIVATE +#include <dev/i2c/i2cvar.h> + +#include <machine/bus.h> +#include <machine/fdt.h> + +#include <dev/fdt/gttwsivar.h> + +#include <dev/ofw/openfirm.h> +#include <dev/ofw/ofw_clock.h> +#include <dev/ofw/ofw_pinctrl.h> +#include <dev/ofw/fdt.h> + + +#define TWI_CCR_REG 0x14 +#define TWI_CCR_CLK_M (0x0f << 3) +#define TWI_CCR_CLK_N (0x07 << 0) + +void sxitwi_attach(struct device *, struct device *, void *); +int sxitwi_match(struct device *, void *, void *); +void sxitwi_bus_scan(struct device *, struct i2cbus_attach_args *, void *); + +struct sxitwi_softc { + struct gttwsi_softc sc_sc; + void *sc_ih; +}; + +struct cfdriver sxitwi_cd = { + NULL, "sxitwi", DV_DULL +}; + +struct cfattach sxitwi_ca = { + sizeof(struct sxitwi_softc), sxitwi_match, sxitwi_attach +}; + +int +sxitwi_match(struct device *parent, void *cf, void *arg) +{ + struct fdt_attach_args *faa = arg; + + if (OF_is_compatible(faa->fa_node, "allwinner,sun4i-a10-i2c")) + return 1; + if (OF_is_compatible(faa->fa_node, "allwinner,sun7i-a20-i2c")) + return 1; + + return 0; +} + +void +sxitwi_attach(struct device *parent, struct device *self, void *arg) +{ + struct sxitwi_softc *sc = (struct sxitwi_softc *)self; + struct fdt_attach_args *faa = arg; + bus_space_tag_t iot = faa->fa_iot; + bus_space_handle_t ioh; + + if (bus_space_map(iot, faa->fa_reg[0].addr, + faa->fa_reg[0].size, 0, &ioh)) + panic("sxitwi_attach: bus_space_map failed!"); + + /* + * Acquire the PIO pins needed for the TWI port, and + * enable clock gating via CCMU + */ + pinctrl_byname(faa->fa_node, "default"); + + /* enable clock */ + clock_enable(faa->fa_node, NULL); + + /* + * Set clock rate to 100kHz. From the datasheet: + * For 100Khz standard speed 2Wire, CLK_N=2, CLK_M=11 + * F0=48M/2^2=12Mhz, F1=F0/(10*(11+1)) = 0.1Mhz + */ + bus_space_write_4(iot, ioh, TWI_CCR_REG, (11 << 3) | (2 << 0)); + + /* + * Do the MI attach + */ + gttwsi_attach_subr(self, iot, ioh, faa->fa_node); + + /* + * Establish interrupt for it + */ + sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_BIO, + gttwsi_intr, sc, sc->sc_sc.sc_dev.dv_xname); + if (sc->sc_ih == NULL) { + printf(": can't to establish interrupt\n"); + return; + } + + /* + * Configure its children + */ + + struct i2cbus_attach_args iba; + + memset(&iba, 0, sizeof(iba)); + iba.iba_name = "iic"; + iba.iba_tag = &sc->sc_sc.sc_ic; + iba.iba_bus_scan = sxitwi_bus_scan; + iba.iba_bus_scan_arg = &sc->sc_sc.sc_node; + + (void)config_found(&sc->sc_sc.sc_dev, &iba, iicbus_print); + +} + +void +sxitwi_bus_scan(struct device *self, struct i2cbus_attach_args *iba, void *arg) +{ + int iba_node = *(int *)arg; + struct i2c_attach_args ia; + char name[32]; + uint32_t reg[1]; + int node; + + for (node = OF_child(iba_node); node; node = OF_peer(node)) { + memset(name, 0, sizeof(name)); + memset(reg, 0, sizeof(reg)); + + if (OF_getprop(node, "compatible", name, sizeof(name)) == -1) + continue; + if (name[0] == '\0') + continue; + + if (OF_getprop(node, "reg", ®, sizeof(reg)) != sizeof(reg)) + continue; + + memset(&ia, 0, sizeof(ia)); + ia.ia_tag = iba->iba_tag; + ia.ia_addr = bemtoh32(®[0]); + ia.ia_name = name; + ia.ia_cookie = &node; + config_found(self, &ia, iic_print); + } +}