123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- /*
- * Opencore tiny_spi driver
- *
- * http://opencores.org/project,tiny_spi
- *
- * based on bfin_spi.c
- * Copyright (c) 2005-2008 Analog Devices Inc.
- * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
- *
- * Licensed under the GPL-2 or later.
- */
- #include <common.h>
- #include <asm/io.h>
- #include <malloc.h>
- #include <spi.h>
- #include <asm/gpio.h>
- #define TINY_SPI_STATUS_TXE 0x1
- #define TINY_SPI_STATUS_TXR 0x2
- struct tiny_spi_regs {
- unsigned rxdata; /* Rx data reg */
- unsigned txdata; /* Tx data reg */
- unsigned status; /* Status reg */
- unsigned control; /* Control reg */
- unsigned baud; /* Baud reg */
- };
- struct tiny_spi_host {
- uint base;
- uint freq;
- uint baudwidth;
- };
- static const struct tiny_spi_host tiny_spi_host_list[] =
- CONFIG_SYS_TINY_SPI_LIST;
- struct tiny_spi_slave {
- struct spi_slave slave;
- const struct tiny_spi_host *host;
- uint mode;
- uint baud;
- uint flg;
- };
- #define to_tiny_spi_slave(s) container_of(s, struct tiny_spi_slave, slave)
- int spi_cs_is_valid(unsigned int bus, unsigned int cs)
- {
- return bus < ARRAY_SIZE(tiny_spi_host_list) && gpio_is_valid(cs);
- }
- void spi_cs_activate(struct spi_slave *slave)
- {
- struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
- unsigned int cs = slave->cs;
- gpio_set_value(cs, tiny_spi->flg);
- debug("%s: SPI_CS_GPIO:%x\n", __func__, gpio_get_value(cs));
- }
- void spi_cs_deactivate(struct spi_slave *slave)
- {
- struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
- unsigned int cs = slave->cs;
- gpio_set_value(cs, !tiny_spi->flg);
- debug("%s: SPI_CS_GPIO:%x\n", __func__, gpio_get_value(cs));
- }
- void spi_set_speed(struct spi_slave *slave, uint hz)
- {
- struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
- const struct tiny_spi_host *host = tiny_spi->host;
- tiny_spi->baud = min(DIV_ROUND_UP(host->freq, hz * 2),
- (1 << host->baudwidth)) - 1;
- debug("%s: speed %u actual %u\n", __func__, hz,
- host->freq / ((tiny_spi->baud + 1) * 2));
- }
- void spi_init(void)
- {
- }
- struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
- unsigned int hz, unsigned int mode)
- {
- struct tiny_spi_slave *tiny_spi;
- if (!spi_cs_is_valid(bus, cs) || gpio_request(cs, "tiny_spi"))
- return NULL;
- tiny_spi = spi_alloc_slave(struct tiny_spi_slave, bus, cs);
- if (!tiny_spi)
- return NULL;
- tiny_spi->host = &tiny_spi_host_list[bus];
- tiny_spi->mode = mode & (SPI_CPOL | SPI_CPHA);
- tiny_spi->flg = mode & SPI_CS_HIGH ? 1 : 0;
- spi_set_speed(&tiny_spi->slave, hz);
- debug("%s: bus:%i cs:%i base:%lx\n", __func__,
- bus, cs, tiny_spi->host->base);
- return &tiny_spi->slave;
- }
- void spi_free_slave(struct spi_slave *slave)
- {
- struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
- gpio_free(slave->cs);
- free(tiny_spi);
- }
- int spi_claim_bus(struct spi_slave *slave)
- {
- struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
- struct tiny_spi_regs *regs = (void *)tiny_spi->host->base;
- debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
- gpio_direction_output(slave->cs, !tiny_spi->flg);
- writel(tiny_spi->mode, ®s->control);
- writel(tiny_spi->baud, ®s->baud);
- return 0;
- }
- void spi_release_bus(struct spi_slave *slave)
- {
- debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
- }
- #ifndef CONFIG_TINY_SPI_IDLE_VAL
- # define CONFIG_TINY_SPI_IDLE_VAL 0xff
- #endif
- int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
- void *din, unsigned long flags)
- {
- struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
- struct tiny_spi_regs *regs = (void *)tiny_spi->host->base;
- const u8 *txp = dout;
- u8 *rxp = din;
- uint bytes = bitlen / 8;
- uint i;
- debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__,
- slave->bus, slave->cs, bitlen, bytes, flags);
- if (bitlen == 0)
- goto done;
- /* assume to do 8 bits transfers */
- if (bitlen % 8) {
- flags |= SPI_XFER_END;
- goto done;
- }
- if (flags & SPI_XFER_BEGIN)
- spi_cs_activate(slave);
- /* we need to tighten the transfer loop */
- if (txp && rxp) {
- writeb(*txp++, ®s->txdata);
- if (bytes > 1) {
- writeb(*txp++, ®s->txdata);
- for (i = 2; i < bytes; i++) {
- u8 rx, tx = *txp++;
- while (!(readb(®s->status) &
- TINY_SPI_STATUS_TXR))
- ;
- rx = readb(®s->txdata);
- writeb(tx, ®s->txdata);
- *rxp++ = rx;
- }
- while (!(readb(®s->status) &
- TINY_SPI_STATUS_TXR))
- ;
- *rxp++ = readb(®s->txdata);
- }
- while (!(readb(®s->status) &
- TINY_SPI_STATUS_TXE))
- ;
- *rxp++ = readb(®s->rxdata);
- } else if (rxp) {
- writeb(CONFIG_TINY_SPI_IDLE_VAL, ®s->txdata);
- if (bytes > 1) {
- writeb(CONFIG_TINY_SPI_IDLE_VAL,
- ®s->txdata);
- for (i = 2; i < bytes; i++) {
- u8 rx;
- while (!(readb(®s->status) &
- TINY_SPI_STATUS_TXR))
- ;
- rx = readb(®s->txdata);
- writeb(CONFIG_TINY_SPI_IDLE_VAL,
- ®s->txdata);
- *rxp++ = rx;
- }
- while (!(readb(®s->status) &
- TINY_SPI_STATUS_TXR))
- ;
- *rxp++ = readb(®s->txdata);
- }
- while (!(readb(®s->status) &
- TINY_SPI_STATUS_TXE))
- ;
- *rxp++ = readb(®s->rxdata);
- } else if (txp) {
- writeb(*txp++, ®s->txdata);
- if (bytes > 1) {
- writeb(*txp++, ®s->txdata);
- for (i = 2; i < bytes; i++) {
- u8 tx = *txp++;
- while (!(readb(®s->status) &
- TINY_SPI_STATUS_TXR))
- ;
- writeb(tx, ®s->txdata);
- }
- }
- while (!(readb(®s->status) &
- TINY_SPI_STATUS_TXE))
- ;
- } else {
- writeb(CONFIG_TINY_SPI_IDLE_VAL, ®s->txdata);
- if (bytes > 1) {
- writeb(CONFIG_TINY_SPI_IDLE_VAL,
- ®s->txdata);
- for (i = 2; i < bytes; i++) {
- while (!(readb(®s->status) &
- TINY_SPI_STATUS_TXR))
- ;
- writeb(CONFIG_TINY_SPI_IDLE_VAL,
- ®s->txdata);
- }
- }
- while (!(readb(®s->status) &
- TINY_SPI_STATUS_TXE))
- ;
- }
- done:
- if (flags & SPI_XFER_END)
- spi_cs_deactivate(slave);
- return 0;
- }
|