From owner-freebsd-embedded@FreeBSD.ORG Thu Dec 22 12:08:58 2011 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 5E27E106566B; Thu, 22 Dec 2011 12:08:58 +0000 (UTC) (envelope-from stb@lassitu.de) Received: from gilb.zs64.net (gilb.zs64.net [IPv6:2001:470:1f0b:105e::1ea]) by mx1.freebsd.org (Postfix) with ESMTP id 86F658FC13; Thu, 22 Dec 2011 12:08:57 +0000 (UTC) Received: by gilb.zs64.net (Postfix, from stb@lassitu.de) id 52AB147DAA; Thu, 22 Dec 2011 13:08:56 +0100 (CET) Mime-Version: 1.0 (Apple Message framework v1251.1) Content-Type: multipart/mixed; boundary="Apple-Mail=_80F6A1CE-E774-4603-B510-783FDD6677E0" From: Stefan Bethke In-Reply-To: <45529EC2-73BE-4F69-A9BE-E22D9FEAADD7@lassitu.de> Date: Thu, 22 Dec 2011 13:08:55 +0100 Message-Id: <7FDE5802-B680-464F-8765-9353D9DDD043@lassitu.de> References: <0F6CC18F-6973-42A2-AC03-F01BF59458AE@lassitu.de> <1100F70E-9DA9-4163-AC9A-423ECE5AA9A3@lassitu.de> <18CABB46-9B9A-41CB-8742-6723C5FF4D67@lassitu.de> <2CBD8651-E132-49DC-A082-37A8F5C626EA@bsdimp.com> <09670C34-0D30-46BC-BA7E-4AAA22193B61@lassitu.de> <45529EC2-73BE-4F69-A9BE-E22D9FEAADD7@lassitu.de> To: Adrian Chadd X-Mailer: Apple Mail (2.1251.1) Cc: Oleksandr Tymoshenko , "freebsd-embedded@freebsd.org" Subject: Re: Updated switch/glue patch? X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 22 Dec 2011 12:08:58 -0000 --Apple-Mail=_80F6A1CE-E774-4603-B510-783FDD6677E0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=windows-1252 Am 22.12.2011 um 12:55 schrieb Stefan Bethke: >=20 > Am 22.12.2011 um 06:41 schrieb Adrian Chadd: >=20 >> On 21 December 2011 07:13, Stefan Bethke wrote: >>=20 >>> I've replaced the generic PHY status poll with a custom one that = uses the switch registers instead of the PHYs. I've cloned your git and = have started adding my changes to it (branch also named work/ath): >>> http://gitorious.org/~stb/freebsd/stb-adrianchadd-freebsd-work >>>=20 >>> I tried a merge request, but gitorious didn't like it (at least at = the top level). >>=20 >> Cool! Can you please either figure out why that's the case, or just >> throw me some diffs? >=20 > It complains about the merge being too big to display in a browser? >=20 > Anyway, here's two diffs. I believe you can track my tree by adding = it to your local repository, and then merge it locally. That should be = easier and less error prone than applying diffs. >=20 >> We should figure out how to merge stuff back into your tree to mine >> (and then propagate the changes back to you) so we don't have to face >> this when the changes are bigger. >=20 > I'm tracking your tree and merging changes into mine. One option = could be to allow me write access to your repo and let me stuff my = changes into a branch there. >=20 >> After that's done, I'll work on you to tidy up the management = utility. >> Then we can start merging in whatever's needed from zrouter, and = start >> pushing this into -HEAD. I don't mind if it's a work in progress - at >> least something will be in the tree. >=20 > Cool! >=20 > I've got a WRT160NL here with an RTL8306S which I could write a driver = for. I started bringing FreeBSD up on that last night, but accidentally = overwrote half my uboot. Waiting for the JTAG adapter to ship=85 Updated and corrected patch: --Apple-Mail=_80F6A1CE-E774-4603-B510-783FDD6677E0 Content-Disposition: attachment; filename=iicbb.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="iicbb.patch" Content-Transfer-Encoding: 7bit diff --git a/sys/dev/iicbus/iicbb.c b/sys/dev/iicbus/iicbb.c index fed203c..cdb65e5 100644 --- a/sys/dev/iicbus/iicbb.c +++ b/sys/dev/iicbus/iicbb.c @@ -25,7 +25,7 @@ */ #include -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/iicbus/iicbb.c 188461 2009-02-10 22:50:23Z imp $"); /* * Generic I2C bit-banging code @@ -48,9 +48,9 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include - #include #include @@ -59,9 +59,31 @@ __FBSDID("$FreeBSD$"); #include "iicbus_if.h" #include "iicbb_if.h" +#define IIC_DELAY_100KHZ 3 /* 3 microseconds per quarter cycle, should be 2.5 */ + +#if defined(DEBUG) +static int i2c_debug = 0; +#define I2C_DEBUG(x) \ + do { \ + if (i2c_debug) (x); \ + } while (0) + +#define I2C_LOG(args...) \ + do { \ + if (i2c_debug) printf(args); \ + } while (0) +static SYSCTL_NODE(_debug, OID_AUTO, iicbb, CTLFLAG_RD, 0, "iicbb"); +SYSCTL_INT(_debug_iicbb, OID_AUTO, debug, CTLFLAG_RW, &i2c_debug, 0, + "print bus transactions"); +#else +#define I2C_DEBUG(x) +#define I2C_LOG(args...) +#endif + struct iicbb_softc { device_t iicbus; - int udelay; /* signal toggle delay in usec */ + int iicdelay; + int iictimeout; }; static int iicbb_attach(device_t); @@ -126,11 +148,11 @@ iicbb_attach(device_t dev) if (!sc->iicbus) return (ENXIO); - sc->udelay = 10; /* 10 uS default */ + sc->iicdelay = IIC_DELAY_100KHZ; if (resource_int_value(device_get_name(dev), device_get_unit(dev), "udelay", &udelay) == 0) - sc->udelay = udelay; - device_printf(dev, "udelay=%d microseconds\n", sc->udelay); + sc->iicdelay = udelay; + device_printf(dev, "udelay=%d microseconds\n", sc->iicdelay); bus_generic_attach(dev); @@ -193,149 +215,191 @@ iicbb_print_child(device_t bus, device_t dev) return (retval); } -#define I2C_SETSDA(sc,dev,val) do { \ - IICBB_SETSDA(device_get_parent(dev), val); \ - DELAY(sc->udelay); \ - } while (0) -#define I2C_SETSCL(dev,val) do { \ - iicbb_setscl(dev, val, 100); \ - } while (0) - -#define I2C_SET(sc,dev,ctrl,data) do { \ - I2C_SETSCL(dev, ctrl); \ - I2C_SETSDA(sc, dev, data); \ - } while (0) - -#define I2C_GETSDA(dev) (IICBB_GETSDA(device_get_parent(dev))) - -#define I2C_GETSCL(dev) (IICBB_GETSCL(device_get_parent(dev))) - -static int i2c_debug = 0; -#define I2C_DEBUG(x) do { \ - if (i2c_debug) (x); \ - } while (0) - -#define I2C_LOG(format,args...) do { \ - printf(format, args); \ - } while (0) +/* + * Low-level bus state functions. The following functions implement the + * basic bus states for I2C. We divide the full clock cycle into four + * phases. Transitions of SCL and SDA occur between these phases. The + * nominal duration of each phase is 100 kHz/4, or 2.5 us. Implementations + * for busses and devices can choose a lower delay for faster operation. + * + * Each of the functions returns -1 if the operation could not be completed. + */ -static void -iicbb_setscl(device_t dev, int val, int timeout) +/* + * I2C start (S) and repeated start (Sr) condition + * 0 1 2 3 + * __.__ + * SCL XXXX \__. + * __ + * SDA XXXX \__.__. + * + */ +static __inline int +i2c_start(device_t dev) { - struct iicbb_softc *sc = device_get_softc(dev); - int k = 0; - - IICBB_SETSCL(device_get_parent(dev), val); - DELAY(sc->udelay); - - while (val && !I2C_GETSCL(dev) && k++ < timeout) { - IICBB_SETSCL(device_get_parent(dev), val); - DELAY(sc->udelay); + struct iicbb_softc *sc = (struct iicbb_softc *)device_get_softc(dev); + int timeout = sc->iictimeout; + + /* 0 */ + IICBB_SETSDA(device_get_parent(dev), 1); + IICBB_SETSCL(device_get_parent(dev), 1); + /* wait for the bus to become idle */ + while(1) { + DELAY(sc->iicdelay); + if (IICBB_GETSDA(device_get_parent(dev)) != 0 && + IICBB_GETSCL(device_get_parent(dev)) != 0) + break; + if (timeout <= 0) + return (-1); + timeout -= sc->iicdelay; } - - return; + /* 1 */ + DELAY(sc->iicdelay); + /* 2 */ + IICBB_SETSDA(device_get_parent(dev), 0); + DELAY(sc->iicdelay); + /* 3 */ + IICBB_SETSCL(device_get_parent(dev), 0); + DELAY(sc->iicdelay); + return (0); } -static void -iicbb_one(device_t dev, int timeout) +/* + * I2C stop (P) condition + * 0 1 2 3 + * __.__.__. + * SCL .__/ + * _____. + * SDA XXXX__/ + */ +static __inline int +i2c_stop(device_t dev) { - struct iicbb_softc *sc = device_get_softc(dev); + struct iicbb_softc *sc = (struct iicbb_softc *)device_get_softc(dev); - I2C_SET(sc,dev,0,1); - I2C_SET(sc,dev,1,1); - I2C_SET(sc,dev,0,1); - return; + /* 0 */ + IICBB_SETSDA(device_get_parent(dev), 0); + DELAY(sc->iicdelay); + /* 1 */ + IICBB_SETSCL(device_get_parent(dev), 1); + DELAY(sc->iicdelay); + /* 2 */ + IICBB_SETSDA(device_get_parent(dev), 1); + DELAY(sc->iicdelay); + /* + * we can skip the last delay since the bus will either be idle, + * or the next S will wait long enough to keep the timing correct. + */ + return (0); } -static void -iicbb_zero(device_t dev, int timeout) +/* + * I2C transmit one bit + * 0 1 2 3 + * __.__ + * SCL .__/ \__. + * __.__ + * SDA .XXX__.__XXX. + */ +static __inline int +i2c_xmitbit(device_t dev, int value) { - struct iicbb_softc *sc = device_get_softc(dev); - - I2C_SET(sc,dev,0,0); - I2C_SET(sc,dev,1,0); - I2C_SET(sc,dev,0,0); - return; + struct iicbb_softc *sc = (struct iicbb_softc *)device_get_softc(dev); + int timeout = sc->iictimeout; + + /* 0 */ + IICBB_SETSDA(device_get_parent(dev), value); + DELAY(sc->iicdelay); + /* 1 */ + IICBB_SETSCL(device_get_parent(dev), 1); + while (1) { + DELAY(sc->iicdelay); + if (IICBB_GETSCL(device_get_parent(dev)) != 0) + break; + if (timeout <= 0) + return (-1); + timeout -= sc->iicdelay; + } + /* 2 */ + if (value != 0 && IICBB_GETSDA(device_get_parent(dev)) == 0) + return (-1); /* another master is pulling down SDA */ + DELAY(sc->iicdelay); + /* 3 */ + IICBB_SETSCL(device_get_parent(dev), 0); + DELAY(sc->iicdelay); + return (0); } /* - * Waiting for ACKNOWLEDGE. - * - * When a chip is being addressed or has received data it will issue an - * ACKNOWLEDGE pulse. Therefore the MASTER must release the DATA line - * (set it to high level) and then release the CLOCK line. - * Now it must wait for the SLAVE to pull the DATA line low. - * Actually on the bus this looks like a START condition so nothing happens - * because of the fact that the IC's that have not been addressed are doing - * nothing. - * - * When the SLAVE has pulled this line low the MASTER will take the CLOCK - * line low and then the SLAVE will release the SDA (data) line. + * I2C receive one bit + * 0 1 2 3 + * __.__ + * SCL .__/ \__. + * __.__ + * SDA .XXX__.__XXX. */ -static int -iicbb_ack(device_t dev, int timeout) +static __inline int +i2c_recvbit(device_t dev) { - struct iicbb_softc *sc = device_get_softc(dev); - int noack; - int k = 0; - - I2C_SET(sc,dev,0,1); - I2C_SET(sc,dev,1,1); - do { - noack = I2C_GETSDA(dev); - if (!noack) + struct iicbb_softc *sc = (struct iicbb_softc *)device_get_softc(dev); + int timeout = sc->iictimeout; + int value; + + /* 0 */ + IICBB_SETSDA(device_get_parent(dev), 1); + DELAY(sc->iicdelay); + IICBB_SETSCL(device_get_parent(dev), 1); + while (1) { + DELAY(sc->iicdelay); + if (IICBB_GETSCL(device_get_parent(dev)) != 0) break; - DELAY(1); - k++; - } while (k < timeout); - - I2C_SET(sc,dev,0,1); - I2C_DEBUG(printf("%c ",noack?'-':'+')); - - return (noack); + if (timeout <= 0) + return (-1); + timeout -= sc->iicdelay; + } + value = IICBB_GETSDA(device_get_parent(dev)); + DELAY(sc->iicdelay); + IICBB_SETSCL(device_get_parent(dev), 0); + DELAY(sc->iicdelay); + return (value != 0 ? 1 : 0); } -static void -iicbb_sendbyte(device_t dev, u_char data, int timeout) +/* + * Transmit a byte. Returns -1 on error. + */ +static int +i2c_xmitbyte(device_t dev, int value) { - int i; - - for (i=7; i>=0; i--) { - if (data&(1<= 0; i--) { + error = i2c_xmitbit(dev, (value >> i) & 0x01); + if (error < 0) + return (error); } - I2C_DEBUG(printf("w%02x",(int)data)); - return; + return (error); } -static u_char -iicbb_readbyte(device_t dev, int last, int timeout) +/* + * Receive a byte. Returns the byte value (0..255), or -1 on error. + */ +static int +i2c_recvbyte(device_t dev) { - struct iicbb_softc *sc = device_get_softc(dev); - int i; - unsigned char data=0; - - I2C_SET(sc,dev,0,1); - for (i=7; i>=0; i--) - { - I2C_SET(sc,dev,1,1); - if (I2C_GETSDA(dev)) - data |= (1<= 0; i--) { + error = i2c_recvbit(dev); + if (error < 0) + return (error); + value |= error << i; } - I2C_DEBUG(printf("r%02x%c ",(int)data,last?'-':'+')); - return data; + return (value); } + static int iicbb_callback(device_t dev, int index, caddr_t data) { @@ -351,61 +415,53 @@ iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) static int iicbb_start(device_t dev, u_char slave, int timeout) { - struct iicbb_softc *sc = device_get_softc(dev); int error; + struct iicbb_softc *sc = (struct iicbb_softc *)device_get_softc(dev); - I2C_DEBUG(printf("<")); - - I2C_SET(sc,dev,1,1); - I2C_SET(sc,dev,1,0); - I2C_SET(sc,dev,0,0); - - /* send address */ - iicbb_sendbyte(dev, slave, timeout); - - /* check for ack */ - if (iicbb_ack(dev, timeout)) { - error = IIC_ENOACK; - goto error; - } - - return(0); - -error: - iicbb_stop(dev); - return (error); + I2C_LOG("<"); + + sc->iictimeout = timeout; + if (i2c_start(dev) < 0) + return (IIC_ENOACK); + error = i2c_xmitbyte(dev, slave); + if (error < 0) + return (IIC_EBUSERR); /* lost arbitration */ + I2C_LOG("%02x", slave); + error = i2c_recvbit(dev); + if (error < 0) + return (IIC_EBUSERR); /* lost arbitration */ + I2C_LOG("%c", error != 0 ? '-' : '+'); + return(error != 0 ? IIC_ENOACK : 0); } static int iicbb_stop(device_t dev) { - struct iicbb_softc *sc = device_get_softc(dev); - - I2C_SET(sc,dev,0,0); - I2C_SET(sc,dev,1,0); - I2C_SET(sc,dev,1,1); - I2C_DEBUG(printf(">")); - I2C_DEBUG(printf("\n")); + i2c_stop(dev); + I2C_LOG(">\n"); return (0); } static int iicbb_write(device_t dev, const char *buf, int len, int *sent, int timeout) { - int bytes, error = 0; + int bytes, ack, error = 0; + I2C_LOG(" W%d:", len); bytes = 0; while (len) { - /* send byte */ - iicbb_sendbyte(dev,(u_char)*buf++, timeout); - - /* check for ack */ - if (iicbb_ack(dev, timeout)) { + I2C_LOG(" %02x", (u_char)*buf); + i2c_xmitbyte(dev,(u_char)*buf++); + ack = i2c_recvbit(dev); + if (ack < 0) + return (IIC_EBUSERR); + I2C_LOG("%c", ack != 0 ? '-' : '+'); + if (len != 1 && ack != 0) { error = IIC_ENOACK; goto error; } - bytes ++; - len --; + bytes++; + len--; } error: @@ -416,19 +472,31 @@ error: static int iicbb_read(device_t dev, char * buf, int len, int *read, int last, int delay) { - int bytes; + int bytes, value, error = 0; + I2C_LOG(" R%d:", len); bytes = 0; while (len) { - /* XXX should insert delay here */ - *buf++ = (char)iicbb_readbyte(dev, (len == 1) ? last : 0, delay); - - bytes ++; - len --; + value = i2c_recvbyte(dev); + if (value < 0) { + error = IIC_EBUSERR; + goto error; + } + I2C_LOG(" %02x", value); + error = i2c_xmitbit(dev, len == 1 && last ? 1 : 0); + if (value < 0) { + error = IIC_EBUSERR; + goto error; + } + I2C_LOG("%c", len == 1 && last ? '-' : '+'); + *buf++ = value; + bytes++; + len--; } +error: *read = bytes; - return (0); + return (error); } DRIVER_MODULE(iicbus, iicbb, iicbus_driver, iicbus_devclass, 0, 0); --Apple-Mail=_80F6A1CE-E774-4603-B510-783FDD6677E0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=iso-8859-1 -- Stefan Bethke Fon +49 151 14070811 --Apple-Mail=_80F6A1CE-E774-4603-B510-783FDD6677E0--