]>
Commit | Line | Data |
---|---|---|
16f47c9c NI |
1 | /* |
2 | * SH QSPI (Quad SPI) driver | |
3 | * | |
4 | * Copyright (C) 2013 Renesas Electronics Corporation | |
5 | * Copyright (C) 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com> | |
6 | * | |
7 | * SPDX-License-Identifier: GPL-2.0 | |
8 | */ | |
9 | ||
10 | #include <common.h> | |
24b852a7 | 11 | #include <console.h> |
16f47c9c NI |
12 | #include <malloc.h> |
13 | #include <spi.h> | |
22e75d6d | 14 | #include <asm/arch/rmobile.h> |
16f47c9c NI |
15 | #include <asm/io.h> |
16 | ||
17 | /* SH QSPI register bit masks <REG>_<BIT> */ | |
18 | #define SPCR_MSTR 0x08 | |
19 | #define SPCR_SPE 0x40 | |
20 | #define SPSR_SPRFF 0x80 | |
21 | #define SPSR_SPTEF 0x20 | |
22 | #define SPPCR_IO3FV 0x04 | |
23 | #define SPPCR_IO2FV 0x02 | |
24 | #define SPPCR_IO1FV 0x01 | |
ccaa9485 JT |
25 | #define SPBDCR_RXBC0 BIT(0) |
26 | #define SPCMD_SCKDEN BIT(15) | |
27 | #define SPCMD_SLNDEN BIT(14) | |
28 | #define SPCMD_SPNDEN BIT(13) | |
29 | #define SPCMD_SSLKP BIT(7) | |
30 | #define SPCMD_BRDV0 BIT(2) | |
16f47c9c NI |
31 | #define SPCMD_INIT1 SPCMD_SCKDEN | SPCMD_SLNDEN | \ |
32 | SPCMD_SPNDEN | SPCMD_SSLKP | \ | |
33 | SPCMD_BRDV0 | |
34 | #define SPCMD_INIT2 SPCMD_SPNDEN | SPCMD_SSLKP | \ | |
35 | SPCMD_BRDV0 | |
ccaa9485 JT |
36 | #define SPBFCR_TXRST BIT(7) |
37 | #define SPBFCR_RXRST BIT(6) | |
16f47c9c NI |
38 | |
39 | /* SH QSPI register set */ | |
40 | struct sh_qspi_regs { | |
41 | unsigned char spcr; | |
42 | unsigned char sslp; | |
43 | unsigned char sppcr; | |
44 | unsigned char spsr; | |
45 | unsigned long spdr; | |
46 | unsigned char spscr; | |
47 | unsigned char spssr; | |
48 | unsigned char spbr; | |
49 | unsigned char spdcr; | |
50 | unsigned char spckd; | |
51 | unsigned char sslnd; | |
52 | unsigned char spnd; | |
53 | unsigned char dummy0; | |
54 | unsigned short spcmd0; | |
55 | unsigned short spcmd1; | |
56 | unsigned short spcmd2; | |
57 | unsigned short spcmd3; | |
58 | unsigned char spbfcr; | |
59 | unsigned char dummy1; | |
60 | unsigned short spbdcr; | |
61 | unsigned long spbmul0; | |
62 | unsigned long spbmul1; | |
63 | unsigned long spbmul2; | |
64 | unsigned long spbmul3; | |
65 | }; | |
66 | ||
67 | struct sh_qspi_slave { | |
68 | struct spi_slave slave; | |
69 | struct sh_qspi_regs *regs; | |
70 | }; | |
71 | ||
72 | static inline struct sh_qspi_slave *to_sh_qspi(struct spi_slave *slave) | |
73 | { | |
74 | return container_of(slave, struct sh_qspi_slave, slave); | |
75 | } | |
76 | ||
77 | static void sh_qspi_init(struct sh_qspi_slave *ss) | |
78 | { | |
79 | /* QSPI initialize */ | |
80 | /* Set master mode only */ | |
81 | writeb(SPCR_MSTR, &ss->regs->spcr); | |
82 | ||
83 | /* Set SSL signal level */ | |
84 | writeb(0x00, &ss->regs->sslp); | |
85 | ||
86 | /* Set MOSI signal value when transfer is in idle state */ | |
87 | writeb(SPPCR_IO3FV|SPPCR_IO2FV, &ss->regs->sppcr); | |
88 | ||
89 | /* Set bit rate. See 58.3.8 Quad Serial Peripheral Interface */ | |
90 | writeb(0x01, &ss->regs->spbr); | |
91 | ||
92 | /* Disable Dummy Data Transmission */ | |
93 | writeb(0x00, &ss->regs->spdcr); | |
94 | ||
95 | /* Set clock delay value */ | |
96 | writeb(0x00, &ss->regs->spckd); | |
97 | ||
98 | /* Set SSL negation delay value */ | |
99 | writeb(0x00, &ss->regs->sslnd); | |
100 | ||
101 | /* Set next-access delay value */ | |
102 | writeb(0x00, &ss->regs->spnd); | |
103 | ||
104 | /* Set equence command */ | |
105 | writew(SPCMD_INIT2, &ss->regs->spcmd0); | |
106 | ||
107 | /* Reset transfer and receive Buffer */ | |
108 | setbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST); | |
109 | ||
110 | /* Clear transfer and receive Buffer control bit */ | |
111 | clrbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST); | |
112 | ||
113 | /* Set equence control method. Use equence0 only */ | |
114 | writeb(0x00, &ss->regs->spscr); | |
115 | ||
116 | /* Enable SPI function */ | |
117 | setbits_8(&ss->regs->spcr, SPCR_SPE); | |
118 | } | |
119 | ||
120 | int spi_cs_is_valid(unsigned int bus, unsigned int cs) | |
121 | { | |
122 | return 1; | |
123 | } | |
124 | ||
125 | void spi_cs_activate(struct spi_slave *slave) | |
126 | { | |
127 | struct sh_qspi_slave *ss = to_sh_qspi(slave); | |
128 | ||
129 | /* Set master mode only */ | |
130 | writeb(SPCR_MSTR, &ss->regs->spcr); | |
131 | ||
132 | /* Set command */ | |
133 | writew(SPCMD_INIT1, &ss->regs->spcmd0); | |
134 | ||
135 | /* Reset transfer and receive Buffer */ | |
136 | setbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST); | |
137 | ||
138 | /* Clear transfer and receive Buffer control bit */ | |
139 | clrbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST); | |
140 | ||
141 | /* Set equence control method. Use equence0 only */ | |
142 | writeb(0x00, &ss->regs->spscr); | |
143 | ||
144 | /* Enable SPI function */ | |
145 | setbits_8(&ss->regs->spcr, SPCR_SPE); | |
146 | } | |
147 | ||
148 | void spi_cs_deactivate(struct spi_slave *slave) | |
149 | { | |
150 | struct sh_qspi_slave *ss = to_sh_qspi(slave); | |
151 | ||
152 | /* Disable SPI Function */ | |
153 | clrbits_8(&ss->regs->spcr, SPCR_SPE); | |
154 | } | |
155 | ||
156 | void spi_init(void) | |
157 | { | |
158 | /* nothing to do */ | |
159 | } | |
160 | ||
161 | struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, | |
162 | unsigned int max_hz, unsigned int mode) | |
163 | { | |
164 | struct sh_qspi_slave *ss; | |
165 | ||
166 | if (!spi_cs_is_valid(bus, cs)) | |
167 | return NULL; | |
168 | ||
169 | ss = spi_alloc_slave(struct sh_qspi_slave, bus, cs); | |
170 | if (!ss) { | |
171 | printf("SPI_error: Fail to allocate sh_qspi_slave\n"); | |
172 | return NULL; | |
173 | } | |
174 | ||
22e75d6d | 175 | ss->regs = (struct sh_qspi_regs *)SH_QSPI_BASE; |
16f47c9c NI |
176 | |
177 | /* Init SH QSPI */ | |
178 | sh_qspi_init(ss); | |
179 | ||
180 | return &ss->slave; | |
181 | } | |
182 | ||
183 | void spi_free_slave(struct spi_slave *slave) | |
184 | { | |
185 | struct sh_qspi_slave *spi = to_sh_qspi(slave); | |
186 | ||
187 | free(spi); | |
188 | } | |
189 | ||
190 | int spi_claim_bus(struct spi_slave *slave) | |
191 | { | |
192 | return 0; | |
193 | } | |
194 | ||
195 | void spi_release_bus(struct spi_slave *slave) | |
196 | { | |
197 | } | |
198 | ||
199 | int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, | |
200 | void *din, unsigned long flags) | |
201 | { | |
202 | struct sh_qspi_slave *ss = to_sh_qspi(slave); | |
203 | unsigned long nbyte; | |
204 | int ret = 0; | |
205 | unsigned char dtdata = 0, drdata; | |
206 | unsigned char *tdata = &dtdata, *rdata = &drdata; | |
207 | unsigned long *spbmul0 = &ss->regs->spbmul0; | |
208 | ||
209 | if (dout == NULL && din == NULL) { | |
210 | if (flags & SPI_XFER_END) | |
211 | spi_cs_deactivate(slave); | |
212 | return 0; | |
213 | } | |
214 | ||
215 | if (bitlen % 8) { | |
216 | printf("%s: bitlen is not 8bit alined %d", __func__, bitlen); | |
217 | return 1; | |
218 | } | |
219 | ||
220 | nbyte = bitlen / 8; | |
221 | ||
222 | if (flags & SPI_XFER_BEGIN) { | |
223 | spi_cs_activate(slave); | |
224 | ||
225 | /* Set 1048576 byte */ | |
226 | writel(0x100000, spbmul0); | |
227 | } | |
228 | ||
229 | if (flags & SPI_XFER_END) | |
230 | writel(nbyte, spbmul0); | |
231 | ||
232 | if (dout != NULL) | |
233 | tdata = (unsigned char *)dout; | |
234 | ||
235 | if (din != NULL) | |
236 | rdata = din; | |
237 | ||
238 | while (nbyte > 0) { | |
239 | while (!(readb(&ss->regs->spsr) & SPSR_SPTEF)) { | |
240 | if (ctrlc()) { | |
241 | puts("abort\n"); | |
242 | return 1; | |
243 | } | |
244 | udelay(10); | |
245 | } | |
246 | ||
247 | writeb(*tdata, (unsigned char *)(&ss->regs->spdr)); | |
248 | ||
249 | while ((readw(&ss->regs->spbdcr) != SPBDCR_RXBC0)) { | |
250 | if (ctrlc()) { | |
251 | puts("abort\n"); | |
252 | return 1; | |
253 | } | |
254 | udelay(1); | |
255 | } | |
256 | ||
257 | while (!(readb(&ss->regs->spsr) & SPSR_SPRFF)) { | |
258 | if (ctrlc()) { | |
259 | puts("abort\n"); | |
260 | return 1; | |
261 | } | |
262 | udelay(10); | |
263 | } | |
264 | ||
265 | *rdata = readb((unsigned char *)(&ss->regs->spdr)); | |
266 | ||
267 | if (dout != NULL) | |
268 | tdata++; | |
269 | if (din != NULL) | |
270 | rdata++; | |
271 | ||
272 | nbyte--; | |
273 | } | |
274 | ||
275 | if (flags & SPI_XFER_END) | |
276 | spi_cs_deactivate(slave); | |
277 | ||
278 | return ret; | |
279 | } |