1 /* $NetBSD: i2c_exec.c,v 1.15 2020/01/02 16:18:37 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.15 2020/01/02 16:18:37 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 return error; 145 } 146 147 /* 148 * iic_release_bus: 149 * 150 * Relese the I2C bus, allowing another client to use it. 151 */ 152 void 153 iic_release_bus(i2c_tag_t tag, int flags) 154 { 155 156 #if 0 /* XXX Not quite ready for this yet. */ 157 KASSERT(!cpu_intr_p()); 158 #endif 159 160 flags = iic_op_flags(flags); 161 162 if (tag->ic_release_bus) { 163 (*tag->ic_release_bus)(tag->ic_cookie, flags); 164 } 165 166 mutex_exit(&tag->ic_bus_lock); 167 } 168 169 /* 170 * iic_exec: 171 * 172 * Simplified I2C client interface engine. 173 * 174 * This and the SMBus routines are the preferred interface for 175 * client access to I2C/SMBus, since many automated controllers 176 * do not provide access to the low-level primitives of the I2C 177 * bus protocol. 178 */ 179 int 180 iic_exec(i2c_tag_t tag, i2c_op_t op, i2c_addr_t addr, const void *vcmd, 181 size_t cmdlen, void *vbuf, size_t buflen, int flags) 182 { 183 const uint8_t *cmd = vcmd; 184 uint8_t *buf = vbuf; 185 int error; 186 size_t len; 187 188 #if 0 /* XXX Not quite ready for this yet. */ 189 KASSERT(!cpu_intr_p()); 190 #endif 191 192 flags = iic_op_flags(flags); 193 194 if ((flags & I2C_F_PEC) && cmdlen > 0 && tag->ic_exec != NULL) { 195 uint8_t data[33]; /* XXX */ 196 uint8_t b[3]; 197 198 b[0] = addr << 1; 199 b[1] = cmd[0]; 200 201 switch (buflen) { 202 case 0: 203 data[0] = iic_smbus_pec(2, b, NULL); 204 buflen++; 205 break; 206 case 1: 207 b[2] = buf[0]; 208 data[0] = iic_smbus_pec(3, b, NULL); 209 data[1] = b[2]; 210 buflen++; 211 break; 212 case 2: 213 break; 214 default: 215 KASSERT(buflen+1 < sizeof(data)); 216 memcpy(data, vbuf, buflen); 217 data[buflen] = iic_smbus_pec(2, b, data); 218 buflen++; 219 break; 220 } 221 222 return ((*tag->ic_exec)(tag->ic_cookie, op, addr, cmd, 223 cmdlen, data, buflen, flags)); 224 } 225 226 /* 227 * Defer to the controller if it provides an exec function. Use 228 * it if it does. 229 */ 230 if (tag->ic_exec != NULL) 231 return ((*tag->ic_exec)(tag->ic_cookie, op, addr, cmd, 232 cmdlen, buf, buflen, flags)); 233 234 if ((len = cmdlen) != 0) { 235 if ((error = iic_initiate_xfer(tag, addr, flags)) != 0) 236 goto bad; 237 while (len--) { 238 if ((error = iic_write_byte(tag, *cmd++, flags)) != 0) 239 goto bad; 240 } 241 } else if (buflen == 0) { 242 /* 243 * This is a quick_read()/quick_write() command with 244 * neither command nor data bytes 245 */ 246 if (I2C_OP_STOP_P(op)) 247 flags |= I2C_F_STOP; 248 if (I2C_OP_READ_P(op)) 249 flags |= I2C_F_READ; 250 if ((error = iic_initiate_xfer(tag, addr, flags)) != 0) 251 goto bad; 252 } 253 254 if (I2C_OP_READ_P(op)) 255 flags |= I2C_F_READ; 256 257 len = buflen; 258 while (len--) { 259 if (len == 0 && I2C_OP_STOP_P(op)) 260 flags |= I2C_F_STOP; 261 if (I2C_OP_READ_P(op)) { 262 /* Send REPEATED START. */ 263 if ((len + 1) == buflen && 264 (error = iic_initiate_xfer(tag, addr, flags)) != 0) 265 goto bad; 266 /* NACK on last byte. */ 267 if (len == 0) 268 flags |= I2C_F_LAST; 269 if ((error = iic_read_byte(tag, buf++, flags)) != 0) 270 goto bad; 271 } else { 272 /* Maybe send START. */ 273 if ((len + 1) == buflen && cmdlen == 0 && 274 (error = iic_initiate_xfer(tag, addr, flags)) != 0) 275 goto bad; 276 if ((error = iic_write_byte(tag, *buf++, flags)) != 0) 277 goto bad; 278 } 279 } 280 281 return (0); 282 bad: 283 iic_send_stop(tag, flags); 284 return (error); 285 } 286 287 /* 288 * iic_smbus_write_byte: 289 * 290 * Perform an SMBus "write byte" operation. 291 */ 292 int 293 iic_smbus_write_byte(i2c_tag_t tag, i2c_addr_t addr, uint8_t cmd, 294 uint8_t val, int flags) 295 { 296 297 return (iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &cmd, 1, 298 &val, 1, flags)); 299 } 300 301 /* 302 * iic_smbus_write_word: 303 * 304 * Perform an SMBus "write word" operation. 305 */ 306 int 307 iic_smbus_write_word(i2c_tag_t tag, i2c_addr_t addr, uint8_t cmd, 308 uint16_t val, int flags) 309 { 310 uint8_t vbuf[2]; 311 312 vbuf[0] = val & 0xff; 313 vbuf[1] = (val >> 8) & 0xff; 314 315 return (iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &cmd, 1, 316 vbuf, 2, flags)); 317 } 318 319 /* 320 * iic_smbus_read_byte: 321 * 322 * Perform an SMBus "read byte" operation. 323 */ 324 int 325 iic_smbus_read_byte(i2c_tag_t tag, i2c_addr_t addr, uint8_t cmd, 326 uint8_t *valp, int flags) 327 { 328 329 return (iic_exec(tag, I2C_OP_READ_WITH_STOP, addr, &cmd, 1, 330 valp, 1, flags)); 331 } 332 333 /* 334 * iic_smbus_read_word: 335 * 336 * Perform an SMBus "read word" operation. 337 */ 338 int 339 iic_smbus_read_word(i2c_tag_t tag, i2c_addr_t addr, uint8_t cmd, 340 uint16_t *valp, int flags) 341 { 342 343 return (iic_exec(tag, I2C_OP_READ_WITH_STOP, addr, &cmd, 1, 344 (uint8_t *)valp, 2, flags)); 345 } 346 347 /* 348 * iic_smbus_receive_byte: 349 * 350 * Perform an SMBus "receive byte" operation. 351 */ 352 int 353 iic_smbus_receive_byte(i2c_tag_t tag, i2c_addr_t addr, uint8_t *valp, 354 int flags) 355 { 356 357 return (iic_exec(tag, I2C_OP_READ_WITH_STOP, addr, NULL, 0, 358 valp, 1, flags)); 359 } 360 361 /* 362 * iic_smbus_send_byte: 363 * 364 * Perform an SMBus "send byte" operation. 365 */ 366 int 367 iic_smbus_send_byte(i2c_tag_t tag, i2c_addr_t addr, uint8_t val, int flags) 368 { 369 370 return (iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, NULL, 0, 371 &val, 1, flags)); 372 } 373 374 /* 375 * iic_smbus_quick_read: 376 * 377 * Perform an SMBus "quick read" operation. 378 */ 379 int 380 iic_smbus_quick_read(i2c_tag_t tag, i2c_addr_t addr, int flags) 381 { 382 383 return (iic_exec(tag, I2C_OP_READ_WITH_STOP, addr, NULL, 0, 384 NULL, 0, flags)); 385 } 386 387 /* 388 * iic_smbus_quick_write: 389 * 390 * Perform an SMBus "quick write" operation. 391 */ 392 int 393 iic_smbus_quick_write(i2c_tag_t tag, i2c_addr_t addr, int flags) 394 { 395 396 return (iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, NULL, 0, 397 NULL, 0, flags)); 398 } 399 400 /* 401 * iic_smbus_block_read: 402 * 403 * Perform an SMBus "block read" operation. 404 */ 405 int 406 iic_smbus_block_read(i2c_tag_t tag, i2c_addr_t addr, uint8_t cmd, 407 uint8_t *vbuf, size_t buflen, int flags) 408 { 409 410 return (iic_exec(tag, I2C_OP_READ_BLOCK, addr, &cmd, 1, 411 vbuf, buflen, flags)); 412 } 413 414 /* 415 * iic_smbus_block_write: 416 * 417 * Perform an SMBus "block write" operation. 418 */ 419 int 420 iic_smbus_block_write(i2c_tag_t tag, i2c_addr_t addr, uint8_t cmd, 421 uint8_t *vbuf, size_t buflen, int flags) 422 { 423 424 return (iic_exec(tag, I2C_OP_WRITE_BLOCK, addr, &cmd, 1, 425 vbuf, buflen, flags)); 426 } 427 428 /* 429 * iic_smbus_crc8 430 * 431 * Private helper for calculating packet error checksum 432 */ 433 static uint8_t 434 iic_smbus_crc8(uint16_t data) 435 { 436 int i; 437 438 for (i = 0; i < 8; i++) { 439 if (data & 0x8000) 440 data = data ^ (0x1070U << 3); 441 data = data << 1; 442 } 443 444 return (uint8_t)(data >> 8); 445 } 446 447 /* 448 * iic_smbus_pec 449 * 450 * Private function for calculating packet error checking on SMBus 451 * packets. 452 */ 453 static uint8_t 454 iic_smbus_pec(int count, uint8_t *s, uint8_t *r) 455 { 456 int i; 457 uint8_t crc = 0; 458 459 for (i = 0; i < count; i++) 460 crc = iic_smbus_crc8((crc ^ s[i]) << 8); 461 if (r != NULL) 462 for (i = 0; i <= r[0]; i++) 463 crc = iic_smbus_crc8((crc ^ r[i]) << 8); 464 465 return crc; 466 } 467 468 MODULE(MODULE_CLASS_MISC, i2cexec, NULL); 469 470 static int 471 i2cexec_modcmd(modcmd_t cmd, void *opaque) 472 { 473 switch (cmd) { 474 case MODULE_CMD_INIT: 475 case MODULE_CMD_FINI: 476 return 0; 477 break; 478 default: 479 return ENOTTY; 480 } 481 } 482