void spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen) { spih_info_t *si = (spih_info_t *)sd->controller; osl_t *osh = si->osh; spih_regs_t *regs = si->regs; uint32 count; uint32 spi_data_out; uint32 spi_data_in; bool yield; sd_trace(("%s: enter\n", __FUNCTION__)); if (bcmpcispi_dump) { printf("SENDRECV(len=%d)\n", msglen); hexdump(" OUT: ", msg_out, msglen); } #ifdef BCMSDYIELD yield = ((msglen > 500) && (si->rev >= 8)); #else yield = FALSE; #endif ASSERT(msglen % 4 == 0); SPIPCI_ANDREG(osh, ®s->spih_gpio_data, ~SPIH_CS); for (count = 0; count < (uint32)msglen/4; count++) { spi_data_out = ((uint32)((uint32 *)msg_out)[count]); SPIPCI_WREG(osh, ®s->spih_data, spi_data_out); } #ifdef BCMSDYIELD if (yield) { SPIPCI_WREG(osh, ®s->spih_int_status, SPIH_WFIFO_INTR); SPIPCI_RREG(osh, ®s->spih_int_status); sd->intmask |= SPIH_WFIFO_INTR; sd->got_hcint = FALSE; SPIPCI_WREG(osh, ®s->spih_int_mask, sd->intmask); } #endif SPIPCI_ANDREG(osh, ®s->spih_gpio_data, ~0x00000020); if (yield) { ASSERT((SPIPCI_RREG(sd->osh, ®s->spih_stat) & SPIH_WFEMPTY) == 0); } spi_waitbits(sd, yield); SPIPCI_ORREG(osh, ®s->spih_gpio_data, 0x00000020); for (count = 0; count < (uint32)msglen/4; count++) { spi_data_in = SPIPCI_RREG(osh, ®s->spih_data); ((uint32 *)msg_in)[count] = spi_data_in; } SPIPCI_ORREG(osh, ®s->spih_gpio_data, SPIH_CS); if (bcmpcispi_dump) { hexdump(" IN : ", msg_in, msglen); } }
/* Send/Receive an SPI Packet */ void spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen) { spih_info_t *si = (spih_info_t *)sd->controller; osl_t *osh = si->osh; spih_regs_t *regs = si->regs; uint32 count; uint32 spi_data_out; uint32 spi_data_in; bool yield; sd_trace(("%s: enter\n", __FUNCTION__)); if (bcmpcispi_dump) { printf("SENDRECV(len=%d)\n", msglen); hexdump(" OUT: ", msg_out, msglen); } #ifdef BCMSDYIELD /* Only yield the CPU and wait for interrupt on Rev 8 and newer FPGA images. */ yield = ((msglen > 500) && (si->rev >= 8)); #else yield = FALSE; #endif /* BCMSDYIELD */ ASSERT(msglen % 4 == 0); SPIPCI_ANDREG(osh, ®s->spih_gpio_data, ~SPIH_CS); /* Set GPIO CS# Low (asserted) */ for (count = 0; count < (uint32)msglen/4; count++) { spi_data_out = ((uint32)((uint32 *)msg_out)[count]); SPIPCI_WREG(osh, ®s->spih_data, spi_data_out); } #ifdef BCMSDYIELD if (yield) { /* Ack the interrupt in the interrupt controller */ SPIPCI_WREG(osh, ®s->spih_int_status, SPIH_WFIFO_INTR); SPIPCI_RREG(osh, ®s->spih_int_status); /* Enable the FIFO Empty Interrupt */ sd->intmask |= SPIH_WFIFO_INTR; sd->got_hcint = FALSE; SPIPCI_WREG(osh, ®s->spih_int_mask, sd->intmask); } #endif /* BCMSDYIELD */ /* Wait for write fifo to empty... */ SPIPCI_ANDREG(osh, ®s->spih_gpio_data, ~0x00000020); /* Set GPIO 5 Low */ if (yield) { ASSERT((SPIPCI_RREG(sd->osh, ®s->spih_stat) & SPIH_WFEMPTY) == 0); } spi_waitbits(sd, yield); SPIPCI_ORREG(osh, ®s->spih_gpio_data, 0x00000020); /* Set GPIO 5 High (de-asserted) */ for (count = 0; count < (uint32)msglen/4; count++) { spi_data_in = SPIPCI_RREG(osh, ®s->spih_data); ((uint32 *)msg_in)[count] = spi_data_in; } /* Set GPIO CS# High (de-asserted) */ SPIPCI_ORREG(osh, ®s->spih_gpio_data, SPIH_CS); if (bcmpcispi_dump) { hexdump(" IN : ", msg_in, msglen); } }