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: iicsmb.c,v 1.1.1.1 1998/09/03 20:51:50 nsouch Exp $ 27 * 28 */ 29 30 /* 31 * I2C to SMB bridge 32 * 33 * Example: 34 * 35 * smb bttv 36 * \ / 37 * smbus 38 * / \ 39 * iicsmb bti2c 40 * | 41 * iicbus 42 * / | \ 43 * iicbb pcf ... 44 * | 45 * lpbb 46 */ 47 48 #include <sys/param.h> 49 #include <sys/kernel.h> 50 #include <sys/systm.h> 51 #include <sys/module.h> 52 #include <sys/bus.h> 53 #include <sys/conf.h> 54 #include <sys/buf.h> 55 #include <sys/uio.h> 56 #include <sys/malloc.h> 57 58 #include <machine/clock.h> 59 60 #include <dev/iicbus/iiconf.h> 61 #include <dev/iicbus/iicbus.h> 62 63 #include <dev/smbus/smbconf.h> 64 65 #include "iicbus_if.h" 66 #include "smbus_if.h" 67 68 struct iicsmb_softc { 69 70 #define SMB_WAITING_ADDR 0x0 71 #define SMB_WAITING_LOW 0x1 72 #define SMB_WAITING_HIGH 0x2 73 #define SMB_DONE 0x3 74 int state; 75 76 u_char devaddr; /* slave device address */ 77 78 char low; /* low byte received first */ 79 char high; /* high byte */ 80 81 device_t smbus; 82 }; 83 84 static int iicsmb_probe(device_t); 85 static int iicsmb_attach(device_t); 86 static void iicsmb_print_child(device_t, device_t); 87 88 static void iicsmb_intr(device_t dev, int event, char *buf); 89 static int iicsmb_callback(device_t dev, int index, caddr_t data); 90 static int iicsmb_quick(device_t dev, u_char slave, int how); 91 static int iicsmb_sendb(device_t dev, u_char slave, char byte); 92 static int iicsmb_recvb(device_t dev, u_char slave, char *byte); 93 static int iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte); 94 static int iicsmb_writew(device_t dev, u_char slave, char cmd, short word); 95 static int iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte); 96 static int iicsmb_readw(device_t dev, u_char slave, char cmd, short *word); 97 static int iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata); 98 static int iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); 99 static int iicsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf); 100 101 static devclass_t iicsmb_devclass; 102 103 static device_method_t iicsmb_methods[] = { 104 /* device interface */ 105 DEVMETHOD(device_probe, iicsmb_probe), 106 DEVMETHOD(device_attach, iicsmb_attach), 107 108 /* bus interface */ 109 DEVMETHOD(bus_print_child, iicsmb_print_child), 110 111 /* iicbus interface */ 112 DEVMETHOD(iicbus_intr, iicsmb_intr), 113 114 /* smbus interface */ 115 DEVMETHOD(smbus_callback, iicsmb_callback), 116 DEVMETHOD(smbus_quick, iicsmb_quick), 117 DEVMETHOD(smbus_sendb, iicsmb_sendb), 118 DEVMETHOD(smbus_recvb, iicsmb_recvb), 119 DEVMETHOD(smbus_writeb, iicsmb_writeb), 120 DEVMETHOD(smbus_writew, iicsmb_writew), 121 DEVMETHOD(smbus_readb, iicsmb_readb), 122 DEVMETHOD(smbus_readw, iicsmb_readw), 123 DEVMETHOD(smbus_pcall, iicsmb_pcall), 124 DEVMETHOD(smbus_bwrite, iicsmb_bwrite), 125 DEVMETHOD(smbus_bread, iicsmb_bread), 126 127 { 0, 0 } 128 }; 129 130 static driver_t iicsmb_driver = { 131 "iicsmb", 132 iicsmb_methods, 133 DRIVER_TYPE_MISC, 134 sizeof(struct iicsmb_softc), 135 }; 136 137 static int 138 iicsmb_probe(device_t dev) 139 { 140 struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev); 141 142 sc->smbus = smbus_alloc_bus(dev); 143 144 if (!sc->smbus) 145 return (EINVAL); /* XXX don't know what to return else */ 146 147 return (0); 148 } 149 150 static int 151 iicsmb_attach(device_t dev) 152 { 153 struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev); 154 155 /* probe and attach the smbus */ 156 device_probe_and_attach(sc->smbus); 157 158 return (0); 159 } 160 161 static void 162 iicsmb_print_child(device_t bus, device_t dev) 163 { 164 printf(" on %s%d", device_get_name(bus), device_get_unit(bus)); 165 166 return; 167 } 168 169 /* 170 * iicsmb_intr() 171 * 172 * iicbus interrupt handler 173 */ 174 static void 175 iicsmb_intr(device_t dev, int event, char *buf) 176 { 177 struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev); 178 179 switch (event) { 180 case INTR_GENERAL: 181 case INTR_START: 182 sc->state = SMB_WAITING_ADDR; 183 break; 184 185 case INTR_STOP: 186 /* call smbus intr handler */ 187 smbus_intr(sc->smbus, sc->devaddr, 188 sc->low, sc->high, SMB_ENOERR); 189 break; 190 191 case INTR_RECEIVE: 192 switch (sc->state) { 193 case SMB_DONE: 194 /* XXX too much data, discard */ 195 printf("%s: too much data from 0x%x\n", __FUNCTION__, 196 sc->devaddr & 0xff); 197 goto end; 198 199 case SMB_WAITING_ADDR: 200 sc->devaddr = (u_char)*buf; 201 sc->state = SMB_WAITING_LOW; 202 break; 203 204 case SMB_WAITING_LOW: 205 sc->low = *buf; 206 sc->state = SMB_WAITING_HIGH; 207 break; 208 209 case SMB_WAITING_HIGH: 210 sc->high = *buf; 211 sc->state = SMB_DONE; 212 break; 213 } 214 end: 215 break; 216 217 case INTR_TRANSMIT: 218 case INTR_NOACK: 219 break; 220 221 case INTR_ERROR: 222 switch (*buf) { 223 case IIC_EBUSERR: 224 smbus_intr(sc->smbus, sc->devaddr, 0, 0, SMB_EBUSERR); 225 break; 226 227 default: 228 printf("%s unknown error 0x%x!\n", __FUNCTION__, 229 (int)*buf); 230 break; 231 } 232 break; 233 234 default: 235 panic("%s: unknown event (%d)!", __FUNCTION__, event); 236 } 237 238 return; 239 } 240 241 static int 242 iicsmb_callback(device_t dev, int index, caddr_t data) 243 { 244 device_t parent = device_get_parent(dev); 245 int error = 0; 246 int how; 247 248 switch (index) { 249 case SMB_REQUEST_BUS: 250 /* request underlying iicbus */ 251 how = *(int *)data; 252 error = iicbus_request_bus(parent, dev, how); 253 break; 254 255 case SMB_RELEASE_BUS: 256 /* release underlying iicbus */ 257 error = iicbus_release_bus(parent, dev); 258 break; 259 260 default: 261 error = EINVAL; 262 } 263 264 return (error); 265 } 266 267 static int 268 iicsmb_quick(device_t dev, u_char slave, int how) 269 { 270 device_t parent = device_get_parent(dev); 271 int error; 272 273 switch (how) { 274 case SMB_QWRITE: 275 error = iicbus_start(parent, slave & ~LSB, 0); 276 break; 277 278 case SMB_QREAD: 279 error = iicbus_start(parent, slave | LSB, 0); 280 break; 281 282 default: 283 error = EINVAL; 284 break; 285 } 286 287 if (!error) 288 error = iicbus_stop(parent); 289 290 return (error); 291 } 292 293 static int 294 iicsmb_sendb(device_t dev, u_char slave, char byte) 295 { 296 device_t parent = device_get_parent(dev); 297 int error, sent; 298 299 error = iicbus_start(parent, slave & ~LSB, 0); 300 301 if (!error) { 302 error = iicbus_write(parent, &byte, 1, &sent, 0); 303 304 iicbus_stop(parent); 305 } 306 307 return (error); 308 } 309 310 static int 311 iicsmb_recvb(device_t dev, u_char slave, char *byte) 312 { 313 device_t parent = device_get_parent(dev); 314 int error, read; 315 316 error = iicbus_start(parent, slave | LSB, 0); 317 318 if (!error) { 319 error = iicbus_read(parent, byte, 1, &read, IIC_LAST_READ, 0); 320 321 iicbus_stop(parent); 322 } 323 324 return (error); 325 } 326 327 static int 328 iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 329 { 330 device_t parent = device_get_parent(dev); 331 int error, sent; 332 333 error = iicbus_start(parent, slave & ~LSB, 0); 334 335 if (!error) { 336 if (!(error = iicbus_write(parent, &cmd, 1, &sent, 0))) 337 error = iicbus_write(parent, &byte, 1, &sent, 0); 338 339 iicbus_stop(parent); 340 } 341 342 return (error); 343 } 344 345 static int 346 iicsmb_writew(device_t dev, u_char slave, char cmd, short word) 347 { 348 device_t parent = device_get_parent(dev); 349 int error, sent; 350 351 char low = (char)(word & 0xff); 352 char high = (char)((word & 0xff00) >> 8); 353 354 error = iicbus_start(parent, slave & ~LSB, 0); 355 356 if (!error) { 357 if (!(error = iicbus_write(parent, &cmd, 1, &sent, 0))) 358 if (!(error = iicbus_write(parent, &low, 1, &sent, 0))) 359 error = iicbus_write(parent, &high, 1, &sent, 0); 360 361 iicbus_stop(parent); 362 } 363 364 return (error); 365 } 366 367 static int 368 iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 369 { 370 device_t parent = device_get_parent(dev); 371 int error, sent, read; 372 373 if ((error = iicbus_start(parent, slave & ~LSB, 0))) 374 return (error); 375 376 if ((error = iicbus_write(parent, &cmd, 1, &sent, 0))) 377 goto error; 378 379 if ((error = iicbus_repeated_start(parent, slave | LSB, 0))) 380 goto error; 381 382 if ((error = iicbus_read(parent, byte, 1, &read, IIC_LAST_READ, 0))) 383 goto error; 384 385 error: 386 iicbus_stop(parent); 387 return (error); 388 } 389 390 #define BUF2SHORT(low,high) \ 391 ((short)(((high) & 0xff) << 8) | (short)((low) & 0xff)) 392 393 static int 394 iicsmb_readw(device_t dev, u_char slave, char cmd, short *word) 395 { 396 device_t parent = device_get_parent(dev); 397 int error, sent, read; 398 char buf[2]; 399 400 if ((error = iicbus_start(parent, slave & ~LSB, 0))) 401 return (error); 402 403 if ((error = iicbus_write(parent, &cmd, 1, &sent, 0))) 404 goto error; 405 406 if ((error = iicbus_repeated_start(parent, slave | LSB, 0))) 407 goto error; 408 409 if ((error = iicbus_read(parent, buf, 2, &read, IIC_LAST_READ, 0))) 410 goto error; 411 412 /* first, receive low, then high byte */ 413 *word = BUF2SHORT(buf[0], buf[1]); 414 415 error: 416 iicbus_stop(parent); 417 return (error); 418 } 419 420 static int 421 iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 422 { 423 device_t parent = device_get_parent(dev); 424 int error, sent, read; 425 char buf[2]; 426 427 if ((error = iicbus_start(parent, slave & ~LSB, 0))) 428 return (error); 429 430 if ((error = iicbus_write(parent, &cmd, 1, &sent, 0))) 431 goto error; 432 433 /* first, send low, then high byte */ 434 buf[0] = (char)(sdata & 0xff); 435 buf[1] = (char)((sdata & 0xff00) >> 8); 436 437 if ((error = iicbus_write(parent, buf, 2, &sent, 0))) 438 goto error; 439 440 if ((error = iicbus_repeated_start(parent, slave | LSB, 0))) 441 goto error; 442 443 if ((error = iicbus_read(parent, buf, 2, &read, IIC_LAST_READ, 0))) 444 goto error; 445 446 /* first, receive low, then high byte */ 447 *rdata = BUF2SHORT(buf[0], buf[1]); 448 449 error: 450 iicbus_stop(parent); 451 return (error); 452 } 453 454 static int 455 iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 456 { 457 device_t parent = device_get_parent(dev); 458 int error, sent; 459 460 if ((error = iicbus_start(parent, slave & ~LSB, 0))) 461 goto error; 462 463 if ((error = iicbus_write(parent, &cmd, 1, &sent, 0))) 464 goto error; 465 466 if ((error = iicbus_write(parent, buf, (int)count, &sent, 0))) 467 goto error; 468 469 if ((error = iicbus_stop(parent))) 470 goto error; 471 472 error: 473 return (error); 474 } 475 476 static int 477 iicsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 478 { 479 device_t parent = device_get_parent(dev); 480 int error, sent, read; 481 482 if ((error = iicbus_start(parent, slave & ~LSB, 0))) 483 return (error); 484 485 if ((error = iicbus_write(parent, &cmd, 1, &sent, 0))) 486 goto error; 487 488 if ((error = iicbus_repeated_start(parent, slave | LSB, 0))) 489 goto error; 490 491 if ((error = iicbus_read(parent, buf, (int)count, &read, 492 IIC_LAST_READ, 0))) 493 goto error; 494 495 error: 496 iicbus_stop(parent); 497 return (error); 498 } 499 500 DRIVER_MODULE(iicsmb, iicbus, iicsmb_driver, iicsmb_devclass, 0, 0); 501