1 /*- 2 * Copyright (c) 1998 Nicolas Souchu 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $Id: iicbb.c,v 1.3 1999/01/28 15:50:24 roger Exp $ 27 * 28 */ 29 30 /* 31 * Generic I2C bit-banging code 32 * 33 * Example: 34 * 35 * iicbus 36 * / \ 37 * iicbb pcf 38 * | \ 39 * bti2c lpbb 40 * 41 * From Linux I2C generic interface 42 * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> 43 * 44 * TODO: port Peter's generic bit-banging code <dufault@hda.com> 45 */ 46 47 #include <sys/param.h> 48 #include <sys/kernel.h> 49 #include <sys/systm.h> 50 #include <sys/module.h> 51 #include <sys/bus.h> 52 #include <sys/conf.h> 53 #include <sys/buf.h> 54 #include <sys/uio.h> 55 #include <sys/malloc.h> 56 57 #include <machine/clock.h> 58 59 #include <dev/iicbus/iiconf.h> 60 #include <dev/iicbus/iicbus.h> 61 62 #include <dev/smbus/smbconf.h> 63 64 #include "iicbus_if.h" 65 #include "iicbb_if.h" 66 67 struct iicbb_softc { 68 int dummy; 69 }; 70 71 static int iicbb_probe(device_t); 72 static int iicbb_attach(device_t); 73 static void iicbb_print_child(device_t, device_t); 74 75 static int iicbb_callback(device_t, int, caddr_t); 76 static int iicbb_start(device_t, u_char, int); 77 static int iicbb_stop(device_t); 78 static int iicbb_write(device_t, char *, int, int *, int); 79 static int iicbb_read(device_t, char *, int, int *, int, int); 80 static int iicbb_reset(device_t, u_char, u_char, u_char *); 81 82 static device_method_t iicbb_methods[] = { 83 /* device interface */ 84 DEVMETHOD(device_probe, iicbb_probe), 85 DEVMETHOD(device_attach, iicbb_attach), 86 87 /* bus interface */ 88 DEVMETHOD(bus_print_child, iicbb_print_child), 89 90 /* iicbus interface */ 91 DEVMETHOD(iicbus_callback, iicbb_callback), 92 DEVMETHOD(iicbus_start, iicbb_start), 93 DEVMETHOD(iicbus_repeated_start, iicbb_start), 94 DEVMETHOD(iicbus_stop, iicbb_stop), 95 DEVMETHOD(iicbus_write, iicbb_write), 96 DEVMETHOD(iicbus_read, iicbb_read), 97 DEVMETHOD(iicbus_reset, iicbb_reset), 98 99 { 0, 0 } 100 }; 101 102 static driver_t iicbb_driver = { 103 "iicbb", 104 iicbb_methods, 105 sizeof(struct iicbb_softc), 106 }; 107 108 static devclass_t iicbb_devclass; 109 110 static int iicbb_probe(device_t dev) 111 { 112 device_set_desc(dev, "I2C generic bit-banging driver"); 113 114 return (0); 115 } 116 117 static int iicbb_attach(device_t dev) 118 { 119 return (0); 120 } 121 122 static void 123 iicbb_print_child(device_t bus, device_t dev) 124 { 125 int error; 126 u_char oldaddr; 127 128 /* retrieve the interface I2C address */ 129 error = IICBB_RESET(device_get_parent(bus), IIC_FASTEST, 0, &oldaddr); 130 if (error == IIC_ENOADDR) { 131 printf(" on %s%d master-only", device_get_name(bus), 132 device_get_unit(bus)); 133 134 } else { 135 /* restore the address */ 136 IICBB_RESET(device_get_parent(bus), IIC_FASTEST, oldaddr, NULL); 137 138 printf(" on %s%d addr 0x%x", device_get_name(bus), 139 device_get_unit(bus), oldaddr & 0xff); 140 } 141 142 return; 143 } 144 145 #define I2C_SET(dev,ctrl,data) \ 146 IICBB_SETLINES(device_get_parent(dev), ctrl, data) 147 148 #define I2C_GET(dev) (IICBB_GETDATALINE(device_get_parent(dev))) 149 150 static int i2c_debug = 0; 151 #define I2C_DEBUG(x) if (i2c_debug) (x) 152 153 static void iicbb_one(device_t dev) 154 { 155 I2C_SET(dev,0,1); 156 I2C_SET(dev,1,1); 157 I2C_SET(dev,0,1); 158 return; 159 } 160 161 static void iicbb_zero(device_t dev) 162 { 163 I2C_SET(dev,0,0); 164 I2C_SET(dev,1,0); 165 I2C_SET(dev,0,0); 166 return; 167 } 168 169 /* 170 * Waiting for ACKNOWLEDGE. 171 * 172 * When a chip is being addressed or has received data it will issue an 173 * ACKNOWLEDGE pulse. Therefore the MASTER must release the DATA line 174 * (set it to high level) and then release the CLOCK line. 175 * Now it must wait for the SLAVE to pull the DATA line low. 176 * Actually on the bus this looks like a START condition so nothing happens 177 * because of the fact that the IC's that have not been addressed are doing 178 * nothing. 179 * 180 * When the SLAVE has pulled this line low the MASTER will take the CLOCK 181 * line low and then the SLAVE will release the SDA (data) line. 182 */ 183 static int iicbb_ack(device_t dev, int timeout) 184 { 185 int noack; 186 int k = timeout/10; 187 188 I2C_SET(dev,0,1); 189 I2C_SET(dev,1,1); 190 191 do { 192 noack = I2C_GET(dev); 193 if (!noack) 194 break; 195 DELAY(10); /* XXX wait 10us */ 196 } while (k--); 197 198 I2C_SET(dev,0,1); 199 I2C_DEBUG(printf("%c ",noack?'-':'+')); 200 201 return (noack); 202 } 203 204 static void iicbb_sendbyte(device_t dev, u_char data) 205 { 206 int i; 207 208 I2C_SET(dev,0,0); 209 for (i=7; i>=0; i--) 210 (data&(1<<i)) ? iicbb_one(dev) : iicbb_zero(dev); 211 I2C_DEBUG(printf("w%02x",(int)data)); 212 return; 213 } 214 215 static u_char iicbb_readbyte(device_t dev, int last) 216 { 217 int i; 218 unsigned char data=0; 219 220 I2C_SET(dev,0,1); 221 for (i=7; i>=0; i--) 222 { 223 I2C_SET(dev,1,1); 224 if (I2C_GET(dev)) 225 data |= (1<<i); 226 I2C_SET(dev,0,1); 227 } 228 last ? iicbb_one(dev) : iicbb_zero(dev); 229 I2C_DEBUG(printf("r%02x%c ",(int)data,last?'-':'+')); 230 return data; 231 } 232 233 static int iicbb_callback(device_t dev, int index, caddr_t data) 234 { 235 return (IICBB_CALLBACK(device_get_parent(dev), index, data)); 236 } 237 238 static int iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 239 { 240 return (IICBB_RESET(device_get_parent(dev), speed, addr, oldaddr)); 241 } 242 243 static int iicbb_start(device_t dev, u_char slave, int timeout) 244 { 245 int error; 246 247 I2C_DEBUG(printf("<")); 248 249 I2C_SET(dev,0,1); 250 I2C_SET(dev,1,1); 251 I2C_SET(dev,1,0); 252 I2C_SET(dev,0,0); 253 254 /* send address */ 255 iicbb_sendbyte(dev, slave); 256 257 /* check for ack */ 258 if (iicbb_ack(dev, timeout)) { 259 error = IIC_ENOACK; 260 goto error; 261 } 262 263 return(0); 264 265 error: 266 iicbb_stop(dev); 267 return (error); 268 } 269 270 static int iicbb_stop(device_t dev) 271 { 272 I2C_SET(dev,0,0); 273 I2C_SET(dev,1,0); 274 I2C_SET(dev,1,1); 275 I2C_DEBUG(printf(">")); 276 return (0); 277 } 278 279 static int iicbb_write(device_t dev, char * buf, int len, int *sent, 280 int timeout) 281 { 282 int bytes, error = 0; 283 284 bytes = 0; 285 while (len) { 286 /* send byte */ 287 iicbb_sendbyte(dev,(u_char)*buf++); 288 289 /* check for ack */ 290 if (iicbb_ack(dev, timeout)) { 291 error = IIC_ENOACK; 292 goto error; 293 } 294 bytes ++; 295 len --; 296 } 297 298 error: 299 *sent = bytes; 300 return (error); 301 } 302 303 static int iicbb_read(device_t dev, char * buf, int len, int *read, 304 int last, int delay) 305 { 306 int bytes; 307 308 bytes = 0; 309 while (len) { 310 /* XXX should insert delay here */ 311 *buf++ = (char)iicbb_readbyte(dev, (len == 1) ? last : 0); 312 313 bytes ++; 314 len --; 315 } 316 317 *read = bytes; 318 return (0); 319 } 320 321 DRIVER_MODULE(iicbb, bti2c, iicbb_driver, iicbb_devclass, 0, 0); 322 DRIVER_MODULE(iicbb, lpbb, iicbb_driver, iicbb_devclass, 0, 0); 323