]>
Commit | Line | Data |
---|---|---|
4a207e8b SJ |
1 | /* |
2 | * Analog Devices SPI3 controller driver | |
3 | * | |
4 | * Copyright (c) 2011 Analog Devices Inc. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 as | |
8 | * published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program; if not, write to the Free Software | |
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
18 | */ | |
19 | ||
20 | #include <common.h> | |
24b852a7 | 21 | #include <console.h> |
4a207e8b SJ |
22 | #include <malloc.h> |
23 | #include <spi.h> | |
24 | ||
25 | #include <asm/blackfin.h> | |
d6a320d5 | 26 | #include <asm/clock.h> |
4a207e8b SJ |
27 | #include <asm/gpio.h> |
28 | #include <asm/portmux.h> | |
29 | #include <asm/mach-common/bits/spi6xx.h> | |
30 | ||
31 | struct bfin_spi_slave { | |
32 | struct spi_slave slave; | |
33 | u32 control, clock; | |
34 | struct bfin_spi_regs *regs; | |
35 | int cs_pol; | |
36 | }; | |
37 | ||
38 | #define to_bfin_spi_slave(s) container_of(s, struct bfin_spi_slave, slave) | |
39 | ||
40 | #define gpio_cs(cs) ((cs) - MAX_CTRL_CS) | |
41 | #ifdef CONFIG_BFIN_SPI_GPIO_CS | |
42 | # define is_gpio_cs(cs) ((cs) > MAX_CTRL_CS) | |
43 | #else | |
44 | # define is_gpio_cs(cs) 0 | |
45 | #endif | |
46 | ||
47 | int spi_cs_is_valid(unsigned int bus, unsigned int cs) | |
48 | { | |
49 | if (is_gpio_cs(cs)) | |
50 | return gpio_is_valid(gpio_cs(cs)); | |
51 | else | |
52 | return (cs >= 1 && cs <= MAX_CTRL_CS); | |
53 | } | |
54 | ||
55 | void spi_cs_activate(struct spi_slave *slave) | |
56 | { | |
57 | struct bfin_spi_slave *bss = to_bfin_spi_slave(slave); | |
58 | ||
59 | if (is_gpio_cs(slave->cs)) { | |
60 | unsigned int cs = gpio_cs(slave->cs); | |
61 | gpio_set_value(cs, bss->cs_pol); | |
62 | } else { | |
63 | u32 ssel; | |
64 | ssel = bfin_read32(&bss->regs->ssel); | |
65 | ssel |= 1 << slave->cs; | |
66 | if (bss->cs_pol) | |
c0d1ea4a | 67 | ssel |= BIT(8) << slave->cs; |
4a207e8b | 68 | else |
c0d1ea4a | 69 | ssel &= ~(BIT(8) << slave->cs); |
4a207e8b SJ |
70 | bfin_write32(&bss->regs->ssel, ssel); |
71 | } | |
72 | ||
73 | SSYNC(); | |
74 | } | |
75 | ||
76 | void spi_cs_deactivate(struct spi_slave *slave) | |
77 | { | |
78 | struct bfin_spi_slave *bss = to_bfin_spi_slave(slave); | |
79 | ||
80 | if (is_gpio_cs(slave->cs)) { | |
81 | unsigned int cs = gpio_cs(slave->cs); | |
82 | gpio_set_value(cs, !bss->cs_pol); | |
83 | } else { | |
84 | u32 ssel; | |
85 | ssel = bfin_read32(&bss->regs->ssel); | |
86 | if (bss->cs_pol) | |
c0d1ea4a | 87 | ssel &= ~(BIT(8) << slave->cs); |
4a207e8b | 88 | else |
c0d1ea4a | 89 | ssel |= BIT(8) << slave->cs; |
4a207e8b SJ |
90 | /* deassert cs */ |
91 | bfin_write32(&bss->regs->ssel, ssel); | |
92 | SSYNC(); | |
93 | /* disable cs */ | |
94 | ssel &= ~(1 << slave->cs); | |
95 | bfin_write32(&bss->regs->ssel, ssel); | |
96 | } | |
97 | ||
98 | SSYNC(); | |
99 | } | |
100 | ||
101 | void spi_init() | |
102 | { | |
103 | } | |
104 | ||
105 | #define SPI_PINS(n) \ | |
106 | { 0, P_SPI##n##_SCK, P_SPI##n##_MISO, P_SPI##n##_MOSI, 0 } | |
107 | static unsigned short pins[][5] = { | |
108 | #ifdef SPI0_REGBASE | |
109 | [0] = SPI_PINS(0), | |
110 | #endif | |
111 | #ifdef SPI1_REGBASE | |
112 | [1] = SPI_PINS(1), | |
113 | #endif | |
114 | #ifdef SPI2_REGBASE | |
115 | [2] = SPI_PINS(2), | |
116 | #endif | |
117 | }; | |
118 | ||
119 | #define SPI_CS_PINS(n) \ | |
120 | { \ | |
121 | P_SPI##n##_SSEL1, P_SPI##n##_SSEL2, P_SPI##n##_SSEL3, \ | |
122 | P_SPI##n##_SSEL4, P_SPI##n##_SSEL5, P_SPI##n##_SSEL6, \ | |
123 | P_SPI##n##_SSEL7, \ | |
124 | } | |
125 | static const unsigned short cs_pins[][7] = { | |
126 | #ifdef SPI0_REGBASE | |
127 | [0] = SPI_CS_PINS(0), | |
128 | #endif | |
129 | #ifdef SPI1_REGBASE | |
130 | [1] = SPI_CS_PINS(1), | |
131 | #endif | |
132 | #ifdef SPI2_REGBASE | |
133 | [2] = SPI_CS_PINS(2), | |
134 | #endif | |
135 | }; | |
136 | ||
137 | void spi_set_speed(struct spi_slave *slave, uint hz) | |
138 | { | |
139 | struct bfin_spi_slave *bss = to_bfin_spi_slave(slave); | |
d6a320d5 | 140 | ulong clk; |
4a207e8b SJ |
141 | u32 clock; |
142 | ||
d6a320d5 SZ |
143 | clk = get_spi_clk(); |
144 | clock = clk / hz; | |
4a207e8b SJ |
145 | if (clock) |
146 | clock--; | |
147 | bss->clock = clock; | |
148 | } | |
149 | ||
150 | struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, | |
151 | unsigned int max_hz, unsigned int mode) | |
152 | { | |
153 | struct bfin_spi_slave *bss; | |
154 | u32 reg_base; | |
155 | ||
156 | if (!spi_cs_is_valid(bus, cs)) | |
157 | return NULL; | |
158 | ||
4a207e8b SJ |
159 | switch (bus) { |
160 | #ifdef SPI0_REGBASE | |
161 | case 0: | |
162 | reg_base = SPI0_REGBASE; | |
163 | break; | |
164 | #endif | |
165 | #ifdef SPI1_REGBASE | |
166 | case 1: | |
167 | reg_base = SPI1_REGBASE; | |
168 | break; | |
169 | #endif | |
170 | #ifdef SPI2_REGBASE | |
171 | case 2: | |
172 | reg_base = SPI2_REGBASE; | |
173 | break; | |
174 | #endif | |
175 | default: | |
9bac8f77 | 176 | debug("%s: invalid bus %u\n", __func__, bus); |
4a207e8b SJ |
177 | return NULL; |
178 | } | |
179 | ||
d3504fee | 180 | bss = spi_alloc_slave(struct bfin_spi_slave, bus, cs); |
4a207e8b SJ |
181 | if (!bss) |
182 | return NULL; | |
183 | ||
4a207e8b SJ |
184 | bss->regs = (struct bfin_spi_regs *)reg_base; |
185 | bss->control = SPI_CTL_EN | SPI_CTL_MSTR; | |
186 | if (mode & SPI_CPHA) | |
187 | bss->control |= SPI_CTL_CPHA; | |
188 | if (mode & SPI_CPOL) | |
189 | bss->control |= SPI_CTL_CPOL; | |
190 | if (mode & SPI_LSB_FIRST) | |
191 | bss->control |= SPI_CTL_LSBF; | |
192 | bss->control &= ~SPI_CTL_ASSEL; | |
193 | bss->cs_pol = mode & SPI_CS_HIGH ? 1 : 0; | |
194 | spi_set_speed(&bss->slave, max_hz); | |
195 | ||
196 | return &bss->slave; | |
197 | } | |
198 | ||
199 | void spi_free_slave(struct spi_slave *slave) | |
200 | { | |
201 | struct bfin_spi_slave *bss = to_bfin_spi_slave(slave); | |
202 | free(bss); | |
203 | } | |
204 | ||
205 | int spi_claim_bus(struct spi_slave *slave) | |
206 | { | |
207 | struct bfin_spi_slave *bss = to_bfin_spi_slave(slave); | |
208 | ||
209 | debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs); | |
210 | ||
211 | if (is_gpio_cs(slave->cs)) { | |
212 | unsigned int cs = gpio_cs(slave->cs); | |
213 | gpio_request(cs, "bfin-spi"); | |
214 | gpio_direction_output(cs, !bss->cs_pol); | |
215 | pins[slave->bus][0] = P_DONTCARE; | |
216 | } else | |
217 | pins[slave->bus][0] = cs_pins[slave->bus][slave->cs - 1]; | |
218 | peripheral_request_list(pins[slave->bus], "bfin-spi"); | |
219 | ||
220 | bfin_write32(&bss->regs->control, bss->control); | |
221 | bfin_write32(&bss->regs->clock, bss->clock); | |
222 | bfin_write32(&bss->regs->delay, 0x0); | |
223 | bfin_write32(&bss->regs->rx_control, SPI_RXCTL_REN); | |
224 | bfin_write32(&bss->regs->tx_control, SPI_TXCTL_TEN | SPI_TXCTL_TTI); | |
225 | SSYNC(); | |
226 | ||
227 | return 0; | |
228 | } | |
229 | ||
230 | void spi_release_bus(struct spi_slave *slave) | |
231 | { | |
232 | struct bfin_spi_slave *bss = to_bfin_spi_slave(slave); | |
233 | ||
234 | debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs); | |
235 | ||
236 | peripheral_free_list(pins[slave->bus]); | |
237 | if (is_gpio_cs(slave->cs)) | |
238 | gpio_free(gpio_cs(slave->cs)); | |
239 | ||
240 | bfin_write32(&bss->regs->rx_control, 0x0); | |
241 | bfin_write32(&bss->regs->tx_control, 0x0); | |
242 | bfin_write32(&bss->regs->control, 0x0); | |
243 | SSYNC(); | |
244 | } | |
245 | ||
246 | #ifndef CONFIG_BFIN_SPI_IDLE_VAL | |
247 | # define CONFIG_BFIN_SPI_IDLE_VAL 0xff | |
248 | #endif | |
249 | ||
250 | static int spi_pio_xfer(struct bfin_spi_slave *bss, const u8 *tx, u8 *rx, | |
251 | uint bytes) | |
252 | { | |
253 | /* discard invalid rx data and empty rfifo */ | |
254 | while (!(bfin_read32(&bss->regs->status) & SPI_STAT_RFE)) | |
255 | bfin_read32(&bss->regs->rfifo); | |
256 | ||
257 | while (bytes--) { | |
258 | u8 value = (tx ? *tx++ : CONFIG_BFIN_SPI_IDLE_VAL); | |
259 | debug("%s: tx:%x ", __func__, value); | |
260 | bfin_write32(&bss->regs->tfifo, value); | |
261 | SSYNC(); | |
262 | while (bfin_read32(&bss->regs->status) & SPI_STAT_RFE) | |
263 | if (ctrlc()) | |
264 | return -1; | |
265 | value = bfin_read32(&bss->regs->rfifo); | |
266 | if (rx) | |
267 | *rx++ = value; | |
268 | debug("rx:%x\n", value); | |
269 | } | |
270 | ||
271 | return 0; | |
272 | } | |
273 | ||
274 | int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, | |
275 | void *din, unsigned long flags) | |
276 | { | |
277 | struct bfin_spi_slave *bss = to_bfin_spi_slave(slave); | |
278 | const u8 *tx = dout; | |
279 | u8 *rx = din; | |
280 | uint bytes = bitlen / 8; | |
281 | int ret = 0; | |
282 | ||
283 | debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__, | |
284 | slave->bus, slave->cs, bitlen, bytes, flags); | |
285 | ||
286 | if (bitlen == 0) | |
287 | goto done; | |
288 | ||
289 | /* we can only do 8 bit transfers */ | |
290 | if (bitlen % 8) { | |
291 | flags |= SPI_XFER_END; | |
292 | goto done; | |
293 | } | |
294 | ||
295 | if (flags & SPI_XFER_BEGIN) | |
296 | spi_cs_activate(slave); | |
297 | ||
298 | ret = spi_pio_xfer(bss, tx, rx, bytes); | |
299 | ||
300 | done: | |
301 | if (flags & SPI_XFER_END) | |
302 | spi_cs_deactivate(slave); | |
303 | ||
304 | return ret; | |
305 | } |