+ /* We need to disable SPI before changing registers */
+ reg_ctrl &= ~MXC_CSPICTRL_EN;
+
+ if (mode & SPI_CS_HIGH)
+ ss_pol = 1;
+
+ if (mode & SPI_CPOL)
+ sclkpol = 1;
+
+ if (mode & SPI_CPHA)
+ sclkpha = 1;
+
+ reg_config = reg_read(®s->cfg);
+
+ /*
+ * Configuration register setup
+ * The MX51 supports different setup for each SS
+ */
+ reg_config = (reg_config & ~(1 << (cs + MXC_CSPICON_SSPOL))) |
+ (ss_pol << (cs + MXC_CSPICON_SSPOL));
+ reg_config = (reg_config & ~(1 << (cs + MXC_CSPICON_POL))) |
+ (sclkpol << (cs + MXC_CSPICON_POL));
+ reg_config = (reg_config & ~(1 << (cs + MXC_CSPICON_PHA))) |
+ (sclkpha << (cs + MXC_CSPICON_PHA));
+
+ debug("reg_ctrl = 0x%x\n", reg_ctrl);
+ reg_write(®s->ctrl, reg_ctrl);
+ debug("reg_config = 0x%x\n", reg_config);
+ reg_write(®s->cfg, reg_config);
+
+ /* save config register and control register */
+ mxcs->ctrl_reg = reg_ctrl;
+ mxcs->cfg_reg = reg_config;
+
+ /* clear interrupt reg */
+ reg_write(®s->intr, 0);
+ reg_write(®s->stat, MXC_CSPICTRL_TC | MXC_CSPICTRL_RXOVF);
+
+ return 0;
+}
+#endif
+
+int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen,
+ const u8 *dout, u8 *din, unsigned long flags)
+{
+ struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave);
+ int nbytes = (bitlen + 7) / 8;
+ u32 data, cnt, i;
+ struct cspi_regs *regs = (struct cspi_regs *)mxcs->base;
+
+ debug("%s: bitlen %d dout 0x%x din 0x%x\n",
+ __func__, bitlen, (u32)dout, (u32)din);
+
+ mxcs->ctrl_reg = (mxcs->ctrl_reg &
+ ~MXC_CSPICTRL_BITCOUNT(MXC_CSPICTRL_MAXBITS)) |
+ MXC_CSPICTRL_BITCOUNT(bitlen - 1);
+
+ reg_write(®s->ctrl, mxcs->ctrl_reg | MXC_CSPICTRL_EN);
+#ifdef CONFIG_MX51
+ reg_write(®s->cfg, mxcs->cfg_reg);
+#endif
+
+ /* Clear interrupt register */
+ reg_write(®s->stat, MXC_CSPICTRL_TC | MXC_CSPICTRL_RXOVF);
+
+ /*
+ * The SPI controller works only with words,
+ * check if less than a word is sent.
+ * Access to the FIFO is only 32 bit
+ */
+ if (bitlen % 32) {
+ data = 0;
+ cnt = (bitlen % 32) / 8;
+ if (dout) {
+ for (i = 0; i < cnt; i++) {
+ data = (data << 8) | (*dout++ & 0xFF);
+ }
+ }
+ debug("Sending SPI 0x%x\n", data);
+
+ reg_write(®s->txdata, data);
+ nbytes -= cnt;
+ }
+
+ data = 0;
+
+ while (nbytes > 0) {
+ data = 0;
+ if (dout) {
+ /* Buffer is not 32-bit aligned */
+ if ((unsigned long)dout & 0x03) {
+ data = 0;
+ for (i = 0; i < 4; i++)
+ data = (data << 8) | (*dout++ & 0xFF);
+ } else {
+ data = *(u32 *)dout;
+ data = cpu_to_be32(data);
+ }
+ dout += 4;
+ }
+ debug("Sending SPI 0x%x\n", data);
+ reg_write(®s->txdata, data);
+ nbytes -= 4;
+ }
+
+ /* FIFO is written, now starts the transfer setting the XCH bit */
+ reg_write(®s->ctrl, mxcs->ctrl_reg |
+ MXC_CSPICTRL_EN | MXC_CSPICTRL_XCH);
+
+ /* Wait until the TC (Transfer completed) bit is set */
+ while ((reg_read(®s->stat) & MXC_CSPICTRL_TC) == 0)
+ ;
+
+ /* Transfer completed, clear any pending request */
+ reg_write(®s->stat, MXC_CSPICTRL_TC | MXC_CSPICTRL_RXOVF);
+
+ nbytes = (bitlen + 7) / 8;
+
+ cnt = nbytes % 32;
+
+ if (bitlen % 32) {
+ data = reg_read(®s->rxdata);
+ cnt = (bitlen % 32) / 8;
+ data = cpu_to_be32(data) >> ((sizeof(data) - cnt) * 8);
+ debug("SPI Rx unaligned: 0x%x\n", data);
+ if (din) {
+ memcpy(din, &data, cnt);
+ din += cnt;
+ }
+ nbytes -= cnt;
+ }
+
+ while (nbytes > 0) {
+ u32 tmp;
+ tmp = reg_read(®s->rxdata);
+ data = cpu_to_be32(tmp);
+ debug("SPI Rx: 0x%x 0x%x\n", tmp, data);
+ cnt = min(nbytes, sizeof(data));
+ if (din) {
+ memcpy(din, &data, cnt);
+ din += cnt;
+ }
+ nbytes -= cnt;
+ }
+
+ return 0;
+
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
+ void *din, unsigned long flags)
+{
+ int n_bytes = (bitlen + 7) / 8;
+ int n_bits;
+ int ret;
+ u32 blk_size;
+ u8 *p_outbuf = (u8 *)dout;
+ u8 *p_inbuf = (u8 *)din;
+
+ if (!slave)
+ return -1;
+
+ if (flags & SPI_XFER_BEGIN)
+ spi_cs_activate(slave);
+
+ while (n_bytes > 0) {
+ if (n_bytes < MAX_SPI_BYTES)
+ blk_size = n_bytes;
+ else
+ blk_size = MAX_SPI_BYTES;
+
+ n_bits = blk_size * 8;
+
+ ret = spi_xchg_single(slave, n_bits, p_outbuf, p_inbuf, 0);
+
+ if (ret)
+ return ret;
+ if (dout)
+ p_outbuf += blk_size;
+ if (din)
+ p_inbuf += blk_size;
+ n_bytes -= blk_size;
+ }
+
+ if (flags & SPI_XFER_END) {
+ spi_cs_deactivate(slave);
+ }