Esempio n. 1
0
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);
}
Esempio n. 2
0
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);
}
Esempio n. 3
0
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);
}
Esempio n. 5
0
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);
}
Esempio n. 7
0
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);
}
Esempio n. 8
0
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;
}
Esempio n. 9
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;
}