Message ID | 1366277139-29728-6-git-send-email-dantesu@gmail.com |
---|---|
State | Superseded |
Delegated to: | Albert ARIBAUD |
Headers | show |
Dear Kuo-Jung Su, In message <1366277139-29728-6-git-send-email-dantesu@gmail.com> you wrote: ... > +/* Register access macros */ > +#define SPI_READ(r) le32_to_cpu(readl(r)) > +#define SPI_WRITE(v, r) writel(cpu_to_le32(v), r) > +#define SPI_SETBITS(m, r) setbits_le32(r, m) > +#define SPI_CLRBITS(m, r) clrbits_le32(r, m) Ad before: drop these. > +#ifdef CONFIG_FTSSP010_GPIO_BASE > +#define SPI_GPIO_READ(p, r) \ > + le32_to_cpu(readl((p)->gpio.iobase + (r))) > +#define SPI_GPIO_WRITE(p, v, r) \ > + writel(cpu_to_le32(v), (p)->gpio.iobase + (r)) > +#define SPI_GPIO_SETBITS(p, m, r) \ > + setbits_le32((p)->gpio.iobase + (r), m) > +#define SPI_GPIO_CLRBITS(p, m, r) \ > + clrbits_le32((p)->gpio.iobase + (r), m) > +#endif /* #ifdef CONFIG_FTSSP010_GPIO_BASE */ We do not allos I/O accesses throug base addrss plus offset. Please use proper C structs instead. Best regards, Wolfgang Denk
2013/4/18 Wolfgang Denk <wd@denx.de>: > Dear Kuo-Jung Su, > > In message <1366277139-29728-6-git-send-email-dantesu@gmail.com> you wrote: > ... >> +/* Register access macros */ >> +#define SPI_READ(r) le32_to_cpu(readl(r)) >> +#define SPI_WRITE(v, r) writel(cpu_to_le32(v), r) >> +#define SPI_SETBITS(m, r) setbits_le32(r, m) >> +#define SPI_CLRBITS(m, r) clrbits_le32(r, m) > > Ad before: drop these. > Got it, thanks >> +#ifdef CONFIG_FTSSP010_GPIO_BASE >> +#define SPI_GPIO_READ(p, r) \ >> + le32_to_cpu(readl((p)->gpio.iobase + (r))) >> +#define SPI_GPIO_WRITE(p, v, r) \ >> + writel(cpu_to_le32(v), (p)->gpio.iobase + (r)) >> +#define SPI_GPIO_SETBITS(p, m, r) \ >> + setbits_le32((p)->gpio.iobase + (r), m) >> +#define SPI_GPIO_CLRBITS(p, m, r) \ >> + clrbits_le32((p)->gpio.iobase + (r), m) >> +#endif /* #ifdef CONFIG_FTSSP010_GPIO_BASE */ > > We do not allos I/O accesses throug base addrss plus offset. > Please use proper C structs instead. > > Got it, thanks > Best regards, > > Wolfgang Denk > > -- > DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel > HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany > Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de > Sorry, but my karma just ran over your dogma. -- Best wishes, Kuo-Jung Su
Hi Kuo-Jung Su, Please fix the comments I sent on v4. http://patchwork.ozlabs.org/patch/242023/ Feel free to ask for any quires. Thanks, Jagan. On Thu, Apr 18, 2013 at 2:55 PM, Kuo-Jung Su <dantesu@gmail.com> wrote: > From: Kuo-Jung Su <dantesu@faraday-tech.com> > > The Faraday FTSSP010 is a multi-function controller > which supports I2S/SPI/SSP/AC97/SPDIF. > This patch simpily implements the SPI mode only. > BTW the DMA and CS/Clock control logic has been > altered since revision 1.19.0. So this patch > would 1st detects the revision id of the underlying > chip, and then switch to the corresponding control > routines. > > Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com> > --- > drivers/spi/Makefile | 1 + > drivers/spi/ftssp010_spi.c | 337 ++++++++++++++++++++++++++++++++++++++++++++ > drivers/spi/ftssp010_spi.h | 86 +++++++++++ > 3 files changed, 424 insertions(+) > create mode 100644 drivers/spi/ftssp010_spi.c > create mode 100644 drivers/spi/ftssp010_spi.h > > diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile > index d08609e..947d60e 100644 > --- a/drivers/spi/Makefile > +++ b/drivers/spi/Makefile > @@ -38,6 +38,7 @@ 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 > +COBJS-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o > COBJS-$(CONFIG_EXYNOS_SPI) += exynos_spi.o > COBJS-$(CONFIG_ICH_SPI) += ich.o > COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o > diff --git a/drivers/spi/ftssp010_spi.c b/drivers/spi/ftssp010_spi.c > new file mode 100644 > index 0000000..4247c8c > --- /dev/null > +++ b/drivers/spi/ftssp010_spi.c > @@ -0,0 +1,337 @@ > +/* > + * Faraday Multi-function Controller - SPI Mode > + * > + * (C) Copyright 2010 Faraday Technology > + * Dante Su <dantesu@faraday-tech.com> > + * > + * This file is released under the terms of GPL v2 and any later version. > + * See the file COPYING in the root directory of the source tree for details. > + */ > + > +#include <common.h> > +#include <asm/io.h> > +#include <spi.h> > +#include <malloc.h> > + > +#include "ftssp010_spi.h" > + > +struct ftssp010_chip { > + void *iobase; > + uint32_t fifo; > + uint32_t rev; > + uint32_t div; > + uint32_t mode; > + > + struct { > + uint32_t iobase; > + uint32_t pin; > + } gpio; > +}; > + > +static struct ftssp010_chip chip_list[] = { > +#if defined(CONFIG_FTSSP010_BASE) || defined(CONFIG_FTSSP010_BASE0) > + { > + .iobase = (void *)CONFIG_FTSSP010_BASE, > +#ifdef CONFIG_FTSSP010_GPIO_BASE > + .gpio = { CONFIG_FTSSP010_GPIO_BASE, CONFIG_FTSSP010_GPIO_PIN }, > +#endif > + }, > +#endif > +#ifdef CONFIG_FTSSP010_BASE1 > + { .iobase = (void *)CONFIG_FTSSP010_BASE1, }, > +#endif > +#ifdef CONFIG_FTSSP010_BASE2 > + { .iobase = (void *)CONFIG_FTSSP010_BASE2, }, > +#endif > +#ifdef CONFIG_FTSSP010_BASE3 > + { .iobase = (void *)CONFIG_FTSSP010_BASE3, }, > +#endif > +}; > + > +/* Register access macros */ > +#define SPI_READ(r) le32_to_cpu(readl(r)) > +#define SPI_WRITE(v, r) writel(cpu_to_le32(v), r) > +#define SPI_SETBITS(m, r) setbits_le32(r, m) > +#define SPI_CLRBITS(m, r) clrbits_le32(r, m) > + > +#ifdef CONFIG_FTSSP010_GPIO_BASE > +#define SPI_GPIO_READ(p, r) \ > + le32_to_cpu(readl((p)->gpio.iobase + (r))) > +#define SPI_GPIO_WRITE(p, v, r) \ > + writel(cpu_to_le32(v), (p)->gpio.iobase + (r)) > +#define SPI_GPIO_SETBITS(p, m, r) \ > + setbits_le32((p)->gpio.iobase + (r), m) > +#define SPI_GPIO_CLRBITS(p, m, r) \ > + clrbits_le32((p)->gpio.iobase + (r), m) > +#endif /* #ifdef CONFIG_FTSSP010_GPIO_BASE */ > + > +static int ftssp010_spi_work_transfer_v1_19(struct ftssp010_chip *chip, > + const void *tx_buf, void *rx_buf, int len, uint flags) > +{ > + struct ftssp010_regs *regs = chip->iobase; > + const uint8_t *txb = tx_buf; > + uint8_t *rxb = rx_buf; > + > + while (len > 0) { > + int i, depth = min(chip->fifo >> 2, len); > + uint32_t xmsk = 0; > + > + if (tx_buf) { > + for (i = 0; i < depth; ++i) { > + while (!(SPI_READ(®s->sr) & SR_TFNF)) > + ; > + SPI_WRITE(*txb++, ®s->dr); > + } > + xmsk |= CR2_TXEN | CR2_TXDOE; > + if ((SPI_READ(®s->cr[2]) & xmsk) != xmsk) > + SPI_SETBITS(xmsk, ®s->cr[2]); > + } > + if (rx_buf) { > + xmsk |= CR2_RXEN; > + if ((SPI_READ(®s->cr[2]) & xmsk) != xmsk) > + SPI_SETBITS(xmsk, ®s->cr[2]); > + for (i = 0; i < depth; ++i) { > + while (!SR_RFVE(SPI_READ(®s->sr))) > + ; > + *rxb++ = (uint8_t)SPI_READ(®s->dr); > + } > + } > + > + len -= depth; > + } > + > + return 0; > +} > + > +static int ftssp010_spi_work_transfer(struct ftssp010_chip *chip, > + const void *tx_buf, void *rx_buf, int len, uint flags) > +{ > + struct ftssp010_regs *regs = chip->iobase; > + const uint8_t *txb = tx_buf; > + uint8_t *rxb = rx_buf; > + > + while (len > 0) { > + int i, depth = min(chip->fifo >> 2, len); > + uint32_t tmp; > + > + for (i = 0; i < depth; ++i) { > + while (!(SPI_READ(®s->sr) & SR_TFNF)) > + ; > + SPI_WRITE(txb ? (*txb++) : 0, ®s->dr); > + } > + for (i = 0; i < depth; ++i) { > + while (!SR_RFVE(SPI_READ(®s->sr))) > + ; > + tmp = SPI_READ(®s->dr); > + if (rxb) > + *rxb++ = (uint8_t)tmp; > + } > + > + len -= depth; > + } > + > + return 0; > +} > + > +/*=====================================================================*/ > +/* Public Functions */ > +/*=====================================================================*/ > + > +/*----------------------------------------------------------------------- > + * Determine if a SPI chipselect is valid. > + * This function is provided by the board if the low-level SPI driver > + * needs it to determine if a given chipselect is actually valid. > + * > + * Returns: 1 if bus:cs identifies a valid chip on this board, 0 > + * otherwise. > + */ > +int spi_cs_is_valid(unsigned int bus, unsigned int cs) > +{ > + struct ftssp010_chip *chip; > + struct ftssp010_regs *regs; > + uint32_t txfifo, rxfifo; > + > + if (bus >= ARRAY_SIZE(chip_list)) > + return 0; > + > + chip = chip_list + bus; > + regs = chip->iobase; > + chip->rev = SPI_READ(®s->revr); > + txfifo = FEAR_TXFIFO(SPI_READ(®s->fear)); > + rxfifo = FEAR_RXFIFO(SPI_READ(®s->fear)); > + chip->fifo = min(txfifo, rxfifo); > + > + printf("ftssp010: rev.=0x%08X, fifo=%d\n", chip->rev, chip->fifo); > + > + if (chip->rev >= 0x00011900) { > + if (cs > 3) > + return 0; > + } else { > +#ifdef CONFIG_FTSSP010_GPIO_BASE > + if (cs > 0) > + return 0; > + /* setup gpio pin as an output pin */ > + SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x08); > +#else > + return 0; > +#endif > + } > + > + return 1; > +} > + > +/*----------------------------------------------------------------------- > + * Activate a SPI chipselect. > + * This function is provided by the board code when using a driver > + * that can't control its chipselects automatically (e.g. > + * common/soft_spi.c). When called, it should activate the chip select > + * to the device identified by "slave". > + */ > +void spi_cs_activate(struct spi_slave *slave) > +{ > + struct ftssp010_chip *chip = chip_list + slave->bus; > + struct ftssp010_regs *regs = chip->iobase; > + > + /* cs pull low */ > + if (chip->rev >= 0x00011900) { > + SPI_WRITE((slave->cs << 10) | CR2_SSPEN | CR2_TXFCLR > + | CR2_RXFCLR, ®s->cr[2]); > + } else { > +#ifdef CONFIG_FTSSP010_GPIO_BASE > + SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x14); > +#endif > + } > + udelay_masked(1); > +} > + > +/*----------------------------------------------------------------------- > + * Deactivate a SPI chipselect. > + * This function is provided by the board code when using a driver > + * that can't control its chipselects automatically (e.g. > + * common/soft_spi.c). When called, it should deactivate the chip > + * select to the device identified by "slave". > + */ > +void spi_cs_deactivate(struct spi_slave *slave) > +{ > + struct ftssp010_chip *chip = chip_list + slave->bus; > + struct ftssp010_regs *regs = chip->iobase; > + > + /* wait until device idle */ > + while (SPI_READ(®s->sr) & SR_BUSY) > + ; > + > + /* cs pull high */ > + if (chip->rev >= 0x00011900) { > + SPI_WRITE((slave->cs << 10) | CR2_FS, ®s->cr[2]); > + } else { > +#ifdef CONFIG_FTSSP010_GPIO_BASE > + SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x10); > +#endif > + } > + udelay_masked(1); > +} > + > +void spi_init(void) > +{ > +} > + > +struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode) > +{ > + uint32_t clk, div; > + struct spi_slave *ss; > + struct ftssp010_chip *chip; > + > + if (!spi_cs_is_valid(bus, cs)) > + return NULL; > + > + if (mode != SPI_MODE_0) { > + printf("ftssp010: MODE%d is not supported\n", mode); > + return NULL; > + } > + > + ss = malloc(sizeof(struct spi_slave)); > + if (!ss) > + return NULL; > + > + ss->bus = bus; > + ss->cs = cs; > + > +#ifdef CONFIG_FTSSP010_SCLK > + clk = CONFIG_FTSSP010_SCLK; > +#else > + clk = clk_get_rate("SSP"); > +#endif > + if (max_hz > 0) { > + for (div = 0; div < 0xFFFF; ++div) { > + if ((clk / (2 * (div + 1))) <= max_hz) > + break; > + } > + } else { > + div = 7; > + } > + > + chip = chip_list + bus; > + chip->div = div; > + chip->mode = mode; > + > + printf("ftssp010: bus=%d, hz=%u\n", bus, (clk / (2 * (div + 1)))); > + > + return ss; > +} > + > +void spi_free_slave(struct spi_slave *slave) > +{ > + free(slave); > +} > + > +int spi_claim_bus(struct spi_slave *slave) > +{ > + struct ftssp010_chip *chip = chip_list + slave->bus; > + struct ftssp010_regs *regs = chip->iobase; > + > + SPI_WRITE(CR1_SDL(8) | CR1_CLKDIV(chip->div), ®s->cr[1]); > + > + if (chip->rev >= 0x00011900) { > + SPI_WRITE(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO | CR0_FLASH, > + ®s->cr[0]); > + SPI_WRITE(CR2_TXFCLR | CR2_RXFCLR, > + ®s->cr[2]); > + } else { > + SPI_WRITE(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO, > + ®s->cr[0]); > + SPI_WRITE(CR2_TXFCLR | CR2_RXFCLR | CR2_SSPEN | CR2_TXDOE, > + ®s->cr[2]); > + } > + > + spi_cs_deactivate(slave); > + > + return 0; > +} > + > +void spi_release_bus(struct spi_slave *slave) > +{ > + struct ftssp010_chip *chip = chip_list + slave->bus; > + struct ftssp010_regs *regs = chip->iobase; > + > + SPI_WRITE(0, ®s->cr[2]); > +} > + > +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, > + const void *dout, void *din, unsigned long flags) > +{ > + struct ftssp010_chip *chip = chip_list + slave->bus; > + uint32_t len = bitlen >> 3; > + > + if (flags & SPI_XFER_BEGIN) > + spi_cs_activate(slave); > + > + if (chip->rev >= 0x00011900) > + ftssp010_spi_work_transfer_v1_19(chip, dout, din, len, flags); > + else > + ftssp010_spi_work_transfer(chip, dout, din, len, flags); > + > + if (flags & SPI_XFER_END) > + spi_cs_deactivate(slave); > + > + return 0; > +} > diff --git a/drivers/spi/ftssp010_spi.h b/drivers/spi/ftssp010_spi.h > new file mode 100644 > index 0000000..5ad7c47 > --- /dev/null > +++ b/drivers/spi/ftssp010_spi.h > @@ -0,0 +1,86 @@ > +/* > + * Faraday Multi-function Controller - SPI Mode > + * > + * (C) Copyright 2010 Faraday Technology > + * Dante Su <dantesu@faraday-tech.com> > + * > + * This file is released under the terms of GPL v2 and any later version. > + * See the file COPYING in the root directory of the source tree for details. > + */ > + > +#ifndef _FTSSP010_H > +#define _FTSSP010_H > + > +/* FTSSP010 HW Registers */ > +struct ftssp010_regs { > + uint32_t cr[3];/* control register */ > + uint32_t sr; /* status register */ > + uint32_t icr; /* interrupt control register */ > + uint32_t isr; /* interrupt status register */ > + uint32_t dr; /* data register */ > + uint32_t rsvd[17]; > + uint32_t revr; /* revision register */ > + uint32_t fear; /* feature register */ > +}; > + > +/* Control register 0 */ > +#define CR0_FFMT_MASK (7 << 12) > +#define CR0_FFMT_SSP (0 << 12) > +#define CR0_FFMT_SPI (1 << 12) > +#define CR0_FFMT_MICROWIRE (2 << 12) > +#define CR0_FFMT_I2S (3 << 12) > +#define CR0_FFMT_AC97 (4 << 12) > +#define CR0_FLASH (1 << 11) > +#define CR0_FSDIST(x) (((x) & 0x03) << 8) > +#define CR0_LBM (1 << 7) /* Loopback mode */ > +#define CR0_LSB (1 << 6) /* LSB first */ > +#define CR0_FSPO (1 << 5) /* Frame sync atcive low */ > +#define CR0_FSJUSTIFY (1 << 4) > +#define CR0_OPM_SLAVE (0 << 2) > +#define CR0_OPM_MASTER (3 << 2) > +#define CR0_OPM_I2S_MSST (3 << 2) /* Master stereo mode */ > +#define CR0_OPM_I2S_MSMO (2 << 2) /* Master mono mode */ > +#define CR0_OPM_I2S_SLST (1 << 2) /* Slave stereo mode */ > +#define CR0_OPM_I2S_SLMO (0 << 2) /* Slave mono mode */ > +#define CR0_SCLKPO (1 << 1) /* SCLK Remain HIGH */ > +#define CR0_SCLKPH (1 << 0) /* Half CLK cycle */ > + > +/* Control Register 1 */ > + > +#define CR1_PDL(x) (((x) & 0xff) << 24) /* padding length */ > +#define CR1_SDL(x) ((((x) - 1) & 0x1f) << 16) /* data length */ > +#define CR1_CLKDIV(x) ((x) & 0xffff) /* clk divider */ > + > +/* Control Register 2 */ > +#define CR2_FSOS(x) (((x) & 0x03) << 10) /* FS/CS Select */ > +#define CR2_FS (1 << 9) /* FS/CS Signal Level */ > +#define CR2_TXEN (1 << 8) /* Tx Enable */ > +#define CR2_RXEN (1 << 7) /* Rx Enable */ > +#define CR2_SSPRST (1 << 6) /* SSP reset */ > +#define CR2_TXFCLR (1 << 3) /* TX FIFO Clear */ > +#define CR2_RXFCLR (1 << 2) /* RX FIFO Clear */ > +#define CR2_TXDOE (1 << 1) /* TX Data Output Enable */ > +#define CR2_SSPEN (1 << 0) /* SSP Enable */ > + > +/* > + * Status Register > + */ > +#define SR_RFF (1 << 0) /* receive FIFO full */ > +#define SR_TFNF (1 << 1) /* transmit FIFO not full */ > +#define SR_BUSY (1 << 2) /* bus is busy */ > +#define SR_RFVE(reg) (((reg) >> 4) & 0x1f) /* receive FIFO valid entries */ > +#define SR_TFVE(reg) (((reg) >> 12) & 0x1f) /* transmit FIFO valid entries */ > + > +/* > + * Feature Register > + */ > +#define FEAR_WIDTH(reg) ((((reg) >> 0) & 0xff) + 1) > +#define FEAR_RXFIFO(reg) ((((reg) >> 8) & 0xff) + 1) > +#define FEAR_TXFIFO(reg) ((((reg) >> 16) & 0xff) + 1) > +#define FEAR_AC97 (1 << 24) > +#define FEAR_I2S (1 << 25) > +#define FEAR_SPI_MWR (1 << 26) > +#define FEAR_SSP (1 << 27) > +#define FEAR_SPDIF (1 << 28) > + > +#endif > -- > 1.7.9.5 > > _______________________________________________ > U-Boot mailing list > U-Boot@lists.denx.de > http://lists.denx.de/mailman/listinfo/u-boot
Hi Jagan: Thanks for the comments, but the [spi bus controller: ftssp010] has been scheduled after the [Faraday A36x platform support] get approved. In this way, the entire patch itself looks much better & clean. Best Wishes Dante Su 2013/8/8 Jagan Teki <jagannadh.teki@gmail.com>: > Hi Kuo-Jung Su, > > Please fix the comments I sent on v4. > http://patchwork.ozlabs.org/patch/242023/ > > Feel free to ask for any quires. > > Thanks, > Jagan. > > On Thu, Apr 18, 2013 at 2:55 PM, Kuo-Jung Su <dantesu@gmail.com> wrote: >> From: Kuo-Jung Su <dantesu@faraday-tech.com> >> >> The Faraday FTSSP010 is a multi-function controller >> which supports I2S/SPI/SSP/AC97/SPDIF. >> This patch simpily implements the SPI mode only. >> BTW the DMA and CS/Clock control logic has been >> altered since revision 1.19.0. So this patch >> would 1st detects the revision id of the underlying >> chip, and then switch to the corresponding control >> routines. >> >> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com> >> --- >> drivers/spi/Makefile | 1 + >> drivers/spi/ftssp010_spi.c | 337 ++++++++++++++++++++++++++++++++++++++++++++ >> drivers/spi/ftssp010_spi.h | 86 +++++++++++ >> 3 files changed, 424 insertions(+) >> create mode 100644 drivers/spi/ftssp010_spi.c >> create mode 100644 drivers/spi/ftssp010_spi.h >> >> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile >> index d08609e..947d60e 100644 >> --- a/drivers/spi/Makefile >> +++ b/drivers/spi/Makefile >> @@ -38,6 +38,7 @@ 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 >> +COBJS-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o >> COBJS-$(CONFIG_EXYNOS_SPI) += exynos_spi.o >> COBJS-$(CONFIG_ICH_SPI) += ich.o >> COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o >> diff --git a/drivers/spi/ftssp010_spi.c b/drivers/spi/ftssp010_spi.c >> new file mode 100644 >> index 0000000..4247c8c >> --- /dev/null >> +++ b/drivers/spi/ftssp010_spi.c >> @@ -0,0 +1,337 @@ >> +/* >> + * Faraday Multi-function Controller - SPI Mode >> + * >> + * (C) Copyright 2010 Faraday Technology >> + * Dante Su <dantesu@faraday-tech.com> >> + * >> + * This file is released under the terms of GPL v2 and any later version. >> + * See the file COPYING in the root directory of the source tree for details. >> + */ >> + >> +#include <common.h> >> +#include <asm/io.h> >> +#include <spi.h> >> +#include <malloc.h> >> + >> +#include "ftssp010_spi.h" >> + >> +struct ftssp010_chip { >> + void *iobase; >> + uint32_t fifo; >> + uint32_t rev; >> + uint32_t div; >> + uint32_t mode; >> + >> + struct { >> + uint32_t iobase; >> + uint32_t pin; >> + } gpio; >> +}; >> + >> +static struct ftssp010_chip chip_list[] = { >> +#if defined(CONFIG_FTSSP010_BASE) || defined(CONFIG_FTSSP010_BASE0) >> + { >> + .iobase = (void *)CONFIG_FTSSP010_BASE, >> +#ifdef CONFIG_FTSSP010_GPIO_BASE >> + .gpio = { CONFIG_FTSSP010_GPIO_BASE, CONFIG_FTSSP010_GPIO_PIN }, >> +#endif >> + }, >> +#endif >> +#ifdef CONFIG_FTSSP010_BASE1 >> + { .iobase = (void *)CONFIG_FTSSP010_BASE1, }, >> +#endif >> +#ifdef CONFIG_FTSSP010_BASE2 >> + { .iobase = (void *)CONFIG_FTSSP010_BASE2, }, >> +#endif >> +#ifdef CONFIG_FTSSP010_BASE3 >> + { .iobase = (void *)CONFIG_FTSSP010_BASE3, }, >> +#endif >> +}; >> + >> +/* Register access macros */ >> +#define SPI_READ(r) le32_to_cpu(readl(r)) >> +#define SPI_WRITE(v, r) writel(cpu_to_le32(v), r) >> +#define SPI_SETBITS(m, r) setbits_le32(r, m) >> +#define SPI_CLRBITS(m, r) clrbits_le32(r, m) >> + >> +#ifdef CONFIG_FTSSP010_GPIO_BASE >> +#define SPI_GPIO_READ(p, r) \ >> + le32_to_cpu(readl((p)->gpio.iobase + (r))) >> +#define SPI_GPIO_WRITE(p, v, r) \ >> + writel(cpu_to_le32(v), (p)->gpio.iobase + (r)) >> +#define SPI_GPIO_SETBITS(p, m, r) \ >> + setbits_le32((p)->gpio.iobase + (r), m) >> +#define SPI_GPIO_CLRBITS(p, m, r) \ >> + clrbits_le32((p)->gpio.iobase + (r), m) >> +#endif /* #ifdef CONFIG_FTSSP010_GPIO_BASE */ >> + >> +static int ftssp010_spi_work_transfer_v1_19(struct ftssp010_chip *chip, >> + const void *tx_buf, void *rx_buf, int len, uint flags) >> +{ >> + struct ftssp010_regs *regs = chip->iobase; >> + const uint8_t *txb = tx_buf; >> + uint8_t *rxb = rx_buf; >> + >> + while (len > 0) { >> + int i, depth = min(chip->fifo >> 2, len); >> + uint32_t xmsk = 0; >> + >> + if (tx_buf) { >> + for (i = 0; i < depth; ++i) { >> + while (!(SPI_READ(®s->sr) & SR_TFNF)) >> + ; >> + SPI_WRITE(*txb++, ®s->dr); >> + } >> + xmsk |= CR2_TXEN | CR2_TXDOE; >> + if ((SPI_READ(®s->cr[2]) & xmsk) != xmsk) >> + SPI_SETBITS(xmsk, ®s->cr[2]); >> + } >> + if (rx_buf) { >> + xmsk |= CR2_RXEN; >> + if ((SPI_READ(®s->cr[2]) & xmsk) != xmsk) >> + SPI_SETBITS(xmsk, ®s->cr[2]); >> + for (i = 0; i < depth; ++i) { >> + while (!SR_RFVE(SPI_READ(®s->sr))) >> + ; >> + *rxb++ = (uint8_t)SPI_READ(®s->dr); >> + } >> + } >> + >> + len -= depth; >> + } >> + >> + return 0; >> +} >> + >> +static int ftssp010_spi_work_transfer(struct ftssp010_chip *chip, >> + const void *tx_buf, void *rx_buf, int len, uint flags) >> +{ >> + struct ftssp010_regs *regs = chip->iobase; >> + const uint8_t *txb = tx_buf; >> + uint8_t *rxb = rx_buf; >> + >> + while (len > 0) { >> + int i, depth = min(chip->fifo >> 2, len); >> + uint32_t tmp; >> + >> + for (i = 0; i < depth; ++i) { >> + while (!(SPI_READ(®s->sr) & SR_TFNF)) >> + ; >> + SPI_WRITE(txb ? (*txb++) : 0, ®s->dr); >> + } >> + for (i = 0; i < depth; ++i) { >> + while (!SR_RFVE(SPI_READ(®s->sr))) >> + ; >> + tmp = SPI_READ(®s->dr); >> + if (rxb) >> + *rxb++ = (uint8_t)tmp; >> + } >> + >> + len -= depth; >> + } >> + >> + return 0; >> +} >> + >> +/*=====================================================================*/ >> +/* Public Functions */ >> +/*=====================================================================*/ >> + >> +/*----------------------------------------------------------------------- >> + * Determine if a SPI chipselect is valid. >> + * This function is provided by the board if the low-level SPI driver >> + * needs it to determine if a given chipselect is actually valid. >> + * >> + * Returns: 1 if bus:cs identifies a valid chip on this board, 0 >> + * otherwise. >> + */ >> +int spi_cs_is_valid(unsigned int bus, unsigned int cs) >> +{ >> + struct ftssp010_chip *chip; >> + struct ftssp010_regs *regs; >> + uint32_t txfifo, rxfifo; >> + >> + if (bus >= ARRAY_SIZE(chip_list)) >> + return 0; >> + >> + chip = chip_list + bus; >> + regs = chip->iobase; >> + chip->rev = SPI_READ(®s->revr); >> + txfifo = FEAR_TXFIFO(SPI_READ(®s->fear)); >> + rxfifo = FEAR_RXFIFO(SPI_READ(®s->fear)); >> + chip->fifo = min(txfifo, rxfifo); >> + >> + printf("ftssp010: rev.=0x%08X, fifo=%d\n", chip->rev, chip->fifo); >> + >> + if (chip->rev >= 0x00011900) { >> + if (cs > 3) >> + return 0; >> + } else { >> +#ifdef CONFIG_FTSSP010_GPIO_BASE >> + if (cs > 0) >> + return 0; >> + /* setup gpio pin as an output pin */ >> + SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x08); >> +#else >> + return 0; >> +#endif >> + } >> + >> + return 1; >> +} >> + >> +/*----------------------------------------------------------------------- >> + * Activate a SPI chipselect. >> + * This function is provided by the board code when using a driver >> + * that can't control its chipselects automatically (e.g. >> + * common/soft_spi.c). When called, it should activate the chip select >> + * to the device identified by "slave". >> + */ >> +void spi_cs_activate(struct spi_slave *slave) >> +{ >> + struct ftssp010_chip *chip = chip_list + slave->bus; >> + struct ftssp010_regs *regs = chip->iobase; >> + >> + /* cs pull low */ >> + if (chip->rev >= 0x00011900) { >> + SPI_WRITE((slave->cs << 10) | CR2_SSPEN | CR2_TXFCLR >> + | CR2_RXFCLR, ®s->cr[2]); >> + } else { >> +#ifdef CONFIG_FTSSP010_GPIO_BASE >> + SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x14); >> +#endif >> + } >> + udelay_masked(1); >> +} >> + >> +/*----------------------------------------------------------------------- >> + * Deactivate a SPI chipselect. >> + * This function is provided by the board code when using a driver >> + * that can't control its chipselects automatically (e.g. >> + * common/soft_spi.c). When called, it should deactivate the chip >> + * select to the device identified by "slave". >> + */ >> +void spi_cs_deactivate(struct spi_slave *slave) >> +{ >> + struct ftssp010_chip *chip = chip_list + slave->bus; >> + struct ftssp010_regs *regs = chip->iobase; >> + >> + /* wait until device idle */ >> + while (SPI_READ(®s->sr) & SR_BUSY) >> + ; >> + >> + /* cs pull high */ >> + if (chip->rev >= 0x00011900) { >> + SPI_WRITE((slave->cs << 10) | CR2_FS, ®s->cr[2]); >> + } else { >> +#ifdef CONFIG_FTSSP010_GPIO_BASE >> + SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x10); >> +#endif >> + } >> + udelay_masked(1); >> +} >> + >> +void spi_init(void) >> +{ >> +} >> + >> +struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode) >> +{ >> + uint32_t clk, div; >> + struct spi_slave *ss; >> + struct ftssp010_chip *chip; >> + >> + if (!spi_cs_is_valid(bus, cs)) >> + return NULL; >> + >> + if (mode != SPI_MODE_0) { >> + printf("ftssp010: MODE%d is not supported\n", mode); >> + return NULL; >> + } >> + >> + ss = malloc(sizeof(struct spi_slave)); >> + if (!ss) >> + return NULL; >> + >> + ss->bus = bus; >> + ss->cs = cs; >> + >> +#ifdef CONFIG_FTSSP010_SCLK >> + clk = CONFIG_FTSSP010_SCLK; >> +#else >> + clk = clk_get_rate("SSP"); >> +#endif >> + if (max_hz > 0) { >> + for (div = 0; div < 0xFFFF; ++div) { >> + if ((clk / (2 * (div + 1))) <= max_hz) >> + break; >> + } >> + } else { >> + div = 7; >> + } >> + >> + chip = chip_list + bus; >> + chip->div = div; >> + chip->mode = mode; >> + >> + printf("ftssp010: bus=%d, hz=%u\n", bus, (clk / (2 * (div + 1)))); >> + >> + return ss; >> +} >> + >> +void spi_free_slave(struct spi_slave *slave) >> +{ >> + free(slave); >> +} >> + >> +int spi_claim_bus(struct spi_slave *slave) >> +{ >> + struct ftssp010_chip *chip = chip_list + slave->bus; >> + struct ftssp010_regs *regs = chip->iobase; >> + >> + SPI_WRITE(CR1_SDL(8) | CR1_CLKDIV(chip->div), ®s->cr[1]); >> + >> + if (chip->rev >= 0x00011900) { >> + SPI_WRITE(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO | CR0_FLASH, >> + ®s->cr[0]); >> + SPI_WRITE(CR2_TXFCLR | CR2_RXFCLR, >> + ®s->cr[2]); >> + } else { >> + SPI_WRITE(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO, >> + ®s->cr[0]); >> + SPI_WRITE(CR2_TXFCLR | CR2_RXFCLR | CR2_SSPEN | CR2_TXDOE, >> + ®s->cr[2]); >> + } >> + >> + spi_cs_deactivate(slave); >> + >> + return 0; >> +} >> + >> +void spi_release_bus(struct spi_slave *slave) >> +{ >> + struct ftssp010_chip *chip = chip_list + slave->bus; >> + struct ftssp010_regs *regs = chip->iobase; >> + >> + SPI_WRITE(0, ®s->cr[2]); >> +} >> + >> +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, >> + const void *dout, void *din, unsigned long flags) >> +{ >> + struct ftssp010_chip *chip = chip_list + slave->bus; >> + uint32_t len = bitlen >> 3; >> + >> + if (flags & SPI_XFER_BEGIN) >> + spi_cs_activate(slave); >> + >> + if (chip->rev >= 0x00011900) >> + ftssp010_spi_work_transfer_v1_19(chip, dout, din, len, flags); >> + else >> + ftssp010_spi_work_transfer(chip, dout, din, len, flags); >> + >> + if (flags & SPI_XFER_END) >> + spi_cs_deactivate(slave); >> + >> + return 0; >> +} >> diff --git a/drivers/spi/ftssp010_spi.h b/drivers/spi/ftssp010_spi.h >> new file mode 100644 >> index 0000000..5ad7c47 >> --- /dev/null >> +++ b/drivers/spi/ftssp010_spi.h >> @@ -0,0 +1,86 @@ >> +/* >> + * Faraday Multi-function Controller - SPI Mode >> + * >> + * (C) Copyright 2010 Faraday Technology >> + * Dante Su <dantesu@faraday-tech.com> >> + * >> + * This file is released under the terms of GPL v2 and any later version. >> + * See the file COPYING in the root directory of the source tree for details. >> + */ >> + >> +#ifndef _FTSSP010_H >> +#define _FTSSP010_H >> + >> +/* FTSSP010 HW Registers */ >> +struct ftssp010_regs { >> + uint32_t cr[3];/* control register */ >> + uint32_t sr; /* status register */ >> + uint32_t icr; /* interrupt control register */ >> + uint32_t isr; /* interrupt status register */ >> + uint32_t dr; /* data register */ >> + uint32_t rsvd[17]; >> + uint32_t revr; /* revision register */ >> + uint32_t fear; /* feature register */ >> +}; >> + >> +/* Control register 0 */ >> +#define CR0_FFMT_MASK (7 << 12) >> +#define CR0_FFMT_SSP (0 << 12) >> +#define CR0_FFMT_SPI (1 << 12) >> +#define CR0_FFMT_MICROWIRE (2 << 12) >> +#define CR0_FFMT_I2S (3 << 12) >> +#define CR0_FFMT_AC97 (4 << 12) >> +#define CR0_FLASH (1 << 11) >> +#define CR0_FSDIST(x) (((x) & 0x03) << 8) >> +#define CR0_LBM (1 << 7) /* Loopback mode */ >> +#define CR0_LSB (1 << 6) /* LSB first */ >> +#define CR0_FSPO (1 << 5) /* Frame sync atcive low */ >> +#define CR0_FSJUSTIFY (1 << 4) >> +#define CR0_OPM_SLAVE (0 << 2) >> +#define CR0_OPM_MASTER (3 << 2) >> +#define CR0_OPM_I2S_MSST (3 << 2) /* Master stereo mode */ >> +#define CR0_OPM_I2S_MSMO (2 << 2) /* Master mono mode */ >> +#define CR0_OPM_I2S_SLST (1 << 2) /* Slave stereo mode */ >> +#define CR0_OPM_I2S_SLMO (0 << 2) /* Slave mono mode */ >> +#define CR0_SCLKPO (1 << 1) /* SCLK Remain HIGH */ >> +#define CR0_SCLKPH (1 << 0) /* Half CLK cycle */ >> + >> +/* Control Register 1 */ >> + >> +#define CR1_PDL(x) (((x) & 0xff) << 24) /* padding length */ >> +#define CR1_SDL(x) ((((x) - 1) & 0x1f) << 16) /* data length */ >> +#define CR1_CLKDIV(x) ((x) & 0xffff) /* clk divider */ >> + >> +/* Control Register 2 */ >> +#define CR2_FSOS(x) (((x) & 0x03) << 10) /* FS/CS Select */ >> +#define CR2_FS (1 << 9) /* FS/CS Signal Level */ >> +#define CR2_TXEN (1 << 8) /* Tx Enable */ >> +#define CR2_RXEN (1 << 7) /* Rx Enable */ >> +#define CR2_SSPRST (1 << 6) /* SSP reset */ >> +#define CR2_TXFCLR (1 << 3) /* TX FIFO Clear */ >> +#define CR2_RXFCLR (1 << 2) /* RX FIFO Clear */ >> +#define CR2_TXDOE (1 << 1) /* TX Data Output Enable */ >> +#define CR2_SSPEN (1 << 0) /* SSP Enable */ >> + >> +/* >> + * Status Register >> + */ >> +#define SR_RFF (1 << 0) /* receive FIFO full */ >> +#define SR_TFNF (1 << 1) /* transmit FIFO not full */ >> +#define SR_BUSY (1 << 2) /* bus is busy */ >> +#define SR_RFVE(reg) (((reg) >> 4) & 0x1f) /* receive FIFO valid entries */ >> +#define SR_TFVE(reg) (((reg) >> 12) & 0x1f) /* transmit FIFO valid entries */ >> + >> +/* >> + * Feature Register >> + */ >> +#define FEAR_WIDTH(reg) ((((reg) >> 0) & 0xff) + 1) >> +#define FEAR_RXFIFO(reg) ((((reg) >> 8) & 0xff) + 1) >> +#define FEAR_TXFIFO(reg) ((((reg) >> 16) & 0xff) + 1) >> +#define FEAR_AC97 (1 << 24) >> +#define FEAR_I2S (1 << 25) >> +#define FEAR_SPI_MWR (1 << 26) >> +#define FEAR_SSP (1 << 27) >> +#define FEAR_SPDIF (1 << 28) >> + >> +#endif >> -- >> 1.7.9.5 >> >> _______________________________________________ >> U-Boot mailing list >> U-Boot@lists.denx.de >> http://lists.denx.de/mailman/listinfo/u-boot
On Fri, Aug 9, 2013 at 6:17 AM, Kuo-Jung Su <dantesu@gmail.com> wrote: > Hi Jagan: > > Thanks for the comments, but the [spi bus controller: ftssp010] > > has been scheduled after the [Faraday A36x platform support] get approved. > > In this way, the entire patch itself looks much better & clean. > > Best Wishes > > Dante Su > > 2013/8/8 Jagan Teki <jagannadh.teki@gmail.com>: >> Hi Kuo-Jung Su, >> >> Please fix the comments I sent on v4. >> http://patchwork.ozlabs.org/patch/242023/ >> >> Feel free to ask for any quires. >> >> Thanks, >> Jagan. >> >> On Thu, Apr 18, 2013 at 2:55 PM, Kuo-Jung Su <dantesu@gmail.com> wrote: >>> From: Kuo-Jung Su <dantesu@faraday-tech.com> >>> >>> The Faraday FTSSP010 is a multi-function controller >>> which supports I2S/SPI/SSP/AC97/SPDIF. >>> This patch simpily implements the SPI mode only. >>> BTW the DMA and CS/Clock control logic has been >>> altered since revision 1.19.0. So this patch >>> would 1st detects the revision id of the underlying >>> chip, and then switch to the corresponding control >>> routines. >>> >>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com> >>> --- >>> drivers/spi/Makefile | 1 + >>> drivers/spi/ftssp010_spi.c | 337 ++++++++++++++++++++++++++++++++++++++++++++ >>> drivers/spi/ftssp010_spi.h | 86 +++++++++++ >>> 3 files changed, 424 insertions(+) >>> create mode 100644 drivers/spi/ftssp010_spi.c >>> create mode 100644 drivers/spi/ftssp010_spi.h >>> >>> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile >>> index d08609e..947d60e 100644 >>> --- a/drivers/spi/Makefile >>> +++ b/drivers/spi/Makefile >>> @@ -38,6 +38,7 @@ 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 >>> +COBJS-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o >>> COBJS-$(CONFIG_EXYNOS_SPI) += exynos_spi.o >>> COBJS-$(CONFIG_ICH_SPI) += ich.o >>> COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o >>> diff --git a/drivers/spi/ftssp010_spi.c b/drivers/spi/ftssp010_spi.c >>> new file mode 100644 >>> index 0000000..4247c8c >>> --- /dev/null >>> +++ b/drivers/spi/ftssp010_spi.c >>> @@ -0,0 +1,337 @@ >>> +/* >>> + * Faraday Multi-function Controller - SPI Mode >>> + * >>> + * (C) Copyright 2010 Faraday Technology >>> + * Dante Su <dantesu@faraday-tech.com> >>> + * >>> + * This file is released under the terms of GPL v2 and any later version. >>> + * See the file COPYING in the root directory of the source tree for details. >>> + */ >>> + >>> +#include <common.h> >>> +#include <asm/io.h> >>> +#include <spi.h> >>> +#include <malloc.h> >>> + >>> +#include "ftssp010_spi.h" >>> + >>> +struct ftssp010_chip { >>> + void *iobase; >>> + uint32_t fifo; >>> + uint32_t rev; >>> + uint32_t div; >>> + uint32_t mode; >>> + >>> + struct { >>> + uint32_t iobase; >>> + uint32_t pin; >>> + } gpio; >>> +}; >>> + >>> +static struct ftssp010_chip chip_list[] = { >>> +#if defined(CONFIG_FTSSP010_BASE) || defined(CONFIG_FTSSP010_BASE0) >>> + { >>> + .iobase = (void *)CONFIG_FTSSP010_BASE, >>> +#ifdef CONFIG_FTSSP010_GPIO_BASE >>> + .gpio = { CONFIG_FTSSP010_GPIO_BASE, CONFIG_FTSSP010_GPIO_PIN }, >>> +#endif >>> + }, >>> +#endif >>> +#ifdef CONFIG_FTSSP010_BASE1 >>> + { .iobase = (void *)CONFIG_FTSSP010_BASE1, }, >>> +#endif >>> +#ifdef CONFIG_FTSSP010_BASE2 >>> + { .iobase = (void *)CONFIG_FTSSP010_BASE2, }, >>> +#endif >>> +#ifdef CONFIG_FTSSP010_BASE3 >>> + { .iobase = (void *)CONFIG_FTSSP010_BASE3, }, >>> +#endif >>> +}; >>> + >>> +/* Register access macros */ >>> +#define SPI_READ(r) le32_to_cpu(readl(r)) >>> +#define SPI_WRITE(v, r) writel(cpu_to_le32(v), r) >>> +#define SPI_SETBITS(m, r) setbits_le32(r, m) >>> +#define SPI_CLRBITS(m, r) clrbits_le32(r, m) >>> + >>> +#ifdef CONFIG_FTSSP010_GPIO_BASE >>> +#define SPI_GPIO_READ(p, r) \ >>> + le32_to_cpu(readl((p)->gpio.iobase + (r))) >>> +#define SPI_GPIO_WRITE(p, v, r) \ >>> + writel(cpu_to_le32(v), (p)->gpio.iobase + (r)) >>> +#define SPI_GPIO_SETBITS(p, m, r) \ >>> + setbits_le32((p)->gpio.iobase + (r), m) >>> +#define SPI_GPIO_CLRBITS(p, m, r) \ >>> + clrbits_le32((p)->gpio.iobase + (r), m) >>> +#endif /* #ifdef CONFIG_FTSSP010_GPIO_BASE */ >>> + >>> +static int ftssp010_spi_work_transfer_v1_19(struct ftssp010_chip *chip, >>> + const void *tx_buf, void *rx_buf, int len, uint flags) >>> +{ >>> + struct ftssp010_regs *regs = chip->iobase; >>> + const uint8_t *txb = tx_buf; >>> + uint8_t *rxb = rx_buf; >>> + >>> + while (len > 0) { >>> + int i, depth = min(chip->fifo >> 2, len); >>> + uint32_t xmsk = 0; >>> + >>> + if (tx_buf) { >>> + for (i = 0; i < depth; ++i) { >>> + while (!(SPI_READ(®s->sr) & SR_TFNF)) >>> + ; >>> + SPI_WRITE(*txb++, ®s->dr); >>> + } >>> + xmsk |= CR2_TXEN | CR2_TXDOE; >>> + if ((SPI_READ(®s->cr[2]) & xmsk) != xmsk) >>> + SPI_SETBITS(xmsk, ®s->cr[2]); >>> + } >>> + if (rx_buf) { >>> + xmsk |= CR2_RXEN; >>> + if ((SPI_READ(®s->cr[2]) & xmsk) != xmsk) >>> + SPI_SETBITS(xmsk, ®s->cr[2]); >>> + for (i = 0; i < depth; ++i) { >>> + while (!SR_RFVE(SPI_READ(®s->sr))) >>> + ; >>> + *rxb++ = (uint8_t)SPI_READ(®s->dr); >>> + } >>> + } >>> + >>> + len -= depth; >>> + } >>> + >>> + return 0; >>> +} >>> + >>> +static int ftssp010_spi_work_transfer(struct ftssp010_chip *chip, >>> + const void *tx_buf, void *rx_buf, int len, uint flags) >>> +{ >>> + struct ftssp010_regs *regs = chip->iobase; >>> + const uint8_t *txb = tx_buf; >>> + uint8_t *rxb = rx_buf; >>> + >>> + while (len > 0) { >>> + int i, depth = min(chip->fifo >> 2, len); >>> + uint32_t tmp; >>> + >>> + for (i = 0; i < depth; ++i) { >>> + while (!(SPI_READ(®s->sr) & SR_TFNF)) >>> + ; >>> + SPI_WRITE(txb ? (*txb++) : 0, ®s->dr); >>> + } >>> + for (i = 0; i < depth; ++i) { >>> + while (!SR_RFVE(SPI_READ(®s->sr))) >>> + ; >>> + tmp = SPI_READ(®s->dr); >>> + if (rxb) >>> + *rxb++ = (uint8_t)tmp; >>> + } >>> + >>> + len -= depth; >>> + } >>> + >>> + return 0; >>> +} >>> + >>> +/*=====================================================================*/ >>> +/* Public Functions */ >>> +/*=====================================================================*/ >>> + >>> +/*----------------------------------------------------------------------- >>> + * Determine if a SPI chipselect is valid. >>> + * This function is provided by the board if the low-level SPI driver >>> + * needs it to determine if a given chipselect is actually valid. >>> + * >>> + * Returns: 1 if bus:cs identifies a valid chip on this board, 0 >>> + * otherwise. >>> + */ >>> +int spi_cs_is_valid(unsigned int bus, unsigned int cs) >>> +{ >>> + struct ftssp010_chip *chip; >>> + struct ftssp010_regs *regs; >>> + uint32_t txfifo, rxfifo; >>> + >>> + if (bus >= ARRAY_SIZE(chip_list)) >>> + return 0; >>> + >>> + chip = chip_list + bus; >>> + regs = chip->iobase; >>> + chip->rev = SPI_READ(®s->revr); >>> + txfifo = FEAR_TXFIFO(SPI_READ(®s->fear)); >>> + rxfifo = FEAR_RXFIFO(SPI_READ(®s->fear)); >>> + chip->fifo = min(txfifo, rxfifo); >>> + >>> + printf("ftssp010: rev.=0x%08X, fifo=%d\n", chip->rev, chip->fifo); >>> + >>> + if (chip->rev >= 0x00011900) { >>> + if (cs > 3) >>> + return 0; >>> + } else { >>> +#ifdef CONFIG_FTSSP010_GPIO_BASE >>> + if (cs > 0) >>> + return 0; >>> + /* setup gpio pin as an output pin */ >>> + SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x08); >>> +#else >>> + return 0; >>> +#endif >>> + } >>> + >>> + return 1; >>> +} >>> + >>> +/*----------------------------------------------------------------------- >>> + * Activate a SPI chipselect. >>> + * This function is provided by the board code when using a driver >>> + * that can't control its chipselects automatically (e.g. >>> + * common/soft_spi.c). When called, it should activate the chip select >>> + * to the device identified by "slave". >>> + */ >>> +void spi_cs_activate(struct spi_slave *slave) >>> +{ >>> + struct ftssp010_chip *chip = chip_list + slave->bus; >>> + struct ftssp010_regs *regs = chip->iobase; >>> + >>> + /* cs pull low */ >>> + if (chip->rev >= 0x00011900) { >>> + SPI_WRITE((slave->cs << 10) | CR2_SSPEN | CR2_TXFCLR >>> + | CR2_RXFCLR, ®s->cr[2]); >>> + } else { >>> +#ifdef CONFIG_FTSSP010_GPIO_BASE >>> + SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x14); >>> +#endif >>> + } >>> + udelay_masked(1); >>> +} >>> + >>> +/*----------------------------------------------------------------------- >>> + * Deactivate a SPI chipselect. >>> + * This function is provided by the board code when using a driver >>> + * that can't control its chipselects automatically (e.g. >>> + * common/soft_spi.c). When called, it should deactivate the chip >>> + * select to the device identified by "slave". >>> + */ >>> +void spi_cs_deactivate(struct spi_slave *slave) >>> +{ >>> + struct ftssp010_chip *chip = chip_list + slave->bus; >>> + struct ftssp010_regs *regs = chip->iobase; >>> + >>> + /* wait until device idle */ >>> + while (SPI_READ(®s->sr) & SR_BUSY) >>> + ; >>> + >>> + /* cs pull high */ >>> + if (chip->rev >= 0x00011900) { >>> + SPI_WRITE((slave->cs << 10) | CR2_FS, ®s->cr[2]); >>> + } else { >>> +#ifdef CONFIG_FTSSP010_GPIO_BASE >>> + SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x10); >>> +#endif >>> + } >>> + udelay_masked(1); >>> +} >>> + >>> +void spi_init(void) >>> +{ >>> +} >>> + >>> +struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode) >>> +{ >>> + uint32_t clk, div; >>> + struct spi_slave *ss; >>> + struct ftssp010_chip *chip; >>> + >>> + if (!spi_cs_is_valid(bus, cs)) >>> + return NULL; >>> + >>> + if (mode != SPI_MODE_0) { >>> + printf("ftssp010: MODE%d is not supported\n", mode); >>> + return NULL; >>> + } >>> + >>> + ss = malloc(sizeof(struct spi_slave)); >>> + if (!ss) >>> + return NULL; >>> + >>> + ss->bus = bus; >>> + ss->cs = cs; >>> + >>> +#ifdef CONFIG_FTSSP010_SCLK >>> + clk = CONFIG_FTSSP010_SCLK; >>> +#else >>> + clk = clk_get_rate("SSP"); >>> +#endif >>> + if (max_hz > 0) { >>> + for (div = 0; div < 0xFFFF; ++div) { >>> + if ((clk / (2 * (div + 1))) <= max_hz) >>> + break; >>> + } >>> + } else { >>> + div = 7; >>> + } >>> + >>> + chip = chip_list + bus; >>> + chip->div = div; >>> + chip->mode = mode; >>> + >>> + printf("ftssp010: bus=%d, hz=%u\n", bus, (clk / (2 * (div + 1)))); >>> + >>> + return ss; >>> +} >>> + >>> +void spi_free_slave(struct spi_slave *slave) >>> +{ >>> + free(slave); >>> +} >>> + >>> +int spi_claim_bus(struct spi_slave *slave) >>> +{ >>> + struct ftssp010_chip *chip = chip_list + slave->bus; >>> + struct ftssp010_regs *regs = chip->iobase; >>> + >>> + SPI_WRITE(CR1_SDL(8) | CR1_CLKDIV(chip->div), ®s->cr[1]); >>> + >>> + if (chip->rev >= 0x00011900) { >>> + SPI_WRITE(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO | CR0_FLASH, >>> + ®s->cr[0]); >>> + SPI_WRITE(CR2_TXFCLR | CR2_RXFCLR, >>> + ®s->cr[2]); >>> + } else { >>> + SPI_WRITE(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO, >>> + ®s->cr[0]); >>> + SPI_WRITE(CR2_TXFCLR | CR2_RXFCLR | CR2_SSPEN | CR2_TXDOE, >>> + ®s->cr[2]); >>> + } >>> + >>> + spi_cs_deactivate(slave); >>> + >>> + return 0; >>> +} >>> + >>> +void spi_release_bus(struct spi_slave *slave) >>> +{ >>> + struct ftssp010_chip *chip = chip_list + slave->bus; >>> + struct ftssp010_regs *regs = chip->iobase; >>> + >>> + SPI_WRITE(0, ®s->cr[2]); >>> +} >>> + >>> +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, >>> + const void *dout, void *din, unsigned long flags) >>> +{ >>> + struct ftssp010_chip *chip = chip_list + slave->bus; >>> + uint32_t len = bitlen >> 3; >>> + >>> + if (flags & SPI_XFER_BEGIN) >>> + spi_cs_activate(slave); >>> + >>> + if (chip->rev >= 0x00011900) >>> + ftssp010_spi_work_transfer_v1_19(chip, dout, din, len, flags); >>> + else >>> + ftssp010_spi_work_transfer(chip, dout, din, len, flags); >>> + >>> + if (flags & SPI_XFER_END) >>> + spi_cs_deactivate(slave); >>> + >>> + return 0; >>> +} >>> diff --git a/drivers/spi/ftssp010_spi.h b/drivers/spi/ftssp010_spi.h >>> new file mode 100644 >>> index 0000000..5ad7c47 >>> --- /dev/null >>> +++ b/drivers/spi/ftssp010_spi.h >>> @@ -0,0 +1,86 @@ >>> +/* >>> + * Faraday Multi-function Controller - SPI Mode >>> + * >>> + * (C) Copyright 2010 Faraday Technology >>> + * Dante Su <dantesu@faraday-tech.com> >>> + * >>> + * This file is released under the terms of GPL v2 and any later version. >>> + * See the file COPYING in the root directory of the source tree for details. >>> + */ >>> + >>> +#ifndef _FTSSP010_H >>> +#define _FTSSP010_H >>> + >>> +/* FTSSP010 HW Registers */ >>> +struct ftssp010_regs { >>> + uint32_t cr[3];/* control register */ >>> + uint32_t sr; /* status register */ >>> + uint32_t icr; /* interrupt control register */ >>> + uint32_t isr; /* interrupt status register */ >>> + uint32_t dr; /* data register */ >>> + uint32_t rsvd[17]; >>> + uint32_t revr; /* revision register */ >>> + uint32_t fear; /* feature register */ >>> +}; >>> + >>> +/* Control register 0 */ >>> +#define CR0_FFMT_MASK (7 << 12) >>> +#define CR0_FFMT_SSP (0 << 12) >>> +#define CR0_FFMT_SPI (1 << 12) >>> +#define CR0_FFMT_MICROWIRE (2 << 12) >>> +#define CR0_FFMT_I2S (3 << 12) >>> +#define CR0_FFMT_AC97 (4 << 12) >>> +#define CR0_FLASH (1 << 11) >>> +#define CR0_FSDIST(x) (((x) & 0x03) << 8) >>> +#define CR0_LBM (1 << 7) /* Loopback mode */ >>> +#define CR0_LSB (1 << 6) /* LSB first */ >>> +#define CR0_FSPO (1 << 5) /* Frame sync atcive low */ >>> +#define CR0_FSJUSTIFY (1 << 4) >>> +#define CR0_OPM_SLAVE (0 << 2) >>> +#define CR0_OPM_MASTER (3 << 2) >>> +#define CR0_OPM_I2S_MSST (3 << 2) /* Master stereo mode */ >>> +#define CR0_OPM_I2S_MSMO (2 << 2) /* Master mono mode */ >>> +#define CR0_OPM_I2S_SLST (1 << 2) /* Slave stereo mode */ >>> +#define CR0_OPM_I2S_SLMO (0 << 2) /* Slave mono mode */ >>> +#define CR0_SCLKPO (1 << 1) /* SCLK Remain HIGH */ >>> +#define CR0_SCLKPH (1 << 0) /* Half CLK cycle */ >>> + >>> +/* Control Register 1 */ >>> + >>> +#define CR1_PDL(x) (((x) & 0xff) << 24) /* padding length */ >>> +#define CR1_SDL(x) ((((x) - 1) & 0x1f) << 16) /* data length */ >>> +#define CR1_CLKDIV(x) ((x) & 0xffff) /* clk divider */ >>> + >>> +/* Control Register 2 */ >>> +#define CR2_FSOS(x) (((x) & 0x03) << 10) /* FS/CS Select */ >>> +#define CR2_FS (1 << 9) /* FS/CS Signal Level */ >>> +#define CR2_TXEN (1 << 8) /* Tx Enable */ >>> +#define CR2_RXEN (1 << 7) /* Rx Enable */ >>> +#define CR2_SSPRST (1 << 6) /* SSP reset */ >>> +#define CR2_TXFCLR (1 << 3) /* TX FIFO Clear */ >>> +#define CR2_RXFCLR (1 << 2) /* RX FIFO Clear */ >>> +#define CR2_TXDOE (1 << 1) /* TX Data Output Enable */ >>> +#define CR2_SSPEN (1 << 0) /* SSP Enable */ >>> + >>> +/* >>> + * Status Register >>> + */ >>> +#define SR_RFF (1 << 0) /* receive FIFO full */ >>> +#define SR_TFNF (1 << 1) /* transmit FIFO not full */ >>> +#define SR_BUSY (1 << 2) /* bus is busy */ >>> +#define SR_RFVE(reg) (((reg) >> 4) & 0x1f) /* receive FIFO valid entries */ >>> +#define SR_TFVE(reg) (((reg) >> 12) & 0x1f) /* transmit FIFO valid entries */ >>> + >>> +/* >>> + * Feature Register >>> + */ >>> +#define FEAR_WIDTH(reg) ((((reg) >> 0) & 0xff) + 1) >>> +#define FEAR_RXFIFO(reg) ((((reg) >> 8) & 0xff) + 1) >>> +#define FEAR_TXFIFO(reg) ((((reg) >> 16) & 0xff) + 1) >>> +#define FEAR_AC97 (1 << 24) >>> +#define FEAR_I2S (1 << 25) >>> +#define FEAR_SPI_MWR (1 << 26) >>> +#define FEAR_SSP (1 << 27) >>> +#define FEAR_SPDIF (1 << 28) >>> + >>> +#endif >>> -- >>> 1.7.9.5 >>> >>> _______________________________________________ >>> U-Boot mailing list >>> U-Boot@lists.denx.de >>> http://lists.denx.de/mailman/listinfo/u-boot Please see the comments on below patch http://patchwork.ozlabs.org/patch/265683/ -- Thanks, Jagan.
> > Please see the comments on below patch > http://patchwork.ozlabs.org/patch/265683/ > > -- Got it, thanks
Any update on this. On Mon, Aug 12, 2013 at 6:07 AM, Kuo-Jung Su <dantesu@gmail.com> wrote: >> >> Please see the comments on below patch >> http://patchwork.ozlabs.org/patch/265683/ >> >> -- > > Got it, thanks > > > -- > Best wishes, > Kuo-Jung Su
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index d08609e..947d60e 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -38,6 +38,7 @@ 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 +COBJS-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o COBJS-$(CONFIG_EXYNOS_SPI) += exynos_spi.o COBJS-$(CONFIG_ICH_SPI) += ich.o COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o diff --git a/drivers/spi/ftssp010_spi.c b/drivers/spi/ftssp010_spi.c new file mode 100644 index 0000000..4247c8c --- /dev/null +++ b/drivers/spi/ftssp010_spi.c @@ -0,0 +1,337 @@ +/* + * Faraday Multi-function Controller - SPI Mode + * + * (C) Copyright 2010 Faraday Technology + * Dante Su <dantesu@faraday-tech.com> + * + * This file is released under the terms of GPL v2 and any later version. + * See the file COPYING in the root directory of the source tree for details. + */ + +#include <common.h> +#include <asm/io.h> +#include <spi.h> +#include <malloc.h> + +#include "ftssp010_spi.h" + +struct ftssp010_chip { + void *iobase; + uint32_t fifo; + uint32_t rev; + uint32_t div; + uint32_t mode; + + struct { + uint32_t iobase; + uint32_t pin; + } gpio; +}; + +static struct ftssp010_chip chip_list[] = { +#if defined(CONFIG_FTSSP010_BASE) || defined(CONFIG_FTSSP010_BASE0) + { + .iobase = (void *)CONFIG_FTSSP010_BASE, +#ifdef CONFIG_FTSSP010_GPIO_BASE + .gpio = { CONFIG_FTSSP010_GPIO_BASE, CONFIG_FTSSP010_GPIO_PIN }, +#endif + }, +#endif +#ifdef CONFIG_FTSSP010_BASE1 + { .iobase = (void *)CONFIG_FTSSP010_BASE1, }, +#endif +#ifdef CONFIG_FTSSP010_BASE2 + { .iobase = (void *)CONFIG_FTSSP010_BASE2, }, +#endif +#ifdef CONFIG_FTSSP010_BASE3 + { .iobase = (void *)CONFIG_FTSSP010_BASE3, }, +#endif +}; + +/* Register access macros */ +#define SPI_READ(r) le32_to_cpu(readl(r)) +#define SPI_WRITE(v, r) writel(cpu_to_le32(v), r) +#define SPI_SETBITS(m, r) setbits_le32(r, m) +#define SPI_CLRBITS(m, r) clrbits_le32(r, m) + +#ifdef CONFIG_FTSSP010_GPIO_BASE +#define SPI_GPIO_READ(p, r) \ + le32_to_cpu(readl((p)->gpio.iobase + (r))) +#define SPI_GPIO_WRITE(p, v, r) \ + writel(cpu_to_le32(v), (p)->gpio.iobase + (r)) +#define SPI_GPIO_SETBITS(p, m, r) \ + setbits_le32((p)->gpio.iobase + (r), m) +#define SPI_GPIO_CLRBITS(p, m, r) \ + clrbits_le32((p)->gpio.iobase + (r), m) +#endif /* #ifdef CONFIG_FTSSP010_GPIO_BASE */ + +static int ftssp010_spi_work_transfer_v1_19(struct ftssp010_chip *chip, + const void *tx_buf, void *rx_buf, int len, uint flags) +{ + struct ftssp010_regs *regs = chip->iobase; + const uint8_t *txb = tx_buf; + uint8_t *rxb = rx_buf; + + while (len > 0) { + int i, depth = min(chip->fifo >> 2, len); + uint32_t xmsk = 0; + + if (tx_buf) { + for (i = 0; i < depth; ++i) { + while (!(SPI_READ(®s->sr) & SR_TFNF)) + ; + SPI_WRITE(*txb++, ®s->dr); + } + xmsk |= CR2_TXEN | CR2_TXDOE; + if ((SPI_READ(®s->cr[2]) & xmsk) != xmsk) + SPI_SETBITS(xmsk, ®s->cr[2]); + } + if (rx_buf) { + xmsk |= CR2_RXEN; + if ((SPI_READ(®s->cr[2]) & xmsk) != xmsk) + SPI_SETBITS(xmsk, ®s->cr[2]); + for (i = 0; i < depth; ++i) { + while (!SR_RFVE(SPI_READ(®s->sr))) + ; + *rxb++ = (uint8_t)SPI_READ(®s->dr); + } + } + + len -= depth; + } + + return 0; +} + +static int ftssp010_spi_work_transfer(struct ftssp010_chip *chip, + const void *tx_buf, void *rx_buf, int len, uint flags) +{ + struct ftssp010_regs *regs = chip->iobase; + const uint8_t *txb = tx_buf; + uint8_t *rxb = rx_buf; + + while (len > 0) { + int i, depth = min(chip->fifo >> 2, len); + uint32_t tmp; + + for (i = 0; i < depth; ++i) { + while (!(SPI_READ(®s->sr) & SR_TFNF)) + ; + SPI_WRITE(txb ? (*txb++) : 0, ®s->dr); + } + for (i = 0; i < depth; ++i) { + while (!SR_RFVE(SPI_READ(®s->sr))) + ; + tmp = SPI_READ(®s->dr); + if (rxb) + *rxb++ = (uint8_t)tmp; + } + + len -= depth; + } + + return 0; +} + +/*=====================================================================*/ +/* Public Functions */ +/*=====================================================================*/ + +/*----------------------------------------------------------------------- + * Determine if a SPI chipselect is valid. + * This function is provided by the board if the low-level SPI driver + * needs it to determine if a given chipselect is actually valid. + * + * Returns: 1 if bus:cs identifies a valid chip on this board, 0 + * otherwise. + */ +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + struct ftssp010_chip *chip; + struct ftssp010_regs *regs; + uint32_t txfifo, rxfifo; + + if (bus >= ARRAY_SIZE(chip_list)) + return 0; + + chip = chip_list + bus; + regs = chip->iobase; + chip->rev = SPI_READ(®s->revr); + txfifo = FEAR_TXFIFO(SPI_READ(®s->fear)); + rxfifo = FEAR_RXFIFO(SPI_READ(®s->fear)); + chip->fifo = min(txfifo, rxfifo); + + printf("ftssp010: rev.=0x%08X, fifo=%d\n", chip->rev, chip->fifo); + + if (chip->rev >= 0x00011900) { + if (cs > 3) + return 0; + } else { +#ifdef CONFIG_FTSSP010_GPIO_BASE + if (cs > 0) + return 0; + /* setup gpio pin as an output pin */ + SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x08); +#else + return 0; +#endif + } + + return 1; +} + +/*----------------------------------------------------------------------- + * Activate a SPI chipselect. + * This function is provided by the board code when using a driver + * that can't control its chipselects automatically (e.g. + * common/soft_spi.c). When called, it should activate the chip select + * to the device identified by "slave". + */ +void spi_cs_activate(struct spi_slave *slave) +{ + struct ftssp010_chip *chip = chip_list + slave->bus; + struct ftssp010_regs *regs = chip->iobase; + + /* cs pull low */ + if (chip->rev >= 0x00011900) { + SPI_WRITE((slave->cs << 10) | CR2_SSPEN | CR2_TXFCLR + | CR2_RXFCLR, ®s->cr[2]); + } else { +#ifdef CONFIG_FTSSP010_GPIO_BASE + SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x14); +#endif + } + udelay_masked(1); +} + +/*----------------------------------------------------------------------- + * Deactivate a SPI chipselect. + * This function is provided by the board code when using a driver + * that can't control its chipselects automatically (e.g. + * common/soft_spi.c). When called, it should deactivate the chip + * select to the device identified by "slave". + */ +void spi_cs_deactivate(struct spi_slave *slave) +{ + struct ftssp010_chip *chip = chip_list + slave->bus; + struct ftssp010_regs *regs = chip->iobase; + + /* wait until device idle */ + while (SPI_READ(®s->sr) & SR_BUSY) + ; + + /* cs pull high */ + if (chip->rev >= 0x00011900) { + SPI_WRITE((slave->cs << 10) | CR2_FS, ®s->cr[2]); + } else { +#ifdef CONFIG_FTSSP010_GPIO_BASE + SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x10); +#endif + } + udelay_masked(1); +} + +void spi_init(void) +{ +} + +struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode) +{ + uint32_t clk, div; + struct spi_slave *ss; + struct ftssp010_chip *chip; + + if (!spi_cs_is_valid(bus, cs)) + return NULL; + + if (mode != SPI_MODE_0) { + printf("ftssp010: MODE%d is not supported\n", mode); + return NULL; + } + + ss = malloc(sizeof(struct spi_slave)); + if (!ss) + return NULL; + + ss->bus = bus; + ss->cs = cs; + +#ifdef CONFIG_FTSSP010_SCLK + clk = CONFIG_FTSSP010_SCLK; +#else + clk = clk_get_rate("SSP"); +#endif + if (max_hz > 0) { + for (div = 0; div < 0xFFFF; ++div) { + if ((clk / (2 * (div + 1))) <= max_hz) + break; + } + } else { + div = 7; + } + + chip = chip_list + bus; + chip->div = div; + chip->mode = mode; + + printf("ftssp010: bus=%d, hz=%u\n", bus, (clk / (2 * (div + 1)))); + + return ss; +} + +void spi_free_slave(struct spi_slave *slave) +{ + free(slave); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + struct ftssp010_chip *chip = chip_list + slave->bus; + struct ftssp010_regs *regs = chip->iobase; + + SPI_WRITE(CR1_SDL(8) | CR1_CLKDIV(chip->div), ®s->cr[1]); + + if (chip->rev >= 0x00011900) { + SPI_WRITE(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO | CR0_FLASH, + ®s->cr[0]); + SPI_WRITE(CR2_TXFCLR | CR2_RXFCLR, + ®s->cr[2]); + } else { + SPI_WRITE(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO, + ®s->cr[0]); + SPI_WRITE(CR2_TXFCLR | CR2_RXFCLR | CR2_SSPEN | CR2_TXDOE, + ®s->cr[2]); + } + + spi_cs_deactivate(slave); + + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + struct ftssp010_chip *chip = chip_list + slave->bus; + struct ftssp010_regs *regs = chip->iobase; + + SPI_WRITE(0, ®s->cr[2]); +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct ftssp010_chip *chip = chip_list + slave->bus; + uint32_t len = bitlen >> 3; + + if (flags & SPI_XFER_BEGIN) + spi_cs_activate(slave); + + if (chip->rev >= 0x00011900) + ftssp010_spi_work_transfer_v1_19(chip, dout, din, len, flags); + else + ftssp010_spi_work_transfer(chip, dout, din, len, flags); + + if (flags & SPI_XFER_END) + spi_cs_deactivate(slave); + + return 0; +} diff --git a/drivers/spi/ftssp010_spi.h b/drivers/spi/ftssp010_spi.h new file mode 100644 index 0000000..5ad7c47 --- /dev/null +++ b/drivers/spi/ftssp010_spi.h @@ -0,0 +1,86 @@ +/* + * Faraday Multi-function Controller - SPI Mode + * + * (C) Copyright 2010 Faraday Technology + * Dante Su <dantesu@faraday-tech.com> + * + * This file is released under the terms of GPL v2 and any later version. + * See the file COPYING in the root directory of the source tree for details. + */ + +#ifndef _FTSSP010_H +#define _FTSSP010_H + +/* FTSSP010 HW Registers */ +struct ftssp010_regs { + uint32_t cr[3];/* control register */ + uint32_t sr; /* status register */ + uint32_t icr; /* interrupt control register */ + uint32_t isr; /* interrupt status register */ + uint32_t dr; /* data register */ + uint32_t rsvd[17]; + uint32_t revr; /* revision register */ + uint32_t fear; /* feature register */ +}; + +/* Control register 0 */ +#define CR0_FFMT_MASK (7 << 12) +#define CR0_FFMT_SSP (0 << 12) +#define CR0_FFMT_SPI (1 << 12) +#define CR0_FFMT_MICROWIRE (2 << 12) +#define CR0_FFMT_I2S (3 << 12) +#define CR0_FFMT_AC97 (4 << 12) +#define CR0_FLASH (1 << 11) +#define CR0_FSDIST(x) (((x) & 0x03) << 8) +#define CR0_LBM (1 << 7) /* Loopback mode */ +#define CR0_LSB (1 << 6) /* LSB first */ +#define CR0_FSPO (1 << 5) /* Frame sync atcive low */ +#define CR0_FSJUSTIFY (1 << 4) +#define CR0_OPM_SLAVE (0 << 2) +#define CR0_OPM_MASTER (3 << 2) +#define CR0_OPM_I2S_MSST (3 << 2) /* Master stereo mode */ +#define CR0_OPM_I2S_MSMO (2 << 2) /* Master mono mode */ +#define CR0_OPM_I2S_SLST (1 << 2) /* Slave stereo mode */ +#define CR0_OPM_I2S_SLMO (0 << 2) /* Slave mono mode */ +#define CR0_SCLKPO (1 << 1) /* SCLK Remain HIGH */ +#define CR0_SCLKPH (1 << 0) /* Half CLK cycle */ + +/* Control Register 1 */ + +#define CR1_PDL(x) (((x) & 0xff) << 24) /* padding length */ +#define CR1_SDL(x) ((((x) - 1) & 0x1f) << 16) /* data length */ +#define CR1_CLKDIV(x) ((x) & 0xffff) /* clk divider */ + +/* Control Register 2 */ +#define CR2_FSOS(x) (((x) & 0x03) << 10) /* FS/CS Select */ +#define CR2_FS (1 << 9) /* FS/CS Signal Level */ +#define CR2_TXEN (1 << 8) /* Tx Enable */ +#define CR2_RXEN (1 << 7) /* Rx Enable */ +#define CR2_SSPRST (1 << 6) /* SSP reset */ +#define CR2_TXFCLR (1 << 3) /* TX FIFO Clear */ +#define CR2_RXFCLR (1 << 2) /* RX FIFO Clear */ +#define CR2_TXDOE (1 << 1) /* TX Data Output Enable */ +#define CR2_SSPEN (1 << 0) /* SSP Enable */ + +/* + * Status Register + */ +#define SR_RFF (1 << 0) /* receive FIFO full */ +#define SR_TFNF (1 << 1) /* transmit FIFO not full */ +#define SR_BUSY (1 << 2) /* bus is busy */ +#define SR_RFVE(reg) (((reg) >> 4) & 0x1f) /* receive FIFO valid entries */ +#define SR_TFVE(reg) (((reg) >> 12) & 0x1f) /* transmit FIFO valid entries */ + +/* + * Feature Register + */ +#define FEAR_WIDTH(reg) ((((reg) >> 0) & 0xff) + 1) +#define FEAR_RXFIFO(reg) ((((reg) >> 8) & 0xff) + 1) +#define FEAR_TXFIFO(reg) ((((reg) >> 16) & 0xff) + 1) +#define FEAR_AC97 (1 << 24) +#define FEAR_I2S (1 << 25) +#define FEAR_SPI_MWR (1 << 26) +#define FEAR_SSP (1 << 27) +#define FEAR_SPDIF (1 << 28) + +#endif