On Sun, Jul 16, 2017 at 11:13:35PM +0200, Mark Kettenis wrote:
> > 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.
> 

done in diff below, hope i understood correctly what you meant.

> 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.
> 
> 
> > ... snip...
> > +
> > +#define DNAME(sc)  ((sc)->sc_dev.dv_xname)
> 
> This macro is unused.

fixed.

> 
> > + ... snip...
> > +u_int      axp20x_get_acin(void);
> 
> This function is unused.

fixed w/omission due no comments to alternative in my last mail.

> 
> > + ... snip...
> > +void
> > +axp20x_shutdown(void)
> > +{
> > +   /* XXX
> > +    * if (!i2c_initialized) sxitwi_init(); ?
> > +    * or bring back bitbanging gpio 'soft'i2c..
> > +    */
> 
> This comment makes no sense to me.

neither to me anymore, fixed.

> 
> > + ... snip...
> > +
> > +/*efine    TWSI_DEBUG
> 
> You messed that one up ;).

fixed:)

> 
> > +#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.

leftover, fixed.

> 
> > + ... snip...
> > +void       gttwsi_config_children(struct device *);
> 
> This function is unused.

fixed.

> 
> > + ... snip...
> > 
> > 


Had no time to do more than compile test for correctness yet, but should
be enough to get told if i misunderstood anything w/regards the fixes,
and there was no really rainy day yet either, so no manuals.
-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..7d627f78226
--- /dev/null
+++ b/sys/dev/fdt/axp20x.c
@@ -0,0 +1,139 @@
+/* $OpenBSD$ */
+/*
+ * 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 */
+
+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);
+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;
+}
+
+void
+axp20x_shutdown(void)
+{
+       axp20x_writeb(AXP209_SDR, AXP209_SDR_SHUTDOWN);
+}
diff --git a/sys/dev/fdt/files.fdt b/sys/dev/fdt/files.fdt
index 9e2f64cbdaa..6a96910ca2e 100644
--- a/sys/dev/fdt/files.fdt
+++ b/sys/dev/fdt/files.fdt
@@ -23,6 +23,14 @@ 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
+
+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/sxitwi.c b/sys/dev/fdt/sxitwi.c
new file mode 100644
index 00000000000..f699d5f7f49
--- /dev/null
+++ b/sys/dev/fdt/sxitwi.c
@@ -0,0 +1,487 @@
+/* $OpenBSD$ */
+/*     $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>
+
+#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/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)
+
+#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
+
+#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 */
+
+struct sxitwi_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                    *sc_ih;
+};
+
+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 *);
+
+int    sxitwi_intr(void *);
+int    sxitwi_acquire_bus(void *, int);
+void   sxitwi_release_bus(void *, int);
+int    sxitwi_send_start(void *, int);
+int    sxitwi_send_stop(void *, int);
+int    sxitwi_initiate_xfer(void *, i2c_addr_t, int);
+int    sxitwi_read_byte(void *, uint8_t *, int);
+int    sxitwi_write_byte(void *, uint8_t, int);
+int    sxitwi_wait(struct sxitwi_softc *, u_int, u_int, int);
+static inline u_int sxitwi_read_4(struct sxitwi_softc *, u_int);
+static inline void sxitwi_write_4(struct sxitwi_softc *, u_int, u_int);
+
+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;
+       struct i2cbus_attach_args iba;
+       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!");
+
+       sc->sc_iot = iot;
+       sc->sc_ioh = ioh;
+       sc->sc_node = faa->fa_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 = sxitwi_acquire_bus;
+       sc->sc_ic.ic_release_bus = sxitwi_release_bus;
+       sc->sc_ic.ic_exec = NULL;
+       sc->sc_ic.ic_send_start = sxitwi_send_start;
+       sc->sc_ic.ic_send_stop = sxitwi_send_stop;
+       sc->sc_ic.ic_initiate_xfer = sxitwi_initiate_xfer;
+       sc->sc_ic.ic_read_byte = sxitwi_read_byte;
+       sc->sc_ic.ic_write_byte = sxitwi_write_byte;
+
+       /*
+        * 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));
+
+       /* Put the controller into Soft Reset. */
+       sxitwi_write_4(sc, TWSI_SOFTRESET, SOFTRESET_VAL);
+
+       /* Establish interrupt */
+       sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_BIO,
+           sxitwi_intr, sc, sc->sc_dev.dv_xname);
+       if (sc->sc_ih == NULL) {
+               printf(": can't to establish interrupt\n");
+               return;
+       }
+
+       printf("\n");
+
+       /* Configure its children */
+       memset(&iba, 0, sizeof(iba));
+       iba.iba_name = "iic";
+       iba.iba_tag = &sc->sc_ic;
+       iba.iba_bus_scan = sxitwi_bus_scan;
+       iba.iba_bus_scan_arg = &sc->sc_node;
+
+       (void)config_found(&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", &reg, sizeof(reg)) != sizeof(reg))
+                       continue;
+
+               memset(&ia, 0, sizeof(ia));
+               ia.ia_tag = iba->iba_tag;
+               ia.ia_addr = bemtoh32(&reg[0]);
+               ia.ia_name = name;
+               ia.ia_cookie = &node;
+               config_found(self, &ia, iic_print);
+       }
+}
+
+u_int
+sxitwi_read_4(struct sxitwi_softc *sc, u_int reg)
+{
+       u_int val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg);
+
+       delay(TWSI_READ_DELAY);
+
+       return val;
+}
+
+void
+sxitwi_write_4(struct sxitwi_softc *sc, u_int reg, u_int val)
+{
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg, val);
+
+       delay(TWSI_WRITE_DELAY);
+
+       return;
+}
+
+int
+sxitwi_intr(void *arg)
+{
+       struct sxitwi_softc *sc = arg;
+       u_int val;
+
+       val = sxitwi_read_4(sc, TWSI_CONTROL);
+       if (val & CONTROL_IFLG) {
+               sxitwi_write_4(sc, TWSI_CONTROL, val & ~CONTROL_INTEN);
+               wakeup(&sc->sc_dev);
+               return 1;
+       }
+       return 0;
+}
+
+int
+sxitwi_acquire_bus(void *arg, int flags)
+{
+       struct sxitwi_softc *sc = arg;
+
+       if (flags & I2C_F_POLL)
+               return 0;
+
+       return rw_enter(&sc->sc_buslock, RW_WRITE);
+}
+
+void
+sxitwi_release_bus(void *arg, int flags)
+{
+       struct sxitwi_softc *sc = arg;
+
+       if (flags & I2C_F_POLL)
+               return;
+
+       rw_exit(&sc->sc_buslock);
+}
+
+int
+sxitwi_send_start(void *v, int flags)
+{
+       struct sxitwi_softc *sc = v;
+       int expect;
+
+       if (sc->sc_started)
+               expect = STAT_RSCT;
+       else
+               expect = STAT_SCT;
+       sc->sc_started = 1;
+
+       return sxitwi_wait(sc, CONTROL_START, expect, flags);
+}
+
+int
+sxitwi_send_stop(void *v, int flags)
+{
+       struct sxitwi_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;
+       sxitwi_write_4(sc, TWSI_CONTROL, control);
+       while (--retry > 0) {
+               if (sxitwi_read_4(sc, TWSI_STATUS) == STAT_NRS)
+                       return 0;
+               delay(TWSI_STAT_DELAY);
+       }
+
+       return -1;
+}
+
+int
+sxitwi_initiate_xfer(void *v, i2c_addr_t addr, int flags)
+{
+       struct sxitwi_softc *sc = v;
+       u_int data, expect;
+       int error, read;
+
+       sxitwi_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);
+               sxitwi_write_4(sc, TWSI_DATA, data);
+               error = sxitwi_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);
+
+       sxitwi_write_4(sc, TWSI_DATA, data);
+       return sxitwi_wait(sc, 0, expect, flags);
+}
+
+int
+sxitwi_read_byte(void *v, uint8_t *valp, int flags)
+{
+       struct sxitwi_softc *sc = v;
+       int error;
+
+       if (flags & I2C_F_LAST)
+               error = sxitwi_wait(sc, 0, STAT_MRRD_ANT, flags);
+       else
+               error = sxitwi_wait(sc, CONTROL_ACK, STAT_MRRD_AT, flags);
+       if (!error)
+               *valp = sxitwi_read_4(sc, TWSI_DATA);
+       if ((flags & (I2C_F_LAST | I2C_F_STOP)) == (I2C_F_LAST | I2C_F_STOP))
+               error = sxitwi_send_stop(sc, flags);
+       return error;
+}
+
+int
+sxitwi_write_byte(void *v, uint8_t val, int flags)
+{
+       struct sxitwi_softc *sc = v;
+       int error;
+
+       sxitwi_write_4(sc, TWSI_DATA, val);
+       error = sxitwi_wait(sc, 0, STAT_MTDB_AR, flags);
+       if (flags & I2C_F_STOP)
+               sxitwi_send_stop(sc, flags);
+       return error;
+}
+
+int
+sxitwi_wait(struct sxitwi_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;
+       sxitwi_write_4(sc, TWSI_CONTROL, control | CONTROL_TWSIEN);
+
+       timo = 0;
+       do {
+               control = sxitwi_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, "sxitwi", 100);
+                       if (error)
+                               return error;
+               }
+       } while (++timo < 1000000);
+
+       status = sxitwi_read_4(sc, TWSI_STATUS);
+       if (status != expect)
+               return EIO;
+
+       return error;
+}

Reply via email to