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. >
Yes, it would be plenty more ideal for us, if it did. Yep, there's plenty more than just pmics we could have support for. > A bit of a step backwards to add code under the old-style 4-clause BSD > license, but I believe that is still acceptable. > Yep, tbh., i haven't looked at freebsd, if they would have something better w/regards that license currently, nor if netbsd has cleaned it, but i doubt not. > 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. > Will take a look at it, while it doesn't help w/the license. > A few more comments inline below. > reply to one of the comments below, for which i'd like to get some input before going for the rest, but i will look at fixing everything in a single new diff anyway, which might require a rainy day. Thank you for your comments. :) > 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. > I have met these serial power leakages on most boards when using ftdi usb uarts. will check if cubies do the same w/ethernet, atleast i don't remember having noticed such. > > > 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. Ah, forgot about that, and this is something like i had in mind for it: -Artturi diff --git a/sys/arch/armv7/armv7/armv7_machdep.c b/sys/arch/armv7/armv7/armv7_machdep.c index aa1c549b29b..cbe9daf47a2 100644 --- a/sys/arch/armv7/armv7/armv7_machdep.c +++ b/sys/arch/armv7/armv7/armv7_machdep.c @@ -203,6 +203,7 @@ int bootstrap_bs_map(void *, uint64_t, bus_size_t, int, bus_space_handle_t *); void process_kernel_args(char *); void consinit(void); +static int armv7_powerinput(void); bs_protos(bs_notimpl); @@ -220,6 +221,13 @@ int stdout_node = 0; void (*cpuresetfn)(void); void (*powerdownfn)(void); +int (*powerinputfn)(void) = armv7_powerinput; + +int +armv7_powerinput(void) +{ + return _PMIC_POWERINPUT_UNK; /* default input unknown */ +} /* * void boot(int howto, char *bootstr) diff --git a/sys/arch/armv7/armv7/armv7_machdep.h b/sys/arch/armv7/armv7/armv7_machdep.h index ff52b0c2744..c0dc99589e5 100644 --- a/sys/arch/armv7/armv7/armv7_machdep.h +++ b/sys/arch/armv7/armv7/armv7_machdep.h @@ -29,6 +29,13 @@ struct board_dev *platform_board_devs(); void *fdt_find_cons(const char *); extern void (*cpuresetfn)(void); extern void (*powerdownfn)(void); +extern int (*powerinputfn)(void); + +/* int *powerinputfn(void); return values */ +#define _PMIC_POWERINPUT_BATT 0 +#define _PMIC_POWERINPUT_UNK 1 /* default, allowing ie. ahci_attach */ +#define _PMIC_POWERINPUT_USB 2 +#define _PMIC_POWERINPUT_ACIN 3 struct armv7_platform { struct board_dev *devs; diff --git a/sys/arch/armv7/sunxi/sxiahci.c b/sys/arch/armv7/sunxi/sxiahci.c index 455ff94754b..3c93b92a126 100644 --- a/sys/arch/armv7/sunxi/sxiahci.c +++ b/sys/arch/armv7/sunxi/sxiahci.c @@ -100,6 +100,11 @@ sxiahci_attach(struct device *parent, struct device *self, void *aux) uint32_t target_supply; uint32_t timo; + if ((*powerinputfn)() == _PMIC_POWERINPUT_BATT) { + printf(": unsupported configuration, power input battery.\n"); + return; + } + if (faa->fa_nreg < 1) return; diff --git a/sys/dev/fdt/axp20x.c b/sys/dev/fdt/axp20x.c index 833038f0eff..852b05d466a 100644 --- a/sys/dev/fdt/axp20x.c +++ b/sys/dev/fdt/axp20x.c @@ -51,7 +51,7 @@ 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); +int axp20x_get_powerinput(void); void axp20x_shutdown(void); struct cfattach axppmic_ca = { @@ -98,6 +98,7 @@ axp20x_attach(struct device *parent, struct device *self, void *args) printf("\n"); powerdownfn = axp20x_shutdown; + powerinputfn = axp20x_get_powerinput; } int @@ -138,15 +139,16 @@ axp20x_writeb(u_char reg, u_char data) * 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) +int +axp20x_get_powerinput(void) { u_char psr; if (axp20x_readb(AXP209_PSR, &psr)) - psr = 0; - if (psr & AXP209_PSR_ACIN) - return 1; - return 0; + psr = 0; if (psr & AXP209_PSR_ACIN) + return _PMIC_POWERINPUT_ACIN; + else if (psr & AXP209_PSR_VBUS) + return _PMIC_POWERINPUT_USB; + return _PMIC_POWERINPUT_BATT; } 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.. > > + */ > > This comment makes no sense to me. > > > + axp20x_writeb(AXP209_SDR, AXP209_SDR_SHUTDOWN); > > +} > > diff --git a/sys/dev/fdt/files.fdt b/sys/dev/fdt/files.fdt > > index 9e2f64cbdaa..07e9b9025fd 100644 > > --- a/sys/dev/fdt/files.fdt > > +++ b/sys/dev/fdt/files.fdt > > @@ -23,6 +23,15 @@ device sximmc: sdmmcbus > > attach sximmc at fdt > > file dev/fdt/sximmc.c sximmc > > > > +device sxitwi: i2cbus > > +attach sxitwi at fdt > > +file dev/fdt/sxitwi.c sxitwi > > +file dev/fdt/gttwsi_core.c sxitwi > > + > > +device axppmic > > +attach axppmic at i2c > > +file dev/fdt/axp20x.c axppmic > > + > > device bcmdog > > attach bcmdog at fdt > > file dev/fdt/bcm2835_dog.c bcmdog > > diff --git a/sys/dev/fdt/gttwsi_core.c b/sys/dev/fdt/gttwsi_core.c > > new file mode 100644 > > index 00000000000..2f6f09c3464 > > --- /dev/null > > +++ b/sys/dev/fdt/gttwsi_core.c > > @@ -0,0 +1,430 @@ > > +/* $NetBSD: gttwsi_core.c,v 1.2 2014/11/23 13:37:27 jmcneill Exp $ */ > > +/* > > + * Copyright (c) 2008 Eiji Kawauchi. > > + * All rights reserved. > > + * > > + * Redistribution and use in source and binary forms, with or without > > + * modification, are permitted provided that the following conditions > > + * are met: > > + * 1. Redistributions of source code must retain the above copyright > > + * notice, this list of conditions and the following disclaimer. > > + * 2. Redistributions in binary form must reproduce the above copyright > > + * notice, this list of conditions and the following disclaimer in the > > + * documentation and/or other materials provided with the distribution. > > + * 3. All advertising materials mentioning features or use of this software > > + * must display the following acknowledgement: > > + * This product includes software developed for the NetBSD Project by > > + * Eiji Kawauchi. > > + * 4. The name of the author may not be used to endorse or promote products > > + * derived from this software without specific prior written permission > > + * > > + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR > > + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED > > WARRANTIES > > + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. > > + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, > > + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT > > + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF > > USE, > > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY > > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF > > + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. > > + */ > > +/* > > + * Copyright (c) 2005 Brocade Communcations, inc. > > + * All rights reserved. > > + * > > + * Written by Matt Thomas for Brocade Communcations, Inc. > > + * > > + * Redistribution and use in source and binary forms, with or without > > + * modification, are permitted provided that the following conditions > > + * are met: > > + * 1. Redistributions of source code must retain the above copyright > > + * notice, this list of conditions and the following disclaimer. > > + * 2. Redistributions in binary form must reproduce the above copyright > > + * notice, this list of conditions and the following disclaimer in the > > + * documentation and/or other materials provided with the distribution. > > + * 3. The name of Brocade Communications, Inc. may not be used to endorse > > + * or promote products derived from this software without specific prior > > + * written permission. > > + * > > + * THIS SOFTWARE IS PROVIDED BY BROCADE COMMUNICATIONS, INC. ``AS IS'' AND > > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR > > PURPOSE > > + * ARE DISCLAIMED. IN NO EVENT SHALL EITHER BROCADE COMMUNICATIONS, INC. > > BE > > + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > > + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > > + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > > + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > > + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > > + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED > > + * OF THE POSSIBILITY OF SUCH DAMAGE. > > + */ > > + > > +/* > > + * Marvell Two-Wire Serial Interface (aka I2C) master driver > > + */ > > + > > +#include <sys/param.h> > > +#include <sys/systm.h> > > +#include <sys/device.h> > > +#include <sys/kernel.h> > > +#include <sys/rwlock.h> > > + > > +#define _I2C_PRIVATE > > +#include <dev/i2c/i2cvar.h> > > + > > +#include <machine/bus.h> > > + > > +#include <dev/fdt/gttwsivar.h> > > + > > +#define GTTWSI_SIZE 0x100 > > + > > +#define GTTWSI_ALLWINNER > > +#if defined(GTTWSI_ALLWINNER) > > +#define TWSI_SLAVEADDR 0x00 > > +#define TWSI_EXTEND_SLAVEADDR 0x04 > > +#define TWSI_DATA 0x08 > > +#define TWSI_CONTROL 0x0c > > +#define TWSI_STATUS 0x10 > > +#define TWSI_BAUDRATE 0x14 > > +#define TWSI_SOFTRESET 0x18 > > +#else > > +#define TWSI_SLAVEADDR 0x00 > > +#define TWSI_EXTEND_SLAVEADDR 0x10 > > +#define TWSI_DATA 0x04 > > +#define TWSI_CONTROL 0x08 > > +#define TWSI_STATUS 0x0c /* for read */ > > +#define TWSI_BAUDRATE 0x0c /* for write */ > > +#define TWSI_SOFTRESET 0x1c > > +#endif > > + > > +#define SLAVEADDR_GCE_MASK 0x01 > > +#define SLAVEADDR_SADDR_MASK 0xfe > > + > > +#define EXTEND_SLAVEADDR_MASK 0xff > > + > > +#define DATA_MASK 0xff > > + > > +#define CONTROL_ACK (1 << 2) > > +#define CONTROL_IFLG (1 << 3) > > +#define CONTROL_STOP (1 << 4) > > +#define CONTROL_START (1 << 5) > > +#define CONTROL_TWSIEN (1 << 6) > > +#define CONTROL_INTEN (1 << 7) > > + > > +#define STAT_BE 0x00 /* Bus Error */ > > +#define STAT_SCT 0x08 /* Start condition transmitted */ > > +#define STAT_RSCT 0x10 /* Repeated start condition transmitted > > */ > > +#define STAT_AWBT_AR 0x18 /* Address + write bit transd, ack > > recvd */ > > +#define STAT_AWBT_ANR 0x20 /* Address + write bit transd, ack not > > recvd */ > > +#define STAT_MTDB_AR 0x28 /* Master transd data byte, ack recvd */ > > +#define STAT_MTDB_ANR 0x30 /* Master transd data byte, ack not > > recvd */ > > +#define STAT_MLADADT 0x38 /* Master lost arbitr during addr or > > data tx */ > > +#define STAT_ARBT_AR 0x40 /* Address + read bit transd, ack recvd > > */ > > +#define STAT_ARBT_ANR 0x48 /* Address + read bit transd, ack not > > recvd */ > > +#define STAT_MRRD_AT 0x50 /* Master received read data, ack > > transd */ > > +#define STAT_MRRD_ANT 0x58 /* Master received read data, ack not > > transd */ > > +#define STAT_SAWBT_AR 0xd0 /* Second addr + write bit transd, ack > > recvd */ > > +#define STAT_SAWBT_ANR 0xd8 /* S addr + write bit transd, ack not > > recvd */ > > +#define STAT_SARBT_AR 0xe0 /* Second addr + read bit transd, ack > > recvd */ > > +#define STAT_SARBT_ANR 0xe8 /* S addr + read bit transd, ack not > > recvd */ > > +#define STAT_NRS 0xf8 /* No relevant status */ > > + > > +#define SOFTRESET_VAL 0 /* reset value */ > > + > > +#define TWSI_RETRY_COUNT 1000 /* retry loop count */ > > +#define TWSI_RETRY_DELAY 1 /* retry delay */ > > +#define TWSI_STAT_DELAY 1 /* poll status delay */ > > +#define TWSI_READ_DELAY 2 /* read delay */ > > +#define TWSI_WRITE_DELAY 2 /* write delay */ > > + > > + > > +/*efine TWSI_DEBUG > > You messed that one up ;). > > > +#ifdef TWSI_DEBUG > > +/* > > + * conditional debugging > > + */ > > +#define CD_INIT 0x00000001 /* init */ > > +#define CD_ERR 0x00000002 /* errors */ > > +#define CD_TIMO 0x00000004 /* timeout */ > > +#define CD_INFO 0x00000004 /* timeout */ > > +#define CD_DBG 0x00000010 /* just dbg */ > > +#define CD_SPAM 0x00000020 /* verbose boot */ > > +#define CD_ALL 0xffffffff > > + > > +int gttwsi_debug = 0 /*| CD_INIT | CD_DBG | CD_SPAM | CD_ALL*/; > > + > > +#define DPRINTF(flg, stmt) \ > > +do { \ > > + if (gttwsi_debug & (flg)) \ > > + printf stmt; \ > > +} while (0) > > +#else > > +#define DPRINTF(flg, stmt) do { } while (0) > > +#endif /* TWSI_DEBUG */ > > + > > +#define DNAME(sc) ((sc)->sc_dev.dv_xname) > > We try to avoid elaborate debugging code like this. I doubt it is > very useful in this case. > > > + > > +int gttwsi_acquire_bus(void *, int); > > +void gttwsi_release_bus(void *, int); > > +int gttwsi_send_start(void *v, int flags); > > +int gttwsi_send_stop(void *v, int flags); > > +int gttwsi_initiate_xfer(void *v, i2c_addr_t addr, int flags); > > +int gttwsi_read_byte(void *v, uint8_t *valp, int flags); > > +int gttwsi_write_byte(void *v, uint8_t val, int flags); > > + > > +int gttwsi_wait(struct gttwsi_softc *, uint32_t, uint32_t, int); > > + > > +inline u_int > > +gttwsi_read_4(struct gttwsi_softc *sc, u_int reg) > > +{ > > + u_int val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg); > > + > > + DPRINTF(CD_SPAM, ("I2C:R:%02x:%02x\n", reg, val)); > > +#if !defined(TWSI_DEBUG) > > + delay(TWSI_READ_DELAY); > > +#endif > > + > > + return val; > > +} > > + > > +inline void > > +gttwsi_write_4(struct gttwsi_softc *sc, u_int reg, u_int val) > > +{ > > + bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg, val); > > + > > + DPRINTF(CD_SPAM, ("I2C:W:%02x:%02x\n", reg, val)); > > +#if !defined(TWSI_DEBUG) > > + delay(TWSI_WRITE_DELAY); > > +#endif > > + > > + return; > > +} > > + > > +void > > +gttwsi_attach_subr(struct device *self, bus_space_tag_t iot, > > + bus_space_handle_t ioh, int node) > > +{ > > + struct gttwsi_softc * const sc = (struct gttwsi_softc *)self; > > + > > + sc->sc_iot = iot; > > + sc->sc_ioh = ioh; > > + sc->sc_node = node; > > + > > + rw_init(&sc->sc_buslock, sc->sc_dev.dv_xname); > > + > > + sc->sc_started = 0; > > + sc->sc_ic.ic_cookie = sc; > > + sc->sc_ic.ic_acquire_bus = gttwsi_acquire_bus; > > + sc->sc_ic.ic_release_bus = gttwsi_release_bus; > > + sc->sc_ic.ic_exec = NULL; > > + sc->sc_ic.ic_send_start = gttwsi_send_start; > > + sc->sc_ic.ic_send_stop = gttwsi_send_stop; > > + sc->sc_ic.ic_initiate_xfer = gttwsi_initiate_xfer; > > + sc->sc_ic.ic_read_byte = gttwsi_read_byte; > > + sc->sc_ic.ic_write_byte = gttwsi_write_byte; > > + > > + /* > > + * Put the controller into Soft Reset. > > + */ > > + > > + gttwsi_write_4(sc, TWSI_SOFTRESET, SOFTRESET_VAL); > > + > > + printf("\n"); > > +} > > + > > +void > > +gttwsi_config_children(struct device *self) > > +{ > > + struct gttwsi_softc * const sc = (struct gttwsi_softc *)self; > > + struct i2cbus_attach_args iba; > > + > > + memset(&iba, 0, sizeof(iba)); > > + iba.iba_name = "iic"; > > + iba.iba_tag = &sc->sc_ic; > > + > > + (void)config_found(&sc->sc_dev, &iba, iicbus_print); > > +} > > + > > +int > > +gttwsi_intr(void *arg) > > +{ > > + struct gttwsi_softc *sc = arg; > > + u_int val; > > + > > + val = gttwsi_read_4(sc, TWSI_CONTROL); > > + if (val & CONTROL_IFLG) { > > + gttwsi_write_4(sc, TWSI_CONTROL, val & ~CONTROL_INTEN); > > + wakeup(&sc->sc_dev); > > + return 1; > > + } > > + return 0; > > +} > > + > > +int > > +gttwsi_acquire_bus(void *arg, int flags) > > +{ > > + struct gttwsi_softc *sc = arg; > > + > > + if (flags & I2C_F_POLL) > > + return 0; > > + > > + return rw_enter(&sc->sc_buslock, RW_WRITE); > > +} > > + > > +void > > +gttwsi_release_bus(void *arg, int flags) > > +{ > > + struct gttwsi_softc *sc = arg; > > + > > + if (flags & I2C_F_POLL) > > + return; > > + > > + rw_exit(&sc->sc_buslock); > > +} > > + > > +int > > +gttwsi_send_start(void *v, int flags) > > +{ > > + struct gttwsi_softc *sc = v; > > + int expect; > > + > > + if (sc->sc_started) > > + expect = STAT_RSCT; > > + else > > + expect = STAT_SCT; > > + sc->sc_started = 1; > > + return gttwsi_wait(sc, CONTROL_START, expect, flags); > > +} > > + > > +int > > +gttwsi_send_stop(void *v, int flags) > > +{ > > + struct gttwsi_softc *sc = v; > > + int retry = TWSI_RETRY_COUNT; > > + u_int control; > > + > > + sc->sc_started = 0; > > + > > + /* Interrupt is not generated for STAT_NRS. */ > > + control = CONTROL_STOP | CONTROL_TWSIEN; > > + gttwsi_write_4(sc, TWSI_CONTROL, control); > > + while (--retry > 0) { > > + if (gttwsi_read_4(sc, TWSI_STATUS) == STAT_NRS) > > + return 0; > > + delay(TWSI_STAT_DELAY); > > + } > > + > > + DPRINTF(CD_ERR, ("%s: send STOP failed\n", DNAME(sc))); > > + > > + return -1; > > +} > > + > > +int > > +gttwsi_initiate_xfer(void *v, i2c_addr_t addr, int flags) > > +{ > > + struct gttwsi_softc *sc = v; > > + u_int data, expect; > > + int error, read; > > + > > + gttwsi_send_start(v, flags); > > + > > + read = (flags & I2C_F_READ) != 0; > > + if (read) > > + expect = STAT_ARBT_AR; > > + else > > + expect = STAT_AWBT_AR; > > + > > + /* > > + * First byte contains whether this xfer is a read or write. > > + */ > > + data = read; > > + if (addr > 0x7f) { > > + /* > > + * If this is a 10bit request, the first address byte is > > + * 0b11110<b9><b8><r/w>. > > + */ > > + data |= 0xf0 | ((addr & 0x300) >> 7); > > + gttwsi_write_4(sc, TWSI_DATA, data); > > + error = gttwsi_wait(sc, 0, expect, flags); > > + if (error) > > + return error; > > + /* > > + * The first address byte has been sent, now to send > > + * the second one. > > + */ > > + if (read) > > + expect = STAT_SARBT_AR; > > + else > > + expect = STAT_SAWBT_AR; > > + data = (uint8_t)addr; > > + } else > > + data |= (addr << 1); > > + > > + gttwsi_write_4(sc, TWSI_DATA, data); > > + return gttwsi_wait(sc, 0, expect, flags); > > +} > > + > > +int > > +gttwsi_read_byte(void *v, uint8_t *valp, int flags) > > +{ > > + struct gttwsi_softc *sc = v; > > + int error; > > + > > + if (flags & I2C_F_LAST) > > + error = gttwsi_wait(sc, 0, STAT_MRRD_ANT, flags); > > + else > > + error = gttwsi_wait(sc, CONTROL_ACK, STAT_MRRD_AT, flags); > > + if (!error) > > + *valp = gttwsi_read_4(sc, TWSI_DATA); > > + if ((flags & (I2C_F_LAST | I2C_F_STOP)) == (I2C_F_LAST | I2C_F_STOP)) > > + error = gttwsi_send_stop(sc, flags); > > + return error; > > +} > > + > > +int > > +gttwsi_write_byte(void *v, uint8_t val, int flags) > > +{ > > + struct gttwsi_softc *sc = v; > > + int error; > > + > > + gttwsi_write_4(sc, TWSI_DATA, val); > > + error = gttwsi_wait(sc, 0, STAT_MTDB_AR, flags); > > + if (flags & I2C_F_STOP) > > + gttwsi_send_stop(sc, flags); > > + return error; > > +} > > + > > +int > > +gttwsi_wait(struct gttwsi_softc *sc, u_int control, u_int expect, int > > flags) > > +{ > > + u_int status; > > + int timo, error = 0; > > + > > + delay(5); > > + if (!(flags & I2C_F_POLL)) > > + control |= CONTROL_INTEN; > > + gttwsi_write_4(sc, TWSI_CONTROL, control | CONTROL_TWSIEN); > > + > > + timo = 0; > > + do { > > + control = gttwsi_read_4(sc, TWSI_CONTROL); > > + if (control & CONTROL_IFLG) > > + break; > > + if (flags & I2C_F_POLL) > > + delay(TWSI_RETRY_DELAY); > > + else { > > + error = tsleep(&sc->sc_dev, PWAIT, "gttwsi", 100); > > + if (error) > > + return error; > > + } > > + } while (++timo < 1000000); > > + > > + status = gttwsi_read_4(sc, TWSI_STATUS); > > + if (status != expect) { > > + DPRINTF(CD_ERR, ("%s: status %#x expected %#x\n", > > + DNAME(sc), status, expect)); > > + return EIO; > > + } > > + return error; > > +} > > diff --git a/sys/dev/fdt/gttwsivar.h b/sys/dev/fdt/gttwsivar.h > > new file mode 100644 > > index 00000000000..c5edf3a8548 > > --- /dev/null > > +++ b/sys/dev/fdt/gttwsivar.h > > @@ -0,0 +1,91 @@ > > +/* $NetBSD: gttwsivar.h,v 1.2 2014/11/23 13:37:27 jmcneill Exp $ */ > > +/* > > + * Copyright (c) 2008 Eiji Kawauchi. > > + * All rights reserved. > > + * > > + * Redistribution and use in source and binary forms, with or without > > + * modification, are permitted provided that the following conditions > > + * are met: > > + * 1. Redistributions of source code must retain the above copyright > > + * notice, this list of conditions and the following disclaimer. > > + * 2. Redistributions in binary form must reproduce the above copyright > > + * notice, this list of conditions and the following disclaimer in the > > + * documentation and/or other materials provided with the distribution. > > + * 3. All advertising materials mentioning features or use of this software > > + * must display the following acknowledgement: > > + * This product includes software developed for the NetBSD Project by > > + * Eiji Kawauchi. > > + * 4. The name of the author may not be used to endorse or promote products > > + * derived from this software without specific prior written permission > > + * > > + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR > > + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED > > WARRANTIES > > + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. > > + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, > > + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT > > + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF > > USE, > > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY > > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF > > + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. > > + */ > > +/* > > + * Copyright (c) 2005 Brocade Communcations, inc. > > + * All rights reserved. > > + * > > + * Written by Matt Thomas for Brocade Communcations, Inc. > > + * > > + * Redistribution and use in source and binary forms, with or without > > + * modification, are permitted provided that the following conditions > > + * are met: > > + * 1. Redistributions of source code must retain the above copyright > > + * notice, this list of conditions and the following disclaimer. > > + * 2. Redistributions in binary form must reproduce the above copyright > > + * notice, this list of conditions and the following disclaimer in the > > + * documentation and/or other materials provided with the distribution. > > + * 3. The name of Brocade Communications, Inc. may not be used to endorse > > + * or promote products derived from this software without specific prior > > + * written permission. > > + * > > + * THIS SOFTWARE IS PROVIDED BY BROCADE COMMUNICATIONS, INC. ``AS IS'' AND > > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR > > PURPOSE > > + * ARE DISCLAIMED. IN NO EVENT SHALL EITHER BROCADE COMMUNICATIONS, INC. > > BE > > + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > > + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > > + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > > + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > > + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > > + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED > > + * OF THE POSSIBILITY OF SUCH DAMAGE. > > + */ > > + > > +#ifndef _DEV_MARVELL_GTTWSIVAR_H_ > > +#define _DEV_MARVELL_GTTWSIVAR_H_ > > + > > +/* > > + * Marvell Two-Wire Serial Interface (aka I2C) master driver > > + */ > > +#include <sys/device.h> > > +#include <sys/rwlock.h> > > + > > +#include <dev/i2c/i2cvar.h> > > +#include <machine/bus.h> > > + > > +struct gttwsi_softc { > > + struct device sc_dev; > > + bus_space_tag_t sc_iot; > > + bus_space_handle_t sc_ioh; > > + int sc_node; > > + u_int sc_started; > > + struct i2c_controller sc_ic; > > + struct rwlock sc_buslock; > > +}; > > + > > +void gttwsi_attach_subr(struct device *, bus_space_tag_t, > > + bus_space_handle_t, int); > > +void gttwsi_config_children(struct device *); > > This function is unused. > > > + > > +int gttwsi_intr(void *); > > + > > +#endif /* _DEV_MARVELL_GTTSWI_VAR_H_ */ > > diff --git a/sys/dev/fdt/sxitwi.c b/sys/dev/fdt/sxitwi.c > > new file mode 100644 > > index 00000000000..665c7201045 > > --- /dev/null > > +++ b/sys/dev/fdt/sxitwi.c > > @@ -0,0 +1,170 @@ > > +/* $NetBSD: awin_twi.c,v 1.7 2015/12/26 16:54:41 macallan Exp $ */ > > +/* > > + * Copyright (c) 2013 The NetBSD Foundation, Inc. > > + * All rights reserved. > > + * > > + * This code is derived from software contributed to The NetBSD Foundation > > + * by Matt Thomas of 3am Software Foundry. > > + * > > + * Redistribution and use in source and binary forms, with or without > > + * modification, are permitted provided that the following conditions > > + * are met: > > + * 1. Redistributions of source code must retain the above copyright > > + * notice, this list of conditions and the following disclaimer. > > + * 2. Redistributions in binary form must reproduce the above copyright > > + * notice, this list of conditions and the following disclaimer in the > > + * documentation and/or other materials provided with the distribution. > > + * > > + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND > > CONTRIBUTORS > > + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > > LIMITED > > + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A > > PARTICULAR > > + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR > > CONTRIBUTORS > > + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > > + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > > + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > > + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > > + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > > + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF > > THE > > + * POSSIBILITY OF SUCH DAMAGE. > > + */ > > + > > +#include <sys/param.h> > > +#include <sys/device.h> > > +#include <sys/systm.h> > > + > > +#define _I2C_PRIVATE > > +#include <dev/i2c/i2cvar.h> > > + > > +#include <machine/bus.h> > > +#include <machine/fdt.h> > > + > > +#include <dev/fdt/gttwsivar.h> > > + > > +#include <dev/ofw/openfirm.h> > > +#include <dev/ofw/ofw_clock.h> > > +#include <dev/ofw/ofw_pinctrl.h> > > +#include <dev/ofw/fdt.h> > > + > > + > > +#define TWI_CCR_REG 0x14 > > +#define TWI_CCR_CLK_M (0x0f << 3) > > +#define TWI_CCR_CLK_N (0x07 << 0) > > + > > +void sxitwi_attach(struct device *, struct device *, void *); > > +int sxitwi_match(struct device *, void *, void *); > > +void sxitwi_bus_scan(struct device *, struct i2cbus_attach_args *, > > void *); > > + > > +struct sxitwi_softc { > > + struct gttwsi_softc sc_sc; > > + void *sc_ih; > > +}; > > + > > +struct cfdriver sxitwi_cd = { > > + NULL, "sxitwi", DV_DULL > > +}; > > + > > +struct cfattach sxitwi_ca = { > > + sizeof(struct sxitwi_softc), sxitwi_match, sxitwi_attach > > +}; > > + > > +int > > +sxitwi_match(struct device *parent, void *cf, void *arg) > > +{ > > + struct fdt_attach_args *faa = arg; > > + > > + if (OF_is_compatible(faa->fa_node, "allwinner,sun4i-a10-i2c")) > > + return 1; > > + if (OF_is_compatible(faa->fa_node, "allwinner,sun7i-a20-i2c")) > > + return 1; > > + > > + return 0; > > +} > > + > > +void > > +sxitwi_attach(struct device *parent, struct device *self, void *arg) > > +{ > > + struct sxitwi_softc *sc = (struct sxitwi_softc *)self; > > + struct fdt_attach_args *faa = arg; > > + bus_space_tag_t iot = faa->fa_iot; > > + bus_space_handle_t ioh; > > + > > + if (bus_space_map(iot, faa->fa_reg[0].addr, > > + faa->fa_reg[0].size, 0, &ioh)) > > + panic("sxitwi_attach: bus_space_map failed!"); > > + > > + /* > > + * Acquire the PIO pins needed for the TWI port, and > > + * enable clock gating via CCMU > > + */ > > + pinctrl_byname(faa->fa_node, "default"); > > + > > + /* enable clock */ > > + clock_enable(faa->fa_node, NULL); > > + > > + /* > > + * Set clock rate to 100kHz. From the datasheet: > > + * For 100Khz standard speed 2Wire, CLK_N=2, CLK_M=11 > > + * F0=48M/2^2=12Mhz, F1=F0/(10*(11+1)) = 0.1Mhz > > + */ > > + bus_space_write_4(iot, ioh, TWI_CCR_REG, (11 << 3) | (2 << 0)); > > + > > + /* > > + * Do the MI attach > > + */ > > + gttwsi_attach_subr(self, iot, ioh, faa->fa_node); > > + > > + /* > > + * Establish interrupt for it > > + */ > > + sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_BIO, > > + gttwsi_intr, sc, sc->sc_sc.sc_dev.dv_xname); > > + if (sc->sc_ih == NULL) { > > + printf(": can't to establish interrupt\n"); > > + return; > > + } > > + > > + /* > > + * Configure its children > > + */ > > + > > + struct i2cbus_attach_args iba; > > + > > + memset(&iba, 0, sizeof(iba)); > > + iba.iba_name = "iic"; > > + iba.iba_tag = &sc->sc_sc.sc_ic; > > + iba.iba_bus_scan = sxitwi_bus_scan; > > + iba.iba_bus_scan_arg = &sc->sc_sc.sc_node; > > + > > + (void)config_found(&sc->sc_sc.sc_dev, &iba, iicbus_print); > > + > > +} > > + > > +void > > +sxitwi_bus_scan(struct device *self, struct i2cbus_attach_args *iba, void > > *arg) > > +{ > > + int iba_node = *(int *)arg; > > + struct i2c_attach_args ia; > > + char name[32]; > > + uint32_t reg[1]; > > + int node; > > + > > + for (node = OF_child(iba_node); node; node = OF_peer(node)) { > > + memset(name, 0, sizeof(name)); > > + memset(reg, 0, sizeof(reg)); > > + > > + if (OF_getprop(node, "compatible", name, sizeof(name)) == -1) > > + continue; > > + if (name[0] == '\0') > > + continue; > > + > > + if (OF_getprop(node, "reg", ®, sizeof(reg)) != sizeof(reg)) > > + continue; > > + > > + memset(&ia, 0, sizeof(ia)); > > + ia.ia_tag = iba->iba_tag; > > + ia.ia_addr = bemtoh32(®[0]); > > + ia.ia_name = name; > > + ia.ia_cookie = &node; > > + config_found(self, &ia, iic_print); > > + } > > +} > > > >