]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/atheros/ar71xx_spi.c
ident(1): Normalizing date format
[FreeBSD/FreeBSD.git] / sys / mips / atheros / ar71xx_spi.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice unmodified, this list of conditions, and the following
12  *    disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35
36 #include <sys/bus.h>
37 #include <sys/interrupt.h>
38 #include <sys/malloc.h>
39 #include <sys/kernel.h>
40 #include <sys/module.h>
41 #include <sys/rman.h>
42
43 #include <vm/vm.h>
44 #include <vm/pmap.h>
45 #include <vm/vm_extern.h>
46
47 #include <machine/bus.h>
48 #include <machine/cpu.h>
49
50 #include <dev/spibus/spi.h>
51 #include <dev/spibus/spibusvar.h>
52 #include "spibus_if.h"
53
54 #include <mips/atheros/ar71xxreg.h>
55
56 #undef AR71XX_SPI_DEBUG
57 #ifdef AR71XX_SPI_DEBUG
58 #define dprintf printf
59 #else
60 #define dprintf(x, arg...)
61 #endif
62
63 /*
64  * register space access macros
65  */
66
67 #define SPI_BARRIER_WRITE(sc)           bus_barrier((sc)->sc_mem_res, 0, 0,     \
68                                             BUS_SPACE_BARRIER_WRITE)
69 #define SPI_BARRIER_READ(sc)    bus_barrier((sc)->sc_mem_res, 0, 0,     \
70                                             BUS_SPACE_BARRIER_READ)
71 #define SPI_BARRIER_RW(sc)              bus_barrier((sc)->sc_mem_res, 0, 0,     \
72                                             BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)
73
74 #define SPI_WRITE(sc, reg, val) do {                            \
75                 bus_write_4(sc->sc_mem_res, (reg), (val));      \
76         } while (0)
77
78 #define SPI_READ(sc, reg)        bus_read_4(sc->sc_mem_res, (reg))
79
80 #define SPI_SET_BITS(sc, reg, bits)     \
81         SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) | (bits))
82
83 #define SPI_CLEAR_BITS(sc, reg, bits)   \
84         SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) & ~(bits))
85
86 struct ar71xx_spi_softc {
87         device_t                sc_dev;
88         struct resource         *sc_mem_res;
89         uint32_t                sc_reg_ctrl;
90 };
91
92 static int
93 ar71xx_spi_probe(device_t dev)
94 {
95         device_set_desc(dev, "AR71XX SPI");
96         return (BUS_PROBE_NOWILDCARD);
97 }
98
99 static int
100 ar71xx_spi_attach(device_t dev)
101 {
102         struct ar71xx_spi_softc *sc = device_get_softc(dev);
103         int rid;
104
105         sc->sc_dev = dev;
106         rid = 0;
107         sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 
108             RF_ACTIVE);
109         if (!sc->sc_mem_res) {
110                 device_printf(dev, "Could not map memory\n");
111                 return (ENXIO);
112         }
113
114         SPI_WRITE(sc, AR71XX_SPI_FS, 1);
115
116         /* Flush out read before reading the control register */
117         SPI_BARRIER_WRITE(sc);
118
119         sc->sc_reg_ctrl  = SPI_READ(sc, AR71XX_SPI_CTRL);
120
121         /*
122          * XXX TODO: document what the SPI control register does.
123          */
124         SPI_WRITE(sc, AR71XX_SPI_CTRL, 0x43);
125
126         /*
127          * Ensure the config register write has gone out before configuring
128          * the chip select mask.
129          */
130         SPI_BARRIER_WRITE(sc);
131         SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, SPI_IO_CTRL_CSMASK);
132
133         /*
134          * .. and ensure the write has gone out before continuing.
135          */
136         SPI_BARRIER_WRITE(sc);
137
138         device_add_child(dev, "spibus", -1);
139         return (bus_generic_attach(dev));
140 }
141
142 static void
143 ar71xx_spi_chip_activate(struct ar71xx_spi_softc *sc, int cs)
144 {
145         uint32_t ioctrl = SPI_IO_CTRL_CSMASK;
146         /*
147          * Put respective CSx to low
148          */
149         ioctrl &= ~(SPI_IO_CTRL_CS0 << cs);
150
151         /*
152          * Make sure any other writes have gone out to the
153          * device before changing the chip select line;
154          * then ensure that it has made it out to the device
155          * before continuing.
156          */
157         SPI_BARRIER_WRITE(sc);
158         SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, ioctrl);
159         SPI_BARRIER_WRITE(sc);
160 }
161
162 static void
163 ar71xx_spi_chip_deactivate(struct ar71xx_spi_softc *sc, int cs)
164 {
165         /*
166          * Put all CSx to high
167          */
168         SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, SPI_IO_CTRL_CSMASK);
169 }
170
171 static uint8_t
172 ar71xx_spi_txrx(struct ar71xx_spi_softc *sc, int cs, uint8_t data)
173 {
174         int bit;
175         /* CS0 */
176         uint32_t ioctrl = SPI_IO_CTRL_CSMASK;
177         /*
178          * low-level for selected CS
179          */
180         ioctrl &= ~(SPI_IO_CTRL_CS0 << cs);
181
182         uint32_t iod, rds;
183         for (bit = 7; bit >=0; bit--) {
184                 if (data & (1 << bit))
185                         iod = ioctrl | SPI_IO_CTRL_DO;
186                 else
187                         iod = ioctrl & ~SPI_IO_CTRL_DO;
188                 SPI_BARRIER_WRITE(sc);
189                 SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, iod);
190                 SPI_BARRIER_WRITE(sc);
191                 SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, iod | SPI_IO_CTRL_CLK);
192         }
193
194         /*
195          * Provide falling edge for connected device by clear clock bit.
196          */
197         SPI_BARRIER_WRITE(sc);
198         SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, iod);
199         SPI_BARRIER_WRITE(sc);
200         rds = SPI_READ(sc, AR71XX_SPI_RDS);
201
202         return (rds & 0xff);
203 }
204
205 static int
206 ar71xx_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
207 {
208         struct ar71xx_spi_softc *sc;
209         uint32_t cs;
210         uint8_t *buf_in, *buf_out;
211         int i;
212
213         sc = device_get_softc(dev);
214
215         spibus_get_cs(child, &cs);
216
217         cs &= ~SPIBUS_CS_HIGH;
218
219         ar71xx_spi_chip_activate(sc, cs);
220
221         KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz, 
222             ("TX/RX command sizes should be equal"));
223         KASSERT(cmd->tx_data_sz == cmd->rx_data_sz, 
224             ("TX/RX data sizes should be equal"));
225
226         /*
227          * Transfer command
228          */
229         buf_out = (uint8_t *)cmd->tx_cmd;
230         buf_in = (uint8_t *)cmd->rx_cmd;
231         for (i = 0; i < cmd->tx_cmd_sz; i++)
232                 buf_in[i] = ar71xx_spi_txrx(sc, cs, buf_out[i]);
233
234         /*
235          * Receive/transmit data (depends on  command)
236          */
237         buf_out = (uint8_t *)cmd->tx_data;
238         buf_in = (uint8_t *)cmd->rx_data;
239         for (i = 0; i < cmd->tx_data_sz; i++)
240                 buf_in[i] = ar71xx_spi_txrx(sc, cs, buf_out[i]);
241
242         ar71xx_spi_chip_deactivate(sc, cs);
243
244         return (0);
245 }
246
247 static int
248 ar71xx_spi_detach(device_t dev)
249 {
250         struct ar71xx_spi_softc *sc = device_get_softc(dev);
251
252         /*
253          * Ensure any other writes to the device are finished
254          * before we tear down the SPI device.
255          */
256         SPI_BARRIER_WRITE(sc);
257
258         /*
259          * Restore the control register; ensure it has hit the
260          * hardware before continuing.
261          */
262         SPI_WRITE(sc, AR71XX_SPI_CTRL, sc->sc_reg_ctrl);
263         SPI_BARRIER_WRITE(sc);
264
265         /*
266          * And now, put the flash back into mapped IO mode and
267          * ensure _that_ has completed before we finish up.
268          */
269         SPI_WRITE(sc, AR71XX_SPI_FS, 0);
270         SPI_BARRIER_WRITE(sc);
271
272         if (sc->sc_mem_res)
273                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
274
275         return (0);
276 }
277
278 static device_method_t ar71xx_spi_methods[] = {
279         /* Device interface */
280         DEVMETHOD(device_probe,         ar71xx_spi_probe),
281         DEVMETHOD(device_attach,        ar71xx_spi_attach),
282         DEVMETHOD(device_detach,        ar71xx_spi_detach),
283
284         DEVMETHOD(spibus_transfer,      ar71xx_spi_transfer),
285         {0, 0}
286 };
287
288 static driver_t ar71xx_spi_driver = {
289         "spi",
290         ar71xx_spi_methods,
291         sizeof(struct ar71xx_spi_softc),
292 };
293
294 static devclass_t ar71xx_spi_devclass;
295
296 DRIVER_MODULE(ar71xx_spi, nexus, ar71xx_spi_driver, ar71xx_spi_devclass, 0, 0);