xilinx_spi: add support for the DS570 IP.

This patch adds in support for the DS570 IP.

It's register compatible with the DS464, but adds support for 8/16/32 SPI.

The 8/16/32 support is added by attaching callbacks reading/writing the
proper amount of data. To indicate to the driver which amount of bits
to use a new field is introduced in the platform data struct.

Acked-by: Grant Likely <grant.likely@secretlab.ca>
Tested-by: John Linn <John.Linn@xilinx.com>
Signed-off-by: Richard Röjfors <richard.rojfors@mocean-labs.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
This commit is contained in:
Richard Röjfors 2009-11-13 12:28:55 +01:00 committed by Grant Likely
parent 86fc593599
commit c9da2e1255
4 changed files with 95 additions and 34 deletions

View file

@ -243,7 +243,7 @@ config SPI_TXX9
SPI driver for Toshiba TXx9 MIPS SoCs SPI driver for Toshiba TXx9 MIPS SoCs
config SPI_XILINX config SPI_XILINX
tristate "Xilinx SPI controller" tristate "Xilinx SPI controller common module"
depends on HAS_IOMEM && EXPERIMENTAL depends on HAS_IOMEM && EXPERIMENTAL
select SPI_BITBANG select SPI_BITBANG
select SPI_XILINX_OF if (XILINX_VIRTEX || MICROBLAZE) select SPI_XILINX_OF if (XILINX_VIRTEX || MICROBLAZE)
@ -253,6 +253,8 @@ config SPI_XILINX
See the "OPB Serial Peripheral Interface (SPI) (v1.00e)" See the "OPB Serial Peripheral Interface (SPI) (v1.00e)"
Product Specification document (DS464) for hardware details. Product Specification document (DS464) for hardware details.
Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)"
config SPI_XILINX_OF config SPI_XILINX_OF
tristate "Xilinx SPI controller OF device" tristate "Xilinx SPI controller OF device"
depends on SPI_XILINX && (XILINX_VIRTEX || MICROBLAZE) depends on SPI_XILINX && (XILINX_VIRTEX || MICROBLAZE)

View file

@ -27,7 +27,7 @@
/* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e) /* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e)
* Product Specification", DS464 * Product Specification", DS464
*/ */
#define XSPI_CR_OFFSET 0x60 /* 16-bit Control Register */ #define XSPI_CR_OFFSET 0x60 /* Control Register */
#define XSPI_CR_ENABLE 0x02 #define XSPI_CR_ENABLE 0x02
#define XSPI_CR_MASTER_MODE 0x04 #define XSPI_CR_MASTER_MODE 0x04
@ -38,8 +38,9 @@
#define XSPI_CR_RXFIFO_RESET 0x40 #define XSPI_CR_RXFIFO_RESET 0x40
#define XSPI_CR_MANUAL_SSELECT 0x80 #define XSPI_CR_MANUAL_SSELECT 0x80
#define XSPI_CR_TRANS_INHIBIT 0x100 #define XSPI_CR_TRANS_INHIBIT 0x100
#define XSPI_CR_LSB_FIRST 0x200
#define XSPI_SR_OFFSET 0x64 /* 8-bit Status Register */ #define XSPI_SR_OFFSET 0x64 /* Status Register */
#define XSPI_SR_RX_EMPTY_MASK 0x01 /* Receive FIFO is empty */ #define XSPI_SR_RX_EMPTY_MASK 0x01 /* Receive FIFO is empty */
#define XSPI_SR_RX_FULL_MASK 0x02 /* Receive FIFO is full */ #define XSPI_SR_RX_FULL_MASK 0x02 /* Receive FIFO is full */
@ -47,8 +48,8 @@
#define XSPI_SR_TX_FULL_MASK 0x08 /* Transmit FIFO is full */ #define XSPI_SR_TX_FULL_MASK 0x08 /* Transmit FIFO is full */
#define XSPI_SR_MODE_FAULT_MASK 0x10 /* Mode fault error */ #define XSPI_SR_MODE_FAULT_MASK 0x10 /* Mode fault error */
#define XSPI_TXD_OFFSET 0x68 /* 8-bit Data Transmit Register */ #define XSPI_TXD_OFFSET 0x68 /* Data Transmit Register */
#define XSPI_RXD_OFFSET 0x6c /* 8-bit Data Receive Register */ #define XSPI_RXD_OFFSET 0x6c /* Data Receive Register */
#define XSPI_SSR_OFFSET 0x70 /* 32-bit Slave Select Register */ #define XSPI_SSR_OFFSET 0x70 /* 32-bit Slave Select Register */
@ -68,6 +69,7 @@
#define XSPI_INTR_TX_UNDERRUN 0x08 /* TxFIFO was underrun */ #define XSPI_INTR_TX_UNDERRUN 0x08 /* TxFIFO was underrun */
#define XSPI_INTR_RX_FULL 0x10 /* RxFIFO is full */ #define XSPI_INTR_RX_FULL 0x10 /* RxFIFO is full */
#define XSPI_INTR_RX_OVERRUN 0x20 /* RxFIFO was overrun */ #define XSPI_INTR_RX_OVERRUN 0x20 /* RxFIFO was overrun */
#define XSPI_INTR_TX_HALF_EMPTY 0x40 /* TxFIFO is half empty */
#define XIPIF_V123B_RESETR_OFFSET 0x40 /* IPIF reset register */ #define XIPIF_V123B_RESETR_OFFSET 0x40 /* IPIF reset register */
#define XIPIF_V123B_RESET_MASK 0x0a /* the value to write */ #define XIPIF_V123B_RESET_MASK 0x0a /* the value to write */
@ -81,15 +83,61 @@ struct xilinx_spi {
u32 irq; u32 irq;
u32 speed_hz; /* SCK has a fixed frequency of speed_hz Hz */
u8 *rx_ptr; /* pointer in the Tx buffer */ u8 *rx_ptr; /* pointer in the Tx buffer */
const u8 *tx_ptr; /* pointer in the Rx buffer */ const u8 *tx_ptr; /* pointer in the Rx buffer */
int remaining_bytes; /* the number of bytes left to transfer */ int remaining_bytes; /* the number of bytes left to transfer */
u8 bits_per_word;
unsigned int (*read_fn) (void __iomem *); unsigned int (*read_fn) (void __iomem *);
void (*write_fn) (u32, void __iomem *); void (*write_fn) (u32, void __iomem *);
void (*tx_fn) (struct xilinx_spi *);
void (*rx_fn) (struct xilinx_spi *);
}; };
static void xspi_tx8(struct xilinx_spi *xspi)
{
xspi->write_fn(*xspi->tx_ptr, xspi->regs + XSPI_TXD_OFFSET);
xspi->tx_ptr++;
}
static void xspi_tx16(struct xilinx_spi *xspi)
{
xspi->write_fn(*(u16 *)(xspi->tx_ptr), xspi->regs + XSPI_TXD_OFFSET);
xspi->tx_ptr += 2;
}
static void xspi_tx32(struct xilinx_spi *xspi)
{
xspi->write_fn(*(u32 *)(xspi->tx_ptr), xspi->regs + XSPI_TXD_OFFSET);
xspi->tx_ptr += 4;
}
static void xspi_rx8(struct xilinx_spi *xspi)
{
u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET);
if (xspi->rx_ptr) {
*xspi->rx_ptr = data & 0xff;
xspi->rx_ptr++;
}
}
static void xspi_rx16(struct xilinx_spi *xspi)
{
u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET);
if (xspi->rx_ptr) {
*(u16 *)(xspi->rx_ptr) = data & 0xffff;
xspi->rx_ptr += 2;
}
}
static void xspi_rx32(struct xilinx_spi *xspi)
{
u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET);
if (xspi->rx_ptr) {
*(u32 *)(xspi->rx_ptr) = data;
xspi->rx_ptr += 4;
}
}
static void xspi_init_hw(struct xilinx_spi *xspi) static void xspi_init_hw(struct xilinx_spi *xspi)
{ {
void __iomem *regs_base = xspi->regs; void __iomem *regs_base = xspi->regs;
@ -107,8 +155,8 @@ static void xspi_init_hw(struct xilinx_spi *xspi)
/* Disable the transmitter, enable Manual Slave Select Assertion, /* Disable the transmitter, enable Manual Slave Select Assertion,
* put SPI controller into master mode, and enable it */ * put SPI controller into master mode, and enable it */
xspi->write_fn(XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT | xspi->write_fn(XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT |
XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE, XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE | XSPI_CR_TXFIFO_RESET |
regs_base + XSPI_CR_OFFSET); XSPI_CR_RXFIFO_RESET, regs_base + XSPI_CR_OFFSET);
} }
static void xilinx_spi_chipselect(struct spi_device *spi, int is_on) static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
@ -141,18 +189,20 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
/* spi_bitbang requires custom setup_transfer() to be defined if there is a /* spi_bitbang requires custom setup_transfer() to be defined if there is a
* custom txrx_bufs(). We have nothing to setup here as the SPI IP block * custom txrx_bufs(). We have nothing to setup here as the SPI IP block
* supports just 8 bits per word, and SPI clock can't be changed in software. * supports 8 or 16 bits per word which cannot be changed in software.
* Check for 8 bits per word. Chip select delay calculations could be * SPI clock can't be changed in software either.
* Check for correct bits per word. Chip select delay calculations could be
* added here as soon as bitbang_work() can be made aware of the delay value. * added here as soon as bitbang_work() can be made aware of the delay value.
*/ */
static int xilinx_spi_setup_transfer(struct spi_device *spi, static int xilinx_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t) struct spi_transfer *t)
{ {
struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
u8 bits_per_word; u8 bits_per_word;
bits_per_word = (t && t->bits_per_word) bits_per_word = (t && t->bits_per_word)
? t->bits_per_word : spi->bits_per_word; ? t->bits_per_word : spi->bits_per_word;
if (bits_per_word != 8) { if (bits_per_word != xspi->bits_per_word) {
dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n", dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
__func__, bits_per_word); __func__, bits_per_word);
return -EINVAL; return -EINVAL;
@ -163,17 +213,16 @@ static int xilinx_spi_setup_transfer(struct spi_device *spi,
static int xilinx_spi_setup(struct spi_device *spi) static int xilinx_spi_setup(struct spi_device *spi)
{ {
struct spi_bitbang *bitbang; /* always return 0, we can not check the number of bits.
struct xilinx_spi *xspi; * There are cases when SPI setup is called before any driver is
int retval; * there, in that case the SPI core defaults to 8 bits, which we
* do not support in some cases. But if we return an error, the
xspi = spi_master_get_devdata(spi->master); * SPI device would not be registered and no driver can get hold of it
bitbang = &xspi->bitbang; * When the driver is there, it will call SPI setup again with the
* correct number of bits per transfer.
retval = xilinx_spi_setup_transfer(spi, NULL); * If a driver setups with the wrong bit number, it will fail when
if (retval < 0) * it tries to do a transfer
return retval; */
return 0; return 0;
} }
@ -185,11 +234,10 @@ static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi)
sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
while ((sr & XSPI_SR_TX_FULL_MASK) == 0 && xspi->remaining_bytes > 0) { while ((sr & XSPI_SR_TX_FULL_MASK) == 0 && xspi->remaining_bytes > 0) {
if (xspi->tx_ptr) if (xspi->tx_ptr)
xspi->write_fn(*xspi->tx_ptr++, xspi->tx_fn(xspi);
xspi->regs + XSPI_TXD_OFFSET);
else else
xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET); xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET);
xspi->remaining_bytes--; xspi->remaining_bytes -= xspi->bits_per_word / 8;
sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
} }
} }
@ -260,12 +308,7 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
/* Read out all the data from the Rx FIFO */ /* Read out all the data from the Rx FIFO */
sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) { while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) {
u8 data; xspi->rx_fn(xspi);
data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET);
if (xspi->rx_ptr) {
*xspi->rx_ptr++ = data;
}
sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
} }
@ -337,6 +380,19 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
xspi->read_fn = ioread32be; xspi->read_fn = ioread32be;
xspi->write_fn = iowrite32be; xspi->write_fn = iowrite32be;
} }
xspi->bits_per_word = pdata->bits_per_word;
if (xspi->bits_per_word == 8) {
xspi->tx_fn = xspi_tx8;
xspi->rx_fn = xspi_rx8;
} else if (xspi->bits_per_word == 16) {
xspi->tx_fn = xspi_tx16;
xspi->rx_fn = xspi_rx16;
} else if (xspi->bits_per_word == 32) {
xspi->tx_fn = xspi_tx32;
xspi->rx_fn = xspi_rx32;
} else
goto unmap_io;
/* SPI controller initializations */ /* SPI controller initializations */
xspi_init_hw(xspi); xspi_init_hw(xspi);

View file

@ -72,6 +72,7 @@ static int __devinit xilinx_spi_of_probe(struct of_device *ofdev,
return -EINVAL; return -EINVAL;
} }
pdata->num_chipselect = *prop; pdata->num_chipselect = *prop;
pdata->bits_per_word = 8;
master = xilinx_spi_init(&ofdev->dev, &r_mem, r_irq.start, -1); master = xilinx_spi_init(&ofdev->dev, &r_mem, r_irq.start, -1);
if (!master) if (!master)
return -ENODEV; return -ENODEV;

View file

@ -3,14 +3,16 @@
/** /**
* struct xspi_platform_data - Platform data of the Xilinx SPI driver * struct xspi_platform_data - Platform data of the Xilinx SPI driver
* @num_chipselect: Number of chip select by the IP * @num_chipselect: Number of chip select by the IP.
* @little_endian If registers should be accessed little endian or not * @little_endian: If registers should be accessed little endian or not.
* @bits_per_word: Number of bits per word.
* @devices: Devices to add when the driver is probed. * @devices: Devices to add when the driver is probed.
* @num_devices: Number of devices in the devices array. * @num_devices: Number of devices in the devices array.
*/ */
struct xspi_platform_data { struct xspi_platform_data {
u16 num_chipselect; u16 num_chipselect;
bool little_endian; bool little_endian;
u8 bits_per_word;
struct spi_board_info *devices; struct spi_board_info *devices;
u8 num_devices; u8 num_devices;
}; };