1 /* $NetBSD: spi.c,v 1.38 2025/10/10 18:36:17 brad Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 Urbana-Champaign Independent Media Center. 5 * Copyright (c) 2006 Garrett D'Amore. 6 * All rights reserved. 7 * 8 * Portions of this code were written by Garrett D'Amore for the 9 * Champaign-Urbana Community Wireless Network Project. 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above 17 * copyright notice, this list of conditions and the following 18 * disclaimer in the documentation and/or other materials provided 19 * with the distribution. 20 * 3. All advertising materials mentioning features or use of this 21 * software must display the following acknowledgements: 22 * This product includes software developed by the Urbana-Champaign 23 * Independent Media Center. 24 * This product includes software developed by Garrett D'Amore. 25 * 4. Urbana-Champaign Independent Media Center's name and Garrett 26 * D'Amore's name may not be used to endorse or promote products 27 * derived from this software without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE URBANA-CHAMPAIGN INDEPENDENT 30 * MEDIA CENTER AND GARRETT D'AMORE ``AS IS'' AND ANY EXPRESS OR 31 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 32 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE URBANA-CHAMPAIGN INDEPENDENT 34 * MEDIA CENTER OR GARRETT D'AMORE BE LIABLE FOR ANY DIRECT, INDIRECT, 35 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 38 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 41 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 */ 43 44 #include "opt_fdt.h" /* XXX */ 45 46 #include <sys/cdefs.h> 47 __KERNEL_RCSID(0, "$NetBSD: spi.c,v 1.38 2025/10/10 18:36:17 brad Exp $"); 48 49 #include "locators.h" 50 51 #include <sys/param.h> 52 #include <sys/systm.h> 53 #include <sys/device.h> 54 #include <sys/kmem.h> 55 #include <sys/conf.h> 56 #include <sys/malloc.h> 57 #include <sys/mutex.h> 58 #include <sys/condvar.h> 59 #include <sys/errno.h> 60 #include <sys/uio.h> 61 62 #include <dev/spi/spivar.h> 63 #include <dev/spi/spi_io.h> 64 #include <dev/spi/spi_calls.h> 65 66 #ifdef FDT 67 #include <dev/fdt/fdt_spi.h> /* XXX */ 68 #include <dev/ofw/openfirm.h> /* XXX */ 69 #endif 70 71 #include "ioconf.h" 72 #include "locators.h" 73 74 struct spi_softc { 75 device_t sc_dev; 76 const struct spi_controller *sc_controller; 77 int sc_mode; 78 int sc_speed; 79 int sc_slave; 80 int sc_nslaves; 81 spi_handle_t sc_slaves; 82 kmutex_t sc_slave_state_lock; 83 kmutex_t sc_lock; 84 kcondvar_t sc_cv; 85 kmutex_t sc_dev_lock; 86 int sc_flags; 87 #define SPIC_BUSY 1 88 }; 89 90 static dev_type_open(spi_open); 91 static dev_type_close(spi_close); 92 static dev_type_ioctl(spi_ioctl); 93 94 const struct cdevsw spi_cdevsw = { 95 .d_open = spi_open, 96 .d_close = spi_close, 97 .d_read = noread, 98 .d_write = nowrite, 99 .d_ioctl = spi_ioctl, 100 .d_stop = nostop, 101 .d_tty = notty, 102 .d_poll = nopoll, 103 .d_mmap = nommap, 104 .d_kqfilter = nokqfilter, 105 .d_discard = nodiscard, 106 .d_flag = D_OTHER | D_MPSAFE 107 }; 108 109 /* 110 * SPI slave device. We have one of these per slave. 111 */ 112 struct spi_handle { 113 struct spi_softc *sh_sc; /* static */ 114 const struct spi_controller *sh_controller; /* static */ 115 int sh_slave; /* static */ 116 int sh_mode; /* locked by owning child */ 117 int sh_speed; /* locked by owning child */ 118 int sh_flags; /* vv slave_state_lock vv */ 119 #define SPIH_ATTACHED __BIT(0) 120 #define SPIH_DIRECT __BIT(1) 121 device_t sh_dev; /* ^^ slave_state_lock ^^ */ 122 }; 123 124 #define SPI_MAXDATA 4096 125 126 /* 127 * API for bus drivers. 128 */ 129 130 int 131 spibus_print(void *aux, const char *pnp) 132 { 133 134 if (pnp != NULL) 135 aprint_normal("spi at %s", pnp); 136 137 return (UNCONF); 138 } 139 140 141 static int 142 spi_match(device_t parent, cfdata_t cf, void *aux) 143 { 144 145 return 1; 146 } 147 148 static int 149 spi_print_direct(void *aux, const char *pnp) 150 { 151 struct spi_attach_args *sa = aux; 152 153 if (pnp != NULL) { 154 aprint_normal("%s%s%s%s at %s slave %d", 155 sa->sa_name ? sa->sa_name : "(unknown)", 156 sa->sa_clist ? " (" : "", 157 sa->sa_clist ? sa->sa_clist : "", 158 sa->sa_clist ? ")" : "", 159 pnp, sa->sa_handle->sh_slave); 160 } else { 161 aprint_normal(" slave %d", sa->sa_handle->sh_slave); 162 } 163 164 return UNCONF; 165 } 166 167 static int 168 spi_print(void *aux, const char *pnp) 169 { 170 struct spi_attach_args *sa = aux; 171 172 aprint_normal(" slave %d", sa->sa_handle->sh_slave); 173 174 return UNCONF; 175 } 176 177 static void 178 spi_attach_child(struct spi_softc *sc, struct spi_attach_args *sa, 179 int chip_select, cfdata_t cf) 180 { 181 spi_handle_t sh; 182 device_t newdev = NULL; 183 bool is_direct = cf == NULL; 184 const int skip_flags = is_direct ? SPIH_ATTACHED 185 : (SPIH_ATTACHED | SPIH_DIRECT); 186 const int claim_flags = skip_flags ^ SPIH_DIRECT; 187 int locs[SPICF_NLOCS] = { 0 }; 188 189 if (chip_select < 0 || 190 chip_select >= sc->sc_controller->sct_nslaves) { 191 return; 192 } 193 194 sh = &sc->sc_slaves[chip_select]; 195 196 mutex_enter(&sc->sc_slave_state_lock); 197 if (ISSET(sh->sh_flags, skip_flags)) { 198 mutex_exit(&sc->sc_slave_state_lock); 199 return; 200 } 201 202 /* Keep others off of this chip select. */ 203 SET(sh->sh_flags, claim_flags); 204 mutex_exit(&sc->sc_slave_state_lock); 205 206 locs[SPICF_SLAVE] = chip_select; 207 sa->sa_handle = sh; 208 209 if (is_direct) { 210 newdev = config_found(sc->sc_dev, sa, spi_print_direct, 211 CFARGS(.submatch = config_stdsubmatch, 212 .locators = locs, 213 .devhandle = sa->sa_devhandle)); 214 } else { 215 if (config_probe(sc->sc_dev, cf, sa)) { 216 newdev = config_attach(sc->sc_dev, cf, sa, spi_print, 217 CFARGS(.locators = locs)); 218 } 219 } 220 221 mutex_enter(&sc->sc_slave_state_lock); 222 if (newdev == NULL) { 223 /* 224 * Clear our claim on this chip select (yes, just 225 * the ATTACHED flag; we want to keep indirects off 226 * of chip selects for which there is a device tree 227 * node). 228 */ 229 CLR(sh->sh_flags, SPIH_ATTACHED); 230 } else { 231 /* Record the child for posterity. */ 232 sh->sh_dev = newdev; 233 } 234 mutex_exit(&sc->sc_slave_state_lock); 235 } 236 237 static int 238 spi_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux) 239 { 240 struct spi_softc *sc = device_private(parent); 241 242 if (cf->cf_loc[SPICF_SLAVE] == SPICF_SLAVE_DEFAULT) { 243 /* No wildcards for indirect on SPI. */ 244 return 0; 245 } 246 247 struct spi_attach_args sa = { 0 }; 248 spi_attach_child(sc, &sa, cf->cf_loc[SPICF_SLAVE], cf); 249 250 return 0; 251 } 252 253 static bool 254 spi_enumerate_devices_callback(device_t self, 255 struct spi_enumerate_devices_args *args) 256 { 257 struct spi_softc *sc = device_private(self); 258 259 spi_attach_child(sc, args->sa, args->chip_select, NULL); 260 261 return true; /* keep enumerating */ 262 } 263 264 int 265 spi_compatible_match(const struct spi_attach_args *sa, 266 const struct device_compatible_entry *compats) 267 { 268 return device_compatible_match_strlist(sa->sa_clist, 269 sa->sa_clist_size, compats); 270 } 271 272 const struct device_compatible_entry * 273 spi_compatible_lookup(const struct spi_attach_args *sa, 274 const struct device_compatible_entry *compats) 275 { 276 return device_compatible_lookup_strlist(sa->sa_clist, 277 sa->sa_clist_size, compats); 278 } 279 280 bool 281 spi_use_direct_match(const struct spi_attach_args *sa, 282 const struct device_compatible_entry *compats, 283 int *match_resultp) 284 { 285 KASSERT(match_resultp != NULL); 286 287 if (sa->sa_clist != NULL && sa->sa_clist_size != 0) { 288 *match_resultp = spi_compatible_match(sa, compats); 289 return true; 290 } 291 292 return false; 293 } 294 295 /* 296 * API for device drivers. 297 * 298 * We provide wrapper routines to decouple the ABI for the SPI 299 * device drivers from the ABI for the SPI bus drivers. 300 */ 301 static void 302 spi_attach(device_t parent, device_t self, void *aux) 303 { 304 struct spi_softc *sc = device_private(self); 305 struct spibus_attach_args *sba = aux; 306 int i; 307 308 aprint_naive(": SPI bus\n"); 309 aprint_normal(": SPI bus\n"); 310 311 mutex_init(&sc->sc_dev_lock, MUTEX_DEFAULT, IPL_NONE); 312 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM); 313 mutex_init(&sc->sc_slave_state_lock, MUTEX_DEFAULT, IPL_NONE); 314 cv_init(&sc->sc_cv, "spictl"); 315 316 sc->sc_dev = self; 317 sc->sc_controller = sba->sba_controller; 318 sc->sc_nslaves = sba->sba_controller->sct_nslaves; 319 /* allocate slave structures */ 320 sc->sc_slaves = malloc(sizeof(*sc->sc_slaves) * sc->sc_nslaves, 321 M_DEVBUF, M_WAITOK | M_ZERO); 322 323 sc->sc_speed = 0; 324 sc->sc_mode = -1; 325 sc->sc_slave = -1; 326 327 /* 328 * Initialize slave handles 329 */ 330 for (i = 0; i < sc->sc_nslaves; i++) { 331 sc->sc_slaves[i].sh_slave = i; 332 sc->sc_slaves[i].sh_sc = sc; 333 sc->sc_slaves[i].sh_controller = sc->sc_controller; 334 } 335 336 /* XXX Need a better way for this. */ 337 switch (devhandle_type(device_handle(sc->sc_dev))) { 338 #ifdef FDT 339 case DEVHANDLE_TYPE_OF: 340 fdtbus_register_spi_controller(self, sc->sc_controller); 341 break; 342 #endif /* FDT */ 343 default: 344 break; 345 } 346 347 /* 348 * Attempt to enumerate the devices on the bus using the 349 * platform device tree. 350 */ 351 struct spi_attach_args sa = { 0 }; 352 struct spi_enumerate_devices_args enumargs = { 353 .sa = &sa, 354 .callback = spi_enumerate_devices_callback, 355 }; 356 device_call(self, SPI_ENUMERATE_DEVICES(&enumargs)); 357 358 /* Then do any other devices the user may have manually wired */ 359 config_search(self, NULL, 360 CFARGS(.search = spi_search)); 361 } 362 363 static int 364 spi_open(dev_t dev, int flag, int fmt, lwp_t *l) 365 { 366 struct spi_softc *sc = device_lookup_private(&spi_cd, minor(dev)); 367 368 if (sc == NULL) 369 return ENXIO; 370 371 return 0; 372 } 373 374 static int 375 spi_close(dev_t dev, int flag, int fmt, lwp_t *l) 376 { 377 378 return 0; 379 } 380 381 static int 382 spi_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l) 383 { 384 struct spi_softc *sc = device_lookup_private(&spi_cd, minor(dev)); 385 spi_handle_t sh; 386 spi_ioctl_configure_t *sic; 387 spi_ioctl_transfer_t *sit; 388 uint8_t *sbuf, *rbuf; 389 int error; 390 391 if (sc == NULL) 392 return ENXIO; 393 394 mutex_enter(&sc->sc_dev_lock); 395 396 switch (cmd) { 397 case SPI_IOCTL_CONFIGURE: 398 sic = (spi_ioctl_configure_t *)data; 399 if (sic->sic_addr < 0 || sic->sic_addr >= sc->sc_nslaves) { 400 error = EINVAL; 401 break; 402 } 403 sh = &sc->sc_slaves[sic->sic_addr]; 404 error = spi_configure(sc->sc_dev, sh, sic->sic_mode, 405 sic->sic_speed); 406 break; 407 case SPI_IOCTL_TRANSFER: 408 sit = (spi_ioctl_transfer_t *)data; 409 if (sit->sit_addr < 0 || sit->sit_addr >= sc->sc_nslaves) { 410 error = EINVAL; 411 break; 412 } 413 if ((sit->sit_send && sit->sit_sendlen == 0) 414 || (sit->sit_recv && sit->sit_recvlen == 0)) { 415 error = EINVAL; 416 break; 417 } 418 sh = &sc->sc_slaves[sit->sit_addr]; 419 sbuf = rbuf = NULL; 420 error = 0; 421 if (sit->sit_send && sit->sit_sendlen <= SPI_MAXDATA) { 422 sbuf = malloc(sit->sit_sendlen, M_DEVBUF, M_WAITOK); 423 error = copyin(sit->sit_send, sbuf, sit->sit_sendlen); 424 } 425 if (sit->sit_recv && sit->sit_recvlen <= SPI_MAXDATA) { 426 rbuf = malloc(sit->sit_recvlen, M_DEVBUF, M_WAITOK); 427 } 428 if (error == 0) { 429 if (sbuf && rbuf) 430 error = spi_send_recv(sh, 431 sit->sit_sendlen, sbuf, 432 sit->sit_recvlen, rbuf); 433 else if (sbuf) 434 error = spi_send(sh, 435 sit->sit_sendlen, sbuf); 436 else if (rbuf) 437 error = spi_recv(sh, 438 sit->sit_recvlen, rbuf); 439 } 440 if (rbuf) { 441 if (error == 0) 442 error = copyout(rbuf, sit->sit_recv, 443 sit->sit_recvlen); 444 free(rbuf, M_DEVBUF); 445 } 446 if (sbuf) { 447 free(sbuf, M_DEVBUF); 448 } 449 break; 450 default: 451 error = ENODEV; 452 break; 453 } 454 455 mutex_exit(&sc->sc_dev_lock); 456 457 return error; 458 } 459 460 CFATTACH_DECL_NEW(spi, sizeof(struct spi_softc), 461 spi_match, spi_attach, NULL, NULL); 462 463 /* 464 * Configure. This should be the first thing that the SPI driver 465 * should do, to configure which mode (e.g. SPI_MODE_0, which is the 466 * same as Philips Microwire mode), and speed. If the bus driver 467 * cannot run fast enough, then it should just configure the fastest 468 * mode that it can support. If the bus driver cannot run slow 469 * enough, then the device is incompatible and an error should be 470 * returned. 471 */ 472 int 473 spi_configure(device_t dev, spi_handle_t sh, int mode, int speed) 474 { 475 struct spi_get_transfer_mode_args args = { 0 }; 476 int error; 477 478 /* 479 * Get transfer mode information from the platform device tree, if 480 * it exists. 481 */ 482 error = device_call(dev, SPI_GET_TRANSFER_MODE(&args)); 483 if (error) { 484 if (error != ENOTSUP) { 485 /* 486 * This error is fatal. Error message has already 487 * been displayed. 488 */ 489 return error; 490 } 491 } else { 492 /* 493 * If the device tree specifies clock phase shift or 494 * polarity inversion, override whatever the caller 495 * specified. 496 */ 497 if (args.mode != 0) { 498 aprint_debug_dev(dev, 499 "using SPI mode %u from device tree\n", 500 args.mode); 501 mode = args.mode; 502 } 503 504 /* 505 * If the device tree specifies the max clock frequency, 506 * override whatever the caller specified. 507 */ 508 if (args.max_frequency != 0) { 509 aprint_debug_dev(dev, 510 "using max-frequency %u Hz from device tree\n", 511 args.max_frequency); 512 speed = args.max_frequency; 513 } 514 515 /* XXX Handle the other transfer properties. */ 516 } 517 518 sh->sh_mode = mode; 519 sh->sh_speed = speed; 520 521 return 0; 522 } 523 524 /* 525 * Acquire controller 526 */ 527 static void 528 spi_acquire(spi_handle_t sh) 529 { 530 struct spi_softc *sc = sh->sh_sc; 531 532 mutex_enter(&sc->sc_lock); 533 while ((sc->sc_flags & SPIC_BUSY) != 0) 534 cv_wait(&sc->sc_cv, &sc->sc_lock); 535 sc->sc_flags |= SPIC_BUSY; 536 mutex_exit(&sc->sc_lock); 537 } 538 539 /* 540 * Release controller 541 */ 542 static void 543 spi_release(spi_handle_t sh) 544 { 545 struct spi_softc *sc = sh->sh_sc; 546 547 mutex_enter(&sc->sc_lock); 548 sc->sc_flags &= ~SPIC_BUSY; 549 cv_broadcast(&sc->sc_cv); 550 mutex_exit(&sc->sc_lock); 551 } 552 553 void 554 spi_transfer_init(struct spi_transfer *st) 555 { 556 557 mutex_init(&st->st_lock, MUTEX_DEFAULT, IPL_VM); 558 cv_init(&st->st_cv, "spixfr"); 559 560 st->st_flags = 0; 561 st->st_errno = 0; 562 st->st_done = NULL; 563 st->st_chunks = NULL; 564 st->st_private = NULL; 565 st->st_slave = -1; 566 } 567 568 void 569 spi_chunk_init(struct spi_chunk *chunk, int cnt, const uint8_t *wptr, 570 uint8_t *rptr) 571 { 572 573 chunk->chunk_write = chunk->chunk_wptr = wptr; 574 chunk->chunk_read = chunk->chunk_rptr = rptr; 575 chunk->chunk_rresid = chunk->chunk_wresid = chunk->chunk_count = cnt; 576 chunk->chunk_next = NULL; 577 } 578 579 void 580 spi_transfer_add(struct spi_transfer *st, struct spi_chunk *chunk) 581 { 582 struct spi_chunk **cpp; 583 584 /* this is an O(n) insert -- perhaps we should use a simpleq? */ 585 for (cpp = &st->st_chunks; *cpp; cpp = &(*cpp)->chunk_next); 586 *cpp = chunk; 587 } 588 589 int 590 spi_transfer(spi_handle_t sh, struct spi_transfer *st) 591 { 592 struct spi_softc *sc = sh->sh_sc; 593 const struct spi_controller *tag = sh->sh_controller; 594 struct spi_chunk *chunk; 595 int error; 596 597 /* 598 * Initialize "resid" counters and pointers, so that callers 599 * and bus drivers don't have to. 600 */ 601 for (chunk = st->st_chunks; chunk; chunk = chunk->chunk_next) { 602 chunk->chunk_wresid = chunk->chunk_rresid = chunk->chunk_count; 603 chunk->chunk_wptr = chunk->chunk_write; 604 chunk->chunk_rptr = chunk->chunk_read; 605 } 606 607 /* 608 * Match slave and parameters to handle 609 */ 610 st->st_slave = sh->sh_slave; 611 612 /* 613 * Reserve controller during transaction 614 */ 615 spi_acquire(sh); 616 617 st->st_spiprivate = (void *)sh; 618 619 /* 620 * Reconfigure controller 621 * 622 * XXX backends don't configure per-slave parameters 623 * Whenever we switch slaves or change mode or speed, we 624 * need to tell the backend. 625 */ 626 if (sc->sc_slave != sh->sh_slave 627 || sc->sc_mode != sh->sh_mode 628 || sc->sc_speed != sh->sh_speed) { 629 error = (*tag->sct_configure)(tag->sct_cookie, 630 sh->sh_slave, sh->sh_mode, sh->sh_speed); 631 if (error) 632 return error; 633 } 634 sc->sc_mode = sh->sh_mode; 635 sc->sc_speed = sh->sh_speed; 636 sc->sc_slave = sh->sh_slave; 637 638 error = (*tag->sct_transfer)(tag->sct_cookie, st); 639 640 return error; 641 } 642 643 void 644 spi_wait(struct spi_transfer *st) 645 { 646 spi_handle_t sh = st->st_spiprivate; 647 648 mutex_enter(&st->st_lock); 649 while (!(st->st_flags & SPI_F_DONE)) { 650 cv_wait(&st->st_cv, &st->st_lock); 651 } 652 mutex_exit(&st->st_lock); 653 cv_destroy(&st->st_cv); 654 mutex_destroy(&st->st_lock); 655 656 /* 657 * End transaction 658 */ 659 spi_release(sh); 660 } 661 662 void 663 spi_done(struct spi_transfer *st, int err) 664 { 665 666 mutex_enter(&st->st_lock); 667 if ((st->st_errno = err) != 0) { 668 st->st_flags |= SPI_F_ERROR; 669 } 670 st->st_flags |= SPI_F_DONE; 671 if (st->st_done != NULL) { 672 (*st->st_done)(st); 673 } else { 674 cv_broadcast(&st->st_cv); 675 } 676 mutex_exit(&st->st_lock); 677 } 678 679 /* 680 * Some convenience routines. These routines block until the work 681 * is done. 682 * 683 * spi_recv - receives data from the bus 684 * 685 * spi_send - sends data to the bus 686 * 687 * spi_send_recv - sends data to the bus, and then receives. Note that this is 688 * done synchronously, i.e. send a command and get the response. This is 689 * not full duplex. If you want full duplex, you can't use these convenience 690 * wrappers. 691 * 692 * spi_sendv - scatter send data to the bus 693 */ 694 int 695 spi_recv(spi_handle_t sh, int cnt, uint8_t *data) 696 { 697 struct spi_transfer trans; 698 struct spi_chunk chunk; 699 700 spi_transfer_init(&trans); 701 spi_chunk_init(&chunk, cnt, NULL, data); 702 spi_transfer_add(&trans, &chunk); 703 704 /* enqueue it and wait for it to complete */ 705 spi_transfer(sh, &trans); 706 spi_wait(&trans); 707 708 if (trans.st_flags & SPI_F_ERROR) 709 return trans.st_errno; 710 711 return 0; 712 } 713 714 int 715 spi_send(spi_handle_t sh, int cnt, const uint8_t *data) 716 { 717 struct spi_transfer trans; 718 struct spi_chunk chunk; 719 720 spi_transfer_init(&trans); 721 spi_chunk_init(&chunk, cnt, data, NULL); 722 spi_transfer_add(&trans, &chunk); 723 724 /* enqueue it and wait for it to complete */ 725 spi_transfer(sh, &trans); 726 spi_wait(&trans); 727 728 if (trans.st_flags & SPI_F_ERROR) 729 return trans.st_errno; 730 731 return 0; 732 } 733 734 int 735 spi_send_recv(spi_handle_t sh, int scnt, const uint8_t *snd, 736 int rcnt, uint8_t *rcv) 737 { 738 struct spi_transfer trans; 739 struct spi_chunk chunk1, chunk2; 740 741 spi_transfer_init(&trans); 742 spi_chunk_init(&chunk1, scnt, snd, NULL); 743 spi_chunk_init(&chunk2, rcnt, NULL, rcv); 744 spi_transfer_add(&trans, &chunk1); 745 spi_transfer_add(&trans, &chunk2); 746 747 /* enqueue it and wait for it to complete */ 748 spi_transfer(sh, &trans); 749 spi_wait(&trans); 750 751 if (trans.st_flags & SPI_F_ERROR) 752 return trans.st_errno; 753 754 return 0; 755 } 756 757 int 758 spi_sendv(spi_handle_t sh, const struct iovec *iov, 759 int iovcnt) 760 { 761 struct spi_transfer trans; 762 SIMPLEQ_HEAD(,spi_chunk_q) ck_q; 763 struct spi_chunk_q *ce; 764 765 SIMPLEQ_INIT(&ck_q); 766 767 spi_transfer_init(&trans); 768 for(int c = 0; c < iovcnt;c++) { 769 ce = kmem_alloc(sizeof(struct spi_chunk_q),KM_NOSLEEP); 770 if (ce == NULL) 771 return ENOMEM; 772 spi_chunk_init(&ce->chunk, iov[c].iov_len, iov[c].iov_base, NULL); 773 spi_transfer_add(&trans, &ce->chunk); 774 SIMPLEQ_INSERT_HEAD(&ck_q, ce, chunk_q); 775 } 776 777 /* enqueue it and wait for it to complete */ 778 spi_transfer(sh, &trans); 779 spi_wait(&trans); 780 781 while ((ce = SIMPLEQ_FIRST(&ck_q)) != NULL) { 782 SIMPLEQ_REMOVE_HEAD(&ck_q, chunk_q); 783 kmem_free(ce, sizeof(struct spi_chunk_q)); 784 } 785 786 if (trans.st_flags & SPI_F_ERROR) 787 return trans.st_errno; 788 789 return 0; 790 } 791