From a8f721865de13fdf796dd7a371aed217c14710fa Mon Sep 17 00:00:00 2001 From: nsouch Date: Sat, 31 Oct 1998 11:31:07 +0000 Subject: iicbb is generic support for I2C bit-banging. Other files: timeout management added to the I2C framework. --- sys/dev/iicbus/if_ic.c | 4 +- sys/dev/iicbus/iic.c | 6 +- sys/dev/iicbus/iicbb.c | 323 +++++++++++++++++++++++++++++++++++++++++++++ sys/dev/iicbus/iicbb_if.m | 65 +++++++++ sys/dev/iicbus/iicbus.c | 127 +++++++++++++----- sys/dev/iicbus/iicbus.h | 3 +- sys/dev/iicbus/iicbus_if.m | 20 ++- sys/dev/iicbus/iiconf.c | 73 ++++++---- sys/dev/iicbus/iiconf.h | 36 +++-- sys/dev/iicbus/iicsmb.c | 128 ++++++++++++------ 10 files changed, 665 insertions(+), 120 deletions(-) create mode 100644 sys/dev/iicbus/iicbb.c create mode 100644 sys/dev/iicbus/iicbb_if.m (limited to 'sys/dev/iicbus') diff --git a/sys/dev/iicbus/if_ic.c b/sys/dev/iicbus/if_ic.c index 52626e0..540b07f 100644 --- a/sys/dev/iicbus/if_ic.c +++ b/sys/dev/iicbus/if_ic.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: if_ic.c,v 1.1.1.11 1998/08/13 17:10:42 son Exp $ + * $Id: if_ic.c,v 1.1.1.1 1998/09/03 20:51:50 nsouch Exp $ */ /* @@ -213,7 +213,7 @@ icioctl(struct ifnet *ifp, u_long cmd, caddr_t data) return ENOBUFS; } - iicbus_reset(parent, IIC_FASTEST); + iicbus_reset(parent, IIC_FASTEST, 0, NULL); ifp->if_flags |= IFF_RUNNING; } diff --git a/sys/dev/iicbus/iic.c b/sys/dev/iicbus/iic.c index 45d551b..ccebb5b 100644 --- a/sys/dev/iicbus/iic.c +++ b/sys/dev/iicbus/iic.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: iic.c,v 1.2 1998/09/04 17:53:35 nsouch Exp $ + * $Id: iic.c,v 1.3 1998/09/09 18:57:24 nsouch Exp $ * */ #include @@ -219,7 +219,7 @@ iicioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) switch (cmd) { case I2CSTART: - error = iicbus_start(parent, sc->sc_addr); + error = iicbus_start(parent, sc->sc_addr, 0); break; case I2CSTOP: @@ -227,7 +227,7 @@ iicioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) break; case I2CRSTCARD: - error = iicbus_reset(parent, 0); + error = iicbus_reset(parent, 0, 0, NULL); break; default: diff --git a/sys/dev/iicbus/iicbb.c b/sys/dev/iicbus/iicbb.c new file mode 100644 index 0000000..f544d4b --- /dev/null +++ b/sys/dev/iicbus/iicbb.c @@ -0,0 +1,323 @@ +/*- + * Copyright (c) 1998 Nicolas Souchu + * 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 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 AUTHOR 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. + * + * $Id$ + * + */ + +/* + * Generic I2C bit-banging code + * + * Example: + * + * iicbus + * / \ + * iicbb pcf + * | \ + * bti2c lpbb + * + * From Linux I2C generic interface + * (c) 1998 Gerd Knorr + * + * TODO: port Peter's generic bit-banging code + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include "iicbus_if.h" +#include "iicbb_if.h" + +struct iicbb_softc { + int dummy; +}; + +static int iicbb_probe(device_t); +static int iicbb_attach(device_t); +static void iicbb_print_child(device_t, device_t); + +static int iicbb_callback(device_t, int, caddr_t); +static int iicbb_start(device_t, u_char, int); +static int iicbb_stop(device_t); +static int iicbb_write(device_t, char *, int, int *, int); +static int iicbb_read(device_t, char *, int, int *, int, int); +static int iicbb_reset(device_t, u_char, u_char, u_char *); + +static device_method_t iicbb_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, iicbb_probe), + DEVMETHOD(device_attach, iicbb_attach), + + /* bus interface */ + DEVMETHOD(bus_print_child, iicbb_print_child), + + /* iicbus interface */ + DEVMETHOD(iicbus_callback, iicbb_callback), + DEVMETHOD(iicbus_start, iicbb_start), + DEVMETHOD(iicbus_repeated_start, iicbb_start), + DEVMETHOD(iicbus_stop, iicbb_stop), + DEVMETHOD(iicbus_write, iicbb_write), + DEVMETHOD(iicbus_read, iicbb_read), + DEVMETHOD(iicbus_reset, iicbb_reset), + + { 0, 0 } +}; + +static driver_t iicbb_driver = { + "iicbb", + iicbb_methods, + DRIVER_TYPE_MISC, + sizeof(struct iicbb_softc), +}; + +static devclass_t iicbb_devclass; + +static int iicbb_probe(device_t dev) +{ + device_set_desc(dev, "I2C generic bit-banging driver"); + + return (0); +} + +static int iicbb_attach(device_t dev) +{ + return (0); +} + +static void +iicbb_print_child(device_t bus, device_t dev) +{ + int error; + u_char oldaddr; + + /* retrieve the interface I2C address */ + error = IICBB_RESET(bus, IIC_FASTEST, 0, &oldaddr); + if (error == IIC_ENOADDR) { + printf(" on %s%d master-only", device_get_name(bus), + device_get_unit(bus)); + + } else { + /* restore the address */ + IICBB_RESET(bus, IIC_FASTEST, oldaddr, NULL); + + printf(" on %s%d addr 0x%x", device_get_name(bus), + device_get_unit(bus), oldaddr & 0xff); + } + + return; +} + +#define I2C_SET(dev,ctrl,data) \ + IICBB_SETLINES(device_get_parent(dev), ctrl, data) + +#define I2C_GET(dev) (IICBB_GETDATALINE(device_get_parent(dev))) + +static int i2c_debug = 0; +#define I2C_DEBUG(x) if (i2c_debug) (x) + +static void iicbb_one(device_t dev) +{ + I2C_SET(dev,0,1); + I2C_SET(dev,1,1); + I2C_SET(dev,0,1); + return; +} + +static void iicbb_zero(device_t dev) +{ + I2C_SET(dev,0,0); + I2C_SET(dev,1,0); + I2C_SET(dev,0,0); + return; +} + +/* + * 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. + */ +static int iicbb_ack(device_t dev, int timeout) +{ + int noack; + int k = timeout/10; + + I2C_SET(dev,0,1); + I2C_SET(dev,1,1); + + do { + noack = I2C_GET(dev); + if (!noack) + break; + DELAY(10); /* XXX wait 10us */ + } while (k--); + + I2C_SET(dev,0,1); + I2C_DEBUG(printf("%c ",noack?'-':'+')); + + return (noack); +} + +static void iicbb_sendbyte(device_t dev, u_char data) +{ + int i; + + I2C_SET(dev,0,0); + for (i=7; i>=0; i--) + (data&(1<=0; i--) + { + I2C_SET(dev,1,1); + if (I2C_GET(dev)) + data |= (1<")); + return (0); +} + +static int iicbb_write(device_t dev, char * buf, int len, int *sent, + int timeout) +{ + int bytes, error = 0; + + bytes = 0; + while (len) { + /* send byte */ + iicbb_sendbyte(dev,(u_char)*buf++); + + /* check for ack */ + if (iicbb_ack(dev, timeout)) { + error = IIC_ENOACK; + goto error; + } + bytes ++; + len --; + } + +error: + *sent = bytes; + return (error); +} + +static int iicbb_read(device_t dev, char * buf, int len, int *read, + int last, int delay) +{ + int bytes; + + bytes = 0; + while (len) { + /* XXX should insert delay here */ + *buf++ = (char)iicbb_readbyte(dev, (len == 1) ? 1 : 0); + + bytes ++; + len --; + } + + *read = bytes; + return (0); +} + +DRIVER_MODULE(iicbb, bti2c, iicbb_driver, iicbb_devclass, 0, 0); +DRIVER_MODULE(iicbb, lpbb, iicbb_driver, iicbb_devclass, 0, 0); diff --git a/sys/dev/iicbus/iicbb_if.m b/sys/dev/iicbus/iicbb_if.m new file mode 100644 index 0000000..b5565b3 --- /dev/null +++ b/sys/dev/iicbus/iicbb_if.m @@ -0,0 +1,65 @@ +# +# Copyright (c) 1998 Nicolas Souchu +# 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 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 AUTHOR 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. +# +# $Id$ +# + +INTERFACE iicbb + +# +# iicbus callback +# +METHOD int callback { + device_t dev; + int index; + caddr_t data; +}; + +# +# Set I2C bus lines +# +METHOD void setlines { + device_t dev; + int ctrl; + int data; +}; + +# +# Get I2C bus lines +# +# +METHOD int getdataline { + device_t dev; +}; + +# +# Reset interface +# +METHOD int reset { + device_t dev; + u_char speed; + u_char addr; + u_char *oldaddr; +}; diff --git a/sys/dev/iicbus/iicbus.c b/sys/dev/iicbus/iicbus.c index 41a0cea..930858f 100644 --- a/sys/dev/iicbus/iicbus.c +++ b/sys/dev/iicbus/iicbus.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: iicbus.c,v 1.1.2.7 1998/08/29 16:54:16 son Exp $ + * $Id: iicbus.c,v 1.1.1.1 1998/09/03 20:51:50 nsouch Exp $ * */ @@ -54,6 +54,7 @@ struct iicbus_device { int iicd_class; /* driver or slave device class */ const char *iicd_desc; /* device descriptor */ u_char iicd_addr; /* address of the device */ + int iicd_waitack; /* wait for ack timeout or delay */ int iicd_alive; /* 1 if device found */ }; @@ -61,8 +62,8 @@ struct iicbus_device { * Common I2C addresses */ #define I2C_GENERAL_CALL 0x0 -#define I2C_MASTER_ADDRESS 0xaa -#define I2C_INET_ADDRESS 0xaa +#define PCF_MASTER_ADDRESS 0xaa +#define FIRST_SLAVE_ADDR 0x2 #define MAXSLAVE 256 @@ -74,11 +75,13 @@ struct iicbus_device { * list of known devices */ struct iicbus_device iicbus_children[] = { - { "iic", IICBUS_DRIVER_CLASS, "General Call", I2C_GENERAL_CALL }, { "iicsmb", IICBUS_DRIVER_CLASS, "I2C to SMB bridge" }, { "iic", IICBUS_DEVICE_CLASS, "PCF8574 I2C to 8 bits parallel i/o", 64}, - { "iic", IICBUS_DEVICE_CLASS, "PCF8584 as slave", I2C_MASTER_ADDRESS }, - { "ic", IICBUS_DEVICE_CLASS, "network interface", I2C_INET_ADDRESS }, + { "iic", IICBUS_DEVICE_CLASS, "PCF8584 as slave", PCF_MASTER_ADDRESS }, + { "ic", IICBUS_DEVICE_CLASS, "network interface", PCF_MASTER_ADDRESS }, +#if 0 + { "iic", IICBUS_DRIVER_CLASS, "General Call", I2C_GENERAL_CALL }, +#endif { NULL, 0 } }; @@ -91,6 +94,7 @@ static int iicbus_probe(device_t); static int iicbus_attach(device_t); static void iicbus_print_child(device_t, device_t); static int iicbus_read_ivar(device_t , device_t, int, u_long *); +static int iicbus_write_ivar(device_t , device_t, int, u_long); static device_method_t iicbus_methods[] = { /* device interface */ @@ -102,7 +106,7 @@ static device_method_t iicbus_methods[] = { /* bus interface */ DEVMETHOD(bus_print_child, iicbus_print_child), DEVMETHOD(bus_read_ivar, iicbus_read_ivar), - DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), + DEVMETHOD(bus_write_ivar, iicbus_write_ivar), DEVMETHOD(bus_create_intr, bus_generic_create_intr), DEVMETHOD(bus_connect_intr, bus_generic_connect_intr), @@ -116,50 +120,85 @@ static driver_t iicbus_driver = { sizeof(struct iicbus_softc), }; +static int +iicbus_probe(device_t dev) +{ + /* always present if probed */ + return (0); +} + +#define MAXADDR 256 +static int iicdev_found[MAXADDR]; + +static int +iic_probe_device(device_t dev, u_char addr) +{ + int count; + char byte; + + if ((addr & 1) == 0) { + /* is device writable? */ + if (!iicbus_start(dev, (u_char)addr, 0)) { + iicbus_stop(dev); + return (1); + } + } else { + /* is device readable? */ + if (!iicbus_block_read(dev, (u_char)addr, &byte, 1, &count)) + return (1); + } + + return (0); +} + /* - * At 'probe' time, we add all the devices which we know about to the - * bus. The generic attach routine will probe and attach them if they - * are alive. + * We add all the devices which we know about. + * The generic attach routine will attach them if they are alive. */ static int -iicbus_probe(device_t dev) +iicbus_attach(device_t dev) { struct iicbus_softc *sc = device_get_softc(dev); struct iicbus_device *iicdev; device_t child; + int addr, count; + char byte; - /* XXX should query parent */ - sc->ownaddr = I2C_MASTER_ADDRESS; + iicbus_reset(dev, IIC_FASTEST, 0, NULL); - iicbus_reset(dev, IIC_FASTEST); + printf("Probing for devices on iicbus%d:", device_get_unit(dev)); - for (iicdev = iicbus_children; iicdev->iicd_name; iicdev++) { + /* probe any devices */ + for (addr = FIRST_SLAVE_ADDR; addr < MAXADDR; addr++) { + if (iic_probe_device(dev, (u_char)addr)) { + printf(" <%x>", addr); + } + } + printf("\n"); + /* attach known devices */ + for (iicdev = iicbus_children; iicdev->iicd_name; iicdev++) { /* probe devices, not drivers */ switch (iicdev->iicd_class) { case IICBUS_DEVICE_CLASS: - if (!iicbus_start(dev, iicdev->iicd_addr)) { - iicbus_stop(dev); + if (iic_probe_device(dev, iicdev->iicd_addr)) iicdev->iicd_alive = 1; - } break; + case IICBUS_DRIVER_CLASS: - iicdev->iicd_addr = sc->ownaddr; + iicdev->iicd_alive = 1; break; + default: panic("%s: unknown class!", __FUNCTION__); } - child = device_add_child(dev, iicdev->iicd_name, -1, iicdev); - device_set_desc(child, iicdev->iicd_desc); + if (iicdev->iicd_alive) { + child = device_add_child(dev, iicdev->iicd_name, + -1, iicdev); + device_set_desc(child, iicdev->iicd_desc); + } } - - return (0); -} - -static int -iicbus_attach(device_t dev) -{ bus_generic_attach(dev); return (0); @@ -171,6 +210,18 @@ iicbus_generic_intr(device_t dev, int event, char *buf) return (0); } +int +iicbus_null_callback(device_t dev, int index, caddr_t data) +{ + return (0); +} + +int +iicbus_null_repeated_start(device_t dev, u_char addr) +{ + return (IIC_ENOTSUPP); +} + static void iicbus_print_child(device_t bus, device_t dev) { @@ -178,9 +229,8 @@ iicbus_print_child(device_t bus, device_t dev) switch (iicdev->iicd_class) { case IICBUS_DEVICE_CLASS: - printf(" on %s%d addr %d %s", device_get_name(bus), - device_get_unit(bus), iicdev->iicd_addr, - (iicdev->iicd_alive) ? "found" : "not found"); + printf(" on %s%d addr 0x%x", device_get_name(bus), + device_get_unit(bus), iicdev->iicd_addr); break; case IICBUS_DRIVER_CLASS: @@ -212,4 +262,19 @@ iicbus_read_ivar(device_t bus, device_t dev, int index, u_long* result) return (0); } +static int +iicbus_write_ivar(device_t bus, device_t dev, int index, u_long val) +{ + struct iicbus_device* iicdev = DEVTOIICBUS(dev); + + switch (index) { + default: + return (ENOENT); + } + + return (0); +} + DRIVER_MODULE(iicbus, pcf, iicbus_driver, iicbus_devclass, 0, 0); +DRIVER_MODULE(iicbus, iicbb, iicbus_driver, iicbus_devclass, 0, 0); +DRIVER_MODULE(iicbus, bti2c, iicbus_driver, iicbus_devclass, 0, 0); diff --git a/sys/dev/iicbus/iicbus.h b/sys/dev/iicbus/iicbus.h index e845252..21c0f97 100644 --- a/sys/dev/iicbus/iicbus.h +++ b/sys/dev/iicbus/iicbus.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: iicbus.h,v 1.1.2.3 1998/08/13 17:10:43 son Exp $ + * $Id: iicbus.h,v 1.1.1.1 1998/09/03 20:51:50 nsouch Exp $ * */ #ifndef __IICBUS_H @@ -31,7 +31,6 @@ struct iicbus_softc { - u_char ownaddr; /* address of the adapter */ device_t owner; /* iicbus owner device structure */ }; diff --git a/sys/dev/iicbus/iicbus_if.m b/sys/dev/iicbus/iicbus_if.m index bf7efeb..edb7587 100644 --- a/sys/dev/iicbus/iicbus_if.m +++ b/sys/dev/iicbus/iicbus_if.m @@ -23,13 +23,13 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# $Id: iicbus_if.m,v 1.1.2.4 1998/08/13 17:10:43 son Exp $ +# $Id: iicbus_if.m,v 1.1.1.1 1998/09/03 20:51:50 nsouch Exp $ # INTERFACE iicbus # -# Interprete interrupt +# Interpret interrupt # METHOD int intr { device_t dev; @@ -38,11 +38,21 @@ METHOD int intr { }; # +# iicbus callback +# +METHOD int callback { + device_t dev; + int index; + caddr_t data; +}; + +# # Send REPEATED_START condition # METHOD int repeated_start { device_t dev; u_char slave; + int timeout; }; # @@ -51,6 +61,7 @@ METHOD int repeated_start { METHOD int start { device_t dev; u_char slave; + int timeout; }; # @@ -68,6 +79,8 @@ METHOD int read { char *buf; int len; int *bytes; + int last; + int delay; }; # @@ -78,6 +91,7 @@ METHOD int write { char *buf; int len; int *bytes; + int timeout; }; # @@ -86,4 +100,6 @@ METHOD int write { METHOD int reset { device_t dev; u_char speed; + u_char addr; + u_char *oldaddr; }; diff --git a/sys/dev/iicbus/iiconf.c b/sys/dev/iicbus/iiconf.c index b037b7c..38e0bd9 100644 --- a/sys/dev/iicbus/iiconf.c +++ b/sys/dev/iicbus/iiconf.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: iiconf.c,v 1.1.1.11 1998/08/29 17:02:05 son Exp $ + * $Id: iiconf.c,v 1.1.1.1 1998/09/03 20:51:50 nsouch Exp $ * */ #include @@ -71,6 +71,28 @@ iicbus_alloc_bus(device_t parent) return (child); } +static int +iicbus_poll(struct iicbus_softc *sc, int how) +{ + int error; + + switch (how) { + case (IIC_WAIT | IIC_INTR): + error = tsleep(sc, IICPRI|PCATCH, "iicreq", 0); + break; + + case (IIC_WAIT | IIC_NOINTR): + error = tsleep(sc, IICPRI, "iicreq", 0); + break; + + default: + return (EWOULDBLOCK); + break; + } + + return (error); +} + /* * iicbus_request_bus() * @@ -84,25 +106,20 @@ iicbus_request_bus(device_t bus, device_t dev, int how) struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); int s, error = 0; + /* first, ask the underlying layers if the request is ok */ + do { + error = IICBUS_CALLBACK(device_get_parent(bus), + IIC_REQUEST_BUS, (caddr_t)&how); + if (error) + error = iicbus_poll(sc, how); + } while (error); + while (!error) { s = splhigh(); if (sc->owner) { splx(s); - switch (how) { - case (IIC_WAIT | IIC_INTR): - error = tsleep(sc, IICPRI|PCATCH, "iicreq", 0); - break; - - case (IIC_WAIT | IIC_NOINTR): - error = tsleep(sc, IICPRI, "iicreq", 0); - break; - - default: - return (EWOULDBLOCK); - break; - } - + error = iicbus_poll(sc, how); } else { sc->owner = dev; @@ -123,7 +140,13 @@ int iicbus_release_bus(device_t bus, device_t dev) { struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); - int s; + int s, error; + + /* first, ask the underlying layers if the release is ok */ + error = IICBUS_CALLBACK(device_get_parent(bus), IIC_RELEASE_BUS, NULL); + + if (error) + return (error); s = splhigh(); if (sc->owner != dev) { @@ -151,10 +174,10 @@ iicbus_block_write(device_t bus, u_char slave, char *buf, int len, int *sent) u_char addr = slave & ~LSB; int error; - if ((error = iicbus_start(bus, addr))) + if ((error = iicbus_start(bus, addr, 0))) return (error); - error = iicbus_write(bus, buf, len, sent); + error = iicbus_write(bus, buf, len, sent, 0); iicbus_stop(bus); @@ -172,12 +195,12 @@ iicbus_block_read(device_t bus, u_char slave, char *buf, int len, int *read) u_char addr = slave | LSB; int error; - if ((error = iicbus_start(bus, addr))) + if ((error = iicbus_start(bus, addr, 0))) return (error); - error = iicbus_read(bus, buf, len, read); + error = iicbus_read(bus, buf, len, read, IIC_LAST_READ, 0); - /* STOP condition sent at adapter level */ + iicbus_stop(bus); return (error); } @@ -197,11 +220,3 @@ iicbus_get_addr(device_t dev) return ((u_char)addr); } - -u_char -iicbus_get_own_address(device_t bus) -{ - struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); - - return (sc->ownaddr); -} diff --git a/sys/dev/iicbus/iiconf.h b/sys/dev/iicbus/iiconf.h index 9bf0ed3..874ecd4 100644 --- a/sys/dev/iicbus/iiconf.h +++ b/sys/dev/iicbus/iiconf.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: iiconf.h,v 1.1.1.10 1998/08/13 17:10:43 son Exp $ + * $Id: iiconf.h,v 1.1.1.1 1998/09/03 20:51:50 nsouch Exp $ */ #ifndef __IICONF_H #define __IICONF_H @@ -59,6 +59,14 @@ #define IIC_FAST 0x2 #define IIC_FASTEST 0x3 +#define IIC_LAST_READ 0x1 + +/* + * callback index + */ +#define IIC_REQUEST_BUS 0x1 +#define IIC_RELEASE_BUS 0x2 + /* * interrupt events */ @@ -81,6 +89,8 @@ #define IIC_ESTATUS 0x5 /* status error */ #define IIC_EUNDERFLOW 0x6 /* slave ready for more data */ #define IIC_EOVERFLOW 0x7 /* too much data */ +#define IIC_ENOTSUPP 0x8 /* request not supported */ +#define IIC_ENOADDR 0x9 /* no address assigned to the interface */ /* * ivars codes @@ -93,23 +103,25 @@ extern device_t iicbus_alloc_bus(device_t); extern void iicbus_intr(device_t, int, char *); -#define iicbus_repeated_start(bus,slave) \ - (IICBUS_REPEATED_START(device_get_parent(bus), slave)) -#define iicbus_start(bus,slave) \ - (IICBUS_START(device_get_parent(bus), slave)) +extern int iicbus_null_repeated_start(device_t, u_char); +extern int iicbus_null_callback(device_t, int, caddr_t); + +#define iicbus_repeated_start(bus,slave,timeout) \ + (IICBUS_REPEATED_START(device_get_parent(bus), slave, timeout)) +#define iicbus_start(bus,slave,timeout) \ + (IICBUS_START(device_get_parent(bus), slave, timeout)) #define iicbus_stop(bus) \ (IICBUS_STOP(device_get_parent(bus))) -#define iicbus_reset(bus,speed) \ - (IICBUS_RESET(device_get_parent(bus), speed)) -#define iicbus_write(bus,buf,len,sent) \ - (IICBUS_WRITE(device_get_parent(bus), buf, len, sent)) -#define iicbus_read(bus,buf,len,sent) \ - (IICBUS_READ(device_get_parent(bus), buf, len, sent)) +#define iicbus_reset(bus,speed,addr,oldaddr) \ + (IICBUS_RESET(device_get_parent(bus), speed, addr, oldaddr)) +#define iicbus_write(bus,buf,len,sent,timeout) \ + (IICBUS_WRITE(device_get_parent(bus), buf, len, sent, timeout)) +#define iicbus_read(bus,buf,len,sent,last,delay) \ + (IICBUS_READ(device_get_parent(bus), buf, len, sent, last, delay)) extern int iicbus_block_write(device_t, u_char, char *, int, int *); extern int iicbus_block_read(device_t, u_char, char *, int, int *); extern u_char iicbus_get_addr(device_t); -extern u_char iicbus_get_own_address(device_t); #endif diff --git a/sys/dev/iicbus/iicsmb.c b/sys/dev/iicbus/iicsmb.c index 8f3a8bb..060c548 100644 --- a/sys/dev/iicbus/iicsmb.c +++ b/sys/dev/iicbus/iicsmb.c @@ -23,12 +23,26 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: iicsmb.c,v 1.1.2.2 1998/08/13 17:10:44 son Exp $ + * $Id: iicsmb.c,v 1.1.1.1 1998/09/03 20:51:50 nsouch Exp $ * */ /* * I2C to SMB bridge + * + * Example: + * + * smb bttv + * \ / + * smbus + * / \ + * iicsmb bti2c + * | + * iicbus + * / | \ + * iicbb pcf ... + * | + * lpbb */ #include @@ -72,6 +86,7 @@ static int iicsmb_attach(device_t); static void iicsmb_print_child(device_t, device_t); static void iicsmb_intr(device_t dev, int event, char *buf); +static int iicsmb_callback(device_t dev, int index, caddr_t data); static int iicsmb_quick(device_t dev, u_char slave, int how); static int iicsmb_sendb(device_t dev, u_char slave, char byte); static int iicsmb_recvb(device_t dev, u_char slave, char *byte); @@ -97,6 +112,7 @@ static device_method_t iicsmb_methods[] = { DEVMETHOD(iicbus_intr, iicsmb_intr), /* smbus interface */ + DEVMETHOD(smbus_callback, iicsmb_callback), DEVMETHOD(smbus_quick, iicsmb_quick), DEVMETHOD(smbus_sendb, iicsmb_sendb), DEVMETHOD(smbus_recvb, iicsmb_recvb), @@ -223,6 +239,32 @@ end: } static int +iicsmb_callback(device_t dev, int index, caddr_t data) +{ + device_t parent = device_get_parent(dev); + int error = 0; + int how; + + switch (index) { + case SMB_REQUEST_BUS: + /* request underlying iicbus */ + how = *(int *)data; + error = iicbus_request_bus(parent, dev, how); + break; + + case SMB_RELEASE_BUS: + /* release underlying iicbus */ + error = iicbus_release_bus(parent, dev); + break; + + default: + error = EINVAL; + } + + return (error); +} + +static int iicsmb_quick(device_t dev, u_char slave, int how) { device_t parent = device_get_parent(dev); @@ -230,11 +272,11 @@ iicsmb_quick(device_t dev, u_char slave, int how) switch (how) { case SMB_QWRITE: - error = iicbus_start(parent, slave & ~LSB); + error = iicbus_start(parent, slave & ~LSB, 0); break; case SMB_QREAD: - error = iicbus_start(parent, slave | LSB); + error = iicbus_start(parent, slave | LSB, 0); break; default: @@ -254,10 +296,10 @@ iicsmb_sendb(device_t dev, u_char slave, char byte) device_t parent = device_get_parent(dev); int error, sent; - error = iicbus_start(parent, slave & ~LSB); + error = iicbus_start(parent, slave & ~LSB, 0); if (!error) { - error = iicbus_write(parent, &byte, 1, &sent); + error = iicbus_write(parent, &byte, 1, &sent, 0); iicbus_stop(parent); } @@ -271,10 +313,13 @@ iicsmb_recvb(device_t dev, u_char slave, char *byte) device_t parent = device_get_parent(dev); int error, read; - error = iicbus_start(parent, slave | LSB); + error = iicbus_start(parent, slave | LSB, 0); - if (!error) - error = iicbus_read(parent, byte, 1, &read); + if (!error) { + error = iicbus_read(parent, byte, 1, &read, IIC_LAST_READ, 0); + + iicbus_stop(parent); + } return (error); } @@ -285,11 +330,11 @@ iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte) device_t parent = device_get_parent(dev); int error, sent; - error = iicbus_start(parent, slave & ~LSB); + error = iicbus_start(parent, slave & ~LSB, 0); if (!error) { - if (!(error = iicbus_write(parent, &cmd, 1, &sent))) - error = iicbus_write(parent, &byte, 1, &sent); + if (!(error = iicbus_write(parent, &cmd, 1, &sent, 0))) + error = iicbus_write(parent, &byte, 1, &sent, 0); iicbus_stop(parent); } @@ -306,12 +351,12 @@ iicsmb_writew(device_t dev, u_char slave, char cmd, short word) char low = (char)(word & 0xff); char high = (char)((word & 0xff00) >> 8); - error = iicbus_start(parent, slave & ~LSB); + error = iicbus_start(parent, slave & ~LSB, 0); if (!error) { - if (!(error = iicbus_write(parent, &cmd, 1, &sent))) - if (!(error = iicbus_write(parent, &low, 1, &sent))) - error = iicbus_write(parent, &high, 1, &sent); + if (!(error = iicbus_write(parent, &cmd, 1, &sent, 0))) + if (!(error = iicbus_write(parent, &low, 1, &sent, 0))) + error = iicbus_write(parent, &high, 1, &sent, 0); iicbus_stop(parent); } @@ -325,19 +370,20 @@ iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte) device_t parent = device_get_parent(dev); int error, sent, read; - if ((error = iicbus_start(parent, slave & ~LSB))) - goto error; + if ((error = iicbus_start(parent, slave & ~LSB, 0))) + return (error); - if ((error = iicbus_write(parent, &cmd, 1, &sent))) + if ((error = iicbus_write(parent, &cmd, 1, &sent, 0))) goto error; - if ((error = iicbus_repeated_start(parent, slave | LSB))) + if ((error = iicbus_repeated_start(parent, slave | LSB, 0))) goto error; - if ((error = iicbus_read(parent, byte, 1, &read))) + if ((error = iicbus_read(parent, byte, 1, &read, IIC_LAST_READ, 0))) goto error; error: + iicbus_stop(parent); return (error); } @@ -351,22 +397,23 @@ iicsmb_readw(device_t dev, u_char slave, char cmd, short *word) int error, sent, read; char buf[2]; - if ((error = iicbus_start(parent, slave & ~LSB))) - goto error; + if ((error = iicbus_start(parent, slave & ~LSB, 0))) + return (error); - if ((error = iicbus_write(parent, &cmd, 1, &sent))) + if ((error = iicbus_write(parent, &cmd, 1, &sent, 0))) goto error; - if ((error = iicbus_repeated_start(parent, slave | LSB))) + if ((error = iicbus_repeated_start(parent, slave | LSB, 0))) goto error; - if ((error = iicbus_read(parent, buf, 2, &read))) + if ((error = iicbus_read(parent, buf, 2, &read, IIC_LAST_READ, 0))) goto error; /* first, receive low, then high byte */ *word = BUF2SHORT(buf[0], buf[1]); error: + iicbus_stop(parent); return (error); } @@ -377,29 +424,30 @@ iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) int error, sent, read; char buf[2]; - if ((error = iicbus_start(parent, slave & ~LSB))) - goto error; + if ((error = iicbus_start(parent, slave & ~LSB, 0))) + return (error); - if ((error = iicbus_write(parent, &cmd, 1, &sent))) + if ((error = iicbus_write(parent, &cmd, 1, &sent, 0))) goto error; /* first, send low, then high byte */ buf[0] = (char)(sdata & 0xff); buf[1] = (char)((sdata & 0xff00) >> 8); - if ((error = iicbus_write(parent, buf, 2, &sent))) + if ((error = iicbus_write(parent, buf, 2, &sent, 0))) goto error; - if ((error = iicbus_repeated_start(parent, slave | LSB))) + if ((error = iicbus_repeated_start(parent, slave | LSB, 0))) goto error; - if ((error = iicbus_read(parent, buf, 2, &read))) + if ((error = iicbus_read(parent, buf, 2, &read, IIC_LAST_READ, 0))) goto error; /* first, receive low, then high byte */ *rdata = BUF2SHORT(buf[0], buf[1]); error: + iicbus_stop(parent); return (error); } @@ -409,13 +457,13 @@ iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) device_t parent = device_get_parent(dev); int error, sent; - if ((error = iicbus_start(parent, slave & ~LSB))) + if ((error = iicbus_start(parent, slave & ~LSB, 0))) goto error; - if ((error = iicbus_write(parent, &cmd, 1, &sent))) + if ((error = iicbus_write(parent, &cmd, 1, &sent, 0))) goto error; - if ((error = iicbus_write(parent, buf, (int)count, &sent))) + if ((error = iicbus_write(parent, buf, (int)count, &sent, 0))) goto error; if ((error = iicbus_stop(parent))) @@ -431,19 +479,21 @@ iicsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) device_t parent = device_get_parent(dev); int error, sent, read; - if ((error = iicbus_start(parent, slave & ~LSB))) - goto error; + if ((error = iicbus_start(parent, slave & ~LSB, 0))) + return (error); - if ((error = iicbus_write(parent, &cmd, 1, &sent))) + if ((error = iicbus_write(parent, &cmd, 1, &sent, 0))) goto error; - if ((error = iicbus_repeated_start(parent, slave | LSB))) + if ((error = iicbus_repeated_start(parent, slave | LSB, 0))) goto error; - if ((error = iicbus_read(parent, buf, (int)count, &read))) + if ((error = iicbus_read(parent, buf, (int)count, &read, + IIC_LAST_READ, 0))) goto error; error: + iicbus_stop(parent); return (error); } -- cgit v1.1