summaryrefslogtreecommitdiffstats
path: root/sys/dev/iicbus/iicbus.c
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/iicbus.c
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/iicbus.c')
-rw-r--r--sys/dev/iicbus/iicbus.c127
1 files changed, 96 insertions, 31 deletions
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);
OpenPOWER on IntegriCloud