]> git.sur5r.net Git - u-boot/blob - drivers/spi/bfin_spi.c
Blackfin: bfin_spi: convert to portmux framework
[u-boot] / drivers / spi / bfin_spi.c
1 /*
2  * Driver for Blackfin On-Chip SPI device
3  *
4  * Copyright (c) 2005-2008 Analog Devices Inc.
5  *
6  * Licensed under the GPL-2 or later.
7  */
8
9 /*#define DEBUG*/
10
11 #include <common.h>
12 #include <malloc.h>
13 #include <spi.h>
14
15 #include <asm/blackfin.h>
16 #include <asm/portmux.h>
17 #include <asm/mach-common/bits/spi.h>
18
19 struct bfin_spi_slave {
20         struct spi_slave slave;
21         void *mmr_base;
22         u16 ctl, baud, flg;
23 };
24
25 #define MAKE_SPI_FUNC(mmr, off) \
26 static inline void write_##mmr(struct bfin_spi_slave *bss, u16 val) { bfin_write16(bss->mmr_base + off, val); } \
27 static inline u16 read_##mmr(struct bfin_spi_slave *bss) { return bfin_read16(bss->mmr_base + off); }
28 MAKE_SPI_FUNC(SPI_CTL,  0x00)
29 MAKE_SPI_FUNC(SPI_FLG,  0x04)
30 MAKE_SPI_FUNC(SPI_STAT, 0x08)
31 MAKE_SPI_FUNC(SPI_TDBR, 0x0c)
32 MAKE_SPI_FUNC(SPI_RDBR, 0x10)
33 MAKE_SPI_FUNC(SPI_BAUD, 0x14)
34
35 #define to_bfin_spi_slave(s) container_of(s, struct bfin_spi_slave, slave)
36
37 __attribute__((weak))
38 int spi_cs_is_valid(unsigned int bus, unsigned int cs)
39 {
40 #if defined(__ADSPBF538__) || defined(__ADSPBF539__)
41         /* The SPI1/SPI2 buses are weird ... only 1 CS */
42         if (bus > 0 && cs != 1)
43                 return 0;
44 #endif
45         return (cs >= 1 && cs <= 7);
46 }
47
48 __attribute__((weak))
49 void spi_cs_activate(struct spi_slave *slave)
50 {
51         struct bfin_spi_slave *bss = to_bfin_spi_slave(slave);
52         write_SPI_FLG(bss,
53                 (read_SPI_FLG(bss) &
54                 ~((!bss->flg << 8) << slave->cs)) |
55                 (1 << slave->cs));
56         SSYNC();
57         debug("%s: SPI_FLG:%x\n", __func__, read_SPI_FLG(bss));
58 }
59
60 __attribute__((weak))
61 void spi_cs_deactivate(struct spi_slave *slave)
62 {
63         struct bfin_spi_slave *bss = to_bfin_spi_slave(slave);
64         u16 flg;
65
66         /* make sure we force the cs to deassert rather than let the
67          * pin float back up.  otherwise, exact timings may not be
68          * met some of the time leading to random behavior (ugh).
69          */
70         flg = read_SPI_FLG(bss) | ((!bss->flg << 8) << slave->cs);
71         write_SPI_FLG(bss, flg);
72         SSYNC();
73         debug("%s: SPI_FLG:%x\n", __func__, read_SPI_FLG(bss));
74
75         flg &= ~(1 << slave->cs);
76         write_SPI_FLG(bss, flg);
77         SSYNC();
78         debug("%s: SPI_FLG:%x\n", __func__, read_SPI_FLG(bss));
79 }
80
81 void spi_init()
82 {
83 }
84
85 #ifdef SPI_CTL
86 # define SPI0_CTL SPI_CTL
87 #endif
88
89 #define SPI_PINS(n) \
90         [n] = { 0, P_SPI##n##_SCK, P_SPI##n##_MISO, P_SPI##n##_MOSI, 0 }
91 static unsigned short pins[][5] = {
92 #ifdef SPI0_CTL
93         SPI_PINS(0),
94 #endif
95 #ifdef SPI1_CTL
96         SPI_PINS(1),
97 #endif
98 #ifdef SPI2_CTL
99         SPI_PINS(2),
100 #endif
101 };
102
103 #define SPI_CS_PINS(n) \
104         [n] = { \
105                 P_SPI##n##_SSEL1, P_SPI##n##_SSEL2, P_SPI##n##_SSEL3, \
106                 P_SPI##n##_SSEL4, P_SPI##n##_SSEL5, P_SPI##n##_SSEL6, \
107                 P_SPI##n##_SSEL7, \
108         }
109 static const unsigned short cs_pins[][7] = {
110 #ifdef SPI0_CTL
111         SPI_CS_PINS(0),
112 #endif
113 #ifdef SPI1_CTL
114         SPI_CS_PINS(1),
115 #endif
116 #ifdef SPI2_CTL
117         SPI_CS_PINS(2),
118 #endif
119 };
120
121 struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
122                 unsigned int max_hz, unsigned int mode)
123 {
124         struct bfin_spi_slave *bss;
125         ulong sclk;
126         u32 mmr_base;
127         u32 baud;
128
129         if (!spi_cs_is_valid(bus, cs))
130                 return NULL;
131
132         if (bus >= ARRAY_SIZE(pins) || pins[bus] == NULL) {
133                 debug("%s: invalid bus %u\n", __func__, bus);
134                 return NULL;
135         }
136         switch (bus) {
137 #ifdef SPI0_CTL
138                 case 0: mmr_base = SPI0_CTL; break;
139 #endif
140 #ifdef SPI1_CTL
141                 case 1: mmr_base = SPI1_CTL; break;
142 #endif
143 #ifdef SPI2_CTL
144                 case 2: mmr_base = SPI2_CTL; break;
145 #endif
146                 default: return NULL;
147         }
148
149         sclk = get_sclk();
150         baud = sclk / (2 * max_hz);
151         /* baud should be rounded up */
152         if (sclk % (2 * max_hz))
153                 baud += 1;
154         if (baud < 2)
155                 baud = 2;
156         else if (baud > (u16)-1)
157                 baud = -1;
158
159         bss = malloc(sizeof(*bss));
160         if (!bss)
161                 return NULL;
162
163         bss->slave.bus = bus;
164         bss->slave.cs = cs;
165         bss->mmr_base = (void *)mmr_base;
166         bss->ctl = SPE | MSTR | TDBR_CORE;
167         if (mode & SPI_CPHA) bss->ctl |= CPHA;
168         if (mode & SPI_CPOL) bss->ctl |= CPOL;
169         if (mode & SPI_LSB_FIRST) bss->ctl |= LSBF;
170         bss->baud = baud;
171         bss->flg = mode & SPI_CS_HIGH ? 1 : 0;
172
173         debug("%s: bus:%i cs:%i mmr:%x ctl:%x baud:%i flg:%i\n", __func__,
174                 bus, cs, mmr_base, bss->ctl, baud, bss->flg);
175
176         return &bss->slave;
177 }
178
179 void spi_free_slave(struct spi_slave *slave)
180 {
181         struct bfin_spi_slave *bss = to_bfin_spi_slave(slave);
182         free(bss);
183 }
184
185 int spi_claim_bus(struct spi_slave *slave)
186 {
187         struct bfin_spi_slave *bss = to_bfin_spi_slave(slave);
188
189         debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
190
191         pins[slave->bus][0] = cs_pins[slave->bus][slave->cs - 1];
192         peripheral_request_list(pins[slave->bus], "bfin-spi");
193
194         write_SPI_CTL(bss, bss->ctl);
195         write_SPI_BAUD(bss, bss->baud);
196         SSYNC();
197
198         return 0;
199 }
200
201 void spi_release_bus(struct spi_slave *slave)
202 {
203         struct bfin_spi_slave *bss = to_bfin_spi_slave(slave);
204
205         debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
206
207         peripheral_free_list(pins[slave->bus]);
208
209         write_SPI_CTL(bss, 0);
210         SSYNC();
211 }
212
213 #ifndef CONFIG_BFIN_SPI_IDLE_VAL
214 # define CONFIG_BFIN_SPI_IDLE_VAL 0xff
215 #endif
216
217 int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
218                 void *din, unsigned long flags)
219 {
220         struct bfin_spi_slave *bss = to_bfin_spi_slave(slave);
221         const u8 *tx = dout;
222         u8 *rx = din;
223         uint bytes = bitlen / 8;
224         int ret = 0;
225
226         debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__,
227                 slave->bus, slave->cs, bitlen, bytes, flags);
228
229         if (bitlen == 0)
230                 goto done;
231
232         /* we can only do 8 bit transfers */
233         if (bitlen % 8) {
234                 flags |= SPI_XFER_END;
235                 goto done;
236         }
237
238         if (flags & SPI_XFER_BEGIN)
239                 spi_cs_activate(slave);
240
241         /* todo: take advantage of hardware fifos and setup RX dma */
242         while (bytes--) {
243                 u8 value = (tx ? *tx++ : CONFIG_BFIN_SPI_IDLE_VAL);
244                 debug("%s: tx:%x ", __func__, value);
245                 write_SPI_TDBR(bss, value);
246                 SSYNC();
247                 while ((read_SPI_STAT(bss) & TXS))
248                         if (ctrlc()) {
249                                 ret = -1;
250                                 goto done;
251                         }
252                 while (!(read_SPI_STAT(bss) & SPIF))
253                         if (ctrlc()) {
254                                 ret = -1;
255                                 goto done;
256                         }
257                 while (!(read_SPI_STAT(bss) & RXS))
258                         if (ctrlc()) {
259                                 ret = -1;
260                                 goto done;
261                         }
262                 value = read_SPI_RDBR(bss);
263                 if (rx)
264                         *rx++ = value;
265                 debug("rx:%x\n", value);
266         }
267
268  done:
269         if (flags & SPI_XFER_END)
270                 spi_cs_deactivate(slave);
271
272         return ret;
273 }