/* * Transfer (i.e. exchange) one "word" with selected SPI device. * Typically one word is 8-bits (an octet), but it does not need to be, * this function is word-width agnostic - when using the SSC. * However, for PIO bit-banging, then one word is explicitly * unconditionally assumed to be exactly 8-bits in length. * * input: "out" is word to be send to slave SPI device * returns: one word read from the slave SPI device * * It is the caller's responsibility to ensure that the * chip select (SPI_NOTCS) is correctly asserted. */ static unsigned int spi_xfer_one_word(const unsigned int out) { unsigned int in = 0; #if defined(CONFIG_SOFT_SPI) /* Use PIO Bit-Banging for SPI */ signed int i; for(i=7; i>=0; i--) /* for each bit in turn ... */ { /* do 8 bits, msb first */ SPI_SCL(0); /* SPI_CLK = low */ SPI_SDA(out & (1u<<i)); /* output next bit on SPI_DOUT */ SPI_DELAY; /* clock low cycle */ SPI_SCL(1); /* SPI_CLK = high */ SPI_DELAY; /* sample on RISING clock edge */ in <<= 1; /* shift */ in |= SPI_READ; /* get next bit from SPI_DIN */ } #else /* Use SSC for SPI */ /* write out data 'out' */ ssc_write(SSC_TBUF, out); /* wait for Receive Buffer Full flag to be asserted */ while ((ssc_read(SSC_STAT) & SSC_STAT_RIR) == 0) { ; /* busy poll - do nothing */ } /* read in data */ in = ssc_read(SSC_RBUF); #endif /* CONFIG_SOFT_SPI */ /* return exchanged data */ return in; }
/** * \brief Synchronous Serial Controller Handler. * */ void SSC_Handler(void) { uint32_t ul_data; ssc_get_status(SSC); ssc_read(SSC, &ul_data); g_uc_rx_buff[g_uc_rx_index++] = ul_data; if (BUFFER_SIZE == g_uc_rx_index) { g_uc_rx_done = 1; ssc_disable_interrupt(SSC, SSC_IDR_RXRDY); } }
/* * initialise the SSC to talk to the slave SPI device. */ extern void spi_init(void) { //DECLARE_GLOBAL_DATA_PTR; spi_chipsel_type const chipsel = spi_chipsel[0]; /* SPI Device #0 */ #if !defined(CONFIG_SOFT_SPI) /* Use SSC for SPI */ unsigned long reg; const unsigned long bits_per_word = 8; /* one word == 8-bits */ const unsigned long mode = CFG_STM_SPI_MODE /* | SPI_LOOP */; //const unsigned long fcomms = gd->bd->bi_emifrq*1000*1000; const unsigned long hz = CFG_STM_SPI_FREQUENCY; //unsigned long sscbrg = fcomms/(2*hz); #endif /* CONFIG_SOFT_SPI */ /*init pio15.0-pio15.3*/ configSpi(); /* de-assert SPI CS */ (*chipsel)(0); #if !defined(CONFIG_SOFT_SPI) /* Use SSC for SPI */ /* program the SSC's Baud-Rate Generator */ if ((sscbrg < 0x07u) || (sscbrg > (0x1u << 16))) { printk("ERROR: Unable to set SSC buad-rate generator to 0x%04x\n", sscbrg); return; } /* TODO: program pre-scaler for slower baud rates */ if (sscbrg == (0x1 << 16)) /* 16-bit counter wraps */ { sscbrg = 0x0; /* slowest possible clock frequency */ } ssc_write(SSC_BRG,sscbrg); #if 0 /* QQQ */ printk("info: fcomms=%uMHz, SPI=%uHz, brg=0x%04x\n", fcomms/1000/1000, hz, sscbrg); #endif /* Disable I2C sub-system */ ssc_write( SSC_I2C, 0x0); /* Perform a S/W reset the SSC */ reg = ssc_read( SSC_CON); reg |= SSC_CON_SR; /* enable software reset */ ssc_write( SSC_CON, reg); udelay(1); /* let reset propagate */ reg = ssc_read( SSC_CON); reg &= ~SSC_CON_SR; /* disable software reset */ ssc_write( SSC_CON, reg); /* Configure & enable the SSC's control register */ reg = ssc_read(SSC_CON); reg |= SSC_CON_EN; /* Enable the SSC */ reg |= SSC_CON_MS; /* set SSC as the SPI master */ if (mode & SPI_CPOL) reg |= SSC_CON_PO; /* Clock idles at logic 1 */ else reg &= ~SSC_CON_PO; /* Clock idles at logic 0 */ if (mode & SPI_CPHA) reg |= SSC_CON_PH; /* Pulse in first half-cycle */ else reg &= ~SSC_CON_PH; /* Pulse in second half-cycle */ if (mode & SPI_LSB_FIRST) reg &= ~SSC_CON_HB; /* LSB first */ else reg |= SSC_CON_HB; /* MSB first */ if (mode & SPI_LOOP) reg |= SSC_CON_LPB; /* put SSC in loop-back mode */ else reg &= ~SSC_CON_LPB; /* remove SSC from loop-back mode */ reg &= ~0x0ful; /* set bit width */ reg |= (bits_per_word - 1ul); /* set bit width */ ssc_write(SSC_CON,reg); /* clear the status register */ (void)ssc_read(SSC_RBUF); #endif /* CONFIG_SOFT_SPI */ /* now probe the serial flash, to ensure it is the correct one */ spi_probe_serial_flash(chipsel); }