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 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 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 struct mtx lock; 79 device_t smbus; 80 }; 81 82 static int iicsmb_probe(device_t); 83 static int iicsmb_attach(device_t); 84 static int iicsmb_detach(device_t); 85 static void iicsmb_identify(driver_t *driver, device_t parent); 86 87 static int iicsmb_intr(device_t dev, int event, char *buf); 88 static int iicsmb_callback(device_t dev, int index, void *data); 89 static int iicsmb_quick(device_t dev, u_char slave, int how); 90 static int iicsmb_sendb(device_t dev, u_char slave, char byte); 91 static int iicsmb_recvb(device_t dev, u_char slave, char *byte); 92 static int iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte); 93 static int iicsmb_writew(device_t dev, u_char slave, char cmd, short word); 94 static int iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte); 95 static int iicsmb_readw(device_t dev, u_char slave, char cmd, short *word); 96 static int iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata); 97 static int iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); 98 static int iicsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf); 99 100 static devclass_t iicsmb_devclass; 101 102 static device_method_t iicsmb_methods[] = { 103 /* device interface */ 104 DEVMETHOD(device_identify, iicsmb_identify), 105 DEVMETHOD(device_probe, iicsmb_probe), 106 DEVMETHOD(device_attach, iicsmb_attach), 107 DEVMETHOD(device_detach, iicsmb_detach), 108 109 /* iicbus interface */ 110 DEVMETHOD(iicbus_intr, iicsmb_intr), 111 112 /* smbus interface */ 113 DEVMETHOD(smbus_callback, iicsmb_callback), 114 DEVMETHOD(smbus_quick, iicsmb_quick), 115 DEVMETHOD(smbus_sendb, iicsmb_sendb), 116 DEVMETHOD(smbus_recvb, iicsmb_recvb), 117 DEVMETHOD(smbus_writeb, iicsmb_writeb), 118 DEVMETHOD(smbus_writew, iicsmb_writew), 119 DEVMETHOD(smbus_readb, iicsmb_readb), 120 DEVMETHOD(smbus_readw, iicsmb_readw), 121 DEVMETHOD(smbus_pcall, iicsmb_pcall), 122 DEVMETHOD(smbus_bwrite, iicsmb_bwrite), 123 DEVMETHOD(smbus_bread, iicsmb_bread), 124 125 DEVMETHOD_END 126 }; 127 128 static driver_t iicsmb_driver = { 129 "iicsmb", 130 iicsmb_methods, 131 sizeof(struct iicsmb_softc), 132 }; 133 134 static void 135 iicsmb_identify(driver_t *driver, device_t parent) 136 { 137 138 if (device_find_child(parent, "iicsmb", -1) == NULL) 139 BUS_ADD_CHILD(parent, 0, "iicsmb", -1); 140 } 141 142 static int 143 iicsmb_probe(device_t dev) 144 { 145 device_set_desc(dev, "SMBus over I2C bridge"); 146 return (BUS_PROBE_NOWILDCARD); 147 } 148 149 static int 150 iicsmb_attach(device_t dev) 151 { 152 struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev); 153 154 mtx_init(&sc->lock, "iicsmb", NULL, MTX_DEF); 155 156 sc->smbus = device_add_child(dev, "smbus", -1); 157 158 /* probe and attach the smbus */ 159 bus_generic_attach(dev); 160 161 return (0); 162 } 163 164 static int 165 iicsmb_detach(device_t dev) 166 { 167 struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev); 168 169 bus_generic_detach(dev); 170 device_delete_children(dev); 171 mtx_destroy(&sc->lock); 172 173 return (0); 174 } 175 176 /* 177 * iicsmb_intr() 178 * 179 * iicbus interrupt handler 180 */ 181 static int 182 iicsmb_intr(device_t dev, int event, char *buf) 183 { 184 struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev); 185 186 mtx_lock(&sc->lock); 187 switch (event) { 188 case INTR_GENERAL: 189 case INTR_START: 190 sc->state = SMB_WAITING_ADDR; 191 break; 192 193 case INTR_STOP: 194 /* call smbus intr handler */ 195 smbus_intr(sc->smbus, sc->devaddr, 196 sc->low, sc->high, SMB_ENOERR); 197 break; 198 199 case INTR_RECEIVE: 200 switch (sc->state) { 201 case SMB_DONE: 202 /* XXX too much data, discard */ 203 printf("%s: too much data from 0x%x\n", __func__, 204 sc->devaddr & 0xff); 205 goto end; 206 207 case SMB_WAITING_ADDR: 208 sc->devaddr = (u_char)*buf; 209 sc->state = SMB_WAITING_LOW; 210 break; 211 212 case SMB_WAITING_LOW: 213 sc->low = *buf; 214 sc->state = SMB_WAITING_HIGH; 215 break; 216 217 case SMB_WAITING_HIGH: 218 sc->high = *buf; 219 sc->state = SMB_DONE; 220 break; 221 } 222 end: 223 break; 224 225 case INTR_TRANSMIT: 226 case INTR_NOACK: 227 break; 228 229 case INTR_ERROR: 230 switch (*buf) { 231 case IIC_EBUSERR: 232 smbus_intr(sc->smbus, sc->devaddr, 0, 0, SMB_EBUSERR); 233 break; 234 235 default: 236 printf("%s unknown error 0x%x!\n", __func__, 237 (int)*buf); 238 break; 239 } 240 break; 241 242 default: 243 panic("%s: unknown event (%d)!", __func__, event); 244 } 245 mtx_unlock(&sc->lock); 246 247 return (0); 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 error = iicbus_request_bus(parent, dev, how); 262 break; 263 264 case SMB_RELEASE_BUS: 265 /* release underlying iicbus */ 266 error = iicbus_release_bus(parent, dev); 267 break; 268 269 default: 270 error = EINVAL; 271 } 272 273 return (error); 274 } 275 276 static int 277 iic2smb_error(int error) 278 { 279 switch (error) { 280 case IIC_NOERR: 281 return (SMB_ENOERR); 282 case IIC_EBUSERR: 283 return (SMB_EBUSERR); 284 case IIC_ENOACK: 285 return (SMB_ENOACK); 286 case IIC_ETIMEOUT: 287 return (SMB_ETIMEOUT); 288 case IIC_EBUSBSY: 289 return (SMB_EBUSY); 290 case IIC_ESTATUS: 291 return (SMB_EBUSERR); 292 case IIC_EUNDERFLOW: 293 return (SMB_EBUSERR); 294 case IIC_EOVERFLOW: 295 return (SMB_EBUSERR); 296 case IIC_ENOTSUPP: 297 return (SMB_ENOTSUPP); 298 case IIC_ENOADDR: 299 return (SMB_EBUSERR); 300 case IIC_ERESOURCE: 301 return (SMB_EBUSERR); 302 default: 303 return (SMB_EBUSERR); 304 } 305 } 306 307 #define TRANSFER_MSGS(dev, msgs) iicbus_transfer(dev, msgs, nitems(msgs)) 308 309 static int 310 iicsmb_quick(device_t dev, u_char slave, int how) 311 { 312 struct iic_msg msgs[] = { 313 { slave, how == SMB_QWRITE ? IIC_M_WR : IIC_M_RD, 0, NULL }, 314 }; 315 int error; 316 317 switch (how) { 318 case SMB_QWRITE: 319 case SMB_QREAD: 320 break; 321 default: 322 return (SMB_EINVAL); 323 } 324 325 error = TRANSFER_MSGS(dev, msgs); 326 return (iic2smb_error(error)); 327 } 328 329 static int 330 iicsmb_sendb(device_t dev, u_char slave, char byte) 331 { 332 struct iic_msg msgs[] = { 333 { slave, IIC_M_WR, 1, &byte }, 334 }; 335 int error; 336 337 error = TRANSFER_MSGS(dev, msgs); 338 return (iic2smb_error(error)); 339 } 340 341 static int 342 iicsmb_recvb(device_t dev, u_char slave, char *byte) 343 { 344 struct iic_msg msgs[] = { 345 { slave, IIC_M_RD, 1, byte }, 346 }; 347 int error; 348 349 error = TRANSFER_MSGS(dev, msgs); 350 return (iic2smb_error(error)); 351 } 352 353 static int 354 iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 355 { 356 uint8_t bytes[] = { cmd, byte }; 357 struct iic_msg msgs[] = { 358 { slave, IIC_M_WR, nitems(bytes), bytes }, 359 }; 360 int error; 361 362 error = TRANSFER_MSGS(dev, msgs); 363 return (iic2smb_error(error)); 364 } 365 366 static int 367 iicsmb_writew(device_t dev, u_char slave, char cmd, short word) 368 { 369 uint8_t bytes[] = { cmd, word & 0xff, word >> 8 }; 370 struct iic_msg msgs[] = { 371 { slave, IIC_M_WR, nitems(bytes), bytes }, 372 }; 373 int error; 374 375 error = TRANSFER_MSGS(dev, msgs); 376 return (iic2smb_error(error)); 377 } 378 379 static int 380 iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 381 { 382 struct iic_msg msgs[] = { 383 { slave, IIC_M_WR | IIC_M_NOSTOP, 1, &cmd }, 384 { slave, IIC_M_RD, 1, byte }, 385 }; 386 int error; 387 388 error = TRANSFER_MSGS(dev, msgs); 389 return (iic2smb_error(error)); 390 } 391 392 static int 393 iicsmb_readw(device_t dev, u_char slave, char cmd, short *word) 394 { 395 uint8_t buf[2]; 396 struct iic_msg msgs[] = { 397 { slave, IIC_M_WR | IIC_M_NOSTOP, 1, &cmd }, 398 { slave, IIC_M_RD, nitems(buf), buf }, 399 }; 400 int error; 401 402 error = TRANSFER_MSGS(dev, msgs); 403 if (error == 0) 404 *word = ((uint16_t)buf[1] << 8) | buf[0]; 405 return (iic2smb_error(error)); 406 } 407 408 static int 409 iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 410 { 411 uint8_t in[3] = { cmd, sdata & 0xff, sdata >> 8 }; 412 uint8_t out[2]; 413 struct iic_msg msgs[] = { 414 { slave, IIC_M_WR | IIC_M_NOSTOP, nitems(in), in }, 415 { slave, IIC_M_RD, nitems(out), out }, 416 }; 417 int error; 418 419 error = TRANSFER_MSGS(dev, msgs); 420 if (error == 0) 421 *rdata = ((uint16_t)out[1] << 8) | out[0]; 422 return (iic2smb_error(error)); 423 } 424 425 static int 426 iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 427 { 428 uint8_t bytes[2] = { cmd, count }; 429 struct iic_msg msgs[] = { 430 { slave, IIC_M_WR | IIC_M_NOSTOP, nitems(bytes), bytes }, 431 { slave, IIC_M_WR | IIC_M_NOSTART, count, buf }, 432 }; 433 int error; 434 435 if (count > 32 || count == 0) 436 return (SMB_EINVAL); 437 error = TRANSFER_MSGS(dev, msgs); 438 return (iic2smb_error(error)); 439 } 440 441 static int 442 iicsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 443 { 444 struct iic_msg msgs[] = { 445 { slave, IIC_M_WR | IIC_M_NOSTOP, 1, &cmd }, 446 { slave, IIC_M_RD | IIC_M_NOSTOP, 1, count }, 447 }; 448 struct iic_msg block_msg[] = { 449 { slave, IIC_M_RD | IIC_M_NOSTART, 0, buf }, 450 }; 451 device_t parent = device_get_parent(dev); 452 int error; 453 u_char bufsz; 454 455 /* Stash output buffer size before overwriting it. */ 456 bufsz = *count; 457 if (bufsz == 0) 458 return (SMB_EINVAL); 459 460 /* Have to do this because the command is split in two transfers. */ 461 error = iicbus_request_bus(parent, dev, IIC_WAIT); 462 if (error == 0) 463 error = TRANSFER_MSGS(dev, msgs); 464 if (error == 0) { 465 /* 466 * If the slave offers an empty or a too long reply, 467 * read one byte to generate the stop or abort. 468 * XXX 32 is hardcoded until SMB_MAXBLOCKSIZE is restored 469 * to sanity. 470 */ 471 if (*count > 32 || *count == 0) 472 block_msg[0].len = 1; 473 /* If longer than the buffer, then clamp at the buffer size. */ 474 if (*count > bufsz) 475 block_msg[0].len = bufsz; 476 else 477 block_msg[0].len = *count; 478 error = TRANSFER_MSGS(dev, block_msg); 479 if (*count > 32 || *count == 0) 480 error = SMB_EINVAL; 481 } 482 (void)iicbus_release_bus(parent, dev); 483 return (iic2smb_error(error)); 484 } 485 486 DRIVER_MODULE(iicsmb, iicbus, iicsmb_driver, iicsmb_devclass, 0, 0); 487 DRIVER_MODULE(smbus, iicsmb, smbus_driver, smbus_devclass, 0, 0); 488 MODULE_DEPEND(iicsmb, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); 489 MODULE_DEPEND(iicsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 490 MODULE_VERSION(iicsmb, 1); 491