1 /* $NetBSD: i2c_exec.c,v 1.16 2020/04/19 17:08:14 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 2003 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: i2c_exec.c,v 1.16 2020/04/19 17:08:14 thorpej Exp $"); 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/cpu.h> 44 #include <sys/device.h> 45 #include <sys/module.h> 46 #include <sys/event.h> 47 #include <sys/conf.h> 48 #include <sys/kernel.h> 49 50 #define _I2C_PRIVATE 51 #include <dev/i2c/i2cvar.h> 52 53 static uint8_t iic_smbus_crc8(uint16_t); 54 static uint8_t iic_smbus_pec(int, uint8_t *, uint8_t *); 55 56 static int i2cexec_modcmd(modcmd_t, void *); 57 58 static inline int 59 iic_op_flags(int flags) 60 { 61 62 return flags | ((cold || shutting_down) ? I2C_F_POLL : 0); 63 } 64 65 /* 66 * iic_tag_init: 67 * 68 * Perform some basic initialization of the i2c controller tag. 69 */ 70 void 71 iic_tag_init(i2c_tag_t tag) 72 { 73 74 memset(tag, 0, sizeof(*tag)); 75 mutex_init(&tag->ic_bus_lock, MUTEX_DEFAULT, IPL_NONE); 76 LIST_INIT(&tag->ic_list); 77 LIST_INIT(&tag->ic_proc_list); 78 } 79 80 /* 81 * iic_tag_fini: 82 * 83 * Teardown of the i2c controller tag. 84 */ 85 void 86 iic_tag_fini(i2c_tag_t tag) 87 { 88 89 mutex_destroy(&tag->ic_bus_lock); 90 } 91 92 /* 93 * iic_acquire_bus: 94 * 95 * Acquire the I2C bus for use by a client. 96 */ 97 int 98 iic_acquire_bus(i2c_tag_t tag, int flags) 99 { 100 101 #if 0 /* XXX Not quite ready for this yet. */ 102 KASSERT(!cpu_intr_p()); 103 #endif 104 105 flags = iic_op_flags(flags); 106 107 if (flags & I2C_F_POLL) { 108 /* 109 * Polling should only be used in rare and/or 110 * extreme circumstances; most i2c clients 111 * should be allowed to sleep. 112 * 113 * Really, the ONLY user of I2C_F_POLL should be 114 * "when cold", i.e. during early autoconfiguration 115 * when there is only proc0, and we might have to 116 * read SEEPROMs, etc. There should be no other 117 * users interfering with our access of the i2c bus 118 * in that case. 119 */ 120 if (mutex_tryenter(&tag->ic_bus_lock) == 0) { 121 return EBUSY; 122 } 123 } else { 124 /* 125 * N.B. We implement this as a mutex that we hold across 126 * across a series of requests beause we'd like to get the 127 * priority boost if a higher-priority process wants the 128 * i2c bus while we're asleep waiting for the controller 129 * to perform the I/O. 130 * 131 * XXXJRT Disable preemption here? We'd like to keep 132 * the CPU while holding this resource, unless we release 133 * it voluntarily (which should only happen while waiting 134 * for a controller to complete I/O). 135 */ 136 mutex_enter(&tag->ic_bus_lock); 137 } 138 139 int error = 0; 140 if (tag->ic_acquire_bus) { 141 error = (*tag->ic_acquire_bus)(tag->ic_cookie, flags); 142 } 143 144 if (__predict_false(error)) { 145 mutex_exit(&tag->ic_bus_lock); 146 } 147 148 return error; 149 } 150 151 /* 152 * iic_release_bus: 153 * 154 * Relese the I2C bus, allowing another client to use it. 155 */ 156 void 157 iic_release_bus(i2c_tag_t tag, int flags) 158 { 159 160 #if 0 /* XXX Not quite ready for this yet. */ 161 KASSERT(!cpu_intr_p()); 162 #endif 163 164 flags = iic_op_flags(flags); 165 166 if (tag->ic_release_bus) { 167 (*tag->ic_release_bus)(tag->ic_cookie, flags); 168 } 169 170 mutex_exit(&tag->ic_bus_lock); 171 } 172 173 /* 174 * iic_exec: 175 * 176 * Simplified I2C client interface engine. 177 * 178 * This and the SMBus routines are the preferred interface for 179 * client access to I2C/SMBus, since many automated controllers 180 * do not provide access to the low-level primitives of the I2C 181 * bus protocol. 182 */ 183 int 184 iic_exec(i2c_tag_t tag, i2c_op_t op, i2c_addr_t addr, const void *vcmd, 185 size_t cmdlen, void *vbuf, size_t buflen, int flags) 186 { 187 const uint8_t *cmd = vcmd; 188 uint8_t *buf = vbuf; 189 int error; 190 size_t len; 191 192 #if 0 /* XXX Not quite ready for this yet. */ 193 KASSERT(!cpu_intr_p()); 194 #endif 195 196 flags = iic_op_flags(flags); 197 198 if ((flags & I2C_F_PEC) && cmdlen > 0 && tag->ic_exec != NULL) { 199 uint8_t data[33]; /* XXX */ 200 uint8_t b[3]; 201 202 b[0] = addr << 1; 203 b[1] = cmd[0]; 204 205 switch (buflen) { 206 case 0: 207 data[0] = iic_smbus_pec(2, b, NULL); 208 buflen++; 209 break; 210 case 1: 211 b[2] = buf[0]; 212 data[0] = iic_smbus_pec(3, b, NULL); 213 data[1] = b[2]; 214 buflen++; 215 break; 216 case 2: 217 break; 218 default: 219 KASSERT(buflen+1 < sizeof(data)); 220 memcpy(data, vbuf, buflen); 221 data[buflen] = iic_smbus_pec(2, b, data); 222 buflen++; 223 break; 224 } 225 226 return ((*tag->ic_exec)(tag->ic_cookie, op, addr, cmd, 227 cmdlen, data, buflen, flags)); 228 } 229 230 /* 231 * Defer to the controller if it provides an exec function. Use 232 * it if it does. 233 */ 234 if (tag->ic_exec != NULL) 235 return ((*tag->ic_exec)(tag->ic_cookie, op, addr, cmd, 236 cmdlen, buf, buflen, flags)); 237 238 if ((len = cmdlen) != 0) { 239 if ((error = iic_initiate_xfer(tag, addr, flags)) != 0) 240 goto bad; 241 while (len--) { 242 if ((error = iic_write_byte(tag, *cmd++, flags)) != 0) 243 goto bad; 244 } 245 } else if (buflen == 0) { 246 /* 247 * This is a quick_read()/quick_write() command with 248 * neither command nor data bytes 249 */ 250 if (I2C_OP_STOP_P(op)) 251 flags |= I2C_F_STOP; 252 if (I2C_OP_READ_P(op)) 253 flags |= I2C_F_READ; 254 if ((error = iic_initiate_xfer(tag, addr, flags)) != 0) 255 goto bad; 256 } 257 258 if (I2C_OP_READ_P(op)) 259 flags |= I2C_F_READ; 260 261 len = buflen; 262 while (len--) { 263 if (len == 0 && I2C_OP_STOP_P(op)) 264 flags |= I2C_F_STOP; 265 if (I2C_OP_READ_P(op)) { 266 /* Send REPEATED START. */ 267 if ((len + 1) == buflen && 268 (error = iic_initiate_xfer(tag, addr, flags)) != 0) 269 goto bad; 270 /* NACK on last byte. */ 271 if (len == 0) 272 flags |= I2C_F_LAST; 273 if ((error = iic_read_byte(tag, buf++, flags)) != 0) 274 goto bad; 275 } else { 276 /* Maybe send START. */ 277 if ((len + 1) == buflen && cmdlen == 0 && 278 (error = iic_initiate_xfer(tag, addr, flags)) != 0) 279 goto bad; 280 if ((error = iic_write_byte(tag, *buf++, flags)) != 0) 281 goto bad; 282 } 283 } 284 285 return (0); 286 bad: 287 iic_send_stop(tag, flags); 288 return (error); 289 } 290 291 /* 292 * iic_smbus_write_byte: 293 * 294 * Perform an SMBus "write byte" operation. 295 */ 296 int 297 iic_smbus_write_byte(i2c_tag_t tag, i2c_addr_t addr, uint8_t cmd, 298 uint8_t val, int flags) 299 { 300 301 return (iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &cmd, 1, 302 &val, 1, flags)); 303 } 304 305 /* 306 * iic_smbus_write_word: 307 * 308 * Perform an SMBus "write word" operation. 309 */ 310 int 311 iic_smbus_write_word(i2c_tag_t tag, i2c_addr_t addr, uint8_t cmd, 312 uint16_t val, int flags) 313 { 314 uint8_t vbuf[2]; 315 316 vbuf[0] = val & 0xff; 317 vbuf[1] = (val >> 8) & 0xff; 318 319 return (iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &cmd, 1, 320 vbuf, 2, flags)); 321 } 322 323 /* 324 * iic_smbus_read_byte: 325 * 326 * Perform an SMBus "read byte" operation. 327 */ 328 int 329 iic_smbus_read_byte(i2c_tag_t tag, i2c_addr_t addr, uint8_t cmd, 330 uint8_t *valp, int flags) 331 { 332 333 return (iic_exec(tag, I2C_OP_READ_WITH_STOP, addr, &cmd, 1, 334 valp, 1, flags)); 335 } 336 337 /* 338 * iic_smbus_read_word: 339 * 340 * Perform an SMBus "read word" operation. 341 */ 342 int 343 iic_smbus_read_word(i2c_tag_t tag, i2c_addr_t addr, uint8_t cmd, 344 uint16_t *valp, int flags) 345 { 346 347 return (iic_exec(tag, I2C_OP_READ_WITH_STOP, addr, &cmd, 1, 348 (uint8_t *)valp, 2, flags)); 349 } 350 351 /* 352 * iic_smbus_receive_byte: 353 * 354 * Perform an SMBus "receive byte" operation. 355 */ 356 int 357 iic_smbus_receive_byte(i2c_tag_t tag, i2c_addr_t addr, uint8_t *valp, 358 int flags) 359 { 360 361 return (iic_exec(tag, I2C_OP_READ_WITH_STOP, addr, NULL, 0, 362 valp, 1, flags)); 363 } 364 365 /* 366 * iic_smbus_send_byte: 367 * 368 * Perform an SMBus "send byte" operation. 369 */ 370 int 371 iic_smbus_send_byte(i2c_tag_t tag, i2c_addr_t addr, uint8_t val, int flags) 372 { 373 374 return (iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, NULL, 0, 375 &val, 1, flags)); 376 } 377 378 /* 379 * iic_smbus_quick_read: 380 * 381 * Perform an SMBus "quick read" operation. 382 */ 383 int 384 iic_smbus_quick_read(i2c_tag_t tag, i2c_addr_t addr, int flags) 385 { 386 387 return (iic_exec(tag, I2C_OP_READ_WITH_STOP, addr, NULL, 0, 388 NULL, 0, flags)); 389 } 390 391 /* 392 * iic_smbus_quick_write: 393 * 394 * Perform an SMBus "quick write" operation. 395 */ 396 int 397 iic_smbus_quick_write(i2c_tag_t tag, i2c_addr_t addr, int flags) 398 { 399 400 return (iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, NULL, 0, 401 NULL, 0, flags)); 402 } 403 404 /* 405 * iic_smbus_block_read: 406 * 407 * Perform an SMBus "block read" operation. 408 */ 409 int 410 iic_smbus_block_read(i2c_tag_t tag, i2c_addr_t addr, uint8_t cmd, 411 uint8_t *vbuf, size_t buflen, int flags) 412 { 413 414 return (iic_exec(tag, I2C_OP_READ_BLOCK, addr, &cmd, 1, 415 vbuf, buflen, flags)); 416 } 417 418 /* 419 * iic_smbus_block_write: 420 * 421 * Perform an SMBus "block write" operation. 422 */ 423 int 424 iic_smbus_block_write(i2c_tag_t tag, i2c_addr_t addr, uint8_t cmd, 425 uint8_t *vbuf, size_t buflen, int flags) 426 { 427 428 return (iic_exec(tag, I2C_OP_WRITE_BLOCK, addr, &cmd, 1, 429 vbuf, buflen, flags)); 430 } 431 432 /* 433 * iic_smbus_crc8 434 * 435 * Private helper for calculating packet error checksum 436 */ 437 static uint8_t 438 iic_smbus_crc8(uint16_t data) 439 { 440 int i; 441 442 for (i = 0; i < 8; i++) { 443 if (data & 0x8000) 444 data = data ^ (0x1070U << 3); 445 data = data << 1; 446 } 447 448 return (uint8_t)(data >> 8); 449 } 450 451 /* 452 * iic_smbus_pec 453 * 454 * Private function for calculating packet error checking on SMBus 455 * packets. 456 */ 457 static uint8_t 458 iic_smbus_pec(int count, uint8_t *s, uint8_t *r) 459 { 460 int i; 461 uint8_t crc = 0; 462 463 for (i = 0; i < count; i++) 464 crc = iic_smbus_crc8((crc ^ s[i]) << 8); 465 if (r != NULL) 466 for (i = 0; i <= r[0]; i++) 467 crc = iic_smbus_crc8((crc ^ r[i]) << 8); 468 469 return crc; 470 } 471 472 MODULE(MODULE_CLASS_MISC, i2cexec, NULL); 473 474 static int 475 i2cexec_modcmd(modcmd_t cmd, void *opaque) 476 { 477 switch (cmd) { 478 case MODULE_CMD_INIT: 479 case MODULE_CMD_FINI: 480 return 0; 481 break; 482 default: 483 return ENOTTY; 484 } 485 } 486