1 /* 2 * Copyright (C) 2007 Atmel Corporation 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 #include <common.h> 7 #include <spi.h> 8 #include <malloc.h> 9 10 #include <asm/io.h> 11 12 #include <asm/arch/clk.h> 13 #include <asm/arch/hardware.h> 14 15 #include "atmel_spi.h" 16 17 static int spi_has_wdrbt(struct atmel_spi_slave *slave) 18 { 19 unsigned int ver; 20 21 ver = spi_readl(slave, VERSION); 22 23 return (ATMEL_SPI_VERSION_REV(ver) >= 0x210); 24 } 25 26 void spi_init() 27 { 28 29 } 30 31 struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, 32 unsigned int max_hz, unsigned int mode) 33 { 34 struct atmel_spi_slave *as; 35 unsigned int scbr; 36 u32 csrx; 37 void *regs; 38 39 if (!spi_cs_is_valid(bus, cs)) 40 return NULL; 41 42 switch (bus) { 43 case 0: 44 regs = (void *)ATMEL_BASE_SPI0; 45 break; 46 #ifdef ATMEL_BASE_SPI1 47 case 1: 48 regs = (void *)ATMEL_BASE_SPI1; 49 break; 50 #endif 51 #ifdef ATMEL_BASE_SPI2 52 case 2: 53 regs = (void *)ATMEL_BASE_SPI2; 54 break; 55 #endif 56 #ifdef ATMEL_BASE_SPI3 57 case 3: 58 regs = (void *)ATMEL_BASE_SPI3; 59 break; 60 #endif 61 default: 62 return NULL; 63 } 64 65 66 scbr = (get_spi_clk_rate(bus) + max_hz - 1) / max_hz; 67 if (scbr > ATMEL_SPI_CSRx_SCBR_MAX) 68 /* Too low max SCK rate */ 69 return NULL; 70 if (scbr < 1) 71 scbr = 1; 72 73 csrx = ATMEL_SPI_CSRx_SCBR(scbr); 74 csrx |= ATMEL_SPI_CSRx_BITS(ATMEL_SPI_BITS_8); 75 if (!(mode & SPI_CPHA)) 76 csrx |= ATMEL_SPI_CSRx_NCPHA; 77 if (mode & SPI_CPOL) 78 csrx |= ATMEL_SPI_CSRx_CPOL; 79 80 as = spi_alloc_slave(struct atmel_spi_slave, bus, cs); 81 if (!as) 82 return NULL; 83 84 as->regs = regs; 85 as->mr = ATMEL_SPI_MR_MSTR | ATMEL_SPI_MR_MODFDIS 86 | ATMEL_SPI_MR_PCS(~(1 << cs) & 0xf); 87 if (spi_has_wdrbt(as)) 88 as->mr |= ATMEL_SPI_MR_WDRBT; 89 90 spi_writel(as, CSR(cs), csrx); 91 92 return &as->slave; 93 } 94 95 void spi_free_slave(struct spi_slave *slave) 96 { 97 struct atmel_spi_slave *as = to_atmel_spi(slave); 98 99 free(as); 100 } 101 102 int spi_claim_bus(struct spi_slave *slave) 103 { 104 struct atmel_spi_slave *as = to_atmel_spi(slave); 105 106 /* Enable the SPI hardware */ 107 spi_writel(as, CR, ATMEL_SPI_CR_SPIEN); 108 109 /* 110 * Select the slave. This should set SCK to the correct 111 * initial state, etc. 112 */ 113 spi_writel(as, MR, as->mr); 114 115 return 0; 116 } 117 118 void spi_release_bus(struct spi_slave *slave) 119 { 120 struct atmel_spi_slave *as = to_atmel_spi(slave); 121 122 /* Disable the SPI hardware */ 123 spi_writel(as, CR, ATMEL_SPI_CR_SPIDIS); 124 } 125 126 int spi_xfer(struct spi_slave *slave, unsigned int bitlen, 127 const void *dout, void *din, unsigned long flags) 128 { 129 struct atmel_spi_slave *as = to_atmel_spi(slave); 130 unsigned int len_tx; 131 unsigned int len_rx; 132 unsigned int len; 133 u32 status; 134 const u8 *txp = dout; 135 u8 *rxp = din; 136 u8 value; 137 138 if (bitlen == 0) 139 /* Finish any previously submitted transfers */ 140 goto out; 141 142 /* 143 * TODO: The controller can do non-multiple-of-8 bit 144 * transfers, but this driver currently doesn't support it. 145 * 146 * It's also not clear how such transfers are supposed to be 147 * represented as a stream of bytes...this is a limitation of 148 * the current SPI interface. 149 */ 150 if (bitlen % 8) { 151 /* Errors always terminate an ongoing transfer */ 152 flags |= SPI_XFER_END; 153 goto out; 154 } 155 156 len = bitlen / 8; 157 158 /* 159 * The controller can do automatic CS control, but it is 160 * somewhat quirky, and it doesn't really buy us much anyway 161 * in the context of U-Boot. 162 */ 163 if (flags & SPI_XFER_BEGIN) { 164 spi_cs_activate(slave); 165 /* 166 * sometimes the RDR is not empty when we get here, 167 * in theory that should not happen, but it DOES happen. 168 * Read it here to be on the safe side. 169 * That also clears the OVRES flag. Required if the 170 * following loop exits due to OVRES! 171 */ 172 spi_readl(as, RDR); 173 } 174 175 for (len_tx = 0, len_rx = 0; len_rx < len; ) { 176 status = spi_readl(as, SR); 177 178 if (status & ATMEL_SPI_SR_OVRES) 179 return -1; 180 181 if (len_tx < len && (status & ATMEL_SPI_SR_TDRE)) { 182 if (txp) 183 value = *txp++; 184 else 185 value = 0; 186 spi_writel(as, TDR, value); 187 len_tx++; 188 } 189 if (status & ATMEL_SPI_SR_RDRF) { 190 value = spi_readl(as, RDR); 191 if (rxp) 192 *rxp++ = value; 193 len_rx++; 194 } 195 } 196 197 out: 198 if (flags & SPI_XFER_END) { 199 /* 200 * Wait until the transfer is completely done before 201 * we deactivate CS. 202 */ 203 do { 204 status = spi_readl(as, SR); 205 } while (!(status & ATMEL_SPI_SR_TXEMPTY)); 206 207 spi_cs_deactivate(slave); 208 } 209 210 return 0; 211 } 212