summaryrefslogtreecommitdiffstats
path: root/sys/dev/iicbus/iicbb.c
diff options
context:
space:
mode:
authornsouch <nsouch@FreeBSD.org>2002-03-23 15:49:15 +0000
committernsouch <nsouch@FreeBSD.org>2002-03-23 15:49:15 +0000
commit82395b7295123f4d9a786ebd89495ef101103a61 (patch)
treef78e24d69b8d02162ae886a610fb85cac8989741 /sys/dev/iicbus/iicbb.c
parent0dcefe7b55beecbfaeba7c0b20e4b1277b781733 (diff)
downloadFreeBSD-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.c126
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);
OpenPOWER on IntegriCloud