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