/* * $Id: saspi.c,v 1.5 2007/12/24 15:46:40 nbrk Exp $ */ #include #include #include #include #include #include /* #define SASPI_DEBUG */ #ifdef SASPI_DEBUG #define DPRINTF(x...) do { printf(x); } while (0) #else #define DPRINTF(x...) { } #endif /* * SPI driver. */ struct saspi_dd { struct spi_bus_handle sd_sbh; struct bus_handle *sd_bhp; }; int saspi_attach(struct device *, uint32_t, uint8_t); void saspi_init(struct saspi_dd *ddp); uint8_t saspi_transmit(void *selfdd, uint8_t data); void saspi_cs_low(void *selfdd); void saspi_cs_high(void *selfdd); struct driver saspi_dr = { sizeof(struct saspi_dd), saspi_attach, NULL, NULL }; int saspi_attach(struct device *self, uint32_t loc, uint8_t flags) { struct saspi_dd *ddp = self->dv_devdata; /* grab bus_handle */ ddp->sd_bhp = self->dv_parent->dv_aux; printf("SAM7 SPI: "); /* * XXX Check if card present and fail if it is not. */ /* 'Card Present' on PA15 */ bus_write_4(ddp->sd_bhp, (uint32_t)AT91C_PIOA_ODR, 1 << 15); bus_write_4(ddp->sd_bhp, (uint32_t)AT91C_PIOA_PER, 1 << 15); /* Write Protect' on PA16 */ bus_write_4(ddp->sd_bhp, (uint32_t)AT91C_PIOA_ODR, 1 << 16); bus_write_4(ddp->sd_bhp, (uint32_t)AT91C_PIOA_PER, 1 << 16); if((bus_read_4(ddp->sd_bhp, (uint32_t)AT91C_PIOA_PDSR) & 1 << 15) == 0) printf("card present; "); else { printf("card is not presented\n"); return(-1); } printf("write %s\n", (bus_read_4(ddp->sd_bhp, (uint32_t)AT91C_PIOA_PDSR) & 1 << 16) ? "protect" : "allowed"); /* * Initialize ourselfes and provide spi_bus_handle to children throught dv_aux. */ saspi_init(ddp); ddp->sd_sbh.sb_transmitfunc = saspi_transmit; ddp->sd_sbh.sb_cslowfunc = saspi_cs_low; ddp->sd_sbh.sb_cshighfunc = saspi_cs_high; ddp->sd_sbh.sb_dd = ddp; self->dv_aux = &ddp->sd_sbh; return(0); } void saspi_init(struct saspi_dd *ddp) { /* * Initialize on-chip SPI controller. */ /* * Disassociate SPI clock and data lines from PIO. * * PA11 - NPCS0 (we will drive this as gpio pin) * PA12 - MISO * PA13 - MOSI * PA14 - SPCK */ bus_write_4(ddp->sd_bhp, (uint32_t)AT91C_PIOA_PDR, 1 << 12 | 1 << 13 | 1 << 14); /* assign pins to Peripheral A */ bus_write_4(ddp->sd_bhp, (uint32_t)AT91C_PIOA_ASR, 1 << 12 | 1 << 13 | 1 << 14); /* * Configure NCPS0 (CS): * Enable PIO; Set high; Enable output. */ bus_write_4(ddp->sd_bhp, (uint32_t)AT91C_PIOA_PER, 1 << 11); bus_write_4(ddp->sd_bhp, (uint32_t)AT91C_PIOA_SODR, 1 << 11); bus_write_4(ddp->sd_bhp, (uint32_t)AT91C_PIOA_OER, 1 << 11); /* reset and enable SPI */ bus_write_4(ddp->sd_bhp, (uint32_t)AT91C_SPI_CR, AT91C_SPI_SPIEN | AT91C_SPI_SWRST); /* XXX just to be sure */ bus_write_4(ddp->sd_bhp, (uint32_t)AT91C_SPI_CR, AT91C_SPI_SPIEN); /* set SPI mode to master; disable decoding of Chip Select; PCS 1110 (using fixed CS line) */ bus_write_4(ddp->sd_bhp, (uint32_t)AT91C_SPI_MR, AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | 0x0e << 16); /* XXX 15|16 */ /* * Configure Chip Select Register no. 0 (so no offset from SPI_CSR). * CPOL (Clock Polarity) is 0 (SPCK inactive is logic 0); * NCPHA (Clock Phase) is 1; * 8 bits per transfer; * XXX SCBR=4a; */ bus_write_4(ddp->sd_bhp, (uint32_t)AT91C_SPI_CSR, AT91C_SPI_NCPHA | 0x4a00 ); /* enable PDC transfers to/from SPI */ bus_write_4(ddp->sd_bhp, (uint32_t)AT91C_SPI_PTCR, AT91C_PDC_TXTEN | AT91C_PDC_RXTEN); } uint8_t saspi_transmit(void *selfdd, uint8_t data) { struct saspi_dd *ddp = (struct saspi_dd *)selfdd; /* * Shift byte on the SPI bus. */ /* wait for Transmit Data Register Empty flag */ while((bus_read_4(ddp->sd_bhp, (uint32_t)AT91C_SPI_SR) & AT91C_SPI_TDRE) == 0) ; /* okay, send our byte */ bus_write_4(ddp->sd_bhp, (uint32_t)AT91C_SPI_TDR, 0x000000ff & data); DPRINTF("saspi_transmit: tx byte 0x%x\n", 0x000000ff & data); /* wait while Receive Register is full and read it */ while(((bus_read_4(ddp->sd_bhp, (uint32_t)AT91C_SPI_SR)) & AT91C_SPI_RDRF) == 0) ; data = bus_read_4(ddp->sd_bhp, (uint32_t)AT91C_SPI_RDR) & 0x000000ff; DPRINTF("saspi_transmit: rx byte 0x%x\n", data); return( data ); } void saspi_cs_high(void *selfdd) { struct saspi_dd *ddp = selfdd; bus_write_4(ddp->sd_bhp, (uint32_t)AT91C_PIOA_SODR, 1 << 11); } void saspi_cs_low(void *selfdd) { struct saspi_dd *ddp = selfdd; bus_write_4(ddp->sd_bhp, (uint32_t)AT91C_PIOA_CODR, 1 << 11); }