summaryrefslogtreecommitdiffstats
path: root/sys/dev/iicbus
diff options
context:
space:
mode:
authornsouch <nsouch@FreeBSD.org>1998-10-31 11:31:07 +0000
committernsouch <nsouch@FreeBSD.org>1998-10-31 11:31:07 +0000
commita8f721865de13fdf796dd7a371aed217c14710fa (patch)
tree31d38be0f9dd9b02b4c41d3ef20d4731dca19e37 /sys/dev/iicbus
parent714f720fe4d52d1e7de1220cced124f0cab0314b (diff)
downloadFreeBSD-src-a8f721865de13fdf796dd7a371aed217c14710fa.zip
FreeBSD-src-a8f721865de13fdf796dd7a371aed217c14710fa.tar.gz
iicbb is generic support for I2C bit-banging.
Other files: timeout management added to the I2C framework.
Diffstat (limited to 'sys/dev/iicbus')
-rw-r--r--sys/dev/iicbus/if_ic.c4
-rw-r--r--sys/dev/iicbus/iic.c6
-rw-r--r--sys/dev/iicbus/iicbb.c323
-rw-r--r--sys/dev/iicbus/iicbb_if.m65
-rw-r--r--sys/dev/iicbus/iicbus.c127
-rw-r--r--sys/dev/iicbus/iicbus.h3
-rw-r--r--sys/dev/iicbus/iicbus_if.m20
-rw-r--r--sys/dev/iicbus/iiconf.c73
-rw-r--r--sys/dev/iicbus/iiconf.h36
-rw-r--r--sys/dev/iicbus/iicsmb.c128
10 files changed, 665 insertions, 120 deletions
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 <sys/param.h>
@@ -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 <kraxel@cs.tu-berlin.de>
+ *
+ * TODO: port Peter's generic bit-banging code <dufault@hda.com>
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/buf.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+
+#include <machine/clock.h>
+
+#include <dev/iicbus/iiconf.h>
+#include <dev/iicbus/iicbus.h>
+
+#include <dev/smbus/smbconf.h>
+
+#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<<i)) ? iicbb_one(dev) : iicbb_zero(dev);
+ I2C_DEBUG(printf("w%02x",(int)data));
+ return;
+}
+
+static u_char iicbb_readbyte(device_t dev, int last)
+{
+ int i;
+ unsigned char data=0;
+
+ I2C_SET(dev,0,1);
+ for (i=7; i>=0; i--)
+ {
+ I2C_SET(dev,1,1);
+ if (I2C_GET(dev))
+ data |= (1<<i);
+ I2C_SET(dev,0,1);
+ }
+ last ? iicbb_one(dev) : iicbb_zero(dev);
+ I2C_DEBUG(printf("r%02x%c ",(int)data,last?'-':'+'));
+ return data;
+}
+
+static int iicbb_callback(device_t dev, int index, caddr_t data)
+{
+ return (IICBB_CALLBACK(device_get_parent(dev), index, data));
+}
+
+static int iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
+{
+ return (IICBB_RESET(device_get_parent(dev), speed, addr, oldaddr));
+}
+
+static int iicbb_start(device_t dev, u_char slave, int timeout)
+{
+ int error;
+
+ 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);
+
+ /* check for ack */
+ if (iicbb_ack(dev, timeout)) {
+ error = IIC_ENOACK;
+ goto error;
+ }
+
+ return(0);
+
+error:
+ iicbb_stop(dev);
+ return (error);
+}
+
+static int iicbb_stop(device_t dev)
+{
+ I2C_SET(dev,0,0);
+ I2C_SET(dev,1,0);
+ I2C_SET(dev,1,1);
+ I2C_DEBUG(printf(">"));
+ 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 <sys/param.h>
@@ -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 <sys/param.h>
@@ -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);
}
OpenPOWER on IntegriCloud