static void cs_activate(struct atmel_spi *as, struct spi_device *spi) { unsigned gpio = (unsigned) spi->controller_data; unsigned active = spi->mode & SPI_CS_HIGH; u32 mr; int i; u32 csr; u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0; /* Make sure clock polarity is correct */ for (i = 0; i < spi->master->num_chipselect; i++) { csr = spi_readl(as, CSR0 + 4 * i); if ((csr ^ cpol) & SPI_BIT(CPOL)) spi_writel(as, CSR0 + 4 * i, csr ^ SPI_BIT(CPOL)); } mr = spi_readl(as, MR); mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr); dev_dbg(&spi->dev, "activate %u%s, mr %08x\n", gpio, active ? " (high)" : "", mr); if (!(cpu_is_at91rm9200() && spi->chip_select == 0)) gpio_set_value(gpio, active); spi_writel(as, MR, mr); }
static void cs_activate(struct atmel_spi *as, struct spi_device *spi) { struct atmel_spi_device *asd = spi->controller_state; unsigned active = spi->mode & SPI_CS_HIGH; u32 mr; if (atmel_spi_is_v2(as)) { spi_writel(as, CSR0 + 4 * spi->chip_select, asd->csr); /* For the low SPI version, there is a issue that PDC transfer * on CS1,2,3 needs SPI_CSR0.BITS config as SPI_CSR1,2,3.BITS */ spi_writel(as, CSR0, asd->csr); if (as->caps.has_wdrbt) { spi_writel(as, MR, SPI_BF(PCS, ~(0x01 << spi->chip_select)) | SPI_BIT(WDRBT) | SPI_BIT(MODFDIS) | SPI_BIT(MSTR)); } else { spi_writel(as, MR, SPI_BF(PCS, ~(0x01 << spi->chip_select)) | SPI_BIT(MODFDIS) | SPI_BIT(MSTR)); } mr = spi_readl(as, MR); if (as->use_cs_gpios) gpio_set_value(asd->npcs_pin, active); } else { u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0; int i; u32 csr; /* Make sure clock polarity is correct */ for (i = 0; i < spi->master->num_chipselect; i++) { csr = spi_readl(as, CSR0 + 4 * i); if ((csr ^ cpol) & SPI_BIT(CPOL)) spi_writel(as, CSR0 + 4 * i, csr ^ SPI_BIT(CPOL)); } mr = spi_readl(as, MR); mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr); if (as->use_cs_gpios && spi->chip_select != 0) gpio_set_value(asd->npcs_pin, active); spi_writel(as, MR, mr); } dev_dbg(&spi->dev, "activate %u%s, mr %08x\n", asd->npcs_pin, active ? " (high)" : "", mr); }
static int spi_has_wdrbt(struct atmel_spi_slave *slave) { unsigned int ver; ver = spi_readl(slave, VERSION); return (ATMEL_SPI_VERSION_REV(ver) >= 0x210); }
static void cs_activate(struct atmel_spi *as, struct spi_device *spi) { struct atmel_spi_device *asd = spi->controller_state; unsigned active = spi->mode & SPI_CS_HIGH; u32 mr; if (atmel_spi_is_v2()) { /* * Always use CSR0. This ensures that the clock * switches to the correct idle polarity before we * toggle the CS. */ spi_writel(as, CSR0, asd->csr); spi_writel(as, MR, SPI_BF(PCS, 0x0e) | SPI_BIT(MODFDIS) | SPI_BIT(MSTR)); mr = spi_readl(as, MR); gpio_set_value(asd->npcs_pin, active); } else { u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0; int i; u32 csr; /* Make sure clock polarity is correct */ for (i = 0; i < spi->master->num_chipselect; i++) { csr = spi_readl(as, CSR0 + 4 * i); if ((csr ^ cpol) & SPI_BIT(CPOL)) spi_writel(as, CSR0 + 4 * i, csr ^ SPI_BIT(CPOL)); } mr = spi_readl(as, MR); mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr); if (spi->chip_select != 0) gpio_set_value(asd->npcs_pin, active); spi_writel(as, MR, mr); } dev_dbg(&spi->dev, "activate %u%s, mr %08x\n", asd->npcs_pin, active ? " (high)" : "", mr); }
static void cs_activate(struct atmel_spi *as, struct spi_device *spi) { unsigned gpio = (unsigned) spi->controller_data; unsigned active = spi->mode & SPI_CS_HIGH; u32 mr; mr = spi_readl(as, MR); mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr); dev_dbg(&spi->dev, "activate %u%s, mr %08x\n", gpio, active ? " (high)" : "", mr); if (!(cpu_is_at91rm9200() && spi->chip_select == 0)) gpio_set_value(gpio, active); spi_writel(as, MR, mr); }
static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) { struct atmel_spi_device *asd = spi->controller_state; unsigned active = spi->mode & SPI_CS_HIGH; u32 mr; /* only deactivate *this* device; sometimes transfers to * another device may be active when this routine is called. */ mr = spi_readl(as, MR); if (~SPI_BFEXT(PCS, mr) & (1 << spi->chip_select)) { mr = SPI_BFINS(PCS, 0xf, mr); spi_writel(as, MR, mr); } dev_dbg(&spi->dev, "DEactivate %u%s, mr %08x\n", asd->npcs_pin, active ? " (low)" : "", mr); if (atmel_spi_is_v2() || spi->chip_select != 0) gpio_set_value(asd->npcs_pin, !active); }
static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) { unsigned gpio = (unsigned) spi->controller_data; unsigned active = spi->mode & SPI_CS_HIGH; u32 mr; /* only deactivate *this* device; sometimes transfers to * another device may be active when this routine is called. */ mr = spi_readl(as, MR); if (~SPI_BFEXT(PCS, mr) & (1 << spi->chip_select)) { mr = SPI_BFINS(PCS, 0xf, mr); spi_writel(as, MR, mr); } dev_dbg(&spi->dev, "DEactivate %u%s, mr %08x\n", gpio, active ? " (low)" : "", mr); if (!(cpu_is_at91rm9200() && spi->chip_select == 0)) gpio_set_value(gpio, !active); }
int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { struct atmel_spi_slave *as = to_atmel_spi(slave); unsigned int len_tx; unsigned int len_rx; unsigned int len; u32 status; const u8 *txp = dout; u8 *rxp = din; u8 value; if (bitlen == 0) /* Finish any previously submitted transfers */ goto out; /* * TODO: The controller can do non-multiple-of-8 bit * transfers, but this driver currently doesn't support it. * * It's also not clear how such transfers are supposed to be * represented as a stream of bytes...this is a limitation of * the current SPI interface. */ if (bitlen % 8) { /* Errors always terminate an ongoing transfer */ flags |= SPI_XFER_END; goto out; } len = bitlen / 8; /* * The controller can do automatic CS control, but it is * somewhat quirky, and it doesn't really buy us much anyway * in the context of U-Boot. */ if (flags & SPI_XFER_BEGIN) { spi_cs_activate(slave); /* * sometimes the RDR is not empty when we get here, * in theory that should not happen, but it DOES happen. * Read it here to be on the safe side. * That also clears the OVRES flag. Required if the * following loop exits due to OVRES! */ spi_readl(as, RDR); } for (len_tx = 0, len_rx = 0; len_rx < len; ) { status = spi_readl(as, SR); if (status & ATMEL_SPI_SR_OVRES) return -1; if (len_tx < len && (status & ATMEL_SPI_SR_TDRE)) { if (txp) value = *txp++; else value = 0; spi_writel(as, TDR, value); len_tx++; } if (status & ATMEL_SPI_SR_RDRF) { value = spi_readl(as, RDR); if (rxp) *rxp++ = value; len_rx++; } } out: if (flags & SPI_XFER_END) { /* * Wait until the transfer is completely done before * we deactivate CS. */ do { status = spi_readl(as, SR); } while (!(status & ATMEL_SPI_SR_TXEMPTY)); spi_cs_deactivate(slave); } return 0; }
int spi_xfer(unsigned int len, const void *dout, void *din, unsigned long flags) { unsigned int len_tx; unsigned int len_rx; const unsigned char *txp = dout; unsigned char *rxp = din; unsigned int status; unsigned char value; if (len == 0) goto out; /* * The controller can do automatic CS control, but it is * somewhat quirky, and it doesn't really buy us much anyway * in the context of U-Boot. */ if (flags & SPI_XFER_BEGIN) { spi_cs_activate(); /* * sometimes the RDR is not empty when we get here, * in theory that should not happen, but it DOES happen. * Read it here to be on the safe side. * That also clears the OVRES flag. Required if the * following loop exits due to OVRES! */ spi_readl(SPI_RDR); spi_readl(SPI_SR); } for (len_tx = 0, len_rx = 0; len_rx < len; ) { /* send data */ if (len_tx < len) { do { status = spi_readl(SPI_SR); } while ((status & AT91C_SPI_TDRE) == 0); if (txp) value = *txp++; else value = 0; spi_writel(SPI_TDR, value); len_tx++; } /* recv data */ do { status = spi_readl(SPI_SR); if (status & AT91C_SPI_OVRES) { spi_cs_deactivate(); return -1; } } while ((status & AT91C_SPI_RDRF) == 0); value = spi_readl(SPI_RDR); if (rxp) *rxp++ = value; len_rx++; } out: if (flags & SPI_XFER_END) { /* * Wait until the transfer is completely done before * we deactivate CS. */ do { status = spi_readl(SPI_SR); } while (!(status & AT91C_SPI_TXEMPTY)); spi_cs_deactivate(); } return 0; }