Commit d4820b7496219edd9a7055022681364d304525f7
Committed by
Mark Brown
1 parent
faa98f7ea6
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
spi/spi-atmel: detect the capabilities of SPI core by reading the VERSION register.
The "has_dma_support" needed for future use with dmaengine driver. [Fixed some unneded ternery operators -- broonie] Signed-off-by: Wenyou Yang <wenyou.yang@atmel.com> Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Showing 1 changed file with 50 additions and 16 deletions Side-by-side Diff
drivers/spi/spi-atmel.c
... | ... | @@ -22,9 +22,8 @@ |
22 | 22 | #include <linux/platform_data/atmel.h> |
23 | 23 | #include <linux/of.h> |
24 | 24 | |
25 | -#include <asm/io.h> | |
26 | -#include <asm/gpio.h> | |
27 | -#include <mach/cpu.h> | |
25 | +#include <linux/io.h> | |
26 | +#include <linux/gpio.h> | |
28 | 27 | |
29 | 28 | /* SPI register offsets */ |
30 | 29 | #define SPI_CR 0x0000 |
... | ... | @@ -39,6 +38,7 @@ |
39 | 38 | #define SPI_CSR1 0x0034 |
40 | 39 | #define SPI_CSR2 0x0038 |
41 | 40 | #define SPI_CSR3 0x003c |
41 | +#define SPI_VERSION 0x00fc | |
42 | 42 | #define SPI_RPR 0x0100 |
43 | 43 | #define SPI_RCR 0x0104 |
44 | 44 | #define SPI_TPR 0x0108 |
... | ... | @@ -71,6 +71,8 @@ |
71 | 71 | #define SPI_FDIV_SIZE 1 |
72 | 72 | #define SPI_MODFDIS_OFFSET 4 |
73 | 73 | #define SPI_MODFDIS_SIZE 1 |
74 | +#define SPI_WDRBT_OFFSET 5 | |
75 | +#define SPI_WDRBT_SIZE 1 | |
74 | 76 | #define SPI_LLB_OFFSET 7 |
75 | 77 | #define SPI_LLB_SIZE 1 |
76 | 78 | #define SPI_PCS_OFFSET 16 |
... | ... | @@ -180,6 +182,11 @@ |
180 | 182 | #define spi_writel(port,reg,value) \ |
181 | 183 | __raw_writel((value), (port)->regs + SPI_##reg) |
182 | 184 | |
185 | +struct atmel_spi_caps { | |
186 | + bool is_spi2; | |
187 | + bool has_wdrbt; | |
188 | + bool has_dma_support; | |
189 | +}; | |
183 | 190 | |
184 | 191 | /* |
185 | 192 | * The core SPI transfer engine just talks to a register bank to set up |
... | ... | @@ -204,6 +211,8 @@ |
204 | 211 | |
205 | 212 | void *buffer; |
206 | 213 | dma_addr_t buffer_dma; |
214 | + | |
215 | + struct atmel_spi_caps caps; | |
207 | 216 | }; |
208 | 217 | |
209 | 218 | /* Controller-specific per-slave state */ |
210 | 219 | |
211 | 220 | |
... | ... | @@ -222,14 +231,10 @@ |
222 | 231 | * - SPI_SR.TXEMPTY, SPI_SR.NSSR (and corresponding irqs) |
223 | 232 | * - SPI_CSRx.CSAAT |
224 | 233 | * - SPI_CSRx.SBCR allows faster clocking |
225 | - * | |
226 | - * We can determine the controller version by reading the VERSION | |
227 | - * register, but I haven't checked that it exists on all chips, and | |
228 | - * this is cheaper anyway. | |
229 | 234 | */ |
230 | -static bool atmel_spi_is_v2(void) | |
235 | +static bool atmel_spi_is_v2(struct atmel_spi *as) | |
231 | 236 | { |
232 | - return !cpu_is_at91rm9200(); | |
237 | + return as->caps.is_spi2; | |
233 | 238 | } |
234 | 239 | |
235 | 240 | /* |
236 | 241 | |
237 | 242 | |
... | ... | @@ -263,15 +268,20 @@ |
263 | 268 | unsigned active = spi->mode & SPI_CS_HIGH; |
264 | 269 | u32 mr; |
265 | 270 | |
266 | - if (atmel_spi_is_v2()) { | |
271 | + if (atmel_spi_is_v2(as)) { | |
267 | 272 | /* |
268 | 273 | * Always use CSR0. This ensures that the clock |
269 | 274 | * switches to the correct idle polarity before we |
270 | 275 | * toggle the CS. |
271 | 276 | */ |
272 | 277 | spi_writel(as, CSR0, asd->csr); |
273 | - spi_writel(as, MR, SPI_BF(PCS, 0x0e) | SPI_BIT(MODFDIS) | |
278 | + if (as->caps.has_wdrbt) { | |
279 | + spi_writel(as, MR, SPI_BF(PCS, 0x0e) | SPI_BIT(WDRBT) | |
280 | + | SPI_BIT(MODFDIS) | SPI_BIT(MSTR)); | |
281 | + } else { | |
282 | + spi_writel(as, MR, SPI_BF(PCS, 0x0e) | SPI_BIT(MODFDIS) | |
274 | 283 | | SPI_BIT(MSTR)); |
284 | + } | |
275 | 285 | mr = spi_readl(as, MR); |
276 | 286 | gpio_set_value(asd->npcs_pin, active); |
277 | 287 | } else { |
... | ... | @@ -318,7 +328,7 @@ |
318 | 328 | asd->npcs_pin, active ? " (low)" : "", |
319 | 329 | mr); |
320 | 330 | |
321 | - if (atmel_spi_is_v2() || spi->chip_select != 0) | |
331 | + if (atmel_spi_is_v2(as) || spi->chip_select != 0) | |
322 | 332 | gpio_set_value(asd->npcs_pin, !active); |
323 | 333 | } |
324 | 334 | |
... | ... | @@ -719,7 +729,7 @@ |
719 | 729 | } |
720 | 730 | |
721 | 731 | /* see notes above re chipselect */ |
722 | - if (!atmel_spi_is_v2() | |
732 | + if (!atmel_spi_is_v2(as) | |
723 | 733 | && spi->chip_select == 0 |
724 | 734 | && (spi->mode & SPI_CS_HIGH)) { |
725 | 735 | dev_dbg(&spi->dev, "setup: can't be active-high\n"); |
... | ... | @@ -728,7 +738,7 @@ |
728 | 738 | |
729 | 739 | /* v1 chips start out at half the peripheral bus speed. */ |
730 | 740 | bus_hz = clk_get_rate(as->clk); |
731 | - if (!atmel_spi_is_v2()) | |
741 | + if (!atmel_spi_is_v2(as)) | |
732 | 742 | bus_hz /= 2; |
733 | 743 | |
734 | 744 | if (spi->max_speed_hz) { |
... | ... | @@ -804,7 +814,7 @@ |
804 | 814 | "setup: %lu Hz bpw %u mode 0x%x -> csr%d %08x\n", |
805 | 815 | bus_hz / scbr, bits, spi->mode, spi->chip_select, csr); |
806 | 816 | |
807 | - if (!atmel_spi_is_v2()) | |
817 | + if (!atmel_spi_is_v2(as)) | |
808 | 818 | spi_writel(as, CSR0 + 4 * spi->chip_select, csr); |
809 | 819 | |
810 | 820 | return 0; |
... | ... | @@ -910,6 +920,23 @@ |
910 | 920 | kfree(asd); |
911 | 921 | } |
912 | 922 | |
923 | +static inline unsigned int atmel_get_version(struct atmel_spi *as) | |
924 | +{ | |
925 | + return spi_readl(as, VERSION) & 0x00000fff; | |
926 | +} | |
927 | + | |
928 | +static void atmel_get_caps(struct atmel_spi *as) | |
929 | +{ | |
930 | + unsigned int version; | |
931 | + | |
932 | + version = atmel_get_version(as); | |
933 | + dev_info(&as->pdev->dev, "version: 0x%x\n", version); | |
934 | + | |
935 | + as->caps.is_spi2 = version > 0x121; | |
936 | + as->caps.has_wdrbt = version >= 0x210; | |
937 | + as->caps.has_dma_support = version >= 0x212; | |
938 | +} | |
939 | + | |
913 | 940 | /*-------------------------------------------------------------------------*/ |
914 | 941 | |
915 | 942 | static int atmel_spi_probe(struct platform_device *pdev) |
... | ... | @@ -970,6 +997,8 @@ |
970 | 997 | as->irq = irq; |
971 | 998 | as->clk = clk; |
972 | 999 | |
1000 | + atmel_get_caps(as); | |
1001 | + | |
973 | 1002 | ret = request_irq(irq, atmel_spi_interrupt, 0, |
974 | 1003 | dev_name(&pdev->dev), master); |
975 | 1004 | if (ret) |
... | ... | @@ -979,7 +1008,12 @@ |
979 | 1008 | clk_enable(clk); |
980 | 1009 | spi_writel(as, CR, SPI_BIT(SWRST)); |
981 | 1010 | spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ |
982 | - spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS)); | |
1011 | + if (as->caps.has_wdrbt) { | |
1012 | + spi_writel(as, MR, SPI_BIT(WDRBT) | SPI_BIT(MODFDIS) | |
1013 | + | SPI_BIT(MSTR)); | |
1014 | + } else { | |
1015 | + spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS)); | |
1016 | + } | |
983 | 1017 | spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); |
984 | 1018 | spi_writel(as, CR, SPI_BIT(SPIEN)); |
985 | 1019 |