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