1/*- 2 * Copyright (c) 2006 M. Warner Losh. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25#include <sys/cdefs.h>
| 1/*- 2 * Copyright (c) 2006 M. Warner Losh. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25#include <sys/cdefs.h>
|
26__FBSDID("$FreeBSD: head/sys/arm/at91/at91_spi.c 155324 2006-02-04 23:32:13Z imp $");
| 26__FBSDID("$FreeBSD: head/sys/arm/at91/at91_spi.c 160358 2006-07-14 21:35:59Z imp $");
|
27 28#include <sys/param.h> 29#include <sys/systm.h> 30#include <sys/bus.h> 31#include <sys/conf.h> 32#include <sys/kernel.h> 33#include <sys/lock.h> 34#include <sys/mbuf.h> 35#include <sys/malloc.h> 36#include <sys/module.h> 37#include <sys/mutex.h> 38#include <sys/rman.h> 39#include <machine/bus.h> 40 41#include <arm/at91/at91_spireg.h>
| 27 28#include <sys/param.h> 29#include <sys/systm.h> 30#include <sys/bus.h> 31#include <sys/conf.h> 32#include <sys/kernel.h> 33#include <sys/lock.h> 34#include <sys/mbuf.h> 35#include <sys/malloc.h> 36#include <sys/module.h> 37#include <sys/mutex.h> 38#include <sys/rman.h> 39#include <machine/bus.h> 40 41#include <arm/at91/at91_spireg.h>
|
42#include <arm/at91/at91_spiio.h>
| 42#include <arm/at91/at91_pdcreg.h>
|
43
| 43
|
| 44#include <dev/spibus/spi.h> 45#include "spibus_if.h" 46
|
44struct at91_spi_softc 45{ 46 device_t dev; /* Myself */ 47 void *intrhand; /* Interrupt handle */ 48 struct resource *irq_res; /* IRQ resource */ 49 struct resource *mem_res; /* Memory resource */ 50 struct mtx sc_mtx; /* basically a perimeter lock */
| 47struct at91_spi_softc 48{ 49 device_t dev; /* Myself */ 50 void *intrhand; /* Interrupt handle */ 51 struct resource *irq_res; /* IRQ resource */ 52 struct resource *mem_res; /* Memory resource */ 53 struct mtx sc_mtx; /* basically a perimeter lock */
|
51 int flags; 52#define XFER_PENDING 1 /* true when transfer taking place */ 53#define OPENED 2 /* Device opened */ 54#define RXRDY 4 55#define TXCOMP 8 56#define TXRDY 0x10 57 struct cdev *cdev;
| 54 bus_dma_tag_t dmatag; /* bus dma tag for mbufs */ 55 bus_dmamap_t map[4]; /* Maps for the transaction */
|
58}; 59 60static inline uint32_t 61RD4(struct at91_spi_softc *sc, bus_size_t off) 62{ 63 return bus_read_4(sc->mem_res, off); 64} 65 66static inline void 67WR4(struct at91_spi_softc *sc, bus_size_t off, uint32_t val) 68{ 69 bus_write_4(sc->mem_res, off, val); 70} 71 72#define AT91_SPI_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 73#define AT91_SPI_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 74#define AT91_SPI_LOCK_INIT(_sc) \ 75 mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ 76 "spi", MTX_DEF) 77#define AT91_SPI_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); 78#define AT91_SPI_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); 79#define AT91_SPI_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
| 56}; 57 58static inline uint32_t 59RD4(struct at91_spi_softc *sc, bus_size_t off) 60{ 61 return bus_read_4(sc->mem_res, off); 62} 63 64static inline void 65WR4(struct at91_spi_softc *sc, bus_size_t off, uint32_t val) 66{ 67 bus_write_4(sc->mem_res, off, val); 68} 69 70#define AT91_SPI_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 71#define AT91_SPI_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 72#define AT91_SPI_LOCK_INIT(_sc) \ 73 mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ 74 "spi", MTX_DEF) 75#define AT91_SPI_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); 76#define AT91_SPI_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); 77#define AT91_SPI_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
|
80#define CDEV2SOFTC(dev) ((dev)->si_drv1)
| |
81 82static devclass_t at91_spi_devclass; 83 84/* bus entry points */ 85 86static int at91_spi_probe(device_t dev); 87static int at91_spi_attach(device_t dev); 88static int at91_spi_detach(device_t dev);
| 78 79static devclass_t at91_spi_devclass; 80 81/* bus entry points */ 82 83static int at91_spi_probe(device_t dev); 84static int at91_spi_attach(device_t dev); 85static int at91_spi_detach(device_t dev);
|
89static void at91_spi_intr(void *);
| |
90 91/* helper routines */ 92static int at91_spi_activate(device_t dev); 93static void at91_spi_deactivate(device_t dev); 94
| 86 87/* helper routines */ 88static int at91_spi_activate(device_t dev); 89static void at91_spi_deactivate(device_t dev); 90
|
95/* cdev routines */ 96static d_open_t at91_spi_open; 97static d_close_t at91_spi_close; 98static d_ioctl_t at91_spi_ioctl; 99 100static struct cdevsw at91_spi_cdevsw = 101{ 102 .d_version = D_VERSION, 103 .d_open = at91_spi_open, 104 .d_close = at91_spi_close, 105 .d_ioctl = at91_spi_ioctl 106}; 107
| |
108static int 109at91_spi_probe(device_t dev) 110{ 111 device_set_desc(dev, "SPI"); 112 return (0); 113} 114 115static int 116at91_spi_attach(device_t dev) 117{ 118 struct at91_spi_softc *sc = device_get_softc(dev);
| 91static int 92at91_spi_probe(device_t dev) 93{ 94 device_set_desc(dev, "SPI"); 95 return (0); 96} 97 98static int 99at91_spi_attach(device_t dev) 100{ 101 struct at91_spi_softc *sc = device_get_softc(dev);
|
119 int err;
| 102 int err, i;
|
120 121 sc->dev = dev; 122 err = at91_spi_activate(dev); 123 if (err) 124 goto out; 125 126 AT91_SPI_LOCK_INIT(sc); 127 128 /*
| 103 104 sc->dev = dev; 105 err = at91_spi_activate(dev); 106 if (err) 107 goto out; 108 109 AT91_SPI_LOCK_INIT(sc); 110 111 /*
|
129 * Activate the interrupt
| 112 * Allocate DMA tags and maps
|
130 */
| 113 */
|
131 err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, 132 at91_spi_intr, sc, &sc->intrhand); 133 if (err) { 134 AT91_SPI_LOCK_DESTROY(sc);
| 114 err = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT, 115 BUS_SPACE_MAXADDR, NULL, NULL, 2058, 1, 2048, BUS_DMA_ALLOCNOW, 116 NULL, NULL, &sc->dmatag); 117 if (err != 0)
|
135 goto out;
| 118 goto out;
|
| 119 for (i = 0; i < 4; i++) { 120 err = bus_dmamap_create(sc->dmatag, 0, &sc->map[i]); 121 if (err != 0) 122 goto out;
|
136 }
| 123 }
|
137 sc->cdev = make_dev(&at91_spi_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, 138 "spi%d", device_get_unit(dev)); 139 if (sc->cdev == NULL) { 140 err = ENOMEM; 141 goto out; 142 } 143 sc->cdev->si_drv1 = sc; 144#if 0 145 /* init */ 146 sc->cwgr = SPI_CWGR_CKDIV(1) | 147 SPI_CWGR_CHDIV(SPI_CWGR_DIV(SPI_DEF_CLK)) | 148 SPI_CWGR_CLDIV(SPI_CWGR_DIV(SPI_DEF_CLK));
| |
149
| 124
|
| 125 // reset the SPI
|
150 WR4(sc, SPI_CR, SPI_CR_SWRST);
| 126 WR4(sc, SPI_CR, SPI_CR_SWRST);
|
151 WR4(sc, SPI_CR, SPI_CR_MSEN | SPI_CR_SVDIS); 152 WR4(sc, SPI_CWGR, sc->cwgr); 153#endif
| 127 128 WR4(sc, SPI_MR, (0xf << 24) | SPI_MR_MSTR | SPI_MR_MODFDIS | 129 (0xE << 16)); 130 131 WR4(sc, SPI_CSR0, SPI_CSR_CPOL | (4 << 16) | (2 << 8)); 132 WR4(sc, SPI_CR, SPI_CR_SPIEN); 133 134 WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS); 135 WR4(sc, PDC_PTCR, PDC_PTCR_RXTDIS); 136 WR4(sc, PDC_RNPR, 0); 137 WR4(sc, PDC_RNCR, 0); 138 WR4(sc, PDC_TNPR, 0); 139 WR4(sc, PDC_TNCR, 0); 140 WR4(sc, PDC_RPR, 0); 141 WR4(sc, PDC_RCR, 0); 142 WR4(sc, PDC_TPR, 0); 143 WR4(sc, PDC_TCR, 0); 144 WR4(sc, PDC_PTCR, PDC_PTCR_RXTEN); 145 WR4(sc, PDC_PTCR, PDC_PTCR_TXTEN); 146 RD4(sc, SPI_RDR); 147 RD4(sc, SPI_SR); 148 149 device_add_child(dev, "spibus", -1); 150 bus_generic_attach(dev);
|
154out:; 155 if (err) 156 at91_spi_deactivate(dev); 157 return (err); 158} 159 160static int 161at91_spi_detach(device_t dev) 162{ 163 return (EBUSY); /* XXX */ 164} 165 166static int 167at91_spi_activate(device_t dev) 168{ 169 struct at91_spi_softc *sc; 170 int rid; 171 172 sc = device_get_softc(dev); 173 rid = 0; 174 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 175 RF_ACTIVE); 176 if (sc->mem_res == NULL) 177 goto errout; 178 rid = 0; 179 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 180 RF_ACTIVE); 181 if (sc->mem_res == NULL) 182 goto errout; 183 return (0); 184errout: 185 at91_spi_deactivate(dev); 186 return (ENOMEM); 187} 188 189static void 190at91_spi_deactivate(device_t dev) 191{ 192 struct at91_spi_softc *sc; 193 194 sc = device_get_softc(dev); 195 if (sc->intrhand) 196 bus_teardown_intr(dev, sc->irq_res, sc->intrhand); 197 sc->intrhand = 0; 198 bus_generic_detach(sc->dev); 199 if (sc->mem_res) 200 bus_release_resource(dev, SYS_RES_IOPORT, 201 rman_get_rid(sc->mem_res), sc->mem_res); 202 sc->mem_res = 0; 203 if (sc->irq_res) 204 bus_release_resource(dev, SYS_RES_IRQ, 205 rman_get_rid(sc->irq_res), sc->irq_res); 206 sc->irq_res = 0; 207 return; 208} 209 210static void
| 151out:; 152 if (err) 153 at91_spi_deactivate(dev); 154 return (err); 155} 156 157static int 158at91_spi_detach(device_t dev) 159{ 160 return (EBUSY); /* XXX */ 161} 162 163static int 164at91_spi_activate(device_t dev) 165{ 166 struct at91_spi_softc *sc; 167 int rid; 168 169 sc = device_get_softc(dev); 170 rid = 0; 171 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 172 RF_ACTIVE); 173 if (sc->mem_res == NULL) 174 goto errout; 175 rid = 0; 176 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 177 RF_ACTIVE); 178 if (sc->mem_res == NULL) 179 goto errout; 180 return (0); 181errout: 182 at91_spi_deactivate(dev); 183 return (ENOMEM); 184} 185 186static void 187at91_spi_deactivate(device_t dev) 188{ 189 struct at91_spi_softc *sc; 190 191 sc = device_get_softc(dev); 192 if (sc->intrhand) 193 bus_teardown_intr(dev, sc->irq_res, sc->intrhand); 194 sc->intrhand = 0; 195 bus_generic_detach(sc->dev); 196 if (sc->mem_res) 197 bus_release_resource(dev, SYS_RES_IOPORT, 198 rman_get_rid(sc->mem_res), sc->mem_res); 199 sc->mem_res = 0; 200 if (sc->irq_res) 201 bus_release_resource(dev, SYS_RES_IRQ, 202 rman_get_rid(sc->irq_res), sc->irq_res); 203 sc->irq_res = 0; 204 return; 205} 206 207static void
|
211at91_spi_intr(void *xsc)
| 208at91_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
|
212{
| 209{
|
213 struct at91_spi_softc *sc = xsc; 214#if 0 215 uint32_t status; 216 217 /* Reading the status also clears the interrupt */ 218 status = RD4(sc, SPI_SR); 219 if (status == 0)
| 210 if (error != 0)
|
220 return;
| 211 return;
|
221 AT91_SPI_LOCK(sc); 222 if (status & SPI_SR_RXRDY) 223 sc->flags |= RXRDY; 224 if (status & SPI_SR_TXCOMP) 225 sc->flags |= TXCOMP; 226 if (status & SPI_SR_TXRDY) 227 sc->flags |= TXRDY; 228 AT91_SPI_UNLOCK(sc); 229#endif 230 wakeup(sc); 231 return;
| 212 *(bus_addr_t *)arg = segs[0].ds_addr;
|
232} 233
| 213} 214
|
234static int 235at91_spi_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 236{ 237 struct at91_spi_softc *sc; 238 239 sc = CDEV2SOFTC(dev); 240 AT91_SPI_LOCK(sc); 241 if (!(sc->flags & OPENED)) { 242 sc->flags |= OPENED; 243#if 0 244 WR4(sc, SPI_IER, SPI_SR_TXCOMP | SPI_SR_RXRDY | SPI_SR_TXRDY | 245 SPI_SR_OVRE | SPI_SR_UNRE | SPI_SR_NACK); 246#endif 247 } 248 AT91_SPI_UNLOCK(sc); 249 return (0); 250} 251
| |
252static int
| 215static int
|
253at91_spi_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
| 216at91_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
|
254{ 255 struct at91_spi_softc *sc;
| 217{ 218 struct at91_spi_softc *sc;
|
| 219 int i; 220 bus_addr_t addr;
|
256
| 221
|
257 sc = CDEV2SOFTC(dev); 258 AT91_SPI_LOCK(sc); 259 sc->flags &= ~OPENED; 260#if 0 261 WR4(sc, SPI_IDR, SPI_SR_TXCOMP | SPI_SR_RXRDY | SPI_SR_TXRDY | 262 SPI_SR_OVRE | SPI_SR_UNRE | SPI_SR_NACK); 263#endif 264 AT91_SPI_UNLOCK(sc); 265 return (0); 266}
| 222 sc = device_get_softc(dev); 223 WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS); 224 i = 0; 225 if (bus_dmamap_load(sc->dmatag, sc->map[i], cmd->tx_cmd, 226 cmd->tx_cmd_sz, at91_getaddr, &addr, 0) != 0) 227 goto out; 228 WR4(sc, PDC_TPR, addr); 229 WR4(sc, PDC_TCR, cmd->tx_cmd_sz); 230 bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREWRITE); 231 i++; 232 if (bus_dmamap_load(sc->dmatag, sc->map[i], cmd->tx_data, 233 cmd->tx_data_sz, at91_getaddr, &addr, 0) != 0) 234 goto out; 235 WR4(sc, PDC_TNPR, addr); 236 WR4(sc, PDC_TNCR, cmd->tx_cmd_sz); 237 bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREWRITE); 238 i++; 239 if (bus_dmamap_load(sc->dmatag, sc->map[i], cmd->rx_cmd, 240 cmd->tx_cmd_sz, at91_getaddr, &addr, 0) != 0) 241 goto out; 242 WR4(sc, PDC_RPR, addr); 243 WR4(sc, PDC_RCR, cmd->tx_cmd_sz); 244 bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREREAD); 245 i++; 246 if (bus_dmamap_load(sc->dmatag, sc->map[i], cmd->rx_data, 247 cmd->tx_data_sz, at91_getaddr, &addr, 0) != 0) 248 goto out; 249 WR4(sc, PDC_RNPR, addr); 250 WR4(sc, PDC_RNCR, cmd->tx_data_sz); 251 bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREREAD);
|
267
| 252
|
268static int 269at91_spi_read_master(struct at91_spi_softc *sc, struct at91_spi_io *xfr) 270{ 271#if 1 272 return ENOTTY; 273#else 274 uint8_t *walker; 275 uint8_t buffer[256]; 276 size_t len; 277 int err = 0;
| 253 WR4(sc, PDC_PTCR, PDC_PTCR_TXTEN | PDC_PTCR_RXTEN);
|
278
| 254
|
279 if (xfr->xfer_len > sizeof(buffer)) 280 return (EINVAL); 281 walker = buffer; 282 len = xfr->xfer_len; 283 RD4(sc, SPI_RHR); 284 // Master mode, with the right address and interal addr size 285 WR4(sc, SPI_MMR, SPI_MMR_IADRSZ(xfr->iadrsz) | SPI_MMR_MREAD | 286 SPI_MMR_DADR(xfr->dadr)); 287 WR4(sc, SPI_IADR, xfr->iadr); 288 WR4(sc, SPI_CR, SPI_CR_START); 289 while (len-- > 1) { 290 while (!(sc->flags & RXRDY)) { 291 err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH, "spird", 292 0); 293 if (err) 294 return (err); 295 } 296 sc->flags &= ~RXRDY; 297 *walker++ = RD4(sc, SPI_RHR) & 0xff; 298 } 299 WR4(sc, SPI_CR, SPI_CR_STOP); 300 while (!(sc->flags & TXCOMP)) { 301 err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH, "spird2", 0); 302 if (err) 303 return (err); 304 } 305 sc->flags &= ~TXCOMP; 306 *walker = RD4(sc, SPI_RHR) & 0xff; 307 if (xfr->xfer_buf) { 308 AT91_SPI_UNLOCK(sc); 309 err = copyout(buffer, xfr->xfer_buf, xfr->xfer_len); 310 AT91_SPI_LOCK(sc); 311 } 312 return (err); 313#endif 314}
| 255 // wait for completion 256 // XXX should be done as an ISR of some sort. 257 while (RD4(sc, SPI_SR) & SPI_SR_ENDRX) 258 DELAY(700);
|
315
| 259
|
316static int 317at91_spi_write_master(struct at91_spi_softc *sc, struct at91_spi_io *xfr) 318{ 319#if 1 320 return ENOTTY; 321#else 322 uint8_t *walker; 323 uint8_t buffer[256]; 324 size_t len; 325 int err; 326 327 if (xfr->xfer_len > sizeof(buffer)) 328 return (EINVAL); 329 walker = buffer; 330 len = xfr->xfer_len; 331 AT91_SPI_UNLOCK(sc); 332 err = copyin(xfr->xfer_buf, buffer, xfr->xfer_len); 333 AT91_SPI_LOCK(sc); 334 if (err) 335 return (err); 336 /* Setup the xfr for later readback */ 337 xfr->xfer_buf = 0; 338 xfr->xfer_len = 1; 339 while (len--) { 340 WR4(sc, SPI_MMR, SPI_MMR_IADRSZ(xfr->iadrsz) | SPI_MMR_MWRITE | 341 SPI_MMR_DADR(xfr->dadr)); 342 WR4(sc, SPI_IADR, xfr->iadr++); 343 WR4(sc, SPI_THR, *walker++); 344 WR4(sc, SPI_CR, SPI_CR_START); 345 /* 346 * If we get signal while waiting for TXRDY, make sure we 347 * try to stop this device 348 */ 349 while (!(sc->flags & TXRDY)) { 350 err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH, "spiwr", 351 0); 352 if (err) 353 break; 354 } 355 WR4(sc, SPI_CR, SPI_CR_STOP); 356 if (err) 357 return (err); 358 while (!(sc->flags & TXCOMP)) { 359 err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH, "spiwr2", 360 0); 361 if (err) 362 return (err); 363 } 364 /* Readback */ 365 at91_spi_read_master(sc, xfr); 366 } 367 return (err); 368#endif
| 260 // Sync the buffers after the DMA is done, and unload them. 261 bus_dmamap_sync(sc->dmatag, sc->map[0], BUS_DMASYNC_POSTWRITE); 262 bus_dmamap_sync(sc->dmatag, sc->map[1], BUS_DMASYNC_POSTWRITE); 263 bus_dmamap_sync(sc->dmatag, sc->map[2], BUS_DMASYNC_POSTREAD); 264 bus_dmamap_sync(sc->dmatag, sc->map[3], BUS_DMASYNC_POSTREAD); 265 for (i = 0; i < 4; i++) 266 bus_dmamap_unload(sc->dmatag, sc->map[i]); 267 return (0); 268out:; 269 while (i-- > 0) 270 bus_dmamap_unload(sc->dmatag, sc->map[i]); 271 return (EIO);
|
369} 370
| 272} 273
|
371static int 372at91_spi_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, 373 struct thread *td) 374{ 375 int err = 0; 376 struct at91_spi_softc *sc; 377 378 sc = CDEV2SOFTC(dev); 379 AT91_SPI_LOCK(sc); 380 while (sc->flags & XFER_PENDING) { 381 err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH, 382 "spiwait", 0); 383 if (err) { 384 AT91_SPI_UNLOCK(sc); 385 return (err); 386 } 387 } 388 sc->flags |= XFER_PENDING; 389 390 switch (cmd) 391 { 392 case SPIIOCXFER: 393 { 394 struct at91_spi_io *xfr = (struct at91_spi_io *)data; 395 switch (xfr->type) 396 { 397 case SPI_IO_READ_MASTER: 398 err = at91_spi_read_master(sc, xfr); 399 break; 400 case SPI_IO_WRITE_MASTER: 401 err = at91_spi_write_master(sc, xfr); 402 break; 403 default: 404 err = EINVAL; 405 break; 406 } 407 break; 408 } 409 410 case SPIIOCSETCLOCK: 411 { 412#if 0 413 struct at91_spi_clock *spick = (struct at91_spi_clock *)data; 414 415 sc->cwgr = SPI_CWGR_CKDIV(spick->ckdiv) | 416 SPI_CWGR_CHDIV(SPI_CWGR_DIV(spick->high_rate)) | 417 SPI_CWGR_CLDIV(SPI_CWGR_DIV(spick->low_rate)); 418 WR4(sc, SPI_CR, SPI_CR_SWRST); 419 WR4(sc, SPI_CR, SPI_CR_MSEN | SPI_CR_SVDIS); 420 WR4(sc, SPI_CWGR, sc->cwgr); 421#else 422 err = ENOTTY; 423#endif 424 break; 425 } 426 default: 427 err = ENOTTY; 428 break; 429 } 430 sc->flags &= ~XFER_PENDING; 431 AT91_SPI_UNLOCK(sc); 432 wakeup(sc); 433 return err; 434} 435
| |
436static device_method_t at91_spi_methods[] = { 437 /* Device interface */ 438 DEVMETHOD(device_probe, at91_spi_probe), 439 DEVMETHOD(device_attach, at91_spi_attach), 440 DEVMETHOD(device_detach, at91_spi_detach), 441
| 274static device_method_t at91_spi_methods[] = { 275 /* Device interface */ 276 DEVMETHOD(device_probe, at91_spi_probe), 277 DEVMETHOD(device_attach, at91_spi_attach), 278 DEVMETHOD(device_detach, at91_spi_detach), 279
|
| 280 /* spibus interface */ 281 DEVMETHOD(spibus_transfer, at91_spi_transfer),
|
442 { 0, 0 } 443}; 444 445static driver_t at91_spi_driver = { 446 "at91_spi", 447 at91_spi_methods, 448 sizeof(struct at91_spi_softc), 449}; 450 451DRIVER_MODULE(at91_spi, atmelarm, at91_spi_driver, at91_spi_devclass, 0, 0);
| 282 { 0, 0 } 283}; 284 285static driver_t at91_spi_driver = { 286 "at91_spi", 287 at91_spi_methods, 288 sizeof(struct at91_spi_softc), 289}; 290 291DRIVER_MODULE(at91_spi, atmelarm, at91_spi_driver, at91_spi_devclass, 0, 0);
|