//写一页数据 int w25qxx_write_page(uint32_t addr, uint8_t *buf, uint32_t len) { w25qxx_write_enable(); /* send addr */ spi_xfer(W25X_PageProgram, W25QXX_CS_LOW); spi_xfer((uint8_t)((addr)>>16), W25QXX_CS_LOW); spi_xfer((uint8_t)((addr)>>8), W25QXX_CS_LOW); spi_xfer((uint8_t)addr, W25QXX_CS_LOW); w25_dev.ops.xfer(NULL, buf, len, W25QXX_CS_HIGH); while(w25_dev.ops.get_reamin() != 0) { w25_dev.ops.delayms(10); } /* wait busy */ while((w25qxx_read_sr() & 0x01) == 0x01) { w25_dev.ops.delayms(1); } return 0; }
/* control backlight pwm (display brightness). * allow values 0-250 with 0 = turn off and 250 = max brightness */ void mergerbox_tft_dim(u16 value) { struct spi_slave *slave; u16 din; u16 dout = 0; if (value > 0 && value < 250) dout = 0x4000 | value; slave = spi_setup_slave(0, 0, 1000000, SPI_MODE_0 | SPI_CS_HIGH); spi_claim_bus(slave); spi_xfer(slave, 16, &dout, &din, SPI_XFER_BEGIN | SPI_XFER_END); spi_release_bus(slave); spi_free_slave(slave); }
void rtc_set_time(uint8_t year, uint8_t month, uint8_t day, uint8_t hours, uint8_t minutes, uint8_t seconds, uint8_t weekday) { RTC_BEGIN(); spi_xfer(RTC_WRITE_CMD(2)); spi_xfer(seconds); spi_xfer(minutes); spi_xfer(hours); spi_xfer(day); spi_xfer(weekday); spi_xfer(month); spi_xfer(year); RTC_END(); /* read what we just wrote */ rtc_get_time(); }
void lcd_spi_send(unsigned char reg_addr, unsigned char reg_data) { int ret = 0; int msg,imsg; uchar omsg[2]; msg=(reg_addr<<10)|reg_data; // note big endian, so swap omsg[0]=(msg>>8)&0xff; omsg[1]=(msg)&0xff; spi_xfer(spi_chipsel[0], 16,( uchar *)omsg, (uchar *) &imsg); // wait for transaction to finish udelay(400); }
void SPITouch_Init() { if(! HAS_TOUCH) return; #if 0 /* Enable SPI1 */ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_SPI1EN); /* Enable GPIOA */ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN); /* Enable GPIOB */ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPBEN); #endif /* CS */ gpio_set_mode(_TOUCH_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, _TOUCH_PIN); /* PenIRQ is pull-up input*/ gpio_set_mode(_TOUCH_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, _TOUCH_IRQ_PIN); gpio_set(_TOUCH_PORT, _TOUCH_IRQ_PIN); CS_LO(); spi_xfer(SPI1, RESET); CS_HI(); //SPITouch_Calibrate(197312, 147271, -404, -20); /* Read from my Tx */ #if 0 /* SCK, MOSI */ gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO5 | GPIO7); /* MISO */ gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO6); /* Includes enable */ spi_init_master(SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_4, SPI_CR1_CPOL_CLK_TO_1_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_2, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST); spi_enable_software_slave_management(SPI1); spi_set_nss_high(SPI1); spi_enable(SPI1); #endif }
int spi_flash_adr_write(struct spi_slave *spi, u32 adr){ unsigned flags=SPI_XFER_END; int ret; ret=adr; flags|=SPI_XFER_ADR; ret=spi_xfer(spi,4*8,&ret,NULL,flags); if(ret) { debug("SF: Faild to send adr(%zu bytes): %d\n",4,ret); } return ret; }
void radio_configure() { radio_in_tx = 0; radio_command(SIDLE); radio_select(); for (int i = 0; i < sizeof(cc1101_regs); ++i) { spi_xfer(cc1101_regs[i]); } radio_deselect(); radio_write(IOCFG2, 6 | GDOx_INVERT); radio_channel(current_channel); radio_command(SFRX); radio_command(SRX); }
u8 A7105_ReadReg(u8 address) { u8 data; CS_LO(); spi_xfer(SPI2, 0x40 | address); spi_disable(SPI2); spi_set_bidirectional_receive_only_mode(SPI2); spi_enable(SPI2); int i; for(i = 0; i < 10; i++) ; spi_disable(SPI2); data = spi_read(SPI2); CS_HI(); spi_set_unidirectional_mode(SPI2); spi_enable(SPI2); return data; }
void spi_exchange_nodma(const uint8_t *txbuf, uint8_t *rxbuf, size_t n) { uint8_t byte; const uint8_t *txptr = txbuf; uint8_t *rxptr = rxbuf; while (n-- > 0) { if (txptr) byte = *txptr++; else byte = 0xFF; while (!(SPI_SR(SPI2) & SPI_SR_TXE)); byte = (uint8_t)spi_xfer(SPI2, byte); if (rxptr) *rxptr++ = byte; } }
void nowplus_lcd_disable(void) { u32 memsize = gdev.winSizeX*gdev.winSizeY*gdev.gdfBytesPP; memset((void *)gdev.frameAdrs, 0x00, memsize); //disable graphics pipeline //writel(readl(DISPC_GFX_ATTRIBUTES) & ~(0x1), DISPC_GFX_ATTRIBUTES); #if 0 static unsigned int bus; static unsigned int cs; static unsigned int mode; static int bitlen; static uchar dout[MAX_SPI_BYTES]; static uchar din[MAX_SPI_BYTES]; static struct spi_slave *slave; slave = spi_setup_slave(0, 0, 37500000, mode); if (!slave) { printf("Invalid device %d:%d\n", bus, cs); return 1; } spi_claim_bus(slave); //spi1write(0x14, 0x00); // set black //spi1write(0x1D, 0xA1); // standby on if(spi_xfer(slave, bitlen, dout, din, SPI_XFER_BEGIN | SPI_XFER_END) != 0) { printf("Error during SPI transaction\n"); rcode = 1; } spi_release_bus(slave); spi_free_slave(slave); //Wait 200ms msleep(250); //mdelay(200); #endif #if 0 //disable display writel(readl(DISPC_CONTROL) & ~0x3, DISPC_CONTROL); #endif }
/** * Performs an SPI transfer */ static int do_spi_transfer(const struct spi_slave_params* cfg, void* txbuf, unsigned int wcount, void* rxbuf, unsigned int rcount) { int ret; int status; set_speed(cfg); chip_select(cfg, SPI_CS_ASSERT); /* Begin the transfer */ ret = spi_xfer(spi_bus, txbuf, wcount, rxbuf, rcount, spi_complete_callback, &status); if(ret >= 0){ bus_sem_wait(); ret = status; } chip_select(cfg, SPI_CS_RELEASE); return ret; }
static void UseModule(int module) { if (module == last_module_used) return; u8 cmd = (module & 0x07) | extra_bits; CS_LO(); spi_xfer(PROTO_SPI.spi, cmd); CS_HI(); // Adjust baud rate spi_disable(PROTO_SPI.spi); if (module == MODULE_FLASH) { spi_set_baudrate_prescaler(PROTO_SPI.spi, SPI_CR1_BR_FPCLK_DIV_4); } else if (last_module_used == MODULE_FLASH) { spi_set_baudrate_prescaler(PROTO_SPI.spi, SPI_CR1_BR_FPCLK_DIV_16); } spi_enable(PROTO_SPI.spi); last_module_used = module; }
int cros_ec_spi_packet(struct cros_ec_dev *dev, int out_bytes, int in_bytes) { int rv; /* Do the transfer */ if (spi_claim_bus(dev->spi)) { debug("%s: Cannot claim SPI bus\n", __func__); return -1; } rv = spi_xfer(dev->spi, max(out_bytes, in_bytes) * 8, dev->dout, dev->din, SPI_XFER_BEGIN | SPI_XFER_END); spi_release_bus(dev->spi); if (rv) { debug("%s: Cannot complete SPI transfer\n", __func__); return -1; } return in_bytes; }
/****************************************************************************** * * Function: Fpga_write * * Description: This function writes data to the FPGA * * Parameters: uint8_t* cmd - pointer to the Command to be send to FPGA * uint32_t cmd_len - Length of the command in bytes * uint8_t* Data - Pointer to the data to be written * uint32_t data_len - Length of the data in bytes ******************************************************************************/ FPGA_STATUS fpga_spi_write(uint8_t* cmd,uint32_t cmd_len,uint8_t* data,uint32_t data_len) { FPGA_STATUS ret; uint8_t writecmd = CMDPKT_FPGA_WRITE; /* Claim the SPI controller */ ret = fpga_spiclaim(SPI_FPGA_OPFREQ); if (ret) { spi_release(); return FAIL; } spi_xfer(1,&writecmd,NULL,0); printf("Write command sent:%d\n",writecmd); ret = spi_cmd_write(cmd,cmd_len,data,data_len); if (ret) { spi_release(); return FAIL; } else { spi_release(); return SUCCESS; } }
void m25_write_disable(void) { spi_slave_select(SPI_SLAVE_FLASH); spi_xfer(SPI_BUS_FLASH, M25_WRDI); spi_slave_deselect(); }
void CC2500_Strobe(u8 state) { CS_LO(); spi_xfer(SPI2, state); CS_HI(); }
/** * Send a command to a LPC CROS_EC device and return the reply. * * The device's internal input/output buffers are used. * * @param dev CROS_EC device * @param cmd Command to send (EC_CMD_...) * @param cmd_version Version of command to send (EC_VER_...) * @param dout Output data (may be NULL If dout_len=0) * @param dout_len Size of output data in bytes * @param dinp Returns pointer to response data. This will be * untouched unless we return a value > 0. * @param din_len Maximum size of response in bytes * @return number of bytes in response, or -1 on error */ int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, const uint8_t *dout, int dout_len, uint8_t **dinp, int din_len) { int in_bytes = din_len + 4; /* status, length, checksum, trailer */ uint8_t *out; uint8_t *p; int csum, len; int rv; if (dev->protocol_version != 2) { debug("%s: Unsupported EC protcol version %d\n", __func__, dev->protocol_version); return -1; } /* * Sanity-check input size to make sure it plus transaction overhead * fits in the internal device buffer. */ if (in_bytes > sizeof(dev->din)) { debug("%s: Cannot receive %d bytes\n", __func__, din_len); return -1; } /* We represent message length as a byte */ if (dout_len > 0xff) { debug("%s: Cannot send %d bytes\n", __func__, dout_len); return -1; } /* * Clear input buffer so we don't get false hits for MSG_HEADER */ memset(dev->din, '\0', in_bytes); if (spi_claim_bus(dev->spi)) { debug("%s: Cannot claim SPI bus\n", __func__); return -1; } out = dev->dout; out[0] = EC_CMD_VERSION0 + cmd_version; out[1] = cmd; out[2] = (uint8_t)dout_len; memcpy(out + 3, dout, dout_len); csum = cros_ec_calc_checksum(out, 3) + cros_ec_calc_checksum(dout, dout_len); out[3 + dout_len] = (uint8_t)csum; /* * Send output data and receive input data starting such that the * message body will be dword aligned. */ p = dev->din + sizeof(int64_t) - 2; len = dout_len + 4; cros_ec_dump_data("out", cmd, out, len); rv = spi_xfer(dev->spi, max(len, in_bytes) * 8, out, p, SPI_XFER_BEGIN | SPI_XFER_END); spi_release_bus(dev->spi); if (rv) { debug("%s: Cannot complete SPI transfer\n", __func__); return -1; } len = min(p[1], din_len); cros_ec_dump_data("in", -1, p, len + 3); /* Response code is first byte of message */ if (p[0] != EC_RES_SUCCESS) { printf("%s: Returned status %d\n", __func__, p[0]); return -(int)(p[0]); } /* Check checksum */ csum = cros_ec_calc_checksum(p, len + 2); if (csum != p[len + 2]) { debug("%s: Invalid checksum rx %#02x, calced %#02x\n", __func__, p[2 + len], csum); return -1; } /* Anything else is the response data */ *dinp = p + 2; return len; }
int do_spi (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { struct spi_slave *slave; char *cp = 0; uchar tmp; int j; int rcode = 0; /* * We use the last specified parameters, unless new ones are * entered. */ if ((flag & CMD_FLAG_REPEAT) == 0) { if (argc >= 2) { mode = CONFIG_DEFAULT_SPI_MODE; bus = simple_strtoul(argv[1], &cp, 10); if (*cp == ':') { cs = simple_strtoul(cp+1, &cp, 10); } else { cs = bus; bus = CONFIG_DEFAULT_SPI_BUS; } if (*cp == '.') mode = simple_strtoul(cp+1, NULL, 10); } if (argc >= 3) bitlen = simple_strtoul(argv[2], NULL, 10); if (argc >= 4) { cp = argv[3]; for(j = 0; *cp; j++, cp++) { tmp = *cp - '0'; if(tmp > 9) tmp -= ('A' - '0') - 10; if(tmp > 15) tmp -= ('a' - 'A'); if(tmp > 15) { printf("Hex conversion error on %c\n", *cp); return 1; } if((j % 2) == 0) dout[j / 2] = (tmp << 4); else dout[j / 2] |= tmp; } } } if ((bitlen < 0) || (bitlen > (MAX_SPI_BYTES * 8))) { printf("Invalid bitlen %d\n", bitlen); return 1; } slave = spi_setup_slave(bus, cs, 1000000, mode); if (!slave) { printf("Invalid device %d:%d\n", bus, cs); return 1; } spi_claim_bus(slave); if(spi_xfer(slave, bitlen, dout, din, SPI_XFER_BEGIN | SPI_XFER_END) != 0) { printf("Error during SPI transaction\n"); rcode = 1; } else { for(j = 0; j < ((bitlen + 7) / 8); j++) { printf("%02X", din[j]); } printf("\n"); } spi_release_bus(slave); spi_free_slave(slave); return rcode; }
static int ksz8893m_transfer(struct spi_slave *slave, uchar dir, uchar reg, uchar data, uchar result[3]) { unsigned char dout[3] = { dir, reg, data, }; return spi_xfer(slave, sizeof(dout) * 8, dout, result, SPI_XFER_BEGIN | SPI_XFER_END); }
void exti3_isr(void) { int i, j; uint16_t endFillByte; gpio_set(GREEN_LED_PORT, GREEN_LED_PIN); // gpio_set(RED_LED_PORT, RED_LED_PIN); // iprintf("fill bytes\r\n"); exti_reset_request(EXTI3); iprintf("exti3_isr\r\n"); if(media_file.buffer_ready[media_file.active_buffer] == 0) { iprintf("Buffer %d was ready...\r\n", media_file.active_buffer); while(gpio_get(CODEC_DREQ_PORT, CODEC_DREQ)) { // iprintf("loop\r\n"); gpio_set(CODEC_PORT, CODEC_CS); if(!media_file.near_end) { for(i=0;i<32;i++) { spi_xfer(CODEC_SPI, media_file.buffer[media_file.active_buffer][current_track.byte_count++]); } if((current_track.byte_count % 512) == 0) { gpio_clear(CODEC_PORT, CODEC_CS); } if(current_track.byte_count == MEDIA_BUFFER_SIZE) { // iprintf("reading\r\n"); sdfat_read_media(); current_track.byte_count = 0; gpio_clear(CODEC_PORT, CODEC_CS); // iprintf("swapping...\r\n"); /* fetch the value of current decode position */ vs1053_SCI_write(SCI_WRAMADDR, PARAM_POSITION_LO); for(i=0;i<150;i++) {__asm__("nop\n\t");} current_track.pos = vs1053_SCI_read(SCI_WRAM); for(i=0;i<150;i++) {__asm__("nop\n\t");} vs1053_SCI_write(SCI_WRAMADDR, PARAM_POSITION_HI); for(i=0;i<150;i++) {__asm__("nop\n\t");} current_track.pos += vs1053_SCI_read(SCI_WRAM) << 16; // iprintf("swap\r\n"); gpio_set(CODEC_PORT, CODEC_CS); while(media_file.buffer_ready[media_file.active_buffer]) {__asm__("nop\n\t");} // iprintf("Breaking out\r\n"); // break; // } } } else { for(i=0;i<32;i++) { if(current_track.byte_count > media_file.file_end) { iprintf("ending\r\n"); // Ought to do this next bit by issuing a player_stop job so that the cleanup code // is all in one place and we can power down everything automatically for power saving /* now need to clean up the fifos and stop the player */ gpio_clear(CODEC_PORT, CODEC_CS); /* fetch the value of endFillByte */ vs1053_SCI_write(SCI_WRAMADDR, PARAM_END_FILL_BYTE); while(!gpio_get(CODEC_DREQ_PORT, CODEC_DREQ)) {__asm__("nop\n\t");} endFillByte = vs1053_SCI_read(SCI_WRAM) & 0xFF; iprintf("End Fill Byte %02X\r\n", endFillByte); gpio_set(CODEC_PORT, CODEC_CS); for(i=0;i<65;i++) { while(!gpio_get(CODEC_DREQ_PORT, CODEC_DREQ)) {__asm__("nop\n\t");} for(j=0;j<32;j++) { spi_xfer(CODEC_SPI, endFillByte); } } gpio_clear(CODEC_PORT, CODEC_CS); i = vs1053_SCI_read(SCI_MODE); i |= SM_CANCEL; vs1053_SCI_write(SCI_MODE, i); gpio_set(CODEC_PORT, CODEC_CS); j = 0; while(j < 2048) { while(!gpio_get(CODEC_DREQ_PORT, CODEC_DREQ)) {__asm__("nop\n\t");} for(i=0;i<32;i++) { spi_xfer(CODEC_SPI, endFillByte); } j += 32; if(!(vs1053_SCI_read(SCI_MODE) & SM_CANCEL)) { break; } } gpio_clear(CODEC_PORT, CODEC_CS); if(j >= 2048) { /* need to do a software reset */ vs1053_SCI_write(SCI_MODE, SM_RESET); } iprintf("End Fill Byte %02X\r\n", endFillByte); current_track_playing = 0; exti_reset_request(EXTI3); exti_disable_request(EXTI3); nvic_disable_irq(NVIC_EXTI3_IRQ); return; } else { spi_xfer(CODEC_SPI, media_file.buffer[media_file.active_buffer][current_track.byte_count++]); } } } } } gpio_clear(GREEN_LED_PORT, GREEN_LED_PIN); }
static int mmc_spi_request(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { struct spi_slave *spi = mmc->priv; u8 r1; int i; int ret = 0; debug("%s:cmd%d %x %x\n", __func__, cmd->cmdidx, cmd->resp_type, cmd->cmdarg); spi_claim_bus(spi); spi_cs_activate(spi); r1 = mmc_spi_sendcmd(mmc, cmd->cmdidx, cmd->cmdarg); if (r1 == 0xff) { /* no response */ ret = NO_CARD_ERR; goto done; } else if (r1 & R1_SPI_COM_CRC) { ret = COMM_ERR; goto done; } else if (r1 & ~R1_SPI_IDLE) { /* other errors */ ret = TIMEOUT; goto done; } else if (cmd->resp_type == MMC_RSP_R2) { r1 = mmc_spi_readdata(mmc, cmd->response, 1, 16); for (i = 0; i < 4; i++) cmd->response[i] = be32_to_cpu(cmd->response[i]); debug("r128 %x %x %x %x\n", cmd->response[0], cmd->response[1], cmd->response[2], cmd->response[3]); } else if (!data) { switch (cmd->cmdidx) { case SD_CMD_APP_SEND_OP_COND: case MMC_CMD_SEND_OP_COND: cmd->response[0] = (r1 & R1_SPI_IDLE) ? 0 : OCR_BUSY; break; case SD_CMD_SEND_IF_COND: case MMC_CMD_SPI_READ_OCR: spi_xfer(spi, 4 * 8, NULL, cmd->response, 0); cmd->response[0] = be32_to_cpu(cmd->response[0]); debug("r32 %x\n", cmd->response[0]); break; case MMC_CMD_SEND_STATUS: spi_xfer(spi, 1 * 8, NULL, cmd->response, 0); cmd->response[0] = (cmd->response[0] & 0xff) ? MMC_STATUS_ERROR : MMC_STATUS_RDY_FOR_DATA; break; } } else { debug("%s:data %x %x %x\n", __func__, data->flags, data->blocks, data->blocksize); if (data->flags == MMC_DATA_READ) r1 = mmc_spi_readdata(mmc, data->dest, data->blocks, data->blocksize); else if (data->flags == MMC_DATA_WRITE) r1 = mmc_spi_writedata(mmc, data->src, data->blocks, data->blocksize, (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK)); if (r1 & R1_SPI_COM_CRC) ret = COMM_ERR; else if (r1) /* other errors */ ret = TIMEOUT; } done: spi_cs_deactivate(spi); spi_release_bus(spi); return ret; }
static uint mmc_spi_writedata(struct mmc *mmc, const void *xbuf, u32 bcnt, u32 bsize, int multi) { struct spi_slave *spi = mmc->priv; const u8 *buf = xbuf; u8 r1; u16 crc; u8 tok[2]; int i; tok[0] = 0xff; tok[1] = multi ? SPI_TOKEN_MULTI_WRITE : SPI_TOKEN_SINGLE; while (bcnt--) { #ifdef CONFIG_MMC_SPI_CRC_ON crc = cpu_to_be16(cyg_crc16((u8 *)buf, bsize)); #endif spi_xfer(spi, 2 * 8, tok, NULL, 0); spi_xfer(spi, bsize * 8, buf, NULL, 0); spi_xfer(spi, 2 * 8, &crc, NULL, 0); for (i = 0; i < CTOUT; i++) { spi_xfer(spi, 1 * 8, NULL, &r1, 0); if ((r1 & 0x10) == 0) /* response token */ break; } debug("%s:tok%d %x\n", __func__, i, r1); if (SPI_MMC_RESPONSE_CODE(r1) == SPI_RESPONSE_ACCEPTED) { for (i = 0; i < WTOUT; i++) { /* wait busy */ spi_xfer(spi, 1 * 8, NULL, &r1, 0); if (i && r1 == 0xff) { r1 = 0; break; } } if (i == WTOUT) { debug("%s:wtout %x\n", __func__, r1); r1 = R1_SPI_ERROR; break; } } else { debug("%s: err %x\n", __func__, r1); r1 = R1_SPI_COM_CRC; break; } buf += bsize; } if (multi && bcnt == -1) { /* stop multi write */ tok[1] = SPI_TOKEN_STOP_TRAN; spi_xfer(spi, 2 * 8, tok, NULL, 0); for (i = 0; i < WTOUT; i++) { /* wait busy */ spi_xfer(spi, 1 * 8, NULL, &r1, 0); if (i && r1 == 0xff) { r1 = 0; break; } } if (i == WTOUT) { debug("%s:wstop %x\n", __func__, r1); r1 = R1_SPI_ERROR; } } return r1; }
/* * Once transaction is initiated and the TPM indicated that it is ready to go, * read the actual bytes from the register. */ static void read_bytes(void *buffer, size_t bytes) { struct spi_slave *spi_slave = car_get_var_ptr(&g_spi_slave); spi_xfer(spi_slave, NULL, 0, buffer, bytes); }
void flash_write_enable() { spi_begin(); spi_xfer(0x06, 8); spi_end(); }
void flash_power_up() { spi_begin(); spi_xfer(0xAB, 8); spi_end(); }
void processSPI(void) { uint8_t b, c; b = spi_xfer(0); switch (b) { case 0x80: // set brightness c = spi_xfer(0); set_brightness(c); eeprom_write_byte(&b_brightness, c); break; case 0x82: // clear clear_screen(); counter = 0; dots = 0; break; case 0x83: // set scroll mode c = spi_xfer(0); if (c == 0) scroll_mode = ROTATE; else scroll_mode = SCROLL; break; case 0x84: // receive segment data c = spi_xfer(0); /* if (scroll_mode == ROTATE) { set_segments_at(c, counter++); if (counter >= 4) counter = 0; } else { shift_in_segments(c); } */ break; case 0x85: // set dots (the four bits of the second byte controls dots individually) dots = spi_xfer(0); break; case 0x88: // display integer { uint8_t i1 = spi_xfer(0); uint8_t i2 = spi_xfer(0); uint16_t i = (i2 << 8) + i1; set_number(i); } break; case 0x89: // set position (only valid for ROTATE mode) counter = spi_xfer(0); break; case 0x8a: // get firmware revision spi_xfer(3); break; case 0x8b: // get number of digits spi_xfer(8); break; default: if (b >= 0x80) break; // anything above 0x80 is considered a reserved command and is ignored if (scroll_mode == ROTATE) { set_char_at(b, counter++); if (counter >= 8) counter = 0; } else { shift_in(b); } break; } }
uint8_t spi_msg(uint8_t dat) { return spi_xfer(CODEC_SPI, dat); }
/* * Each TPM2 SPI transaction starts the same: CS is asserted, the 4 byte * header is sent to the TPM, the master waits til TPM is ready to continue. * * Returns 1 on success, 0 on failure (TPM SPI flow control timeout.) */ static int start_transaction(int read_write, size_t bytes, unsigned addr) { spi_frame_header header; uint8_t byte; int i; struct stopwatch sw; static int tpm_sync_needed CAR_GLOBAL; static struct stopwatch wake_up_sw CAR_GLOBAL; struct spi_slave *spi_slave = car_get_var_ptr(&g_spi_slave); /* * First Cr50 access in each coreboot stage where TPM is used will be * prepended by a wake up pulse on the CS line. */ int wakeup_needed = 1; /* Wait for TPM to finish previous transaction if needed */ if (car_get_var(tpm_sync_needed)) { tpm_sync(); /* * During the first invocation of this function on each stage * this if () clause code does not run (as tpm_sync_needed * value is zero), during all following invocations the * stopwatch below is guaranteed to be started. */ if (!stopwatch_expired(car_get_var_ptr(&wake_up_sw))) wakeup_needed = 0; } else { car_set_var(tpm_sync_needed, 1); } if (wakeup_needed) { /* Just in case Cr50 is asleep. */ spi_claim_bus(spi_slave); udelay(1); spi_release_bus(spi_slave); udelay(100); } /* * The Cr50 on H1 does not go to sleep for 1 second after any * SPI slave activity, let's be conservative and limit the * window to 900 ms. */ stopwatch_init_msecs_expire(car_get_var_ptr(&wake_up_sw), 900); /* * The first byte of the frame header encodes the transaction type * (read or write) and transfer size (set to lentgh - 1), limited to * 64 bytes. */ header.body[0] = (read_write ? 0x80 : 0) | 0x40 | (bytes - 1); /* The rest of the frame header is the TPM register address. */ for (i = 0; i < 3; i++) header.body[i + 1] = (addr >> (8 * (2 - i))) & 0xff; /* CS assert wakes up the slave. */ spi_claim_bus(spi_slave); /* * The TCG TPM over SPI specification introduces the notion of SPI * flow control (Section "6.4.5 Flow Control"). * * Again, the slave (TPM device) expects each transaction to start * with a 4 byte header trasmitted by master. The header indicates if * the master needs to read or write a register, and the register * address. * * If the slave needs to stall the transaction (for instance it is not * ready to send the register value to the master), it sets the MOSI * line to 0 during the last clock of the 4 byte header. In this case * the master is supposed to start polling the SPI bus, one byte at * time, until the last bit in the received byte (transferred during * the last clock of the byte) is set to 1. * * Due to some SPI controllers' shortcomings (Rockchip comes to * mind...) we trasmit the 4 byte header without checking the byte * transmitted by the TPM during the transaction's last byte. * * We know that cr50 is guaranteed to set the flow control bit to 0 * during the header transfer, but real TPM2 might be fast enough not * to require to stall the master, this would present an issue. * crosbug.com/p/52132 has been opened to track this. */ spi_xfer(spi_slave, header.body, sizeof(header.body), NULL, 0); /* * Now poll the bus until TPM removes the stall bit. Give it up to 100 * ms to sort it out - it could be saving stuff in nvram at some * point. */ stopwatch_init_msecs_expire(&sw, 100); do { if (stopwatch_expired(&sw)) { printk(BIOS_ERR, "TPM flow control failure\n"); spi_release_bus(spi_slave); return 0; } spi_xfer(spi_slave, NULL, 0, &byte, 1); } while (!(byte & 1)); return 1; }
/* * Once transaction is initiated and the TPM indicated that it is ready to go, * write the actual bytes to the register. */ static void write_bytes(const void *buffer, size_t bytes) { struct spi_slave *spi_slave = car_get_var_ptr(&g_spi_slave); spi_xfer(spi_slave, buffer, bytes, NULL, 0); }
int do_spi (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { struct spi_slave *slave; char *cp = 0; uchar tmp; int j; int rcode = 0; /* * We use the last specified parameters, unless new ones are * entered. */ if ((flag & CMD_FLAG_REPEAT) == 0) { if (argc >= 2) device = simple_strtoul(argv[1], NULL, 10); if (argc >= 3) bitlen = simple_strtoul(argv[2], NULL, 10); if (argc >= 4) { cp = argv[3]; for(j = 0; *cp; j++, cp++) { tmp = *cp - '0'; if(tmp > 9) tmp -= ('A' - '0') - 10; if(tmp > 15) tmp -= ('a' - 'A'); if(tmp > 15) { printf("Hex conversion error on %c, giving up.\n", *cp); return 1; } if((j % 2) == 0) dout[j / 2] = (tmp << 4); else dout[j / 2] |= tmp; } } } if ((bitlen < 0) || (bitlen > (MAX_SPI_BYTES * 8))) { printf("Invalid bitlen %d, giving up.\n", bitlen); return 1; } /* FIXME: Make these parameters run-time configurable */ slave = spi_setup_slave(CONFIG_DEFAULT_SPI_BUS, device, 1000000, CONFIG_DEFAULT_SPI_MODE); if (!slave) { printf("Invalid device %d, giving up.\n", device); return 1; } debug ("spi chipsel = %08X\n", device); spi_claim_bus(slave); if(spi_xfer(slave, bitlen, dout, din, SPI_XFER_BEGIN | SPI_XFER_END) != 0) { printf("Error with the SPI transaction.\n"); rcode = 1; } else { for(j = 0; j < ((bitlen + 7) / 8); j++) { printf("%02X", din[j]); } printf("\n"); } spi_release_bus(slave); spi_free_slave(slave); return rcode; }