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