1 /* 2 * Copyright (c) 2006 Ben Warren, Qstreams Networks Inc. 3 * With help from the common/soft_spi and arch/powerpc/cpu/mpc8260 drivers 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 10 #include <malloc.h> 11 #include <spi.h> 12 #include <asm/mpc8xxx_spi.h> 13 14 #define SPI_EV_NE (0x80000000 >> 22) /* Receiver Not Empty */ 15 #define SPI_EV_NF (0x80000000 >> 23) /* Transmitter Not Full */ 16 17 #define SPI_MODE_LOOP (0x80000000 >> 1) /* Loopback mode */ 18 #define SPI_MODE_REV (0x80000000 >> 5) /* Reverse mode - MSB first */ 19 #define SPI_MODE_MS (0x80000000 >> 6) /* Always master */ 20 #define SPI_MODE_EN (0x80000000 >> 7) /* Enable interface */ 21 22 #define SPI_TIMEOUT 1000 23 24 struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, 25 unsigned int max_hz, unsigned int mode) 26 { 27 struct spi_slave *slave; 28 29 if (!spi_cs_is_valid(bus, cs)) 30 return NULL; 31 32 slave = spi_alloc_slave_base(bus, cs); 33 if (!slave) 34 return NULL; 35 36 /* 37 * TODO: Some of the code in spi_init() should probably move 38 * here, or into spi_claim_bus() below. 39 */ 40 41 return slave; 42 } 43 44 void spi_free_slave(struct spi_slave *slave) 45 { 46 free(slave); 47 } 48 49 void spi_init(void) 50 { 51 volatile spi8xxx_t *spi = &((immap_t *) (CONFIG_SYS_IMMR))->spi; 52 53 /* 54 * SPI pins on the MPC83xx are not muxed, so all we do is initialize 55 * some registers 56 */ 57 spi->mode = SPI_MODE_REV | SPI_MODE_MS | SPI_MODE_EN; 58 spi->mode = (spi->mode & 0xfff0ffff) | BIT(16); /* Use SYSCLK / 8 59 (16.67MHz typ.) */ 60 spi->event = 0xffffffff; /* Clear all SPI events */ 61 spi->mask = 0x00000000; /* Mask all SPI interrupts */ 62 spi->com = 0; /* LST bit doesn't do anything, so disregard */ 63 } 64 65 int spi_claim_bus(struct spi_slave *slave) 66 { 67 return 0; 68 } 69 70 void spi_release_bus(struct spi_slave *slave) 71 { 72 73 } 74 75 int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, 76 void *din, unsigned long flags) 77 { 78 volatile spi8xxx_t *spi = &((immap_t *) (CONFIG_SYS_IMMR))->spi; 79 unsigned int tmpdout, tmpdin, event; 80 int numBlks = DIV_ROUND_UP(bitlen, 32); 81 int tm, isRead = 0; 82 unsigned char charSize = 32; 83 84 debug("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n", 85 slave->bus, slave->cs, *(uint *) dout, *(uint *) din, bitlen); 86 87 if (flags & SPI_XFER_BEGIN) 88 spi_cs_activate(slave); 89 90 spi->event = 0xffffffff; /* Clear all SPI events */ 91 92 /* handle data in 32-bit chunks */ 93 while (numBlks--) { 94 tmpdout = 0; 95 charSize = (bitlen >= 32 ? 32 : bitlen); 96 97 /* Shift data so it's msb-justified */ 98 tmpdout = *(u32 *) dout >> (32 - charSize); 99 100 /* The LEN field of the SPMODE register is set as follows: 101 * 102 * Bit length setting 103 * len <= 4 3 104 * 4 < len <= 16 len - 1 105 * len > 16 0 106 */ 107 108 spi->mode &= ~SPI_MODE_EN; 109 110 if (bitlen <= 16) { 111 if (bitlen <= 4) 112 spi->mode = (spi->mode & 0xff0fffff) | 113 (3 << 20); 114 else 115 spi->mode = (spi->mode & 0xff0fffff) | 116 ((bitlen - 1) << 20); 117 } else { 118 spi->mode = (spi->mode & 0xff0fffff); 119 /* Set up the next iteration if sending > 32 bits */ 120 bitlen -= 32; 121 dout += 4; 122 } 123 124 spi->mode |= SPI_MODE_EN; 125 126 spi->tx = tmpdout; /* Write the data out */ 127 debug("*** spi_xfer: ... %08x written\n", tmpdout); 128 129 /* 130 * Wait for SPI transmit to get out 131 * or time out (1 second = 1000 ms) 132 * The NE event must be read and cleared first 133 */ 134 for (tm = 0, isRead = 0; tm < SPI_TIMEOUT; ++tm) { 135 event = spi->event; 136 if (event & SPI_EV_NE) { 137 tmpdin = spi->rx; 138 spi->event |= SPI_EV_NE; 139 isRead = 1; 140 141 *(u32 *) din = (tmpdin << (32 - charSize)); 142 if (charSize == 32) { 143 /* Advance output buffer by 32 bits */ 144 din += 4; 145 } 146 } 147 /* 148 * Only bail when we've had both NE and NF events. 149 * This will cause timeouts on RO devices, so maybe 150 * in the future put an arbitrary delay after writing 151 * the device. Arbitrary delays suck, though... 152 */ 153 if (isRead && (event & SPI_EV_NF)) 154 break; 155 } 156 if (tm >= SPI_TIMEOUT) 157 puts("*** spi_xfer: Time out during SPI transfer"); 158 159 debug("*** spi_xfer: transfer ended. Value=%08x\n", tmpdin); 160 } 161 162 if (flags & SPI_XFER_END) 163 spi_cs_deactivate(slave); 164 165 return 0; 166 } 167