]> git.karo-electronics.de Git - karo-tx-uboot.git/blob - drivers/spi/ep93xx_spi.c
Merge remote-tracking branch 'u-boot/master'
[karo-tx-uboot.git] / drivers / spi / ep93xx_spi.c
1 /*
2  * SPI Driver for EP93xx
3  *
4  * Copyright (C) 2013 Sergey Kostanabev <sergey.kostanbaev <at> fairwaves.ru>
5  *
6  * Inspired form linux kernel driver and atmel uboot driver
7  *
8  * SPDX-License-Identifier:     GPL-2.0+
9  */
10
11 #include <common.h>
12 #include <spi.h>
13 #include <malloc.h>
14
15 #include <asm/io.h>
16
17 #include <asm/arch/ep93xx.h>
18
19 #define SSPBASE                 SPI_BASE
20
21 #define SSPCR0                  0x0000
22 #define SSPCR0_MODE_SHIFT       6
23 #define SSPCR0_SCR_SHIFT        8
24 #define SSPCR0_SPH              BIT(7)
25 #define SSPCR0_SPO              BIT(6)
26 #define SSPCR0_FRF_SPI          0
27 #define SSPCR0_DSS_8BIT         7
28
29 #define SSPCR1                  0x0004
30 #define SSPCR1_RIE              BIT(0)
31 #define SSPCR1_TIE              BIT(1)
32 #define SSPCR1_RORIE            BIT(2)
33 #define SSPCR1_LBM              BIT(3)
34 #define SSPCR1_SSE              BIT(4)
35 #define SSPCR1_MS               BIT(5)
36 #define SSPCR1_SOD              BIT(6)
37
38 #define SSPDR                   0x0008
39
40 #define SSPSR                   0x000c
41 #define SSPSR_TFE               BIT(0)
42 #define SSPSR_TNF               BIT(1)
43 #define SSPSR_RNE               BIT(2)
44 #define SSPSR_RFF               BIT(3)
45 #define SSPSR_BSY               BIT(4)
46 #define SSPCPSR                 0x0010
47
48 #define SSPIIR                  0x0014
49 #define SSPIIR_RIS              BIT(0)
50 #define SSPIIR_TIS              BIT(1)
51 #define SSPIIR_RORIS            BIT(2)
52 #define SSPICR                  SSPIIR
53
54 #define SSPCLOCK                14745600
55 #define SSP_MAX_RATE            (SSPCLOCK / 2)
56 #define SSP_MIN_RATE            (SSPCLOCK / (254 * 256))
57
58 /* timeout in milliseconds */
59 #define SPI_TIMEOUT             5
60 /* maximum depth of RX/TX FIFO */
61 #define SPI_FIFO_SIZE           8
62
63 struct ep93xx_spi_slave {
64         struct spi_slave slave;
65
66         unsigned sspcr0;
67         unsigned sspcpsr;
68 };
69
70 static inline struct ep93xx_spi_slave *to_ep93xx_spi(struct spi_slave *slave)
71 {
72         return container_of(slave, struct ep93xx_spi_slave, slave);
73 }
74
75 void spi_init()
76 {
77 }
78
79 static inline void ep93xx_spi_write_u8(u16 reg, u8 value)
80 {
81         writel(value, (unsigned int *)(SSPBASE + reg));
82 }
83
84 static inline u8 ep93xx_spi_read_u8(u16 reg)
85 {
86         return readl((unsigned int *)(SSPBASE + reg));
87 }
88
89 static inline void ep93xx_spi_write_u16(u16 reg, u16 value)
90 {
91         writel(value, (unsigned int *)(SSPBASE + reg));
92 }
93
94 static inline u16 ep93xx_spi_read_u16(u16 reg)
95 {
96         return (u16)readl((unsigned int *)(SSPBASE + reg));
97 }
98
99 static int ep93xx_spi_init_hw(unsigned int rate, unsigned int mode,
100                                 struct ep93xx_spi_slave *slave)
101 {
102         unsigned cpsr, scr;
103
104         if (rate > SSP_MAX_RATE)
105                 rate = SSP_MAX_RATE;
106
107         if (rate < SSP_MIN_RATE)
108                 return -1;
109
110         /* Calculate divisors so that we can get speed according the
111          * following formula:
112          *      rate = spi_clock_rate / (cpsr * (1 + scr))
113          *
114          * cpsr must be even number and starts from 2, scr can be any number
115          * between 0 and 255.
116          */
117         for (cpsr = 2; cpsr <= 254; cpsr += 2) {
118                 for (scr = 0; scr <= 255; scr++) {
119                         if ((SSPCLOCK / (cpsr * (scr + 1))) <= rate) {
120                                 /* Set CHPA and CPOL, SPI format and 8bit */
121                                 unsigned sspcr0 = (scr << SSPCR0_SCR_SHIFT) |
122                                         SSPCR0_FRF_SPI | SSPCR0_DSS_8BIT;
123                                 if (mode & SPI_CPHA)
124                                         sspcr0 |= SSPCR0_SPH;
125                                 if (mode & SPI_CPOL)
126                                         sspcr0 |= SSPCR0_SPO;
127
128                                 slave->sspcr0 = sspcr0;
129                                 slave->sspcpsr = cpsr;
130                                 return 0;
131                         }
132                 }
133         }
134
135         return -1;
136 }
137
138 void spi_set_speed(struct spi_slave *slave, unsigned int hz)
139 {
140         struct ep93xx_spi_slave *as = to_ep93xx_spi(slave);
141
142         unsigned int mode = 0;
143         if (as->sspcr0 & SSPCR0_SPH)
144                 mode |= SPI_CPHA;
145         if (as->sspcr0 & SSPCR0_SPO)
146                 mode |= SPI_CPOL;
147
148         ep93xx_spi_init_hw(hz, mode, as);
149 }
150
151 struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
152                         unsigned int max_hz, unsigned int mode)
153 {
154         struct ep93xx_spi_slave *as;
155
156         if (!spi_cs_is_valid(bus, cs))
157                 return NULL;
158
159         as = spi_alloc_slave(struct ep93xx_spi_slave, bus, cs);
160         if (!as)
161                 return NULL;
162
163         if (ep93xx_spi_init_hw(max_hz, mode, as)) {
164                 free(as);
165                 return NULL;
166         }
167
168         return &as->slave;
169 }
170
171 void spi_free_slave(struct spi_slave *slave)
172 {
173         struct ep93xx_spi_slave *as = to_ep93xx_spi(slave);
174
175         free(as);
176 }
177
178 int spi_claim_bus(struct spi_slave *slave)
179 {
180         struct ep93xx_spi_slave *as = to_ep93xx_spi(slave);
181
182         /* Enable the SPI hardware */
183         ep93xx_spi_write_u8(SSPCR1, SSPCR1_SSE);
184
185
186         ep93xx_spi_write_u8(SSPCPSR, as->sspcpsr);
187         ep93xx_spi_write_u16(SSPCR0, as->sspcr0);
188
189         debug("Select CS:%d SSPCPSR=%02x SSPCR0=%04x\n",
190               slave->cs, as->sspcpsr, as->sspcr0);
191         return 0;
192 }
193
194 void spi_release_bus(struct spi_slave *slave)
195 {
196         /* Disable the SPI hardware */
197         ep93xx_spi_write_u8(SSPCR1, 0);
198 }
199
200 int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
201                 const void *dout, void *din, unsigned long flags)
202 {
203         unsigned int    len_tx;
204         unsigned int    len_rx;
205         unsigned int    len;
206         u32             status;
207         const u8        *txp = dout;
208         u8              *rxp = din;
209         u8              value;
210
211         debug("spi_xfer: slave %u:%u dout %p din %p bitlen %u\n",
212               slave->bus, slave->cs, (uint *)dout, (uint *)din, bitlen);
213
214
215         if (bitlen == 0)
216                 /* Finish any previously submitted transfers */
217                 goto out;
218
219         if (bitlen % 8) {
220                 /* Errors always terminate an ongoing transfer */
221                 flags |= SPI_XFER_END;
222                 goto out;
223         }
224
225         len = bitlen / 8;
226
227
228         if (flags & SPI_XFER_BEGIN) {
229                 /* Empty RX FIFO */
230                 while ((ep93xx_spi_read_u8(SSPSR) & SSPSR_RNE))
231                         ep93xx_spi_read_u8(SSPDR);
232
233                 spi_cs_activate(slave);
234         }
235
236         for (len_tx = 0, len_rx = 0; len_rx < len; ) {
237                 status = ep93xx_spi_read_u8(SSPSR);
238
239                 if ((len_tx < len) && (status & SSPSR_TNF)) {
240                         if (txp)
241                                 value = *txp++;
242                         else
243                                 value = 0xff;
244
245                         ep93xx_spi_write_u8(SSPDR, value);
246                         len_tx++;
247                 }
248
249                 if (status & SSPSR_RNE) {
250                         value = ep93xx_spi_read_u8(SSPDR);
251
252                         if (rxp)
253                                 *rxp++ = value;
254                         len_rx++;
255                 }
256         }
257
258 out:
259         if (flags & SPI_XFER_END) {
260                 /*
261                  * Wait until the transfer is completely done before
262                  * we deactivate CS.
263                  */
264                 do {
265                         status = ep93xx_spi_read_u8(SSPSR);
266                 } while (status & SSPSR_BSY);
267
268                 spi_cs_deactivate(slave);
269         }
270
271         return 0;
272 }