diff options
author | nsouch <nsouch@FreeBSD.org> | 2002-03-23 15:49:15 +0000 |
---|---|---|
committer | nsouch <nsouch@FreeBSD.org> | 2002-03-23 15:49:15 +0000 |
commit | 82395b7295123f4d9a786ebd89495ef101103a61 (patch) | |
tree | f78e24d69b8d02162ae886a610fb85cac8989741 /sys/dev/iicbus/iicbb.c | |
parent | 0dcefe7b55beecbfaeba7c0b20e4b1277b781733 (diff) | |
download | FreeBSD-src-82395b7295123f4d9a786ebd89495ef101103a61.zip FreeBSD-src-82395b7295123f4d9a786ebd89495ef101103a61.tar.gz |
Major rework of the iicbus/smbus framework:
- VIA chipset SMBus controllers added
- alpm driver updated
- Support for dynamic modules added
- bktr FreeBSD smbus updated but not tested
- cleanup
Diffstat (limited to 'sys/dev/iicbus/iicbb.c')
-rw-r--r-- | sys/dev/iicbus/iicbb.c | 126 |
1 files changed, 98 insertions, 28 deletions
diff --git a/sys/dev/iicbus/iicbb.c b/sys/dev/iicbus/iicbb.c index 56bc390..436626c 100644 --- a/sys/dev/iicbus/iicbb.c +++ b/sys/dev/iicbus/iicbb.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 Nicolas Souchu + * Copyright (c) 1998, 2001 Nicolas Souchu * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,7 +41,6 @@ * From Linux I2C generic interface * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> * - * TODO: port Peter's generic bit-banging code <dufault@hda.com> */ #include <sys/param.h> @@ -61,11 +60,12 @@ #include "iicbb_if.h" struct iicbb_softc { - int dummy; + device_t iicbus; }; static int iicbb_probe(device_t); static int iicbb_attach(device_t); +static int iicbb_detach(device_t); static int iicbb_print_child(device_t, device_t); static int iicbb_callback(device_t, int, caddr_t); @@ -79,7 +79,7 @@ static device_method_t iicbb_methods[] = { /* device interface */ DEVMETHOD(device_probe, iicbb_probe), DEVMETHOD(device_attach, iicbb_attach), - DEVMETHOD(device_detach, bus_generic_detach), + DEVMETHOD(device_detach, iicbb_detach), /* bus interface */ DEVMETHOD(bus_print_child, iicbb_print_child), @@ -106,13 +106,36 @@ static devclass_t iicbb_devclass; static int iicbb_probe(device_t dev) { - device_set_desc(dev, "I2C generic bit-banging driver"); + device_set_desc(dev, "I2C bit-banging driver"); return (0); } static int iicbb_attach(device_t dev) { + struct iicbb_softc *sc = (struct iicbb_softc *)device_get_softc(dev); + + bzero(sc, sizeof(struct iicbb_softc)); + + sc->iicbus = device_add_child(dev, "iicbus", -1); + + if (!sc->iicbus) + return (ENXIO); + + bus_generic_attach(dev); + + return (0); +} + +static int iicbb_detach(device_t dev) +{ + struct iicbb_softc *sc = (struct iicbb_softc *)device_get_softc(dev); + + if (sc->iicbus) { + bus_generic_detach(dev); + device_delete_child(dev, sc->iicbus); + } + return (0); } @@ -140,15 +163,51 @@ iicbb_print_child(device_t bus, device_t dev) return (retval); } -#define I2C_SET(dev,ctrl,data) \ - IICBB_SETLINES(device_get_parent(dev), ctrl, data) +#define IIC_DELAY 10 + +#define I2C_SETSDA(dev,val) do { \ + IICBB_SETSDA(device_get_parent(dev), val); \ + DELAY(IIC_DELAY); \ + } while (0) + +#define I2C_SETSCL(dev,val) do { \ + iicbb_setscl(dev, val, 100); \ + } while (0) + +#define I2C_SET(dev,ctrl,data) do { \ + I2C_SETSCL(dev, ctrl); \ + I2C_SETSDA(dev, data); \ + } while (0) + +#define I2C_GETSDA(dev) (IICBB_GETSDA(device_get_parent(dev))) -#define I2C_GET(dev) (IICBB_GETDATALINE(device_get_parent(dev))) +#define I2C_GETSCL(dev) (IICBB_GETSCL(device_get_parent(dev))) static int i2c_debug = 0; -#define I2C_DEBUG(x) if (i2c_debug) (x) +#define I2C_DEBUG(x) do { \ + if (i2c_debug) (x); \ + } while (0) -static void iicbb_one(device_t dev) +#define I2C_LOG(format,args...) do { \ + printf(format, args); \ + } while (0) + +static void iicbb_setscl(device_t dev, int val, int timeout) +{ + int k = 0; + + IICBB_SETSCL(device_get_parent(dev), val); + DELAY(IIC_DELAY); + + while (val && !I2C_GETSCL(dev) && k++ < timeout) { + IICBB_SETSCL(device_get_parent(dev), val); + DELAY(IIC_DELAY); + } + + return; +} + +static void iicbb_one(device_t dev, int timeout) { I2C_SET(dev,0,1); I2C_SET(dev,1,1); @@ -156,7 +215,7 @@ static void iicbb_one(device_t dev) return; } -static void iicbb_zero(device_t dev) +static void iicbb_zero(device_t dev, int timeout) { I2C_SET(dev,0,0); I2C_SET(dev,1,0); @@ -181,17 +240,17 @@ static void iicbb_zero(device_t dev) static int iicbb_ack(device_t dev, int timeout) { int noack; - int k = timeout/10; + int k = 0; I2C_SET(dev,0,1); I2C_SET(dev,1,1); - do { - noack = I2C_GET(dev); + noack = I2C_GETSDA(dev); if (!noack) break; - DELAY(10); /* XXX wait 10us */ - } while (k--); + DELAY(10); + k += 10; + } while (k < timeout); I2C_SET(dev,0,1); I2C_DEBUG(printf("%c ",noack?'-':'+')); @@ -199,18 +258,22 @@ static int iicbb_ack(device_t dev, int timeout) return (noack); } -static void iicbb_sendbyte(device_t dev, u_char data) +static void iicbb_sendbyte(device_t dev, u_char data, int timeout) { int i; - I2C_SET(dev,0,0); - for (i=7; i>=0; i--) - (data&(1<<i)) ? iicbb_one(dev) : iicbb_zero(dev); + for (i=7; i>=0; i--) { + if (data&(1<<i)) { + iicbb_one(dev, timeout); + } else { + iicbb_zero(dev, timeout); + } + } I2C_DEBUG(printf("w%02x",(int)data)); return; } -static u_char iicbb_readbyte(device_t dev, int last) +static u_char iicbb_readbyte(device_t dev, int last, int timeout) { int i; unsigned char data=0; @@ -219,11 +282,15 @@ static u_char iicbb_readbyte(device_t dev, int last) for (i=7; i>=0; i--) { I2C_SET(dev,1,1); - if (I2C_GET(dev)) + if (I2C_GETSDA(dev)) data |= (1<<i); I2C_SET(dev,0,1); } - last ? iicbb_one(dev) : iicbb_zero(dev); + if (last) { + iicbb_one(dev, timeout); + } else { + iicbb_zero(dev, timeout); + } I2C_DEBUG(printf("r%02x%c ",(int)data,last?'-':'+')); return data; } @@ -244,13 +311,12 @@ static int iicbb_start(device_t dev, u_char slave, int timeout) I2C_DEBUG(printf("<")); - I2C_SET(dev,0,1); I2C_SET(dev,1,1); I2C_SET(dev,1,0); I2C_SET(dev,0,0); /* send address */ - iicbb_sendbyte(dev, slave); + iicbb_sendbyte(dev, slave, timeout); /* check for ack */ if (iicbb_ack(dev, timeout)) { @@ -282,7 +348,7 @@ static int iicbb_write(device_t dev, char * buf, int len, int *sent, bytes = 0; while (len) { /* send byte */ - iicbb_sendbyte(dev,(u_char)*buf++); + iicbb_sendbyte(dev,(u_char)*buf++, timeout); /* check for ack */ if (iicbb_ack(dev, timeout)) { @@ -306,7 +372,7 @@ static int iicbb_read(device_t dev, char * buf, int len, int *read, bytes = 0; while (len) { /* XXX should insert delay here */ - *buf++ = (char)iicbb_readbyte(dev, (len == 1) ? last : 0); + *buf++ = (char)iicbb_readbyte(dev, (len == 1) ? last : 0, delay); bytes ++; len --; @@ -316,5 +382,9 @@ static int iicbb_read(device_t dev, char * buf, int len, int *read, return (0); } -DRIVER_MODULE(iicbb, bti2c, iicbb_driver, iicbb_devclass, 0, 0); +DRIVER_MODULE(iicbb, bktr, iicbb_driver, iicbb_devclass, 0, 0); DRIVER_MODULE(iicbb, lpbb, iicbb_driver, iicbb_devclass, 0, 0); +DRIVER_MODULE(iicbb, viapm, iicbb_driver, iicbb_devclass, 0, 0); + +MODULE_DEPEND(iicbb, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); +MODULE_VERSION(iicbb, IICBB_MODVER); |