> 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", &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);
> +     }
> +}
> 
> 

Reply via email to