> Date: Sun, 9 Jul 2017 20:34:29 +0300 > From: Artturi Alm <artturi....@gmail.com> > > 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
It's a pity that the PSCI "firmware" doesn't do an actual shutdown. But having i2c support is worth having in its own right. A bit of a step backwards to add code under the old-style 4-clause BSD license, but I believe that is still acceptable. I don't think we'll ever support the Marvell Discovery hardware, so I'd just fold the gttwsi_core.c code into sxitwi.c and get rid of the GTTWSI_ALLWINNER hack. A few more comments inline below. On my (Allwinner A20) Banana Pi this seems to work, although the Ethernet link status LED turns back on shortly after the board powers down. I guess it gets power from the link. The power LED stays on as well, but that is just leakage from the serial console. The green LED that is gpio controllable turns off when the board powers down. > 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) This macro is unused. > +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); This function is unused. > +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.. > + */ This comment makes no sense to me. > + 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 You messed that one up ;). > +#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) We try to avoid elaborate debugging code like this. I doubt it is very useful in this case. > + > +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 *); This function is unused. > + > +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); > + } > +} > >