]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/spi/atmel_spi.c
dm: pmic: max77686: Correct two typos in a comment
[karo-tx-uboot.git] / drivers / spi / atmel_spi.c
1 /*
2  * Copyright (C) 2007 Atmel Corporation
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6 #include <common.h>
7 #include <spi.h>
8 #include <malloc.h>
9
10 #include <asm/io.h>
11
12 #include <asm/arch/clk.h>
13 #include <asm/arch/hardware.h>
14
15 #include "atmel_spi.h"
16
17 static int spi_has_wdrbt(struct atmel_spi_slave *slave)
18 {
19         unsigned int ver;
20
21         ver = spi_readl(slave, VERSION);
22
23         return (ATMEL_SPI_VERSION_REV(ver) >= 0x210);
24 }
25
26 void spi_init()
27 {
28
29 }
30
31 struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
32                         unsigned int max_hz, unsigned int mode)
33 {
34         struct atmel_spi_slave  *as;
35         unsigned int            scbr;
36         u32                     csrx;
37         void                    *regs;
38
39         if (!spi_cs_is_valid(bus, cs))
40                 return NULL;
41
42         switch (bus) {
43         case 0:
44                 regs = (void *)ATMEL_BASE_SPI0;
45                 break;
46 #ifdef ATMEL_BASE_SPI1
47         case 1:
48                 regs = (void *)ATMEL_BASE_SPI1;
49                 break;
50 #endif
51 #ifdef ATMEL_BASE_SPI2
52         case 2:
53                 regs = (void *)ATMEL_BASE_SPI2;
54                 break;
55 #endif
56 #ifdef ATMEL_BASE_SPI3
57         case 3:
58                 regs = (void *)ATMEL_BASE_SPI3;
59                 break;
60 #endif
61         default:
62                 return NULL;
63         }
64
65
66         scbr = (get_spi_clk_rate(bus) + max_hz - 1) / max_hz;
67         if (scbr > ATMEL_SPI_CSRx_SCBR_MAX)
68                 /* Too low max SCK rate */
69                 return NULL;
70         if (scbr < 1)
71                 scbr = 1;
72
73         csrx = ATMEL_SPI_CSRx_SCBR(scbr);
74         csrx |= ATMEL_SPI_CSRx_BITS(ATMEL_SPI_BITS_8);
75         if (!(mode & SPI_CPHA))
76                 csrx |= ATMEL_SPI_CSRx_NCPHA;
77         if (mode & SPI_CPOL)
78                 csrx |= ATMEL_SPI_CSRx_CPOL;
79
80         as = spi_alloc_slave(struct atmel_spi_slave, bus, cs);
81         if (!as)
82                 return NULL;
83
84         as->regs = regs;
85         as->mr = ATMEL_SPI_MR_MSTR | ATMEL_SPI_MR_MODFDIS
86                         | ATMEL_SPI_MR_PCS(~(1 << cs) & 0xf);
87         if (spi_has_wdrbt(as))
88                 as->mr |= ATMEL_SPI_MR_WDRBT;
89
90         spi_writel(as, CSR(cs), csrx);
91
92         return &as->slave;
93 }
94
95 void spi_free_slave(struct spi_slave *slave)
96 {
97         struct atmel_spi_slave *as = to_atmel_spi(slave);
98
99         free(as);
100 }
101
102 int spi_claim_bus(struct spi_slave *slave)
103 {
104         struct atmel_spi_slave *as = to_atmel_spi(slave);
105
106         /* Enable the SPI hardware */
107         spi_writel(as, CR, ATMEL_SPI_CR_SPIEN);
108
109         /*
110          * Select the slave. This should set SCK to the correct
111          * initial state, etc.
112          */
113         spi_writel(as, MR, as->mr);
114
115         return 0;
116 }
117
118 void spi_release_bus(struct spi_slave *slave)
119 {
120         struct atmel_spi_slave *as = to_atmel_spi(slave);
121
122         /* Disable the SPI hardware */
123         spi_writel(as, CR, ATMEL_SPI_CR_SPIDIS);
124 }
125
126 int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
127                 const void *dout, void *din, unsigned long flags)
128 {
129         struct atmel_spi_slave *as = to_atmel_spi(slave);
130         unsigned int    len_tx;
131         unsigned int    len_rx;
132         unsigned int    len;
133         u32             status;
134         const u8        *txp = dout;
135         u8              *rxp = din;
136         u8              value;
137
138         if (bitlen == 0)
139                 /* Finish any previously submitted transfers */
140                 goto out;
141
142         /*
143          * TODO: The controller can do non-multiple-of-8 bit
144          * transfers, but this driver currently doesn't support it.
145          *
146          * It's also not clear how such transfers are supposed to be
147          * represented as a stream of bytes...this is a limitation of
148          * the current SPI interface.
149          */
150         if (bitlen % 8) {
151                 /* Errors always terminate an ongoing transfer */
152                 flags |= SPI_XFER_END;
153                 goto out;
154         }
155
156         len = bitlen / 8;
157
158         /*
159          * The controller can do automatic CS control, but it is
160          * somewhat quirky, and it doesn't really buy us much anyway
161          * in the context of U-Boot.
162          */
163         if (flags & SPI_XFER_BEGIN) {
164                 spi_cs_activate(slave);
165                 /*
166                  * sometimes the RDR is not empty when we get here,
167                  * in theory that should not happen, but it DOES happen.
168                  * Read it here to be on the safe side.
169                  * That also clears the OVRES flag. Required if the
170                  * following loop exits due to OVRES!
171                  */
172                 spi_readl(as, RDR);
173         }
174
175         for (len_tx = 0, len_rx = 0; len_rx < len; ) {
176                 status = spi_readl(as, SR);
177
178                 if (status & ATMEL_SPI_SR_OVRES)
179                         return -1;
180
181                 if (len_tx < len && (status & ATMEL_SPI_SR_TDRE)) {
182                         if (txp)
183                                 value = *txp++;
184                         else
185                                 value = 0;
186                         spi_writel(as, TDR, value);
187                         len_tx++;
188                 }
189                 if (status & ATMEL_SPI_SR_RDRF) {
190                         value = spi_readl(as, RDR);
191                         if (rxp)
192                                 *rxp++ = value;
193                         len_rx++;
194                 }
195         }
196
197 out:
198         if (flags & SPI_XFER_END) {
199                 /*
200                  * Wait until the transfer is completely done before
201                  * we deactivate CS.
202                  */
203                 do {
204                         status = spi_readl(as, SR);
205                 } while (!(status & ATMEL_SPI_SR_TXEMPTY));
206
207                 spi_cs_deactivate(slave);
208         }
209
210         return 0;
211 }