[BACK]Return to saspi.c CVS log [TXT][DIR] Up to [local] / funnyos / arch / sam7s64 / dev

File: [local] / funnyos / arch / sam7s64 / dev / saspi.c (download)

Revision 1.5, Mon Dec 24 15:46:40 2007 UTC (16 years, 4 months ago) by nbrk
Branch: MAIN
CVS Tags: HEAD
Changes since 1.4: +33 -15 lines

on attachment do not associate NCPS0 to Peripheral A (will drive it through PIO);
rework saspi_cs_{low,high}() to correctly toggle NCPS0 line via PIO;
add debug to sapio;
minor cleanups

/*
 * $Id: saspi.c,v 1.5 2007/12/24 15:46:40 nbrk Exp $
 */
#include <sys/types.h>
#include <sys/device.h>
#include <sys/bus.h>
#include <sys/bus_spi.h>

#include <libkern/printf.h>
#include <arch/sam7s64/dev/at91sam7.h>

/* #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);
}