1 /* $NetBSD: spi.c,v 1.41 2026/01/17 05:33:51 skrll 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.41 2026/01/17 05:33:51 skrll 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 #if 0 341 /* 342 * XXX The addition of a USB SPI controller has triggered 343 * XXX an unfortunate situation, whereby it is attaching 344 * XXX a SPI controller on an otherwise FDT platform (RISC-V) 345 * XXX that does not happen to currently have any platform 346 * XXX SoC SPI controller drivers that carry the fdt_spi 347 * XXX config attribute that would pull in the function 348 * XXX being called here. 349 * XXX 350 * XXX As it happens we can fairly safely elide this call 351 * XXX because, at the moment (1 Dec 2025), there are no 352 * XXX consumers of the registration it performs. However, 353 * XXX this points to a larger problem if needed a way to 354 * XXX resolve these situations at runtime with some sort 355 * XXX of "platform" abstraction rather than at kernel build 356 * XXX time. 357 */ 358 fdtbus_register_spi_controller(self, sc->sc_controller); 359 #endif 360 break; 361 #endif /* FDT */ 362 default: 363 break; 364 } 365 366 /* 367 * Attempt to enumerate the devices on the bus using the 368 * platform device tree. 369 */ 370 struct spi_attach_args sa = { 0 }; 371 struct spi_enumerate_devices_args enumargs = { 372 .sa = &sa, 373 .callback = spi_enumerate_devices_callback, 374 }; 375 device_call(self, SPI_ENUMERATE_DEVICES(&enumargs)); 376 377 /* Then do any other devices the user may have manually wired */ 378 config_search(self, NULL, 379 CFARGS(.search = spi_search)); 380 } 381 382 static int 383 spi_detach(device_t self, int flags) 384 { 385 int error; 386 387 error = config_detach_children(self, flags); 388 if (error) 389 return error; 390 391 return 0; 392 } 393 394 static int 395 spi_open(dev_t dev, int flag, int fmt, lwp_t *l) 396 { 397 struct spi_softc *sc = device_lookup_private(&spi_cd, minor(dev)); 398 399 if (sc == NULL) 400 return ENXIO; 401 402 return 0; 403 } 404 405 static int 406 spi_close(dev_t dev, int flag, int fmt, lwp_t *l) 407 { 408 409 return 0; 410 } 411 412 static int 413 spi_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l) 414 { 415 struct spi_softc *sc = device_lookup_private(&spi_cd, minor(dev)); 416 spi_handle_t sh; 417 spi_ioctl_configure_t *sic; 418 spi_ioctl_transfer_t *sit; 419 uint8_t *sbuf, *rbuf; 420 int error; 421 422 if (sc == NULL) 423 return ENXIO; 424 425 mutex_enter(&sc->sc_dev_lock); 426 427 switch (cmd) { 428 case SPI_IOCTL_CONFIGURE: 429 sic = (spi_ioctl_configure_t *)data; 430 if (sic->sic_addr < 0 || sic->sic_addr >= sc->sc_nslaves) { 431 error = EINVAL; 432 break; 433 } 434 sh = &sc->sc_slaves[sic->sic_addr]; 435 error = spi_configure(sc->sc_dev, sh, sic->sic_mode, 436 sic->sic_speed); 437 break; 438 case SPI_IOCTL_TRANSFER: 439 sit = (spi_ioctl_transfer_t *)data; 440 if (sit->sit_addr < 0 || sit->sit_addr >= sc->sc_nslaves) { 441 error = EINVAL; 442 break; 443 } 444 if ((sit->sit_send && sit->sit_sendlen == 0) 445 || (sit->sit_recv && sit->sit_recvlen == 0)) { 446 error = EINVAL; 447 break; 448 } 449 sh = &sc->sc_slaves[sit->sit_addr]; 450 sbuf = rbuf = NULL; 451 error = 0; 452 if (sit->sit_send && sit->sit_sendlen <= SPI_MAXDATA) { 453 sbuf = malloc(sit->sit_sendlen, M_DEVBUF, M_WAITOK); 454 error = copyin(sit->sit_send, sbuf, sit->sit_sendlen); 455 } 456 if (sit->sit_recv && sit->sit_recvlen <= SPI_MAXDATA) { 457 rbuf = malloc(sit->sit_recvlen, M_DEVBUF, M_WAITOK); 458 } 459 if (error == 0) { 460 if (sbuf && rbuf) 461 error = spi_send_recv(sh, 462 sit->sit_sendlen, sbuf, 463 sit->sit_recvlen, rbuf); 464 else if (sbuf) 465 error = spi_send(sh, 466 sit->sit_sendlen, sbuf); 467 else if (rbuf) 468 error = spi_recv(sh, 469 sit->sit_recvlen, rbuf); 470 } 471 if (rbuf) { 472 if (error == 0) 473 error = copyout(rbuf, sit->sit_recv, 474 sit->sit_recvlen); 475 free(rbuf, M_DEVBUF); 476 } 477 if (sbuf) { 478 free(sbuf, M_DEVBUF); 479 } 480 break; 481 default: 482 error = ENODEV; 483 break; 484 } 485 486 mutex_exit(&sc->sc_dev_lock); 487 488 return error; 489 } 490 491 CFATTACH_DECL_NEW(spi, sizeof(struct spi_softc), 492 spi_match, spi_attach, spi_detach, NULL); 493 494 /* 495 * Configure. This should be the first thing that the SPI driver 496 * should do, to configure which mode (e.g. SPI_MODE_0, which is the 497 * same as Philips Microwire mode), and speed. If the bus driver 498 * cannot run fast enough, then it should just configure the fastest 499 * mode that it can support. If the bus driver cannot run slow 500 * enough, then the device is incompatible and an error should be 501 * returned. 502 */ 503 int 504 spi_configure(device_t dev, spi_handle_t sh, int mode, int speed) 505 { 506 struct spi_get_transfer_mode_args args = { 0 }; 507 int error; 508 509 /* 510 * Get transfer mode information from the platform device tree, if 511 * it exists. 512 */ 513 error = device_call(dev, SPI_GET_TRANSFER_MODE(&args)); 514 if (error) { 515 if (error != ENOTSUP) { 516 /* 517 * This error is fatal. Error message has already 518 * been displayed. 519 */ 520 return error; 521 } 522 } else { 523 /* 524 * If the device tree specifies clock phase shift or 525 * polarity inversion, override whatever the caller 526 * specified. 527 */ 528 if (args.mode != 0) { 529 aprint_debug_dev(dev, 530 "using SPI mode %u from device tree\n", 531 args.mode); 532 mode = args.mode; 533 } 534 535 /* 536 * If the device tree specifies the max clock frequency, 537 * override whatever the caller specified. 538 */ 539 if (args.max_frequency != 0) { 540 aprint_debug_dev(dev, 541 "using max-frequency %u Hz from device tree\n", 542 args.max_frequency); 543 speed = args.max_frequency; 544 } 545 546 /* XXX Handle the other transfer properties. */ 547 } 548 549 sh->sh_mode = mode; 550 sh->sh_speed = speed; 551 552 return 0; 553 } 554 555 /* 556 * Acquire controller 557 */ 558 static void 559 spi_acquire(spi_handle_t sh) 560 { 561 struct spi_softc *sc = sh->sh_sc; 562 563 mutex_enter(&sc->sc_lock); 564 while ((sc->sc_flags & SPIC_BUSY) != 0) 565 cv_wait(&sc->sc_cv, &sc->sc_lock); 566 sc->sc_flags |= SPIC_BUSY; 567 mutex_exit(&sc->sc_lock); 568 } 569 570 /* 571 * Release controller 572 */ 573 static void 574 spi_release(spi_handle_t sh) 575 { 576 struct spi_softc *sc = sh->sh_sc; 577 578 mutex_enter(&sc->sc_lock); 579 sc->sc_flags &= ~SPIC_BUSY; 580 cv_broadcast(&sc->sc_cv); 581 mutex_exit(&sc->sc_lock); 582 } 583 584 void 585 spi_transfer_init(struct spi_transfer *st) 586 { 587 588 mutex_init(&st->st_lock, MUTEX_DEFAULT, IPL_VM); 589 cv_init(&st->st_cv, "spixfr"); 590 591 st->st_flags = 0; 592 st->st_errno = 0; 593 st->st_done = NULL; 594 st->st_chunks = NULL; 595 st->st_private = NULL; 596 st->st_slave = -1; 597 } 598 599 void 600 spi_chunk_init(struct spi_chunk *chunk, int cnt, const uint8_t *wptr, 601 uint8_t *rptr) 602 { 603 604 chunk->chunk_write = chunk->chunk_wptr = wptr; 605 chunk->chunk_read = chunk->chunk_rptr = rptr; 606 chunk->chunk_rresid = chunk->chunk_wresid = chunk->chunk_count = cnt; 607 chunk->chunk_next = NULL; 608 } 609 610 void 611 spi_transfer_add(struct spi_transfer *st, struct spi_chunk *chunk) 612 { 613 struct spi_chunk **cpp; 614 615 /* this is an O(n) insert -- perhaps we should use a simpleq? */ 616 for (cpp = &st->st_chunks; *cpp; cpp = &(*cpp)->chunk_next); 617 *cpp = chunk; 618 } 619 620 int 621 spi_transfer(spi_handle_t sh, struct spi_transfer *st) 622 { 623 struct spi_softc *sc = sh->sh_sc; 624 const struct spi_controller *tag = sh->sh_controller; 625 struct spi_chunk *chunk; 626 int error; 627 628 /* 629 * Initialize "resid" counters and pointers, so that callers 630 * and bus drivers don't have to. 631 */ 632 for (chunk = st->st_chunks; chunk; chunk = chunk->chunk_next) { 633 chunk->chunk_wresid = chunk->chunk_rresid = chunk->chunk_count; 634 chunk->chunk_wptr = chunk->chunk_write; 635 chunk->chunk_rptr = chunk->chunk_read; 636 } 637 638 /* 639 * Match slave and parameters to handle 640 */ 641 st->st_slave = sh->sh_slave; 642 643 /* 644 * Reserve controller during transaction 645 */ 646 spi_acquire(sh); 647 648 st->st_spiprivate = (void *)sh; 649 650 /* 651 * Reconfigure controller 652 * 653 * XXX backends don't configure per-slave parameters 654 * Whenever we switch slaves or change mode or speed, we 655 * need to tell the backend. 656 */ 657 if (sc->sc_slave != sh->sh_slave 658 || sc->sc_mode != sh->sh_mode 659 || sc->sc_speed != sh->sh_speed) { 660 error = (*tag->sct_configure)(tag->sct_cookie, 661 sh->sh_slave, sh->sh_mode, sh->sh_speed); 662 if (error) 663 return error; 664 } 665 sc->sc_mode = sh->sh_mode; 666 sc->sc_speed = sh->sh_speed; 667 sc->sc_slave = sh->sh_slave; 668 669 error = (*tag->sct_transfer)(tag->sct_cookie, st); 670 671 return error; 672 } 673 674 void 675 spi_wait(struct spi_transfer *st) 676 { 677 spi_handle_t sh = st->st_spiprivate; 678 679 mutex_enter(&st->st_lock); 680 while (!(st->st_flags & SPI_F_DONE)) { 681 cv_wait(&st->st_cv, &st->st_lock); 682 } 683 mutex_exit(&st->st_lock); 684 cv_destroy(&st->st_cv); 685 mutex_destroy(&st->st_lock); 686 687 /* 688 * End transaction 689 */ 690 spi_release(sh); 691 } 692 693 void 694 spi_done(struct spi_transfer *st, int err) 695 { 696 697 mutex_enter(&st->st_lock); 698 if ((st->st_errno = err) != 0) { 699 st->st_flags |= SPI_F_ERROR; 700 } 701 st->st_flags |= SPI_F_DONE; 702 if (st->st_done != NULL) { 703 (*st->st_done)(st); 704 } else { 705 cv_broadcast(&st->st_cv); 706 } 707 mutex_exit(&st->st_lock); 708 } 709 710 /* 711 * Some convenience routines. These routines block until the work 712 * is done. 713 * 714 * spi_recv - receives data from the bus 715 * 716 * spi_send - sends data to the bus 717 * 718 * spi_send_recv - sends data to the bus, and then receives. Note that this is 719 * done synchronously, i.e. send a command and get the response. This is 720 * not full duplex. If you want full duplex, you can't use these convenience 721 * wrappers. 722 * 723 * spi_sendv - scatter send data to the bus 724 */ 725 int 726 spi_recv(spi_handle_t sh, int cnt, uint8_t *data) 727 { 728 struct spi_transfer trans; 729 struct spi_chunk chunk; 730 731 spi_transfer_init(&trans); 732 spi_chunk_init(&chunk, cnt, NULL, data); 733 spi_transfer_add(&trans, &chunk); 734 735 /* enqueue it and wait for it to complete */ 736 spi_transfer(sh, &trans); 737 spi_wait(&trans); 738 739 if (trans.st_flags & SPI_F_ERROR) 740 return trans.st_errno; 741 742 return 0; 743 } 744 745 int 746 spi_send(spi_handle_t sh, int cnt, const uint8_t *data) 747 { 748 struct spi_transfer trans; 749 struct spi_chunk chunk; 750 751 spi_transfer_init(&trans); 752 spi_chunk_init(&chunk, cnt, data, NULL); 753 spi_transfer_add(&trans, &chunk); 754 755 /* enqueue it and wait for it to complete */ 756 spi_transfer(sh, &trans); 757 spi_wait(&trans); 758 759 if (trans.st_flags & SPI_F_ERROR) 760 return trans.st_errno; 761 762 return 0; 763 } 764 765 int 766 spi_send_recv(spi_handle_t sh, int scnt, const uint8_t *snd, 767 int rcnt, uint8_t *rcv) 768 { 769 struct spi_transfer trans; 770 struct spi_chunk chunk1, chunk2; 771 772 spi_transfer_init(&trans); 773 spi_chunk_init(&chunk1, scnt, snd, NULL); 774 spi_chunk_init(&chunk2, rcnt, NULL, rcv); 775 spi_transfer_add(&trans, &chunk1); 776 spi_transfer_add(&trans, &chunk2); 777 778 /* enqueue it and wait for it to complete */ 779 spi_transfer(sh, &trans); 780 spi_wait(&trans); 781 782 if (trans.st_flags & SPI_F_ERROR) 783 return trans.st_errno; 784 785 return 0; 786 } 787 788 int 789 spi_sendv(spi_handle_t sh, const struct iovec *iov, 790 int iovcnt) 791 { 792 struct spi_transfer trans; 793 SIMPLEQ_HEAD(,spi_chunk_q) ck_q; 794 struct spi_chunk_q *ce; 795 796 SIMPLEQ_INIT(&ck_q); 797 798 spi_transfer_init(&trans); 799 for(int c = 0; c < iovcnt;c++) { 800 ce = kmem_alloc(sizeof(struct spi_chunk_q),KM_NOSLEEP); 801 if (ce == NULL) 802 return ENOMEM; 803 spi_chunk_init(&ce->chunk, iov[c].iov_len, iov[c].iov_base, NULL); 804 spi_transfer_add(&trans, &ce->chunk); 805 SIMPLEQ_INSERT_HEAD(&ck_q, ce, chunk_q); 806 } 807 808 /* enqueue it and wait for it to complete */ 809 spi_transfer(sh, &trans); 810 spi_wait(&trans); 811 812 while ((ce = SIMPLEQ_FIRST(&ck_q)) != NULL) { 813 SIMPLEQ_REMOVE_HEAD(&ck_q, chunk_q); 814 kmem_free(ce, sizeof(struct spi_chunk_q)); 815 } 816 817 if (trans.st_flags & SPI_F_ERROR) 818 return trans.st_errno; 819 820 return 0; 821 } 822