Module Name: src Committed By: matt Date: Fri Sep 6 00:56:13 UTC 2013
Modified Files: src/sys/dev/i2c: files.i2c src/sys/dev/marvell: files.discovery gttwsi.c Added Files: src/sys/dev/i2c: gttwsi_core.c gttwsireg.h gttwsivar.h Removed Files: src/sys/dev/marvell: gttwsireg.h Log Message: Make gttswi MI and usuable from non-Marvell SoCs. (should rename to mvi2c but ...) To generate a diff of this commit: cvs rdiff -u -r1.50 -r1.51 src/sys/dev/i2c/files.i2c cvs rdiff -u -r0 -r1.1 src/sys/dev/i2c/gttwsi_core.c \ src/sys/dev/i2c/gttwsireg.h src/sys/dev/i2c/gttwsivar.h cvs rdiff -u -r1.21 -r1.22 src/sys/dev/marvell/files.discovery cvs rdiff -u -r1.10 -r1.11 src/sys/dev/marvell/gttwsi.c cvs rdiff -u -r1.4 -r0 src/sys/dev/marvell/gttwsireg.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/i2c/files.i2c diff -u src/sys/dev/i2c/files.i2c:1.50 src/sys/dev/i2c/files.i2c:1.51 --- src/sys/dev/i2c/files.i2c:1.50 Tue Aug 6 15:58:25 2013 +++ src/sys/dev/i2c/files.i2c Fri Sep 6 00:56:12 2013 @@ -1,4 +1,4 @@ -# $NetBSD: files.i2c,v 1.50 2013/08/06 15:58:25 soren Exp $ +# $NetBSD: files.i2c,v 1.51 2013/09/06 00:56:12 matt Exp $ obsolete defflag opt_i2cbus.h I2C_SCAN define i2cbus { } @@ -52,6 +52,8 @@ file dev/i2c/cx24227.c cx24227 # define motoi2c file dev/i2c/motoi2c.c motoi2c +define mvi2c +file dev/i2c/gttwsi_core.c mvi2c # # I2C client devices @@ -152,6 +154,11 @@ device sdtemp: sysmon_envsys attach sdtemp at iic file dev/i2c/sdtemp.c sdtemp +# DS1672 Real Time Clock +device ds1672rtc +attach ds1672rtc at iic +file dev/i2c/ds1672.c ds1672rtc + # ADM1021 device admtemp: sysmon_envsys attach admtemp at iic Index: src/sys/dev/marvell/files.discovery diff -u src/sys/dev/marvell/files.discovery:1.21 src/sys/dev/marvell/files.discovery:1.22 --- src/sys/dev/marvell/files.discovery:1.21 Thu Aug 29 09:46:04 2013 +++ src/sys/dev/marvell/files.discovery Fri Sep 6 00:56:12 2013 @@ -1,4 +1,4 @@ -# $NetBSD: files.discovery,v 1.21 2013/08/29 09:46:04 kiyohara Exp $ +# $NetBSD: files.discovery,v 1.22 2013/09/06 00:56:12 matt Exp $ # # Config file and device description for machine-independent support for # the Marvell (formerly Galileo Technology) Discovery system controllers. @@ -77,7 +77,7 @@ file dev/marvell/mvcesa.c mvcesa attach mvcesa at gt with mvcesa_gt # Two-Wire Serial Interface -device gttwsi: i2cbus +device gttwsi: i2cbus, mvi2c file dev/marvell/gttwsi.c gttwsi attach gttwsi at gt with gttwsi_gt Index: src/sys/dev/marvell/gttwsi.c diff -u src/sys/dev/marvell/gttwsi.c:1.10 src/sys/dev/marvell/gttwsi.c:1.11 --- src/sys/dev/marvell/gttwsi.c:1.10 Thu Sep 5 22:28:57 2013 +++ src/sys/dev/marvell/gttwsi.c Fri Sep 6 00:56:12 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: gttwsi.c,v 1.10 2013/09/05 22:28:57 matt Exp $ */ +/* $NetBSD: gttwsi.c,v 1.11 2013/09/06 00:56:12 matt Exp $ */ /* * Copyright (c) 2008 Eiji Kawauchi. * All rights reserved. @@ -66,7 +66,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: gttwsi.c,v 1.10 2013/09/05 22:28:57 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: gttwsi.c,v 1.11 2013/09/06 00:56:12 matt Exp $"); #include "locators.h" #include <sys/param.h> @@ -82,73 +82,19 @@ __KERNEL_RCSID(0, "$NetBSD: gttwsi.c,v 1 #include <machine/param.h> #include <dev/i2c/i2cvar.h> +#include <dev/i2c/gttwsireg.h> +#include <dev/i2c/gttwsivar.h> #include <dev/marvell/marvellvar.h> -#include <dev/marvell/gttwsireg.h> - -struct gttwsi_softc { - device_t sc_dev; - bus_space_tag_t sc_bust; - bus_space_handle_t sc_bush; - bool sc_started; - struct i2c_controller sc_i2c; - kmutex_t sc_buslock; - kmutex_t sc_mtx; - kcondvar_t sc_cv; -}; static int gttwsi_match(device_t, cfdata_t, void *); static void gttwsi_attach(device_t, device_t, void *); -static int gttwsi_intr(void *); - -static int gttwsi_acquire_bus(void *, int); -static void gttwsi_release_bus(void *, int); -static int gttwsi_send_start(void *v, int flags); -static int gttwsi_send_stop(void *v, int flags); -static int gttwsi_initiate_xfer(void *v, i2c_addr_t addr, int flags); -static int gttwsi_read_byte(void *v, uint8_t *valp, int flags); -static int gttwsi_write_byte(void *v, uint8_t val, int flags); - -static int gttwsi_wait(struct gttwsi_softc *, uint32_t, uint32_t, int); - -static __inline u_int32_t RREG(struct gttwsi_softc *, u_int32_t); -static __inline void WREG(struct gttwsi_softc *, u_int32_t, u_int32_t); - - CFATTACH_DECL_NEW(gttwsi_gt, sizeof(struct gttwsi_softc), gttwsi_match, gttwsi_attach, NULL, NULL); CFATTACH_DECL_NEW(gttwsi_mbus, sizeof(struct gttwsi_softc), gttwsi_match, gttwsi_attach, NULL, NULL); - -static __inline u_int32_t -RREG(struct gttwsi_softc *sc, u_int32_t reg) -{ - u_int32_t val; - - val = bus_space_read_4(sc->sc_bust, sc->sc_bush, reg); -#ifdef TWSI_DEBUG - printf("I2C:R:%02x:%02x\n", reg, val); -#else - DELAY(TWSI_READ_DELAY); -#endif - return val; -} - -static __inline void -WREG(struct gttwsi_softc *sc, u_int32_t reg, u_int32_t val) -{ - bus_space_write_4(sc->sc_bust, sc->sc_bush, reg, val); -#ifdef TWSI_DEBUG - printf("I2C:W:%02x:%02x\n", reg, val); -#else - DELAY(TWSI_WRITE_DELAY); -#endif - return; -} - - /* ARGSUSED */ static int gttwsi_match(device_t parent, cfdata_t match, void *aux) @@ -169,230 +115,19 @@ gttwsi_match(device_t parent, cfdata_t m static void gttwsi_attach(device_t parent, device_t self, void *args) { - struct gttwsi_softc *sc = device_private(self); struct marvell_attach_args *mva = args; - struct i2cbus_attach_args iba; - - aprint_naive("\n"); - aprint_normal(": Marvell TWSI controller\n"); + bus_space_handle_t ioh; - sc->sc_dev = self; - sc->sc_bust = mva->mva_iot; if (bus_space_subregion(mva->mva_iot, mva->mva_ioh, mva->mva_offset, - mva->mva_size, &sc->sc_bush)) { - aprint_error_dev(self, "Cannot map registers\n"); + mva->mva_size, &ioh)) { + aprint_error(": cannot map registers\n"); return; } - mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_NONE); - mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_BIO); - cv_init(&sc->sc_cv, "gttwsi"); - - sc->sc_started = false; - sc->sc_i2c.ic_cookie = sc; - sc->sc_i2c.ic_acquire_bus = gttwsi_acquire_bus; - sc->sc_i2c.ic_release_bus = gttwsi_release_bus; - sc->sc_i2c.ic_exec = NULL; - sc->sc_i2c.ic_send_start = gttwsi_send_start; - sc->sc_i2c.ic_send_stop = gttwsi_send_stop; - sc->sc_i2c.ic_initiate_xfer = gttwsi_initiate_xfer; - sc->sc_i2c.ic_read_byte = gttwsi_read_byte; - sc->sc_i2c.ic_write_byte = gttwsi_write_byte; - - marvell_intr_establish(mva->mva_irq, IPL_BIO, gttwsi_intr, sc); - - /* - * Put the controller into Soft Reset. - */ - /* reset */ - WREG(sc, TWSI_SOFTRESET, SOFTRESET_VAL); - - memset(&iba, 0, sizeof(iba)); - iba.iba_tag = &sc->sc_i2c; - (void) config_found_ia(sc->sc_dev, "i2cbus", &iba, iicbus_print); -} + gttwsi_attach_subr(self, mva->mva_iot, ioh); -static int -gttwsi_intr(void *arg) -{ - struct gttwsi_softc *sc = arg; - uint32_t val; - - val = RREG(sc, TWSI_CONTROL); - if (val & CONTROL_IFLG) { - WREG(sc, TWSI_CONTROL, val & ~CONTROL_INTEN); - mutex_enter(&sc->sc_mtx); - cv_signal(&sc->sc_cv); - mutex_exit(&sc->sc_mtx); - - return 1; /* handled */ - } - return 0; -} - -/* ARGSUSED */ -static int -gttwsi_acquire_bus(void *arg, int flags) -{ - struct gttwsi_softc *sc = arg; - - mutex_enter(&sc->sc_buslock); - return 0; -} - -/* ARGSUSED */ -static void -gttwsi_release_bus(void *arg, int flags) -{ - struct gttwsi_softc *sc = arg; - - mutex_exit(&sc->sc_buslock); -} + marvell_intr_establish(mva->mva_irq, IPL_BIO, gttwsi_intr, + device_private(self)); -static 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 = true; - return gttwsi_wait(sc, CONTROL_START, expect, flags); -} - -static int -gttwsi_send_stop(void *v, int flags) -{ - struct gttwsi_softc *sc = v; - int retry = TWSI_RETRY_COUNT; - - sc->sc_started = false; - - /* Interrupt is not generated for STAT_NRS. */ - WREG(sc, TWSI_CONTROL, CONTROL_STOP | CONTROL_TWSIEN); - while (retry > 0) { - if (RREG(sc, TWSI_STATUS) == STAT_NRS) - return 0; - retry--; - DELAY(TWSI_STAT_DELAY); - } - - aprint_error_dev(sc->sc_dev, "send STOP failed\n"); - return -1; -} - -static int -gttwsi_initiate_xfer(void *v, i2c_addr_t addr, int flags) -{ - struct gttwsi_softc *sc = v; - uint32_t 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); - WREG(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); - - WREG(sc, TWSI_DATA, data); - return gttwsi_wait(sc, 0, expect, flags); -} - -static 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 = RREG(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; -} - -static int -gttwsi_write_byte(void *v, uint8_t val, int flags) -{ - struct gttwsi_softc *sc = v; - int error; - - WREG(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; -} - -static int -gttwsi_wait(struct gttwsi_softc *sc, uint32_t control, uint32_t expect, - int flags) -{ - uint32_t status; - int timo, error = 0; - - DELAY(5); - if (!(flags & I2C_F_POLL)) - control |= CONTROL_INTEN; - WREG(sc, TWSI_CONTROL, control | CONTROL_TWSIEN); - - timo = 0; - for (;;) { - control = RREG(sc, TWSI_CONTROL); - if (control & CONTROL_IFLG) - break; - if (!(flags & I2C_F_POLL)) { - mutex_enter(&sc->sc_mtx); - error = cv_timedwait_sig(&sc->sc_cv, &sc->sc_mtx, hz); - mutex_exit(&sc->sc_mtx); - if (error) - return error; - } - DELAY(TWSI_RETRY_DELAY); - if (timo++ > 1000000) /* 1sec */ - break; - } - - status = RREG(sc, TWSI_STATUS); - if (status != expect) { - aprint_error_dev(sc->sc_dev, - "unexpected status 0x%x: expect 0x%x\n", status, expect); - return EIO; - } - return error; + gttwsi_config_children(self); } Added files: Index: src/sys/dev/i2c/gttwsi_core.c diff -u /dev/null src/sys/dev/i2c/gttwsi_core.c:1.1 --- /dev/null Fri Sep 6 00:56:13 2013 +++ src/sys/dev/i2c/gttwsi_core.c Fri Sep 6 00:56:12 2013 @@ -0,0 +1,353 @@ +/* $NetBSD: gttwsi_core.c,v 1.1 2013/09/06 00:56:12 matt 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. + */ +//#define TWSI_DEBUG + +/* + * Marvell Two-Wire Serial Interface (aka I2C) master driver + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: gttwsi_core.c,v 1.1 2013/09/06 00:56:12 matt Exp $"); +#include "locators.h" + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/condvar.h> +#include <sys/device.h> +#include <sys/errno.h> +#include <sys/kernel.h> +#include <sys/mutex.h> +#include <sys/systm.h> + +#include <dev/i2c/i2cvar.h> + +#include <dev/i2c/gttwsireg.h> +#include <dev/i2c/gttwsivar.h> + +static int gttwsi_acquire_bus(void *, int); +static void gttwsi_release_bus(void *, int); +static int gttwsi_send_start(void *v, int flags); +static int gttwsi_send_stop(void *v, int flags); +static int gttwsi_initiate_xfer(void *v, i2c_addr_t addr, int flags); +static int gttwsi_read_byte(void *v, uint8_t *valp, int flags); +static int gttwsi_write_byte(void *v, uint8_t val, int flags); + +static int gttwsi_wait(struct gttwsi_softc *, uint32_t, uint32_t, int); + +static inline uint32_t +gttwsi_read_4(struct gttwsi_softc *sc, uint32_t reg) +{ + uint32_t val = bus_space_read_4(sc->sc_bust, sc->sc_bush, reg); +#ifdef TWSI_DEBUG + printf("I2C:R:%02x:%02x\n", reg, val); +#else + DELAY(TWSI_READ_DELAY); +#endif + return val; +} + +static inline void +gttwsi_write_4(struct gttwsi_softc *sc, uint32_t reg, uint32_t val) +{ + bus_space_write_4(sc->sc_bust, sc->sc_bush, reg, val); +#ifdef TWSI_DEBUG + printf("I2C:W:%02x:%02x\n", reg, val); +#else + DELAY(TWSI_WRITE_DELAY); +#endif + return; +} + + + +/* ARGSUSED */ +void +gttwsi_attach_subr(device_t self, bus_space_tag_t iot, bus_space_handle_t ioh) +{ + struct gttwsi_softc * const sc = device_private(self); + + aprint_naive("\n"); + aprint_normal(": Marvell TWSI controller\n"); + + sc->sc_dev = self; + sc->sc_bust = iot; + sc->sc_bush = ioh; + + mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_NONE); + mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_BIO); + cv_init(&sc->sc_cv, device_xname(self)); + + sc->sc_started = false; + sc->sc_i2c.ic_cookie = sc; + sc->sc_i2c.ic_acquire_bus = gttwsi_acquire_bus; + sc->sc_i2c.ic_release_bus = gttwsi_release_bus; + sc->sc_i2c.ic_exec = NULL; + sc->sc_i2c.ic_send_start = gttwsi_send_start; + sc->sc_i2c.ic_send_stop = gttwsi_send_stop; + sc->sc_i2c.ic_initiate_xfer = gttwsi_initiate_xfer; + sc->sc_i2c.ic_read_byte = gttwsi_read_byte; + sc->sc_i2c.ic_write_byte = gttwsi_write_byte; + + /* + * Put the controller into Soft Reset. + */ + /* reset */ + gttwsi_write_4(sc, TWSI_SOFTRESET, SOFTRESET_VAL); + +} + +void +gttwsi_config_children(device_t self) +{ + struct gttwsi_softc * const sc = device_private(self); + struct i2cbus_attach_args iba; + + memset(&iba, 0, sizeof(iba)); + iba.iba_tag = &sc->sc_i2c; + + (void) config_found_ia(sc->sc_dev, "i2cbus", &iba, iicbus_print); +} + +int +gttwsi_intr(void *arg) +{ + struct gttwsi_softc *sc = arg; + uint32_t val; + + val = gttwsi_read_4(sc, TWSI_CONTROL); + if (val & CONTROL_IFLG) { + gttwsi_write_4(sc, TWSI_CONTROL, val & ~CONTROL_INTEN); + mutex_enter(&sc->sc_mtx); + cv_signal(&sc->sc_cv); + mutex_exit(&sc->sc_mtx); + + return 1; /* handled */ + } + return 0; +} + +/* ARGSUSED */ +static int +gttwsi_acquire_bus(void *arg, int flags) +{ + struct gttwsi_softc *sc = arg; + + mutex_enter(&sc->sc_buslock); + return 0; +} + +/* ARGSUSED */ +static void +gttwsi_release_bus(void *arg, int flags) +{ + struct gttwsi_softc *sc = arg; + + mutex_exit(&sc->sc_buslock); +} + +static 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 = true; + return gttwsi_wait(sc, CONTROL_START, expect, flags); +} + +static int +gttwsi_send_stop(void *v, int flags) +{ + struct gttwsi_softc *sc = v; + int retry = TWSI_RETRY_COUNT; + + sc->sc_started = false; + + /* Interrupt is not generated for STAT_NRS. */ + gttwsi_write_4(sc, TWSI_CONTROL, CONTROL_STOP | CONTROL_TWSIEN); + while (retry > 0) { + if (gttwsi_read_4(sc, TWSI_STATUS) == STAT_NRS) + return 0; + retry--; + DELAY(TWSI_STAT_DELAY); + } + + aprint_error_dev(sc->sc_dev, "send STOP failed\n"); + return -1; +} + +static int +gttwsi_initiate_xfer(void *v, i2c_addr_t addr, int flags) +{ + struct gttwsi_softc *sc = v; + uint32_t 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); +} + +static 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; +} + +static 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; +} + +static int +gttwsi_wait(struct gttwsi_softc *sc, uint32_t control, uint32_t expect, + int flags) +{ + uint32_t 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; + for (;;) { + control = gttwsi_read_4(sc, TWSI_CONTROL); + if (control & CONTROL_IFLG) + break; + if (!(flags & I2C_F_POLL)) { + mutex_enter(&sc->sc_mtx); + error = cv_timedwait_sig(&sc->sc_cv, &sc->sc_mtx, hz); + mutex_exit(&sc->sc_mtx); + if (error) + return error; + } + DELAY(TWSI_RETRY_DELAY); + if (timo++ > 1000000) /* 1sec */ + break; + } + + status = gttwsi_read_4(sc, TWSI_STATUS); + if (status != expect) { + aprint_error_dev(sc->sc_dev, + "unexpected status 0x%x: expect 0x%x\n", status, expect); + return EIO; + } + return error; +} Index: src/sys/dev/i2c/gttwsireg.h diff -u /dev/null src/sys/dev/i2c/gttwsireg.h:1.1 --- /dev/null Fri Sep 6 00:56:13 2013 +++ src/sys/dev/i2c/gttwsireg.h Fri Sep 6 00:56:12 2013 @@ -0,0 +1,80 @@ +/* $NetBSD: gttwsireg.h,v 1.1 2013/09/06 00:56:12 matt 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. + * + * 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. + */ +#ifndef _GTTWSIREG_H_ +#define _GTTWSIREG_H_ + +#define GTTWSI_SIZE 0x100 + +#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 + +#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 */ + +#endif /* _GTTWSIREG_H_ */ Index: src/sys/dev/i2c/gttwsivar.h diff -u /dev/null src/sys/dev/i2c/gttwsivar.h:1.1 --- /dev/null Fri Sep 6 00:56:13 2013 +++ src/sys/dev/i2c/gttwsivar.h Fri Sep 6 00:56:12 2013 @@ -0,0 +1,97 @@ +/* $NetBSD: gttwsivar.h,v 1.1 2013/09/06 00:56:12 matt 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/param.h> +#include <sys/bus.h> +#include <sys/condvar.h> +#include <sys/device.h> +#include <sys/errno.h> +#include <sys/kernel.h> +#include <sys/mutex.h> +#include <sys/systm.h> + +#include <dev/i2c/i2cvar.h> + +struct gttwsi_softc { + device_t sc_dev; + bus_space_tag_t sc_bust; + bus_space_handle_t sc_bush; + bool sc_started; + struct i2c_controller sc_i2c; + kmutex_t sc_buslock; + kmutex_t sc_mtx; + kcondvar_t sc_cv; +}; + +void gttwsi_attach_subr(device_t, bus_space_tag_t, bus_space_handle_t); +void gttwsi_config_children(device_t); + +int gttwsi_intr(void *); + +#endif /* _DEV_MARVELL_GTTSWI_VAR_H_ */