diff options
author | Wenyou Yang <wenyou.yang@atmel.com> | 2013-03-19 03:42:15 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-04-01 09:40:39 -0400 |
commit | d4820b7496219edd9a7055022681364d304525f7 (patch) | |
tree | efaef510f248393c0c29dd085cb4fedab1bb2b34 /drivers/spi/spi-atmel.c | |
parent | faa98f7ea6c720beec8a800c9ac6975f760467e2 (diff) |
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>
Diffstat (limited to 'drivers/spi/spi-atmel.c')
-rw-r--r-- | drivers/spi/spi-atmel.c | 66 |
1 files changed, 50 insertions, 16 deletions
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 656d137db253..af3dbab600d5 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c | |||
@@ -22,9 +22,8 @@ | |||
22 | #include <linux/platform_data/atmel.h> | 22 | #include <linux/platform_data/atmel.h> |
23 | #include <linux/of.h> | 23 | #include <linux/of.h> |
24 | 24 | ||
25 | #include <asm/io.h> | 25 | #include <linux/io.h> |
26 | #include <asm/gpio.h> | 26 | #include <linux/gpio.h> |
27 | #include <mach/cpu.h> | ||
28 | 27 | ||
29 | /* SPI register offsets */ | 28 | /* SPI register offsets */ |
30 | #define SPI_CR 0x0000 | 29 | #define SPI_CR 0x0000 |
@@ -39,6 +38,7 @@ | |||
39 | #define SPI_CSR1 0x0034 | 38 | #define SPI_CSR1 0x0034 |
40 | #define SPI_CSR2 0x0038 | 39 | #define SPI_CSR2 0x0038 |
41 | #define SPI_CSR3 0x003c | 40 | #define SPI_CSR3 0x003c |
41 | #define SPI_VERSION 0x00fc | ||
42 | #define SPI_RPR 0x0100 | 42 | #define SPI_RPR 0x0100 |
43 | #define SPI_RCR 0x0104 | 43 | #define SPI_RCR 0x0104 |
44 | #define SPI_TPR 0x0108 | 44 | #define SPI_TPR 0x0108 |
@@ -71,6 +71,8 @@ | |||
71 | #define SPI_FDIV_SIZE 1 | 71 | #define SPI_FDIV_SIZE 1 |
72 | #define SPI_MODFDIS_OFFSET 4 | 72 | #define SPI_MODFDIS_OFFSET 4 |
73 | #define SPI_MODFDIS_SIZE 1 | 73 | #define SPI_MODFDIS_SIZE 1 |
74 | #define SPI_WDRBT_OFFSET 5 | ||
75 | #define SPI_WDRBT_SIZE 1 | ||
74 | #define SPI_LLB_OFFSET 7 | 76 | #define SPI_LLB_OFFSET 7 |
75 | #define SPI_LLB_SIZE 1 | 77 | #define SPI_LLB_SIZE 1 |
76 | #define SPI_PCS_OFFSET 16 | 78 | #define SPI_PCS_OFFSET 16 |
@@ -180,6 +182,11 @@ | |||
180 | #define spi_writel(port,reg,value) \ | 182 | #define spi_writel(port,reg,value) \ |
181 | __raw_writel((value), (port)->regs + SPI_##reg) | 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 | * The core SPI transfer engine just talks to a register bank to set up | 192 | * The core SPI transfer engine just talks to a register bank to set up |
@@ -204,6 +211,8 @@ struct atmel_spi { | |||
204 | 211 | ||
205 | void *buffer; | 212 | void *buffer; |
206 | dma_addr_t buffer_dma; | 213 | dma_addr_t buffer_dma; |
214 | |||
215 | struct atmel_spi_caps caps; | ||
207 | }; | 216 | }; |
208 | 217 | ||
209 | /* Controller-specific per-slave state */ | 218 | /* Controller-specific per-slave state */ |
@@ -222,14 +231,10 @@ struct atmel_spi_device { | |||
222 | * - SPI_SR.TXEMPTY, SPI_SR.NSSR (and corresponding irqs) | 231 | * - SPI_SR.TXEMPTY, SPI_SR.NSSR (and corresponding irqs) |
223 | * - SPI_CSRx.CSAAT | 232 | * - SPI_CSRx.CSAAT |
224 | * - SPI_CSRx.SBCR allows faster clocking | 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 | /* |
@@ -263,15 +268,20 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) | |||
263 | unsigned active = spi->mode & SPI_CS_HIGH; | 268 | unsigned active = spi->mode & SPI_CS_HIGH; |
264 | u32 mr; | 269 | u32 mr; |
265 | 270 | ||
266 | if (atmel_spi_is_v2()) { | 271 | if (atmel_spi_is_v2(as)) { |
267 | /* | 272 | /* |
268 | * Always use CSR0. This ensures that the clock | 273 | * Always use CSR0. This ensures that the clock |
269 | * switches to the correct idle polarity before we | 274 | * switches to the correct idle polarity before we |
270 | * toggle the CS. | 275 | * toggle the CS. |
271 | */ | 276 | */ |
272 | spi_writel(as, CSR0, asd->csr); | 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 | | SPI_BIT(MSTR)); | 283 | | SPI_BIT(MSTR)); |
284 | } | ||
275 | mr = spi_readl(as, MR); | 285 | mr = spi_readl(as, MR); |
276 | gpio_set_value(asd->npcs_pin, active); | 286 | gpio_set_value(asd->npcs_pin, active); |
277 | } else { | 287 | } else { |
@@ -318,7 +328,7 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) | |||
318 | asd->npcs_pin, active ? " (low)" : "", | 328 | asd->npcs_pin, active ? " (low)" : "", |
319 | mr); | 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 | gpio_set_value(asd->npcs_pin, !active); | 332 | gpio_set_value(asd->npcs_pin, !active); |
323 | } | 333 | } |
324 | 334 | ||
@@ -719,7 +729,7 @@ static int atmel_spi_setup(struct spi_device *spi) | |||
719 | } | 729 | } |
720 | 730 | ||
721 | /* see notes above re chipselect */ | 731 | /* see notes above re chipselect */ |
722 | if (!atmel_spi_is_v2() | 732 | if (!atmel_spi_is_v2(as) |
723 | && spi->chip_select == 0 | 733 | && spi->chip_select == 0 |
724 | && (spi->mode & SPI_CS_HIGH)) { | 734 | && (spi->mode & SPI_CS_HIGH)) { |
725 | dev_dbg(&spi->dev, "setup: can't be active-high\n"); | 735 | dev_dbg(&spi->dev, "setup: can't be active-high\n"); |
@@ -728,7 +738,7 @@ static int atmel_spi_setup(struct spi_device *spi) | |||
728 | 738 | ||
729 | /* v1 chips start out at half the peripheral bus speed. */ | 739 | /* v1 chips start out at half the peripheral bus speed. */ |
730 | bus_hz = clk_get_rate(as->clk); | 740 | bus_hz = clk_get_rate(as->clk); |
731 | if (!atmel_spi_is_v2()) | 741 | if (!atmel_spi_is_v2(as)) |
732 | bus_hz /= 2; | 742 | bus_hz /= 2; |
733 | 743 | ||
734 | if (spi->max_speed_hz) { | 744 | if (spi->max_speed_hz) { |
@@ -804,7 +814,7 @@ static int atmel_spi_setup(struct spi_device *spi) | |||
804 | "setup: %lu Hz bpw %u mode 0x%x -> csr%d %08x\n", | 814 | "setup: %lu Hz bpw %u mode 0x%x -> csr%d %08x\n", |
805 | bus_hz / scbr, bits, spi->mode, spi->chip_select, csr); | 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 | spi_writel(as, CSR0 + 4 * spi->chip_select, csr); | 818 | spi_writel(as, CSR0 + 4 * spi->chip_select, csr); |
809 | 819 | ||
810 | return 0; | 820 | return 0; |
@@ -910,6 +920,23 @@ static void atmel_spi_cleanup(struct spi_device *spi) | |||
910 | kfree(asd); | 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 | static int atmel_spi_probe(struct platform_device *pdev) | 942 | static int atmel_spi_probe(struct platform_device *pdev) |
@@ -970,6 +997,8 @@ static int atmel_spi_probe(struct platform_device *pdev) | |||
970 | as->irq = irq; | 997 | as->irq = irq; |
971 | as->clk = clk; | 998 | as->clk = clk; |
972 | 999 | ||
1000 | atmel_get_caps(as); | ||
1001 | |||
973 | ret = request_irq(irq, atmel_spi_interrupt, 0, | 1002 | ret = request_irq(irq, atmel_spi_interrupt, 0, |
974 | dev_name(&pdev->dev), master); | 1003 | dev_name(&pdev->dev), master); |
975 | if (ret) | 1004 | if (ret) |
@@ -979,7 +1008,12 @@ static int atmel_spi_probe(struct platform_device *pdev) | |||
979 | clk_enable(clk); | 1008 | clk_enable(clk); |
980 | spi_writel(as, CR, SPI_BIT(SWRST)); | 1009 | spi_writel(as, CR, SPI_BIT(SWRST)); |
981 | spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ | 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 | spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); | 1017 | spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); |
984 | spi_writel(as, CR, SPI_BIT(SPIEN)); | 1018 | spi_writel(as, CR, SPI_BIT(SPIEN)); |
985 | 1019 | ||