diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/da8xx_gpio.c | 8 | ||||
-rw-r--r-- | drivers/mmc/bfin_sdh.c | 68 | ||||
-rw-r--r-- | drivers/mtd/nand/kmeter1_nand.c | 4 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_util.c | 19 | ||||
-rw-r--r-- | drivers/net/fm/fm.c | 4 | ||||
-rw-r--r-- | drivers/serial/sandbox.c | 44 | ||||
-rw-r--r-- | drivers/serial/serial_ns16550.c | 12 | ||||
-rw-r--r-- | drivers/spi/Makefile | 1 | ||||
-rw-r--r-- | drivers/spi/bfin_spi6xx.c | 308 |
10 files changed, 441 insertions, 28 deletions
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 2d97b4f..9df1e26 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -39,6 +39,7 @@ COBJS-$(CONFIG_SANDBOX_GPIO) += sandbox.o COBJS-$(CONFIG_SPEAR_GPIO) += spear_gpio.o COBJS-$(CONFIG_TEGRA_GPIO) += tegra_gpio.o COBJS-$(CONFIG_DA8XX_GPIO) += da8xx_gpio.o +COBJS-$(CONFIG_DM644X_GPIO) += da8xx_gpio.o COBJS-$(CONFIG_ALTERA_PIO) += altera_pio.o COBJS-$(CONFIG_MPC83XX_GPIO) += mpc83xx_gpio.o COBJS-$(CONFIG_SH_GPIO_PFC) += sh_pfc.o diff --git a/drivers/gpio/da8xx_gpio.c b/drivers/gpio/da8xx_gpio.c index 271b8d9..76648d2 100644 --- a/drivers/gpio/da8xx_gpio.c +++ b/drivers/gpio/da8xx_gpio.c @@ -31,6 +31,7 @@ static struct gpio_registry { char name[GPIO_NAME_SIZE]; } gpio_registry[MAX_NUM_GPIOS]; +#if defined(CONFIG_SOC_DA8XX) #define pinmux(x) (&davinci_syscfg_regs->pinmux[x]) #if defined(CONFIG_SOC_DA8XX) && !defined(CONFIG_SOC_DA850) @@ -164,7 +165,7 @@ static const struct pinmux_config gpio_pinmux[] = { { pinmux(0), 1, 0 }, { pinmux(0), 1, 1 }, }; -#else +#else /* CONFIG_SOC_DA8XX && CONFIG_SOC_DA850 */ static const struct pinmux_config gpio_pinmux[] = { { pinmux(1), 8, 7 }, /* GP0[0] */ { pinmux(1), 8, 6 }, @@ -311,7 +312,10 @@ static const struct pinmux_config gpio_pinmux[] = { { pinmux(18), 8, 3 }, { pinmux(18), 8, 2 }, }; -#endif +#endif /* CONFIG_SOC_DA8XX && !CONFIG_SOC_DA850 */ +#else /* !CONFIG_SOC_DA8XX */ +#define davinci_configure_pin_mux(a, b) +#endif /* CONFIG_SOC_DA8XX */ int gpio_request(unsigned gpio, const char *label) { diff --git a/drivers/mmc/bfin_sdh.c b/drivers/mmc/bfin_sdh.c index 81d8e54..2631174 100644 --- a/drivers/mmc/bfin_sdh.c +++ b/drivers/mmc/bfin_sdh.c @@ -19,9 +19,7 @@ #include <asm/mach-common/bits/sdh.h> #include <asm/mach-common/bits/dma.h> -#if defined(__ADSPBF50x__) || defined(__ADSPBF51x__) -# define bfin_read_SDH_PWR_CTL bfin_read_RSI_PWR_CONTROL -# define bfin_write_SDH_PWR_CTL bfin_write_RSI_PWR_CONTROL +#if defined(__ADSPBF50x__) || defined(__ADSPBF51x__) || defined(__ADSPBF60x__) # define bfin_read_SDH_CLK_CTL bfin_read_RSI_CLK_CONTROL # define bfin_write_SDH_CLK_CTL bfin_write_RSI_CLK_CONTROL # define bfin_write_SDH_ARGUMENT bfin_write_RSI_ARGUMENT @@ -38,10 +36,21 @@ # define bfin_write_SDH_STATUS_CLR bfin_write_RSI_STATUSCL # define bfin_read_SDH_CFG bfin_read_RSI_CONFIG # define bfin_write_SDH_CFG bfin_write_RSI_CONFIG +# if defined(__ADSPBF60x__) +# define bfin_read_SDH_BLK_SIZE bfin_read_RSI_BLKSZ +# define bfin_write_SDH_BLK_SIZE bfin_write_RSI_BLKSZ +# define bfin_write_DMA_START_ADDR bfin_write_DMA10_START_ADDR +# define bfin_write_DMA_X_COUNT bfin_write_DMA10_X_COUNT +# define bfin_write_DMA_X_MODIFY bfin_write_DMA10_X_MODIFY +# define bfin_write_DMA_CONFIG bfin_write_DMA10_CONFIG +# else +# define bfin_read_SDH_PWR_CTL bfin_read_RSI_PWR_CONTROL +# define bfin_write_SDH_PWR_CTL bfin_write_RSI_PWR_CONTROL # define bfin_write_DMA_START_ADDR bfin_write_DMA4_START_ADDR # define bfin_write_DMA_X_COUNT bfin_write_DMA4_X_COUNT # define bfin_write_DMA_X_MODIFY bfin_write_DMA4_X_MODIFY # define bfin_write_DMA_CONFIG bfin_write_DMA4_CONFIG +# endif # define PORTMUX_PINS \ { P_RSI_DATA0, P_RSI_DATA1, P_RSI_DATA2, P_RSI_DATA3, P_RSI_CMD, P_RSI_CLK, 0 } #elif defined(__ADSPBF54x__) @@ -70,6 +79,9 @@ sdh_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd) sdh_cmd |= CMD_RSP; if (flags & MMC_RSP_136) sdh_cmd |= CMD_L_RSP; +#ifdef RSI_BLKSZ + sdh_cmd |= CMD_DATA0_BUSY; +#endif bfin_write_SDH_ARGUMENT(arg); bfin_write_SDH_COMMAND(sdh_cmd); @@ -104,6 +116,12 @@ sdh_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd) bfin_write_SDH_STATUS_CLR(CMD_SENT_STAT | CMD_RESP_END_STAT | CMD_TIMEOUT_STAT | CMD_CRC_FAIL_STAT); +#ifdef RSI_BLKSZ + /* wait till card ready */ + while (!(bfin_read_RSI_ESTAT() & SD_CARD_READY)) + continue; + bfin_write_RSI_ESTAT(SD_CARD_READY); +#endif return ret; } @@ -113,16 +131,19 @@ static int sdh_setup_data(struct mmc *mmc, struct mmc_data *data) { u16 data_ctl = 0; u16 dma_cfg = 0; - int ret = 0; unsigned long data_size = data->blocksize * data->blocks; /* Don't support write yet. */ if (data->flags & MMC_DATA_WRITE) return UNUSABLE_ERR; +#ifndef RSI_BLKSZ data_ctl |= ((ffs(data_size) - 1) << 4); +#else + bfin_write_SDH_BLK_SIZE(data_size); +#endif data_ctl |= DTX_DIR; bfin_write_SDH_DATA_CTL(data_ctl); - dma_cfg = WDSIZE_32 | RESTART | WNR | DMAEN; + dma_cfg = WDSIZE_32 | PSIZE_32 | RESTART | WNR | DMAEN; bfin_write_SDH_DATA_TIMER(-1); @@ -137,7 +158,7 @@ static int sdh_setup_data(struct mmc *mmc, struct mmc_data *data) /* kick off transfer */ bfin_write_SDH_DATA_CTL(bfin_read_SDH_DATA_CTL() | DTX_DMA_E | DTX_E); - return ret; + return 0; } @@ -147,13 +168,23 @@ static int bfin_sdh_request(struct mmc *mmc, struct mmc_cmd *cmd, u32 status; int ret = 0; + if (data) { + ret = sdh_setup_data(mmc, data); + if (ret) + return ret; + } + ret = sdh_send_cmd(mmc, cmd); if (ret) { + bfin_write_SDH_COMMAND(0); + bfin_write_DMA_CONFIG(0); + bfin_write_SDH_DATA_CTL(0); + SSYNC(); printf("sending CMD%d failed\n", cmd->cmdidx); return ret; } + if (data) { - ret = sdh_setup_data(mmc, data); do { udelay(1); status = bfin_read_SDH_STATUS(); @@ -208,10 +239,12 @@ static void bfin_sdh_set_ios(struct mmc *mmc) if (mmc->bus_width == 4) { cfg = bfin_read_SDH_CFG(); - cfg &= ~0x80; - cfg |= 0x40; +#ifndef RSI_BLKSZ + cfg &= ~PD_SDDAT3; +#endif + cfg |= PUP_SDDAT3; bfin_write_SDH_CFG(cfg); - clk_ctl |= WIDE_BUS; + clk_ctl |= WIDE_BUS_4; } bfin_write_SDH_CLK_CTL(clk_ctl); sdh_set_clk(mmc->clock); @@ -220,20 +253,23 @@ static void bfin_sdh_set_ios(struct mmc *mmc) static int bfin_sdh_init(struct mmc *mmc) { const unsigned short pins[] = PORTMUX_PINS; - u16 pwr_ctl = 0; + int ret; /* Initialize sdh controller */ - peripheral_request_list(pins, "bfin_sdh"); + ret = peripheral_request_list(pins, "bfin_sdh"); + if (ret < 0) + return ret; #if defined(__ADSPBF54x__) bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() | 0x1); #endif bfin_write_SDH_CFG(bfin_read_SDH_CFG() | CLKS_EN); /* Disable card detect pin */ bfin_write_SDH_CFG((bfin_read_SDH_CFG() & 0x1F) | 0x60); - - pwr_ctl |= ROD_CTL; - pwr_ctl |= PWR_ON; - bfin_write_SDH_PWR_CTL(pwr_ctl); +#ifndef RSI_BLKSZ + bfin_write_SDH_PWR_CTL(PWR_ON | ROD_CTL); +#else + bfin_write_SDH_CFG(bfin_read_SDH_CFG() | PWR_ON); +#endif return 0; } diff --git a/drivers/mtd/nand/kmeter1_nand.c b/drivers/mtd/nand/kmeter1_nand.c index e8e5b7b..f044597 100644 --- a/drivers/mtd/nand/kmeter1_nand.c +++ b/drivers/mtd/nand/kmeter1_nand.c @@ -119,7 +119,11 @@ static int kpn_nand_dev_ready(struct mtd_info *mtd) int board_nand_init(struct nand_chip *nand) { +#if defined(CONFIG_NAND_ECC_BCH) + nand->ecc.mode = NAND_ECC_SOFT_BCH; +#else nand->ecc.mode = NAND_ECC_SOFT; +#endif /* Reference hardware control function */ nand->cmd_ctrl = kpn_nand_hwcontrol; diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 2ba0c5e..ff2d348 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -237,6 +237,14 @@ int nand_lock(struct mtd_info *mtd, int tight) /* select the NAND device */ chip->select_chip(mtd, 0); + /* check the Lock Tight Status */ + chip->cmdfunc(mtd, NAND_CMD_LOCK_STATUS, -1, 0); + if (chip->read_byte(mtd) & NAND_LOCK_STATUS_TIGHT) { + printf("nand_lock: Device is locked tight!\n"); + ret = -1; + goto out; + } + chip->cmdfunc(mtd, (tight ? NAND_CMD_LOCK_TIGHT : NAND_CMD_LOCK), -1, -1); @@ -249,6 +257,7 @@ int nand_lock(struct mtd_info *mtd, int tight) ret = -1; } + out: /* de-select the NAND device */ chip->select_chip(mtd, -1); return ret; @@ -337,6 +346,15 @@ int nand_unlock(struct mtd_info *mtd, loff_t start, size_t length, goto out; } + /* check the Lock Tight Status */ + page = (int)(start >> chip->page_shift); + chip->cmdfunc(mtd, NAND_CMD_LOCK_STATUS, -1, page & chip->pagemask); + if (chip->read_byte(mtd) & NAND_LOCK_STATUS_TIGHT) { + printf("nand_unlock: Device is locked tight!\n"); + ret = -1; + goto out; + } + if ((start & (mtd->erasesize - 1)) != 0) { printf("nand_unlock: Start address must be beginning of " "nand block!\n"); @@ -358,7 +376,6 @@ int nand_unlock(struct mtd_info *mtd, loff_t start, size_t length, length -= mtd->erasesize; /* submit address of first page to unlock */ - page = (int)(start >> chip->page_shift); chip->cmdfunc(mtd, NAND_CMD_UNLOCK1, -1, page & chip->pagemask); /* submit ADDRESS of LAST page to unlock */ diff --git a/drivers/net/fm/fm.c b/drivers/net/fm/fm.c index 49c74c2..8d70586 100644 --- a/drivers/net/fm/fm.c +++ b/drivers/net/fm/fm.c @@ -362,7 +362,6 @@ static void fm_init_qmi(struct fm_qmi_common *qmi) int fm_init_common(int index, struct ccsr_fman *reg) { int rc; - char env_addr[32]; #if defined(CONFIG_SYS_QE_FMAN_FW_IN_NOR) void *addr = (void *)CONFIG_SYS_QE_FMAN_FW_ADDR; #elif defined(CONFIG_SYS_QE_FMAN_FW_IN_NAND) @@ -416,8 +415,7 @@ int fm_init_common(int index, struct ccsr_fman *reg) rc = fman_upload_firmware(index, ®->fm_imem, addr); if (rc) return rc; - sprintf(env_addr, "0x%lx", (long unsigned int)addr); - setenv("fman_ucode", env_addr); + setenv_addr("fman_ucode", addr); fm_init_muram(index, ®->muram); fm_init_qmi(®->fm_qmi_common); diff --git a/drivers/serial/sandbox.c b/drivers/serial/sandbox.c index cb19401..b73520c 100644 --- a/drivers/serial/sandbox.c +++ b/drivers/serial/sandbox.c @@ -30,6 +30,19 @@ #include <serial.h> #include <linux/compiler.h> +/* + * + * serial_buf: A buffer that holds keyboard characters for the + * Sandbox U-boot. + * + * invariants: + * serial_buf_write == serial_buf_read -> empty buffer + * (serial_buf_write + 1) % 16 == serial_buf_read -> full buffer + */ +static char serial_buf[16]; +static unsigned int serial_buf_write; +static unsigned int serial_buf_read; + static int sandbox_serial_init(void) { os_tty_raw(0); @@ -50,18 +63,37 @@ static void sandbox_serial_puts(const char *str) os_write(1, str, strlen(str)); } -static int sandbox_serial_getc(void) +static unsigned int increment_buffer_index(unsigned int index) +{ + return (index + 1) % ARRAY_SIZE(serial_buf); +} + +static int sandbox_serial_tstc(void) { - char buf; + const unsigned int next_index = + increment_buffer_index(serial_buf_write); ssize_t count; - count = os_read(0, &buf, 1); - return count == 1 ? buf : 0; + os_usleep(100); + if (next_index == serial_buf_read) + return 1; /* buffer full */ + + count = os_read_no_block(0, &serial_buf[serial_buf_write], 1); + if (count == 1) + serial_buf_write = next_index; + return serial_buf_write != serial_buf_read; } -static int sandbox_serial_tstc(void) +static int sandbox_serial_getc(void) { - return 0; + int result; + + while (!sandbox_serial_tstc()) + ; /* buffer empty */ + + result = serial_buf[serial_buf_read]; + serial_buf_read = increment_buffer_index(serial_buf_read); + return result; } static struct serial_device sandbox_serial_drv = { diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c index fc01a3c..b92eef4 100644 --- a/drivers/serial/serial_ns16550.c +++ b/drivers/serial/serial_ns16550.c @@ -247,24 +247,36 @@ serial_setbrg_dev(unsigned int dev_index) _serial_setbrg(dev_index); } +#if defined(CONFIG_SYS_NS16550_COM1) DECLARE_ESERIAL_FUNCTIONS(1); struct serial_device eserial1_device = INIT_ESERIAL_STRUCTURE(1, "eserial0"); +#endif +#if defined(CONFIG_SYS_NS16550_COM2) DECLARE_ESERIAL_FUNCTIONS(2); struct serial_device eserial2_device = INIT_ESERIAL_STRUCTURE(2, "eserial1"); +#endif +#if defined(CONFIG_SYS_NS16550_COM3) DECLARE_ESERIAL_FUNCTIONS(3); struct serial_device eserial3_device = INIT_ESERIAL_STRUCTURE(3, "eserial2"); +#endif +#if defined(CONFIG_SYS_NS16550_COM4) DECLARE_ESERIAL_FUNCTIONS(4); struct serial_device eserial4_device = INIT_ESERIAL_STRUCTURE(4, "eserial3"); +#endif +#if defined(CONFIG_SYS_NS16550_COM5) DECLARE_ESERIAL_FUNCTIONS(5); struct serial_device eserial5_device = INIT_ESERIAL_STRUCTURE(5, "eserial4"); +#endif +#if defined(CONFIG_SYS_NS16550_COM6) DECLARE_ESERIAL_FUNCTIONS(6); struct serial_device eserial6_device = INIT_ESERIAL_STRUCTURE(6, "eserial5"); +#endif __weak struct serial_device *default_serial_console(void) { diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 83abcbd..b8264df 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -31,6 +31,7 @@ COBJS-$(CONFIG_ARMADA100_SPI) += armada100_spi.o COBJS-$(CONFIG_ATMEL_DATAFLASH_SPI) += atmel_dataflash_spi.o COBJS-$(CONFIG_ATMEL_SPI) += atmel_spi.o COBJS-$(CONFIG_BFIN_SPI) += bfin_spi.o +COBJS-$(CONFIG_BFIN_SPI6XX) += bfin_spi6xx.o COBJS-$(CONFIG_CF_SPI) += cf_spi.o COBJS-$(CONFIG_CF_QSPI) += cf_qspi.o COBJS-$(CONFIG_DAVINCI_SPI) += davinci_spi.o diff --git a/drivers/spi/bfin_spi6xx.c b/drivers/spi/bfin_spi6xx.c new file mode 100644 index 0000000..fde3447 --- /dev/null +++ b/drivers/spi/bfin_spi6xx.c @@ -0,0 +1,308 @@ +/* + * Analog Devices SPI3 controller driver + * + * Copyright (c) 2011 Analog Devices Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <common.h> +#include <malloc.h> +#include <spi.h> + +#include <asm/blackfin.h> +#include <asm/gpio.h> +#include <asm/portmux.h> +#include <asm/mach-common/bits/spi6xx.h> + +struct bfin_spi_slave { + struct spi_slave slave; + u32 control, clock; + struct bfin_spi_regs *regs; + int cs_pol; +}; + +#define to_bfin_spi_slave(s) container_of(s, struct bfin_spi_slave, slave) + +#define gpio_cs(cs) ((cs) - MAX_CTRL_CS) +#ifdef CONFIG_BFIN_SPI_GPIO_CS +# define is_gpio_cs(cs) ((cs) > MAX_CTRL_CS) +#else +# define is_gpio_cs(cs) 0 +#endif + +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + if (is_gpio_cs(cs)) + return gpio_is_valid(gpio_cs(cs)); + else + return (cs >= 1 && cs <= MAX_CTRL_CS); +} + +void spi_cs_activate(struct spi_slave *slave) +{ + struct bfin_spi_slave *bss = to_bfin_spi_slave(slave); + + if (is_gpio_cs(slave->cs)) { + unsigned int cs = gpio_cs(slave->cs); + gpio_set_value(cs, bss->cs_pol); + } else { + u32 ssel; + ssel = bfin_read32(&bss->regs->ssel); + ssel |= 1 << slave->cs; + if (bss->cs_pol) + ssel |= (1 << 8) << slave->cs; + else + ssel &= ~((1 << 8) << slave->cs); + bfin_write32(&bss->regs->ssel, ssel); + } + + SSYNC(); +} + +void spi_cs_deactivate(struct spi_slave *slave) +{ + struct bfin_spi_slave *bss = to_bfin_spi_slave(slave); + + if (is_gpio_cs(slave->cs)) { + unsigned int cs = gpio_cs(slave->cs); + gpio_set_value(cs, !bss->cs_pol); + } else { + u32 ssel; + ssel = bfin_read32(&bss->regs->ssel); + if (bss->cs_pol) + ssel &= ~((1 << 8) << slave->cs); + else + ssel |= (1 << 8) << slave->cs; + /* deassert cs */ + bfin_write32(&bss->regs->ssel, ssel); + SSYNC(); + /* disable cs */ + ssel &= ~(1 << slave->cs); + bfin_write32(&bss->regs->ssel, ssel); + } + + SSYNC(); +} + +void spi_init() +{ +} + +#define SPI_PINS(n) \ + { 0, P_SPI##n##_SCK, P_SPI##n##_MISO, P_SPI##n##_MOSI, 0 } +static unsigned short pins[][5] = { +#ifdef SPI0_REGBASE + [0] = SPI_PINS(0), +#endif +#ifdef SPI1_REGBASE + [1] = SPI_PINS(1), +#endif +#ifdef SPI2_REGBASE + [2] = SPI_PINS(2), +#endif +}; + +#define SPI_CS_PINS(n) \ + { \ + P_SPI##n##_SSEL1, P_SPI##n##_SSEL2, P_SPI##n##_SSEL3, \ + P_SPI##n##_SSEL4, P_SPI##n##_SSEL5, P_SPI##n##_SSEL6, \ + P_SPI##n##_SSEL7, \ + } +static const unsigned short cs_pins[][7] = { +#ifdef SPI0_REGBASE + [0] = SPI_CS_PINS(0), +#endif +#ifdef SPI1_REGBASE + [1] = SPI_CS_PINS(1), +#endif +#ifdef SPI2_REGBASE + [2] = SPI_CS_PINS(2), +#endif +}; + +void spi_set_speed(struct spi_slave *slave, uint hz) +{ + struct bfin_spi_slave *bss = to_bfin_spi_slave(slave); + ulong sclk; + u32 clock; + + sclk = get_sclk1(); + clock = sclk / hz; + if (clock) + clock--; + bss->clock = clock; +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct bfin_spi_slave *bss; + u32 reg_base; + + if (!spi_cs_is_valid(bus, cs)) + return NULL; + + if (bus >= ARRAY_SIZE(pins) || pins[bus] == NULL) { + debug("%s: invalid bus %u\n", __func__, bus); + return NULL; + } + switch (bus) { +#ifdef SPI0_REGBASE + case 0: + reg_base = SPI0_REGBASE; + break; +#endif +#ifdef SPI1_REGBASE + case 1: + reg_base = SPI1_REGBASE; + break; +#endif +#ifdef SPI2_REGBASE + case 2: + reg_base = SPI2_REGBASE; + break; +#endif + default: + return NULL; + } + + bss = malloc(sizeof(*bss)); + if (!bss) + return NULL; + + bss->slave.bus = bus; + bss->slave.cs = cs; + bss->regs = (struct bfin_spi_regs *)reg_base; + bss->control = SPI_CTL_EN | SPI_CTL_MSTR; + if (mode & SPI_CPHA) + bss->control |= SPI_CTL_CPHA; + if (mode & SPI_CPOL) + bss->control |= SPI_CTL_CPOL; + if (mode & SPI_LSB_FIRST) + bss->control |= SPI_CTL_LSBF; + bss->control &= ~SPI_CTL_ASSEL; + bss->cs_pol = mode & SPI_CS_HIGH ? 1 : 0; + spi_set_speed(&bss->slave, max_hz); + + return &bss->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + struct bfin_spi_slave *bss = to_bfin_spi_slave(slave); + free(bss); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + struct bfin_spi_slave *bss = to_bfin_spi_slave(slave); + + debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs); + + if (is_gpio_cs(slave->cs)) { + unsigned int cs = gpio_cs(slave->cs); + gpio_request(cs, "bfin-spi"); + gpio_direction_output(cs, !bss->cs_pol); + pins[slave->bus][0] = P_DONTCARE; + } else + pins[slave->bus][0] = cs_pins[slave->bus][slave->cs - 1]; + peripheral_request_list(pins[slave->bus], "bfin-spi"); + + bfin_write32(&bss->regs->control, bss->control); + bfin_write32(&bss->regs->clock, bss->clock); + bfin_write32(&bss->regs->delay, 0x0); + bfin_write32(&bss->regs->rx_control, SPI_RXCTL_REN); + bfin_write32(&bss->regs->tx_control, SPI_TXCTL_TEN | SPI_TXCTL_TTI); + SSYNC(); + + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + struct bfin_spi_slave *bss = to_bfin_spi_slave(slave); + + debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs); + + peripheral_free_list(pins[slave->bus]); + if (is_gpio_cs(slave->cs)) + gpio_free(gpio_cs(slave->cs)); + + bfin_write32(&bss->regs->rx_control, 0x0); + bfin_write32(&bss->regs->tx_control, 0x0); + bfin_write32(&bss->regs->control, 0x0); + SSYNC(); +} + +#ifndef CONFIG_BFIN_SPI_IDLE_VAL +# define CONFIG_BFIN_SPI_IDLE_VAL 0xff +#endif + +static int spi_pio_xfer(struct bfin_spi_slave *bss, const u8 *tx, u8 *rx, + uint bytes) +{ + /* discard invalid rx data and empty rfifo */ + while (!(bfin_read32(&bss->regs->status) & SPI_STAT_RFE)) + bfin_read32(&bss->regs->rfifo); + + while (bytes--) { + u8 value = (tx ? *tx++ : CONFIG_BFIN_SPI_IDLE_VAL); + debug("%s: tx:%x ", __func__, value); + bfin_write32(&bss->regs->tfifo, value); + SSYNC(); + while (bfin_read32(&bss->regs->status) & SPI_STAT_RFE) + if (ctrlc()) + return -1; + value = bfin_read32(&bss->regs->rfifo); + if (rx) + *rx++ = value; + debug("rx:%x\n", value); + } + + return 0; +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, + void *din, unsigned long flags) +{ + struct bfin_spi_slave *bss = to_bfin_spi_slave(slave); + const u8 *tx = dout; + u8 *rx = din; + uint bytes = bitlen / 8; + int ret = 0; + + 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; + + /* we can only do 8 bit transfers */ + if (bitlen % 8) { + flags |= SPI_XFER_END; + goto done; + } + + if (flags & SPI_XFER_BEGIN) + spi_cs_activate(slave); + + ret = spi_pio_xfer(bss, tx, rx, bytes); + + done: + if (flags & SPI_XFER_END) + spi_cs_deactivate(slave); + + return ret; +} |