iicbb.c revision 49195
1277323Sdim/*- 2277323Sdim * Copyright (c) 1998 Nicolas Souchu 3277323Sdim * All rights reserved. 4277323Sdim * 5277323Sdim * Redistribution and use in source and binary forms, with or without 6277323Sdim * modification, are permitted provided that the following conditions 7277323Sdim * are met: 8277323Sdim * 1. Redistributions of source code must retain the above copyright 9277323Sdim * notice, this list of conditions and the following disclaimer. 10277323Sdim * 2. Redistributions in binary form must reproduce the above copyright 11277323Sdim * notice, this list of conditions and the following disclaimer in the 12277323Sdim * documentation and/or other materials provided with the distribution. 13277323Sdim * 14277323Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15277323Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16296417Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17277323Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18277323Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19277323Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20277323Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21277323Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22277323Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23277323Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24277323Sdim * SUCH DAMAGE. 25277323Sdim * 26277323Sdim * $Id: iicbb.c,v 1.4 1999/05/08 21:59:04 dfr Exp $ 27277323Sdim * 28277323Sdim */ 29277323Sdim 30277323Sdim/* 31277323Sdim * Generic I2C bit-banging code 32277323Sdim * 33277323Sdim * Example: 34296417Sdim * 35277323Sdim * iicbus 36296417Sdim * / \ 37296417Sdim * iicbb pcf 38277323Sdim * | \ 39296417Sdim * bti2c lpbb 40277323Sdim * 41296417Sdim * From Linux I2C generic interface 42296417Sdim * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> 43296417Sdim * 44296417Sdim * TODO: port Peter's generic bit-banging code <dufault@hda.com> 45277323Sdim */ 46296417Sdim 47277323Sdim#include <sys/param.h> 48296417Sdim#include <sys/kernel.h> 49296417Sdim#include <sys/systm.h> 50296417Sdim#include <sys/module.h> 51277323Sdim#include <sys/bus.h> 52296417Sdim#include <sys/conf.h> 53277323Sdim#include <sys/buf.h> 54277323Sdim#include <sys/uio.h> 55296417Sdim#include <sys/malloc.h> 56296417Sdim 57296417Sdim#include <machine/clock.h> 58296417Sdim 59296417Sdim#include <dev/iicbus/iiconf.h> 60277323Sdim#include <dev/iicbus/iicbus.h> 61277323Sdim 62277323Sdim#include <dev/smbus/smbconf.h> 63296417Sdim 64296417Sdim#include "iicbus_if.h" 65296417Sdim#include "iicbb_if.h" 66296417Sdim 67296417Sdimstruct iicbb_softc { 68277323Sdim int dummy; 69296417Sdim}; 70296417Sdim 71296417Sdimstatic int iicbb_probe(device_t); 72296417Sdimstatic int iicbb_attach(device_t); 73296417Sdimstatic int iicbb_print_child(device_t, device_t); 74296417Sdim 75296417Sdimstatic int iicbb_callback(device_t, int, caddr_t); 76277323Sdimstatic int iicbb_start(device_t, u_char, int); 77296417Sdimstatic int iicbb_stop(device_t); 78277323Sdimstatic int iicbb_write(device_t, char *, int, int *, int); 79277323Sdimstatic int iicbb_read(device_t, char *, int, int *, int, int); 80277323Sdimstatic int iicbb_reset(device_t, u_char, u_char, u_char *); 81277323Sdim 82277323Sdimstatic device_method_t iicbb_methods[] = { 83296417Sdim /* device interface */ 84277323Sdim DEVMETHOD(device_probe, iicbb_probe), 85296417Sdim DEVMETHOD(device_attach, iicbb_attach), 86296417Sdim 87296417Sdim /* bus interface */ 88296417Sdim DEVMETHOD(bus_print_child, iicbb_print_child), 89296417Sdim 90296417Sdim /* iicbus interface */ 91296417Sdim DEVMETHOD(iicbus_callback, iicbb_callback), 92277323Sdim DEVMETHOD(iicbus_start, iicbb_start), 93296417Sdim DEVMETHOD(iicbus_repeated_start, iicbb_start), 94296417Sdim DEVMETHOD(iicbus_stop, iicbb_stop), 95296417Sdim DEVMETHOD(iicbus_write, iicbb_write), 96296417Sdim DEVMETHOD(iicbus_read, iicbb_read), 97296417Sdim DEVMETHOD(iicbus_reset, iicbb_reset), 98296417Sdim 99296417Sdim { 0, 0 } 100296417Sdim}; 101296417Sdim 102296417Sdimstatic driver_t iicbb_driver = { 103277323Sdim "iicbb", 104277323Sdim iicbb_methods, 105277323Sdim sizeof(struct iicbb_softc), 106277323Sdim}; 107277323Sdim 108296417Sdimstatic devclass_t iicbb_devclass; 109277323Sdim 110296417Sdimstatic int iicbb_probe(device_t dev) 111296417Sdim{ 112296417Sdim device_set_desc(dev, "I2C generic bit-banging driver"); 113296417Sdim 114296417Sdim return (0); 115296417Sdim} 116296417Sdim 117296417Sdimstatic int iicbb_attach(device_t dev) 118296417Sdim{ 119296417Sdim return (0); 120296417Sdim} 121296417Sdim 122296417Sdimstatic int 123296417Sdimiicbb_print_child(device_t bus, device_t dev) 124296417Sdim{ 125296417Sdim int error; 126296417Sdim int retval = 0; 127296417Sdim u_char oldaddr; 128277323Sdim 129277323Sdim retval += bus_print_child_header(bus, dev); 130277323Sdim /* retrieve the interface I2C address */ 131277323Sdim error = IICBB_RESET(device_get_parent(bus), IIC_FASTEST, 0, &oldaddr); 132277323Sdim if (error == IIC_ENOADDR) { 133277323Sdim retval += printf(" on %s master-only\n", 134277323Sdim device_get_nameunit(bus)); 135 } else { 136 /* restore the address */ 137 IICBB_RESET(device_get_parent(bus), IIC_FASTEST, oldaddr, NULL); 138 139 retval += printf(" on %s addr 0x%x\n", 140 device_get_nameunit(bus), oldaddr & 0xff); 141 } 142 143 return (retval); 144} 145 146#define I2C_SET(dev,ctrl,data) \ 147 IICBB_SETLINES(device_get_parent(dev), ctrl, data) 148 149#define I2C_GET(dev) (IICBB_GETDATALINE(device_get_parent(dev))) 150 151static int i2c_debug = 0; 152#define I2C_DEBUG(x) if (i2c_debug) (x) 153 154static void iicbb_one(device_t dev) 155{ 156 I2C_SET(dev,0,1); 157 I2C_SET(dev,1,1); 158 I2C_SET(dev,0,1); 159 return; 160} 161 162static void iicbb_zero(device_t dev) 163{ 164 I2C_SET(dev,0,0); 165 I2C_SET(dev,1,0); 166 I2C_SET(dev,0,0); 167 return; 168} 169 170/* 171 * Waiting for ACKNOWLEDGE. 172 * 173 * When a chip is being addressed or has received data it will issue an 174 * ACKNOWLEDGE pulse. Therefore the MASTER must release the DATA line 175 * (set it to high level) and then release the CLOCK line. 176 * Now it must wait for the SLAVE to pull the DATA line low. 177 * Actually on the bus this looks like a START condition so nothing happens 178 * because of the fact that the IC's that have not been addressed are doing 179 * nothing. 180 * 181 * When the SLAVE has pulled this line low the MASTER will take the CLOCK 182 * line low and then the SLAVE will release the SDA (data) line. 183 */ 184static int iicbb_ack(device_t dev, int timeout) 185{ 186 int noack; 187 int k = timeout/10; 188 189 I2C_SET(dev,0,1); 190 I2C_SET(dev,1,1); 191 192 do { 193 noack = I2C_GET(dev); 194 if (!noack) 195 break; 196 DELAY(10); /* XXX wait 10us */ 197 } while (k--); 198 199 I2C_SET(dev,0,1); 200 I2C_DEBUG(printf("%c ",noack?'-':'+')); 201 202 return (noack); 203} 204 205static void iicbb_sendbyte(device_t dev, u_char data) 206{ 207 int i; 208 209 I2C_SET(dev,0,0); 210 for (i=7; i>=0; i--) 211 (data&(1<<i)) ? iicbb_one(dev) : iicbb_zero(dev); 212 I2C_DEBUG(printf("w%02x",(int)data)); 213 return; 214} 215 216static u_char iicbb_readbyte(device_t dev, int last) 217{ 218 int i; 219 unsigned char data=0; 220 221 I2C_SET(dev,0,1); 222 for (i=7; i>=0; i--) 223 { 224 I2C_SET(dev,1,1); 225 if (I2C_GET(dev)) 226 data |= (1<<i); 227 I2C_SET(dev,0,1); 228 } 229 last ? iicbb_one(dev) : iicbb_zero(dev); 230 I2C_DEBUG(printf("r%02x%c ",(int)data,last?'-':'+')); 231 return data; 232} 233 234static int iicbb_callback(device_t dev, int index, caddr_t data) 235{ 236 return (IICBB_CALLBACK(device_get_parent(dev), index, data)); 237} 238 239static int iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 240{ 241 return (IICBB_RESET(device_get_parent(dev), speed, addr, oldaddr)); 242} 243 244static int iicbb_start(device_t dev, u_char slave, int timeout) 245{ 246 int error; 247 248 I2C_DEBUG(printf("<")); 249 250 I2C_SET(dev,0,1); 251 I2C_SET(dev,1,1); 252 I2C_SET(dev,1,0); 253 I2C_SET(dev,0,0); 254 255 /* send address */ 256 iicbb_sendbyte(dev, slave); 257 258 /* check for ack */ 259 if (iicbb_ack(dev, timeout)) { 260 error = IIC_ENOACK; 261 goto error; 262 } 263 264 return(0); 265 266error: 267 iicbb_stop(dev); 268 return (error); 269} 270 271static int iicbb_stop(device_t dev) 272{ 273 I2C_SET(dev,0,0); 274 I2C_SET(dev,1,0); 275 I2C_SET(dev,1,1); 276 I2C_DEBUG(printf(">")); 277 return (0); 278} 279 280static int iicbb_write(device_t dev, char * buf, int len, int *sent, 281 int timeout) 282{ 283 int bytes, error = 0; 284 285 bytes = 0; 286 while (len) { 287 /* send byte */ 288 iicbb_sendbyte(dev,(u_char)*buf++); 289 290 /* check for ack */ 291 if (iicbb_ack(dev, timeout)) { 292 error = IIC_ENOACK; 293 goto error; 294 } 295 bytes ++; 296 len --; 297 } 298 299error: 300 *sent = bytes; 301 return (error); 302} 303 304static int iicbb_read(device_t dev, char * buf, int len, int *read, 305 int last, int delay) 306{ 307 int bytes; 308 309 bytes = 0; 310 while (len) { 311 /* XXX should insert delay here */ 312 *buf++ = (char)iicbb_readbyte(dev, (len == 1) ? last : 0); 313 314 bytes ++; 315 len --; 316 } 317 318 *read = bytes; 319 return (0); 320} 321 322DRIVER_MODULE(iicbb, bti2c, iicbb_driver, iicbb_devclass, 0, 0); 323DRIVER_MODULE(iicbb, lpbb, iicbb_driver, iicbb_devclass, 0, 0); 324