1ff1da6fbSAllen Martin /* 2*6b3a03e1SAllen Martin * Copyright (c) 2010-2013 NVIDIA Corporation 3ff1da6fbSAllen Martin * With help from the mpc8xxx SPI driver 4ff1da6fbSAllen Martin * With more help from omap3_spi SPI driver 5ff1da6fbSAllen Martin * 6ff1da6fbSAllen Martin * See file CREDITS for list of people who contributed to this 7ff1da6fbSAllen Martin * project. 8ff1da6fbSAllen Martin * 9ff1da6fbSAllen Martin * This program is free software; you can redistribute it and/or 10ff1da6fbSAllen Martin * modify it under the terms of the GNU General Public License as 11ff1da6fbSAllen Martin * published by the Free Software Foundation; either version 2 of 12ff1da6fbSAllen Martin * the License, or (at your option) any later version. 13ff1da6fbSAllen Martin * 14ff1da6fbSAllen Martin * This program is distributed in the hope that it will be useful, 15ff1da6fbSAllen Martin * but WITHOUT ANY WARRANTY; without even the implied warranty of 16ff1da6fbSAllen Martin * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17ff1da6fbSAllen Martin * GNU General Public License for more details. 18ff1da6fbSAllen Martin * 19ff1da6fbSAllen Martin * You should have received a copy of the GNU General Public License 20ff1da6fbSAllen Martin * along with this program; if not, write to the Free Software 21ff1da6fbSAllen Martin * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 22ff1da6fbSAllen Martin * MA 02111-1307 USA 23ff1da6fbSAllen Martin */ 24ff1da6fbSAllen Martin 25ff1da6fbSAllen Martin #include <common.h> 26ff1da6fbSAllen Martin #include <malloc.h> 27ff1da6fbSAllen Martin #include <asm/io.h> 28ff1da6fbSAllen Martin #include <asm/gpio.h> 29ff1da6fbSAllen Martin #include <asm/arch/clock.h> 30ff1da6fbSAllen Martin #include <asm/arch/pinmux.h> 31ff1da6fbSAllen Martin #include <asm/arch-tegra/clk_rst.h> 32ff1da6fbSAllen Martin #include <asm/arch-tegra20/tegra20_sflash.h> 33ff1da6fbSAllen Martin #include <spi.h> 34ff1da6fbSAllen Martin #include <fdtdec.h> 35ff1da6fbSAllen Martin 36ff1da6fbSAllen Martin DECLARE_GLOBAL_DATA_PTR; 37ff1da6fbSAllen Martin 387a49ba6eSAllen Martin #define SPI_CMD_GO (1 << 30) 397a49ba6eSAllen Martin #define SPI_CMD_ACTIVE_SCLK_SHIFT 26 407a49ba6eSAllen Martin #define SPI_CMD_ACTIVE_SCLK_MASK (3 << SPI_CMD_ACTIVE_SCLK_SHIFT) 417a49ba6eSAllen Martin #define SPI_CMD_CK_SDA (1 << 21) 427a49ba6eSAllen Martin #define SPI_CMD_ACTIVE_SDA_SHIFT 18 437a49ba6eSAllen Martin #define SPI_CMD_ACTIVE_SDA_MASK (3 << SPI_CMD_ACTIVE_SDA_SHIFT) 447a49ba6eSAllen Martin #define SPI_CMD_CS_POL (1 << 16) 457a49ba6eSAllen Martin #define SPI_CMD_TXEN (1 << 15) 467a49ba6eSAllen Martin #define SPI_CMD_RXEN (1 << 14) 477a49ba6eSAllen Martin #define SPI_CMD_CS_VAL (1 << 13) 487a49ba6eSAllen Martin #define SPI_CMD_CS_SOFT (1 << 12) 497a49ba6eSAllen Martin #define SPI_CMD_CS_DELAY (1 << 9) 507a49ba6eSAllen Martin #define SPI_CMD_CS3_EN (1 << 8) 517a49ba6eSAllen Martin #define SPI_CMD_CS2_EN (1 << 7) 527a49ba6eSAllen Martin #define SPI_CMD_CS1_EN (1 << 6) 537a49ba6eSAllen Martin #define SPI_CMD_CS0_EN (1 << 5) 547a49ba6eSAllen Martin #define SPI_CMD_BIT_LENGTH (1 << 4) 557a49ba6eSAllen Martin #define SPI_CMD_BIT_LENGTH_MASK 0x0000001F 567a49ba6eSAllen Martin 577a49ba6eSAllen Martin #define SPI_STAT_BSY (1 << 31) 587a49ba6eSAllen Martin #define SPI_STAT_RDY (1 << 30) 597a49ba6eSAllen Martin #define SPI_STAT_RXF_FLUSH (1 << 29) 607a49ba6eSAllen Martin #define SPI_STAT_TXF_FLUSH (1 << 28) 617a49ba6eSAllen Martin #define SPI_STAT_RXF_UNR (1 << 27) 627a49ba6eSAllen Martin #define SPI_STAT_TXF_OVF (1 << 26) 637a49ba6eSAllen Martin #define SPI_STAT_RXF_EMPTY (1 << 25) 647a49ba6eSAllen Martin #define SPI_STAT_RXF_FULL (1 << 24) 657a49ba6eSAllen Martin #define SPI_STAT_TXF_EMPTY (1 << 23) 667a49ba6eSAllen Martin #define SPI_STAT_TXF_FULL (1 << 22) 677a49ba6eSAllen Martin #define SPI_STAT_SEL_TXRX_N (1 << 16) 687a49ba6eSAllen Martin #define SPI_STAT_CUR_BLKCNT (1 << 15) 697a49ba6eSAllen Martin 707a49ba6eSAllen Martin #define SPI_TIMEOUT 1000 717a49ba6eSAllen Martin #define TEGRA_SPI_MAX_FREQ 52000000 727a49ba6eSAllen Martin 737a49ba6eSAllen Martin struct spi_regs { 747a49ba6eSAllen Martin u32 command; /* SPI_COMMAND_0 register */ 757a49ba6eSAllen Martin u32 status; /* SPI_STATUS_0 register */ 767a49ba6eSAllen Martin u32 rx_cmp; /* SPI_RX_CMP_0 register */ 777a49ba6eSAllen Martin u32 dma_ctl; /* SPI_DMA_CTL_0 register */ 787a49ba6eSAllen Martin u32 tx_fifo; /* SPI_TX_FIFO_0 register */ 797a49ba6eSAllen Martin u32 rsvd[3]; /* offsets 0x14 to 0x1F reserved */ 807a49ba6eSAllen Martin u32 rx_fifo; /* SPI_RX_FIFO_0 register */ 817a49ba6eSAllen Martin }; 827a49ba6eSAllen Martin 83*6b3a03e1SAllen Martin struct tegra_spi_ctrl { 847a49ba6eSAllen Martin struct spi_regs *regs; 85ff1da6fbSAllen Martin unsigned int freq; 86ff1da6fbSAllen Martin unsigned int mode; 87ff1da6fbSAllen Martin int periph_id; 88*6b3a03e1SAllen Martin int valid; 89ff1da6fbSAllen Martin }; 90ff1da6fbSAllen Martin 91*6b3a03e1SAllen Martin struct tegra_spi_slave { 92*6b3a03e1SAllen Martin struct spi_slave slave; 93*6b3a03e1SAllen Martin struct tegra_spi_ctrl *ctrl; 94*6b3a03e1SAllen Martin }; 95*6b3a03e1SAllen Martin 96*6b3a03e1SAllen Martin /* tegra20 only supports one SFLASH controller */ 97*6b3a03e1SAllen Martin static struct tegra_spi_ctrl spi_ctrls[1]; 98*6b3a03e1SAllen Martin 99ff1da6fbSAllen Martin static inline struct tegra_spi_slave *to_tegra_spi(struct spi_slave *slave) 100ff1da6fbSAllen Martin { 101ff1da6fbSAllen Martin return container_of(slave, struct tegra_spi_slave, slave); 102ff1da6fbSAllen Martin } 103ff1da6fbSAllen Martin 104ff1da6fbSAllen Martin int spi_cs_is_valid(unsigned int bus, unsigned int cs) 105ff1da6fbSAllen Martin { 106ff1da6fbSAllen Martin /* Tegra20 SPI-Flash - only 1 device ('bus/cs') */ 107ff1da6fbSAllen Martin if (bus != 0 || cs != 0) 108ff1da6fbSAllen Martin return 0; 109ff1da6fbSAllen Martin else 110ff1da6fbSAllen Martin return 1; 111ff1da6fbSAllen Martin } 112ff1da6fbSAllen Martin 113ff1da6fbSAllen Martin struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, 114ff1da6fbSAllen Martin unsigned int max_hz, unsigned int mode) 115ff1da6fbSAllen Martin { 116ff1da6fbSAllen Martin struct tegra_spi_slave *spi; 117ff1da6fbSAllen Martin 118ff1da6fbSAllen Martin if (!spi_cs_is_valid(bus, cs)) { 119ff1da6fbSAllen Martin printf("SPI error: unsupported bus %d / chip select %d\n", 120ff1da6fbSAllen Martin bus, cs); 121ff1da6fbSAllen Martin return NULL; 122ff1da6fbSAllen Martin } 123ff1da6fbSAllen Martin 124ff1da6fbSAllen Martin if (max_hz > TEGRA_SPI_MAX_FREQ) { 125ff1da6fbSAllen Martin printf("SPI error: unsupported frequency %d Hz. Max frequency" 126ff1da6fbSAllen Martin " is %d Hz\n", max_hz, TEGRA_SPI_MAX_FREQ); 127ff1da6fbSAllen Martin return NULL; 128ff1da6fbSAllen Martin } 129ff1da6fbSAllen Martin 130ff1da6fbSAllen Martin spi = malloc(sizeof(struct tegra_spi_slave)); 131ff1da6fbSAllen Martin if (!spi) { 132ff1da6fbSAllen Martin printf("SPI error: malloc of SPI structure failed\n"); 133ff1da6fbSAllen Martin return NULL; 134ff1da6fbSAllen Martin } 135ff1da6fbSAllen Martin spi->slave.bus = bus; 136ff1da6fbSAllen Martin spi->slave.cs = cs; 137*6b3a03e1SAllen Martin spi->ctrl = &spi_ctrls[bus]; 138*6b3a03e1SAllen Martin if (!spi->ctrl) { 139*6b3a03e1SAllen Martin printf("SPI error: could not find controller for bus %d\n", 140*6b3a03e1SAllen Martin bus); 141*6b3a03e1SAllen Martin return NULL; 142*6b3a03e1SAllen Martin } 1432a3c5bc2SAllen Martin 144*6b3a03e1SAllen Martin if (max_hz < spi->ctrl->freq) { 145ff1da6fbSAllen Martin debug("%s: limiting frequency from %u to %u\n", __func__, 146*6b3a03e1SAllen Martin spi->ctrl->freq, max_hz); 147*6b3a03e1SAllen Martin spi->ctrl->freq = max_hz; 148ff1da6fbSAllen Martin } 149*6b3a03e1SAllen Martin spi->ctrl->mode = mode; 150ff1da6fbSAllen Martin 151ff1da6fbSAllen Martin return &spi->slave; 152ff1da6fbSAllen Martin } 153ff1da6fbSAllen Martin 154ff1da6fbSAllen Martin void spi_free_slave(struct spi_slave *slave) 155ff1da6fbSAllen Martin { 156ff1da6fbSAllen Martin struct tegra_spi_slave *spi = to_tegra_spi(slave); 157ff1da6fbSAllen Martin 158ff1da6fbSAllen Martin free(spi); 159ff1da6fbSAllen Martin } 160ff1da6fbSAllen Martin 161ff1da6fbSAllen Martin void spi_init(void) 162ff1da6fbSAllen Martin { 163*6b3a03e1SAllen Martin struct tegra_spi_ctrl *ctrl; 164*6b3a03e1SAllen Martin int i; 165*6b3a03e1SAllen Martin int node = 0; 166*6b3a03e1SAllen Martin int count; 167*6b3a03e1SAllen Martin int node_list[1]; 168*6b3a03e1SAllen Martin 169*6b3a03e1SAllen Martin count = fdtdec_find_aliases_for_id(gd->fdt_blob, "spi", 170*6b3a03e1SAllen Martin COMPAT_NVIDIA_TEGRA20_SFLASH, 171*6b3a03e1SAllen Martin node_list, 172*6b3a03e1SAllen Martin 1); 173*6b3a03e1SAllen Martin for (i = 0; i < count; i++) { 174*6b3a03e1SAllen Martin ctrl = &spi_ctrls[i]; 175*6b3a03e1SAllen Martin node = node_list[i]; 176*6b3a03e1SAllen Martin 177*6b3a03e1SAllen Martin ctrl->regs = (struct spi_regs *)fdtdec_get_addr(gd->fdt_blob, 178*6b3a03e1SAllen Martin node, "reg"); 179*6b3a03e1SAllen Martin if ((fdt_addr_t)ctrl->regs == FDT_ADDR_T_NONE) { 180*6b3a03e1SAllen Martin debug("%s: no slink register found\n", __func__); 181*6b3a03e1SAllen Martin continue; 182*6b3a03e1SAllen Martin } 183*6b3a03e1SAllen Martin ctrl->freq = fdtdec_get_int(gd->fdt_blob, node, 184*6b3a03e1SAllen Martin "spi-max-frequency", 0); 185*6b3a03e1SAllen Martin if (!ctrl->freq) { 186*6b3a03e1SAllen Martin debug("%s: no slink max frequency found\n", __func__); 187*6b3a03e1SAllen Martin continue; 188*6b3a03e1SAllen Martin } 189*6b3a03e1SAllen Martin 190*6b3a03e1SAllen Martin ctrl->periph_id = clock_decode_periph_id(gd->fdt_blob, node); 191*6b3a03e1SAllen Martin if (ctrl->periph_id == PERIPH_ID_NONE) { 192*6b3a03e1SAllen Martin debug("%s: could not decode periph id\n", __func__); 193*6b3a03e1SAllen Martin continue; 194*6b3a03e1SAllen Martin } 195*6b3a03e1SAllen Martin ctrl->valid = 1; 196*6b3a03e1SAllen Martin 197*6b3a03e1SAllen Martin debug("%s: found controller at %p, freq = %u, periph_id = %d\n", 198*6b3a03e1SAllen Martin __func__, ctrl->regs, ctrl->freq, ctrl->periph_id); 199*6b3a03e1SAllen Martin } 200ff1da6fbSAllen Martin } 201ff1da6fbSAllen Martin 202ff1da6fbSAllen Martin int spi_claim_bus(struct spi_slave *slave) 203ff1da6fbSAllen Martin { 204ff1da6fbSAllen Martin struct tegra_spi_slave *spi = to_tegra_spi(slave); 205*6b3a03e1SAllen Martin struct spi_regs *regs = spi->ctrl->regs; 206ff1da6fbSAllen Martin u32 reg; 207ff1da6fbSAllen Martin 208ff1da6fbSAllen Martin /* Change SPI clock to correct frequency, PLLP_OUT0 source */ 209*6b3a03e1SAllen Martin clock_start_periph_pll(spi->ctrl->periph_id, CLOCK_ID_PERIPH, 210*6b3a03e1SAllen Martin spi->ctrl->freq); 211ff1da6fbSAllen Martin 212ff1da6fbSAllen Martin /* Clear stale status here */ 213ff1da6fbSAllen Martin reg = SPI_STAT_RDY | SPI_STAT_RXF_FLUSH | SPI_STAT_TXF_FLUSH | \ 214ff1da6fbSAllen Martin SPI_STAT_RXF_UNR | SPI_STAT_TXF_OVF; 215ff1da6fbSAllen Martin writel(reg, ®s->status); 216ff1da6fbSAllen Martin debug("spi_init: STATUS = %08x\n", readl(®s->status)); 217ff1da6fbSAllen Martin 218ff1da6fbSAllen Martin /* 219ff1da6fbSAllen Martin * Use sw-controlled CS, so we can clock in data after ReadID, etc. 220ff1da6fbSAllen Martin */ 221*6b3a03e1SAllen Martin reg = (spi->ctrl->mode & 1) << SPI_CMD_ACTIVE_SDA_SHIFT; 222*6b3a03e1SAllen Martin if (spi->ctrl->mode & 2) 223ff1da6fbSAllen Martin reg |= 1 << SPI_CMD_ACTIVE_SCLK_SHIFT; 224ff1da6fbSAllen Martin clrsetbits_le32(®s->command, SPI_CMD_ACTIVE_SCLK_MASK | 225ff1da6fbSAllen Martin SPI_CMD_ACTIVE_SDA_MASK, SPI_CMD_CS_SOFT | reg); 226ff1da6fbSAllen Martin debug("spi_init: COMMAND = %08x\n", readl(®s->command)); 227ff1da6fbSAllen Martin 228ff1da6fbSAllen Martin /* 229ff1da6fbSAllen Martin * SPI pins on Tegra20 are muxed - change pinmux later due to UART 230ff1da6fbSAllen Martin * issue. 231ff1da6fbSAllen Martin */ 232ff1da6fbSAllen Martin pinmux_set_func(PINGRP_GMD, PMUX_FUNC_SFLASH); 233ff1da6fbSAllen Martin pinmux_tristate_disable(PINGRP_LSPI); 234ff1da6fbSAllen Martin pinmux_set_func(PINGRP_GMC, PMUX_FUNC_SFLASH); 235ff1da6fbSAllen Martin 236ff1da6fbSAllen Martin return 0; 237ff1da6fbSAllen Martin } 238ff1da6fbSAllen Martin 239ff1da6fbSAllen Martin void spi_release_bus(struct spi_slave *slave) 240ff1da6fbSAllen Martin { 241ff1da6fbSAllen Martin /* 242ff1da6fbSAllen Martin * We can't release UART_DISABLE and set pinmux to UART4 here since 243ff1da6fbSAllen Martin * some code (e,g, spi_flash_probe) uses printf() while the SPI 244ff1da6fbSAllen Martin * bus is held. That is arguably bad, but it has the advantage of 245ff1da6fbSAllen Martin * already being in the source tree. 246ff1da6fbSAllen Martin */ 247ff1da6fbSAllen Martin } 248ff1da6fbSAllen Martin 249ff1da6fbSAllen Martin void spi_cs_activate(struct spi_slave *slave) 250ff1da6fbSAllen Martin { 251ff1da6fbSAllen Martin struct tegra_spi_slave *spi = to_tegra_spi(slave); 252*6b3a03e1SAllen Martin struct spi_regs *regs = spi->ctrl->regs; 253ff1da6fbSAllen Martin 254ff1da6fbSAllen Martin /* CS is negated on Tegra, so drive a 1 to get a 0 */ 255*6b3a03e1SAllen Martin setbits_le32(®s->command, SPI_CMD_CS_VAL); 256ff1da6fbSAllen Martin } 257ff1da6fbSAllen Martin 258ff1da6fbSAllen Martin void spi_cs_deactivate(struct spi_slave *slave) 259ff1da6fbSAllen Martin { 260ff1da6fbSAllen Martin struct tegra_spi_slave *spi = to_tegra_spi(slave); 261*6b3a03e1SAllen Martin struct spi_regs *regs = spi->ctrl->regs; 262ff1da6fbSAllen Martin 263ff1da6fbSAllen Martin /* CS is negated on Tegra, so drive a 0 to get a 1 */ 264*6b3a03e1SAllen Martin clrbits_le32(®s->command, SPI_CMD_CS_VAL); 265ff1da6fbSAllen Martin } 266ff1da6fbSAllen Martin 267ff1da6fbSAllen Martin int spi_xfer(struct spi_slave *slave, unsigned int bitlen, 268ff1da6fbSAllen Martin const void *data_out, void *data_in, unsigned long flags) 269ff1da6fbSAllen Martin { 270ff1da6fbSAllen Martin struct tegra_spi_slave *spi = to_tegra_spi(slave); 271*6b3a03e1SAllen Martin struct spi_regs *regs = spi->ctrl->regs; 272ff1da6fbSAllen Martin u32 reg, tmpdout, tmpdin = 0; 273ff1da6fbSAllen Martin const u8 *dout = data_out; 274ff1da6fbSAllen Martin u8 *din = data_in; 275ff1da6fbSAllen Martin int num_bytes; 276ff1da6fbSAllen Martin int ret; 277ff1da6fbSAllen Martin 278ff1da6fbSAllen Martin debug("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n", 279ff1da6fbSAllen Martin slave->bus, slave->cs, *(u8 *)dout, *(u8 *)din, bitlen); 280ff1da6fbSAllen Martin if (bitlen % 8) 281ff1da6fbSAllen Martin return -1; 282ff1da6fbSAllen Martin num_bytes = bitlen / 8; 283ff1da6fbSAllen Martin 284ff1da6fbSAllen Martin ret = 0; 285ff1da6fbSAllen Martin 286ff1da6fbSAllen Martin reg = readl(®s->status); 287ff1da6fbSAllen Martin writel(reg, ®s->status); /* Clear all SPI events via R/W */ 288ff1da6fbSAllen Martin debug("spi_xfer entry: STATUS = %08x\n", reg); 289ff1da6fbSAllen Martin 290ff1da6fbSAllen Martin reg = readl(®s->command); 291ff1da6fbSAllen Martin reg |= SPI_CMD_TXEN | SPI_CMD_RXEN; 292ff1da6fbSAllen Martin writel(reg, ®s->command); 293ff1da6fbSAllen Martin debug("spi_xfer: COMMAND = %08x\n", readl(®s->command)); 294ff1da6fbSAllen Martin 295ff1da6fbSAllen Martin if (flags & SPI_XFER_BEGIN) 296ff1da6fbSAllen Martin spi_cs_activate(slave); 297ff1da6fbSAllen Martin 298ff1da6fbSAllen Martin /* handle data in 32-bit chunks */ 299ff1da6fbSAllen Martin while (num_bytes > 0) { 300ff1da6fbSAllen Martin int bytes; 301ff1da6fbSAllen Martin int is_read = 0; 302ff1da6fbSAllen Martin int tm, i; 303ff1da6fbSAllen Martin 304ff1da6fbSAllen Martin tmpdout = 0; 305ff1da6fbSAllen Martin bytes = (num_bytes > 4) ? 4 : num_bytes; 306ff1da6fbSAllen Martin 307ff1da6fbSAllen Martin if (dout != NULL) { 308ff1da6fbSAllen Martin for (i = 0; i < bytes; ++i) 309ff1da6fbSAllen Martin tmpdout = (tmpdout << 8) | dout[i]; 310ff1da6fbSAllen Martin } 311ff1da6fbSAllen Martin 312ff1da6fbSAllen Martin num_bytes -= bytes; 313ff1da6fbSAllen Martin if (dout) 314ff1da6fbSAllen Martin dout += bytes; 315ff1da6fbSAllen Martin 316ff1da6fbSAllen Martin clrsetbits_le32(®s->command, SPI_CMD_BIT_LENGTH_MASK, 317ff1da6fbSAllen Martin bytes * 8 - 1); 318ff1da6fbSAllen Martin writel(tmpdout, ®s->tx_fifo); 319ff1da6fbSAllen Martin setbits_le32(®s->command, SPI_CMD_GO); 320ff1da6fbSAllen Martin 321ff1da6fbSAllen Martin /* 322ff1da6fbSAllen Martin * Wait for SPI transmit FIFO to empty, or to time out. 323ff1da6fbSAllen Martin * The RX FIFO status will be read and cleared last 324ff1da6fbSAllen Martin */ 325ff1da6fbSAllen Martin for (tm = 0, is_read = 0; tm < SPI_TIMEOUT; ++tm) { 326ff1da6fbSAllen Martin u32 status; 327ff1da6fbSAllen Martin 328ff1da6fbSAllen Martin status = readl(®s->status); 329ff1da6fbSAllen Martin 330ff1da6fbSAllen Martin /* We can exit when we've had both RX and TX activity */ 331ff1da6fbSAllen Martin if (is_read && (status & SPI_STAT_TXF_EMPTY)) 332ff1da6fbSAllen Martin break; 333ff1da6fbSAllen Martin 334ff1da6fbSAllen Martin if ((status & (SPI_STAT_BSY | SPI_STAT_RDY)) != 335ff1da6fbSAllen Martin SPI_STAT_RDY) 336ff1da6fbSAllen Martin tm++; 337ff1da6fbSAllen Martin 338ff1da6fbSAllen Martin else if (!(status & SPI_STAT_RXF_EMPTY)) { 339ff1da6fbSAllen Martin tmpdin = readl(®s->rx_fifo); 340ff1da6fbSAllen Martin is_read = 1; 341ff1da6fbSAllen Martin 342ff1da6fbSAllen Martin /* swap bytes read in */ 343ff1da6fbSAllen Martin if (din != NULL) { 344ff1da6fbSAllen Martin for (i = bytes - 1; i >= 0; --i) { 345ff1da6fbSAllen Martin din[i] = tmpdin & 0xff; 346ff1da6fbSAllen Martin tmpdin >>= 8; 347ff1da6fbSAllen Martin } 348ff1da6fbSAllen Martin din += bytes; 349ff1da6fbSAllen Martin } 350ff1da6fbSAllen Martin } 351ff1da6fbSAllen Martin } 352ff1da6fbSAllen Martin 353ff1da6fbSAllen Martin if (tm >= SPI_TIMEOUT) 354ff1da6fbSAllen Martin ret = tm; 355ff1da6fbSAllen Martin 356ff1da6fbSAllen Martin /* clear ACK RDY, etc. bits */ 357ff1da6fbSAllen Martin writel(readl(®s->status), ®s->status); 358ff1da6fbSAllen Martin } 359ff1da6fbSAllen Martin 360ff1da6fbSAllen Martin if (flags & SPI_XFER_END) 361ff1da6fbSAllen Martin spi_cs_deactivate(slave); 362ff1da6fbSAllen Martin 363ff1da6fbSAllen Martin debug("spi_xfer: transfer ended. Value=%08x, status = %08x\n", 364ff1da6fbSAllen Martin tmpdin, readl(®s->status)); 365ff1da6fbSAllen Martin 366ff1da6fbSAllen Martin if (ret) { 367ff1da6fbSAllen Martin printf("spi_xfer: timeout during SPI transfer, tm %d\n", ret); 368ff1da6fbSAllen Martin return -1; 369ff1da6fbSAllen Martin } 370ff1da6fbSAllen Martin 371ff1da6fbSAllen Martin return 0; 372ff1da6fbSAllen Martin } 373