1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 1998, 2001 Nicolas Souchu 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 /* 33 * I2C to SMB bridge 34 * 35 * Example: 36 * 37 * smb bttv 38 * \ / 39 * smbus 40 * / \ 41 * iicsmb bti2c 42 * | 43 * iicbus 44 * / | \ 45 * iicbb pcf ... 46 * | 47 * lpbb 48 */ 49 50 #include <sys/param.h> 51 #include <sys/bus.h> 52 #include <sys/kernel.h> 53 #include <sys/lock.h> 54 #include <sys/module.h> 55 #include <sys/mutex.h> 56 #include <sys/systm.h> 57 #include <sys/uio.h> 58 59 #include <dev/iicbus/iiconf.h> 60 #include <dev/iicbus/iicbus.h> 61 62 #include <dev/smbus/smb.h> 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 struct mtx lock; 82 device_t smbus; 83 }; 84 85 static int iicsmb_probe(device_t); 86 static int iicsmb_attach(device_t); 87 static int iicsmb_detach(device_t); 88 static void iicsmb_identify(driver_t *driver, device_t parent); 89 90 static int iicsmb_intr(device_t dev, int event, char *buf); 91 static int iicsmb_callback(device_t dev, int index, void *data); 92 static int iicsmb_quick(device_t dev, u_char slave, int how); 93 static int iicsmb_sendb(device_t dev, u_char slave, char byte); 94 static int iicsmb_recvb(device_t dev, u_char slave, char *byte); 95 static int iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte); 96 static int iicsmb_writew(device_t dev, u_char slave, char cmd, short word); 97 static int iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte); 98 static int iicsmb_readw(device_t dev, u_char slave, char cmd, short *word); 99 static int iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata); 100 static int iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); 101 static int iicsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf); 102 103 static devclass_t iicsmb_devclass; 104 105 static device_method_t iicsmb_methods[] = { 106 /* device interface */ 107 DEVMETHOD(device_identify, iicsmb_identify), 108 DEVMETHOD(device_probe, iicsmb_probe), 109 DEVMETHOD(device_attach, iicsmb_attach), 110 DEVMETHOD(device_detach, iicsmb_detach), 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 DEVMETHOD_END 129 }; 130 131 static driver_t iicsmb_driver = { 132 "iicsmb", 133 iicsmb_methods, 134 sizeof(struct iicsmb_softc), 135 }; 136 137 static void 138 iicsmb_identify(driver_t *driver, device_t parent) 139 { 140 141 if (device_find_child(parent, "iicsmb", -1) == NULL) 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 (BUS_PROBE_NOWILDCARD); 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 mtx_init(&sc->lock, "iicsmb", NULL, MTX_DEF); 158 159 sc->smbus = device_add_child(dev, "smbus", -1); 160 161 /* probe and attach the smbus */ 162 bus_generic_attach(dev); 163 164 return (0); 165 } 166 167 static int 168 iicsmb_detach(device_t dev) 169 { 170 struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev); 171 172 bus_generic_detach(dev); 173 device_delete_children(dev); 174 mtx_destroy(&sc->lock); 175 176 return (0); 177 } 178 179 /* 180 * iicsmb_intr() 181 * 182 * iicbus interrupt handler 183 */ 184 static int 185 iicsmb_intr(device_t dev, int event, char *buf) 186 { 187 struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev); 188 189 mtx_lock(&sc->lock); 190 switch (event) { 191 case INTR_GENERAL: 192 case INTR_START: 193 sc->state = SMB_WAITING_ADDR; 194 break; 195 196 case INTR_STOP: 197 /* call smbus intr handler */ 198 smbus_intr(sc->smbus, sc->devaddr, 199 sc->low, sc->high, SMB_ENOERR); 200 break; 201 202 case INTR_RECEIVE: 203 switch (sc->state) { 204 case SMB_DONE: 205 /* XXX too much data, discard */ 206 printf("%s: too much data from 0x%x\n", __func__, 207 sc->devaddr & 0xff); 208 goto end; 209 210 case SMB_WAITING_ADDR: 211 sc->devaddr = (u_char)*buf; 212 sc->state = SMB_WAITING_LOW; 213 break; 214 215 case SMB_WAITING_LOW: 216 sc->low = *buf; 217 sc->state = SMB_WAITING_HIGH; 218 break; 219 220 case SMB_WAITING_HIGH: 221 sc->high = *buf; 222 sc->state = SMB_DONE; 223 break; 224 } 225 end: 226 break; 227 228 case INTR_TRANSMIT: 229 case INTR_NOACK: 230 break; 231 232 case INTR_ERROR: 233 switch (*buf) { 234 case IIC_EBUSERR: 235 smbus_intr(sc->smbus, sc->devaddr, 0, 0, SMB_EBUSERR); 236 break; 237 238 default: 239 printf("%s unknown error 0x%x!\n", __func__, 240 (int)*buf); 241 break; 242 } 243 break; 244 245 default: 246 panic("%s: unknown event (%d)!", __func__, event); 247 } 248 mtx_unlock(&sc->lock); 249 250 return (0); 251 } 252 253 static int 254 iicsmb_callback(device_t dev, int index, void *data) 255 { 256 device_t parent = device_get_parent(dev); 257 int error = 0; 258 int how; 259 260 switch (index) { 261 case SMB_REQUEST_BUS: 262 /* request underlying iicbus */ 263 how = *(int *)data; 264 error = iicbus_request_bus(parent, dev, how); 265 break; 266 267 case SMB_RELEASE_BUS: 268 /* release underlying iicbus */ 269 error = iicbus_release_bus(parent, dev); 270 break; 271 272 default: 273 error = EINVAL; 274 } 275 276 return (error); 277 } 278 279 static int 280 iic2smb_error(int error) 281 { 282 switch (error) { 283 case IIC_NOERR: 284 return (SMB_ENOERR); 285 case IIC_EBUSERR: 286 return (SMB_EBUSERR); 287 case IIC_ENOACK: 288 return (SMB_ENOACK); 289 case IIC_ETIMEOUT: 290 return (SMB_ETIMEOUT); 291 case IIC_EBUSBSY: 292 return (SMB_EBUSY); 293 case IIC_ESTATUS: 294 return (SMB_EBUSERR); 295 case IIC_EUNDERFLOW: 296 return (SMB_EBUSERR); 297 case IIC_EOVERFLOW: 298 return (SMB_EBUSERR); 299 case IIC_ENOTSUPP: 300 return (SMB_ENOTSUPP); 301 case IIC_ENOADDR: 302 return (SMB_EBUSERR); 303 case IIC_ERESOURCE: 304 return (SMB_EBUSERR); 305 default: 306 return (SMB_EBUSERR); 307 } 308 } 309 310 #define TRANSFER_MSGS(dev, msgs) iicbus_transfer(dev, msgs, nitems(msgs)) 311 312 static int 313 iicsmb_quick(device_t dev, u_char slave, int how) 314 { 315 struct iic_msg msgs[] = { 316 { slave, how == SMB_QWRITE ? IIC_M_WR : IIC_M_RD, 0, NULL }, 317 }; 318 int error; 319 320 switch (how) { 321 case SMB_QWRITE: 322 case SMB_QREAD: 323 break; 324 default: 325 return (SMB_EINVAL); 326 } 327 328 error = TRANSFER_MSGS(dev, msgs); 329 return (iic2smb_error(error)); 330 } 331 332 static int 333 iicsmb_sendb(device_t dev, u_char slave, char byte) 334 { 335 struct iic_msg msgs[] = { 336 { slave, IIC_M_WR, 1, &byte }, 337 }; 338 int error; 339 340 error = TRANSFER_MSGS(dev, msgs); 341 return (iic2smb_error(error)); 342 } 343 344 static int 345 iicsmb_recvb(device_t dev, u_char slave, char *byte) 346 { 347 struct iic_msg msgs[] = { 348 { slave, IIC_M_RD, 1, byte }, 349 }; 350 int error; 351 352 error = TRANSFER_MSGS(dev, msgs); 353 return (iic2smb_error(error)); 354 } 355 356 static int 357 iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 358 { 359 uint8_t bytes[] = { cmd, byte }; 360 struct iic_msg msgs[] = { 361 { slave, IIC_M_WR, nitems(bytes), bytes }, 362 }; 363 int error; 364 365 error = TRANSFER_MSGS(dev, msgs); 366 return (iic2smb_error(error)); 367 } 368 369 static int 370 iicsmb_writew(device_t dev, u_char slave, char cmd, short word) 371 { 372 uint8_t bytes[] = { cmd, word & 0xff, word >> 8 }; 373 struct iic_msg msgs[] = { 374 { slave, IIC_M_WR, nitems(bytes), bytes }, 375 }; 376 int error; 377 378 error = TRANSFER_MSGS(dev, msgs); 379 return (iic2smb_error(error)); 380 } 381 382 static int 383 iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 384 { 385 struct iic_msg msgs[] = { 386 { slave, IIC_M_WR | IIC_M_NOSTOP, 1, &cmd }, 387 { slave, IIC_M_RD, 1, byte }, 388 }; 389 int error; 390 391 error = TRANSFER_MSGS(dev, msgs); 392 return (iic2smb_error(error)); 393 } 394 395 static int 396 iicsmb_readw(device_t dev, u_char slave, char cmd, short *word) 397 { 398 uint8_t buf[2]; 399 struct iic_msg msgs[] = { 400 { slave, IIC_M_WR | IIC_M_NOSTOP, 1, &cmd }, 401 { slave, IIC_M_RD, nitems(buf), buf }, 402 }; 403 int error; 404 405 error = TRANSFER_MSGS(dev, msgs); 406 if (error == 0) 407 *word = ((uint16_t)buf[1] << 8) | buf[0]; 408 return (iic2smb_error(error)); 409 } 410 411 static int 412 iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 413 { 414 uint8_t in[3] = { cmd, sdata & 0xff, sdata >> 8 }; 415 uint8_t out[2]; 416 struct iic_msg msgs[] = { 417 { slave, IIC_M_WR | IIC_M_NOSTOP, nitems(in), in }, 418 { slave, IIC_M_RD, nitems(out), out }, 419 }; 420 int error; 421 422 error = TRANSFER_MSGS(dev, msgs); 423 if (error == 0) 424 *rdata = ((uint16_t)out[1] << 8) | out[0]; 425 return (iic2smb_error(error)); 426 } 427 428 static int 429 iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 430 { 431 uint8_t bytes[2] = { cmd, count }; 432 struct iic_msg msgs[] = { 433 { slave, IIC_M_WR | IIC_M_NOSTOP, nitems(bytes), bytes }, 434 { slave, IIC_M_WR | IIC_M_NOSTART, count, buf }, 435 }; 436 int error; 437 438 if (count > SMB_MAXBLOCKSIZE || count == 0) 439 return (SMB_EINVAL); 440 error = TRANSFER_MSGS(dev, msgs); 441 return (iic2smb_error(error)); 442 } 443 444 static int 445 iicsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 446 { 447 struct iic_msg msgs[] = { 448 { slave, IIC_M_WR | IIC_M_NOSTOP, 1, &cmd }, 449 { slave, IIC_M_RD | IIC_M_NOSTOP, 1, count }, 450 }; 451 struct iic_msg block_msg[] = { 452 { slave, IIC_M_RD | IIC_M_NOSTART, 0, buf }, 453 }; 454 device_t parent = device_get_parent(dev); 455 int error; 456 457 /* Have to do this because the command is split in two transfers. */ 458 error = iicbus_request_bus(parent, dev, IIC_WAIT); 459 if (error == 0) 460 error = TRANSFER_MSGS(dev, msgs); 461 if (error == 0) { 462 /* 463 * If the slave offers an empty or a too long reply, 464 * read one byte to generate the stop or abort. 465 */ 466 if (*count > SMB_MAXBLOCKSIZE || *count == 0) 467 block_msg[0].len = 1; 468 else 469 block_msg[0].len = *count; 470 error = TRANSFER_MSGS(dev, block_msg); 471 if (*count > SMB_MAXBLOCKSIZE || *count == 0) 472 error = SMB_EINVAL; 473 } 474 (void)iicbus_release_bus(parent, dev); 475 return (iic2smb_error(error)); 476 } 477 478 DRIVER_MODULE(iicsmb, iicbus, iicsmb_driver, iicsmb_devclass, 0, 0); 479 DRIVER_MODULE(smbus, iicsmb, smbus_driver, smbus_devclass, 0, 0); 480 MODULE_DEPEND(iicsmb, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); 481 MODULE_DEPEND(iicsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 482 MODULE_VERSION(iicsmb, 1); 483