diff options
Diffstat (limited to 'drivers/spi/spi-octeon.c')
-rw-r--r-- | drivers/spi/spi-octeon.c | 41 |
1 files changed, 27 insertions, 14 deletions
diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c index e72204089a88..209eddcc19b6 100644 --- a/drivers/spi/spi-octeon.c +++ b/drivers/spi/spi-octeon.c | |||
@@ -17,22 +17,30 @@ | |||
17 | #include <asm/octeon/octeon.h> | 17 | #include <asm/octeon/octeon.h> |
18 | #include <asm/octeon/cvmx-mpi-defs.h> | 18 | #include <asm/octeon/cvmx-mpi-defs.h> |
19 | 19 | ||
20 | #define OCTEON_SPI_CFG 0 | ||
21 | #define OCTEON_SPI_STS 0x08 | ||
22 | #define OCTEON_SPI_TX 0x10 | ||
23 | #define OCTEON_SPI_DAT0 0x80 | ||
24 | |||
25 | #define OCTEON_SPI_MAX_BYTES 9 | 20 | #define OCTEON_SPI_MAX_BYTES 9 |
26 | 21 | ||
27 | #define OCTEON_SPI_MAX_CLOCK_HZ 16000000 | 22 | #define OCTEON_SPI_MAX_CLOCK_HZ 16000000 |
28 | 23 | ||
24 | struct octeon_spi_regs { | ||
25 | int config; | ||
26 | int status; | ||
27 | int tx; | ||
28 | int data; | ||
29 | }; | ||
30 | |||
29 | struct octeon_spi { | 31 | struct octeon_spi { |
30 | void __iomem *register_base; | 32 | void __iomem *register_base; |
31 | u64 last_cfg; | 33 | u64 last_cfg; |
32 | u64 cs_enax; | 34 | u64 cs_enax; |
33 | int sys_freq; | 35 | int sys_freq; |
36 | struct octeon_spi_regs regs; | ||
34 | }; | 37 | }; |
35 | 38 | ||
39 | #define OCTEON_SPI_CFG(x) (x->regs.config) | ||
40 | #define OCTEON_SPI_STS(x) (x->regs.status) | ||
41 | #define OCTEON_SPI_TX(x) (x->regs.tx) | ||
42 | #define OCTEON_SPI_DAT0(x) (x->regs.data) | ||
43 | |||
36 | static void octeon_spi_wait_ready(struct octeon_spi *p) | 44 | static void octeon_spi_wait_ready(struct octeon_spi *p) |
37 | { | 45 | { |
38 | union cvmx_mpi_sts mpi_sts; | 46 | union cvmx_mpi_sts mpi_sts; |
@@ -41,7 +49,7 @@ static void octeon_spi_wait_ready(struct octeon_spi *p) | |||
41 | do { | 49 | do { |
42 | if (loops++) | 50 | if (loops++) |
43 | __delay(500); | 51 | __delay(500); |
44 | mpi_sts.u64 = readq(p->register_base + OCTEON_SPI_STS); | 52 | mpi_sts.u64 = readq(p->register_base + OCTEON_SPI_STS(p)); |
45 | } while (mpi_sts.s.busy); | 53 | } while (mpi_sts.s.busy); |
46 | } | 54 | } |
47 | 55 | ||
@@ -83,7 +91,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, | |||
83 | 91 | ||
84 | if (mpi_cfg.u64 != p->last_cfg) { | 92 | if (mpi_cfg.u64 != p->last_cfg) { |
85 | p->last_cfg = mpi_cfg.u64; | 93 | p->last_cfg = mpi_cfg.u64; |
86 | writeq(mpi_cfg.u64, p->register_base + OCTEON_SPI_CFG); | 94 | writeq(mpi_cfg.u64, p->register_base + OCTEON_SPI_CFG(p)); |
87 | } | 95 | } |
88 | tx_buf = xfer->tx_buf; | 96 | tx_buf = xfer->tx_buf; |
89 | rx_buf = xfer->rx_buf; | 97 | rx_buf = xfer->rx_buf; |
@@ -95,19 +103,19 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, | |||
95 | d = *tx_buf++; | 103 | d = *tx_buf++; |
96 | else | 104 | else |
97 | d = 0; | 105 | d = 0; |
98 | writeq(d, p->register_base + OCTEON_SPI_DAT0 + (8 * i)); | 106 | writeq(d, p->register_base + OCTEON_SPI_DAT0(p) + (8 * i)); |
99 | } | 107 | } |
100 | mpi_tx.u64 = 0; | 108 | mpi_tx.u64 = 0; |
101 | mpi_tx.s.csid = spi->chip_select; | 109 | mpi_tx.s.csid = spi->chip_select; |
102 | mpi_tx.s.leavecs = 1; | 110 | mpi_tx.s.leavecs = 1; |
103 | mpi_tx.s.txnum = tx_buf ? OCTEON_SPI_MAX_BYTES : 0; | 111 | mpi_tx.s.txnum = tx_buf ? OCTEON_SPI_MAX_BYTES : 0; |
104 | mpi_tx.s.totnum = OCTEON_SPI_MAX_BYTES; | 112 | mpi_tx.s.totnum = OCTEON_SPI_MAX_BYTES; |
105 | writeq(mpi_tx.u64, p->register_base + OCTEON_SPI_TX); | 113 | writeq(mpi_tx.u64, p->register_base + OCTEON_SPI_TX(p)); |
106 | 114 | ||
107 | octeon_spi_wait_ready(p); | 115 | octeon_spi_wait_ready(p); |
108 | if (rx_buf) | 116 | if (rx_buf) |
109 | for (i = 0; i < OCTEON_SPI_MAX_BYTES; i++) { | 117 | for (i = 0; i < OCTEON_SPI_MAX_BYTES; i++) { |
110 | u64 v = readq(p->register_base + OCTEON_SPI_DAT0 + (8 * i)); | 118 | u64 v = readq(p->register_base + OCTEON_SPI_DAT0(p) + (8 * i)); |
111 | *rx_buf++ = (u8)v; | 119 | *rx_buf++ = (u8)v; |
112 | } | 120 | } |
113 | len -= OCTEON_SPI_MAX_BYTES; | 121 | len -= OCTEON_SPI_MAX_BYTES; |
@@ -119,7 +127,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, | |||
119 | d = *tx_buf++; | 127 | d = *tx_buf++; |
120 | else | 128 | else |
121 | d = 0; | 129 | d = 0; |
122 | writeq(d, p->register_base + OCTEON_SPI_DAT0 + (8 * i)); | 130 | writeq(d, p->register_base + OCTEON_SPI_DAT0(p) + (8 * i)); |
123 | } | 131 | } |
124 | 132 | ||
125 | mpi_tx.u64 = 0; | 133 | mpi_tx.u64 = 0; |
@@ -130,12 +138,12 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, | |||
130 | mpi_tx.s.leavecs = !xfer->cs_change; | 138 | mpi_tx.s.leavecs = !xfer->cs_change; |
131 | mpi_tx.s.txnum = tx_buf ? len : 0; | 139 | mpi_tx.s.txnum = tx_buf ? len : 0; |
132 | mpi_tx.s.totnum = len; | 140 | mpi_tx.s.totnum = len; |
133 | writeq(mpi_tx.u64, p->register_base + OCTEON_SPI_TX); | 141 | writeq(mpi_tx.u64, p->register_base + OCTEON_SPI_TX(p)); |
134 | 142 | ||
135 | octeon_spi_wait_ready(p); | 143 | octeon_spi_wait_ready(p); |
136 | if (rx_buf) | 144 | if (rx_buf) |
137 | for (i = 0; i < len; i++) { | 145 | for (i = 0; i < len; i++) { |
138 | u64 v = readq(p->register_base + OCTEON_SPI_DAT0 + (8 * i)); | 146 | u64 v = readq(p->register_base + OCTEON_SPI_DAT0(p) + (8 * i)); |
139 | *rx_buf++ = (u8)v; | 147 | *rx_buf++ = (u8)v; |
140 | } | 148 | } |
141 | 149 | ||
@@ -194,6 +202,11 @@ static int octeon_spi_probe(struct platform_device *pdev) | |||
194 | p->register_base = reg_base; | 202 | p->register_base = reg_base; |
195 | p->sys_freq = octeon_get_io_clock_rate(); | 203 | p->sys_freq = octeon_get_io_clock_rate(); |
196 | 204 | ||
205 | p->regs.config = 0; | ||
206 | p->regs.status = 0x08; | ||
207 | p->regs.tx = 0x10; | ||
208 | p->regs.data = 0x80; | ||
209 | |||
197 | master->num_chipselect = 4; | 210 | master->num_chipselect = 4; |
198 | master->mode_bits = SPI_CPHA | | 211 | master->mode_bits = SPI_CPHA | |
199 | SPI_CPOL | | 212 | SPI_CPOL | |
@@ -226,7 +239,7 @@ static int octeon_spi_remove(struct platform_device *pdev) | |||
226 | struct octeon_spi *p = spi_master_get_devdata(master); | 239 | struct octeon_spi *p = spi_master_get_devdata(master); |
227 | 240 | ||
228 | /* Clear the CSENA* and put everything in a known state. */ | 241 | /* Clear the CSENA* and put everything in a known state. */ |
229 | writeq(0, p->register_base + OCTEON_SPI_CFG); | 242 | writeq(0, p->register_base + OCTEON_SPI_CFG(p)); |
230 | 243 | ||
231 | return 0; | 244 | return 0; |
232 | } | 245 | } |